diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..8135b8f0b38 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +*.o +*.d +*.so +*.sw? +tags +cscope* + +# / +/cfg.tab.c +/cfg.tab.h +/lex.yy.c +/opensips +/debian +/curses.out +/.svnrevision +/.gitrevision + +# /doc/ +/doc/database + +# /menuconfig/ +/menuconfig/configure +/Makefile.conf + +# /utils/opensipsunix/ +/utils/opensipsunix/opensipsunix + +# miscellaneous files +core +core.* +out +log +*.log +*.html diff --git a/CREDITS b/CREDITS index 0050451e36c..7f57390f2d4 100644 --- a/CREDITS +++ b/CREDITS @@ -2,7 +2,7 @@ # OpenSIPS # #=============# -Current OpenSIPS team in alphabetical order as of 29 January 2013: +Current OpenSIPS team in alphabetical order as of 20 March 2014: Core Team: @@ -26,37 +26,31 @@ Saúl Ibarra Corretgé Dynamic Packet -============== Release 1.9.0 ================= -Arnaud Chong -Boris Ratner +============== Release 1.11.0 ================= +Baptiste Cholley Brett Nemeroff -Christophe Sollet -Damien Sandras -David Sanders -Diego Barberio -Dragos Oancea -Duane Larson -Gomtesh Jain -James Gledhill -John Quick -Lirakis -Marcel Barbulescu -Michael Schloh von Bennewitz -Muhammad Shahzad -Nathaniel L Keeling III +Christian Lahme +Damien Sanders +Di-Shi Sun +Earl C. Ruby III +Jayesh Nambiar +Jeff Pyle +Marco Hierl +Max E. Reyes Vera Juarez +Mayama Takeshi Nick Altmann -Parantido Julius De Rica -Peter Lemenkov -Rick van Rein -Rudy from DynamicPacket +Norm Brandinger +Richard Revels +Rob Gagnon Ryan Bullock -Samuel Muller -Sergey Avseyev -Stefan Tobe +Stas Kobzar +Stéphane Alnet Trevor Francis Walter Doekes -Yaroslav M Strilchuk -Nick (SourceForge) -Rico (SourceForge) -Toine (SourceForge) -shimaore (SourceForge) +csollet +dcb314 +dexteruk +fabriziopicconi +franklyfox +peppolon +Varun (varunvairavan on GITHUB) diff --git a/ChangeLog b/ChangeLog index f0de2e52e62..6b64e987219 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3628 +1,2532 @@ -=========================== Release 1.9.0 ============================== +=========================== Release 1.11.0 ============================== -2013-01-29 17:53:18 Bogdan-Andrei Iancu, - * [9703] : +2014-03-20 Liviu Chircu + * [1c7f225] : - - fixed shell line to find the builder + Makefile.conf.template: disable HP_MALLOC from the default setup -2013-01-29 17:33:35 Ovidiu Sas - * [9702] : +2014-03-20 Liviu Chircu + * [56b325b] : - Makefile: fix path in menuconfig_templates + core: High Performance Memory Allocator included + * ideal for systems with high volumes of calls-per-second + * fine-grained locking + * tunable two-level hashing of free memory fragments + * memory allocation pattern recording + * fragmentation-on-startup + * enable "HP_MALLOC" within "make menuconfig" +2014-03-20 Liviu Chircu + * [5fbc82f] : -2013-01-29 17:28:44 Bogdan-Andrei Iancu, - * [9700] : + atomic.h: add 64-bit atomic operations - - fixed ugly bug in computing the fromIP and toIP (because of some mixture of STRING and STR type at db level). - Thanks to Vlad Paiu for assisting with the debugging ;) - Closes bug #3576351 +2014-03-20 Razvan Crainea + * [66354d1] : -2013-01-29 17:18:51 Razvan Crainea - * [9699] : + update specs for 1.11 - Updated specs version to 1.9.0 +2014-03-20 Vlad Paiu + * [fcc1ab5] : -2013-01-29 14:19:13 Razvan Crainea - * [9696] : + Changed 1.11 status to beta - updated migration tool from 1.8 to 1.9 +2014-03-20 Răzvan Crainea + * [1a0310f] : -2013-01-29 14:17:55 Razvan Crainea - * [9695] : + dialog: remove timeout_avp from docs - fixed compilation warning for 32bits in event_route module +2014-03-20 Razvan Crainea + * [c6b1a6a] : -2013-01-29 13:35:11 Bogdan-Andrei Iancu, - * [9694] : + packaging: remove old debian-lenny - - module documentation re-generated. - - set SVN props for Id, Date and Revision +2014-03-20 Razvan Crainea + * [d110328] : -2013-01-29 13:08:43 Razvan Crainea - * [9693] : + update credits for 1.11 - fixed gcc 4.4 warning in event_xmlrpc module +2014-03-20 Bogdan-Andrei Iancu + * [e2c7ece] : -2013-01-29 12:59:26 Razvan Crainea - * [9692] : + MYSQL DB migration script updated from 1.10 to 1.11 migration - Fixed gcc 4.4 compile warning in event_route module +2014-03-20 Ovidiu Sas + * [bffa103] : -2013-01-29 12:42:57 Bogdan-Andrei Iancu, - * [9691] : + tm: fix README - - new parameter custom_headers_regexp added, similar to custom_headers, but instead of a list of headers, it allows you to define a regexp to match the headers that need to be propagated through the B2B - Credits go to Nick Altmann - Closes patch #3602478 +2014-03-20 Ovidiu Sas + * [6d41b53] : -2013-01-29 12:26:34 Bogdan-Andrei Iancu, - * [9689] : + tm: update doc for "own_timer_proc" parameter - it defines the number of timer procs - completes commit f001f098a0cf3996655e1ca47675b15d2f69c984 - - return different code if no script is found - - docs updated +2014-03-20 Răzvan Crainea + * [ff3f11a] : -2013-01-29 12:24:19 Vlad Paiu - * [9688] : + rtpproxy: update documentation - do not allocate tmrec structure if time recurrence for rule is empty +2014-03-20 Razvan Crainea + * [3c36a16] : + rtpproxy: rename script functions + * engage_rtp_proxy() is deprecated and replaced by rtpproxy_engage() + * unforce_rtp_proxy() is deprecated and replaced by rtpproxy_unforce() + * start_recording() is deprecated and replaced by rtpproxy_start_recording() -2013-01-29 12:21:22 Bogdan-Andrei Iancu, - * [9687] : - - line wrapping +2014-03-20 Razvan Crainea + * [00c42e3] : + call_center: fix compile warning for unsigned printing -2013-01-29 12:20:35 Bogdan-Andrei Iancu, - * [9686] : - - beautification - comments re-arranged to avoid lines longer than 80 chars +2014-03-20 Ovidiu Sas + * [c2b3726] : + drouting: use constans for indexing values while loading dr_rules table -2013-01-29 12:19:44 Bogdan-Andrei Iancu, - * [9685] : - - removed unused TMCB_ON_FAILURE_RO TM callback type +2014-03-20 Razvan Crainea + * [7b3ead2] : + makefile: prevent Makefile.conf from being ovewritten -2013-01-29 12:16:29 Bogdan-Andrei Iancu, - * [9682] : - - TMCB_ON_FAILURE_RO replaced with TMCB_ON_FAILURE as TMCB_ON_FAILURE_RO is no longer used. +2014-03-20 Ovidiu Sas + * [bdda717] : + Merge branch 'master' of github.com:OpenSIPS/opensips -2013-01-29 10:48:08 Di-Shi Sun - * [9681] : - Merged r9680 changes of OSP module into trunk. +2014-03-20 Ovidiu Sas + * [f552335] : -2013-01-28 19:40:45 Bogdan-Andrei Iancu, - * [9679] : + mi_xmlrpc_ng: make module opensips-cp compatible - -stream_exists() and stream_delete() functions added +2014-03-20 Razvan Crainea + * [6d76fe3] : -2013-01-28 18:40:58 Vlad Paiu - * [9678] : + compile: add Makefile.conf dependency - fixed typo - Credits to Ryan Bullock +2014-03-20 Ovidiu Sas + * [ca046ae] : + drouting: use constans for indexing values while loading dr_carriers table -2013-01-28 18:14:30 Vlad Paiu - * [9677] : - fixed race condition that would lead to invalid memory access when using dialog pinging +2014-03-20 Vlad Paiu + * [a6f42db] : + Fixed compile warning Module compiles even with STATISTICS support disabled -2013-01-28 17:38:49 Ovidiu Sas - * [9676] : +2014-03-20 Vlad Paiu + * [8c83b13] : - cachedb_sql: set svn:ignore + fixed sched_yield() warning +2014-03-20 Ovidiu Sas + * [ecbc003] : -2013-01-28 17:35:11 Ovidiu Sas - * [9675] : + drouting: use constans for indexing values while loading dr_gateways table - cachedb_mongodb: added to the list of excluded modules +2014-03-20 Bogdan-Andrei Iancu + * [791ab01] : + fixed compile warning -2013-01-28 17:31:33 Ovidiu Sas - * [9674] : - - cachedb_mongodb: set svn:ignore - - - -2013-01-28 15:54:12 Bogdan-Andrei Iancu, - * [9671] : - - - fixed who the NOTIFYs are built when triggered by a PUBLISH with expire 0; This is actually a revert of commit 9351, which seems to have some side-effects. - Thanks to Damien Sandras for helping with the the debugging. - Closes bug #3588141 - - -2013-01-28 15:45:48 Razvan Crainea - * [9670] : - - Added a new accounting method to the acc module that triggers events for each - accounting message generated (CDR or normal accounting) - - -2013-01-28 15:45:07 Vlad Paiu - * [9669] : - - for dialog pings, do not try to open a new TCP connection - - - -2013-01-28 15:35:50 Razvan Crainea - * [9668] : - - Allow modules to manage events parameters lists by themselves - - -2013-01-28 15:27:08 Vlad Paiu - * [9667] : - - added a new param, gw_priprefix_avp, for pushing the selected destination's pri prefix to script - - - -2013-01-28 15:20:51 Bogdan-Andrei Iancu, - * [9666] : - - - added more info on TCP connect failures - based on a patch/idea of Michael Schloh von Bennewitz - - -2013-01-28 14:16:58 Vlad Paiu - * [9665] : - - added svn:ignore property - - - -2013-01-28 13:47:02 Bogdan-Andrei Iancu, - * [9664] : - - - added full support for changes in B2B : changes done in script before triggering b2b are now propagated inside B2B; changes done in the b2b request / reply routes are also stored and used. - Credits go to Nick Altmann - Closes patch #3519778 - - -2013-01-28 13:05:32 Vlad Paiu - * [9663] : - - added the RAW query capability - check if the module supports the raw query capability before calling raw query func - - - -2013-01-28 12:33:36 Vlad Paiu - * [9662] : - - Added a MongoDB driver - - Added support for Raw Queries in the CacheDB interface - - Implemented the Raw Query support in MongoDB - - - -2013-01-28 11:43:51 Bogdan-Andrei Iancu, - * [9659] : - - - added new flag when invoking the b2b logic : 't' - preserve the received TO hdr, instead of generating a new one. - Credits go to Nick Altmann - Closes patch #3601891 - - -2013-01-28 10:43:58 Bogdan-Andrei Iancu, - * [9658] : - - - added flushing for the newly added tcp_list_conns MI command - - -2013-01-25 20:20:42 Vlad Paiu - * [9657] : - - Updated the module to support the latest libcouchbase driver - Credits to Sergey Avseyev - - - -2013-01-25 16:12:24 Bogdan-Andrei Iancu, - * [9656] : - - - fix TCP deadlock - see bug report 3585606 - - new MI command - list_tcp_conns to list (with description) the ongoing TCP/TLS commands - - -2013-01-25 11:59:22 Bogdan-Andrei Iancu, - * [9653] : - - fix returning NULL if json is not found - - -2013-01-25 11:17:20 Bogdan-Andrei Iancu, - * [9650] : - - fixed default values for the primary_ip and alternate_ip parameters - better documentation - - -2013-01-24 16:28:31 Vlad Paiu - * [9649] : - - set svn:ignore - - - -2013-01-24 16:27:06 Vlad Paiu - * [9648] : - - added license - - - -2013-01-24 16:24:32 Vlad Paiu - * [9647] : - - Added the CACHEDB_SQL module, which provides an implementation of the Key-Value interface that runs over a regular SQL-based database - - - -2013-01-24 16:08:38 Bogdan-Andrei Iancu, - * [9646] : - - - fix some doc error - - -2013-01-24 15:54:12 Bogdan-Andrei Iancu, - * [9645] : - - - new function lb_count_call(ip,port,grp,resources) - the function counts the current call as load for a given destination with some given resources - - -2013-01-24 11:02:09 Bogdan-Andrei Iancu, - * [9644] : - - - fixed dns resolving for destination (do SIP-wise dns lookup) - - all ips+ports for a destination are now kept in dest struct - - new function lb_is_dst( ip, port[, grp [,is_active]]) to check is an IP+port is a lb destination - - -2013-01-23 23:24:23 Ovidiu Sas - * [9643] : - - httpd: documentation updates - - - -2013-01-23 22:28:57 Ovidiu Sas - * [9642] : - - httpd: fix proper process exit in case of an error - - - -2013-01-23 21:25:22 Ovidiu Sas - * [9641] : - - httpd: better process description - - - -2013-01-23 18:18:19 Vlad Paiu - * [9640] : - - completed previous commit - - - -2013-01-23 18:01:25 Vlad Paiu - * [9639] : - - removed INFO message - - - -2013-01-23 17:40:41 Vlad Paiu - * [9638] : - - added svn:ignore property - - - -2013-01-23 17:31:12 Vlad Paiu - * [9637] : - - Added CouchBase connector integrated with the CacheDB interface - - - -2013-01-23 16:30:09 Bogdan-Andrei Iancu, - * [9636] : - - - removed bogus pkg_free() - related to commit #9633 and patch #3516387 - - -2013-01-23 16:05:01 Razvan Crainea - * [9635] : - - Added a xmlrpc_force_to_xml_chars() implementation for -XMLRPC versions older than 1.12 - - -2013-01-23 15:28:40 Ovidiu Sas - * [9634] : - - b2b_logic: README file re-generated - - - -2013-01-23 15:23:03 Bogdan-Andrei Iancu, - * [9633] : - - - controll the auth handling (local or remote) in b2b-ed calls can be done now per call, via the "a" flag in b2b_init_request() . - Credits go to Nick Altman - Closes patch #3516387 - - -2013-01-23 15:00:51 Bogdan-Andrei Iancu, - * [9632] : - - - fix proto and port selection - related to commit #9620 - Reported by Ovidiu Sas - - -2013-01-23 14:50:42 Bogdan-Andrei Iancu, - * [9631] : - - - PROTO_OTHER added - missing update related to commit 9621 - - -2013-01-23 13:06:07 Razvan Crainea - * [9630] : - - Added a new flag to the sipmsg_validate() function that validates the - Request URI of the message - - -2013-01-23 12:39:20 Bogdan-Andrei Iancu, - * [9627] : - - -fixed crash in a debug printing - pattern may be NULL - Reproted by Nathaniel L Keeling III - - -2013-01-23 11:29:01 Razvan Crainea - * [9624] : - - avoid including non-xml characters in the mi_xmlrpc response - - -2013-01-22 19:27:44 Vlad Paiu - * [9623] : - - import proper locking .h - - - -2013-01-22 19:24:59 Vlad Paiu - * [9622] : - - Added Futex Lock Support ( USE_FUTEX Compilation Option ) - Credits to Ryan Bullock - - - -2013-01-22 19:17:42 Bogdan-Andrei Iancu, - * [9621] : - - - added parsing support to accept any kind of transport description in VIA and URI parsers - needed for the Web Sockets support. - Credits go to Muhammad Shahzad - Closes patch #3545859 - - -2013-01-22 16:45:15 Liviu Chircu - * [9620] : - - - added a new flag to explicitly enable SIP OPTIONS pinging over TCP/TLS connections - - -2013-01-22 16:44:17 Liviu Chircu - * [9619] : - - updated the core branch flag "tcp_no_new_conn_bflag" to follow the recent flag changes - - -2013-01-22 16:16:26 Bogdan-Andrei Iancu, - * [9616] : - - - fixed a race condition when a CANCEL is received when cancelled INVITE is not yet completely processed: - * When t_forward_nonack() start, transaction is still not cancelled. - * When cancel_invite() process transaction, not all branches are created yet. - Result : cancel_invite() process correctly created branches but not ones created later. This is ending with never cancelled branches. - - Credits for the spoting and solving this go to Christophe Sollet - Closes patch #3545138. - - -2013-01-22 13:30:23 Bogdan-Andrei Iancu, - * [9612] : - - - fixed detection of T38 fax codec in SDP - - -2013-01-22 12:42:57 Razvan Crainea - * [9609] : - - Fixed shm_malloc_unsafe macro when using DBG_QM_MALLOC flag - - -2013-01-22 11:41:38 Razvan Crainea - * [9608] : - - Added two new events for signalling when the memory (pkg or shm) exceeds a - certain threshold - - -2013-01-21 21:41:54 Ovidiu Sas - * [9607] : - - pi_http: renaming pi_root parameter to pi_http_root - - - -2013-01-21 21:21:08 Ovidiu Sas - * [9606] : - - opensipsdbctl: fix presence tables provisioning - - - -2013-01-21 20:43:33 Ovidiu Sas - * [9605] : - - nathelper: fix sipping_bflag to accept string as a value - - - -2013-01-21 19:59:28 Liviu Chircu - * [9604] : - - Added named flags! - From now on, the proper way of setting a msg / script / branch flag is by supplying - an unquoted string: setflag(NEW_FLAG). Same for setsflag/setbflag and - their isflagset/resetflag/issflagset/resetsflag/isbflagset/resetbflag counterparts. - - Regarding the module parameters which are affected, for now both INT/STRING versions are - supported, but setting INT flags the classic way is now deprecated, and will throw a - minor warning at module load. - - The maximum individual flags of a flag type remains 32. - - -2013-01-21 13:42:36 Liviu Chircu - * [9603] : - - New functionality: Script tracing! - With script tracing, you can better understand the flow of execution in the OpenSIPS script. - Moreover, you can also trace the values of pseudo-variables, as script execution progresses. - - The blocks of the script where script tracing is enabled will print a line for each individual - action that is done (e.g. assignments, conditional tests, module functions, core functions, etc.). - Multiple pseudo-variables can be monitored by specifying a pv_format string - (e.g. "$ru---$avp(var1)"). The current value of the format will be printed along with each line. - - The logs of multiple traced regions of your script can be differentiated by specifying an - additional plain string as the 3rd parameter. - - Script tracing can be enabled with: script_trace(log_level, pv_format_string[, info_string]) - To disable script tracing, just: script_trace() - - - -2013-01-21 11:50:34 Razvan Crainea - * [9602] : - - Create new message each time an event_route is run and backup the avp lists - Properly set the integer parameters type for the event_route - - -2013-01-18 22:01:52 Ovidiu Sas - * [9601] : - - pi_http: documentation updates - - - -2013-01-18 21:07:39 Ovidiu Sas - * [9600] : - - opensipsdbctl: new command - opensipsdbctl pframework create - - creates a provisioning framework for the installed db tables - - - -2013-01-18 11:54:41 Bogdan-Andrei Iancu, - * [9599] : - - - cross references between XML doc files renamed - - -2013-01-18 11:53:05 Bogdan-Andrei Iancu, - * [9598] : - - doc file renamed to follow the name of the module - - -2013-01-18 07:45:56 Di-Shi Sun - * [9597] : - - Merged r9595/6 changes of OSP module into trunk. - -2013-01-18 00:09:58 Ovidiu Sas - * [9594] : - - osp: fix cross compilation - - - -2013-01-18 00:09:04 Ovidiu Sas - * [9593] : - - carrierroute: fix cross compilation - - - -2013-01-17 23:57:46 Ovidiu Sas - * [9592] : - - identity: fix cross compilation - - - -2013-01-17 23:57:22 Ovidiu Sas - * [9591] : - - tlsops: fix cross compilation - - - -2013-01-17 22:33:04 Ovidiu Sas - * [9590] : - - regex: fix cross compilation - - - -2013-01-17 22:32:41 Ovidiu Sas - * [9589] : - - dialplan: fix cross compilation - - - -2013-01-17 21:12:20 Ovidiu Sas - * [9588] : - - xcap: fix cross compilation - - - -2013-01-17 21:11:05 Ovidiu Sas - * [9587] : - - xcap_client: fix cross compilation - - - -2013-01-17 21:07:41 Ovidiu Sas - * [9586] : - - rls: fix cross compilation - - - -2013-01-17 21:06:58 Ovidiu Sas - * [9585] : - - pua_xmpp: fix cross compilation - - - -2013-01-17 21:06:12 Ovidiu Sas - * [9584] : - - pua_usrloc: fix cross compialtion - - - -2013-01-17 21:05:27 Ovidiu Sas - * [9583] : - - pua_mi: fix cross-compilation - - - -2013-01-17 21:04:38 Ovidiu Sas - * [9582] : - - pua: fix cross compilation - - - -2013-01-17 21:03:41 Ovidiu Sas - * [9581] : - - pua_bla: fix cross compilation - - - -2013-01-17 21:02:43 Ovidiu Sas - * [9580] : - - presence_dialoginfo: fix cross compilation - - - -2013-01-17 21:00:51 Ovidiu Sas - * [9579] : - - cpl-c: fix cross compilation - - - -2013-01-17 20:57:52 Ovidiu Sas - * [9578] : - - b2b_logic: fix cross compilation - - - -2013-01-17 20:52:43 Ovidiu Sas - * [9577] : - - httpd: fix cross-compilation - - - -2013-01-17 19:40:26 Bogdan-Andrei Iancu, - * [9573] : - - - fixed the calculation of the global average by the _bm_log_timer function. - Credits go to David Sanders - Closes patch #3555236. - - -2013-01-17 19:39:31 Ovidiu Sas - * [9572] : - - b2b_entities: fix proxy authentication - - credits goes to shimaore (sourceforge id) - - closes patch 3587231 - - - -2013-01-17 19:30:14 Bogdan-Andrei Iancu, - * [9571] : - - remove_hf_wildcard() and remove_hf() combined and extended: - remove_hf("name"); - remove_hf("wildcard","g"); - remove_hf("regexp","p"); - Credits go to Boris Ratner - Closes patch #3597436 - - -2013-01-17 19:01:44 Bogdan-Andrei Iancu, - * [9570] : - - docs updated - - -2013-01-17 18:02:48 Bogdan-Andrei Iancu, - * [9569] : - - new "m" flag to sipmsg_validate() to ignore the "max-forward" test - Credits go to Nick Altmann - Closes patch #3601093 - - -2013-01-17 17:31:53 Bogdan-Andrei Iancu, - * [9568] : - - added a script parameter called "tcp_accept_backlog" which is supplied to the listen(...) call done in tcp_main.c. - Before this patch the value was hardcoded to 10, which is a major bottleneck for performance when dealing with lots of TCP connections. With the new parameter this can be increased for deployments that need higher throughput. - - Credits go to David Sanders - Closes patch #3592311 - - -2013-01-17 16:44:54 Bogdan-Andrei Iancu, - * [9567] : - - - allow variables into both params of rtpproxy_[answer|offer] - Based on a patch contributed by Peter Lemenkov. - Closes patch #3600377 - - -2013-01-17 16:03:21 Bogdan-Andrei Iancu, - * [9566] : - - removed some silly debugs which ended up on SVN by mistake - - -2013-01-17 14:42:51 Bogdan-Andrei Iancu, - * [9565] : - - -packages updated to reflect changde from perlvdb to db_perlvdb - - -2013-01-17 11:46:49 Bogdan-Andrei Iancu, - * [9564] : - - - small cleanup on STR init definition - Credits go to Peter Lemenkov - Closes patch #3600350 - - -2013-01-17 11:05:22 Bogdan-Andrei Iancu, - * [9563] : - - more fixing on perlvdb_db_init - Perl constants updated for DB_BIGINT - - Related to patch 3599314 - - -2013-01-16 11:56:10 Razvan Crainea - * [9562] : - - allow cache_fetch() functions to receive any type of pvar as the output parameter - - -2013-01-15 20:57:44 Ovidiu Sas - * [9561] : - - Makefile.defs: set proper path to docbook.xsl - - - -2013-01-15 20:37:29 Ovidiu Sas - * [9560] : - - event_route: set svn:ignore - - - -2013-01-15 19:04:46 Bogdan-Andrei Iancu, - * [9559] : - - - renamed perlvdb -> db_perlvdb - - -2013-01-15 19:01:16 Bogdan-Andrei Iancu, - * [9558] : - - - updates to reflex the module renaming - - -2013-01-15 18:57:03 Bogdan-Andrei Iancu, - * [9557] : - - - renamed module to follow the name convention for DB modules - - -2013-01-15 17:26:09 Bogdan-Andrei Iancu, - * [9556] : - - Several fixes: - 1. change the the declared module name to db_perlvdb. Otherwise it is not found as db_ module. - 2. change the init db url type to actually be str - 3. many changes that fix various memory leaks (perl object leaks) - 4. fix result cleanup memory leaks - - Credits go to Boris Ratner ( ratner2 on SF) - Closes patch #3599314 - - -2013-01-15 17:00:06 Bogdan-Andrei Iancu, - * [9553] : - - Fixes perl_exec2() in perlfunc.c. The message object that is passed to the perl-script - was left hanging after every call to perl_exec() in the opensips script. - Moved the declaration of OpenSIPS::Message object to the SAVETMPS/FREETMPS - segment so it will be freed before the function returns. - Tested by using Devel::Gladiator. - - Credits go to Boris Ratner ( ratner2 on SF) - Closes patch #3599210 - - - -2013-01-15 16:50:48 Bogdan-Andrei Iancu, - * [9552] : - - added new module param "syslog_name" to control the logging from the radius client library - Credits go to Boris Ratner ( ratner2 on SF) - Closes patch #3597026 - - -2013-01-15 16:21:32 Bogdan-Andrei Iancu, - * [9551] : - - -added new function remove_hf_wildcard() to remove headers using shell like wildcards. - Credits go to Boris Ratner ( ratner2 on SF) - Closes patch #3591017. - - -2013-01-15 16:10:15 Bogdan-Andrei Iancu, - * [9550] : - - some DBG() cleanup - - -2013-01-15 15:12:09 Razvan Crainea - * [9549] : - - Added an event that is triggered when MySQL changes it's connection status - - -2013-01-15 13:25:49 Razvan Crainea - * [9548] : - - previous commit stands also for route checking, not onlyu fixing - - -2013-01-15 13:23:36 Razvan Crainea - * [9547] : - - bug fix: event_route index starts with 1 - - -2013-01-11 14:22:31 Razvan Crainea - * [9546] : - - Added support for route parameters - when calling a route, some extra - parameters can be attached (example: route(ROUTE_NAME, 1);), that can be later - retrieved using the newly added 'param' pseudo variable - - -2013-01-11 12:44:25 Razvan Crainea - * [9545] : - - fixed event_route documentation typo - - -2013-01-10 17:02:44 Saúl Ibarra Corretgé - * [9544] : - - Added external references support to pres-rules - - This adds support for external references to pres-rules documents - following the OMA specification. In order to achieve this, a few changes - were made in the presence handling: - - - The 'pres_rules_auid' module parameter (in presence_xml) controls - what mode OpenSIPS operates on: IETF or OMA. Right now this is a - global setting since the 2 offer different ways for authorization - and are stored in different XCAP documents. - - - Matching of sub-handling is now done according to the RFC, that - is, a sub-handling action of block has less priority than that of - allow. For reference, check RFC5025, section 3.2.1. - - Following external references is currently supported only for the - integrated mode. - - In order to simplify the implemntation, some common code related to XCAP - handling has been added to the 'xcap' module: - - - A way for normalizing SIP URIs. A SIP URI may appear encoded or - without the SIP scheme inside an XCAP document. The xcap module - now provides a function to normalize such URIs. - - - A way for getting XCAP documents from the DB. The xcap module now - contains a generic function which will fetch any XCAP document - from the DB. - - A TODO file was also added to the xcap module listing future - enhancements to be done to the XCAP related modules. - -2013-01-08 23:51:01 Ovidiu Sas - * [9541] : - - httpd: code cleanup and emable httpd to bind to any port - - - -2012-12-20 16:01:47 Razvan Crainea - * [9540] : - - Added acc multi-leg support for BYE messages - - -2012-12-19 15:40:07 Razvan Crainea - * [9537] : - - Added events description in documentation for modules rtpproxy, dispatcher and pike - Added group description in the E_DISPATCHER_STATUS event - Renamed E_RTPPROXY_STATUS status names to active/inactive - - -2012-12-18 13:35:47 Razvan Crainea - * [9536] : - - Added new event_route module that triggers script routes when an event is - raised by the Event Interface. - - -2012-12-17 20:21:08 Bogdan-Andrei Iancu, - * [9533] : - - - fixed some error messages - - fixed triggering the snmpgget command at startup - attendant process does not exists in fork=no mode - Related to bug 3584278 - - -2012-12-17 20:13:59 Bogdan-Andrei Iancu, - * [9530] : - - - fixed parsing MI commands with no input for commands marked with input (commands with optional input) - Closes bug 3590418 - Repoerted by Digipigeon (SF ID) - - -2012-12-17 18:29:35 Ovidiu Sas - * [9529] : - - db_text: making some error probes visible - - - -2012-12-15 06:11:44 Ovidiu Sas - * [9528] : - - db_text: documentation updates for dbt_dump mi command - - - -2012-12-15 06:09:50 Ovidiu Sas - * [9527] : - - db_text: new mi command 'dbt_dump' - - allows forcing a write back to disk for modified tables - - - -2012-12-15 01:57:36 Ovidiu Sas - * [9525] : - - uac_registrant: fix crash when running from db_text with empty optional parameters - - - -2012-12-14 19:59:57 Ovidiu Sas - * [9524] : - - pi_http: properly handle NULL values - - - -2012-12-14 19:55:32 Ovidiu Sas - * [9523] : - - pi_http: fix query operation for db w/o fetch support (like db_text) - - - -2012-12-14 17:56:39 Vlad Paiu - * [9520] : - - for top hiding, force parsing of all via headers in order to safely remove all of them - - - -2012-12-13 19:51:44 sobomax - * [9517] : - - Also free any callback memory, which is not shared. - - Bug ID: 3582691 - - - -2012-12-13 18:01:42 Bogdan-Andrei Iancu, - * [9516] : - - - updated the usage of timer functions - when registering a new timer handler, specify a label (human readable identifier) to be used when reporting/loging issues related to that handler - - -2012-12-13 16:28:52 Bogdan-Andrei Iancu, - * [9515] : - - Timers enhancements and fixes: - - when re-arming a handler (for next triggering), do not count the time spent on running the handler (two triggering must be exactly at "interval" difference) - - auto-recalibration of timer processes to compensate the time drifting because of running the handlers (running the handlers takes time which usualy accumulates and de-sync the timers) - - report to logs callbacks the abuse (as timer usage) the timer processes (if a handler uses more than on timer tick -> report it) - - This is step 1, step 2 will be to change in all modules the way the timer are registered (to provide mode info for loging) - - -2012-12-13 15:48:33 Bogdan-Andrei Iancu, - * [9514] : - - - fixed Makefile line, broken in commit 9513 - that line cannot be broken as it must be executed under same shell. - - -2012-12-12 20:19:13 Ovidiu Sas - * [9513] : - - osipsconfig: fix mpath for opensips.cfg templates - - - -2012-12-12 19:13:01 Ovidiu Sas - * [9512] : - - osipsconfig: new token USE_HTTP_MANAGEMENT_INTERFACE - - enables the HTTP Management Interface on port 8888 - - - -2012-12-12 18:26:34 Ovidiu Sas - * [9511] : - - pi_http: update documentation to reflect libxml2 dependency - - - -2012-12-12 18:23:17 Ovidiu Sas - * [9510] : - - scripts/pi_http: adding a full framework example - - - -2012-12-12 17:58:35 Ovidiu Sas - * [9509] : - - pi_http: Makefile updates to reflect pi_frameworki -> pi_http rename - - - -2012-12-12 17:56:49 Ovidiu Sas - * [9508] : - - rename pi_framework to pi_http to better reflect module ownership - - - -2012-12-12 17:39:08 Bogdan-Andrei Iancu, - * [9505] : - - - fixed limit check for natping_processes - Closes bug 3594839. - Credits go to Nick Altmann - - -2012-12-12 16:56:21 Ovidiu Sas - * [9504] : - - parser/sdp: Fixed double free - - Found and fixed by Hugh Waite @ Crocodile RCS - - - -2012-12-12 16:22:45 Ovidiu Sas - * [9503] : - - pi_framework_[table|mod]: update licence - - - -2012-12-12 11:27:26 Vlad Paiu - * [9500] : - - backport from 1.8 (rev #9499) - - fixed potential dialog timer list corruption in cases where the dialog timeout is updated via the dialog_timeout_avp from script - - - -2012-12-11 21:27:10 Ovidiu Sas - * [9498] : - - pi_http: install module specific stuff through install_module_custom target - - - -2012-12-11 19:33:35 Bogdan-Andrei Iancu, - * [9497] : - - - re-work of parse_hname2() (function that parses the name of headers) for fixing: - - do not accept spaces in the the name of the headers (not RFC compliant) - - do not include trailing spaces (between name and : separator) in the name (this affects detection of non-statdart headers - like "Foo" versus "Foo " - - buffer overflow when you have a non-standard header that are a prefix of a standard hdr (like "Content-L" versus "Content-Length") - this may leas to scaning entire memory space of the processs and even overflowing it. - - small various optimization in looking for the end of header name (like "From" versus "fromfoo") - - Closes bug #3582533 - - -2012-12-11 19:12:21 Ovidiu Sas - * [9496] : - - pi_http: install pi_framework samples if pi_http module is enabled - - - -2012-12-11 18:52:23 Ovidiu Sas - * [9495] : - - pi_http: adding pi_framework samples - - - -2012-12-11 18:50:35 Ovidiu Sas - * [9494] : - - pi_http: adding infrastructure for building pi_framework samples - - - -2012-12-11 12:12:11 Razvan Crainea - * [9492] : - - fixed ratelimit documentation regarding the default algorithm used - - -2012-12-10 15:46:50 Bogdan-Andrei Iancu, - * [9489] : - - - bogus records in address table should be skipped - - -2012-12-10 15:37:13 Bogdan-Andrei Iancu, - * [9487] : - - - added libterm-readline-perl-perl as dep for osipsconsole package -> uses the PERL stub for ReadLine - - -2012-12-10 15:33:55 Bogdan-Andrei Iancu, - * [9485] : - - fixing of variable initialization (from exported variables versus default values) - fixed historing - fixed address related commands - - -2012-12-07 11:40:28 Bogdan-Andrei Iancu, - * [9482] : - - - fixed setdebug() to accept also negative logging levels (like -1 = L_ERR) - Credits go to David Sanders - Closes patch #3593300 - - -2012-12-06 18:33:56 Bogdan-Andrei Iancu, - * [9479] : - - fixed the NULL value in script variables - without an explicit NULL value, it is impossible to test the variables when expecting a string value (NULL was previously considered a 0 INT value). - - -2012-12-05 18:27:23 Vlad Paiu - * [9478] : - - backport from 1.8 (rev #9477) - - fixed missing info for tcp thresholds - - - -2012-12-04 18:35:34 Bogdan-Andrei Iancu, - * [9475] : - - - switched annoying LM_INFO to DBG - - -2012-12-04 11:56:46 Bogdan-Andrei Iancu, - * [9472] : - - - fixed seg fault : all DR functions must check if DR data is available - data is loaded by first child and it may take a while. - - -2012-12-04 10:42:43 Razvan Crainea - * [9469] : - - avp_print now displays both real name and id of the AVP - - -2012-11-30 21:13:24 Bogdan-Andrei Iancu, - * [9466] : - - - before using be sure that TO hdr and FROM TAG are present. - Reported by Nick Altmann - Closes bug #3589142 - - -2012-11-30 19:20:24 Vlad Paiu - * [9464] : - - fixed mem leak on Redis reconnection - - - -2012-11-30 10:24:50 Razvan Crainea - * [9461] : - - * On some Solaris systems, the iov maximum buffers number is 16. However - rtpproxy tries to send more, therefore the communication fails. This fix - prevents these cases by concatenating the last buffers. - Credits go to Nathaniel L Keeling III for reporting and providing testing - environment - - * added -n flag in documentation - - -2012-11-29 16:04:07 Razvan Crainea - * [9460] : - - Improved the performance of options module by building the reply headers only - once, at startup. Also, if the header's value is empty, the header itself - makes no sense. - - -2012-11-28 18:53:09 Vlad Paiu - * [9458] : - - backport from 1.7 (rev #9456) - - fixed readme about the timeout_avp behavior - Credits to Walter Doekes - - - -2012-11-27 21:47:12 Ovidiu Sas - * [9455] : - - mi_http: fix a few memory leaks - - related to bug #3590411 - - - -2012-11-27 12:28:25 Razvan Crainea - * [9453] : - - fixed exported name of the sipmsgops module - Patch provided by Walter Doekes (#3590336) - - -2012-11-23 15:13:40 Vlad Paiu - * [9451] : - - fixed bug where dialog was marked as removed from ping list without having the ping list lock - - - -2012-11-23 14:57:46 Liviu Chircu - * [9450] : - - - cfgutils module: added check_time_rec() function, which matches a time recurrence string against the current date. - - moved load_TR_value macro from dr_load.c to time_rec.h - - -2012-11-22 19:19:15 Vlad Paiu - * [9448] : - - backport from 1.8 (rev #9446) - - fixed outgoing interface selection for locally generated messages - - - -2012-11-22 14:53:10 Bogdan-Andrei Iancu, - * [9445] : - - - fixed internal fallback (inside of do_routing() function) if a rule has no GWs or all GWs are disabled. - Reported by Rico (SF ID) - Closes bug #3587515 - - -2012-11-21 16:22:29 Liviu Chircu - * [9444] : - - - NEW! Added scripting locks in the cfgutils module. They come in two flavors: - - "static locks" are manipulated with the {get,release}_static_lock functions. - - "dynamic locks", which are bound to the {get,release}_dynamic_lock set of functions. - - Each class of locks has its own scenario of use. Refer to the updated module documentation for details. - - -2012-11-14 18:06:03 Saúl Ibarra Corretgé - * [9443] : - - Regenerated README files for presence_xml, rls, xcap and xcap_client modules - - -2012-11-14 17:46:37 Saúl Ibarra Corretgé - * [9442] : - - Updated documentation with API changes - - presence_xml, rls and xcap_client modules - -2012-11-14 17:46:10 Saúl Ibarra Corretgé - * [9441] : - - Added new XCAP module - - It contains common XCAP settings and functions, the presence_xml, rls - and xcap_client modules have been adapted to use this new module and - thus depend on it. - -2012-11-12 11:05:24 Saúl Ibarra Corretgé - * [9440] : - - Fixed possible infinite loop when parsing Subscription-State expires value +2014-03-20 Vlad Paiu + * [f14766a] : -2012-11-09 20:08:52 Ovidiu Sas - * [9439] : + Fixed free which lead to bogus memory access: - menuconfig: pass extra options to enable proper cross compilation +2014-03-20 Vlad Paiu + * [804c9f7] : + Fixed compile warning -2012-11-09 19:37:40 Ovidiu Sas - * [9437] : - drouting: remove bogus semicolon in structure declaration - (most likely a copy/paste error) +2014-03-20 Bogdan-Andrei Iancu + * [5492dbf] : + Code cleanup - removed variables which are not actually used for anything -2012-11-09 19:03:18 Liviu Chircu - * [9436] : +2014-03-20 Bogdan-Andrei Iancu + * [8ad0901] : - fixed buffer reallocating too often in previous commit + Fixed return code in case of error -2012-11-09 18:28:28 Liviu Chircu - * [9435] : +2014-03-20 Bogdan-Andrei Iancu + * [a4cdbcb] : - is_present_hf() and remove_hf() functions now receive string pseudo-variables as parameters + Added db schema for the Call Center module; DB stuff re-generated -2012-11-08 18:33:53 Saúl Ibarra Corretgé - * [9434] : +2014-03-20 Ovidiu Sas + * [4f5b87a] : - Fixed normalizing SIP URIs in RLS + pua_usrloc: fix error: SCB_RUN_ALL undeclared (first use in this function) -2012-11-08 18:27:24 Saúl Ibarra Corretgé - * [9433] : +2014-03-20 Liviu Chircu + * [276339f] : - Don't use strcat when calculating RLS selector path + [NEW] Script Helper module + * simplifies the scripting process in OpenSIPS + * transparent sequential request management + * embedded record routing and loose routing logic + * may be configured to include dialog support + * future directions include NAT and auth support -2012-11-07 16:44:03 Anca Vamanu, - * [9432] : +2014-03-20 Liviu Chircu + * [f333109] : - Aplied patch #3515749 submitted by Nick Altmann (with small changes). - Feature implemented: insert_hf/append_hf are working before b2b_request_init and in b2b_request/b2b_reply routes. + tm: reset $T_fr_timeout to default when setting a NULL value + * same for $T_fr_inv_timeout + * docs updated -2012-11-06 22:50:15 Bogdan-Andrei Iancu, - * [9429] : +2014-03-20 Liviu Chircu + * [a9c8016] : - -fixed the version and definition of the "aliases" table - Reported by John Quick. + rest_client: rename "ssl_ca_path" to match documentation -2012-11-06 13:57:45 Vlad Paiu - * [9428] : +2014-03-20 Liviu Chircu + * [ff4f8c1] : - removed timer debugging polluting the logs ( introduced with the previous dlg enhancements ) + call_center: added README +2014-03-20 Liviu Chircu + * [6e46a57] : -2012-11-05 19:58:53 Razvan Crainea - * [9424] : + script callbacks: add a priority-based register function + * useful for modules which must run their callback first/last -Fixed exported parameter bug in event_* modules documentation +2014-03-20 Liviu Chircu + * [4570b22] : -2012-11-05 11:56:26 Vlad Paiu - * [9422] : + script callbacks: new return code mechanism + * script callbacks must now return a "what-to-run-next" bitmask + * e.g. a module may now skip running top route, yet run post callbacks - fixed memory corruption +2014-03-20 Bogdan-Andrei Iancu + * [cb847c1] : + Adding new module "Call-Center" for call queueing and distribution TODO : add documentation and add DB schema -2012-11-02 08:59:38 Vlad Paiu - * [9420] : - fixed bug introduced in earlier dialog fix :| +2014-03-19 Ovidiu Sas + * [657ce89] : + mi_xmlrpc_ng: align output format with mi_xmlrpc module -2012-11-01 16:36:13 Vlad Paiu - * [9413] : +2014-03-19 Razvan Crainea + * [beb383f] : - match_dialog() is now able to do DID matching in the case of topology hiding + makefile: add FASTER variable + Increase the compile time of opensips by compiling all modules in parallel. + Because the output of the command gets mixed and it is hard to parse, we + simply suppress it. + Usage example: FASTER=1 make -j all +2014-03-19 Walter Doekes + * [176a41f] : -2012-11-01 11:29:34 Bogdan-Andrei Iancu, - * [9410] : + Address concern: readability of compiling modules without -j. - - one more memory leak (in private mem) fixed - Credits go to Nick Altmann +2014-03-19 Walter Doekes + * [67cfefe] : -2012-10-31 19:17:44 Vlad Paiu - * [9409] : + Address concerns: clearly note that there was an error. - backport from 1.8 (rev #9408) - fixed error message +2014-03-19 Walter Doekes + * [9271a45] : + Replace odd -j in module-submake with ability for proper parallelism. + Recently `-j` was added to the list of flags passed to the modules + $(MAKE) command. That's bad practise for two reasons: (1) the caller + should decide on how much -j is required, not the programmer, and (2) + just -j without any numeric argument is "use all resources you can + get", which can be too much. + We order the Makefile around so the supermake (the user invocation) + can dispatch individual submakes in a parallel fashion. This is done + by (a) making the module directories phony targets and (b) replacing + the sequential for-loop over the modules with a simple dependency. -2012-10-31 12:36:36 Bogdan-Andrei Iancu, - * [9405] : - - fixed VIA parsing to verify the validity of the host part and port part -> report a parse error - - trigger error_route even also for the pre-script parsing - - make send_reply() safe to use even if the sip_msg is not valid (like no VIA hdr at all). +2014-03-19 Razvan Crainea + * [0260de0] : - Reported by David Sanders - Closes bug #3571806 + event_rabbitmq: URI-decode fields in rabbitmq socket + Closes issue #148 -2012-10-31 12:23:44 Bogdan-Andrei Iancu, - * [9402] : +2014-03-19 Ovidiu Sas + * [ff5f403] : - -removed unused variable - -avoid leaking via standard malloc (strdup) - Credits go to Nick Altmann + pi_http: fix copy/paste error that can lead to a crash when 'order_by_cols' are used -2012-10-30 12:46:46 Bogdan-Andrei Iancu, - * [9399] : +2014-03-18 Razvan Crainea + * [a65eca9] : - - fixing small syntax error :D + fix sst dialog timeout after timeout_avp removal -2012-10-30 12:45:26 Bogdan-Andrei Iancu, - * [9398] : +2014-03-18 Liviu Chircu + * [b91cba4] : - - fixed buffer overflow and bogus freeing (related to previous fix on PATH module) - Credits go to Nick Altmann + cfgutils doc: specify RFC 2445 compatibility of "check_time_rec()" params -2012-10-29 16:38:49 Ovidiu Sas - * [9395] : +2014-03-18 Liviu Chircu + * [26af2e8] : - packaging/debian: adding pi_http to the list of HTTP_MODULES + tm: update documentation with latest changes +2014-03-18 Liviu Chircu + * [4b5e4f8] : -2012-10-29 13:47:22 Bogdan-Andrei Iancu, - * [9394] : + tm: rename "fr_timer" and "fr_inv_timer" * to "fr_timeout", "fr_inv_timeout" * rename equivalent variables to $T_fr_timeout and * $T_fr_inv_timeout * backwards-compatible - - fixed compile warning related to data size on 32 and 64 bits archs +2014-03-17 Bogdan-Andrei Iancu + * [253753e] : -2012-10-26 19:12:38 Ovidiu Sas - * [9392] : + Added new script function t_new_request() to allow sending SIP initial requests (as UAC transactions) from the OpenSIPS script. - pi_http: make use of the db api for converting between formats +2014-03-17 Bogdan-Andrei Iancu + * [6c0cdf3] : + Before DB flush, check if the DB connection was actually open (during failed starts, destroy may be triggered without having init done) -2012-10-26 13:14:59 Bogdan-Andrei Iancu, - * [9391] : - - fixed some editing errors.... +2014-03-17 Bogdan-Andrei Iancu + * [d244686] : + Fixed setting timeout (via script vars) for UAC transactions -2012-10-26 12:59:56 Bogdan-Andrei Iancu, - * [9388] : - - fixed mishandling of transport info in PATH module - Credits go to Nick Altmann - Closes bug 3578383 +2014-03-17 Bogdan-Andrei Iancu + * [b4bb68b] : + Forgotten file from commit 1db2fc (local route changes) Reported by Ovidiu Sas. -2012-10-26 12:38:10 Bogdan-Andrei Iancu, - * [9387] : - - fix bug: make the setup time configurable (via new module param and via runtime flags) for topo hiding scenarios, to avoid early timeouts (if setup takes too long). - Credits go to Nick Altmann - Closes patch 3574453 (for trunk version) +2014-03-17 Ovidiu Sas + * [40a34fb] : + drouting: fix compiler warnings - * may be used uninitialized in this function +2014-03-16 Bogdan-Andrei Iancu + * [1db2fc5] : -2012-10-25 23:11:49 Ovidiu Sas - * [9385] : + LOCAL Route support enhanced : - serial forking for UAC transactions added - possibility to use ONREPLY and FAILURE routes for UAC transactions - ability to use (transaction wise) AVPs, flags, timeouts - DNS based failover works now for UAC transactions (solving #140) - pi_http: add support for DB_BLOB +2014-03-15 Ovidiu Sas + * [75f1ed6] : + pi_http: run DB_UPDATE commands with prefilled values -2012-10-25 22:57:13 Ovidiu Sas - * [9384] : - pi_http: add support for DB_STRING +2014-03-13 Liviu Chircu + * [3f3d52d] : + drouting: update documentation with latest changes + * also fix some missing paragraph tags -2012-10-25 13:41:42 Vlad Paiu - * [9381] : +2014-03-13 Liviu Chircu + * [d24b10e] : - fixed hanged dialog issues for Cancels with To Tag + drouting: Rework of all "attributes" AVPs + * now exported at script level using optional function pvar parameters + * by default, they are not stored at all inside the transaction + * stored internally if pvars are given to do_routing|route_to_carrier|route_to_gw + * no additionally required module parameters + * NOT backwards-compatible +2014-03-12 Vlad Paiu + * [61e21a0] : -2012-10-25 13:41:31 Saúl Ibarra Corretgé - * [9380] : + Added support for embedded arrays within MongoDB documents - Avoid creating new outgoing TCP connections for NOTIFY requests - If a subscription dies don't attempt to create a new outging TCP - connection for sending in-dialog NOTIFY requests +2014-03-12 Vlad Paiu + * [2520b8a] : + For topo hiding and fix_route_dialog() usage, do not try do add del lumps for already deleted route headers + (cherry picked from commit 5a119db9031d6231c521367847bf1b3c1b6bb7a5) -2012-10-24 23:55:06 Ovidiu Sas - * [9379] : - pi_http: code cleanup and fix some error handling cases +2014-03-11 Liviu Chircu + * [e93234b] : + Merge branch 'master' of github.com:OpenSIPS/opensips -2012-10-24 11:14:17 Bogdan-Andrei Iancu, - * [9377] : +2014-03-11 Liviu Chircu + * [4b4ac96] : - - fixed creation of DR tables in postgres - Reported by Toine (SF) - Closing bug #3578406 + residential config: Also define the "xcap" db_url +2014-03-11 Razvan Crainea + * [ab80ade] : -2012-10-23 15:33:01 Saúl Ibarra Corretgé - * [9376] : + db_http: add value_delimiter parameter + Add a new parameter used to specify the fields delimiters for queries + variables - RLS: Fixed memory leak - xmlFree was used to free a document, instead of xmlFreeDoc +2014-03-11 Răzvan Crainea + * [112f504] : + Merge pull request #125 from rrb3942/index_trans + Add s.index and s.rindex transformations -2012-10-23 15:28:11 Saúl Ibarra Corretgé - * [9375] : - Fixed potential invalid pointer dereference +2014-03-10 Bogdan Andrei IANCU + * [1e02b32] : - Credits to BNML + Merge pull request #174 from wdoekes/wjd-fix_dialogaggr_memleak + presence_dialoginfo: Fix memory leak in dlginfo_agg_nbody. -2012-10-22 16:02:11 Saúl Ibarra Corretgé - * [9374] : +2014-03-10 Bogdan-Andrei Iancu + * [3c1164a] : - RLS: Fixed read overflow in list_insert + When updating the database records, first perform all update and inserts and then check the timeout for expired records -> records to be deleted. Doing first the delete may hide records "expired but to be updated". Credits go to Nick Altmann Closes bug #112. -2012-10-22 14:17:10 Saúl Ibarra Corretgé - * [9373] : +2014-03-10 Razvan Crainea + * [ec56716] : - Regenerated README files + tm: compute the timer set based on the fragments align -2012-10-22 13:49:19 Saúl Ibarra Corretgé - * [9372] : +2014-03-10 Razvan Crainea + * [ed31ed5] : - RLS: updated documentation + tm: prevent timer list overflow when using multiple timer procs -2012-10-22 13:41:25 Saúl Ibarra Corretgé - * [9371] : +2014-03-10 Razvan Crainea + * [67ced1c] : - Added myself as editor of some modules + dialog: only update timer if the timeout is set on current request -2012-10-22 13:32:07 Saúl Ibarra Corretgé - * [9370] : +2014-03-10 Razvan Crainea + * [ea19362] : - Relaxed check: expires is not mandatory in Subscription-State header + rtpproxy: properly unforce dialog when using engage -2012-10-22 13:28:41 Saúl Ibarra Corretgé - * [9369] : +2014-03-10 Razvan Crainea + * [ff18c53] : - RLS: Handle late NOTIFY to a terminated subscription dialog gracefully + rtpproxy: updated documentation for the setid and pvar changes -2012-10-22 13:22:31 Saúl Ibarra Corretgé - * [9368] : +2014-03-10 Razvan Crainea + * [6a213ed] : - RLS: update backend subscriptions when XCAP documents change + rtpproxy: properly store/fetch variables by engage - - rls_update_subscriptions command added - - Code adapted from the SIP-Router project +2014-03-10 Razvan Crainea + * [dbe4535] : -2012-10-22 13:16:51 Saúl Ibarra Corretgé - * [9367] : + rtpproxy: properly parse the bavp set - RLS: follow external references to resource-list elements - - Code adapted from SIP-Router project - - Fixed generating RLMI version number - - Following references to external domains / documents is not - implemented +2014-03-10 Razvan Crainea + * [26ed2fa] : + rtpproxy: removed the 'rtpp_sock_pvar' parameter + now all functions return the rtpproxy server used in the 4th optional + parameter -2012-10-21 17:48:38 Bogdan-Andrei Iancu, - * [9366] : - - bug fixed: if no interface explicitly set, select as outbound interface the interface the message was received rather than the interface served by the process. +2014-03-10 Razvan Crainea + * [2d4ce86] : + rtpproxy: allow functions to receive optional parameters -2012-10-21 16:03:38 Bogdan-Andrei Iancu, - * [9364] : - one more dependency added to deb packages (lua package) +2014-03-10 Razvan Crainea + * [b528acd] : + rtpproxy: remove set_rtp_proxy_set() function + The set_rtp_proxy_set() function has been completely remove. From now on, you + can specify the set directly in the rtpproxy comands. If not specified, the + default set is used. -2012-10-21 12:11:09 Bogdan-Andrei Iancu, - * [9362] : - - fixed missing dependencies in deb packages - Credits go to shimaore (SF id) - Closes bug #3577302 +2014-03-10 Razvan Crainea + * [ba80ddd] : + nathelper: remove unused nathelper.h header -2012-10-21 11:44:06 Vlad Paiu - * [9360] : - fixed crash at mod_destroy +2014-03-10 Razvan Crainea + * [6b3c22c] : + rtpproxy: allow unexisting set + Do not exit if a set is not found during startup, since it may be later on + loaded from database. -2012-10-21 08:50:09 Liviu Chircu - * [9359] : +2014-03-10 Razvan Crainea + * [b5fd777] : - Fixed a subtle bug in ds_count() and improved code readability + dialog: add $DLG_timeout pvar documentation -2012-10-19 19:03:08 Ovidiu Sas - * [9358] : +2014-03-10 Razvan Crainea + * [dc57fed] : - pi_http: fix typo for DB_UPDATE command + dialog: replace timeout_avp with $DLG_timeout + * removed the timeout_avp parameter + * added DLG_timeout pseudovariable for specifying dialog timeout +2014-03-10 Bogdan-Andrei Iancu + * [f001f09] : -2012-10-19 13:54:36 Saúl Ibarra Corretgé - * [9354] : + Added support for multiple timer processes in TM. The timer process may easyly become a bottleneck in TM because: (a) single lock on the timer lists, (b) single process to purge/free all transactions, (c) single process running all failure routes (with all script complexity of failure routes). This patch addresses all the above problems allowing multi-locking and multi-processing for the the overall timer concept in TM. Existing "own_timer_proc" module parameter extended from boolean value to an integer value : 0 - no separate timer proc for TM; 1 - one separate timer proc for TM; n - multiple timer procs for TM. - Fixed handling of terminated subscriptions in PUA and RLS - DB needs to be updated with the terminated state so that RLS can - use this information in the RLMI part os the RLS NOTIFY. +2014-03-10 Bogdan-Andrei Iancu + * [9314abb] : - Also don't immediately delete the subscription from the PUA to allow - the final NOTIFY to be processed. + Output the address of previous fragment when overwritten is detected (just better logging) -2012-10-19 13:42:14 Saúl Ibarra Corretgé - * [9351] : +2014-03-06 Walter Doekes + * [60716e8] : - Fixed handling PUBLISH with Expires: 0 + presence_dialoginfo: Fix memory leak in dlginfo_agg_nbody. + This commit fixes a couple of presence issues (introduced in 80c48e6): + * There was a memory leak in dlginfo_agg_nbody. + * Bounds checking in dlginfo_agg_nbody was off by 4 (potential stack + corruption). + * There were 2 PKG allocs, straight after one another while no alloc + was needed at all: reduced to 1 optional one. + * Replace "dumy" with "dummy" in the vicinity. - Send required NOTIFY requests after DB has been updated +2014-03-05 Liviu Chircu + * [9a801ba] : -2012-10-19 10:47:49 Liviu Chircu - * [9350] : + Remove 18KB worth of whitespace from all .c, .h and .cpp files - Fixed ds_ping_interval documentation and a compile warning. +2014-03-05 Liviu Chircu + * [1f47b10] : -2012-10-19 10:36:17 Vlad Paiu - * [9348] : + Fix various typos throughout documentation and code - fixed mem leak & run sync MI command under lock +2014-03-05 Liviu Chircu + * [15784be] : + statistics: fix compiler warning in 32-bit environments -2012-10-18 22:33:20 Ovidiu Sas - * [9347] : - Makefile.conf: add pi_http to the list of excluded modules +2014-03-05 Liviu Chircu + * [a1d61f3] : + Merge branch 'wjd-compile_warnings' of https://github.com/wdoekes/opensips into wdoekes-wjd-compile_warnings -2012-10-18 22:25:57 Ovidiu Sas - * [9346] : +2014-03-05 Razvan Crainea + * [f544472] : - pi_httpd: svn settings + config: skip optional parameters + when a parameter is not mandatory, you can skip it by adding the next comma. + For example: uac_replace_from(,"sip:robin@gotham.org") +2014-03-05 Vlad Paiu + * [5cf71c3] : -2012-10-18 22:24:22 Ovidiu Sas - * [9345] : + Fixed the lex for tcp_max_msg_chunks and tcp_max_msg_time - examples: set svn props +2014-03-05 Walter Doekes + * [f2e64f5] : + core: Fix pass_fd.c aliasing warnings by forcing proper packing. + Compiling pass_fd.c + pass_fd.c: In function ‘send_fd’: + pass_fd.c:132:2: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] + *(int*)CMSG_DATA(cmsg)=fd; + ^ + pass_fd.c: In function ‘receive_fd’: + pass_fd.c:240:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] + *fd=*((int*) CMSG_DATA(cmsg)); + ^ -2012-10-18 22:21:50 Ovidiu Sas - * [9344] : - pi_http: example config and xml interface layout file +2014-03-05 Walter Doekes + * [0b18a17] : + exec: Fix kill.c compile warnings by including . + Compiling kill.c + kill.c: In function ‘__popen’: + kill.c:129:2: warning: implicit declaration of function ‘pipe’ [-Wimplicit-function-declaration] + if (pipe(fds) != 0) { + ^ + ... -2012-10-18 22:20:11 Ovidiu Sas - * [9343] : +2014-03-05 Liviu Chircu + * [4aa4f49] : - pi_http: new module providing a simple db provisioning interface + rest_client: update documentation +2014-03-05 Liviu Chircu + * [15423bb] : -2012-10-18 18:21:21 Vlad Paiu - * [9342] : + rest_client: allow disabling of SSL remote host verifications + * with the new *ssl_verifypeer* and *ssl_verifyhost* modparams - added documentation for rev #9341 +2014-03-04 Liviu Chircu + * [277f587] : + stun: update documentation -2012-10-18 18:13:48 Vlad Paiu - * [9341] : - DB API allows to have multiple WHERE conditions sepparated by OR +2014-03-04 Liviu Chircu + * [d5f7ddf] : - Several performance improvements in the dialog module : + stun: add the option to specify advertised addresses and ports + * as an extension to the existing modparam strings - - the dialog module can be configured to have it's own timer process - - for the DLG_DELAYED db mode, the dialog deletion is done in the - timer process ( old way was deleting on the spot, wherever - that was, eg. SIP worker, MI process, etc ) - - dialog DB structure & usage was reworked, in order to only query - by the primary key for all select/delete/update ops - - added the option to do bulk dialog deletions in the dialog - timer process, in order to reduce the number of queries +2014-03-04 Ovidiu Sas + * [7c171aa] : + dispatcher: ds_select_dst/domain - fast emty slot detection -2012-10-18 10:07:11 Bogdan-Andrei Iancu, - * [9340] : - - if using FQDN is SIP URIs of destination, do SIP-wise DNS lookup to find all the IPs+ports behind that SIP URI. - - the bug was that FQDN entries without A record (but with NAPTR / SRV) were simply discarded at load time (because of DNS failure). +2014-03-04 Ovidiu Sas + * [650a60b] : + drouting: enforce route_to_gw() param parsing - no empty slots allowed inside GW list -2012-10-18 09:52:23 Bogdan-Andrei Iancu, - * [9338] : - - fixed storing the port of GWs (internally) - if GWs are defined via FQDN (subject to NAPTR/SRV lookups), a single GW may have multiple IPS with different ports -> ports needs to be an array also ! +2014-03-04 Ovidiu Sas + * [d809369] : + drouting: do not alter PVARs while scanning GW lists in route_to_gw() -2012-10-17 19:21:42 Razvan Crainea - * [9336] : - removed useless update of the dialog variables in db if flush flag is not set +2014-03-04 Ovidiu Sas + * [b3696d2] : + dispatcher: update documentation for ds_select_dst/domain -2012-10-17 17:59:35 Ovidiu Sas - * [9335] : - Makefile.defs: adding a note about the proper location of docbook.xsl on CentOS +2014-03-03 Ovidiu Sas + * [37f8774] : + dispatcher: add ability to dispatch over multiple dispatchng groups - ds_select_dst/domain can accept lists of comma separated values as parameters -2012-10-17 15:23:42 Liviu Chircu - * [9334] : +2014-03-03 Ovidiu Sas + * [671b81d] : - Added the ds_count() function, used to count the number of destinations in a given set - that share same properties (all active, all inactive+probing...). Refer to the module documentation - for further details. + core: add q_memrchr - faster memrchr version -2012-10-16 19:32:13 Bogdan-Andrei Iancu, - * [9332] : +2014-03-02 Liviu Chircu + * [9bfce00] : - -improved docs in how weight (for rules and carriers) should be used. - Suggested by shimaore. - Closes bug #3577322 + for-each statement completed + * final syntax: for ($var(it) in $(ct[*])) { ... } + * now works for any pvar which supports indexing + * current such pvars in OpenSIPS: $avp, $ct, $ct.fields, $branch, $hdr(xxx)) -2012-10-16 19:23:32 Bogdan-Andrei Iancu, - * [9329] : +2014-03-02 Liviu Chircu + * [c09c126] : - - fixed bug in waiting (by other opensips procs) for the startup route to be executed - - fixed triggering of startup route if no UDP interface was configured - Reported by Dragos Oancea - Closes bug #3577353 + Update .gitignore -2012-10-16 18:02:56 Ovidiu Sas - * [9328] : +2014-03-02 Liviu Chircu + * [cd93704] : - dialog: code cleanup (remove duplicate define for dlg_val_lock/dlg_val_unlock) - - dlg_val_lock is actualy dlg_lock_dlg from dlg_hash.h - - dlg_val_unlock is actualy dlg_unlock_dlg from dlg_hash.h + core: $hdrcnt should not be indexed +2014-03-02 Liviu Chircu + * [a5cd55b] : -2012-10-15 12:35:51 Razvan Crainea - * [9320] : + core: improve script_trace() performance with a wrapper macro - Fixed "used" and "real_used" statistics calculation +2014-03-01 Ovidiu Sas + * [0e37b92] : -2012-10-13 18:34:33 Ovidiu Sas - * [9319] : + mod_fix: return error for fixup_get_isvalue() if no int or str value is available - b2b_logic: fix removal of expired tuples while loading them from db +2014-03-01 Ovidiu Sas + * [3186e69] : + core: new function: str_trim_spaces_lr() - same as trim_spaces_lr() but without '0' padding -2012-10-13 17:28:37 Vlad Paiu - * [9317] : - properly increment the dialog failed stat +2014-03-01 Ovidiu Sas + * [08eb851] : + dispatcher: fix erroneous forced mode 0 introduced by previous commit -2012-10-13 13:39:59 Vlad Paiu - * [9316] : +2014-03-01 Liviu Chircu + * [aeb4e88] : - at startup, delete dialogs from DB which are in state 5 + Fix crash when printing $(ct[*]) +2014-03-01 Ovidiu Sas + * [2b64f2a] : -2012-10-13 00:41:43 Ovidiu Sas - * [9315] : + dispatcher: use a single helper function for all ds_select_dst/domain functions - pua_dialoginfo: enhancing error probe +2014-02-28 Ovidiu Sas + * [2049108] : + dispatcher: change signature for ds_select_dst - group all controlling params in a single structure -2012-10-12 12:48:41 Bogdan-Andrei Iancu, - * [9312] : - - fixed uninitialized array of timestamps used for collecting PKG mem stats. This may lead to bogus values on certain systems (where mem is not zero-ed by default). +2014-02-27 Ovidiu Sas + * [abf3947] : + mod_fix:fixup_get_isvalue - make sure that we have a valid string for int converision -2012-10-09 19:07:51 Ovidiu Sas - * [9311] : - httpd/mi_http: allign callback functions with the latest microhttpd API +2014-02-27 Ovidiu Sas + * [d15578c] : + dispatcher: enhance error probe - print dispatching id for unknown dispatching algorithm -2012-10-09 19:04:19 Ovidiu Sas - * [9310] : +2014-02-27 Liviu Chircu + * [52b6793] : - httpd: rework some probes + mod_fix: have commit 4e3b6b7c390a work on strings and pv_elem_t as well +2014-02-27 Ovidiu Sas + * [bf56024] : -2012-10-09 17:57:37 Saúl Ibarra Corretgé - * [9308] : + dispatcher: simplify ds_select_dst/domain params handling - Fixed boundaries check +2014-02-27 Ovidiu Sas + * [4e3b6b7] : -2012-10-09 17:53:45 Saúl Ibarra Corretgé - * [9307] : + mod_fix: fixup_get_isvalue - return the int value if possible - Fixed memory leak in agregate_presence_xmls - Since I'm here, also avoid copying a string since - xmlNewProp duplicates the string itself. +2014-02-27 Ovidiu Sas + * [bc4ccbe] : + dispatcher: reorganize the code by using a define -2012-10-09 10:45:48 Vlad Paiu - * [9304] : - Fixed the ordering of dialog unrefs +2014-02-26 Liviu Chircu + * [79bc8d7] : + tm: change the "fr_(inv_)?timer_avp" params into module vars + * namely $T_fr_timer and $T_fr_inv_timer + * simplifies the scripting logic (also prevents some errors) + * less CPU cycles, less mem usage + * documentation updated -2012-10-08 17:04:41 Razvan Crainea - * [9303] : +2014-02-26 Liviu Chircu + * [1d5e117] : - Enhanced the dispatcher module with a new dispatching algorithm, that allows - you to determine the load of a server by populating a specific variable. The - destinations will be tried in the ascending order of the loads. + Fix issue introduced in commit "23174d2629c" -2012-10-08 15:56:13 Razvan Crainea - * [9301] : +2014-02-26 Ovidiu Sas + * [ff6e145] : - prevent timer process from overlapping with MI ul_sync command + dispatcher: add ability to handle string PVs for ds_select_dst/domain -2012-10-08 14:07:44 Saúl Ibarra Corretgé - * [9298] : +2014-02-26 Liviu Chircu + * [23174d2] : - Fixed checking for memory type + dialplan: move the "attrs" pvar into the "dp_translate" param list + * simplifies the scripting logic + * more efficient - it is now a local option, as opposed to a global one - PKG_MEM_TYPE and SHM_MEM_TYPE are 0 and 1 respectively, - so do equality checks instead of bit operations +2014-02-26 Liviu Chircu + * [6da4e47] : -2012-10-08 13:36:21 Razvan Crainea - * [9297] : + registrar: Fix harmless compiler warning - Fixed AVPs in order to support generic PV parsing at runtime +2014-02-26 Ovidiu Sas + * [7870f22] : -2012-10-08 11:46:47 Razvan Crainea - * [9296] : + mod_fix: new helper fixup function that returns string and/or int value from a gparam_t - Allow exec functions to be executed in reply route +2014-02-24 Liviu Chircu + * [1ccdca4] : -2012-10-04 16:10:55 Bogdan-Andrei Iancu, - * [9294] : + Job timeout for the 'exec' module + * the "time_to_kill" parameter now works for all "exec_*" commands + * improved overall documentation and usage examples - - fixed creation / lookup of dynamic AVP maps. - Thanks for report and help in troubleshooting to Samuel Muller - Credits for the fix go to Razvan Crainea +2014-02-21 Bogdan-Andrei Iancu + * [aaa5f60] : -2012-10-02 14:57:52 Bogdan-Andrei Iancu, - * [9293] : + docs updated for route_to_gw() - silly me, forgot to commit the header file after the fix from yesterday (about module index on dynamic stats) +2014-02-21 Bogdan-Andrei Iancu + * [5232238] : -2012-10-01 16:44:29 Bogdan-Andrei Iancu, - * [9292] : + allow route_to_gw() to receive a list of gw IDs (instead of only one) - the list is a comma separated list of gw IDs - yet another fix in dynamic statistic - populate the correct module index +2014-02-20 Liviu Chircu + * [7637f58] : -2012-10-01 12:03:59 Bogdan-Andrei Iancu, - * [9291] : + Proper reporting for invalid module parameter types - - fix regarding the race condition in creating dynamic statistics - thanks to Razvan for testing this :) +2014-02-13 Bogdan-Andrei Iancu + * [57d60b6] : -2012-09-30 19:46:57 Bogdan-Andrei Iancu, - * [9290] : + improve docs - - fixed race condition on creating dynamic stats - same stat may be created in the same time from different processes. +2014-02-10 Ovidiu Sas + * [14c2630] : -2012-09-28 09:40:17 Bogdan-Andrei Iancu, - * [9289] : + cachedb_mongodb: complete previous commit - handle _id based queries - - fixed compile errors :D +2014-02-10 Ovidiu Sas + * [a6148b1] : -2012-09-27 17:58:08 Bogdan-Andrei Iancu, - * [9288] : + cachedb_mongodb: handle _id based queries - - the "stat" variables may accept in names any combination of strings and other variables -> dynamically named statistic variables. Ex: $stat(attempts_$var(gw_id)) +2014-02-10 Ovidiu Sas + * [4b48f18] : -2012-09-27 17:52:41 Bogdan-Andrei Iancu, - * [9285] : + cachedb_mongodb: fix sorting results for mongo queries - - fixed ugly bug in parsing the FMT string (combinations of variables with strings) - even if the string was passed as str (pointer+len), the internal code was still looking for null terminator :P... +2014-02-07 Ovidiu Sas + * [49a9f2a] : -2012-09-27 12:38:01 Bogdan-Andrei Iancu, - * [9284] : + cachedb_mongodb: retieve ObjectId _id as string - - fixed the evaluation of the name param (for update/reset stat functions) if a FMT is provided +2014-02-06 Ovidiu Sas + * [36fa3cc] : -2012-09-27 08:53:42 Liviu Chircu - * [9283] : + cachedb_mongodb: use constants for oip size - Fixed the cfgutils set_count() function issue, where script execution is stopped when returning 0 value. - The result is now obtained by passing a pvar as the 2nd parameter. +2014-02-06 Liviu Chircu + * [5d61f37] : -2012-09-24 12:57:16 Liviu Chircu - * [9282] : + Fix NULL pointer deref. in "acc_db_request" when "db_url" is not set - Added GPL headers and svn keywords to the recently added files. +2014-02-06 Ovidiu Sas + * [abdcbaf] : -2012-09-24 12:02:41 Liviu Chircu - * [9281] : + cachedb_mongodb: fix BSON_DATE conversion - dispatcher and load_balancer modules now support IP blacklisting based on the destination set/group. - Similar to the drouting blacklists, these will also be disabled by default when created. It is up to the script - writer to enable them with the 'use_blacklist' core function. +2014-02-05 Bogdan-Andrei Iancu + * [cdd3c51] : -2012-09-23 22:07:26 Bogdan-Andrei Iancu, - * [9280] : + Fixed bogus test over the presence of a request route. This was generating bogus warning messages to the logs, but without any negative impact over the actual processing. Credits go to rrb3942 on GITHUB Closes issue #162 - - fixed bug in storing the name of a dynamically created statistic +2014-02-05 Ovidiu Sas + * [5bdd706] : -2012-09-21 15:10:36 Bogdan-Andrei Iancu, - * [9279] : + dispatcher: enhance MI ds_list command - print socket if set - print attr if set - -removed some useless TYPE +2014-02-05 Bogdan Andrei IANCU + * [7949175] : -2012-09-21 14:50:59 Bogdan-Andrei Iancu, - * [9278] : + Merge pull request #164 from wdoekes/wjd-allow_domain_in_digest_user + digest+m_auth: Allow a domain in the digest username. - - added dynamic statistics - anytime you are trying to write (update/reset) a statistic which does not exists, it will be automatically created at runtime (without any pre-definition). +2014-02-05 Walter Doekes + * [3b66855] : -2012-09-21 11:32:26 Bogdan-Andrei Iancu, - * [9277] : + digest+m_auth: Allow a domain in the digest username. + Before this patch, a domain in the digest username was allowed: - - merge $stat() from core into $stat() from statistics module. - $stat() is able to cope with dynamic stats (which will be created at runtime) - - update / reset statistics functions can take the name of statistic as variable, FMT or string + Digest username="abc@domain", realm="domain" + but only if the domain is equal to the realm. This was introduced in + a92bf789 (Juha Heinanen, Mar. 29 2006). -2012-09-21 09:51:49 Bogdan-Andrei Iancu, - * [9274] : + The SIP spec. doesn't mention any such restriction. - fixed the way the tcp conn is looked up when a new timeout is test. - Special thanks to Saúl Ibarra Corretgé in testing this fix. + This patch undoes that commit and makes sure the whole username is used + when authenticating through `pv_www_authorize` and `pv_proxy_authorize`. + That makes the following valid: + Digest username="abc@domain", realm="something different" -2012-09-20 16:29:09 Liviu Chircu - * [9273] : - Recent changes (removing the match_len column) have led to a rework of the index hashing. - It is now done based on a caseless hashing of the rule match string, and not by its length. - Consequently, the matching string length is no longer a rule choosing criterion. +2014-02-04 Ovidiu Sas + * [11db9b8] : - From now on, the primary criterion for chosing a dp rule is the rule's priority. The - first matching rule, out of matching rules with same priority, is chosen (table order). + dispatcher: fix crash at shutdown with incorrect table version +2014-01-30 Liviu Chircu + * [707982e] : -2012-09-20 10:28:33 Bogdan-Andrei Iancu, - * [9270] : + Fix "mf_process_maxfwd_header" retcode in case of parsing errors - fixed the list of chars that does not have to be escaped in URI username and URI param - aligned with the RFC3261 requirements. - Credits go to Rick van Rein. +2014-01-28 Ovidiu Sas + * [76d2499] : -2012-09-19 18:08:04 Bogdan-Andrei Iancu, - * [9269] : + dialog: print dialog start and timeout in human readable format (MI) - added new variable $stat(name) which allow you to read via variable interface any statistic value +2014-01-28 Ovidiu Sas + * [45d660d] : -2012-09-19 17:39:53 Vlad Paiu - * [9268] : + pua_dialoginfo: documentation updates - Added openssl multithreading needed callbacks for locking and process identifier - Should fix ugly bugs related to mem corruption when running TLS +2014-01-28 Ovidiu Sas + * [188b2e7] : + pua_dialog_info: failed calls should not trigger PUBLISH errors - related to Issue #142 -2012-09-18 17:01:45 Razvan Crainea - * [9266] : - fixed linking errors for architectures that don't support TCP keepalive +2014-01-28 Ovidiu Sas + * [51b5195] : + pua: define constants for send_publish return codes -2012-09-18 16:31:17 Vlad Paiu - * [9265] : - Added support for Insert query buffering for manual accounting done from the script - Credits to Ryan Bullock +2014-01-27 Ovidiu Sas + * [f10288b] : + dialog: do not print missing to tag error for final replies in DLG_STATE_UNCONFIRMED -2012-09-17 13:55:05 Liviu Chircu - * [9262] : +2014-01-21 Vlad Paiu + * [ce35927] : - Fixed a bad return code in the db_do_insert function. + Added new flag to is_from_gw/goes_to_gw , 'c' , which will push the respective carrier ID to the carrier_id_avp AVP -2012-09-17 11:38:10 Bogdan-Andrei Iancu, - * [9260] : +2014-01-15 vladpaiu + * [11a74d7] : - fixed load/reload behaviour - if a destination is bogus (bad URI, cannot be resolved, etc), it is simply skipped, but do not fail the entire loading. + Merge pull request #160 from rrb3942/localcache_counter_expire + Do not reset counter expiration on incr/decr -2012-09-17 09:38:44 Bogdan-Andrei Iancu, - * [9258] : +2014-01-15 Bogdan-Andrei Iancu + * [adc3aaa] : - - fixed crash in multi-body parsing if delimiter not present - Reported and fix by Ryan Bullock - Closes bug 3566409 + "Interrupted system call" on "select" must not be reported as error/warning -2012-09-13 12:53:18 Razvan Crainea - * [9256] : +2014-01-14 Razvan Crainea + * [e8195fc] : - Allow asynchronous exec_msg function to receive parameters + properly print statistics while running "-V" -2012-09-13 12:51:54 Razvan Crainea - * [9255] : +2014-01-10 Ryan Bullock + * [4eed903] : - removed drouting blacklist error when no gateways are defined in a specific group + Do not reset counter expiration on incr/decr -2012-09-12 13:05:07 Liviu Chircu - * [9254] : +2014-01-10 Liviu Chircu + * [5685379] : - enum_query can now also receive avp string parameters + Merge pull request #144 from shimaore/mathops_extension + Mathops extension: new RPN expression parsing function -2012-09-12 12:59:59 Razvan Crainea - * [9252] : +2014-01-10 Liviu Chircu + * [6c06594] : - removed stun error generated for EINTR signal + Correct an error message -2012-09-12 12:49:04 Bogdan-Andrei Iancu, - * [9250] : +2014-01-10 Bogdan Andrei IANCU + * [09500ab] : - - do not attempt to set ATTRS AVP if not defined - Reported by Diego Barberio + Merge pull request #158 from nikbyte/master + Fixed bugs with processing m4 in fedora init scripts -2012-09-12 12:44:53 Bogdan-Andrei Iancu, - * [9247] : +2014-01-10 Nick Altmann + * [4f10a57] : - several fixes related to timer route: - * set a valid SIP URI for the dummy SIP request that is used when triggering the timer routes -> this will avoid errors on parsing; - * cleanup the dummy SIP request after each execution, do discard whatever parsing/changes done in timer routes -> this avoid mem leaks - * cleanup the list of AVPs affter each execution -> this avoids inheriting AVPs between the calls of the route (or even worst, between sequential calls of the differen timer routes) + Fixed bugs with processing m4 in fedora init scripts -2012-09-11 19:31:04 Razvan Crainea - * [9245] : +2014-01-06 Bogdan-Andrei Iancu + * [934fa69] : - fixed exec module documentation typo + Fixed copy'n'paste error in the state flushing routine. Reported by Stéphane Alnet (shimaore) Closing issue #154 -2012-09-09 10:01:58 Vlad Paiu - * [9243] : +2013-12-30 Bogdan-Andrei Iancu + * [7565996] : - backport from 1.8 (rev #9242) + Fixed crash when dr_state_flusher() (via timer) may be called before data is loaded (by first SIP worker) Credits go to shimaore on GITHUB - fixed some Solaris related issues - Reported by Nathaniel L Keeling III +2013-12-20 Saúl Ibarra Corretgé + * [e4a334e] : + mediaproxy: fixed detecting messages without a body -2012-09-03 13:32:33 Liviu Chircu - * [9241] : - Removed match_len column from the dialplan table. - Added the match_flags column. 0 (default) for case sensitive, 1 for case insensitive matching. +2013-12-20 Saúl Ibarra Corretgé + * [359db7f] : + mediaproxy: always parse To header -2012-09-01 14:45:15 Bogdan-Andrei Iancu, - * [9239] : +2013-12-17 Ovidiu Sas + * [54a22de] : - -more updated on route permissions + scripts/opensipsctl: nicer output for 'trap' if opensips is not running -2012-09-01 14:37:21 Bogdan-Andrei Iancu, - * [9238] : +2013-12-17 Ovidiu Sas + * [55bde1d] : - - allow routing function from LOCAL_ROUTE + Makefile.conf.template: add newline at end of file -2012-09-01 14:33:23 Bogdan-Andrei Iancu, - * [9237] : +2013-12-16 Ovidiu Sas + * [9d25d0c] : - -added new function "dr_is_gw( uri, [type, [flag]])" to test a generic SIP URI if points to a GW - Contributed by Nick Altmann - -some cleanup in allowed routes for the DR functions - -a bit of restructuring of code to merge all functions testing "if is a GW" - is_from_gw / goes_to_gw / dr_is_gw + opensipsctl: new command 'trap' - useful to get a full bt dump of all opensips processes - handy in dead-lock investigatigations -2012-08-31 17:48:47 Razvan Crainea - * [9236] : +2013-12-15 Bogdan-Andrei Iancu + * [0ecaccb] : - enhanced b2b_bridge mi function with an optional parameter that permits - injecting provisional media in bridging scenario + Fixed bogus triggering of PUBLISHing for non-INVITE sequential requests. Credits go to Damien Sandras Closes pull request #149 + (cherry picked from commit e0cc9d009151a086f42c08d7f8092b8c7d5835ed) -2012-08-31 14:28:24 Razvan Crainea - * [9234] : +2013-12-15 Bogdan Andrei IANCU + * [6b6be30] : - db_flatstore: do not start unless the directory database exists + Merge pull request #150 from staskobzar/master + opensipsctl is calling ds_relaod for dr instead of dr_reload -2012-08-28 10:26:42 Saúl Ibarra Corretgé - * [9231] : +2013-12-15 Stas Kobzar + * [da687c5] : - Fixed memory leak in nat_traversal + opensipsctl is calling ds_relaod for dr instead of dr_reload - Bug report and fix by David Sanders +2013-12-11 Ovidiu Sas + * [017e0c0] : -2012-08-27 10:39:39 Vlad Paiu - * [9230] : + scripts: db files for b2b_sca module - backport from 1.8 (rev #9229) - fixed ds_is_in_list to set the proper attrs avp +2013-12-11 Ovidiu Sas + * [b1cd8a5] : + db/schema: xml files for b2b_sca module -2012-08-24 16:01:12 Vlad Paiu - * [9228] : +2013-12-11 Ovidiu Sas + * [29e1b28] : - in case counter not found in cassandra, treat as value 0 + b2b_sca: new module providing SCA functionality +2013-12-11 Vlad Paiu + * [d4e8c03] : -2012-08-24 13:55:38 Bogdan-Andrei Iancu, - * [9227] : + Re-formatted the dlg_list_ctx output + Added extra intermediary nodes for the dlg values and profiles in order to avoid key duplication for certain MI output formats ( eg. xml, json ) - - docs updated for the latest changes over save() function +2013-12-11 Razvan Crainea + * [0935742] : -2012-08-24 13:27:32 Bogdan-Andrei Iancu, - * [9226] : + fixing the '\b' hexa representation for dialog vals + Thanks go to Walter Doekes for reporting on IRC - - added the Enn (max_expires) and enn (min_expires) params to save() function. This will allow to pass different values for the expire range for the registred contacts - Credits go to Nick Altmann - Closes patch ID #3556883 +2013-12-11 Razvan Crainea + * [0d47a32] : -2012-08-23 11:09:58 Liviu Chircu - * [9225] : + remove bogus flushing for mi_json + TODO: find a proper way for handling flushing, since the current + implementation leads to a infinite loop - Added a new MI command: list_all_profiles +2013-12-11 Razvan Crainea + * [28b399b] : -2012-08-20 16:33:27 Vlad Paiu - * [9223] : + mi_json: escape '\\' character + also fix incorrect '"' escaping - use many supercolumns instead of a single one - faster +2013-12-11 Razvan Crainea + * [9df9872] : + properly fix the dialog values escaping for nonascii chars -2012-08-17 14:13:27 Vlad Paiu - * [9222] : - backport from 1.8 ( rev #9221 ) +2013-12-10 Liviu Chircu + * [c8f47c8] : - fixed some warnings ( -Wunused-but-set-variable ) - reported by Ovidiu Sas + Fix compile warnings when defining -DDBG_LOCK +2013-12-09 Razvan Crainea + * [9eacde3] : -2012-08-16 20:47:38 Bogdan-Andrei Iancu, - * [9218] : + fixed dialog dlg_vals printing + Also encode DEL (0x7f) character since it does not print properly at the + console - - fixed bogus NULL test resulting in compiling warnings - Reported by Ovidiu Sas +2013-12-07 Bogdan Andrei IANCU + * [8988cdb] : -2012-08-15 13:23:26 Vlad Paiu - * [9214] : + Merge pull request #138 from secusmartChris/master + Feature request #77 fulfilled - - enhanced the CacheDB interface - sepparate function to fetch counters from the back-ends - - added new core function, cache_counter_fetch, that maps over the new CacheDB exported function -- adapted all cachedb_* modules to the new interface - - adapted all modules using the CacheDB interface to proper fetch the counters - - added Cassandra Counter support ( you can now have distributed Load-Balancing, Ratelimiting, etc over Cassandra ) - - made Cassandra less noisy when fetching keys that don't exist +2013-12-07 Bogdan Andrei IANCU + * [1076300] : + Merge pull request #135 from bat-modulis/master + Renamed permissions parameter 'from_col' to 'pattern_col' -2012-08-15 13:09:51 Bogdan-Andrei Iancu, - * [9213] : - port from branch 1.8 (rev 9212) - -fixed compatibility with Solaris (on data types) - Credits go to Nathaniel L Keeling +2013-12-07 Bogdan Andrei IANCU + * [ef43e3d] : + Merge pull request #129 from dsandras/ds-pua-expires-refresh-fix + Fix bug where a new publication does not extend the desired expire time. + (cherry picked from commit ccac0fac1da8ad663e500148fb7f7d9e43e34fd1) -2012-08-15 12:33:10 Bogdan-Andrei Iancu, - * [9210] : +2013-12-06 Bogdan-Andrei Iancu + * [012ad21] : - - before a new ds_select_xx(), purge all avps used for failover (avoid inheriting avps from a prev ds_select()) - - remove some useless conditions as now all AVP are defined - Reproted by Ovidiu Sas + Fixed keeping DB conn open in the process doing shutdown Fixed bug in memory handling (size and init) -2012-08-15 11:04:57 Di-Shi Sun - * [9208] : +2013-12-06 Bogdan-Andrei Iancu + * [89b8ffb] : - Added SIP 401 Unauthorized support. + At shutdown, do not attempt to use the DB conn if not opened. -2012-08-15 11:04:09 Razvan Crainea - * [9207] : - ratelimit: removed concurrency issues between pending pipes +2013-12-06 Bogdan-Andrei Iancu + * [1f18541] : + Generate proper branch param for the NAT ping requests Credits go to Varun (varunvairavan on GITHUB) Closes #145 -2012-08-14 15:16:32 Bogdan-Andrei Iancu, - * [9204] : - fixed crash on using both C and F flags in do_routing. - Reported by Parantido Julius De Rica - Closes bug report #3557317 +2013-12-06 Bogdan-Andrei Iancu + * [d0086df] : + Fixed bogus condition in GT, GTE, LT and LTE script tests. Reported by dcb314 on GITHUB Closing issue #146 + (cherry picked from commit 96921f5f90919bdc3dc1a573bcb0c32899c65075) -2012-08-14 12:43:15 Liviu Chircu - * [9202] : - Fixed setid_pvar parsing. +2013-12-06 Razvan Crainea + * [6adb5c3] : + fixed compile error when statistics are not enabled + Thanks to Liviu Chircu for reporting them -2012-08-13 18:52:00 Ovidiu Sas - * [9200] : - httpd: fix documentation - - thanks to Duane Larson for pointing this out +2013-12-06 Liviu Chircu + * [21f543d] : + Fix a couple of potential deadlocks in commit b30b43b4 -2012-08-09 18:31:36 Vlad Paiu - * [9199] : +2013-12-05 Bogdan-Andrei Iancu + * [b30b43b] : - backport from 1.8 (rev #9198) + Rework the reload part - use readers/writers locking for ensure safe and efficient reload. - fixed the trimming of whitespaces while parsing lb resources +2013-12-03 Răzvan Crainea + * [f93bbd3] : + fixed doc avp names -2012-08-09 18:25:25 Vlad Paiu - * [9196] : - search_dlg_profile() is properly aware of cached profiles - needed for distributing load balancer resources +2013-12-03 vladpaiu + * [9a807b8] : + Merge pull request #141 from shimaore/db_http_timeout_doc + Corrected db_http example: the timeout is an integer. -2012-08-08 23:38:04 Vlad Paiu - * [9195] : +2013-12-02 Razvan Crainea + * [8587e79] : - backport from 1.8 (rev #9194) + sort the db_berkeley and dbtext version entries + this makes further updating easier, since the entries are no longer in a + random entry. Moreover, they can be easily followed in the file. - fixed bogus CDRs in case of combining internally terminated dialogs and db_extra_bye +2013-12-02 Razvan Crainea + * [177fe84] : + drouting: properly update the drouting versions -2012-08-08 18:10:18 Bogdan-Andrei Iancu, - * [9192] : - fixed bogus contact string building (introduced in commit 9165) +2013-12-02 Razvan Crainea + * [f25c8e1] : + drouting: fix drc_table doc default value -2012-08-08 17:29:58 Bogdan-Andrei Iancu, - * [9189] : - fix for properly frees resources allocated to the columns in the db_oracle module (prevents memory leakage) - Credits go to Peter Lemenkov - Closes patch 3540105 +2013-12-02 Bogdan-Andrei Iancu + * [bd1b78e] : + Updated DB schema for dispatcher in order to reflect latest changes (state persistency) -2012-08-08 17:21:12 Bogdan-Andrei Iancu, - * [9186] : - fix in setting the data type for empty values -> you still have the type before returning - Credits go to Peter Lemenkov - Closes patch 3538362 +2013-12-02 Bogdan-Andrei Iancu + * [3583ab2] : + Added persistency for the state of the destinations : (1) persistency across opensips restart, via DB amd (2) persistency across reloads. -2012-08-08 17:12:05 Bogdan-Andrei Iancu, - * [9183] : - fixed copy past error resulting in bogus jump to last row. - Credits go to Peter Lemenkov. - Closes patch #3538358 +2013-12-02 Bogdan-Andrei Iancu + * [d2facc3] : + State of the destination is persistent across reloads. -2012-08-08 17:04:55 Bogdan-Andrei Iancu, - * [9180] : - - fixed improper zeroing of a memory within db_res_t (in db_oracle module) - Credits go to Peter Lemenkov - Closes patch 3538355 +2013-12-02 Vlad Paiu + * [0625610] : + Properly take into account the dialplan priority in case entry matches both string and regex rules -2012-08-08 00:31:39 Bogdan-Andrei Iancu, - * [9177] : - - fix LB restore issue - dialog profiles are not properly restored in LB - Credits go to Marcel Barbulescu +2013-12-02 Vlad Paiu + * [adebbe6] : + For dialog pvars, we don't actually need a SIP msg in order to evaluate -2012-08-07 23:50:23 Bogdan-Andrei Iancu, - * [9174] : - - fixed segfault in case of an empty db connection string - Credits go to Peter Lemenkov - Closes patch 3545893 +2013-12-02 Vlad Paiu + * [11e393a] : + For db_extra & db_extra_bye params, create dummy SIP message in case we have NULL msg, in order to allow the evaluation of PVARs that don't actually need the SIP msg ( eg. $DLG_end_reason ) -2012-08-07 23:38:28 Bogdan-Andrei Iancu, - * [9171] : - - fixed missing init of lock - Reported by David Sanders - Closes patch 3554950 +2013-11-30 Stephane Alnet + * [2776156] : + Rebuilt README -2012-08-07 23:29:34 Bogdan-Andrei Iancu, - * [9169] : - - fixed reseting dialog flags (from script) when calling create_dialog() multiple times - Credits go to Ryan Bullock - Closes patch 3553765 +2013-11-30 Stephane Alnet + * [d823932] : + Corrected typos. -2012-08-07 22:29:01 Bogdan-Andrei Iancu, - * [9166] : - - fixed forcing of lifetime for TCP connections - Credits go to Yaroslav M Strilchuk - Closes bug #3546167 +2013-11-30 Stephane Alnet + * [be2ce6f] : + Built README -2012-08-05 12:44:39 Anca Vamanu, - * [9165] : - For URI inserted in Contact header consider the advertised address set in the listen directive. +2013-11-30 Stephane Alnet + * [a87b2af] : + Mathops extensions + Add a new `math_rpn` function, and capacity to add new operators when using the RPN parser. + New operators (RPN only): `exp`, `floor` -2012-08-01 18:28:16 Vlad Paiu - * [9163] : - CDR ACC works even if DLG is internally terminated +2013-11-28 Ovidiu Sas + * [c631abc] : + pua_dialoginfo: do not blindly load all dialogs - only dialogs with "dlg_peer" vals should be registered for callbacks -2012-08-01 17:48:23 Vlad Paiu - * [9160] : +2013-11-28 Răzvan Crainea + * [25289f0] : - propagate direction(downstream/upstream) info to local_route when internally terminating the dialog + Merge pull request #139 from shimaore/pkg_mem_events + Allow for `event_pkg_threshold` support. + Credits go to Stéphane Alnet (shimaore) -2012-07-31 17:03:39 Vlad Paiu - * [9157] : +2013-11-28 Razvan Crainea + * [609c81c] : - fixed ugly bug - reset blacklists only when processing a new SIP message + sipmsgops: prevent remove_hf from removing header twice + closes #137 +2013-11-28 Razvan Crainea + * [1ed8107] : -2012-07-31 15:12:50 Vlad Paiu - * [9155] : + Merge branch 'dialog-vars-fix' + Conflicts: + scripts/db_berkeley/opensips/version + scripts/dbtext/opensips/version - fixed deadlock due to bad ordering of lock acquiring - Thanks to Ryan Bullock for reporting & helping with debugging +2013-11-28 Razvan Crainea + * [62d644e] : + dialog: hexa representation for dlg_list_ctx binary values -2012-07-30 18:57:58 Bogdan-Andrei Iancu, - * [9153] : - fixed the avp_add_last() function - the kept shortcut (last_avp) was not properly updated during delete ops, and may have bogus value (pointed to freed AVPs). As code is complex, simply removed that shortcut +2013-11-28 Razvan Crainea + * [6c7e9c7] : + dialog: update dialog dbschema -2012-07-26 13:54:37 Razvan Crainea - * [9149] : - fixed 'subnet_dump' mi command to output the correct netmask +2013-11-28 Razvan Crainea + * [36b533b] : + dialog: dialog variables should be blob -2012-07-17 17:41:16 Liviu Chircu - * [9148] : - Added auto_bridging warning at rtpproxy module startup. +2013-11-28 Razvan Crainea + * [0aec9af] : + dbtext: generate blob instead of string for binary columns -2012-07-17 13:57:42 Vlad Paiu - * [9146] : - added missing break for BITMAP values +2013-11-27 Razvan Crainea + * [4c1fb5d] : + event_xmlrpc: pass parameters as struct + Added a new parameter that allows the possibility to send the event parameters + as XMLRPC structures, instead of simple values. -2012-07-16 15:10:57 Liviu Chircu - * [9145] : +2013-11-27 Vlad Paiu + * [144e112] : - Added multiple table support to the dialplan module. - The exported "dp_translate" and the mi "dp_translate" functions now - support "example_table/dpid" types of parameters, along with - the old "dpid" ones. The rules will be loaded from the specified - table. The default table is still dialplan. + fixed README typo -2012-07-12 06:53:25 Di-Shi Sun - * [9144] : +2013-11-27 Razvan Crainea + * [fae8dc3] : - Fixed SIP 3xx Contact header format issue caused by revision 8921. + dbtext: fix newline typo -2012-07-06 18:50:43 Bogdan-Andrei Iancu, - * [9140] : - fix init of "model" in fixup function of h350_auth_lookup() +2013-11-27 Razvan Crainea + * [0636a00] : + dbschema: fix tmp file usage in makefile -2012-07-06 16:32:11 Vlad Paiu - * [9138] : - properly increment the active dialogs statistic when calling the dlg_db_sync MI command +2013-11-26 Stephane Alnet + * [2c1af18] : + Corrected db_http example: the timeout is an integer. -2012-07-06 13:04:23 Razvan Crainea - * [9136] : +2013-11-26 Stephane Alnet + * [e86bf5d] : - fixed dialog hash_size normalization + Allow for `event_pkg_threshold` support. + PKG_MEM is not defined or use anywhere else in the code, so assuming `PKG_MALLOC` is meant here. -2012-07-06 12:02:40 Vlad Paiu - * [9133] : +2013-11-26 Christian Lahme + * [9394e0a] : - when saving dialog flags in DB for the first time, do not save the DLG_FLAG_NEW + Added IFDEF to ensure TLSv1.2 is only used when openssl >= 1.0.1 is used +2013-11-26 Christian Lahme + * [2383515] : -2012-07-04 11:49:33 Di-Shi Sun - * [9132] : + Feature request #77 fulfilled - Fixed release source reporting issue. -2012-07-03 12:01:52 Vlad Paiu - * [9130] : +2013-11-26 Ovidiu Sas + * [40962ce] : - fixed DB type inconsistency - Credits to Peter Lemenkov + pua: set db_flag to UPDATEDB_FLAG only if there was a previous update (NO_UPDATEDB_FLAG) - in case of a server restart, if the db_flag went from INSERTDB_FLAG to UPDATEDB_FLAG the record will be lost because the record is marked as to be updated, and since there's no record in the db, the update will fail. - if the db_flag is INSERTDB_FLAG, any updates should leave the flag as is and this will cause the new record to be properly inserted (and not updated) into the db. +2013-11-24 Bogdan-Andrei Iancu + * [4e51f8d] : -2012-07-03 11:34:52 Vlad Paiu - * [9129] : + STEP 3 - flushing changes in GW/CARRIER's state back to DB (periodically and at shutdown) ; preserve the state of GWs/CARRIERs during reload. - Reset column types to NULL upon freeing resultset columns - Credit to Peter Lemenkov +2013-11-24 Bogdan-Andrei Iancu + * [253704e] : + Updated DB schema to reflect the changes in the DR module (adding persistency for carrier/gateway's state and sockets for gateways) -2012-07-02 18:22:09 Razvan Crainea - * [9128] : - modified 'count_init_children' to allow filtering by process flags +2013-11-24 Saúl Ibarra Corretgé + * [a802488] : + Load xcap module, presence_xml depends on it -2012-06-28 12:34:21 Razvan Crainea - * [9125] : - Fixed the case when leg integers could overwrite the extra integers buffer +2013-11-24 Saúl Ibarra Corretgé + * [002b43f] : + Fixed residential example when using presence -2012-06-27 14:54:47 Vlad Paiu - * [9122] : - fixed double profile linking when sync-ing memory with DB +2013-11-23 Bogdan Andrei IANCU + * [175f853] : + Merge pull request #122 from dsandras/ds-fix-dialog-info-entity + This patch fixes the entity URI in XML documents to contain "sip:". + (cherry picked from commit 377e7574d411aa974cf469d6df18b6213b43a31f) -2012-06-27 12:55:13 Razvan Crainea - * [9121] : +2013-11-22 Bogdan Andrei IANCU + * [8c64901] : - Fixed NICER variable + Merge pull request #131 from dsandras/ds-pua-mi-warning-fix + Fixes bug where a refreshed PUBLISH request triggers an error message. + (cherry picked from commit ded0559c527f30181e9bbd494f0e63b048059108) -2012-06-27 12:11:16 Vlad Paiu - * [9119] : +2013-11-22 Bogdan Andrei IANCU + * [3cf2c68] : - added support for DB_BIGINT when populating AVPs + Merge pull request #133 from shimaore/add-callid-to-ul_mi + Add `callid` field to information returned by the `ul` module's MI. +2013-11-22 Bogdan-Andrei Iancu + * [cfb8457] : -2012-06-26 16:40:11 Ovidiu Sas - * [9116] : + Fixed bogus warning because of variables not being reset. Reported by Jeff Pyle, part of fixing issue #126. - db_oracle: typo fixes - - closes bug id: 3535168 +2013-11-22 Liviu Chircu + * [f456377] : + Ignore all cscope database files -2012-06-26 16:32:09 Ovidiu Sas - * [9115] : - packaging/fedora: adding missing opensips.tmpfiles.conf +2013-11-22 Ovidiu Sas + * [f9a8d98] : + uac_registrant: re-register with expires value imposed by the registrar -2012-06-26 16:09:54 Ovidiu Sas - * [9114] : +2013-11-22 Liviu Chircu + * [f90e347] : - packaging/fedora: Improve packaging for Fedora/RHEL and derivatives - - closes bug id: 3535148 + Fix the DB representation of message flags in the acc module + * storing flags as strings rather than bitmasks prevents flag conflicts + when doing flag modifications in the script, then restarting the proxy + * similar usrloc issue was fixed in commit 98b6b0437 +2013-11-22 Liviu Chircu + * [0845069] : -2012-06-26 12:16:51 Anca Vamanu, - * [9111] : + Add the "remove" script function to the registrar module + * remove(domain, AOR[, target]]) + * explicitly remove contacts behind specific addresses-of-record + * may delete contacts by Contact URI or by domain + * domains are resolved before they are matched - Fixed memory leak in xcap auth doc processing +2013-11-22 Liviu Chircu + * [9d5889b] : -2012-06-25 17:39:16 Anca Vamanu, - * [9109] : + Add the SIP-wise determined "next_hop" field to ucontact_t + * based on Path -> Received -> Contact (decreasing priorities) + * URIs are parsed only at contact creation + * useful for the nathelper SIP pinging routine and domain-based lookups + * compatible with all DB modes, no extra DB columns required - Restore display names from DB. ( reported in #3535379 ) +2013-11-22 Razvan Crainea + * [7401a7a] : -2012-06-20 14:25:29 Vlad Paiu - * [9108] : + revert commit ec0d05a + dialog variables might be binary, therefore strlen should not be used - DLGCB_REQ_WITHIN gets called for all requests received in early state, not just for PRACK +2013-11-20 Bogdan-Andrei Iancu + * [b279e17] : + Do not free the header string as it is part of the lumps (and freed together with the lumps). Reported by Jeff Pyle. Fixing bug #126 -2012-06-20 14:07:27 Vlad Paiu - * [9107] : - treat PRACK the same as ACK ( do not register CB for replies ) +2013-11-20 Bogdan-Andrei Iancu + * [a0ba76e] : + Fixed keeping turns on handling PUBLISHes for the same presentity - when presentity is deleted (due a unPUBLISH) do not do any turn related ops anymore Reported by Damien Sanders -2012-06-19 17:14:30 Bogdan-Andrei Iancu, - * [9104] : +2013-11-20 Bogdan-Andrei Iancu + * [3d33b3b] : - - fixed the setting of domain_suffix_avp module paramter - Credits go to Yaroslav M Strilchuk - Closes bug 3535422 + Step 2: use the socket info during routing to GW -2012-06-19 16:16:39 Vlad Paiu - * [9103] : +2013-11-20 Vlad Paiu + * [24f9366] : - search_dlg_profile() is aware of cached profiles and properly checks their existance - Credits to Lirakis + Reset the lump cond flags when the condition evaluates to false. + In case there are multiple branches, the conditions can evaluate + differently on each branch - which might lead to bad counting of the + added lumps ( used by the dialog module for dlg validation ) +2013-11-20 Vlad Paiu + * [b4b3517] : -2012-06-19 15:46:31 Razvan Crainea - * [9102] : + Added exec_threshold parameter to cachedb_* modules in order to be able to track slow queries - fixed some gcc 4.7 warnings +2013-11-20 Bogdan-Andrei Iancu + * [cc657ff] : -2012-06-19 11:00:18 Vlad Paiu - * [9101] : + Fixed restoring SOCKET info from AVP during failover - added 'i' flag to is_from_gw() and goes_to_gw() that populates the gateway ID into an AVP +2013-11-20 Bogdan-Andrei Iancu + * [fdfc71d] : + Step 1 in enhancing drouting: - GW - load state and outbound sokcet from database - carriers - load state (as separate field) from database - cleanup - remove the avp "type" as no longer used (work in progress) -2012-06-14 17:13:59 Vlad Paiu - * [9100] : - fixed compile warning +2013-11-20 Ovidiu Sas + * [f7dac99] : + httpd: remove bogus error log -2012-06-14 11:55:06 Vlad Paiu - * [9098] : +2013-11-19 Baptiste Cholley + * [4f285d1] : - removed call to ns_get16 glibc private function - Credits to Peter Lemenkov + Renamed parameter 'from_col' to 'pattern_col' +2013-11-17 Liviu Chircu + * [c4b8be1] : -2012-06-14 10:27:16 Vlad Paiu - * [9095] : + Mask compile-time shift/reduce conflict due to if statement ambiguity - fixed documentation - Thanks to James Gledhill for reporting +2013-11-16 Stephane Alnet + * [6408bd7] : + Add `callid` field to information returned by the `ul` module's MI. + This allows e.g. to retrieve the information even when using a memory-only store. -2012-06-13 13:12:07 Bogdan-Andrei Iancu, - * [9092] : - fixed setting the destination of request after next_branch() used a branch with PATH - Reported by Gomtesh Jain +2013-11-15 Razvan Crainea + * [5852895] : + when joining two frags, only the used memory changes -2012-06-13 09:58:29 Di-Shi Sun - * [9091] : - Updated to handle device erases '=' from BYE route header case. +2013-11-15 Razvan Crainea + * [27197fa] : -2012-06-12 17:43:03 Ovidiu Sas - * [9088] : + memory statistics can be used only if stats are on - b2b_logic: fix extra headers passing to the other side of the call +2013-11-15 Razvan Crainea + * [a8bdfa8] : + rework ratelimit distributed queries + instead of adding -1 to the counter, use the cachedb_sub function exported by + the cachedb module. This prevents ratelimit counters from adding extremely + large values for some backends (ex: memcached). + Thanks go to Brett Nemeroff for reporting and testing. -2012-06-12 11:17:46 Razvan Crainea - * [9087] : - replaced nh_sockets table with rtpproxy_sockets in opensipsdbctl and osipsconsole +2013-11-12 Ryan Bullock + * [ba22d03] : + Add s.index and s.rindex transformations -2012-06-11 21:15:51 Bogdan-Andrei Iancu, - * [9085] : - - fixed example in documentation - Closes bug 3534375 +2013-11-08 Ovidiu Sas + * [cae7f80] : + core: set proper identification label for timer procs - check labels via 'ps' MI command -2012-06-07 11:12:18 Vlad Paiu - * [9082] : - fixed typo when restoring dialog info +2013-11-07 Liviu Chircu + * [2418f37] : + Fix bogus comma when printing an AVP array with $(avp(foo)[*]) -2012-06-06 13:35:58 Bogdan-Andrei Iancu, - * [9080] : +2013-11-05 Razvan Crainea + * [26d9adc] : - - fixed bug in computing the RURIs for the next GWs to be tried (if more than one) - Reported by Ovidiu Sas + removed Makfile.conf from versioning -2012-06-05 16:25:13 Razvan Crainea - * [9078] : +2013-11-05 Razvan Crainea + * [2055db5] : - fixed memory leak when getting shared profiles size + menuconfig reads from template if config does not exist -2012-06-05 14:36:35 Vlad Paiu - * [9077] : +2013-11-05 Razvan Crainea + * [2cdf24f] : - in case contact has no sock, use the SIP msg rcv address for generating GRUUs + separate file for the original Makefile.conf + The original Makefile.conf is now found in Makefile.conf.template. This + prevents merge conflicts while updating the Makefile.conf +2013-11-05 Vlad Paiu + * [cbe8d24] : -2012-06-05 14:30:28 Vlad Paiu - * [9076] : + Rebuilt mi_json README - increased dev version +2013-11-05 vladpaiu + * [fefa37c] : + Merge pull request #121 from shimaore/mi_json + mi_json documentation: corrected typo and XML translation problem -2012-06-05 14:21:50 Vlad Paiu - * [9075] : - fixed indentation - fixed compiler warning +2013-11-05 Stephane Alnet + * [fff5c39] : + mi_json documentation: corrected typo and XML translation problem -2012-06-05 12:00:07 Vlad Paiu - * [9073] : +2013-11-04 Vlad Paiu + * [52405e6] : - Added regular expressions transformation. So far, only re.subst available + Added mi_json module README +2013-11-04 Vlad Paiu + * [afa15e3] : -2012-06-05 09:56:14 Razvan Crainea - * [9071] : + If commands accepts parameters, doesn't mean they are mandatory Leave it to the MI function to decide if it's ok to have empty params - fixed previous commit related to dbtext schema generation (rev #9069) +2013-11-04 vladpaiu + * [7339345] : -2012-06-04 13:27:43 Saúl Ibarra Corretgé - * [9070] : + Merge pull request #119 from shimaore/mi_json + mi_json module (new module) - Fixed calculating diversion header length +2013-11-04 Bogdan-Andrei Iancu + * [02f983d] : -2012-06-01 14:43:36 Razvan Crainea - * [9069] : + Proper usage of build_req_buf_from_sip_req() function - socket and proto are required. Closes Bug 664 on SF. - fixed dbtext schema generation for tables without version +2013-11-04 Vlad Paiu + * [92a2c9d] : -2012-06-01 12:47:00 Razvan Crainea - * [9068] : + Allow drouting module to be used for DID matching only ( where you only have prefixes provisioned, no GWs, and call do_routing with the 'C' flag ) - updated dbschema for the new rtpproxy_sockets table +2013-11-04 Vlad Paiu + * [43de2d8] : -2012-06-01 12:35:16 Vlad Paiu - * [9067] : + rebuilt the cachedb_couchbase documentation to reflect the recent changes - updated rtpproxy readme +2013-11-04 vladpaiu + * [4d1736d] : + Merge pull request #106 from rrb3942/couchbase + Switches to LCB_SYNCHRONOUS. Enables better reconnect support with command retry as well as a lazy_connect option. -2012-06-01 12:31:36 Razvan Crainea - * [9066] : -renamed all rtpproxy nh_* MI commands and dable table to rtpproxy_* +2013-11-04 Vlad Paiu + * [f59fef0] : + Support returning the new value from cache_add/cache_sub Credits to rrb3942 -2012-06-01 11:56:52 Vlad Paiu - * [9065] : - Added a new flac to nat_uac_test, that checks if port in contact is different from port at signaling level - Credits to Nick Altmann +2013-11-04 Vlad Paiu + * [5635d71] : + Do proper return code to script from cachedb_* functions ( treat 0 as success ) -2012-05-30 19:07:17 Saúl Ibarra Corretgé - * [9064] : +2013-11-04 Vlad Paiu + * [3738a7c] : - Extended add_diversion function with uri and counter parameters - * URI indicates the URI to be put in the header, if missing - the original (unchanged) RURI will be used. - * Counter indicated the amount of diversions that occurred, - as expected by PSTN gateway vendors + Added Redis Raw query capability -2012-05-30 17:44:29 Ovidiu Sas - * [9061] : +2013-11-01 Razvan Crainea + * [bbdd474] : - uac_auth: fix authentication for multiple qop tokens - - closes bug ID: 3530076 + event_rabbitmq: added heartbeat parameter doc +2013-11-01 Răzvan Crainea + * [a6090ec] : -2012-05-29 13:57:56 Vlad Paiu - * [9060] : + Merge pull request #100 from franklyfox/1.9_rabbitmq_heartbeat + enable rabbitmq heartbeat to solve issues of hanging SIP processing because of a broken amqp socket - added nameaddr.params transformation that returns the entire parameter list +2013-11-01 Bogdan Andrei IANCU + * [34df519] : + Merge pull request #111 from csollet/rfc6598 + nat_uac_test() : Add support for Shared Address Space (RFC 6598) -2012-05-29 11:37:34 Bogdan-Andrei Iancu, - * [9058] : - - patch to use the 4.8 version when installed, which ought to be the case when your opensips-berkeley-module package is used. It also takes 4.7 into consideration. - Credits go to Rick van Rein @ OpenFortress +2013-11-01 Vlad Paiu + * [043606a] : + Also trace the CANCEL requests in case we're doing trace_dialog() + (cherry picked from commit 50463f044c5bd42eb5485cac52419a8ec45ee201) +2013-11-01 Stephane Alnet + * [7f5019b] : + mi_json documentation -2012-05-25 22:21:45 Ovidiu Sas - * [9056] : - opensipsctl: fix registrant command +2013-11-01 Stephane Alnet + * [0263804] : + Modified httpd to support `application/json` for our purposes. -2012-05-25 22:21:10 Ovidiu Sas - * [9055] : +2013-11-01 Stephane Alnet + * [90b909a] : - uac_registrant: several fixes - - allow empty sockets - - keep sending REGISTER requests while in WRONG_CREDENTIALS_STATE + mi_json: simplify datasets + Also rewrote the string handling code. +2013-10-31 Stephane Alnet + * [c1d6f19] : -2012-05-25 20:36:26 Anca Vamanu, - * [9052] : + libmicrohttpd5 is no longer in Debian/testing - Fix bug #3529746: allow both and subnodes under node. +2013-10-31 Stephane Alnet + * [ece1322] : -2012-05-25 20:17:47 Anca Vamanu, - * [9051] : + Initial code, copied over from mi_xmlrpc_ng, with output changed to JSON. + The input is statically set to the "which" command. - Fix in scenario interpretation: if a client node has a destination subnode, consider it a new client. +2013-10-30 Ovidiu Sas + * [57e6092] : -2012-05-24 16:01:40 Ovidiu Sas - * [9048] : + core: enhance error log for un-parsable msg by adding the source IP and port - scripts: adding registrant to the list of EXTRA_MODULES +2013-10-29 Bogdan-Andrei Iancu + * [c5b2030] : + Use proper locking function (via the generic locking API) Reported by Max E. Reyes Vera Juarez. -2012-05-24 15:50:56 Ovidiu Sas - * [9047] : - qos: fix crash when the qos list is empty +2013-10-29 Bogdan-Andrei Iancu + * [adfe53f] : + Re-install dlg callbacks (for restoring FROM/TO hdr) upon re-loading dialogs on startup. Reported by Jeff Pyle. -2012-05-22 18:37:11 Ovidiu Sas - * [9045] : +2013-10-24 csollet + * [9af4953] : - menuconfig: fix FreeBSD include headers + nat_uac_test() : Add support for Shared Address Space (RFC 6598) 100.64.0.0/10 address block is processed like any RFC 1918 blocks +2013-10-23 Bogdan Andrei IANCU + * [d2c84e7] : -2012-05-22 18:30:56 Ovidiu Sas - * [9044] : + Merge pull request #109 from rrb3942/shutdown_segfault + Reset prepared statement between query lists on shutdown - Makefile: make should be called through $(MAKE) - - fix freebsd install +2013-10-23 Bogdan-Andrei Iancu + * [aa61cec] : + Fixed the weight-based balancing alg. Credits go to Rob Gagnon (rgagnon24) -2012-05-17 15:55:31 Vlad Paiu - * [9041] : - add by default 0666 permissions to fifo file +2013-10-23 Bogdan-Andrei Iancu + * [582a949] : + Proper support for BIGINT (as long) in the db_text SQL driver. Many thanks to Jeff Pyle for reporting and troubleshooting this. -2012-05-17 10:04:19 Saúl Ibarra Corretgé - * [9038] : +2013-10-22 Bogdan-Andrei Iancu + * [fbab4a8] : - Regenerated README for presence_xml + Removed "auto" flag for the dlg_id in DB_TEXT spec file Reported by Jeff Pyle. -2012-05-17 09:53:13 Saúl Ibarra Corretgé - * [9037] : +2013-10-22 Bogdan-Andrei Iancu + * [2739d12] : - Fixed PIDF body aggregation + README files regenerated from XMLs -2012-05-17 04:13:27 Di-Shi Sun - * [9036] : +2013-10-20 Ryan Bullock + * [a24848f] : - Updated sample configuration file for sipmsgops module. + Reset prepared statement between query lists on shutdown -2012-05-16 19:16:34 Ovidiu Sas - * [9033] : - b2b_logic: removing b2bl_key_avp - - closes bug 3515395: B2B_LOGIC - b2bl_key_avp +2013-10-20 Ryan Bullock + * [83e6399] : + Revert "Reset prepared statement between query lists on shutdown" + This reverts commit 1a070015f4cffe612d3a3cb3a66e864d7374db04. -2012-05-16 16:50:45 Vlad Paiu - * [9031] : +2013-10-20 Ryan Bullock + * [1a07001] : - for TLS & SCTP, it is not enough to set a compile time flag, but some env vars must also be set, to signal to the Makefile to include the related sources for compilation + Reset prepared statement between query lists on shutdown +2013-10-18 Liviu Chircu + * [1b12e26] : -2012-05-15 18:41:34 Bogdan-Andrei Iancu, - * [9027] : + Scripting enhancement: for-each statement - syntax: for ($var(it) in $avp(array)) { ... } - faster than the "while"-based equivalent loop - currently only allows iterating over an avp's values - -fixed bug if VIA1 has no branch param - Credits go to Nick Altmann - Closes #3519386 +2013-10-18 Bogdan-Andrei Iancu + * [bd0952d] : -2012-05-15 18:36:13 Bogdan-Andrei Iancu, - * [9025] : + Fixed bad prototype for abort when compiling with TM_TIMER_DEBUG. Reported by Mayama Takeshi Closes issue #105 - removed testing debug :D +2013-10-18 Bogdan-Andrei Iancu + * [47a3386] : -2012-05-15 18:19:08 Bogdan-Andrei Iancu, - * [9024] : + Fixed locking on purging profiles for terminated dialogs - in strange cases of concurancy between provisional and final replies, the profile ops for provisional reply may end up iterating on a deleted list. Reported by Trevor Francis (46labs) Closes issue #102 - removed old debugging code (served it purpose :D ) +2013-10-18 Bogdan-Andrei Iancu + * [9ceb0c0] : -2012-05-15 18:07:21 Bogdan-Andrei Iancu, - * [9022] : + Fixed accepting "after" changes in lumps attached to the beginning of a del lump Reported by NicK Altmann Solves issues with missing Route hdrs when using the dialog based TH - - fixed in the CANCEL generated by b2b on parallel forking - the missing REASON hdr was added back (lost via commit 8875) - Reported by Ovidiu Sas - Closes bug #3516488 +2013-10-17 Liviu Chircu + * [62cadee] : -2012-05-15 17:10:14 Bogdan-Andrei Iancu, - * [9020] : + Enhance usrloc with the binary replication feature - 3 additional module parameters - extra parameter in some usrloc_api functions - properly works with all DB modes - -fixed bug in incomplete init of fake FROM / TO / CALLID headers. - Reported by Nick Altmann +2013-10-17 Razvan Crainea + * [72ab3f4] : -2012-05-15 16:38:28 Bogdan-Andrei Iancu, - * [9019] : + fix ratelimit memory corruption - - fixed important bugs: - 1) the order of using the GW (based on carrier/rule list) - 2) some carrier info was not removed during failover - Reported by Ovidiu Sas. +2013-10-15 Ryan Bullock + * [b51b980] : -2012-05-15 13:30:42 Bogdan-Andrei Iancu, - * [9017] : + Switches to LCB_SYNCHRONOUS. Enables better reconnect support with command retry as well as a lazy_connect option. - -fixed prefix AVP calculation when using prefix-less rules - Reported by Ovidiu Sas - Closes bug 3526649 +2013-10-15 Ovidiu Sas + * [8689767] : -2012-05-11 17:49:28 Vlad Paiu - * [9015] : + uac_auth: fix memory leak reported by Jeff Pyle - affected modules: b2b_entities, uac, uac_registrant - reset carriers list pointer on freeing routing info +2013-10-16 Bogdan-Andrei Iancu + * [1abc835] : + Make pv_parse_format() more verbous on reporting the causes to fail. Reported by peppolon on IRC -2012-05-11 12:01:45 Vlad Paiu - * [9013] : - call DLG_REQ_WITHIN cb for PRACKs as well - Credits to Ryan Bullock - Closes bug #3525729 +2013-10-15 Liviu Chircu + * [268803b] : + Merge branch 'master' of github.com:OpenSIPS/opensips -2012-05-09 18:28:52 Bogdan-Andrei Iancu, - * [9010] : +2013-10-15 Liviu Chircu + * [0dc6524] : - - fixed buffer overflow in via transformation - Credits go to Walter Doekes - Closes bug 3525039 + Minor binary interface improvements - better debugging on receive operations - improve readability with a couple of macros -2012-05-09 18:19:53 Bogdan-Andrei Iancu, - * [9008] : +2013-10-15 Di-Shi Sun + * [4145040] : - -fixed some table constraints (unique and null) for dr tables + 1. Added support for appending parameter string in outbound URI. 2. Removed skip plus feature for called number. -2012-05-09 17:35:39 Bogdan-Andrei Iancu, - * [9005] : +2013-10-10 Liviu Chircu + * [3a334c3] : - - fixed inconsistence in www_auth() paramters - the function should allow the auth username to be passed as param, in a similar way the proxy_auth() function does. + Allow NULL strings to be pushed into binary interface packets -2012-05-09 17:04:43 Razvan Crainea - * [9004] : +2013-10-10 Liviu Chircu + * [101ee78] : - event_xmlrpc fix compile warning for unused function + Fix a particular startup crash + e.g. when defining only 1 tcp interface while specifying + "disable_tcp=true" -2012-05-09 13:26:22 Vlad Paiu - * [9002] : +2013-10-07 vladpaiu + * [6ce4321] : - avoid double init of DB connections - fixes bug #3524799 + Merge pull request #85 from earlruby/master + Changed -lcurses to -lncurses +2013-10-07 Vlad Paiu + * [ec0d05a] : -2012-05-09 10:25:03 Vlad Paiu - * [9000] : + Fixed the re-loading of dlg vars after restart Credits to Nick Altmann - pass RR headers even for provisional replies. requests within early dialogs should still follow the route set, although it's not definitive - Thanks to Ryan Bullock for reporting - Fixes bug #3523408 +2013-10-07 Vlad Paiu + * [b200e11] : + Fixed topology_hiding("U") in case of no username in Contact header Credits for report & fix to Nick Altmann -2012-05-09 05:01:01 Di-Shi Sun - * [8999] : - Updated documentation. +2013-10-06 Norm Brandinger + * [8dbef29] : -2012-05-07 17:32:01 Ovidiu Sas - * [8995] : + route.c - correct spelling - mi_http: fix URL parsing +2013-10-05 Norm Brandinger + * [de01e4c] : + dialog module - correct spelling in documentation -2012-05-07 17:07:33 Vlad Paiu - * [8993] : - init dialog MI process, to be used by dlg_db_sync +2013-10-04 liviuchircu + * [d54a04c] : + Fix duplicated code in db_virtual -2012-05-07 13:58:33 Bogdan-Andrei Iancu, - * [8992] : +2013-10-04 franklyfox + * [8c21659] : - - added more debug logs to ensure that the information is consistent + enable rabbitmq heartbeat to solve issues of hanging SIP processing because of a broken amqp socket + This implementation enabled the rabbitmq's client side's heartbeat negotiation. + Issue: + Because of TCP's nature, it takes very long time for a TCP peer to make the decision of closing a local socket when the connection actually is broken. The event_rabbitmq module didn't handle the situation which causes the Opensips1.9 stop processing UDP packets until the O.S decides to close the local socket. One of the consequence is that UAC cannot register to the registrar during this time period. + Issue Reproduce: + 1. Block an existing amqp connection from the rabbitmq-server that event_rabbitmq module connects to. + 2. From the event_rabbitmq side, the UDP receive-buffer that Opensips uses should be full. + Solution: + If the module, even_rabbitmq/rabbitmq-client, doesn't get a heartbeat message from the rabbitmq-server within X seconds, the rabbitmq-client will kill the local socket connection actively. -2012-05-07 12:36:10 Razvan Crainea - * [8989] : + Added a modparam: - Added XMLRPC client implementation for Event Interface + modparam("event_rabbitmq", "heartbeat", [X seconds] -2012-05-07 11:24:05 Razvan Crainea - * [8987] : +2013-10-04 Bogdan-Andrei Iancu + * [bdf49e0] : - fixed dialog crash while shutdown when using shared profiles + Fixed is_mod_func_used() (used from is_script_func_used()) to determin if a function is used from script - we need to follow the IF / WHILE / MODULE set of instructions too. Reported by Mayama Takeshi - many thanks for the detailed report on this. Closes issue #98 -2012-05-04 19:31:45 Bogdan-Andrei Iancu, - * [8984] : +2013-10-04 Bogdan-Andrei Iancu + * [2ca05d9] : - - added a NOTE into docs about using the force_send_socket() function in multihomed setups. - Closes bug #3517393 + In DELAYED mode, flush vars & profile to DB at ACK time too - no timer tick between 200 OK and ACK was droping the update operation to DB. Please note that this "bug" had actually no implications, as dialog data is either used from memory cache, either from DB after a restart (and a shutdown flushes everything to DB). Related to issue #97. -2012-05-04 19:22:46 Bogdan-Andrei Iancu, - * [8983] : +2013-10-03 Bogdan-Andrei Iancu + * [d990644] : - - in order to fix the inconsistency of the return code , new flag was added to do_routing() - "C" = only check the prefix without routing. - Closes bug #3522687 + handle the signals while waiting for the startup route to end (if not, the main proc will never know if the child running startup route crashed and it will hang for ever during startup) -2012-05-04 16:49:44 Bogdan-Andrei Iancu, - * [8980] : +2013-10-03 Bogdan-Andrei Iancu + * [00b8b63] : - - more fixing on how the addresses are defined - Related to bug id 3519665 + Merge branch 'master' of github.com:OpenSIPS/opensips -2012-05-03 10:18:46 Vlad Paiu - * [8977] : +2013-10-03 Bogdan-Andrei Iancu + * [b341dde] : - -D command line parameter should have priority over cfg file fork directive - Closes bug #3522964 + Fixed the un-initialized "reason" string when certain headers are missing Fixed reported "invalid" code on maxforrward missing (closes Issue #95) +2013-10-03 Vlad Paiu + * [7ad1db2] : -2012-05-03 10:01:58 Vlad Paiu - * [8975] : + Fixed menuconfig errors when selecting mi_xmlrpc vs mi_xmlrpc_ng - fixed parsing of pvars - Closes bug #3522966 - Credits to Arnaud +2013-10-03 liviuchircu + * [39119d1] : + Properly load contact flags even when NAT pinging is disabled -2012-05-01 05:58:18 Ovidiu Sas - * [8973] : +2013-10-03 liviuchircu + * [bfcc635] : - drouting: do not shm_free NULL pointers + Fix unpatched assignment in commit b33d4b3f +2013-10-03 Bogdan-Andrei Iancu + * [af195e9] : -2012-04-30 02:58:43 Di-Shi Sun - * [8971] : + Merge branch 'master' of github.com:OpenSIPS/opensips - Updated sample configuration file. -2012-04-25 11:04:49 Vlad Paiu - * [8968] : +2013-10-03 Bogdan-Andrei Iancu + * [7ccddbe] : - do not delete contact from mem if DB delete fails + - doc examples fixed Reported by "miha" on IRC +2013-10-02 liviuchircu + * [286f06f] : -2012-04-24 14:00:21 Vlad Paiu - * [8966] : + "registered" must also populate the 'attr' avp, if defined - added disable_gruu parameter to globally disable GRUU handling +2013-10-01 franklyfox + * [62ce85f] : + enable rabbitmq heartbeat to solve processes hang by amqp socket -2012-04-24 13:19:29 Vlad Paiu - * [8964] : - check supported header before attempting to generate GRUUs. sip.instance is not enough, as it is also part of RFC 5626 outbound +2013-10-01 liviuchircu + * [c229d98] : + Fix some documentation typos -2012-04-24 12:50:35 Bogdan-Andrei Iancu, - * [8962] : +2013-10-01 liviuchircu + * [5bcab39] : - - if a GW or carrier is not found, do not drop the entire carrier or rule definition -> just skip the invlaid element ! + Fix missing GPL headers in event_xmlrpc module -2012-04-24 12:23:21 Bogdan-Andrei Iancu, - * [8959] : +2013-09-27 liviuchircu + * [f2b283d] : - - fixed how the GW addresses are stored in DR when the GW definition contains "sip:" or "sip:" - Reported by Ovidiu Sas - Closes bug #3519665 + Fix invalid pointer when fetching the usrloc extra info column -2012-04-24 11:04:21 Razvan Crainea - * [8958] : +2013-09-25 Earl C. Ruby III + * [7ae769d] : - permit ratelimit functions in FAILURE, TIMER and BRANCH routes + The latest Linux distros from OpenSUSE, Fedora, and other non-Debian based distros no longer add symlinks for libcurses.so -> libncurses.so. Trying to compile menuconfig with -lcurses will not work on these distros, so I changed -lcurses to -lncurses, since -lncurses will work on any modern Linux distro with the ncurses5 libraries installed. + See http://stackoverflow.com/questions/1517756/whats-the-difference-between-lcurses-and-lncurses-when-compiling-c-using-ncur for more info. -2012-04-23 18:28:25 Vlad Paiu - * [8955] : +2013-09-25 Bogdan-Andrei Iancu + * [8fbdcc4] : - fixed bug where params len was not set in case the last parameter had a value + - fixed double free when building insert fails (in buffered insert mode) Reported by Brett Nemeroff +2013-09-25 Bogdan-Andrei Iancu + * [3559383] : -2012-04-23 14:14:39 Razvan Crainea - * [8953] : + - fixed overflow in parsing the content len value Reported by franklyfox on GITHUB Closing issue #78 - fixed ratelimit rl_check documentation +2013-09-20 Bogdan Andrei IANCU + * [5c3bcaa] : -2012-04-20 18:05:58 Vlad Paiu - * [8951] : + Merge pull request #69 from dsandras/ds-try-naptr2 + Added new dns_try_naptr option. - additional fix related to previous commit - content type body must be parsed before using it +2013-09-20 Bogdan Andrei IANCU + * [615a36e] : -2012-04-20 17:45:51 Bogdan-Andrei Iancu, - * [8950] : + Merge pull request #73 from wdoekes/wjd-pua_min_expires_doc + pua.c sets int min_expires= 300, not 0 as documentation states. - port from 1.8 (rev #8949): - - fixed validation of SDP in sip_validate() function - try to validate SDP only if application/sdp is advertised. +2013-09-20 Bogdan-Andrei Iancu + * [7938941] : + - fixed updating the index of the last DEL operation - this is essential for deciding which lumps must be skipped (as overlapping with delete parts of the message) Credits go to Nick Altmann for reporting and helping with troubleshooting. Closes issue #79 -2012-04-20 11:24:06 Bogdan-Andrei Iancu, - * [8947] : - - fixed handling of Replace header in REFER methods - if the dialog to be replaced by REFER is not found in b2b, simply do not change it. +2013-09-17 Damien Sandras + * [c5a57a8] : + Fix PUA module so that it sends a final PUBLISH on expiration. + A final PUBLISH with expires=0 is now generated when a publication has + expired. This will trigger the transmission of a final state NOTIFY. -2012-04-17 10:32:18 Razvan Crainea - * [8944] : - fixed AVP parsing in mod_init +2013-09-16 liviuchircu + * [ba04cba] : + Fix evi crash when defining more than 10 events -2012-04-16 21:14:15 Vlad Paiu - * [8941] : - fixed crash in freeing lumps - Closes bug #3516738 +2013-09-04 Bogdan-Andrei Iancu + * [98330c7] : + - UAC module does not load (no dependency) on UAC_AUTH if the uac_auth() function is not used. - UAC module does not load RR and DIALOG (with further dependencies on the params of those modules) if no FROM/TO replace ops are done. -2012-04-12 16:40:24 Bogdan-Andrei Iancu, - * [8939] : +2013-09-04 Bogdan-Andrei Iancu + * [99b233a] : - - fixed functionality bug - during changes from 1.7 to 1.8, the DR module cannot select a signle destination per carrier/set (as the alg 2 in 1.7) - A new flag (0x02) added to carrier flags to say if only the first gw (depending on the sorting order) is to be used. - Reported by Brett Nemeroff + - new functions added to help a module to check if its functions are used from the script (we cannot rely on the fixup functions as we have functions without parameters or need for fixup). Such function is needed for fixing dependencies between modules (to follow up) -2012-04-12 16:16:23 Bogdan-Andrei Iancu, - * [8937] : +2013-09-04 liviuchircu + * [6f048e0] : - - fixed mishandling of the third params of do_routing() - - fixed crash when the second param is not define - Reported by Trevor Francis on IRC - Credits go to Vlad Paiu + Fix: allow rest_client functions in onreply_route + Credits to Jayesh Nambiar for reporting -2012-04-12 13:19:25 Vlad Paiu - * [8935] : +2013-09-04 Bogdan-Andrei Iancu + * [01db912] : - fixed mem leak - free carriers as well + - fixed CANCEL matching in B2B +2013-09-04 Bogdan-Andrei Iancu + * [bb2313d] : -2012-04-11 18:00:43 Ovidiu Sas - * [8933] : + - Gracefully detect if the uac_auth modules is available for usage in b2b_entities modules - do not through an error message but rather an info one, as find the uac_auth module is optional. - httpd: ignore EINTR signal +2013-09-04 Bogdan-Andrei Iancu + * [ea44068] : + - when starting the FR timer, it should not override any previous setting of a FR or FR_INV timers. Solves Issue #25 (reported and troubleshooted by Mayama Takeshi) when a very fast 100 reply may stop retransmissions, but brake the updating of fr timer from FR to FR_INV state. -2012-04-11 17:30:18 Vlad Paiu - * [8931] : - added Makefile.conf as dependency for compiling modules +2013-09-03 Bogdan-Andrei Iancu + * [ec82ef8] : + - fixed how lumps can overlap on the edge - an "add" just next to a "delete" Reported by Saul Ibarra Corretge Closes issue #59 -2012-04-11 15:03:28 Bogdan-Andrei Iancu, - * [8929] : +2013-09-03 Bogdan-Andrei Iancu + * [6dd4b76] : - - more fixes on how to properly fake the internally generated replies, in order to allow lump operations on the replies - Reported by Nick Altmann - Closes bug #3515834 + - fixed incomplete function call (resulted from the merged commit 09a291e) -2012-04-10 19:05:01 Bogdan-Andrei Iancu, - * [8927] : +2013-09-03 Bogdan Andrei IANCU + * [31a7aa2] : - - fix default value for routeid in dr_route - have NULL as default value for it. - Related to bug report #3516034 + Merge pull request #62 from dsandras/ds-dialoginfo-notifications-fixes + Fixed RFC 4235 notifications compliance. -2012-04-10 17:42:47 Vlad Paiu - * [8924] : +2013-09-03 Damien Sandras + * [515b790] : - fixed STUN memory leaks + Added new dns_try_naptr option. + The rationale behind this is that many stacks do not implement NAPTR + correctly and rely only on DNS SRV. With misconfigured DNS servers, it + can lead to useless lookups generating potentially long delays. + This can now be disabled if not needed. -2012-04-09 17:32:43 Bogdan-Andrei Iancu, - * [8921] : +2013-09-03 liviuchircu + * [b33d4b3] : - - fixed the building of Contact hdr in case of redirect replies - the URIs must be enclosed between angle brackets as they may contain parameters ; and without enclosing, the URI params will become header params - Reported by Stefan Tobe + Fix several usrloc named flag issues + - fix get_all_db_ucontacts() lookup logic to work with named flags + - fix "Cflags" row of MI *ul_dump* command + - fix DB contact update function to properly store the flags -2012-04-09 11:31:54 Razvan Crainea - * [8918] : +2013-09-02 liviuchircu + * [5a63dcd] : - Added two new MI commands for the Event Interface: - * events_list - lists all available events - * subscribers_list - lists all subscribers for a particular event + Fix replication of dialog delete events + - instead of sending "deleted" packets based on hash delete operations, + they are now sent when a dialog changes state to "DLG_STATE_DELETED" + - this prevents the receiving instance from replicating the event again -2012-04-09 11:23:45 Vlad Paiu - * [8917] : +2013-08-30 Bogdan-Andrei Iancu + * [5e33750] : - backport from 1.8 (rev #8915) + - fixed NULL sockets in external scenarios (this leads to crashing when building the contact hdr) Reported by dexteruk on IRC . - fixed readme +2013-08-30 liviuchircu + * [6f82449] : + Fix compilation issue introduced in commit a9fcd84c -2012-04-09 11:14:02 Razvan Crainea - * [8916] : - fixed dialog MI response typo +2013-08-29 Bogdan Andrei IANCU + * [3eb2a54] : + Merge pull request #68 from wdoekes/wjd-fix_nathelper_memleak + Fix memleak in nathelper natping when "failed to fetch contacts". -2012-04-04 20:07:24 Ovidiu Sas - * [8914] : - packaging/debian: update dependency req for http modules +2013-08-29 liviuchircu + * [20c9245] : + Fix replicated dialog profile management in distributed systems + - replication-receiving instances must not do any profile-related + DB queries -2012-04-04 13:52:09 Vlad Paiu - * [8908] : +2013-08-29 Bogdan Andrei IANCU + * [50117fb] : - save message flags back in the transaction after running local route + Merge pull request #58 from saghul/pua_double_free + Fixed double free issue in pua module +2013-08-29 Saúl Ibarra Corretgé + * [9da5524] : -2012-04-03 14:20:37 Razvan Crainea - * [8904] : + Fixed double free issue in pua module + Also fix a couple of related memory leaks - Added mi flush support for rl_list mi function - Closes bug #3506254 +2013-08-28 Bogdan-Andrei Iancu + * [5fb6bb8] : -2012-04-03 11:39:52 Bogdan-Andrei Iancu, - * [8902] : + - complete port of pull request #34 - port from 1.8 (rev #8901): - - fixed the dummy mesage (for pushing internal replies into reply route) - push also the reply code as string + callid body trimming - Final fix for bug #3514120 - Thanks to Nick Altmann for report and testing +2013-08-28 Bogdan-Andrei Iancu + * [f26c257] : + - complete backport from 1.8 of pull request #15 -2012-04-03 11:08:29 Razvan Crainea - * [8900] : - added Max-forwards header to nathelper ping message +2013-08-28 Bogdan-Andrei Iancu + * [6cfdc3a] : + - complete backport from 1.8 of pull request #15 -2012-04-03 10:52:36 Bogdan-Andrei Iancu, - * [8897] : - - fix in triggering the B2B reply route - the network info needs to be properly populated in the fake msg (generated for the internal replies) - Partial fix for bug #3514120 - Thanks to Nick Altmann for report and testing +2013-08-28 Vlad Paiu + * [18257f3] : + Fixed bug introduced by previous commit : - downstream BYEs should go to 200OK leg in order to trigger dialog termination - upstream BYEs have no such limitation ( there's only one caller leg :) ) -2012-04-02 22:46:06 Bogdan-Andrei Iancu, - * [8894] : - - fix handling on received Route hdrs: b2b module has to accept the preloaded Route hdrs (with IP pointing to itself) - Closes bug #3514052 +2013-08-28 Bogdan-Andrei Iancu + * [78ff5db] : + - proper backport of all changes from 1.8 branch -2012-03-30 22:14:01 Ovidiu Sas - * [8893] : - httpd: set svn prop keywords +2013-08-27 liviuchircu + * [389de52] : + Fix: also run child_init for bin listeners + - bin listeners are now identified by the PROC_BIN rank + - this way, only the UDP listeners receive positive ranks -2012-03-30 22:11:47 Ovidiu Sas - * [8892] : - httpd: fix improper usage of libmicrohttpd api - mi_httpd: reflect changes in httpd +2013-08-26 Bogdan-Andrei Iancu + * [f153a9a] : + - BYE requests received in confirmed state should terminate the dialog only if they match the TO-tag from 200 OK INVITE. This affects parallel forking scenarios where rejected branches are terminated via BYE by caller. Thanks for reporting and testing to Marco Hierl. -2012-03-30 13:05:32 Vlad Paiu - * [8889] : +2013-08-14 Norm Brandinger + * [879eacb] : - fixed bug where if 'make install' was run, the sources copy of the menuconfig binary would not show Compilation & Installtion options + pike: correct spelling +2013-08-14 liviuchircu + * [a5e9f4b] : -2012-03-30 11:26:07 Vlad Paiu - * [8887] : + Fix: sdp_free() bug introduced in commit bde8c0a045 + Credits to csollet for reporting. - removed unnecesary check if install dir exists or not. make install will take care of creating the dir +2013-08-13 Bogdan Andrei IANCU + * [b19eca9] : + Merge pull request #37 from fabriziopicconi/patch-5 + wrong mpath folder (detected by rpmbuild) -2012-03-30 11:06:50 Vlad Paiu - * [8884] : - fix_route_dialog() should also take care of resetting dst_uri, in case is was wrongly set by a bogus loose routing attempt +2013-08-13 Bogdan Andrei IANCU + * [9e8a497] : + Merge pull request #39 from fabriziopicconi/patch-6 + Update Centos spec file -2012-03-29 12:01:17 Razvan Crainea - * [8880] : +2013-08-13 Bogdan Andrei IANCU + * [c00b39a] : - Added multiple return codes for the sipmsg_validate function - based on the identified error (SDP, headers body, etc). - Closes feature request #3512070 + Merge pull request #54 from nikbyte/master + yum package specs / init-scripts changes for el/fedora -2012-03-28 19:49:42 Bogdan-Andrei Iancu, - * [8879] : +2013-08-13 Bogdan-Andrei Iancu + * [39669e8] : - - fixed matching of in-dialog UPDATE requestes - Reported by Duane Larson + fixed setting the default min_expires and max_expires module parameters. Credits go to MayamaTakeshi. -2012-03-28 19:45:06 Bogdan-Andrei Iancu, - * [8876] : +2013-08-13 Nick Altmann + * [775d22f] : - - fixed missing MaxFwd hdr in ACK for local transactions + changed el/fedora spec version to 1.11.0 -2012-03-28 19:09:53 Bogdan-Andrei Iancu, - * [8875] : +2013-08-13 Nick Altmann + * [2425adf] : - - the TM internal function t_uac_cancel() dropped as it is bogus - replies for this kind of generated CANCELs will never match back the transaction, leading to retransmissions - - t_cancel_uac() TM API function dropped (the external version of t_uac_cancel()) - - b2b_entitites and seas modules re-worked to use t_lookup_ident() + t_cancel_trans() instead of bogus t_cancel_uac() function from TM API + add m4 config support for el/fedora distros, spec file synced with build server -2012-03-28 17:06:06 Bogdan-Andrei Iancu, - * [8872] : +2013-08-13 Nick Altmann + * [310e195] : - - fixed missing Max-FWD hdr when a CANCEL is generated via build_uac_cancel() function (used by b2b) + add m4 config support for debian distros -2012-03-28 15:31:39 Razvan Crainea - * [8869] : +2013-08-13 Damien Sandras + * [b31075d] : - Fixed drouting reallocation bug in 'add_rt_info' function + Added documentation for recent changes. -2012-03-28 13:49:30 Bogdan-Andrei Iancu, - * [8868] : +2013-08-13 Damien Sandras + * [b4d0368] : - fixed the way the contact in client entities is built - instead of using info from the received interface, use info from the outbound interface (contact need to reflect the outbound interface). - Reported by Nick, Closes bug #3512261 + PUBLISH requests are now handled in the same order than received. + That is specifically useful for pua dialoginfo which was generating dialog + info notifications that were handled in the wrong order with that patch. + PUBLISH with older documents were sometimes treated after PUBLISH requests + with newer documents, leading to incoherent states. -2012-03-28 11:42:48 Bogdan-Andrei Iancu, - * [8867] : +2013-08-13 Nick Altmann + * [196ec52] : - - ds_is_in_list() function allowed in local route - Patch provided by Nick - Closes patch #3512210 + spec file for el/fedora synced with build server -2012-03-26 13:28:40 Vlad Paiu - * [8861] : +2013-08-13 vladpaiu + * [3a49140] : - Max-Forwards should not get passed to the other side + Merge pull request #46 from fabriziopicconi/patch-8 + remove warning compilation +2013-08-12 vladpaiu + * [c8e64b8] : -2012-03-26 12:55:42 Vlad Paiu - * [8858] : + Merge pull request #48 from fabriziopicconi/patch-10 + improved parallel compilation - fixed bug in supported parser +2013-08-12 Vlad Paiu + * [db24ec0] : + Fixed double free issue when reading multiple SIP messages in one TCP chunk Do proper zero-ing out of the tcp_req structure -2012-03-26 11:03:14 Vlad Paiu - * [8856] : - fixed GCC issue for latest versions - -l statements must be after .o list +2013-08-11 Vlad Paiu + * [41157e7] : + Increased menuconfig parsing buffer to 1024 (Reported by Richard Revels) + Removed mi_http from the excluded modules list - has no external dependencies -2012-03-24 05:19:19 Ovidiu Sas - * [8854] : +2013-08-09 liviuchircu + * [aeddd31] : - b2b_logic: fix display name for scripted scenarios - - reported by Duane Larson + Fix: mathops internal parsing bug + Credits to Jayesh Nambiar for reporting +2013-08-08 fabriziopicconi + * [56f0269] : -2012-03-23 22:22:59 Bogdan-Andrei Iancu, - * [8852] : + parallel compilation + speedup compilation on multicore/multicpu machines - fixed crash in acc if the comment string did not contain a reply code - Reported by Ovidiu Sas - also thanks for debugging and testing support - Closes bug 3510600 +2013-08-08 fabriziopicconi + * [6dfb090] : -2012-03-23 18:25:00 Ovidiu Sas - * [8851] : + remove warning compilation + remove warning: ‘ret’ may be used uninitialized in this function - opensipsctl: drouting support +2013-08-08 saghul + * [dc83eb1] : + Kill compilation warnings + io_wait.c: In function ‘check_poll_method’: + io_wait.c:368:15: warning: variable ‘os_ver’ set but not used [-Wunused-but-set-variable] + unsigned int os_ver; + ^ + io_wait.c: In function ‘choose_poll_method’: + io_wait.c:448:15: warning: variable ‘os_ver’ set but not used [-Wunused-but-set-variable] + unsigned int os_ver; + ^ -2012-03-23 17:13:38 Vlad Paiu - * [8849] : - some more Max-Forwards fixes +2013-08-08 saghul + * [7d727aa] : + Fixed compilation in systems without EPOLL -2012-03-23 16:36:50 Vlad Paiu - * [8847] : +2013-08-07 saghul + * [4d4d3db] : - Do not try to make any sort of ops regarding Max-Forwards header. TM takes care of it + Cleanup menucnfig files when doing make proper +2013-08-07 Saúl Ibarra Corretgé + * [6e3b16e] : -2012-03-23 12:31:17 Vlad Paiu - * [8846] : + Fixed crash if send_subscribe fails early + In that case presentity is still NULL, check for it - re-generated README +2013-08-07 Vlad Paiu + * [1ee176a] : + Fixed warning Fixed compilation error for libcurl < 7.16.2 ( due to CURLOPT_TIMEOUT_MS ) -2012-03-23 11:55:53 Bogdan-Andrei Iancu, - * [8844] : - - small fixes to remove the references to "list_file" (defintion of destinations per file - old fashion) +2013-08-06 Vlad Paiu + * [8f642ba] : + Properly mentioned Steve Frécinaux from Be IP as the module creator -2012-03-23 11:37:48 Bogdan-Andrei Iancu, - * [8842] : - - documentation fixed (replaced the "dbtext" with "text" in the db_urls) - Reported by Nick (on SF) - Closes bug #3510437 +2013-08-06 Vlad Paiu + * [3bfd505] : + Fixed goes_to_gw, is_from_gw and dr_is_gw so that they accept negative gateway types ( to match all gw types) -2012-03-23 11:16:31 Bogdan-Andrei Iancu, - * [8840] : - - fixed setting "share" and "etc" patch in osipsconfig when generating packages - Based on a patch from Nick (Sourceforge) - Closes patch 3510437 +2013-08-06 fabriziopicconi + * [7fe3f81] : + Update Centos spec file + Some new rpm optional modules are added: + mi_xmlrpc_ng,sngtc,db_cachedb,mathops,rest_client -2012-03-23 10:29:53 Bogdan-Andrei Iancu, - * [8838] : - - fix sql query in loading table - the "null" field was not initialized, resulting in garbage content (from stack). - Credits for fixing this go to Rudy from DynamicPacket - Closes bug #3510412. +2013-08-06 fabriziopicconi + * [9e1f0d3] : + wrong mpath folder (detected by rpmbuild) + change modules-prefix (tmp folder) to modules-target (installation folder) diff --git a/Makefile b/Makefile index c9232d73536..b8d28c88ac1 100644 --- a/Makefile +++ b/Makefile @@ -38,8 +38,6 @@ NICER?=1 auto_gen=lex.yy.c cfg.tab.c #lexx, yacc etc -#include source related defs -include Makefile.sources # whether or not to install opensips.cfg or just opensips.cfg.default # (opensips.cfg will never be overwritten by make install, this is usefull @@ -51,7 +49,15 @@ skip_modules?= makefile_defs=0 DEFS:= +TLS?= +SCTP?= + +# create the template only if the file is not yet created +ifeq (,$(wildcard Makefile.conf)) +$(shell cp Makefile.conf.template Makefile.conf) +endif include Makefile.conf +include Makefile.sources include Makefile.defs # if not set on the cmd. line or the env, exclude this modules: @@ -80,23 +86,39 @@ static_modules_path=$(addprefix modules/, $(static_modules)) extra_sources=$(wildcard $(addsuffix /*.c, $(static_modules_path))) extra_objs=$(extra_sources:.c=.o) -static_defs= $(foreach mod, $(static_modules), \ +static_defs=$(foreach mod, $(static_modules), \ -DSTATIC_$(shell echo $(mod) | tr [:lower:] [:upper:]) ) override extra_defs+=$(static_defs) $(EXTRA_DEFS) export extra_defs +# If modules is supplied, only do those. If not, use all modules when +# building documentation. +ifeq ($(modules),) + doc_modules=$(all_modules) +else + doc_modules=$(modules) +endif + +# Take subset of all modules, excluding the exclude_modules and the +# static_modules. modules=$(filter-out $(addprefix modules/, \ $(exclude_modules) $(static_modules)), \ $(wildcard modules/*)) +# Let modules consist of modules and include_modules (but remove +# duplicates). modules:=$(filter-out $(modules), $(addprefix modules/, $(include_modules) )) \ $(modules) -modules_names=$(shell echo $(modules)| \ - sed -e 's/modules\/\([^/ ]*\)\/*/\1.so/g' ) -modules_basenames=$(shell echo $(modules)| \ - sed -e 's/modules\/\([^/ ]*\)\/*/\1/g' ) -#modules_names=$(patsubst modules/%, %.so, $(modules)) -modules_full_path=$(join $(modules), $(addprefix /, $(modules_names))) + +ifneq ($(module),) + modules:=$(addprefix modules/, $(module)) +endif + +modules_names=$(patsubst modules/%, %.so, $(modules)) +modules_basenames=$(patsubst modules/%, %, $(modules)) +modules_full_path=$(join $(modules), $(addprefix /, $(modules_names))) + +doc_modules_basenames=$(patsubst modules/%, %, $(doc_modules)) ifeq ($(TLS),) tls_configs="" @@ -158,6 +180,7 @@ export DEFS PROFILE CC LD MKDEP MKTAGS CFLAGS LDFLAGS MOD_CFLAGS MOD_LDFLAGS export LIBS RADIUS_LIB export LEX YACC YACC_FLAGS export PREFIX LOCALBASE SYSBASE +export TLS SCTP # export relevant variables for recursive calls of this makefile # (e.g. make deb) #export LIBS @@ -196,110 +219,137 @@ all: $(NAME) modules utils app: $(NAME) +.PHONY: _modules +_modules: $(modules) + +.PHONY: $(modules) +$(modules): + @$(MAKE) --no-print-directory -C $@ && \ + echo "Building $(notdir $@) module succeeded" || (\ + status=$$?; \ + echo "ERROR: Building $(notdir $@) module failed!"; \ + exit $$status; \ + ) + .PHONY: modules modules: +ifeq (,$(FASTER)) @set -e; \ for r in $(modules) "" ; do \ if [ -n "$$r" ]; then \ if [ -d "$$r" ]; then \ echo "" ; \ echo "" ; \ - $(MAKE) -C $$r ; \ + $(MAKE) -j -C $$r ; \ fi ; \ fi ; \ - done + done +else + @$(MAKE) _modules || ( \ + status=$$?; \ + if echo $(MAKEFLAGS) | grep -q -- --jobserver; then \ + printf '\nBuilding one or more modules failed!\n'; \ + printf 'Please re-run make without -j / --jobs to find out which.\n\n'; \ + fi; \ + exit $$status \ + ) +endif + + +.PHONY: tool-docbook2pdf +tool-docbook2pdf: + @if [ -z "$(DBXML2PDF)" ]; then \ + echo "error: docbook2pdf not found"; exit 1; \ + fi + +.PHONY: tool-lynx +tool-lynx: + @if [ -z "$(DBHTML2TXT)" ]; then \ + echo "error: lynx not found"; exit 1; \ + fi + +.PHONY: tool-xsltproc +tool-xsltproc: + @if [ -z "$(DBXML2HTML)" ]; then \ + echo "error: xsltproc not found"; exit 1; \ + fi + @if [ -z "$(DBHTMLXSL)" ]; then \ + echo "error: docbook.xsl not found (docbook-xsl)"; exit 1; \ + fi .PHONY: modules-readme -modules-readme: +modules-readme: tool-lynx tool-xsltproc @set -e; \ - if [ "$(DBXML2HTML)" = "" ]; then \ - echo "error: xsltproc not found"; exit ; \ - fi ; \ - if [ "$(DBHTML2TXT)" = "" ]; then \ - echo "error: lynx not found"; exit ; \ - fi ; \ - for r in $(modules_basenames) "" ; do \ + for r in $(doc_modules_basenames) ""; do \ if [ -d "modules/$$r/doc" ]; then \ - cd "modules/$$r/doc" ; \ + cd "modules/$$r/doc"; \ if [ -f "$$r".xml ]; then \ - echo "" ; \ - echo "docbook xml to html: $$r.xml" ; \ + echo ""; \ + echo "docbook xml to html: $$r.xml"; \ $(DBXML2HTML) -o $$r.html $(DBXML2HTMLPARAMS) $(DBHTMLXSL) \ - $$r.xml ; \ - echo "docbook html to txt: $$r.html" ; \ - $(DBHTML2TXT) $(DBHTML2TXTPARAMS) $$r.html >$$r.txt ; \ - echo "docbook txt to readme: $$r.txt" ; \ - rm $$r.html ; \ - mv $$r.txt ../README ; \ - echo "" ; \ - fi ; \ - cd ../../.. ; \ - fi ; \ - done + $$r.xml; \ + echo "docbook html to txt: $$r.html"; \ + $(DBHTML2TXT) $(DBHTML2TXTPARAMS) $$r.html >$$r.txt; \ + echo "docbook txt to readme: $$r.txt"; \ + rm $$r.html; \ + mv $$r.txt ../README; \ + echo ""; \ + fi; \ + cd ../../..; \ + fi; \ + done .PHONY: modules-docbook-txt -modules-docbook-txt: +modules-docbook-txt: tool-lynx tool-xsltproc @set -e; \ - if [ "$(DBXML2HTML)" = "" ]; then \ - echo "error: xsltproc not found"; exit ; \ - fi ; \ - if [ "$(DBHTML2TXT)" = "" ]; then \ - echo "error: lynx not found"; exit ; \ - fi ; \ - for r in $(modules_basenames) "" ; do \ + for r in $(doc_modules_basenames) ""; do \ if [ -d "modules/$$r/doc" ]; then \ - cd "modules/$$r/doc" ; \ + cd "modules/$$r/doc"; \ if [ -f "$$r".xml ]; then \ - echo "" ; \ - echo "docbook xml to html: $$r.xml" ; \ + echo ""; \ + echo "docbook xml to html: $$r.xml"; \ $(DBXML2HTML) -o $$r.html $(DBXML2HTMLPARAMS) $(DBHTMLXSL) \ - $$r.xml ; \ - echo "docbook html to txt: $$r.html" ; \ - $(DBHTML2TXT) $(DBHTML2TXTPARAMS) $$r.html >$$r.txt ; \ - rm $$r.html ; \ - echo "" ; \ - fi ; \ - cd ../../.. ; \ - fi ; \ - done + $$r.xml; \ + echo "docbook html to txt: $$r.html"; \ + $(DBHTML2TXT) $(DBHTML2TXTPARAMS) $$r.html >$$r.txt; \ + rm $$r.html; \ + echo ""; \ + fi; \ + cd ../../..; \ + fi; \ + done .PHONY: modules-docbook-html -modules-docbook-html: +modules-docbook-html: tool-xsltproc @set -e; \ - if [ "$(DBXML2HTML)" = "" ]; then \ - echo "error: xsltproc not found"; exit ; \ - fi ; \ - for r in $(modules_basenames) "" ; do \ + for r in $(doc_modules_basenames) ""; do \ if [ -d "modules/$$r/doc" ]; then \ - cd "modules/$$r/doc" ; \ + cd "modules/$$r/doc"; \ if [ -f "$$r".xml ]; then \ - echo "" ; \ - echo "docbook xml to html: $$r.xml" ; \ + echo ""; \ + echo "docbook xml to html: $$r.xml"; \ $(DBXML2HTML) -o $$r.html $(DBXML2HTMLPARAMS) $(DBHTMLXSL) \ - $$r.xml ; \ - echo "" ; \ - fi ; \ - cd ../../.. ; \ - fi ; \ - done + $$r.xml; \ + echo ""; \ + fi; \ + cd ../../..; \ + fi; \ + done .PHONY: modules-docbook-pdf -modules-docbook-pdf: +modules-docbook-pdf: tool-docbook2pdf @set -e; \ - if [ "$(DBXML2PDF)" = "" ]; then \ - echo "error: docbook2pdf not found"; exit ; \ - fi ; \ - for r in $(modules_basenames) "" ; do \ + for r in $(doc_modules_basenames) ""; do \ if [ -d "modules/$$r/doc" ]; then \ - cd "modules/$$r/doc" ; \ + cd "modules/$$r/doc"; \ if [ -f "$$r".xml ]; then \ - echo "" ; \ - echo "docbook xml to pdf: $$r.xml" ; \ - $(DBXML2PDF) "$$r".xml ; \ - fi ; \ - cd ../../.. ; \ - fi ; \ - done + echo ""; \ + echo "docbook xml to pdf: $$r.xml"; \ + $(DBXML2PDF) "$$r".xml; \ + fi; \ + cd ../../..; \ + fi; \ + done .PHONY: modules-docbook modules-docbook: modules-docbook-txt modules-docbook-html modules-docbook-pdf @@ -362,11 +412,13 @@ dbg: $(NAME) dist: tar -tar: +tar: $(NEWREVISION) $(TAR) -C .. \ --exclude=$(notdir $(CURDIR))/tmp* \ --exclude=$(notdir $(CURDIR))/debian* \ --exclude=.svn* \ + --exclude=.git \ + --exclude=.gitignore \ --exclude=*.[do] \ --exclude=*.so \ --exclude=*.il \ @@ -404,13 +456,6 @@ deb: dpkg-buildpackage -rfakeroot -tc $(DEBBUILD_EXTRA_OPTIONS) rm -f debian -.PHONY: deb-lenny -deb-lenny: - rm -f debian - ln -sf packaging/debian-lenny debian - dpkg-buildpackage -rfakeroot -tc $(DEBBUILD_EXTRA_OPTIONS) - rm -f debian - .PHONY: sunpkg sunpkg: diff --git a/Makefile.conf b/Makefile.conf.template similarity index 87% rename from Makefile.conf rename to Makefile.conf.template index 0e0890b1e01..78421da85d4 100644 --- a/Makefile.conf +++ b/Makefile.conf.template @@ -14,7 +14,7 @@ #db_perlvdb= Provides a virtualization framework for OpenSIPS's database access. | Perl library development files, tipically libperl-dev #db_postgres= Provides Postgres connectivity for OpenSIPS | PostgreSQL library and development library - tipically libpq5 and libpq-dev #db_unixodbc= Allows to use the unixodbc package with OpenSIPS | ODBC library and ODBC development library -#dialplan= Implements generic string translations based on matching and replacement rules | PCRE development library, tipically libpre-dev +#dialplan= Implements generic string translations based on matching and replacement rules | PCRE development library, tipically libpcre-dev #event_rabbitmq= Provides the implementation of a RabbitMQ client for the Event Interface | RabbitMQ development library, librabbitmq-dev #h350= Enables access to SIP account data stored in an LDAP [RFC4510] directory containing H.350 commObjects | OpenLDAP library & development files, tipically libldap and libldap-dev #regex= Offers matching operations against regular expressions using the powerful PCRE library. | Development library for PCRE, tipically libpcre-dev @@ -24,14 +24,14 @@ #ldap= Implements an LDAP search interface for OpenSIPS | OpenLDAP library & development files, tipically libldap and libldap-dev #lua= Easily implement your own OpenSIPS extensions in Lua | liblua5.1-0-dev, libmemcache-dev and libmysqlclient-dev #httpd= Provides an HTTP transport layer implementation for OpenSIPS. | libmicrohttpd -#mi_http= Provides a simple web interface for running MI comands -#pi_http= Provides a simple web database provisioning interface | XML parsing & building library, tipically libxml-dev -#mi_xmlrpc= Implements a xmlrpc server that handles xmlrpc requests and generates xmlrpc responses. | parsing/building XML library, tipically libxml -#mi_xmlrpc= libxmlrpc-c3 version 0.9.10 - 0.9.42. (using other versions may be dangerous and lead to opensips blocking) +#mi_xmlrpc_ng= New version of the xmlrpc server that handles xmlrpc requests and generates xmlrpc responses. | parsing/building XML library, tipically libxml +#mi_xmlrpc= Old version of the xmlrpc server that handles xmlrpc requests and generates xmlrpc responses. | parsing/building XML library, tipically libxml +#mi_xmlrpc= libxmlrpc-c3 version 0.9.10 - 0.9.42. (using other versions may be dangerous and lead to opensips blocking) #mi_xmlrpc= libxmlrpc-c3-dev version 0.9.10 - 0.9.42 #mmgeoip= Lightweight wrapper for the MaxMind GeoIP API | libGeoIP #osp= Enables OpenSIPS to support secure, multi-lateral peering using the OSP standard | OSP development kit, tipically osptoolkit #perl= Easily implement your own OpenSIPS extensions in Perl | Perl library development files, tipically libperl-dev +#pi_http= Provides a simple web database provisioning interface | XML parsing & building library, tipically libxml-dev #presence= Handles PUBLISH and SUBSCRIBE messages and generates NOTIFY messages in a general, event independent way | XML parsing & Building library, tipically libxml-dev #presence_dialoginfo= Enables the handling of "Event: dialog" (as defined in RFC 4235) | XML parsing & building library, tipically libxml-dev #presence_mwi= Does specific handling for notify-subscribe message-summary (message waiting indication) events as specified in RFC 3842 | XML parsing & building library, tipically libxml-dev @@ -43,14 +43,15 @@ #pua_usrloc= Connector between usrloc and pua modules. | XML parsing & building library,tipically libxml-dev #pua_xmpp= Gateway for presence between SIP and XMPP. | XML parsing & building library,tipically libxml-dev #python= Easily implement your own OpenSIPS extensions in Python | Shared Python runtime library, libpython +#rest_client= Simple HTTP client | CURL library - libcurl #rls= Resource List Server implementation following the specification in RFC 4662 and RFC 4826 | parsing/building XML library, tipically libxml-dev +#sngtc= Voice Transcoding using the D-series Sangoma transcoding cards | libsngtc_node #snmpstats= Provides an SNMP management interface to OpenSIPS | NetSNMP v5.3 -#xcap= XCAP utility functions for OpenSIPS. -#xcap_client= XCAP client for OpenSIPS.It fetches XCAP elements, either documents or part of them, by sending HTTP GET requests | building/parsing XML library - tipically libxml-dev -#xcap_client= CURL development library - tipically libcurl-dev +#xcap= XCAP utility functions for OpenSIPS. | libxml-dev +#xcap_client= XCAP client for OpenSIPS.It fetches XCAP elements, either documents or part of them, by sending HTTP GET requests | libxml-dev and libcurl-dev #xmpp= Gateway between OpenSIPS and a jabber server. It enables the exchange of IMs between SIP clients and XMPP(jabber) clients. | parsing/building XML files, tipically libexpat1-devel -exclude_modules?= aaa_radius b2b_logic cachedb_couchbase cachedb_cassandra cachedb_memcached cachedb_mongodb cachedb_redis carrierroute cpl-c db_berkeley db_http db_mysql db_oracle db_perlvdb db_postgres db_unixodbc dialplan event_rabbitmq h350 regex identity jabber json ldap lua httpd pi_http mi_http mi_xmlrpc mmgeoip osp perl presence presence_dialoginfo presence_mwi presence_xml pua pua_bla pua_dialoginfo pua_mi pua_usrloc pua_xmpp python rls snmpstats xcap xcap_client xmpp +exclude_modules?= aaa_radius b2b_logic cachedb_cassandra cachedb_couchbase cachedb_memcached cachedb_mongodb cachedb_redis carrierroute cpl-c db_berkeley db_http db_mysql db_oracle db_perlvdb db_postgres db_unixodbc dialplan event_rabbitmq h350 regex identity jabber json ldap lua httpd mi_xmlrpc_ng mi_xmlrpc mmgeoip osp perl pi_http presence presence_dialoginfo presence_mwi presence_xml pua pua_bla pua_dialoginfo pua_mi pua_usrloc pua_xmpp python rest_client rls sngtc snmpstats xcap xcap_client xmpp include_modules?= @@ -61,8 +62,8 @@ DEFS+= -DUSE_IPV6 #Compile in support for IPv6 DEFS+= -DUSE_MCAST #Compile in support for IP Multicast DEFS+= -DDISABLE_NAGLE #Disabled the TCP NAgle Algorithm ( lower delay ) DEFS+= -DSTATISTICS #Enables the statistics manager -DEFS+= -DCHANGEABLE_DEBUG_LEVEL #Enables support for changeable debug level at runtime DEFS+= -DHAVE_RESOLV_RES #Support for changing some of the resolver parameters +#DEFS+= -DHP_MALLOC #High performance allocator with fine-grained locking DEFS+= -DF_MALLOC #An even faster allocator. Not recommended for debugging DEFS+= -DUSE_TCP #Compiles in TCP support #DEFS+= -DUSE_TLS #Compiles in TLS support @@ -82,3 +83,5 @@ DEFS+= -DUSE_TCP #Compiles in TCP support #DEFS+= -DNOSMP #Do not use SMP sompliant locking. Faster but won't work on SMP machines #DEFS+= -DEXTRA_DEBUG #Compiles in some extra debugging code #DEFS+= -DORACLE_USRLOC #Uses Oracle compatible queries for USRLOC + +PREFIX=/usr/local/ diff --git a/Makefile.defs b/Makefile.defs index 3af4a7c659e..021592f5b73 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -62,9 +62,9 @@ MAIN_NAME=opensips #version number VERSION = 1 -PATCHLEVEL = 9 +PATCHLEVEL = 12 SUBLEVEL = 0 -EXTRAVERSION = -rc +EXTRAVERSION = dev RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) ifneq ($(OPENSIPS_RELEASE),) # allow override thru environment @@ -282,30 +282,56 @@ CC := $(shell echo "$${CC}") LEX := $(shell echo "$${LEX}") YACC := $(shell echo "$${YACC}") -ifeq ($(SVNVERSION),) -SVNVERSION = $(shell which svnversion) -endif - -ifeq ($(OLDSVNREVISION),) -OLDSVNREVISION = $(shell if [ -f ".svnrevision" ] ; then \ - cat .svnrevision ;\ +ifeq ($(VERSIONTYPE),) +VERSIONTYPE = $(shell if [ -d ".svn" ]; then \ + echo "svn"; \ + elif [ -d ".git" ]; then \ + echo "git"; \ + fi ) +endif + +ifneq ($(VERSIONTYPE),) + ifeq ($(GETVERSION),) + ifeq ($(VERSIONTYPE),svn) + GETVERSION = $(shell which svnversion) + GETVERSIONOPTS = -n -c . + endif + ifeq ($(VERSIONTYPE),git) + GETVERSION = $(shell which git) + GETVERSIONOPTS = rev-parse --short HEAD + endif + endif + + ifeq ($(OLDREVISION),) + OLDREVISION = $(shell if [ -f ".$(VERSIONTYPE)revision" ] ; then \ + cat .$(VERSIONTYPE)revision ;\ fi ) -endif + endif -ifeq ($(SVNREVISION),) -SVNREVISION = $(shell if [ -d .svn -a -f main.c -a -f Makefile.defs ] ; then \ - if [ -x "$(SVNVERSION)" ] ; then \ - $(SVNVERSION) -n -c . ;\ + ifeq ($(THISREVISION),) + THISREVISION = $(shell if [ -f main.c -a -f Makefile.defs ] ; then \ + if [ -x "$(GETVERSION)" ] ; then \ + $(GETVERSION) $(GETVERSIONOPTS) ;\ fi ;\ fi ) + endif +else + # git is the default versioning method + VERSIONTYPE = $(shell [ -f ".gitrevision" ] && echo "git") + ifneq ($(VERSIONTYPE),) + THISREVISION = $(shell cat .gitrevision) + endif endif -ifneq ($(SVNREVISION),) -NEWSVNREVISION = $(shell if [ "$(SVNREVISION)" != "$(OLDSVNREVISION)" ] ; then \ - echo "dosvnrev" ; \ +ifneq ($(THISREVISION),) + NEWREVISION = $(shell if [ "$(THISREVISION)" != "$(OLDREVISION)" ] ; then \ + echo "dosetrev" ; \ fi ) +else + THISREVISION = unknown endif + ifeq ($(DBXML2HTML),) DBXML2HTML = $(shell which xsltproc) endif @@ -472,8 +498,6 @@ export CC_NAME # -DSTATISTICS # enables statistics manager - support for collecting statistics # from core and all modules; all info may be fetch via FIFO/UNIX_SOCK -# -DCHANGEABLE_DEBUG_LEVEL -# enables support for changeable debug level at runtime # -DORACLE_USRLOC # use oracle compatible SQL in the the get_all_ucontacts function in usrloc, # needed for example from the nathelper module @@ -490,8 +514,8 @@ DEFS+= $(extra_defs) \ # use make mode=debug all instead. Anyway now by default opensips # is compiled w/ debugging symbols in all cases (-g). --andrei -ifneq ($(SVNREVISION),) - DEFS+= -DSVNREVISION='"$(SVNREVISION)"' +ifneq ($(VERSIONTYPE),) + DEFS+= -DVERSIONTYPE='"$(VERSIONTYPE)"' -DTHISREVISION='"$(THISREVISION)"' endif ifneq ($(FREERADIUS),) diff --git a/Makefile.modules b/Makefile.modules index 392aa20b06d..230c7e61699 100644 --- a/Makefile.modules +++ b/Makefile.modules @@ -23,6 +23,9 @@ ifneq ($(makefile_defs), 1) $(error "the local makefile does not include Makefile.defs!") endif +ifeq (,$(wildcard ../../Makefile.conf)) +$(shell cp ../../Makefile.conf.template ../../Makefile.conf) +endif include ../../Makefile.conf else diff --git a/Makefile.rules b/Makefile.rules index 3449165a5da..f937d7f55dd 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -21,7 +21,9 @@ all_utils:=$(addprefix utils/, $(all_utils)) #implicit rules %.o: %.c $(ALLDEP) +ifeq (,$(FASTER)) @echo "Compiling $<" +endif $(Q)$(CC) $(CFLAGS) $(DEFS) -c $< -o $@ %.d: %.c $(ALLDEP) @@ -31,9 +33,11 @@ all_utils:=$(addprefix utils/, $(all_utils)) # normal rules -$(NAME): $(NEWSVNREVISION) $(objs) $(ALLDEP) +$(NAME): $(NEWREVISION) $(objs) $(extra_objs) $(ALLDEP) +ifeq (,$(FASTER)) @echo "Linking $(NAME)" - $(Q)$(LD) $(LDFLAGS) $(objs) $(extra_objs) $(LIBS) -o $(NAME) +endif + $(Q)$(LD) $(LDFLAGS) $(objs) $(extra_objs) $(LIBS) -o $(NAME) .PHONY: all @@ -45,13 +49,21 @@ dep: $(depends) .PHONY: static static: $(objs) -.PHONY: dosvnrev -dosvnrev: - @echo "New SVN revision: $(SVNREVISION)" +Makefile.conf: Makefile.conf.template + @if ! [ -e "$@" ]; then \ + echo Creating new $@; \ + cp $< $@; \ + fi + + +.PHONY: dosetrev +dosetrev: + @echo "New $(VERSIONTYPE) revision: $(THISREVISION)" @if [ -f "main.o" ] ; then \ rm main.o ; \ fi - @echo "$(SVNREVISION)" >.svnrevision + @echo "$(THISREVISION)" >.$(VERSIONTYPE)revision + .PHONY: docbook-clean docbook-clean: @@ -99,6 +111,7 @@ proper realclean distclean: clean $(MAKE) -C $$r proper ; \ fi ; \ done + -@if [ -d menuconfig ]; then $(MAKE) -C menuconfig proper; fi -@if [ -d utils/opensipsunix ]; then $(MAKE) -C utils/opensipsunix proper; fi -@if [ -d utils/db_berkeley ]; then $(MAKE) -C utils/db_berkeley proper; fi -@if [ -d utils/db_oracle ]; then $(MAKE) -C utils/db_oracle proper; fi diff --git a/NEWS b/NEWS index 302c6c79621..2a5d10daaa8 100644 --- a/NEWS +++ b/NEWS @@ -50,7 +50,7 @@ What is new in 1.6.0 2.4 Transformations * added a new nameaddr transformation: param; it extract the value of a certain parameter - o example: avp(i:4) = $(hdr(From){nameaddr.param, tag}); + o example: avp(from) = $(hdr(From){nameaddr.param, tag}); 2.5 AAA API and enhancement of RADIUS support(NEW) AAA API @@ -201,7 +201,7 @@ important - Renamed as AUTH_AAA module - see the AAA API and module changes. * example: modparam("call_control", "init", "call-id=$ci to=$tu from=$fu - authruri=$du another_field = $avp(i:10)") + authruri=$du another_field = $avp(extra)") * the message sent if one of these parameter is set will be the string resulted after expanding the pvars diff --git a/aaa/aaa.c b/aaa/aaa.c index 65a9e029f5a..b925ad1445d 100644 --- a/aaa/aaa.c +++ b/aaa/aaa.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -87,7 +87,7 @@ int aaa_prot_bind(str* aaa_url, aaa_prot* prot) { } module_name = (char*) pkg_malloc(pc.prot_name->len + 4 + 1); - + if (!module_name) { LM_ERR("no pkg memory left\n"); return -1; diff --git a/aaa/aaa.h b/aaa/aaa.h index fa6a7230f7e..80701797744 100644 --- a/aaa/aaa.h +++ b/aaa/aaa.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -130,7 +130,7 @@ typedef int (send_request_f)(aaa_conn*, aaa_message*, aaa_message**); This function searches a certain value for a name in the dictionary of AVPs loaded at protcol intialization. The result is returned in the value field of the aaa_map structure. - The third parameter represents the type of search wanted: for a value, + The third parameter represents the type of search wanted: for a value, for an attribute or for a vendor dictionary entry. The return value is an error code. */ @@ -187,7 +187,7 @@ typedef aaa_conn* (init_prot_f)(str*); This structure is a collection of callbacks provided by the modules that implement this generic AAA interface. - A variable of this type will be filled when a bind call is made, and + A variable of this type will be filled when a bind call is made, and therefore it cannot be used before aaa_prot_bind. */ typedef struct _aaa_prot { @@ -207,7 +207,7 @@ typedef struct _aaa_prot { This is the function called by a module that wishes to use an implementation for an AAA protocol. The first parameter is the protocol URL. - The second parameter represents the address where the structure for + The second parameter represents the address where the structure for the protocol callback functions should be stored. The return value is an error code. */ diff --git a/aaa/aaa_avp.h b/aaa/aaa_avp.h index 1211c263874..2a7a1a8b6f1 100644 --- a/aaa/aaa_avp.h +++ b/aaa/aaa_avp.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * WARNING: Don't forget to update the dictionary if you update this file !!! diff --git a/action.c b/action.c index 3a6f3679a45..570dc793f04 100644 --- a/action.c +++ b/action.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -34,7 +34,7 @@ * 2003-10-29 added FORCE_TCP_ALIAS_T (andrei) * 2004-11-30 added FORCE_SEND_SOCKET_T (andrei) * 2005-11-29 added serialize_branches and next_branches (bogdan) - * 2006-03-02 MODULE_T action points to a cmd_export_t struct instead to + * 2006-03-02 MODULE_T action points to a cmd_export_t struct instead to * a function address - more info is accessible (bogdan) * 2006-05-22 forward(_udp,_tcp,_tls) and send(_tcp) merged in forward() and * send() (bogdan) @@ -108,8 +108,8 @@ int min_action_time=0; action_elem_t *route_params = NULL; int route_params_number = 0; +static int for_each_handler(struct sip_msg *msg, struct action *a); -void script_trace(char *class, char *action, struct sip_msg *msg, int line) ; /* run actions from a route */ /* returns: 0, or 1 on success, <0 on error */ @@ -127,7 +127,7 @@ static inline int run_actions(struct action* a, struct sip_msg* msg) } if (a==0){ - LM_WARN("null action list (rec_level=%d)\n", + LM_WARN("null action list (rec_level=%d)\n", rec_lev); ret=1; goto error; @@ -148,16 +148,17 @@ static inline int run_actions(struct action* a, struct sip_msg* msg) } -/* run the error route with correct handling - simpler wrapper to +/* run the error route with correct handling - simpler wrapper to allow the usage from other parts of the code */ void run_error_route(struct sip_msg* msg, int force_reset) { + int old_route; LM_DBG("triggering\n"); - set_route_type( ERROR_ROUTE ); + swap_route_type(old_route, ERROR_ROUTE); run_actions(error_rlist.a, msg); - /* if continue, then reset error info */ - if( force_reset || !( action_flags&(ACT_FL_EXIT|ACT_FL_RETURN) ) ) - init_err_info(); + /* reset error info */ + init_err_info(); + set_route_type(old_route); } @@ -238,9 +239,11 @@ int do_assign(struct sip_msg* msg, struct action* a) if(a->elem[1].type != NULLV_ST) { ret = eval_expr((struct expr*)a->elem[1].u.data, msg, &val); - if(!((val.flags&PV_VAL_STR)||(val.flags&PV_VAL_INT))) { - LM_ERR("no value in right expression\n"); - goto error; + if(!(val.flags & (PV_VAL_STR | PV_VAL_INT | PV_VAL_NULL))) + { + LM_WARN("no value in right expression at %s:%d\n", + a->file, a->line); + goto error2; } } @@ -265,9 +268,9 @@ int do_assign(struct sip_msg* msg, struct action* a) (unsigned char)a->type == MODULOEQ_T? "modulo-eq" : (unsigned char)a->type == BANDEQ_T ? "b-and-eq" : (unsigned char)a->type == BOREQ_T ? "b-or-eq":"b-xor-eq", - msg, a->line); + msg, a->file, a->line); - if(a->elem[1].type == NULLV_ST) + if(a->elem[1].type == NULLV_ST || (val.flags & PV_VAL_NULL)) { if(pv_set_value(msg, dspec, (int)a->type, 0)<0) { @@ -292,13 +295,93 @@ int do_assign(struct sip_msg* msg, struct action* a) return ret; error: - LM_ERR("error at line: %d\n", a->line); + LM_ERR("error at %s:%d\n", a->file, a->line); +error2: pv_value_destroy(&val); return -1; } -#define update_longest_action() do { \ - if (execmsgthreshold) { \ +static int do_action_set_adv_address(struct sip_msg *msg, struct action *a) +{ + str adv_addr; + int ret = 1; /* continue processing */ + + if (a->elem[0].type != STR_ST) { + report_programming_bug("set_advertised_address type %d", a->elem[0].type); + ret = E_BUG; + goto out; + } + + if (pv_printf_s(msg, (pv_elem_t *)a->elem[0].u.data, &adv_addr) != 0 + || adv_addr.len <= 0) { + LM_WARN("cannot get string for value (%s:%d)\n",a->file,a->line); + ret = E_BUG; + goto out; + } + + LM_DBG("setting adv address = [%.*s]\n", adv_addr.len, adv_addr.s); + + /* duplicate the advertised address into private memory */ + if (adv_addr.len > msg->set_global_address.len) { + msg->set_global_address.s = pkg_realloc(msg->set_global_address.s, + adv_addr.len); + if (!msg->set_global_address.s) { + LM_ERR("out of pkg mem\n"); + ret = E_OUT_OF_MEM; + goto out; + } + } + memcpy(msg->set_global_address.s, adv_addr.s, adv_addr.len); + msg->set_global_address.len = adv_addr.len; + +out: + return ret; +} + +static int do_action_set_adv_port(struct sip_msg *msg, struct action *a) +{ + str adv_port; + int ret = 1; + + if (a->elem[0].type != STR_ST) { + report_programming_bug("set_advertised_port type %d", a->elem[0].type); + ret = E_BUG; + goto out; + } + + if (pv_printf_s(msg, (pv_elem_t *)a->elem[0].u.data, &adv_port) != 0 + || adv_port.len <= 0) { + + LM_WARN("cannot get string for value (%s:%d)\n", a->file,a->line); + ret = E_BUG; + goto out; + } + + LM_DBG("setting adv port '%.*s'\n", adv_port.len, adv_port.s); + + /* duplicate the advertised port into private memory */ + if (adv_port.len > msg->set_global_port.len) { + msg->set_global_port.s = pkg_realloc(msg->set_global_port.s, + adv_port.len); + if (!msg->set_global_port.s) { + LM_ERR("out of pkg mem\n"); + ret = E_OUT_OF_MEM; + goto out; + } + } + memcpy(msg->set_global_port.s, adv_port.s, adv_port.len); + msg->set_global_port.len = adv_port.len; + +out: + return ret; +} + +#define should_skip_updating(action_type) \ + (action_type == IF_T || action_type == ROUTE_T || \ + action_type == WHILE_T || action_type == FOR_EACH_T) + +#define update_longest_action(a) do { \ + if (execmsgthreshold && !should_skip_updating((unsigned char)(a)->type)) { \ end_time = get_time_diff(&start); \ if (end_time > min_action_time) { \ for (i=0;i end of list(e.g DROP), +/* ret= 0! if action -> end of list(e.g DROP), > 0 to continue processing next actions and <0 on error */ int do_action(struct action* a, struct sip_msg* msg) @@ -347,6 +430,7 @@ int do_action(struct action* a, struct sip_msg* msg) int end_time; action_elem_t *route_params_bak; int route_params_number_bak; + int aux_counter; /* reset the value of error to E_UNSPEC so avoid unknowledgable functions to return with error (status<0) and not setting it @@ -359,16 +443,41 @@ int do_action(struct action* a, struct sip_msg* msg) ret=E_BUG; switch ((unsigned char)a->type){ + case ASSERT_T: + if (enable_asserts) { + /* if null expr => ignore if? */ + if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ + v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); + + ret=1; /*default is continue */ + + if (v<=0) { + ret=0; + + LM_CRIT("ASSERTION FAILED - %s\n", a->elem[1].u.string); + + if (abort_on_assert) { + abort(); + } else { + set_err_info(OSER_EC_ASSERT, OSER_EL_CRITIC, "assertion failed"); + set_err_reply(500, "server error"); + + run_error_route(msg,0); + } + } + } + } + break; case DROP_T: - script_trace("core", "drop", msg, a->line) ; + script_trace("core", "drop", msg, a->file, a->line) ; action_flags |= ACT_FL_DROP; case EXIT_T: - script_trace("core", "exit", msg, a->line) ; + script_trace("core", "exit", msg, a->file, a->line) ; ret=0; action_flags |= ACT_FL_EXIT; break; case RETURN_T: - script_trace("core", "return", msg, a->line) ; + script_trace("core", "return", msg, a->file, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; @@ -389,7 +498,7 @@ int do_action(struct action* a, struct sip_msg* msg) action_flags |= ACT_FL_RETURN; break; case FORWARD_T: - script_trace("core", "forward", msg, a->line) ; + script_trace("core", "forward", msg, a->file, a->line) ; if (a->elem[0].type==NOSUBTYPE){ /* parse uri and build a proxy */ if (msg->dst_uri.len) { @@ -417,7 +526,14 @@ int do_action(struct action* a, struct sip_msg* msg) pkg_free(p); if (ret==0) ret=1; }else if ((a->elem[0].type==PROXY_ST)) { - ret=forward_request(msg,(struct proxy_l*)a->elem[0].u.data); + if (0==(p=clone_proxy((struct proxy_l*)a->elem[0].u.data))) { + LM_ERR("failed to clone proxy, dropping packet\n"); + ret=E_OUT_OF_MEM; + goto error_fwd_uri; + } + ret=forward_request(msg, p); + free_proxy(p); /* frees only p content, not p itself */ + pkg_free(p); if (ret==0) ret=1; }else{ LM_ALERT("BUG in forward() types %d, %d\n", @@ -426,7 +542,7 @@ int do_action(struct action* a, struct sip_msg* msg) } break; case SEND_T: - script_trace("core", "send", msg, a->line) ; + script_trace("core", "send", msg, a->file, a->line) ; if (a->elem[0].type!= PROXY_ST){ LM_ALERT("BUG in send() type %d\n", a->elem[0].type); ret=E_BUG; @@ -450,16 +566,19 @@ int do_action(struct action* a, struct sip_msg* msg) ret=E_OUT_OF_MEM; break; } - - p=(struct proxy_l*)a->elem[0].u.data; - + if (0==(p=clone_proxy((struct proxy_l*)a->elem[0].u.data))) { + LM_ERR("failed to clone proxy, dropping packet\n"); + ret=E_OUT_OF_MEM; + break; + } ret=hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT ); if (ret==0){ if (pve) { - if ( pv_printf_s(msg, pve, &name_s)!=0 || + if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { - LM_WARN("cannot get string for value\n"); + LM_WARN("cannot get string for value (%s:%d)\n", + a->file,a->line); ret=E_UNSPEC; break; } @@ -489,12 +608,14 @@ int do_action(struct action* a, struct sip_msg* msg) if (ret!=0 && p->host.h_addr_list[p->addr_idx+1]) p->addr_idx++; } + free_proxy(p); /* frees only p content, not p itself */ + pkg_free(p); pkg_free(to); if (ret==0) ret=1; break; case LOG_T: - script_trace("core", "log", msg, a->line) ; + script_trace("core", "log", msg, a->file, a->line) ; if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in log() types %d, %d\n", a->elem[0].type, a->elem[1].type); @@ -505,7 +626,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=1; break; case APPEND_BRANCH_T: - script_trace("core", "append_branch", msg, a->line) ; + script_trace("core", "append_branch", msg, a->file, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in append_branch %d\n", a->elem[0].type ); @@ -528,13 +649,13 @@ int do_action(struct action* a, struct sip_msg* msg) msg->path_vec.s = 0; msg->path_vec.len = 0; } else { - ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, + ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, &msg->path_vec, a->elem[1].u.number, getb0flags(), msg->force_send_socket); } break; case REMOVE_BRANCH_T: - script_trace("core", "remove_branch", msg, a->line) ; + script_trace("core", "remove_branch", msg, a->file, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if( pv_get_spec_value(msg, spec, &val)!=0 @@ -549,7 +670,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret = (remove_branch((unsigned int)i)==0)?1:-1; break; case LEN_GT_T: - script_trace("core", "len_gt", msg, a->line) ; + script_trace("core", "len_gt", msg, a->file, a->line) ; if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in len_gt type %d\n", a->elem[0].type ); @@ -559,7 +680,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1; break; case SET_DEBUG_T: - script_trace("core", "set_debug", msg, a->line) ; + script_trace("core", "set_debug", msg, a->file, a->line) ; if (a->elem[0].type==NUMBER_ST) set_proc_debug_level(a->elem[0].u.number); else @@ -567,43 +688,43 @@ int do_action(struct action* a, struct sip_msg* msg) ret = 1; break; case SETFLAG_T: - script_trace("core", "setflag", msg, a->line) ; + script_trace("core", "setflag", msg, a->file, a->line) ; ret = setflag( msg, a->elem[0].u.number ); break; case RESETFLAG_T: - script_trace("core", "resetflag", msg, a->line) ; + script_trace("core", "resetflag", msg, a->file, a->line) ; ret = resetflag( msg, a->elem[0].u.number ); break; case ISFLAGSET_T: - script_trace("core", "isflagset", msg, a->line) ; + script_trace("core", "isflagset", msg, a->file, a->line) ; ret = isflagset( msg, a->elem[0].u.number ); break; case SETSFLAG_T: - script_trace("core", "setsflag", msg, a->line) ; + script_trace("core", "setsflag", msg, a->file, a->line) ; ret = setsflag( a->elem[0].u.number ); break; case RESETSFLAG_T: - script_trace("core", "resetsflag", msg, a->line) ; + script_trace("core", "resetsflag", msg, a->file, a->line) ; ret = resetsflag( a->elem[0].u.number ); break; case ISSFLAGSET_T: - script_trace("core", "issflagset", msg, a->line) ; + script_trace("core", "issflagset", msg, a->file, a->line) ; ret = issflagset( a->elem[0].u.number ); break; case SETBFLAG_T: - script_trace("core", "setbflag", msg, a->line) ; + script_trace("core", "setbflag", msg, a->file, a->line) ; ret = setbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case RESETBFLAG_T: - script_trace("core", "resetbflag", msg, a->line) ; + script_trace("core", "resetbflag", msg, a->file, a->line) ; ret = resetbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case ISBFLAGSET_T: - script_trace("core", "isbflagset", msg, a->line) ; + script_trace("core", "isbflagset", msg, a->file, a->line) ; ret = isbflagset( a->elem[0].u.number, a->elem[1].u.number ); break; case ERROR_T: - script_trace("core", "error", msg, a->line) ; + script_trace("core", "error", msg, a->file, a->line) ; if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in error() types %d, %d\n", a->elem[0].type, a->elem[1].type); @@ -615,7 +736,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=1; break; case ROUTE_T: - script_trace("route", rlist[a->elem[0].u.number].name, msg, a->line) ; + script_trace("route", rlist[a->elem[0].u.number].name, msg, a->file, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in route() type %d\n", a->elem[0].type); @@ -650,7 +771,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=return_code; break; case REVERT_URI_T: - script_trace("core", "revert_uri", msg, a->line) ; + script_trace("core", "revert_uri", msg, a->file, a->line) ; if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; @@ -668,16 +789,16 @@ int do_action(struct action* a, struct sip_msg* msg) case PREFIX_T: case STRIP_T: case STRIP_TAIL_T: - script_trace("core", + script_trace("core", (unsigned char)a->type == SET_HOST_T ? "set_host" : - (unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : + (unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : (unsigned char)a->type == SET_USER_T ? "set_user" : - (unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : + (unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : (unsigned char)a->type == SET_PORT_T ? "set_port" : - (unsigned char)a->type == SET_URI_T ? "set_uri" : + (unsigned char)a->type == SET_URI_T ? "set_uri" : (unsigned char)a->type == PREFIX_T ? "prefix" : (unsigned char)a->type == STRIP_T ? "strip" : "strip_tail", - msg, a->line); + msg, a->file, a->line); user=0; if (a->type==STRIP_T || a->type==STRIP_TAIL_T) { if (a->elem[0].type!=NUMBER_ST) { @@ -712,7 +833,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=E_UNSPEC; break; } - + new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri==0){ LM_ERR("memory allocation failure\n"); @@ -730,7 +851,7 @@ int do_action(struct action* a, struct sip_msg* msg) if (crt+a->elem[0].u.s.len>end) goto error_uri; memcpy( crt, a->elem[0].u.s.s, a->elem[0].u.s.len); crt+=a->elem[0].u.s.len; - /* whatever we had before, with prefix we have username + /* whatever we had before, with prefix we have username now */ user=1; } @@ -846,7 +967,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=1; break; case SET_DSTURI_T: - script_trace("core", "set_dsturi", msg, a->line) ; + script_trace("core", "set_dsturi", msg, a->file, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in setdsturi() type %d\n", a->elem[0].type); @@ -861,7 +982,7 @@ int do_action(struct action* a, struct sip_msg* msg) case SET_DSTHOST_T: case SET_DSTPORT_T: script_trace("core", (unsigned char) a->type == SET_DSTHOST_T ? - "set_dsturi" : "set_dstport", msg, a->line); + "set_dsturi" : "set_dstport", msg, a->file, a->line); if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in domain setting type %d\n", a->elem[0].type); @@ -971,7 +1092,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret = 1; break; case RESET_DSTURI_T: - script_trace("core", "reset_dsturi", msg, a->line) ; + script_trace("core", "reset_dsturi", msg, a->file, a->line) ; if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; @@ -979,14 +1100,14 @@ int do_action(struct action* a, struct sip_msg* msg) ret = 1; break; case ISDSTURISET_T: - script_trace("core", "isdsturiset", msg, a->line) ; + script_trace("core", "isdsturiset", msg, a->file, a->line) ; if(msg->dst_uri.s==0 || msg->dst_uri.len<=0) ret = -1; else ret = 1; break; case IF_T: - script_trace("core", "if", msg, a->line) ; + script_trace("core", "if", msg, a->file, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); @@ -999,10 +1120,11 @@ int do_action(struct action* a, struct sip_msg* msg) return_code = 0; break; }else{ - LM_WARN("error in expression (l=%d)\n", a->line); + LM_WARN("error in expression at %s:%d\n", + a->file, a->line); } } - + ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){ @@ -1020,7 +1142,7 @@ int do_action(struct action* a, struct sip_msg* msg) } break; case WHILE_T: - script_trace("core", "while", msg, a->line) ; + script_trace("core", "while", msg, a->file, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ len = 0; @@ -1041,11 +1163,11 @@ int do_action(struct action* a, struct sip_msg* msg) return_code = 0; break; }else{ - LM_WARN("error in expression (l=%d)\n", - a->line); + LM_WARN("error in expression at %s:%d\n", + a->file, a->line); } } - + ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST) @@ -1071,8 +1193,12 @@ int do_action(struct action* a, struct sip_msg* msg) } } break; + case FOR_EACH_T: + script_trace("core", "for-each", msg, a->file, a->line) ; + ret = for_each_handler(msg, a); + break; case CACHE_STORE_T: - script_trace("core", "cache_store", msg, a->line) ; + script_trace("core", "cache_store", msg, a->file, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - first argument not of" " type string [%d]\n", @@ -1099,7 +1225,7 @@ int do_action(struct action* a, struct sip_msg* msg) /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; - if ( pv_printf_s(msg, pve, &name_s)!=0 || + if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1108,7 +1234,7 @@ int do_action(struct action* a, struct sip_msg* msg) /* parse the value argument */ pve = (pv_elem_t *)a->elem[2].u.data; - if ( pv_printf_s(msg, pve, &val_s)!=0 || + if ( pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1143,7 +1269,7 @@ int do_action(struct action* a, struct sip_msg* msg) break; case CACHE_REMOVE_T: - script_trace("core", "cache_remove", msg, a->line) ; + script_trace("core", "cache_remove", msg, a->file, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[0].type ); @@ -1158,7 +1284,7 @@ int do_action(struct action* a, struct sip_msg* msg) } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; - if ( pv_printf_s(msg, pve, &name_s)!=0 || + if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1167,7 +1293,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret = cachedb_remove( &a->elem[0].u.s, &name_s); break; case CACHE_FETCH_T: - script_trace("core", "cache_fetch", msg, a->line) ; + script_trace("core", "cache_fetch", msg, a->file, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); @@ -1189,7 +1315,7 @@ int do_action(struct action* a, struct sip_msg* msg) str aux = {0, 0}; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; - if ( pv_printf_s(msg, pve, &name_s)!=0 || + if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1210,10 +1336,10 @@ int do_action(struct action* a, struct sip_msg* msg) } pkg_free(aux.s); } - + break; case CACHE_COUNTER_FETCH_T: - script_trace("core", "cache_counter_fetch", msg, a->line) ; + script_trace("core", "cache_counter_fetch", msg, a->file, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); @@ -1232,10 +1358,10 @@ int do_action(struct action* a, struct sip_msg* msg) ret=E_BUG; break; } - int aux_counter; + /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; - if ( pv_printf_s(msg, pve, &name_s)!=0 || + if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1257,7 +1383,7 @@ int do_action(struct action* a, struct sip_msg* msg) } break; case CACHE_ADD_T: - script_trace("core", "cache_add", msg, a->line) ; + script_trace("core", "cache_add", msg, a->file, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - first argument not of" " type string [%d]\n", @@ -1275,7 +1401,7 @@ int do_action(struct action* a, struct sip_msg* msg) /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; - if ( pv_printf_s(msg, pve, &name_s)!=0 || + if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1309,11 +1435,23 @@ int do_action(struct action* a, struct sip_msg* msg) expires = (int)a->elem[3].u.number; - /* TODO - return the new value to script ? */ - ret = cachedb_add(&a->elem[0].u.s, &name_s, increment,expires,NULL); + ret = cachedb_add(&a->elem[0].u.s, &name_s, increment, expires, &aux_counter); + + /* Return the new value */ + if (ret > 0 && a->elem[4].u.data != NULL) { + val.ri = aux_counter; + val.flags = PV_TYPE_INT|PV_VAL_INT; + + spec = (pv_spec_t*)a->elem[4].u.data; + if (pv_set_value(msg, spec, 0, &val) < 0) { + LM_ERR("cannot set the variable value\n"); + return -1; + } + } + break; case CACHE_SUB_T: - script_trace("core", "cache_sub", msg, a->line) ; + script_trace("core", "cache_sub", msg, a->file, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - first argument not of" " type string [%d]\n", @@ -1331,7 +1469,7 @@ int do_action(struct action* a, struct sip_msg* msg) /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; - if ( pv_printf_s(msg, pve, &name_s)!=0 || + if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1365,8 +1503,20 @@ int do_action(struct action* a, struct sip_msg* msg) expires = (int)a->elem[3].u.number; - /* TODO - return new value to script ? */ - ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,NULL); + ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,&aux_counter); + + /* Return the new value */ + if (ret > 0 && a->elem[4].u.data != NULL) { + val.ri = aux_counter; + val.flags = PV_TYPE_INT|PV_VAL_INT; + + spec = (pv_spec_t*)a->elem[4].u.data; + if (pv_set_value(msg, spec, 0, &val) < 0) { + LM_ERR("cannot set the variable value\n"); + return -1; + } + } + break; case CACHE_RAW_QUERY_T: if ((a->elem[0].type!=STR_ST)) { @@ -1381,7 +1531,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=E_BUG; break; } - if (a->elem[2].u.data != NULL && + if (a->elem[2].u.data != NULL && a->elem[2].type!=STR_ST){ LM_ALERT("BUG in cache_raw_query() type %d\n", a->elem[2].type); @@ -1390,7 +1540,7 @@ int do_action(struct action* a, struct sip_msg* msg) } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; - if ( pv_printf_s(msg, pve, &name_s)!=0 || + if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1423,10 +1573,10 @@ int do_action(struct action* a, struct sip_msg* msg) LM_ERR("cannot get avp name [%d/%d]\n",i,j); goto next_avp; } - + switch (cdb_reply[i][j].type) { case CDB_INT: - avp_val.n = cdb_reply[i][j].val.n; + avp_val.n = cdb_reply[i][j].val.n; break; case CDB_STR: avp_type |= AVP_VAL_STR; @@ -1456,12 +1606,12 @@ int do_action(struct action* a, struct sip_msg* msg) ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, NULL,0,NULL); break; case XDBG_T: - script_trace("core", "xdbg", msg, a->line) ; + script_trace("core", "xdbg", msg, a->file, a->line) ; if (a->elem[0].type == SCRIPTVAR_ELEM_ST) { if (xdbg(msg, a->elem[0].u.data, val.rs.s) < 0) { - LM_ALERT("Cannot print message"); + LM_ALERT("Cannot print message\n"); break; } } @@ -1472,7 +1622,7 @@ int do_action(struct action* a, struct sip_msg* msg) } break; case XLOG_T: - script_trace("core", "xlog", msg, a->line) ; + script_trace("core", "xlog", msg, a->file, a->line) ; if (a->elem[1].u.data != NULL) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST) @@ -1489,7 +1639,7 @@ int do_action(struct action* a, struct sip_msg* msg) } if (xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data) < 0) { - LM_ALERT("Cannot print xlog debug message"); + LM_ALERT("Cannot print xlog debug message\n"); break; } } @@ -1503,14 +1653,14 @@ int do_action(struct action* a, struct sip_msg* msg) } if (xlog_1(msg,a->elem[0].u.data, val.rs.s) < 0) { - LM_ALERT("Cannot print xlog debug message"); + LM_ALERT("Cannot print xlog debug message\n"); break; } } break; case RAISE_EVENT_T: - script_trace("core", "raise_event", msg, a->line) ; + script_trace("core", "raise_event", msg, a->file, a->line) ; if (a->elem[0].type != NUMBER_ST) { LM_ERR("invalid event id\n"); ret=E_BUG; @@ -1532,7 +1682,7 @@ int do_action(struct action* a, struct sip_msg* msg) } break; case SUBSCRIBE_EVENT_T: - script_trace("core", "subscribe_event", msg, a->line) ; + script_trace("core", "subscribe_event", msg, a->file, a->line) ; if (a->elem[0].type != STR_ST || a->elem[1].type != STR_ST) { LM_ERR("BUG in subscribe arguments\n"); ret=E_BUG; @@ -1559,14 +1709,14 @@ int do_action(struct action* a, struct sip_msg* msg) break; case CONSTRUCT_URI_T: - script_trace("core", "construct_uri", msg, a->line) ; + script_trace("core", "construct_uri", msg, a->file, a->line) ; for (i=0;i<5;i++) { pve = (pv_elem_t *)a->elem[i].u.data; if (pve->spec.getf) { - if ( pv_printf_s(msg, pve, &vals[i])!=0 || - vals[i].len == 0 || vals[i].s == NULL) + if ( pv_printf_s(msg, pve, &vals[i])!=0 || + vals[i].len == 0 || vals[i].s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; @@ -1576,7 +1726,7 @@ int do_action(struct action* a, struct sip_msg* msg) else vals[i] = pve->text; } - + result.s = construct_uri(&vals[0],&vals[1],&vals[2],&vals[3],&vals[4], &result.len); @@ -1602,7 +1752,7 @@ int do_action(struct action* a, struct sip_msg* msg) break; case GET_TIMESTAMP_T: - script_trace("core", "get_timestamp", msg, a->line) ; + script_trace("core", "get_timestamp", msg, a->file, a->line) ; if (get_timestamp(&sec,&usec) == 0) { int avp_name; int_str res; @@ -1639,7 +1789,7 @@ int do_action(struct action* a, struct sip_msg* msg) } break; case SWITCH_T: - script_trace("core", "switch", msg, a->line) ; + script_trace("core", "switch", msg, a->file, a->line) ; if (a->elem[0].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in switch() type %d\n", a->elem[0].type); @@ -1678,7 +1828,7 @@ int do_action(struct action* a, struct sip_msg* msg) val.rs.len)==0) cmatch = 1; } else { /* number */ - if(val.flags&PV_VAL_INT && + if(val.flags&PV_VAL_INT && val.ri==aitem->elem[0].u.number) cmatch = 1; } @@ -1709,7 +1859,7 @@ int do_action(struct action* a, struct sip_msg* msg) break; case MODULE_T: script_trace("module", ((cmd_export_t*)(a->elem[0].u.data))->name, - msg, a->line) ; + msg, a->file, a->line) ; if ( (a->elem[0].type==CMD_ST) && a->elem[0].u.data ) { ret=((cmd_export_t*)(a->elem[0].u.data))->function(msg, (char*)a->elem[1].u.data, (char*)a->elem[2].u.data, @@ -1720,56 +1870,35 @@ int do_action(struct action* a, struct sip_msg* msg) } break; case FORCE_RPORT_T: - script_trace("core", "force_rport", msg, a->line) ; + script_trace("core", "force_rport", msg, a->file, a->line) ; msg->msg_flags|=FL_FORCE_RPORT; ret=1; /* continue processing */ break; case FORCE_LOCAL_RPORT_T: - script_trace("core", "force_local_rport", msg, a->line) ; + script_trace("core", "force_local_rport", msg, a->file, a->line) ; msg->msg_flags|=FL_FORCE_LOCAL_RPORT; ret=1; /* continue processing */ break; + case SET_ADV_ADDR_T: - script_trace("core", "set_adv_addr", msg, a->line) ; - if (a->elem[0].type!=STR_ST){ - LM_ALERT("BUG in set_advertised_address() " - "type %d\n", a->elem[0].type); - ret=E_BUG; - break; - } - str adv_addr; - pve = (pv_elem_t *)a->elem[0].u.data; - if ( pv_printf_s(msg, pve, &adv_addr)!=0 || - adv_addr.len == 0 || adv_addr.s == NULL) { - LM_WARN("cannot get string for value\n"); - ret=E_BUG; - break; - } - LM_DBG("adv address = [%.*s]\n",adv_addr.len,adv_addr.s); - msg->set_global_address=adv_addr; - ret=1; /* continue processing */ + script_trace("core", "set_adv_addr", msg, a->file, a->line); + ret = do_action_set_adv_address(msg, a); break; - case SET_ADV_PORT_T: - script_trace("core", "set_adv_port", msg, a->line) ; - if (a->elem[0].type!=STR_ST){ - LM_ALERT("BUG in set_advertised_port() " - "type %d\n", a->elem[0].type); - ret=E_BUG; - break; - } - msg->set_global_port=*((str*)a->elem[0].u.data); - ret=1; /* continue processing */ + case SET_ADV_PORT_T: + script_trace("core", "set_adv_port", msg, a->file, a->line); + ret = do_action_set_adv_port(msg, a); break; + #ifdef USE_TCP case FORCE_TCP_ALIAS_T: - script_trace("core", "force_tcp_alias", msg, a->line) ; + script_trace("core", "force_tcp_alias", msg, a->file, a->line) ; if ( msg->rcv.proto==PROTO_TCP #ifdef USE_TLS || msg->rcv.proto==PROTO_TLS #endif ){ - + if (a->elem[0].type==NOSUBTYPE) port=msg->via1->port; else if (a->elem[0].type==NUMBER_ST) port=(int)a->elem[0].u.number; @@ -1779,7 +1908,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=E_BUG; break; } - + if (tcpconn_add_alias(msg->rcv.proto_reserved1, port, msg->rcv.proto)!=0){ LM_ERR("tcp alias failed\n"); @@ -1791,7 +1920,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=1; /* continue processing */ break; case FORCE_SEND_SOCKET_T: - script_trace("core", "force_send_socket", msg, a->line) ; + script_trace("core", "force_send_socket", msg, a->file, a->line) ; if (a->elem[0].type!=SOCKETINFO_ST){ LM_ALERT("BUG in force_send_socket argument" " type: %d\n", a->elem[0].type); @@ -1802,7 +1931,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=1; /* continue processing */ break; case SERIALIZE_BRANCHES_T: - script_trace("core", "serialize_branches", msg, a->line) ; + script_trace("core", "serialize_branches", msg, a->file, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in serialize_branches argument" " type: %d\n", a->elem[0].type); @@ -1817,7 +1946,7 @@ int do_action(struct action* a, struct sip_msg* msg) ret=1; /* continue processing */ break; case NEXT_BRANCHES_T: - script_trace("core", "next_branches", msg, a->line) ; + script_trace("core", "next_branches", msg, a->file, a->line) ; if ((ret=next_branches(msg))<0) { LM_ERR("next_branches failed\n"); ret=E_UNSPEC; @@ -1838,15 +1967,15 @@ int do_action(struct action* a, struct sip_msg* msg) ret = do_assign(msg, a); break; case USE_BLACKLIST_T: - script_trace("core", "use_blacklist", msg, a->line) ; + script_trace("core", "use_blacklist", msg, a->file, a->line) ; mark_for_search((struct bl_head*)a->elem[0].u.data, 1); break; case UNUSE_BLACKLIST_T: - script_trace("core", "unuse_blacklist", msg, a->line); + script_trace("core", "unuse_blacklist", msg, a->file, a->line); mark_for_search((struct bl_head*)a->elem[0].u.data, 0); break; case PV_PRINTF_T: - script_trace("core", "pv_printf", msg, a->line); + script_trace("core", "pv_printf", msg, a->file, a->line); ret = -1; spec = (pv_spec_p)a->elem[0].u.data; if(!pv_is_w(spec)) @@ -1869,17 +1998,17 @@ int do_action(struct action* a, struct sip_msg* msg) LM_ERR("setting PV failed\n"); goto error; } - + ret = 1; break; case SCRIPT_TRACE_T: - script_trace("core", "script_trace", msg, a->line); + script_trace("core", "script_trace", msg, a->file, a->line); if (a->elem[0].type==NOSUBTYPE) { use_script_trace = 0; } else { - + use_script_trace = 1; - + if (a->elem[0].type != NUMBER_ST || a->elem[1].type != SCRIPTVAR_ELEM_ST) { @@ -1908,40 +2037,93 @@ int do_action(struct action* a, struct sip_msg* msg) return_code = ret; /*skip:*/ - update_longest_action(); + update_longest_action(a); return ret; error: - LM_ERR("error at line: %d\n", a->line); - update_longest_action(); + LM_ERR("error in %s:%d\n", a->file, a->line); + update_longest_action(a); return ret; - + error_uri: LM_ERR("set*: uri too long\n"); - if (new_uri) pkg_free(new_uri); - update_longest_action(); + if (new_uri) + pkg_free(new_uri); + update_longest_action(a); return E_UNSPEC; + error_fwd_uri: - update_longest_action(); + update_longest_action(a); + return ret; +} + +static int for_each_handler(struct sip_msg *msg, struct action *a) +{ + pv_spec_p spec; + pv_param_t pvp; + pv_value_t val; + int ret = 1; + + if (a->elem[2].type == ACTIONS_ST && a->elem[2].u.data) { + spec = a->elem[1].u.data; + + /* + * simple is always better. + * just don't allow fancy for-each statements + */ + if (spec->pvp.pvi.type != PV_IDX_ALL) { + LM_ERR("for-each must be used on a \"[*]\" index! skipping!\n"); + return E_SCRIPT; + } + + memset(&pvp, 0, sizeof pvp); + pvp.pvi.type = PV_IDX_INT; + pvp.pvn = spec->pvp.pvn; + + for (;;) { + if (spec->getf(msg, &pvp, &val) != 0) { + LM_ERR("failed to get spec value\n"); + return E_BUG; + } + + if (val.flags & PV_VAL_NULL) + break; + + if (((pv_spec_p)a->elem[0].u.data)-> + setf(msg, &((pv_spec_p)a->elem[0].u.data)->pvp, + 0, &val) != 0) { + LM_ERR("failed to set scriptvar value\n"); + return E_BUG; + } + + ret = run_action_list( + (struct action *)a->elem[2].u.data, msg); + + /* check for "return" statements or "0" retcodes */ + if (action_flags & (ACT_FL_RETURN | ACT_FL_EXIT)) + return ret; + + pvp.pvi.u.ival++; + } + } + return ret; } /** - * If enabled, prints the current point of execution in the OpenSIPS script - * Params: - * - class - optional, string to be printed meaning the class of action (if any) - * - action - mandatory, string with the name of action - * - msg - mandatory, sip message - * - line - line in script + * prints the current point of execution in the OpenSIPS script + * + * @class - optional, string to be printed meaning the class of action (if any) + * @action - mandatory, string with the name of action + * @msg - mandatory, sip message + * @line - line in script */ -void script_trace(char *class, char *action, struct sip_msg *msg, int line) +void __script_trace(char *class, char *action, struct sip_msg *msg, + char *file, int line) { gparam_t param; str val; - if (use_script_trace == 0) - return; - param.type = GPARAM_TYPE_PVE; param.v.pve = &script_trace_elem; @@ -1954,14 +2136,12 @@ void script_trace(char *class, char *action, struct sip_msg *msg, int line) /* Also print extra info */ if (script_trace_info) { - LM_GEN1(script_trace_log_level, "[Script Trace][line %d][%s][%s %s]"\ - " -> (%.*s)\n", line, script_trace_info, + LM_GEN1(script_trace_log_level, "[Script Trace][%s:%d][%s][%s %s]"\ + " -> (%.*s)\n", file, line, script_trace_info, class?class:"", action, val.len, val.s); } else { - LM_GEN1(script_trace_log_level, "[Script Trace][line %d][%s %s]"\ - " -> (%.*s)\n", line, + LM_GEN1(script_trace_log_level, "[Script Trace][%s:%d][%s %s]"\ + " -> (%.*s)\n", file, line, class?class:"", action, val.len, val.s); } } - - diff --git a/action.h b/action.h index 3dcc1f73d18..13c45854070 100644 --- a/action.h +++ b/action.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -37,6 +37,7 @@ #define ACT_FL_DROP 4 extern int action_flags; +extern int use_script_trace; #define LONGEST_ACTION_SIZE 5 @@ -53,4 +54,13 @@ int run_top_route(struct action* a, struct sip_msg* msg); int run_action_list(struct action* a, struct sip_msg* msg); void run_error_route(struct sip_msg* msg, int force_reset); +#define script_trace(class, action, msg, file, line) \ + do { \ + if (use_script_trace) \ + __script_trace(class, action, msg, file, line); \ + } while (0) + +void __script_trace(char *class, char *action, struct sip_msg *msg, + char *file, int line); + #endif diff --git a/atomic.h b/atomic.h index 8a4a91b962c..8f2986d797f 100644 --- a/atomic.h +++ b/atomic.h @@ -29,35 +29,38 @@ #define _ATOMIC_OPS_H_ /************************* i386 & x86_64 ARCH ****************************/ -#if defined(__CPU_i386) || defined(__CPU_x86_64) +#if defined(__CPU_i386) || defined(__CPU_x86_64) #if defined(__SMP_yes) #define LOCK "lock ; " #else #define LOCK "" #endif +#endif -/*! \brief - * Make sure gcc doesn't try to be clever and move things around - * on us. We need to use _exactly_ the address the user gave us, - * not some alias that contains the same information. - */ -typedef struct { volatile unsigned int counter; } atomic_t; +#if defined(__CPU_i386) /*! \brief * atomic_set - set atomic variable * @v: pointer of type atomic_t * @i: required value - * + * * Atomically sets the value of @v to @i. - */ + */ #define atomic_set(v,i) (((v)->counter) = (i)) +/*! \brief + * Make sure gcc doesn't try to be clever and move things around + * on us. We need to use _exactly_ the address the user gave us, + * not some alias that contains the same information. + */ +typedef struct { volatile unsigned int counter; } atomic_t; + /*! \brief * atomic_add - add integer to atomic variable * @i: integer value to add * @v: pointer of type atomic_t - * + * * Atomically adds @i to @v. */ static __inline__ void atomic_add(int i, atomic_t *v) @@ -72,7 +75,7 @@ static __inline__ void atomic_add(int i, atomic_t *v) * atomic_sub - subtract the atomic variable * @i: integer value to subtract * @v: pointer of type atomic_t - * + * * Atomically subtracts @i from @v. */ static __inline__ void atomic_sub(int i, atomic_t *v) @@ -86,9 +89,9 @@ static __inline__ void atomic_sub(int i, atomic_t *v) /*! \brief * atomic_inc - increment atomic variable * @v: pointer of type atomic_t - * + * * Atomically increments @v by 1. - */ + */ static __inline__ void atomic_inc(atomic_t *v) { __asm__ __volatile__( @@ -100,9 +103,9 @@ static __inline__ void atomic_inc(atomic_t *v) /*! \brief * atomic_dec - decrement atomic variable * @v: pointer of type atomic_t - * + * * Atomically decrements @v by 1. - */ + */ static __inline__ void atomic_dec(atomic_t *v) { __asm__ __volatile__( @@ -110,9 +113,89 @@ static __inline__ void atomic_dec(atomic_t *v) :"=m" (v->counter) :"m" (v->counter)); } + +#undef NO_ATOMIC_OPS + +#elif defined(__CPU_x86_64) /* __CPU_i386 */ + +/*! \brief + * Make sure gcc doesn't try to be clever and move things around + * on us. We need to use _exactly_ the address the user gave us, + * not some alias that contains the same information. + */ +typedef struct { volatile unsigned long counter; } atomic_t; + +/*! \brief + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +#define atomic_set(v,i) (((v)->counter) = (i)) + +/*! \brief + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. + */ +static __inline__ void atomic_add(unsigned long i, atomic_t *v) +{ + __asm__ __volatile__( + LOCK "addq %1,%0" + :"=m" (v->counter) + :"er" (i), "m" (v->counter)); +} + +/*! \brief + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. + */ +static __inline__ void atomic_sub(unsigned long i, atomic_t *v) +{ + __asm__ __volatile__( + LOCK "subq %1,%0" + :"=m" (v->counter) + :"er" (i), "m" (v->counter)); +} + +/*! \brief + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. + */ +static __inline__ void atomic_inc(atomic_t *v) +{ + __asm__ __volatile__( + LOCK "incq %0" + :"=m" (v->counter) + :"m" (v->counter)); +} + +/*! \brief + * atomic_dec - decrement atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. + */ +static __inline__ void atomic_dec(atomic_t *v) +{ + __asm__ __volatile__( + LOCK "decq %0" + :"=m" (v->counter) + :"m" (v->counter)); +} + #undef NO_ATOMIC_OPS /************************* other ARCH ****************************/ + #else #define NO_ATOMIC_OPS diff --git a/bin_interface.c b/bin_interface.c new file mode 100644 index 00000000000..2fdd6e682bd --- /dev/null +++ b/bin_interface.c @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-04-10: Created (Liviu) + */ + +#include "bin_interface.h" +#include "udp_server.h" +#include "config.h" +#include "daemonize.h" +#include "pt.h" + +struct socket_info *bin; + +int bin_children = 1; + +static int child_index; + +static char *send_buffer; +static char *cpos; + +static char rcv_buf[BUF_SIZE]; +static char *rcv_end; + +static struct packet_cb_list *reg_modules; + +/** + * bin_init - begins the construction of a new binary packet (header part): + * + * +-------------------+------------------------------------------------------+ + * | 8-byte HEADER | BODY max 65535 bytes | + * +-------------------+------------------------------------------------------+ + * | PK_MARKER | CRC | LEN | MOD_NAME | CMD | LEN | FIELD | LEN | FIELD |...| + * +-------------------+------------------------------------------------------+ + * + * @param: { LEN, MOD_NAME } + CMD + */ +int bin_init(str *mod_name, int cmd_type) +{ + if (!send_buffer) { + send_buffer = pkg_malloc(BUF_SIZE); + if (!send_buffer) { + LM_ERR("No more pkg memory!\n"); + return -1; + } + } + + /* binary packet header: marker + crc */ + memcpy(send_buffer, BIN_PACKET_MARKER, BIN_PACKET_MARKER_SIZE); + cpos = send_buffer + HEADER_SIZE; + + /* module name */ + memcpy(cpos, &mod_name->len, LEN_FIELD_SIZE); + cpos += LEN_FIELD_SIZE; + memcpy(cpos, mod_name->s, mod_name->len); + cpos += mod_name->len; + + memcpy(cpos, &cmd_type, sizeof(cmd_type)); + cpos += sizeof(cmd_type); + + return 0; +} + +/* + * copies the given string at the 'cpos' position in the buffer + * allows null strings (NULL content or NULL param) + * + * @return: 0 on success + */ +int bin_push_str(const str *info) +{ + if (!cpos || (cpos - send_buffer + LEN_FIELD_SIZE + (info ? info->len : 0)) + > BUF_SIZE) + return -1; + + if (!info || info->len == 0 || !info->s) { + memset(cpos, 0, LEN_FIELD_SIZE); + cpos += LEN_FIELD_SIZE; + return 0; + } + + memcpy(cpos, &info->len, LEN_FIELD_SIZE); + cpos += LEN_FIELD_SIZE; + memcpy(cpos, info->s, info->len); + cpos += info->len; + + return 0; +} + +/* + * adds a new integer value at the 'cpos' position in the buffer + * + * @return: 0 on success + */ +int bin_push_int(int info) +{ + if (!cpos || (cpos + sizeof(info) - send_buffer) > BUF_SIZE) + return -1; + + memcpy(cpos, &info, sizeof(info)); + cpos += sizeof(info); + + return 0; +} + +/* + * skips @count integers from the current position in the received binary packet + * + * @return: 0 on success + */ +int bin_skip_int(int count) +{ + int i; + + if (child_index == 0) { + LM_ERR("Non bin processes cannot do pop operations!\n"); + return -2; + } + + for (i = 0; i < count; i++) { + if (cpos + LEN_FIELD_SIZE > rcv_end) { + LM_ERR("Receive binary packet buffer overflow"); + return -1; + } + + cpos += LEN_FIELD_SIZE; + } + + return 0; +} + +/* + * skips @count strings from the current position in a received binary packet + * + * @return: 0 on success + */ +int bin_skip_str(int count) +{ + int i, len; + + if (child_index == 0) { + LM_ERR("Non bin processes cannot do pop operations!\n"); + return -2; + } + + for (i = 0; i < count; i++) { + if (cpos + LEN_FIELD_SIZE > rcv_end) + goto error; + + memcpy(&len, cpos, LEN_FIELD_SIZE); + cpos += LEN_FIELD_SIZE; + + if (cpos + len > rcv_end) + goto error; + + cpos += len; + } + + return 0; + +error: + LM_ERR("Receive binary packet buffer overflow"); + return -1; +} + +/* + * pops an str from the current position in the buffer + * @info: pointer to store the result + * + * @return: 0 on success + * + * Note: The pointer returned in @info str is only valid for the duration of + * the callback. Don't forget to copy the info into a safe buffer! + */ +int bin_pop_str(str *info) +{ + if (child_index == 0) { + LM_ERR("Non bin processes cannot do pop operations!\n"); + return -2; + } + + if (cpos + LEN_FIELD_SIZE > rcv_end) + goto error; + + memcpy(&info->len, cpos, LEN_FIELD_SIZE); + cpos += LEN_FIELD_SIZE; + + if (cpos + info->len > rcv_end) + goto error; + + if (info->len == 0) + info->s = NULL; + else + info->s = cpos; + + cpos += info->len; + + LM_DBG("Popped: '%.*s' [%d]\n", info->len, info->s, info->len); + + return 0; + +error: + LM_ERR("Receive binary packet buffer overflow"); + return -1; +} + +/* + * pops an integer value from the current position in the buffer + * @info: pointer to store the result + * + * @return: 0 on success + */ +int bin_pop_int(void *info) +{ + if (child_index == 0) { + LM_ERR("Non bin processes cannot do pop operations!\n"); + return -2; + } + + if (cpos + sizeof(int) > rcv_end) { + LM_ERR("Receive binary packet buffer overflow"); + return -1; + } + + memcpy(info, cpos, sizeof(int)); + cpos += sizeof(int); + + return 0; +} + +/** + * bin_send - computes the checksum of the current packet and then + * sends the packet over UDP to the @dest destination + * + * @return: number of bytes sent, or -1 on error + */ +int bin_send(union sockaddr_union *dest) +{ + int rc; + str st; + + if (!dest) + return 0; + + st.s = send_buffer + HEADER_SIZE; + st.len = bin_send_size - HEADER_SIZE; + + /* compute a checksum of the binary packet content */ + crc32_uint(&st, (unsigned int *)(send_buffer + BIN_PACKET_MARKER_SIZE)); + + LM_DBG("sending packet {'%.*s', %d}: %.*s [%d B] from socket %d\n", + *(int *)(send_buffer + HEADER_SIZE), send_buffer + HEADER_SIZE + + LEN_FIELD_SIZE, bin_send_type, bin_send_size, send_buffer, bin_send_size, + bin->socket); + + rc = udp_send(bin, send_buffer, bin_send_size, dest); + if (rc == -1) + LM_ERR("binary packet UDP send failed!\n"); + + return rc; +} + +/** + * bin_register_cb - registers a module handler for specific packets + * @mod_name: used to classify the incoming packets + * @cb: the handler function, called once for each matched packet + * + * @return: 0 on success + */ +int bin_register_cb(char *mod_name, void (*cb)(int)) +{ + struct packet_cb_list *new_mod; + + new_mod = pkg_malloc(sizeof(*new_mod)); + if (!new_mod) { + LM_ERR("No more pkg mem!\n"); + return -1; + } + memset(new_mod, 0, sizeof(*new_mod)); + + new_mod->cbf = cb; + new_mod->module.len = strlen(mod_name); + new_mod->module.s = mod_name; + + new_mod->next = reg_modules; + reg_modules = new_mod; + + return 0; +} + +static int has_valid_checksum(char *buf, int len) +{ + unsigned int crc, real_crc; + str st; + + crc = *(unsigned int *)(buf + BIN_PACKET_MARKER_SIZE); + + st.s = buf + HEADER_SIZE; + st.len = len - HEADER_SIZE; + + crc32_uint(&st, &real_crc); + + return crc == real_crc; +} + +/* + * main binary packet UDP receiver loop + */ +static void bin_receive_loop(void) +{ + int rcv_bytes; + unsigned int from_len; + union sockaddr_union* from; + struct receive_info ri; + struct packet_cb_list *p; + str name; + + from = pkg_malloc(sizeof(*from)); + if (!from) { + LM_ERR("No more pkg memory!\n"); + goto exit; + } + memset(from, 0, sizeof(*from)); + + ri.bind_address = bind_address; + ri.dst_port = bind_address->port_no; + ri.dst_ip = bind_address->address; + ri.proto = PROTO_UDP; + ri.proto_reserved1 = ri.proto_reserved2 = 0; + + for (;;) { + rcv_bytes = recvfrom(bind_address->socket, rcv_buf, BUF_SIZE, + 0, &from->s, &from_len); + if (rcv_bytes == -1) { + if (errno == EAGAIN) { + LM_DBG("packet with bad checksum received\n"); + continue; + } + + LM_ERR("recvfrom: [%d] %s\n", errno, strerror(errno)); + if (errno == EINTR || errno == EWOULDBLOCK || errno == ECONNREFUSED) + continue; + else + goto exit; + } + + rcv_end = rcv_buf + rcv_bytes; + +#ifndef NO_ZERO_CHECKS + if (rcv_bytes < MIN_UDP_PACKET) { + LM_DBG("probing packet received len = %d\n", rcv_bytes); + continue; + } +#endif + + if (!is_valid_bin_packet(rcv_buf)) { + LM_WARN("Invalid binary packet header! First 10 bytes: %.*s\n", + 10, rcv_buf); + continue; + } + + if (!has_valid_checksum(rcv_buf, rcv_bytes)) { + LM_WARN("binary packet checksum test failed!\n"); + continue; + } + + get_name(rcv_buf, name); + cpos = name.s + name.len + CMD_FIELD_SIZE; + + /* packet will be now processed by a specific module */ + for (p = reg_modules; p; p = p->next) { + if (p->module.len == name.len && + memcmp(name.s, p->module.s, name.len) == 0) { + + LM_DBG("binary Packet CMD: %d. Module: %.*s\n", + bin_rcv_type, name.len, name.s); + + p->cbf(bin_rcv_type); + + break; + } + } + } + +exit: + if (from) + pkg_free(from); +} + +/* + * called in the OpenSIPS initialization phase by the main process. + * forks the binary packet UDP receivers. + * + * @return: 0 on success + */ +int start_bin_receivers(void) +{ + pid_t pid; + int i; + + if (udp_init(bin) != 0) + return -1; + + for (i = 1; i <= bin_children; i++) { + if ((pid = internal_fork("BIN receiver")) < 0) { + LM_CRIT("Cannot fork binary packet receiver process!\n"); + return -1; + } + + if (pid == 0) { + LM_DBG("CHILD sock: %d\n", bin->socket); + + child_index = i; + set_proc_attrs("BIN receiver %.*s ", + bin->sock_str.len, + bin->sock_str.s); + bind_address = bin; + + if (init_child(PROC_BIN) < 0) { + LM_ERR("init_child failed for BIN listener\n"); + if (send_status_code(-1) < 0) + LM_ERR("failed to send status code\n"); + clean_write_pipeend(); + exit(-1); + } + + bin_receive_loop(); + exit(-1); + } else + LM_DBG("PARENT sock: %d\n", bin->socket); + } + + return 0; +} + diff --git a/bin_interface.h b/bin_interface.h new file mode 100644 index 00000000000..e88ceffeaa5 --- /dev/null +++ b/bin_interface.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-04-10: Created (Liviu) + */ + +#ifndef __BINARY_INTERFACE__ +#define __BINARY_INTERFACE__ + +#include "ip_addr.h" +#include "crc.h" + +#define BIN_PACKET_MARKER "P4CK" +#define BIN_PACKET_MARKER_SIZE 4 +#define CRC_FIELD_SIZE 4 +#define LEN_FIELD_SIZE sizeof(int) +#define CMD_FIELD_SIZE sizeof(int) +#define HEADER_SIZE (BIN_PACKET_MARKER_SIZE + CRC_FIELD_SIZE) + +#define bin_send_type \ + (*(int *)(send_buffer + HEADER_SIZE + LEN_FIELD_SIZE + \ + *(int *)(send_buffer + HEADER_SIZE))) + +#define bin_rcv_type \ + (*(int *)(rcv_buf + HEADER_SIZE + LEN_FIELD_SIZE + \ + *(int *)(rcv_buf + HEADER_SIZE))) + +#define bin_send_size ((int)(cpos - send_buffer)) +#define bin_rcv_size ((int)(rcv_end - rcv_buf)) + +#define is_valid_bin_packet(_p) \ + (memcmp(_p, BIN_PACKET_MARKER, BIN_PACKET_MARKER_SIZE) == 0) + +#define get_name(_p, name) \ + do { \ + name.len = *(int *)(_p + HEADER_SIZE); \ + name.s = _p + HEADER_SIZE + LEN_FIELD_SIZE; \ + } while (0) + +extern struct socket_info *bin; +extern int bin_children; + +struct packet_cb_list { + str module; /* registered module */ + void (*cbf)(int cmd_type); /* module callback */ + + struct packet_cb_list *next; +}; + + +/* + * registers a callback function to be triggered on a received + * binary packet marked with the @mod_name module name + */ +int bin_register_cb(char *mod_name, void (*)(int packet_type)); + + +/** + * first function called when building a binary packet + * + * @mod_name: module specific string + * @cmd_type: module specific identifier for this new packet + * + * @return: 0 on success + */ +int bin_init(str *mod_name, int packet_type); + +/* + * adds a new string value to the packet being currently built + * @info: may also be NULL + * + * @return: 0 on success, otherwise buffer limit reached + */ +int bin_push_str(const str *info); + +/* + * adds a new integer value to the packet being currently built + * + * @return: 0 on success, otherwise buffer limit reached + */ +int bin_push_int(int info); + +/* + * pops a str structure from a received binary packet + * @info: pointer to store the result + * + * @return: 0 on success + * + * Note: The pointer returned in @info is only valid for the duration of + * the callback. Don't forget to copy the data into a safe buffer! + * + * Note2: Information is retrieved in the same order it was stored + */ +int bin_pop_str(str *info); + +/* + * pops an integer from a received binary packet + * @info: pointer to store the result + * + * @return: 0 on success + * + * Note: Information is retrieved in the same order it was stored + */ +int bin_pop_int(void *info); + +/* + * skips @count integers from a received binary packet + * + * @return: 0 on success + */ +int bin_skip_int(int count); + +/* + * skips @count strings from a received binary packet + * + * @return: 0 on success + */ +int bin_skip_str(int count); + +/** + * bin_send - computes the checksum of the current packet and then + * sends the packet over UDP to the @dest destination + * + * @return: number of bytes sent, or -1 on error + */ +int bin_send(union sockaddr_union *dest); + +/* at OpenSIPS startup */ +int start_bin_receivers(void); + +#endif /* __BINARY_INTERFACE__ */ + diff --git a/blacklists.c b/blacklists.c index 6a3e1c473a1..b337581f0d2 100644 --- a/blacklists.c +++ b/blacklists.c @@ -355,7 +355,7 @@ int add_rule_to_list(struct bl_rule **first, struct bl_rule **last, /* is it a duplicate? */ for(q = *first ; q ; q = q->next) { if ( (flags==q->flags) && (port==q->port) && - (proto==q->proto) && + (proto==q->proto) && (ip_class_compare(ip_net, &q->ip_net)==1) && ((body==NULL && q->body.s==NULL) || (body && q->body.s && (body->len==q->body.len) && @@ -417,7 +417,7 @@ static inline void rm_dups(struct bl_head *head, for( p=0,q=*first ; q ; ) { for( r=head->first; r ; r = r->next) { if ( (r->flags==q->flags) && (r->port==q->port) && - (r->proto==q->proto) && + (r->proto==q->proto) && (ip_class_compare(&r->ip_net, &q->ip_net)==1) && ((!r->body.s && !q->body.s) || ((r->body.len==q->body.len) && !strncmp(r->body.s,q->body.s,q->body.len)) ) diff --git a/cachedb/cachedb.c b/cachedb/cachedb.c index 498e2ebd9e9..dc59f398432 100644 --- a/cachedb/cachedb.c +++ b/cachedb/cachedb.c @@ -35,7 +35,7 @@ #include #include -struct cachedb_engine_t +struct cachedb_engine_t { cachedb_engine cde; struct cachedb_engine_t* next; @@ -45,7 +45,7 @@ int cachedb_store_url(struct cachedb_url **list,char *val) { struct cachedb_url *new,*it; int len; - + len = strlen(val); new = pkg_malloc(sizeof(struct cachedb_url) + len); if (new == NULL) { @@ -99,7 +99,7 @@ static inline cachedb_engine* lookup_cachedb(str *name) return 0; } -int cachedb_bind_mod(str *url,cachedb_funcs *funcs) +int cachedb_bind_mod(str *url,cachedb_funcs *funcs) { char *mod_name,*grp_name; int len; @@ -119,13 +119,13 @@ int cachedb_bind_mod(str *url,cachedb_funcs *funcs) LM_ERR("cannot extract cachedb type\n"); return -1; } - + len = mod_name - url->s; cachedb_name.len = len; cachedb_name.s = url->s; /* no point in giving here the grp_name, but for the sake of uniform - * cachedb_urls in modules and for script, take in into account + * cachedb_urls in modules and for script, take in into account * the presence of grp here too, and skip it */ grp_name=memchr(cachedb_name.s,':',cachedb_name.len); if (grp_name) @@ -133,7 +133,7 @@ int cachedb_bind_mod(str *url,cachedb_funcs *funcs) cde = lookup_cachedb(&cachedb_name); if (cde == NULL) { - LM_ERR("failed to bind to %.*s module. Is it loaded ?\n", + LM_ERR("failed to bind to [%.*s] module. Is it loaded ?\n", cachedb_name.len,cachedb_name.s); return -1; } @@ -196,8 +196,8 @@ int cachedb_insert_connection(cachedb_engine *cde,cachedb_con *conn) { cachedb_con_list *new,*it; str grp; - - grp.s = ((cachedb_pool_con *)conn->data)->id->group_name; + + grp.s = ((cachedb_pool_con *)conn->data)->id->group_name; if (grp.s) grp.len = strlen(grp.s); @@ -264,7 +264,7 @@ cachedb_con *cachedb_get_connection(cachedb_engine *cde,str *group_name) return cde->default_connection; else { for (ret=cde->connections;ret;ret=ret->next) { - if (ret->grp.len == group_name->len && + if (ret->grp.len == group_name->len && memcmp(ret->grp.s,group_name->s,group_name->len) == 0) return ret->connection; } @@ -284,10 +284,10 @@ void cachedb_end_connections(str *cachedb_name) cachedb_name->len,cachedb_name->s); return; } - + if (cde->default_connection) cde->cdb_func.destroy(cde->default_connection); - + for (it=cde->connections;it;it=it->next) cde->cdb_func.destroy(it->connection); } @@ -299,6 +299,7 @@ int cachedb_remove(str* cachedb_name, str* attr) str cde_engine,grp_name; char *p; cachedb_con *con; + int ret; if(cachedb_name == NULL || attr == NULL) { @@ -338,7 +339,11 @@ int cachedb_remove(str* cachedb_name, str* attr) return -1; } - return cde->cdb_func.remove(con,attr)<0?-1:1; + ret = cde->cdb_func.remove(con,attr); + if (ret == 0) + ret++; + + return ret; } int cachedb_store(str* cachedb_name, str* attr, str* val,int expires) @@ -347,6 +352,7 @@ int cachedb_store(str* cachedb_name, str* attr, str* val,int expires) str cde_engine,grp_name; char *p; cachedb_con *con; + int ret; if(cachedb_name == NULL || attr == NULL || val == NULL) { @@ -386,7 +392,11 @@ int cachedb_store(str* cachedb_name, str* attr, str* val,int expires) return -1; } - return cde->cdb_func.set(con,attr,val,expires)<0?-1:1; + ret = cde->cdb_func.set(con,attr,val,expires); + if (ret ==0) + ret++; + + return ret; } int cachedb_fetch(str* cachedb_name, str* attr, str* val) @@ -395,6 +405,7 @@ int cachedb_fetch(str* cachedb_name, str* attr, str* val) str cde_engine,grp_name; char *p; cachedb_con *con; + int ret; if(cachedb_name == NULL || attr == NULL || val == NULL) { @@ -434,7 +445,11 @@ int cachedb_fetch(str* cachedb_name, str* attr, str* val) return -1; } - return cde->cdb_func.get(con,attr,val)<0?-1:1; + ret = cde->cdb_func.get(con,attr,val); + if (ret == 0) + ret++; + + return ret; } int cachedb_counter_fetch(str* cachedb_name, str* attr, int* val) @@ -443,6 +458,7 @@ int cachedb_counter_fetch(str* cachedb_name, str* attr, int* val) str cde_engine,grp_name; char *p; cachedb_con *con; + int ret; if(cachedb_name == NULL || attr == NULL || val == NULL) { @@ -482,7 +498,11 @@ int cachedb_counter_fetch(str* cachedb_name, str* attr, int* val) return -1; } - return cde->cdb_func.get_counter(con,attr,val)<0?-1:1; + ret = cde->cdb_func.get_counter(con,attr,val); + if (ret == 0) + ret++; + + return ret; } int cachedb_add(str* cachedb_name, str* attr, int val,int expires,int *new_val) @@ -491,6 +511,7 @@ int cachedb_add(str* cachedb_name, str* attr, int val,int expires,int *new_val) str cde_engine,grp_name; char *p; cachedb_con *con; + int ret; if(cachedb_name == NULL || attr == NULL) { @@ -536,7 +557,11 @@ int cachedb_add(str* cachedb_name, str* attr, int val,int expires,int *new_val) return -1; } - return cde->cdb_func.add(con,attr,val,expires,new_val)<0?-1:1; + ret = cde->cdb_func.add(con,attr,val,expires,new_val); + if (ret == 0) + ret++; + + return ret; } int cachedb_sub(str* cachedb_name, str* attr, int val,int expires,int *new_val) @@ -545,6 +570,7 @@ int cachedb_sub(str* cachedb_name, str* attr, int val,int expires,int *new_val) str cde_engine,grp_name; char *p; cachedb_con *con; + int ret; if(cachedb_name == NULL || attr == NULL) { @@ -590,7 +616,11 @@ int cachedb_sub(str* cachedb_name, str* attr, int val,int expires,int *new_val) return -1; } - return cde->cdb_func.sub(con,attr,val,expires,new_val)<0?-1:1; + ret = cde->cdb_func.sub(con,attr,val,expires,new_val); + if (ret == 0) + ret++; + + return ret; } cachedb_con* cachedb_do_init(str *url,void* (*new_connection)(struct cachedb_id *)) @@ -616,7 +646,7 @@ cachedb_con* cachedb_do_init(str *url,void* (*new_connection)(struct cachedb_id res->url.s = (char *)res + sizeof(cachedb_con); res->url.len = url->len; memcpy(res->url.s,url->s,url->len); - + id = new_cachedb_id(url); if (!id) { LM_ERR("cannot parse url [%.*s]\n",url->len,url->s); @@ -641,7 +671,7 @@ cachedb_con* cachedb_do_init(str *url,void* (*new_connection)(struct cachedb_id return res; err: - if (res) + if (res) pkg_free(res); if (id) free_cachedb_id(id); @@ -672,6 +702,7 @@ int cachedb_raw_query(str* cachedb_name, str* attr, cdb_raw_entry*** reply,int e str cde_engine,grp_name; char *p; cachedb_con *con; + int ret; if(cachedb_name == NULL || attr == NULL) { @@ -716,10 +747,14 @@ int cachedb_raw_query(str* cachedb_name, str* attr, cdb_raw_entry*** reply,int e return -1; } - return cde->cdb_func.raw_query(con,attr,reply,expected_kv_no,rpl_no)<0?-1:1; + ret = cde->cdb_func.raw_query(con,attr,reply,expected_kv_no,rpl_no); + if (ret == 0) + ret++; + + return ret; } -void free_raw_fetch(cdb_raw_entry **reply,int no_key,int no_val) +void free_raw_fetch(cdb_raw_entry **reply, int no_val, int no_key) { int i,j; diff --git a/cachedb/cachedb.h b/cachedb/cachedb.h index 8ff841beac4..f22f18d5543 100644 --- a/cachedb/cachedb.h +++ b/cachedb/cachedb.h @@ -28,6 +28,7 @@ #define _CACHEDB_H #include "../str.h" +#include "../db/db_query.h" #include "cachedb_con.h" #include "cachedb_pool.h" #include "cachedb_id.h" @@ -68,16 +69,27 @@ typedef int (cachedb_sub_f)(cachedb_con *con,str *attr,int val,int expires,int * /* bi-dimensional array will be returned */ typedef int (cachedb_raw_f)(cachedb_con *con,str *query,cdb_raw_entry ***reply,int expected_key_no,int *reply_no); +typedef int(cachedb_query_trans_f)(cachedb_con *con,const str *table,const db_key_t* _k, const db_op_t* _op,const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,const db_key_t _o, db_res_t** _r); +typedef int(cachedb_free_trans_f)(cachedb_con* con, db_res_t* _r); +typedef int(cachedb_insert_trans_f)(cachedb_con *con,const str *table,const db_key_t* _k, const db_val_t* _v,const int _n); +typedef int(cachedb_delete_trans_f)(cachedb_con *con,const str *table,const db_key_t* _k,const db_op_t *_o, const db_val_t* _v,const int _n); +typedef int (cachedb_update_trans_f)(cachedb_con *con,const str *table,const db_key_t* _k,const db_op_t *_o, const db_val_t* _v,const db_key_t* _uk, const db_val_t* _uv, const int _n,const int _un); + typedef struct cachedb_funcs_t { - cachedb_init_f *init; - cachedb_destroy_f *destroy; - cachedb_get_f *get; + cachedb_init_f *init; + cachedb_destroy_f *destroy; + cachedb_get_f *get; cachedb_getcounter_f *get_counter; - cachedb_set_f *set; - cachedb_remove_f *remove; - cachedb_add_f *add; - cachedb_sub_f *sub; - cachedb_raw_f *raw_query; + cachedb_set_f *set; + cachedb_remove_f *remove; + cachedb_add_f *add; + cachedb_sub_f *sub; + cachedb_raw_f *raw_query; + cachedb_query_trans_f *db_query_trans; + cachedb_free_trans_f *db_free_trans; + cachedb_insert_trans_f *db_insert_trans; + cachedb_delete_trans_f *db_delete_trans; + cachedb_update_trans_f *db_update_trans; int capability; } cachedb_funcs; @@ -105,5 +117,5 @@ int cachedb_bind_mod(str *url,cachedb_funcs *funcs); int cachedb_put_connection(str *cachedb_name,cachedb_con *con); void cachedb_end_connections(str *cachedb_name); -void free_raw_fetch(cdb_raw_entry **reply,int no_key,int no_val); +void free_raw_fetch(cdb_raw_entry **reply, int no_val, int no_key); #endif diff --git a/cachedb/cachedb_cap.h b/cachedb/cachedb_cap.h index 97a3429703b..90deca65c2b 100644 --- a/cachedb/cachedb_cap.h +++ b/cachedb/cachedb_cap.h @@ -59,7 +59,7 @@ static inline int check_cachedb_api(cachedb_engine *cde) cde->name.len,cde->name.s); return -1; } - + if (cde->cdb_func.get) cde->cdb_func.capability |= CACHEDB_CAP_GET; if (cde->cdb_func.set) diff --git a/cachedb/cachedb_id.c b/cachedb/cachedb_id.c index 8ed5416f313..cf59c06ff91 100644 --- a/cachedb/cachedb_id.c +++ b/cachedb/cachedb_id.c @@ -54,7 +54,7 @@ static int dupl_string(char** dst, const char* begin, const char* end) /** - * Parse a database URL of form + * Parse a database URL of form * scheme://[username[:password]@]hostname[:port]/database * * \param id filled id struct @@ -88,19 +88,21 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url) if (!id || !url || !url->s) { goto err; } - + len = url->len; if (len < SHORTEST_DB_URL_LEN) { goto err; } - - LM_DBG("parsing [%.*s]\n",url->len,url->s); + LM_DBG("parsing [%.*s]\n",url->len,url->s); /* Initialize all attributes to 0 */ memset(id, 0, sizeof(struct cachedb_id)); st = ST_SCHEME; begin = url->s; + if (dupl_string(&id->initial_url,url->s,url->s+url->len) < 0) + goto err; + for(i = 0; i < len; i++) { switch(st) { case ST_SCHEME: @@ -142,7 +144,7 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url) st = ST_USER_HOST; begin = url->s + i + 1; break; - + default: goto err; } @@ -249,7 +251,7 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url) id->flags |= CACHEDB_ID_MULTIPLE_HOSTS; break; } - + case ST_DB: break; } @@ -267,6 +269,7 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url) return 0; err: + if (id->initial_url) pkg_free(id->initial_url); if (id->scheme) pkg_free(id->scheme); if (id->username) pkg_free(id->username); if (id->password) pkg_free(id->password); @@ -373,6 +376,7 @@ void free_cachedb_id(struct cachedb_id* id) { if (!id) return; + if (id->initial_url) pkg_free(id->initial_url); if (id->scheme) pkg_free(id->scheme); if (id->group_name) pkg_free(id->group_name); if (id->username) pkg_free(id->username); diff --git a/cachedb/cachedb_id.h b/cachedb/cachedb_id.h index 8a6bca3629e..501ae42b117 100644 --- a/cachedb/cachedb_id.h +++ b/cachedb/cachedb_id.h @@ -37,7 +37,8 @@ struct cachedb_id { char* host; /**< Host or IP, case insensitive */ unsigned short port; /**< Port number */ char* database; /**< Database, case sensitive */ - int flags; /**< Flags for signaling various events */ + char* initial_url; /**< Initial full URL */ + int flags; /**< Flags for signaling various events */ }; #define CACHEDB_ID_NO_URL (1<<0) diff --git a/cachedb/cachedb_pool.c b/cachedb/cachedb_pool.c index 5b76939a791..cf72d01e5d7 100644 --- a/cachedb/cachedb_pool.c +++ b/cachedb/cachedb_pool.c @@ -25,6 +25,7 @@ #include "../dprint.h" +#include "../mem/mem.h" #include "cachedb_pool.h" #include @@ -33,7 +34,7 @@ static cachedb_pool_con *cachedb_pool = NULL; cachedb_pool_con* cachedb_pool_get(struct cachedb_id *id) { cachedb_pool_con *it; - + for (it=cachedb_pool;it;it=it->next) if (cmp_cachedb_id(id,it->id)) { it->ref++; @@ -43,6 +44,34 @@ cachedb_pool_con* cachedb_pool_get(struct cachedb_id *id) return 0; } +cachedb_pool_con** filter_pool_by_scheme(str *scheme,int* lst_size) +{ + cachedb_pool_con *it; + cachedb_pool_con **lst=NULL; + int size = 0; + int alloc_size = 0; + + for (it=cachedb_pool;it;it=it->next) { + if (memcmp(scheme->s,it->id->scheme,scheme->len) == 0) { + if (alloc_size - size == 0) { + alloc_size=(alloc_size==0)?2:2*alloc_size; + lst = pkg_realloc(lst,alloc_size * sizeof(cachedb_pool_con*)); + if (lst == NULL) { + LM_ERR("No more pkg \n"); + *lst_size = 0; + return NULL; + } + } + + lst[size]=it; + size++; + } + } + + *lst_size = size; + return lst; +} + void cachedb_pool_insert(cachedb_pool_con *con) { if (!con) diff --git a/cachedb/cachedb_pool.h b/cachedb/cachedb_pool.h index 2f99e222785..9d536ccde8d 100644 --- a/cachedb/cachedb_pool.h +++ b/cachedb/cachedb_pool.h @@ -36,6 +36,7 @@ typedef struct cachedb_pool_con_t{ } cachedb_pool_con; cachedb_pool_con* cachedb_pool_get(struct cachedb_id* id); +cachedb_pool_con** filter_pool_by_scheme(str *scheme,int *size); void cachedb_pool_insert(cachedb_pool_con *con); int cachedb_pool_remove(cachedb_pool_con *con); diff --git a/cachedb/example/example_cachedb.c b/cachedb/example/example_cachedb.c index 87edffa4d9f..70421b86871 100644 --- a/cachedb/example/example_cachedb.c +++ b/cachedb/example/example_cachedb.c @@ -71,8 +71,10 @@ static param_export_t params[]={ /** module exports */ struct module_exports exports= { "example_cachedb", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -174,7 +176,7 @@ static int process_msg(struct sip_msg *msg) { str key=str_init("inv_bye"); int ret,result; - + LM_DBG("Inside process_msg\n"); /* based on different message contents, decide to do some Cache/DB ops diff --git a/cfg.lex b/cfg.lex index 08ab6784f67..c0739a3294c 100644 --- a/cfg.lex +++ b/cfg.lex @@ -134,6 +134,7 @@ /* action keywords */ FORWARD forward +ASSERT "assert" DROP "drop" EXIT "exit" RETURN "return" @@ -186,6 +187,8 @@ CASE "case" DEFAULT "default" SBREAK "break"|"esac" WHILE "while" +FOR "for" +IN "in" SET_ADV_ADDRESS "set_advertised_address" SET_ADV_PORT "set_advertised_port" FORCE_SEND_SOCKET "force_send_socket" @@ -278,17 +281,22 @@ SCRIPTVAR_START "$" /* config vars. */ DEBUG debug +ENABLE_ASSERTS enable_asserts +ABORT_ON_ASSERT abort_on_assert FORK fork LOGSTDERROR log_stderror LOGFACILITY log_facility LOGNAME log_name AVP_ALIASES avp_aliases LISTEN listen +BIN_LISTEN bin_listen +BIN_CHILDREN bin_children ALIAS alias AUTO_ALIASES auto_aliases DNS dns REV_DNS rev_dns DNS_TRY_IPV6 dns_try_ipv6 +DNS_TRY_NAPTR dns_try_naptr DNS_RETR_TIME dns_retr_time DNS_RETR_NO dns_retr_no DNS_SERVERS_NO dns_servers_no @@ -297,6 +305,11 @@ PORT port MAXBUFFER maxbuffer CHILDREN children CHECK_VIA check_via +SHM_HASH_SPLIT_PERCENTAGE "shm_hash_split_percentage" +SHM_SECONDARY_HASH_SIZE "shm_secondary_hash_size" +MEM_WARMING_ENABLED "mem_warming"|"mem_warming_enabled" +MEM_WARMING_PATTERN_FILE "mem_warming_pattern_file" +MEM_WARMING_PERCENTAGE "mem_warming_percentage" MEMLOG "memlog"|"mem_log" MEMDUMP "memdump"|"mem_dump" EXECMSGTHRESHOLD "execmsgthreshold"|"exec_msg_threshold" @@ -316,6 +329,10 @@ CHROOT "chroot" WDIR "workdir"|"wdir" MHOMED mhomed DISABLE_TCP "disable_tcp" +ASYNC_TCP "tcp_async" +ASYNC_TCP_LOCAL_CON_TIMEOUT "tcp_async_local_connect_timeout" +ASYNC_TCP_LOCAL_WRITE_TIMEOUT "tcp_async_local_write_timeout" +ASYNC_TCP_MAX_POSTPONED_CHUNKS "tcp_async_max_postponed_chunks" TCP_CHILDREN "tcp_children" TCP_ACCEPT_ALIASES "tcp_accept_aliases" TCP_SEND_TIMEOUT "tcp_send_timeout" @@ -330,6 +347,8 @@ TCP_KEEPALIVE "tcp_keepalive" TCP_KEEPCOUNT "tcp_keepcount" TCP_KEEPIDLE "tcp_keepidle" TCP_KEEPINTERVAL "tcp_keepinterval" +TCP_MAX_MSG_CHUNKS "tcp_max_msg_chunks" +TCP_MAX_MSG_TIME "tcp_max_msg_time" DISABLE_TLS "disable_tls" TLSLOG "tlslog"|"tls_log" TLS_PORT_NO "tls_port_no" @@ -340,6 +359,9 @@ TLS_REQUIRE_CLIENT_CERTIFICATE "tls_require_client_certificate" TLS_CERTIFICATE "tls_certificate" TLS_PRIVATE_KEY "tls_private_key" TLS_CA_LIST "tls_ca_list" +TLS_CA_DIR "tls_ca_dir" +TLS_DH_PARAMS "tls_dh_params" +TLS_EC_CURVE "tls_ec_curve" TLS_CIPHERS_LIST "tls_ciphers_list" TLS_HANDSHAKE_TIMEOUT "tls_handshake_timeout" TLS_SEND_TIMEOUT "tls_send_timeout" @@ -379,6 +401,7 @@ SSLv23 "sslv23"|"SSLv23"|"SSLV23" SSLv2 "sslv2"|"SSLv2"|"SSLV2" SSLv3 "sslv3"|"SSLv3"|"SSLV3" TLSv1 "tlsv1"|"TLSv1"|"TLSV1" +TLSv1_2 "tlsv1_2"|"TLSv1_2"|"TLSV1_2" NULLV "null"|"NULL" LETTER [a-zA-Z] @@ -429,6 +452,7 @@ IMPORTFILE "import_file" {EAT_ABLE} { count(); } {FORWARD} {count(); yylval.strval=yytext; return FORWARD; } +{ASSERT} {count(); yylval.strval=yytext; return ASSERT; } {DROP} { count(); yylval.strval=yytext; return DROP; } {EXIT} { count(); yylval.strval=yytext; return EXIT; } {RETURN} { count(); yylval.strval=yytext; return RETURN; } @@ -491,6 +515,8 @@ IMPORTFILE "import_file" {DEFAULT} { count(); yylval.strval=yytext; return DEFAULT; } {SBREAK} { count(); yylval.strval=yytext; return SBREAK; } {WHILE} { count(); yylval.strval=yytext; return WHILE; } +{FOR} { count(); yylval.strval=yytext; return FOR; } +{IN} { count(); yylval.strval=yytext; return IN; } {INCLUDEFILE} { count(); BEGIN(INCLF); } {IMPORTFILE} { count(); BEGIN(IMPTF); } @@ -558,18 +584,26 @@ IMPORTFILE "import_file" {MYSELF} { count(); yylval.strval=yytext; return MYSELF; } {DEBUG} { count(); yylval.strval=yytext; return DEBUG; } +{ENABLE_ASSERTS} { count(); yylval.strval=yytext; return ENABLE_ASSERTS; } +{ABORT_ON_ASSERT} { count(); yylval.strval=yytext; return ABORT_ON_ASSERT; } {FORK} { count(); yylval.strval=yytext; return FORK; } {LOGSTDERROR} { yylval.strval=yytext; return LOGSTDERROR; } {LOGFACILITY} { yylval.strval=yytext; return LOGFACILITY; } {LOGNAME} { yylval.strval=yytext; return LOGNAME; } {AVP_ALIASES} { yylval.strval=yytext; return AVP_ALIASES; } {LISTEN} { count(); yylval.strval=yytext; return LISTEN; } +{BIN_CHILDREN} { count(); yylval.strval=yytext; + return BIN_CHILDREN; } +{BIN_LISTEN} { count(); yylval.strval=yytext; + return BIN_LISTEN; } {ALIAS} { count(); yylval.strval=yytext; return ALIAS; } {AUTO_ALIASES} { count(); yylval.strval=yytext; return AUTO_ALIASES; } {DNS} { count(); yylval.strval=yytext; return DNS; } {REV_DNS} { count(); yylval.strval=yytext; return REV_DNS; } {DNS_TRY_IPV6} { count(); yylval.strval=yytext; return DNS_TRY_IPV6; } +{DNS_TRY_NAPTR} { count(); yylval.strval=yytext; + return DNS_TRY_NAPTR; } {DNS_RETR_TIME} { count(); yylval.strval=yytext; return DNS_RETR_TIME; } {DNS_RETR_NO} { count(); yylval.strval=yytext; @@ -584,6 +618,11 @@ IMPORTFILE "import_file" {MAXBUFFER} { count(); yylval.strval=yytext; return MAXBUFFER; } {CHILDREN} { count(); yylval.strval=yytext; return CHILDREN; } {CHECK_VIA} { count(); yylval.strval=yytext; return CHECK_VIA; } +{SHM_HASH_SPLIT_PERCENTAGE} { count(); yylval.strval=yytext; return SHM_HASH_SPLIT_PERCENTAGE; } +{SHM_SECONDARY_HASH_SIZE} { count(); yylval.strval=yytext; return SHM_SECONDARY_HASH_SIZE; } +{MEM_WARMING_ENABLED} { count(); yylval.strval=yytext; return MEM_WARMING_ENABLED; } +{MEM_WARMING_PATTERN_FILE} { count(); yylval.strval=yytext; return MEM_WARMING_PATTERN_FILE; } +{MEM_WARMING_PERCENTAGE} { count(); yylval.strval=yytext; return MEM_WARMING_PERCENTAGE; } {MEMLOG} { count(); yylval.strval=yytext; return MEMLOG; } {MEMDUMP} { count(); yylval.strval=yytext; return MEMDUMP; } {EXECMSGTHRESHOLD} { count(); yylval.strval=yytext; return EXECMSGTHRESHOLD; } @@ -602,6 +641,12 @@ IMPORTFILE "import_file" {TCP_OPT_CRLF_PINGPONG} { count(); yylval.strval=yytext; return TCP_OPT_CRLF_PINGPONG; } {TCP_NO_NEW_CONN_BFLAG} { count(); yylval.strval=yytext; return TCP_NO_NEW_CONN_BFLAG; } {DISABLE_TCP} { count(); yylval.strval=yytext; return DISABLE_TCP; } +{ASYNC_TCP} { count(); yylval.strval=yytext; return ASYNC_TCP; } +{ASYNC_TCP_LOCAL_CON_TIMEOUT} { count(); yylval.strval=yytext; return ASYNC_TCP_LOCAL_CON_TIMEOUT; } +{ASYNC_TCP_LOCAL_WRITE_TIMEOUT} { count(); yylval.strval=yytext; + return ASYNC_TCP_LOCAL_WRITE_TIMEOUT; } +{ASYNC_TCP_MAX_POSTPONED_CHUNKS} { count(); yylval.strval=yytext; + return ASYNC_TCP_MAX_POSTPONED_CHUNKS; } {TCP_CHILDREN} { count(); yylval.strval=yytext; return TCP_CHILDREN; } {TCP_ACCEPT_ALIASES} { count(); yylval.strval=yytext; return TCP_ACCEPT_ALIASES; } @@ -621,6 +666,8 @@ IMPORTFILE "import_file" {TCP_KEEPCOUNT} { count(); yylval.strval=yytext; return TCP_KEEPCOUNT; } {TCP_KEEPIDLE} { count(); yylval.strval=yytext; return TCP_KEEPIDLE; } {TCP_KEEPINTERVAL} { count(); yylval.strval=yytext; return TCP_KEEPINTERVAL; } +{TCP_MAX_MSG_CHUNKS} { count(); yylval.strval=yytext; return TCP_MAX_MSG_CHUNKS; } +{TCP_MAX_MSG_TIME} { count(); yylval.strval=yytext; return TCP_MAX_MSG_TIME; } {DISABLE_TLS} { count(); yylval.strval=yytext; return DISABLE_TLS; } {TLSLOG} { count(); yylval.strval=yytext; return TLS_PORT_NO; } {TLS_PORT_NO} { count(); yylval.strval=yytext; return TLS_PORT_NO; } @@ -635,6 +682,12 @@ IMPORTFILE "import_file" return TLS_PRIVATE_KEY; } {TLS_CA_LIST} { count(); yylval.strval=yytext; return TLS_CA_LIST; } +{TLS_CA_DIR} { count(); yylval.strval=yytext; + return TLS_CA_DIR; } +{TLS_DH_PARAMS} { count(); yylval.strval=yytext; + return TLS_DH_PARAMS; } +{TLS_EC_CURVE} { count(); yylval.strval=yytext; + return TLS_EC_CURVE; } {TLS_CIPHERS_LIST} { count(); yylval.strval=yytext; return TLS_CIPHERS_LIST; } {TLS_HANDSHAKE_TIMEOUT} { count(); yylval.strval=yytext; @@ -742,6 +795,7 @@ IMPORTFILE "import_file" {SSLv2} { count(); yylval.strval=yytext; return SSLv2; } {SSLv3} { count(); yylval.strval=yytext; return SSLv3; } {TLSv1} { count(); yylval.strval=yytext; return TLSv1; } +{TLSv1_2} { count(); yylval.strval=yytext; return TLSv1_2; } {COMMA} { count(); return COMMA; } {SEMICOLON} { count(); return SEMICOLON; } diff --git a/cfg.y b/cfg.y index 7817e26a2f5..ff22bbba5e9 100644 --- a/cfg.y +++ b/cfg.y @@ -71,6 +71,10 @@ * 2007-01-25 disable_dns_failover option added (bogdan) * 2012-01-19 added TCP keepalive support * 2012-12-06 added event_route (razvanc) + * 2013-05-23 added NAPTR lookup option (dsandras) + * 2013-09-25 added TLS_CA_DIR option (chris_secusmart) + * 2013-10-06 added TLS_DH_PARAM option (mehmet_secusmart) + * 2013-10-30 added TLS_EC_CURVE option (yrjoe_secusmart) */ @@ -106,6 +110,7 @@ #include "tcp_server.h" #include "tcp_conn.h" #include "db/db_insertq.h" +#include "bin_interface.h" #include "config.h" @@ -131,7 +136,6 @@ static int i_tmp; static void* cmd_tmp; static struct socket_id* lst_tmp; static int rt; /* Type of route block for find_export */ -static str* str_tmp; static str s_tmp; static str tstr; static struct ip_addr* ip_tmp; @@ -154,16 +158,28 @@ static char mpath_buf[256]; static int mpath_len = 0; extern int line; +extern int column; +extern int startcolumn; +extern char *finame; + +#define get_cfg_file_name \ + ((finame) ? finame : cfg_file ? cfg_file : "default") + + +#define mk_action_(_res, _type, _no, _elems) \ + do { \ + _res = mk_action(_type, _no, _elems, line, get_cfg_file_name); \ + } while(0) #define mk_action0(_res, _type, _p1_type, _p2_type, _p1, _p2) \ do { \ - _res = mk_action(_type, 0, 0, line); \ + _res = mk_action(_type, 0, 0, line, get_cfg_file_name); \ } while(0) #define mk_action1(_res, _type, _p1_type, _p1) \ do { \ elems[0].type = _p1_type; \ elems[0].u.data = _p1; \ - _res = mk_action(_type, 1, elems, line); \ + _res = mk_action(_type, 1, elems, line, get_cfg_file_name); \ } while(0) #define mk_action2(_res, _type, _p1_type, _p2_type, _p1, _p2) \ do { \ @@ -171,7 +187,7 @@ extern int line; elems[0].u.data = _p1; \ elems[1].type = _p2_type; \ elems[1].u.data = _p2; \ - _res = mk_action(_type, 2, elems, line); \ + _res = mk_action(_type, 2, elems, line, get_cfg_file_name); \ } while(0) #define mk_action3(_res, _type, _p1_type, _p2_type, _p3_type, _p1, _p2, _p3) \ do { \ @@ -181,7 +197,7 @@ extern int line; elems[1].u.data = _p2; \ elems[2].type = _p3_type; \ elems[2].u.data = _p3; \ - _res = mk_action(_type, 3, elems, line); \ + _res = mk_action(_type, 3, elems, line, get_cfg_file_name); \ } while(0) %} @@ -205,6 +221,7 @@ extern int line; %token FORWARD %token SEND %token DROP +%token ASSERT %token EXIT %token RETURN %token LOG_TOK @@ -244,6 +261,8 @@ extern int line; %token DEFAULT %token SBREAK %token WHILE +%token FOR +%token IN %token SET_ADV_ADDRESS %token SET_ADV_PORT %token FORCE_SEND_SOCKET @@ -298,17 +317,22 @@ extern int line; /* config vars. */ %token DEBUG +%token ENABLE_ASSERTS +%token ABORT_ON_ASSERT %token FORK %token LOGSTDERROR %token LOGFACILITY %token LOGNAME %token AVP_ALIASES %token LISTEN +%token BIN_LISTEN +%token BIN_CHILDREN %token ALIAS %token AUTO_ALIASES %token DNS %token REV_DNS %token DNS_TRY_IPV6 +%token DNS_TRY_NAPTR %token DNS_RETR_TIME %token DNS_RETR_NO %token DNS_SERVERS_NO @@ -317,6 +341,11 @@ extern int line; %token PORT %token CHILDREN %token CHECK_VIA +%token SHM_HASH_SPLIT_PERCENTAGE +%token SHM_SECONDARY_HASH_SIZE +%token MEM_WARMING_ENABLED +%token MEM_WARMING_PATTERN_FILE +%token MEM_WARMING_PERCENTAGE %token MEMLOG %token MEMDUMP %token EXECMSGTHRESHOLD @@ -346,6 +375,10 @@ extern int line; %token WDIR %token MHOMED %token DISABLE_TCP +%token ASYNC_TCP +%token ASYNC_TCP_LOCAL_CON_TIMEOUT +%token ASYNC_TCP_LOCAL_WRITE_TIMEOUT +%token ASYNC_TCP_MAX_POSTPONED_CHUNKS %token TCP_ACCEPT_ALIASES %token TCP_CHILDREN %token TCP_CONNECT_TIMEOUT @@ -360,6 +393,8 @@ extern int line; %token TCP_KEEPCOUNT %token TCP_KEEPIDLE %token TCP_KEEPINTERVAL +%token TCP_MAX_MSG_CHUNKS +%token TCP_MAX_MSG_TIME %token DISABLE_TLS %token TLSLOG %token TLS_PORT_NO @@ -373,13 +408,17 @@ extern int line; %token SSLv2 %token SSLv3 %token TLSv1 +%token TLSv1_2 %token TLS_VERIFY_CLIENT %token TLS_VERIFY_SERVER %token TLS_REQUIRE_CLIENT_CERTIFICATE %token TLS_CERTIFICATE %token TLS_PRIVATE_KEY %token TLS_CA_LIST +%token TLS_CA_DIR %token TLS_CIPHERS_LIST +%token TLS_DH_PARAMS +%token TLS_EC_CURVE %token ADVERTISED_ADDRESS %token ADVERTISED_PORT %token DISABLE_CORE @@ -453,6 +492,7 @@ extern int line; /*non-terminals */ %type exp exp_elem exp_cond assignexp /*, condition*/ %type action actions cmd if_cmd stm exp_stm assign_cmd while_cmd + foreach_cmd %type switch_cmd switch_stm case_stms case_stm default_stm %type module_func_param %type ipv4 ipv6 ipv6addr ip @@ -473,6 +513,11 @@ extern int line; %type route_name %type route_param +/* + * since "if_cmd" is inherently ambiguous, + * skip 1 harmless shift/reduce conflict when compiling our grammar + */ +%expect 1 %% @@ -613,13 +658,13 @@ blst_elem_list: blst_elem_list COMMA blst_elem {} assign_stm: DEBUG EQUAL snumber { -#ifdef CHANGEABLE_DEBUG_LEVEL *debug=$3; -#else - debug=$3; -#endif } | DEBUG EQUAL error { yyerror("number expected"); } + | ENABLE_ASSERTS EQUAL NUMBER { enable_asserts=$3; } + | ENABLE_ASSERTS EQUAL error { yyerror("boolean value expected"); } + | ABORT_ON_ASSERT EQUAL NUMBER { abort_on_assert=$3; } + | ABORT_ON_ASSERT EQUAL error { yyerror("boolean value expected"); } | FORK EQUAL NUMBER { dont_fork= !dont_fork ? ! $3:1; } | FORK EQUAL error { yyerror("boolean value expected"); } | LOGSTDERROR EQUAL NUMBER { if (!config_check) log_stderr=$3; } @@ -643,6 +688,8 @@ assign_stm: DEBUG EQUAL snumber { | REV_DNS EQUAL error { yyerror("boolean value expected"); } | DNS_TRY_IPV6 EQUAL NUMBER { dns_try_ipv6=$3; } | DNS_TRY_IPV6 error { yyerror("boolean value expected"); } + | DNS_TRY_NAPTR EQUAL NUMBER { dns_try_naptr=$3; } + | DNS_TRY_NAPTR error { yyerror("boolean value expected"); } | DNS_RETR_TIME EQUAL NUMBER { dns_retr_time=$3; } | DNS_RETR_TIME error { yyerror("number expected"); } | DNS_RETR_NO EQUAL NUMBER { dns_retr_no=$3; } @@ -661,6 +708,16 @@ assign_stm: DEBUG EQUAL snumber { | CHILDREN EQUAL error { yyerror("number expected"); } | CHECK_VIA EQUAL NUMBER { check_via=$3; } | CHECK_VIA EQUAL error { yyerror("boolean value expected"); } + | SHM_HASH_SPLIT_PERCENTAGE EQUAL NUMBER { shm_hash_split_percentage=$3; } + | SHM_HASH_SPLIT_PERCENTAGE EQUAL error { yyerror("number expected"); } + | SHM_SECONDARY_HASH_SIZE EQUAL NUMBER { shm_secondary_hash_size=$3; } + | SHM_SECONDARY_HASH_SIZE EQUAL error { yyerror("number expected"); } + | MEM_WARMING_ENABLED EQUAL NUMBER { mem_warming_enabled = $3; } + | MEM_WARMING_ENABLED EQUAL error { yyerror("number expected"); } + | MEM_WARMING_PATTERN_FILE EQUAL STRING { mem_warming_pattern_file = $3; } + | MEM_WARMING_PATTERN_FILE EQUAL error { yyerror("string expected"); } + | MEM_WARMING_PERCENTAGE EQUAL NUMBER { mem_warming_percentage = $3; } + | MEM_WARMING_PERCENTAGE EQUAL error { yyerror("number expected"); } | MEMLOG EQUAL NUMBER { memlog=$3; memdump=$3; } | MEMLOG EQUAL error { yyerror("int value expected"); } | MEMDUMP EQUAL NUMBER { memdump=$3; } @@ -681,17 +738,21 @@ assign_stm: DEBUG EQUAL snumber { yyerror("statistics support not compiled in"); #endif /* STATISTICS */ #else /* SHM_MEM */ - yyerror("shm support not compiled in"); + yyerror("shm memory support not compiled in"); #endif } | EVENT_SHM_THRESHOLD EQUAL error { yyerror("int value expected"); } | EVENT_PKG_THRESHOLD EQUAL NUMBER { - #ifdef STATISTICS - if ($3 < 0 || $3 > 100) - yyerror("PKG threshold has to be a percentage between 0 and 100"); - event_pkg_threshold=$3; - #else - yyerror("statistics support not compiled in"); + #ifdef PKG_MALLOC + #ifdef STATISTICS + if ($3 < 0 || $3 > 100) + yyerror("PKG threshold has to be a percentage between 0 and 100"); + event_pkg_threshold=$3; + #else + yyerror("statistics support not compiled in"); + #endif + #else /* PKG_MALLOC */ + yyerror("pkg memory support not compiled in"); #endif } | EVENT_PKG_THRESHOLD EQUAL error { yyerror("int value expected"); } @@ -723,6 +784,38 @@ assign_stm: DEBUG EQUAL snumber { #endif } | DISABLE_TCP EQUAL error { yyerror("boolean value expected"); } + | ASYNC_TCP EQUAL NUMBER { + #ifdef USE_TCP + tcp_async=$3; + #else + warn("tcp support not compiled in"); + #endif + } + | ASYNC_TCP EQUAL error { yyerror("boolean value expected"); } + | ASYNC_TCP_LOCAL_CON_TIMEOUT EQUAL NUMBER { + #ifdef USE_TCP + tcp_async_local_connect_timeout=$3; + #else + warn("tcp support not compiled in"); + #endif + } + | ASYNC_TCP_LOCAL_CON_TIMEOUT EQUAL error { yyerror("boolean value expected"); } + | ASYNC_TCP_LOCAL_WRITE_TIMEOUT EQUAL NUMBER { + #ifdef USE_TCP + tcp_async_local_write_timeout=$3; + #else + warn("tcp support not compiled in"); + #endif + } + | ASYNC_TCP_LOCAL_WRITE_TIMEOUT EQUAL error { yyerror("boolean value expected"); } + | ASYNC_TCP_MAX_POSTPONED_CHUNKS EQUAL NUMBER { + #ifdef USE_TCP + tcp_async_max_postponed_chunks=$3; + #else + warn("tcp support not compiled in"); + #endif + } + | ASYNC_TCP_MAX_POSTPONED_CHUNKS EQUAL error { yyerror("boolean value expected"); } | TCP_ACCEPT_ALIASES EQUAL NUMBER { #ifdef USE_TCP tcp_accept_aliases=$3; @@ -818,7 +911,8 @@ assign_stm: DEBUG EQUAL snumber { | TCP_OPT_CRLF_PINGPONG EQUAL error { yyerror("boolean value expected"); } | TCP_NO_NEW_CONN_BFLAG EQUAL NUMBER { #ifdef USE_TCP - fix_flag_name(&tmp, $3); + tmp = NULL; + fix_flag_name(tmp, $3); tcp_no_new_conn_bflag = get_flag_id_by_name(FLAG_TYPE_BRANCH, tmp); if (!flag_in_range( (flag_t)tcp_no_new_conn_bflag ) ) yyerror("invalid TCP no_new_conn Branch Flag"); @@ -846,6 +940,22 @@ assign_stm: DEBUG EQUAL snumber { #endif } | TCP_KEEPALIVE EQUAL error { yyerror("boolean value expected"); } + | TCP_MAX_MSG_CHUNKS EQUAL NUMBER { + #ifdef USE_TCP + tcp_max_msg_chunks=$3; + #else + warn("tcp support not compiled in"); + #endif + } + | TCP_MAX_MSG_CHUNKS EQUAL error { yyerror("boolean value expected"); } + | TCP_MAX_MSG_TIME EQUAL NUMBER { + #ifdef USE_TCP + tcp_max_msg_time=$3; + #else + warn("tcp support not compiled in"); + #endif + } + | TCP_MAX_MSG_TIME EQUAL error { yyerror("boolean value expected"); } | TCP_KEEPCOUNT EQUAL NUMBER { #ifdef USE_TCP #ifndef HAVE_TCP_KEEPCNT @@ -946,9 +1056,19 @@ assign_stm: DEBUG EQUAL snumber { warn("tls support not compiled in"); #endif } + | TLS_METHOD EQUAL TLSv1_2 { + #ifdef USE_TLS + tls_default_server_domain->method = + TLS_USE_TLSv1_2; + tls_default_client_domain->method = + TLS_USE_TLSv1_2; + #else + warn("tls support not compiled in"); + #endif + } | TLS_METHOD EQUAL error { #ifdef USE_TLS - yyerror("SSLv23, SSLv2, SSLv3 or TLSv1" + yyerror("SSLv23, SSLv2, SSLv3, TLSv1 or TLSv1_2" " expected"); #else warn("tls support not compiled in"); @@ -1014,6 +1134,17 @@ assign_stm: DEBUG EQUAL snumber { #endif } | TLS_CA_LIST EQUAL error { yyerror("string value expected"); } + | TLS_CA_DIR EQUAL STRING { + #ifdef USE_TLS + tls_default_server_domain->ca_directory = + $3; + tls_default_client_domain->ca_directory = + $3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_CA_DIR EQUAL error { yyerror("string value expected"); } | TLS_CIPHERS_LIST EQUAL STRING { #ifdef USE_TLS tls_default_server_domain->ciphers_list @@ -1025,6 +1156,28 @@ assign_stm: DEBUG EQUAL snumber { #endif } | TLS_CIPHERS_LIST EQUAL error { yyerror("string value expected"); } + | TLS_DH_PARAMS EQUAL STRING { + #ifdef USE_TLS + tls_default_server_domain->tmp_dh_file = + $3; + tls_default_client_domain->tmp_dh_file = + $3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_DH_PARAMS EQUAL error { yyerror("string value expected"); } + | TLS_EC_CURVE EQUAL STRING { + #ifdef USE_TLS + tls_default_server_domain->tls_ec_curve = + $3; + tls_default_client_domain->tls_ec_curve = + $3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_EC_CURVE EQUAL error { yyerror("string value expected"); } | TLS_HANDSHAKE_TIMEOUT EQUAL NUMBER { #ifdef USE_TLS tls_handshake_timeout=$3; @@ -1069,7 +1222,6 @@ assign_stm: DEBUG EQUAL snumber { | XLOG_FORCE_COLOR EQUAL NUMBER { xlog_force_color = $3; } | XLOG_BUF_SIZE EQUAL error { yyerror("number expected"); } | XLOG_FORCE_COLOR EQUAL error { yyerror("boolean value expected"); } - | LISTEN EQUAL listen_lst { for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next){ if (add_listen_iface( lst_tmp->name, @@ -1089,6 +1241,30 @@ assign_stm: DEBUG EQUAL snumber { | LISTEN EQUAL error { yyerror("ip address or hostname " "expected (use quotes if the hostname includes" " config keywords)"); } + | BIN_LISTEN EQUAL listen_id COLON port { + if (bin) { + yyerror("can only define one binary packet interface"); + YYABORT; + } + + lst_tmp = mk_listen_id($3, PROTO_UDP, $5); + bin = new_sock_info(lst_tmp->name, + lst_tmp->port, + lst_tmp->proto, + lst_tmp->adv_name, + lst_tmp->adv_port, + lst_tmp->children, + 0); + if (!bin) { + LM_CRIT("Failed to create new socket info!\n"); + YYABORT; + } + } + | BIN_LISTEN EQUAL error { yyerror("ip address or hostname " + "expected (use quotes if the hostname includes" + " config keywords)"); } + | BIN_CHILDREN EQUAL NUMBER { bin_children=$3; } + | BIN_CHILDREN EQUAL error { yyerror("number expected"); } | ALIAS EQUAL id_lst { for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) add_alias(lst_tmp->name, strlen(lst_tmp->name), @@ -1104,19 +1280,22 @@ assign_stm: DEBUG EQUAL snumber { default_global_address.len=strlen($3); } } - |ADVERTISED_ADDRESS EQUAL error {yyerror("ip address or hostname " + | ADVERTISED_ADDRESS EQUAL error {yyerror("ip address or hostname " "expected"); } | ADVERTISED_PORT EQUAL NUMBER { - tmp=int2str($3, &i_tmp); - if ((default_global_port.s=pkg_malloc(i_tmp)) - ==0){ - LM_CRIT("cfg. parser: out of memory.\n"); - default_global_port.len=0; - }else{ - default_global_port.len=i_tmp; + tmp = int2str($3, &i_tmp); + if (i_tmp > default_global_port.len) + default_global_port.s = + pkg_realloc(default_global_port.s, i_tmp); + + if (!default_global_port.s) { + LM_CRIT("cfg. parser: out of memory.\n"); + default_global_port.len = 0; + } else { + default_global_port.len = i_tmp; memcpy(default_global_port.s, tmp, default_global_port.len); - }; + } } |ADVERTISED_PORT EQUAL error {yyerror("ip address or hostname " "expected"); } @@ -1404,7 +1583,14 @@ tls_server_var : TLS_METHOD EQUAL SSLv23 { warn("tls support not compiled in"); #endif } - | TLS_METHOD EQUAL error { yyerror("SSLv23, SSLv2, SSLv3 or TLSv1 expected"); } + | TLS_METHOD EQUAL TLSv1_2 { + #ifdef USE_TLS + tls_server_domains->method=TLS_USE_TLSv1_2; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_METHOD EQUAL error { yyerror("SSLv23, SSLv2, SSLv3, TLSv1 or TLSV1_2 expected"); } | TLS_CERTIFICATE EQUAL STRING { #ifdef USE_TLS tls_server_domains->cert_file=$3; @@ -1431,6 +1617,14 @@ tls_server_var : TLS_METHOD EQUAL SSLv23 { #endif } | TLS_CA_LIST EQUAL error { yyerror("string value expected"); } + | TLS_CA_DIR EQUAL STRING { + #ifdef USE_TLS + tls_server_domains->ca_directory=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_CA_DIR EQUAL error { yyerror("string value expected"); } | TLS_CIPHERS_LIST EQUAL STRING { #ifdef USE_TLS tls_server_domains->ciphers_list=$3; @@ -1439,6 +1633,22 @@ tls_server_var : TLS_METHOD EQUAL SSLv23 { #endif } | TLS_CIPHERS_LIST EQUAL error { yyerror("string value expected"); } + | TLS_DH_PARAMS EQUAL STRING { + #ifdef USE_TLS + tls_server_domains->tmp_dh_file=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_DH_PARAMS EQUAL error { yyerror("string value expected"); } + | TLS_EC_CURVE EQUAL STRING { + #ifdef USE_TLS + tls_server_domains->tls_ec_curve=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_EC_CURVE EQUAL error { yyerror("string value expected"); } | TLS_VERIFY_CLIENT EQUAL NUMBER { #ifdef USE_TLS tls_server_domains->verify_cert=$3; @@ -1486,8 +1696,15 @@ tls_client_var : TLS_METHOD EQUAL SSLv23 { warn("tls support not compiled in"); #endif } + | TLS_METHOD EQUAL TLSv1_2 { + #ifdef USE_TLS + tls_client_domains->method=TLS_USE_TLSv1_2; + #else + warn("tls support not compiled in"); + #endif + } | TLS_METHOD EQUAL error { - yyerror("SSLv23, SSLv2, SSLv3 or TLSv1 expected"); } + yyerror("SSLv23, SSLv2, SSLv3, TLSv1 or TLSv1_2 expected"); } | TLS_CERTIFICATE EQUAL STRING { #ifdef USE_TLS tls_client_domains->cert_file=$3; @@ -1514,6 +1731,14 @@ tls_client_var : TLS_METHOD EQUAL SSLv23 { #endif } | TLS_CA_LIST EQUAL error { yyerror("string value expected"); } + | TLS_CA_DIR EQUAL STRING { + #ifdef USE_TLS + tls_client_domains->ca_directory=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_CA_DIR EQUAL error { yyerror("string value expected"); } | TLS_CIPHERS_LIST EQUAL STRING { #ifdef USE_TLS tls_client_domains->ciphers_list=$3; @@ -1522,6 +1747,22 @@ tls_client_var : TLS_METHOD EQUAL SSLv23 { #endif } | TLS_CIPHERS_LIST EQUAL error { yyerror("string value expected"); } + | TLS_DH_PARAMS EQUAL STRING { + #ifdef USE_TLS + tls_client_domains->tmp_dh_file=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_DH_PARAMS EQUAL error { yyerror("string value expected"); } + | TLS_EC_CURVE EQUAL STRING { + #ifdef USE_TLS + tls_client_domains->tls_ec_curve=$3; + #else + warn("tls support not compiled in"); + #endif + } + | TLS_EC_CURVE EQUAL error { yyerror("string value expected"); } | TLS_VERIFY_SERVER EQUAL NUMBER { #ifdef USE_TLS tls_client_domains->verify_cert=$3; @@ -1549,7 +1790,7 @@ route_name: ID { route_stm: ROUTE LBRACE actions RBRACE { if (rlist[DEFAULT_RT].a!=0) { - yyerror("overwritting default " + yyerror("overwriting default " "request routing table"); YYABORT; } @@ -1559,7 +1800,7 @@ route_stm: ROUTE LBRACE actions RBRACE { if ( strtol($3,&tmp,10)==0 && *tmp==0) { /* route[0] detected */ if (rlist[DEFAULT_RT].a!=0) { - yyerror("overwritting(2) default " + yyerror("overwriting(2) default " "request routing table"); YYABORT; } @@ -1584,7 +1825,7 @@ failure_route_stm: ROUTE_FAILURE LBRACK route_name RBRACK LBRACE actions RBRACE onreply_route_stm: ROUTE_ONREPLY LBRACE actions RBRACE { if (onreply_rlist[DEFAULT_RT].a!=0) { - yyerror("overwritting default " + yyerror("overwriting default " "onreply routing table"); YYABORT; } @@ -1610,7 +1851,7 @@ branch_route_stm: ROUTE_BRANCH LBRACK route_name RBRACK LBRACE actions RBRACE { error_route_stm: ROUTE_ERROR LBRACE actions RBRACE { if (error_rlist.a!=0) { - yyerror("overwritting default " + yyerror("overwriting default " "error routing table"); YYABORT; } @@ -2015,6 +2256,7 @@ actions: actions action {$$=append_action($1, $2); } action: cmd SEMICOLON {$$=$1;} | if_cmd {$$=$1;} | while_cmd { $$=$1;} + | foreach_cmd { $$=$1;} | switch_cmd {$$=$1;} | assign_cmd SEMICOLON {$$=$1;} | SEMICOLON /* null action */ {$$=0;} @@ -2047,6 +2289,23 @@ while_cmd: WHILE exp stm { mk_action2( $$, WHILE_T, } ; +foreach_cmd: FOR LPAREN script_var IN script_var RPAREN stm { + if ($3->type != PVT_SCRIPTVAR && + $3->type != PVT_AVP) { + yyerror("\nfor-each statement: only \"var\" " + "and \"avp\" iterators are supported"); + } + + mk_action3( $$, FOR_EACH_T, + SCRIPTVAR_ST, + SCRIPTVAR_ST, + ACTIONS_ST, + $3, + $5, + $7); + } + ; + switch_cmd: SWITCH LPAREN script_var RPAREN LBRACE switch_stm RBRACE { mk_action2( $$, SWITCH_T, SCRIPTVAR_ST, @@ -2162,10 +2421,37 @@ module_func_param: STRING { elems[$1+1].u.data = $3; $$=$1+1; } + | COMMA { + elems[1].type = NULLV_ST; + elems[1].u.data = NULL; + elems[2].type = NULLV_ST; + elems[2].u.data = NULL; + $$=2; + } + | COMMA STRING { + elems[1].type = NULLV_ST; + elems[1].u.data = NULL; + elems[2].type = STRING_ST; + elems[2].u.data = $2; + $$=2; + } + | module_func_param COMMA { + if ($1+1>=MAX_ACTION_ELEMS) { + yyerror("too many arguments in function\n"); + $$=0; + } + elems[$1+1].type = NULLV_ST; + elems[$1+1].u.data = NULL; + $$=$1+1; + } | NUMBER { $$=0; yyerror("numbers used as parameters - they should be quoted"); } + | COMMA NUMBER { + $$=0; + yyerror("numbers used as parameters - they should be quoted"); + } | module_func_param COMMA NUMBER { $$=0; yyerror("numbers used as parameters - they should be quoted"); @@ -2251,6 +2537,7 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, | SEND error { $$=0; yyerror("missing '(' or ')' ?"); } | SEND LPAREN error RPAREN { $$=0; yyerror("bad send" "argument"); } + | ASSERT LPAREN exp COMMA STRING RPAREN {mk_action2( $$, ASSERT_T, EXPR_ST, STRING_ST, $3, $5); } | DROP LPAREN RPAREN {mk_action2( $$, DROP_T,0, 0, 0, 0); } | DROP {mk_action2( $$, DROP_T,0, 0, 0, 0); } | EXIT LPAREN RPAREN {mk_action2( $$, EXIT_T,0, 0, 0, 0); } @@ -2567,23 +2854,24 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, "string expected"); } | SET_ADV_ADDRESS error {$$=0; yyerror("missing '(' or ')' ?"); } | SET_ADV_PORT LPAREN NUMBER RPAREN { - $$=0; - tmp=int2str($3, &i_tmp); - if ((str_tmp=pkg_malloc(sizeof(str)))==0){ - LM_CRIT("cfg. parser: out of memory.\n"); - }else{ - if ((str_tmp->s=pkg_malloc(i_tmp))==0){ + tstr.s = int2str($3, &tstr.len); + if (!(tmp = pkg_malloc(tstr.len + 1))) { LM_CRIT("cfg. parser: out of memory.\n"); - }else{ - memcpy(str_tmp->s, tmp, i_tmp); - str_tmp->len=i_tmp; - mk_action2( $$, SET_ADV_PORT_T, STR_ST, - 0, str_tmp, 0); - } + $$ = 0; + } else { + memcpy(tmp, tstr.s, tstr.len); + tmp[tstr.len] = '\0'; + mk_action2($$, SET_ADV_PORT_T, STR_ST, + 0, tmp, 0); } } - | SET_ADV_PORT LPAREN error RPAREN { $$=0; yyerror("bad argument, " - "string expected"); } + | SET_ADV_PORT LPAREN STRING RPAREN { + mk_action2($$, SET_ADV_PORT_T, + STR_ST, NOSUBTYPE, + $3, NULL); + } + | SET_ADV_PORT LPAREN error RPAREN { $$=0; yyerror("bad argument " + "(string or integer expected)"); } | SET_ADV_PORT error {$$=0; yyerror("missing '(' or ')' ?"); } | FORCE_SEND_SOCKET LPAREN phostport RPAREN { mk_action2( $$, FORCE_SEND_SOCKET_T, @@ -2643,7 +2931,7 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, elems[2].u.data = $7; elems[3].type = NUMBER_ST; elems[3].u.number = $9; - $$ = mk_action(CACHE_STORE_T, 4, elems, line); + mk_action_($$, CACHE_STORE_T, 4, elems); } | CACHE_STORE LPAREN STRING COMMA STRING COMMA STRING COMMA script_var RPAREN { @@ -2655,7 +2943,7 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, elems[2].u.data = $7; elems[3].type = SCRIPTVAR_ST; elems[3].u.data = $9; - $$ = mk_action(CACHE_STORE_T, 4, elems, line); + mk_action_($$, CACHE_STORE_T, 4, elems); } | CACHE_REMOVE LPAREN STRING COMMA STRING RPAREN { @@ -2692,7 +2980,7 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, elems[2].u.number = $7; elems[3].type = NUMBER_ST; elems[3].u.number = $9; - $$ = mk_action(CACHE_ADD_T, 4, elems, line); + mk_action_($$, CACHE_ADD_T, 4, elems); } | CACHE_ADD LPAREN STRING COMMA STRING COMMA script_var COMMA NUMBER RPAREN { elems[0].type = STR_ST; @@ -2703,7 +2991,33 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, elems[2].u.data = $7; elems[3].type = NUMBER_ST; elems[3].u.number = $9; - $$ = mk_action(CACHE_ADD_T, 4, elems, line); + mk_action_($$, CACHE_ADD_T, 4, elems); + } + | CACHE_ADD LPAREN STRING COMMA STRING COMMA NUMBER COMMA NUMBER COMMA script_var RPAREN { + elems[0].type = STR_ST; + elems[0].u.data = $3; + elems[1].type = STR_ST; + elems[1].u.data = $5; + elems[2].type = NUMBER_ST; + elems[2].u.number = $7; + elems[3].type = NUMBER_ST; + elems[3].u.number = $9; + elems[4].type = SCRIPTVAR_ST; + elems[4].u.data = $11; + mk_action_($$, CACHE_ADD_T, 5, elems); + } + | CACHE_ADD LPAREN STRING COMMA STRING COMMA script_var COMMA NUMBER COMMA script_var RPAREN { + elems[0].type = STR_ST; + elems[0].u.data = $3; + elems[1].type = STR_ST; + elems[1].u.data = $5; + elems[2].type = SCRIPTVAR_ST; + elems[2].u.data = $7; + elems[3].type = NUMBER_ST; + elems[3].u.number = $9; + elems[4].type = SCRIPTVAR_ST; + elems[4].u.data = $11; + mk_action_($$, CACHE_ADD_T, 5, elems); } | CACHE_SUB LPAREN STRING COMMA STRING COMMA NUMBER COMMA NUMBER RPAREN { elems[0].type = STR_ST; @@ -2714,7 +3028,7 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, elems[2].u.number = $7; elems[3].type = NUMBER_ST; elems[3].u.number = $9; - $$ = mk_action(CACHE_SUB_T, 4, elems, line); + mk_action_($$, CACHE_SUB_T, 4, elems); } | CACHE_SUB LPAREN STRING COMMA STRING COMMA script_var COMMA NUMBER RPAREN { elems[0].type = STR_ST; @@ -2725,7 +3039,33 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, elems[2].u.data = $7; elems[3].type = NUMBER_ST; elems[3].u.number = $9; - $$ = mk_action(CACHE_SUB_T, 4, elems, line); + mk_action_($$, CACHE_SUB_T, 4, elems); + } + | CACHE_SUB LPAREN STRING COMMA STRING COMMA NUMBER COMMA NUMBER COMMA script_var RPAREN { + elems[0].type = STR_ST; + elems[0].u.data = $3; + elems[1].type = STR_ST; + elems[1].u.data = $5; + elems[2].type = NUMBER_ST; + elems[2].u.number = $7; + elems[3].type = NUMBER_ST; + elems[3].u.number = $9; + elems[4].type = SCRIPTVAR_ST; + elems[4].u.data = $11; + mk_action_($$, CACHE_SUB_T, 5, elems); + } + | CACHE_SUB LPAREN STRING COMMA STRING COMMA script_var COMMA NUMBER COMMA script_var RPAREN { + elems[0].type = STR_ST; + elems[0].u.data = $3; + elems[1].type = STR_ST; + elems[1].u.data = $5; + elems[2].type = SCRIPTVAR_ST; + elems[2].u.data = $7; + elems[3].type = NUMBER_ST; + elems[3].u.number = $9; + elems[4].type = SCRIPTVAR_ST; + elems[4].u.data = $11; + mk_action_($$, CACHE_SUB_T, 5, elems); } | CACHE_RAW_QUERY LPAREN STRING COMMA STRING COMMA STRING RPAREN { elems[0].type = STR_ST; @@ -2734,14 +3074,14 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, elems[1].u.data = $5; elems[2].type = STR_ST; elems[2].u.data = $7; - $$ = mk_action(CACHE_RAW_QUERY_T, 3, elems, line); + mk_action_($$, CACHE_RAW_QUERY_T, 3, elems); } | CACHE_RAW_QUERY LPAREN STRING COMMA STRING RPAREN { elems[0].type = STR_ST; elems[0].u.data = $3; elems[1].type = STR_ST; elems[1].u.data = $5; - $$ = mk_action(CACHE_RAW_QUERY_T, 2, elems, line); + mk_action_($$, CACHE_RAW_QUERY_T, 2, elems); } | ID LPAREN RPAREN { cmd_tmp=(void*)find_cmd_export_t($1, 0, rt); @@ -2757,7 +3097,7 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, }else{ elems[0].type = CMD_ST; elems[0].u.data = cmd_tmp; - $$ = mk_action(MODULE_T, 1, elems, line); + mk_action_($$, MODULE_T, 1, elems); } } | ID LPAREN module_func_param RPAREN { @@ -2774,7 +3114,7 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, }else{ elems[0].type = CMD_ST; elems[0].u.data = cmd_tmp; - $$ = mk_action(MODULE_T, $3+1, elems, line); + mk_action_($$, MODULE_T, $3+1, elems); } } | ID LPAREN error RPAREN { $$=0; yyerrorf("bad arguments for " @@ -2810,13 +3150,13 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, elems[4].u.data = $11; elems[5].type = SCRIPTVAR_ST; elems[5].u.data = $13; - $$ = mk_action(CONSTRUCT_URI_T,6,elems,line); } + mk_action_($$, CONSTRUCT_URI_T,6,elems); } | GET_TIMESTAMP LPAREN script_var COMMA script_var RPAREN { elems[0].type = SCRIPTVAR_ST; elems[0].u.data = $3; elems[1].type = SCRIPTVAR_ST; elems[1].u.data = $5; - $$ = mk_action(GET_TIMESTAMP_T,2,elems,line); } + mk_action_($$, GET_TIMESTAMP_T,2,elems); } | SCRIPT_TRACE LPAREN RPAREN { mk_action2($$, SCRIPT_TRACE_T, 0, 0, 0, 0); } | SCRIPT_TRACE LPAREN NUMBER COMMA STRING RPAREN { @@ -2841,13 +3181,6 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T, %% -extern int column; -extern int startcolumn; -extern char *finame; - -#define get_cfg_file_name \ - ((finame) ? finame : cfg_file ? cfg_file : "default") - static inline void warn(char* s) { LM_WARN("warning in config file %s, line %d, column %d-%d: %s\n", @@ -2883,13 +3216,15 @@ static struct socket_id* mk_listen_id(char* host, int proto, int port) if (l==0){ LM_CRIT("cfg. parser: out of memory.\n"); }else{ - l->name=host; - l->port=port; - l->proto=proto; - l->adv_name=NULL; - l->adv_port=0; - l->next=0; + l->name = host; + l->adv_name = NULL; + l->adv_port = 0; + l->proto = proto; + l->port = port; + l->children = 0; + l->next = NULL; } + return l; } diff --git a/config.h b/config.h index 95f36c97a9c..65743673e0d 100644 --- a/config.h +++ b/config.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -25,6 +25,7 @@ * 2003-07-04 fixed SRV lookup prefix for TLS/sips (andrei) * 2007-02-16 Added an OPENSER_OID define to localize OpenSER's IANA assigned * OID under the enterprise branch (jmagder) + * 2013-09-17 TLS_DH_PARAMS_FILE added (mehmet) */ /*! @@ -40,11 +41,14 @@ #define SIPS_PORT 5061 /*! default sip port for tls if none specified */ #define CFG_FILE CFG_DIR "opensips.cfg" +#define MEM_WARMING_DEFAULT_PATTERN_FILE CFG_DIR "mem_warming_pattern" +#define MEM_WARMING_DEFAULT_PERCENTAGE 75 -#define TLS_PKEY_FILE CFG_DIR "tls/cert.pem" +#define TLS_PKEY_FILE CFG_DIR "tls/cert.pem" #define TLS_CERT_FILE CFG_DIR "tls/cert.pem" #define TLS_CA_FILE 0 /*!< no CA list file by default */ - +#define TLS_CA_DIRECTORY "/etc/pki/CA/" +#define TLS_DH_PARAMS_FILE 0 /*!< no DH params file by default */ #define MAX_LISTEN 16 /*!< maximum number of addresses on which we will listen */ @@ -115,13 +119,20 @@ #define SRV_MAX_PREFIX_LEN SRV_TLS_PREFIX_LEN +#ifdef HP_MALLOC +#define PKG_MEM_SIZE 16 /*!< Used only if PKG_MALLOC is defined*/ +#else #define PKG_MEM_SIZE 2 /*!< Used only if PKG_MALLOC is defined*/ +#endif #define SHM_MEM_SIZE 32 /*!< Used if SH_MEM is defined*/ +#define SHM_MAX_SECONDARY_HASH_SIZE 32 +#define DEFAULT_SHM_HASH_SPLIT_PERCENTAGE 1 /*!< Used if SH_MEM is defined*/ +#define DEFAULT_SHM_SECONDARY_HASH_SIZE 8 #define TIMER_TICK 1 /*!< one second */ #define UTIMER_TICK 100*1000 /*!< 100 miliseconds*/ -/*!< dimensioning buckets in q_malloc +/*!< dimensioning buckets in q_malloc size of the size2bucket table; everything beyond that asks for a variable-size kilo-bucket */ diff --git a/core_stats.c b/core_stats.c index 6db8ab0ac02..14b25c4ec51 100644 --- a/core_stats.c +++ b/core_stats.c @@ -22,7 +22,7 @@ * History: * --------- * 2006-01-23 first version (bogdan) - * 2006-11-28 Added statistics for the number of bad URI's, methods, and + * 2006-11-28 Added statistics for the number of bad URI's, methods, and * proxy requests (Jeffrey Magder - SOMA Networks) * 2009-04-23 NET and PKG statistics added (bogdan) */ @@ -196,42 +196,42 @@ int init_pkg_stats(int no_procs) if ( (name=build_stat_name( &n_str,"total_size"))==0 || register_stat2("pkmem", name, (stat_var**)get_pkg_total_size, - STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n)!=0 ) { + STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n, 0)!=0 ) { LM_ERR("failed to add stat variable\n"); return -1; } if ( (name=build_stat_name( &n_str,"used_size"))==0 || register_stat2("pkmem", name, (stat_var**)get_pkg_used_size, - STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n)!=0 ) { + STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n, 0)!=0 ) { LM_ERR("failed to add stat variable\n"); return -1; } if ( (name=build_stat_name( &n_str,"real_used_size"))==0 || register_stat2("pkmem", name, (stat_var**)get_pkg_real_used_size, - STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n)!=0 ) { + STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n, 0)!=0 ) { LM_ERR("failed to add stat variable\n"); return -1; } if ( (name=build_stat_name( &n_str,"max_used_size"))==0 || register_stat2("pkmem", name, (stat_var**)get_pkg_max_used_size, - STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n)!=0 ) { + STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n, 0)!=0 ) { LM_ERR("failed to add stat variable\n"); return -1; } if ( (name=build_stat_name( &n_str,"free_size"))==0 || register_stat2("pkmem", name, (stat_var**)get_pkg_free_size, - STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n)!=0 ) { + STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n, 0)!=0 ) { LM_ERR("failed to add stat variable\n"); return -1; } if ( (name=build_stat_name( &n_str,"fragments"))==0 || register_stat2("pkmem", name, (stat_var**)get_pkg_fragments, - STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n)!=0 ) { + STAT_NO_RESET|STAT_SHM_NAME|STAT_IS_FUNC, (void*)(long)n, 0)!=0 ) { LM_ERR("failed to add stat variable\n"); return -1; } diff --git a/core_stats.h b/core_stats.h index 949aceee0be..324f58cec1e 100644 --- a/core_stats.h +++ b/core_stats.h @@ -22,7 +22,7 @@ * History: * --------- * 2006-01-23 first version (bogdan) - * 2006-11-28 Added statistics for the number of bad URI's, methods, and + * 2006-11-28 Added statistics for the number of bad URI's, methods, and * proxy requests (Jeffrey Magder - SOMA Networks) * 2009-04-23 NET and PKG statistics added (bogdan) */ diff --git a/crc.c b/crc.c index 70cd552b14e..974c94ac0b8 100644 --- a/crc.c +++ b/crc.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -202,7 +202,7 @@ unsigned short int crc_16_tab[] = { /* CRC polynomial 0xA001 */ unsigned short crcitt_string( char *s, int len ) { register unsigned short ccitt; - + ccitt = 0xFFFF; while( len ) { @@ -246,10 +246,10 @@ void crcitt_string_array( char *dst, str src[], int size ) void crc32_uint (str *source_string, unsigned int *hash_ret) { unsigned int hash; unsigned int len; - const char *data; + const unsigned char *data; hash = 0xffffffff; - data = source_string->s; + data = (const unsigned char *)source_string->s; for (len = source_string->len / 4; len--; data += 4) { hash = crc_32_tab[((unsigned char)hash) ^ data[0]] ^ (hash >> 8); hash = crc_32_tab[((unsigned char)hash) ^ data[1]] ^ (hash >> 8); diff --git a/daemonize.c b/daemonize.c index 15fdc9a03b1..dd98399ee0b 100644 --- a/daemonize.c +++ b/daemonize.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -71,7 +71,7 @@ static int *init_timer_no; int create_status_pipe(void) { int rc; - + status_pipe[0] = -1; status_pipe[1] = -1; @@ -118,7 +118,7 @@ int send_status_code(char val) if (rc == 1) return 0; - + return -1; } @@ -166,7 +166,7 @@ int wait_for_all_children(void) return -1; } - /* we got this far, means everything went ok with + /* we got this far, means everything went ok with * SIP listeners and module procs * * still need to see if @@ -182,7 +182,7 @@ int wait_for_all_children(void) return 0; } -/* cleans read pipe end +/* cleans read pipe end * for processes done reading */ void clean_read_pipeend(void) { @@ -195,7 +195,7 @@ void clean_read_pipeend(void) /* cleans write pipe end * for processes done writing the status code - * MUST be called to ensure that the original + * MUST be called to ensure that the original * parent process does not keep waiting forever */ void clean_write_pipeend(void) { @@ -230,7 +230,7 @@ int daemonize(char* name, int * own_pgid) LM_CRIT("Cannot chroot to %s: %s\n", chroot_dir, strerror(errno)); goto error; } - + if (chdir(working_dir)<0){ LM_CRIT("Cannot chdir to %s: %s\n", working_dir, strerror(errno)); goto error; @@ -241,36 +241,38 @@ int daemonize(char* name, int * own_pgid) goto error; } - /* fork to become!= group leader*/ - if ((pid=fork())<0){ - LM_CRIT("Cannot fork:%s\n", strerror(errno)); - goto error; - }else if (pid!=0){ - /* parent process => wait for status codes from children*/ - clean_write_pipeend(); - LM_DBG("waiting for status code from children\n"); - rc = wait_for_all_children(); - LM_INFO("pre-daemon process exiting with %d\n",rc); - exit(rc); - } + if (!no_daemon_mode) { + /* fork to become!= group leader*/ + if ((pid=fork())<0){ + LM_CRIT("Cannot fork:%s\n", strerror(errno)); + goto error; + }else if (pid!=0){ + /* parent process => wait for status codes from children*/ + clean_write_pipeend(); + LM_DBG("waiting for status code from children\n"); + rc = wait_for_all_children(); + LM_INFO("pre-daemon process exiting with %d\n",rc); + exit(rc); + } - /* cleanup read end - nobody should - * need to read from status pipe from this point on */ - clean_read_pipeend(); + /* cleanup read end - nobody should + * need to read from status pipe from this point on */ + clean_read_pipeend(); - /* become session leader to drop the ctrl. terminal */ - if (setsid()<0){ - LM_WARN("setsid failed: %s\n",strerror(errno)); - }else{ - *own_pgid=1;/* we have our own process group */ - } - /* fork again to drop group leadership */ - if ((pid=fork())<0){ - LM_CRIT("Cannot fork:%s\n", strerror(errno)); - goto error; - }else if (pid!=0){ - /*parent process => exit */ - exit(0); + /* become session leader to drop the ctrl. terminal */ + if (setsid()<0){ + LM_WARN("setsid failed: %s\n",strerror(errno)); + }else{ + *own_pgid=1;/* we have our own process group */ + } + /* fork again to drop group leadership */ + if ((pid=fork())<0){ + LM_CRIT("Cannot fork: %s\n", strerror(errno)); + goto error; + }else if (pid!=0){ + /*parent process => exit */ + exit(0); + } } #ifdef __OS_linux @@ -282,14 +284,14 @@ int daemonize(char* name, int * own_pgid) /* added by noh: create a pid file for the main process */ if (pid_file!=0){ - + if ((pid_stream=fopen(pid_file, "r"))!=NULL){ pid_items=fscanf(pid_stream, "%d", &p); fclose(pid_stream); if (p==-1 || pid_items <= 0){ LM_WARN("pid file %s exists, but doesn't contain a valid" " pid number, replacing...\n", pid_file); - } else + } else if (kill((pid_t)p, 0)==0 || errno==EPERM){ LM_CRIT("running process found in the pid file %s\n", pid_file); @@ -300,13 +302,13 @@ int daemonize(char* name, int * own_pgid) } pid=getpid(); if ((pid_stream=fopen(pid_file, "w"))==NULL){ - LM_ERR("unable to create pid file %s: %s\n", + LM_ERR("unable to create pid file %s: %s\n", pid_file, strerror(errno)); goto error; }else{ r = fprintf(pid_stream, "%i\n", (int)pid); if (r<=0) { - LM_ERR("unable to write pid to file %s: %s\n", + LM_ERR("unable to write pid to file %s: %s\n", pid_file, strerror(errno)); goto error; } @@ -332,7 +334,7 @@ int daemonize(char* name, int * own_pgid) }else{ r = fprintf(pid_stream, "%i\n", (int)pid); if (r<=0) { - LM_ERR("unable to write pgid to file %s: %s\n", + LM_ERR("unable to write pgid to file %s: %s\n", pid_file, strerror(errno)); goto error; } @@ -396,7 +398,7 @@ int do_suid(const int uid, const int gid) { if (!dont_fork) { if (pid_file) { - /* pid file should be already created by deamonize function + /* pid file should be already created by deamonize function -> change the owner and group also */ if (chown( pid_file , uid?uid:-1, gid?gid:-1)!=0) { @@ -406,7 +408,7 @@ int do_suid(const int uid, const int gid) } } if (pgid_file) { - /* pgid file should be already created by deamonize function + /* pgid file should be already created by deamonize function -> change the owner and group also */ if (chown( pgid_file , uid?uid:-1, gid?gid:-1)!=0) { @@ -423,14 +425,14 @@ int do_suid(const int uid, const int gid) goto error; } } - + if(uid){ if(setuid(uid)<0){ LM_CRIT("cannot change uid to %d: %s\n", uid, strerror(errno)); goto error; } } - + #ifdef __OS_linux /* setuid disables core dumping on linux, reenable it */ if ( !disable_core_dump && prctl(PR_SET_DUMPABLE, 1)) { @@ -453,7 +455,7 @@ int do_suid(const int uid, const int gid) int increase_open_fds(unsigned int target) { struct rlimit lim, orig; - + if (getrlimit(RLIMIT_NOFILE, &lim)<0){ LM_CRIT("cannot get the maximum number of file descriptors: %s\n", strerror(errno)); @@ -470,7 +472,7 @@ int increase_open_fds(unsigned int target) }else{ /* more than the hard limit */ LM_INFO("trying to increase the open file limit" - " past the hard limit (%ld -> %d)\n", + " past the hard limit (%ld -> %d)\n", (unsigned long)lim.rlim_max, target); lim.rlim_max=target; lim.rlim_cur=target; @@ -511,7 +513,7 @@ int increase_open_fds(unsigned int target) int set_core_dump(int enable, unsigned int size) { struct rlimit lim, newlim; - + if (enable){ if (getrlimit(RLIMIT_CORE, &lim)<0){ LM_CRIT("cannot get the maximum core size: %s\n", diff --git a/daemonize.h b/daemonize.h index c15ac489907..6de60e82361 100644 --- a/daemonize.h +++ b/daemonize.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/data_lump.c b/data_lump.c index 77ffa0c98b7..e7f45cc424e 100644 --- a/data_lump.c +++ b/data_lump.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -50,7 +50,7 @@ #include #endif -/*! \note WARNING: all lump add/insert operations expect a pkg_malloc'ed char* +/*! \note WARNING: all lump add/insert operations expect a pkg_malloc'ed char* * pointer the will be DEALLOCATED when the sip_msg is destroyed! */ enum lump_dir { LD_NEXT, LD_BEFORE, LD_AFTER }; @@ -58,13 +58,18 @@ enum lump_dir { LD_NEXT, LD_BEFORE, LD_AFTER }; int init_lump_flags = 0; /*! \brief adds a header to the end - * \return returns pointer on success, 0 on error */ + * \return returns pointer if success, 0 on error + * + * WARNING: currently broken! + * - lumps_len() needs to properly handle LUMP_ADD along the main chain of + * lumps before we can use this + */ struct lump* append_new_lump(struct lump** list, char* new_hdr, unsigned int len, enum _hdr_types_t type) { struct lump** t; struct lump* tmp; - + for (t=list;*t;t=&((*t)->next)); tmp=pkg_malloc(sizeof(struct lump)); @@ -72,7 +77,7 @@ struct lump* append_new_lump(struct lump** list, char* new_hdr, LM_ERR("out of pkg memory\n"); return 0; } - + memset(tmp,0,sizeof(struct lump)); tmp->type=type; tmp->flags=init_lump_flags; @@ -85,8 +90,13 @@ struct lump* append_new_lump(struct lump** list, char* new_hdr, -/*! \brief inserts a header to the beginning - * \return returns pointer if success, 0 on error */ +/*! \brief inserts a header to the beginning + * \return returns pointer if success, 0 on error + * + * WARNING: currently broken! + * - lumps_len() needs to properly handle LUMP_ADD along the main chain of + * lumps before we can use this + */ struct lump* insert_new_lump(struct lump** list, char* new_hdr, unsigned int len, enum _hdr_types_t type) { @@ -110,7 +120,7 @@ struct lump* insert_new_lump(struct lump** list, char* new_hdr, -/*! \brief inserts a header/data lump immediately after hdr +/*! \brief inserts a header/data lump immediately after hdr * \return returns pointer on success, 0 on error */ struct lump* insert_new_lump_after( struct lump* after, char* new_hdr, unsigned int len, enum _hdr_types_t type) @@ -136,7 +146,7 @@ struct lump* insert_new_lump_after( struct lump* after, char* new_hdr, -/*! \brief inserts a header/data lump immediately before "before" +/*! \brief inserts a header/data lump immediately before "before" * \return returns pointer on success, 0 on error */ struct lump* insert_new_lump_before( struct lump* before, char* new_hdr, unsigned int len, enum _hdr_types_t type) @@ -162,13 +172,13 @@ struct lump* insert_new_lump_before( struct lump* before, char* new_hdr, -/*! \brief inserts a subst lump immediately after hdr +/*! \brief inserts a subst lump immediately after hdr * \return returns pointer on success, 0 on error */ struct lump* insert_subst_lump_after( struct lump* after,enum lump_subst subst, enum _hdr_types_t type) { struct lump* tmp; - + tmp=pkg_malloc(sizeof(struct lump)); if (tmp==0){ ser_error=E_OUT_OF_MEM; @@ -188,14 +198,14 @@ struct lump* insert_subst_lump_after( struct lump* after,enum lump_subst subst, -/*! \brief inserts a subst lump immediately before "before" +/*! \brief inserts a subst lump immediately before "before" * \return returns pointer on success, 0 on error */ -struct lump* insert_subst_lump_before( struct lump* before, +struct lump* insert_subst_lump_before( struct lump* before, enum lump_subst subst, enum _hdr_types_t type) { struct lump* tmp; - + tmp=pkg_malloc(sizeof(struct lump)); if (tmp==0){ ser_error=E_OUT_OF_MEM; @@ -215,13 +225,13 @@ struct lump* insert_subst_lump_before( struct lump* before, -/*! \brief inserts a cond lump immediately after hdr +/*! \brief inserts a cond lump immediately after hdr * \return returns pointer on success, 0 on error */ struct lump* insert_cond_lump_after( struct lump* after,enum lump_conditions c, enum _hdr_types_t type) { struct lump* tmp; - + tmp=pkg_malloc(sizeof(struct lump)); if (tmp==0){ ser_error=E_OUT_OF_MEM; @@ -241,14 +251,14 @@ struct lump* insert_cond_lump_after( struct lump* after,enum lump_conditions c, -/*! \brief inserts a conditional lump immediately before "before" +/*! \brief inserts a conditional lump immediately before "before" * \return returns pointer on success, 0 on error */ -struct lump* insert_cond_lump_before( struct lump* before, +struct lump* insert_cond_lump_before( struct lump* before, enum lump_conditions c, enum _hdr_types_t type) { struct lump* tmp; - + tmp=pkg_malloc(sizeof(struct lump)); if (tmp==0){ ser_error=E_OUT_OF_MEM; @@ -268,12 +278,12 @@ struct lump* insert_cond_lump_before( struct lump* before, -/*! \brief inserts a skip lump immediately after hdr +/*! \brief inserts a skip lump immediately after hdr * \return returns pointer on success, 0 on error */ struct lump* insert_skip_lump_after( struct lump* after) { struct lump* tmp; - + tmp=pkg_malloc(sizeof(struct lump)); if (tmp==0){ ser_error=E_OUT_OF_MEM; @@ -290,12 +300,12 @@ struct lump* insert_skip_lump_after( struct lump* after) -/*! \brief inserts a skip lump immediately before "before" +/*! \brief inserts a skip lump immediately before "before" * \return returns pointer on success, 0 on error */ struct lump* insert_skip_lump_before( struct lump* before ) { struct lump* tmp; - + tmp=pkg_malloc(sizeof(struct lump)); if (tmp==0){ ser_error=E_OUT_OF_MEM; @@ -338,7 +348,7 @@ struct lump* del_lump(struct sip_msg* msg, unsigned int offset, if (len==0){ LM_WARN("called with 0 len (offset =%d)\n", offset); } - + tmp=pkg_malloc(sizeof(struct lump)); if (tmp==0){ LM_ERR("out of pkg memory\n"); @@ -375,26 +385,20 @@ struct lump* del_lump(struct sip_msg* msg, unsigned int offset, * so msg->eoh must be parsed (parse with HDR_EOH) if you think your lump * might affect the body!! */ struct lump* anchor_lump(struct sip_msg* msg, unsigned int offset, - int unsigned len, enum _hdr_types_t type) + enum _hdr_types_t type) { struct lump* tmp; struct lump* prev, *t; struct lump** list; - + /* extra checks */ if (offset>msg->len){ LM_CRIT("offset exceeds message size (%d > %d)" " aborting...\n", offset, msg->len); abort(); } - if (len){ - LM_WARN("called with len !=0 (%d)\n", len); - if (offset+len>msg->len) - LM_WARN("offset + len exceeds message" - " size (%d + %d > %d)\n", offset, len, msg->len); - } - + tmp=pkg_malloc(sizeof(struct lump)); if (tmp==0){ ser_error=E_OUT_OF_MEM; @@ -406,21 +410,20 @@ struct lump* anchor_lump(struct sip_msg* msg, unsigned int offset, tmp->type=type; tmp->flags=init_lump_flags; tmp->u.offset=offset; - tmp->len=len; prev=0; /* check to see whether this might be a body lump */ if ((msg->eoh) && (offset> (unsigned long)(msg->eoh-msg->buf))) list=&msg->body_lumps; else list=&msg->add_rm; - + for (t=*list;t; prev=t, t=t->next){ /* insert it sorted after offset */ if (((t->op==LUMP_DEL)||(t->op==LUMP_NOP))&&(t->u.offset>offset)) break; } tmp->next=t; - + if (prev) prev->next=tmp; else *list=tmp; return tmp; @@ -467,7 +470,7 @@ void free_lump_list(struct lump* l) free_lump(foo); pkg_free(foo); } - + /*clean current elem*/ free_lump(crt); pkg_free(crt); @@ -493,7 +496,7 @@ static void free_shallow_lump( struct lump *l ) } /*! \brief* duplicate (shallow-ly) a lump list into pkg memory */ -static struct lump *dup_lump_list_r( struct lump *l, +static struct lump *dup_lump_list_r( struct lump *l, enum lump_dir dir, int *error) { int deep_error; @@ -511,22 +514,22 @@ static struct lump *dup_lump_list_r( struct lump *l, new_lump->next=new_lump->before=new_lump->after=0; switch(dir) { - case LD_NEXT: - new_lump->before=dup_lump_list_r(l->before, + case LD_NEXT: + new_lump->before=dup_lump_list_r(l->before, LD_BEFORE, &deep_error); if (deep_error) goto deeperror; - new_lump->after=dup_lump_list_r(l->after, + new_lump->after=dup_lump_list_r(l->after, LD_AFTER, &deep_error); if (deep_error) goto deeperror; - new_lump->next=dup_lump_list_r(l->next, + new_lump->next=dup_lump_list_r(l->next, LD_NEXT, &deep_error); break; case LD_BEFORE: - new_lump->before=dup_lump_list_r(l->before, + new_lump->before=dup_lump_list_r(l->before, LD_BEFORE, &deep_error); break; case LD_AFTER: - new_lump->after=dup_lump_list_r(l->after, + new_lump->after=dup_lump_list_r(l->after, LD_AFTER, &deep_error); break; default: @@ -578,7 +581,7 @@ void free_duped_lump_list(struct lump* l) * duped list, remove it completely, preserve it * otherwise (it is still referred by original list) */ - if (foo->flags!=LUMPFLAG_DUPED) + if (foo->flags!=LUMPFLAG_DUPED) free_lump(foo); pkg_free(foo); } @@ -589,7 +592,7 @@ void free_duped_lump_list(struct lump* l) free_lump(foo); pkg_free(foo); } - + /*clean current elem*/ if (crt->flags!=LUMPFLAG_DUPED) /* (+) ... see above */ free_lump(crt); diff --git a/data_lump.h b/data_lump.h index dca20af98f4..4578c9fe6ef 100644 --- a/data_lump.h +++ b/data_lump.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -26,7 +26,7 @@ * 2003-01-29 s/int/enum ... more convenient for gdb (jiri) * 2003-03-31 added subst lumps -- they expand in ip addr, port a.s.o (andrei) * 2003-04-01 added opt (condition) lumps (andrei) - * 2003-04-02 added more subst lumps: SUBST_{SND,RCV}_ALL + * 2003-04-02 added more subst lumps: SUBST_{SND,RCV}_ALL * => ip:port;transport=proto (andrei) * */ @@ -58,11 +58,19 @@ extern int init_lump_flags; }while(0) -/*! \brief adds a header to the end */ +/*! \brief adds a header to the end + * WARNING: currently broken! + * - lumps_len() needs to properly handle LUMP_ADD along the main chain of + * lumps before we can use this + */ struct lump* append_new_lump(struct lump** list, char* new_hdr, unsigned int len, enum _hdr_types_t type); -/*! \brief inserts a header to the beginning */ +/*! \brief inserts a header to the beginning + * WARNING: currently broken! + * - lumps_len() needs to properly handle LUMP_ADD along the main chain of + * lumps before we can use this + */ struct lump* insert_new_lump(struct lump** list, char* new_hdr, unsigned int len, enum _hdr_types_t type); /*! \brief inserts a header to the beginning - after */ @@ -96,7 +104,7 @@ struct lump* del_lump(struct sip_msg* msg, unsigned int offset, unsigned int len, enum _hdr_types_t type); /*! \brief set an anchor */ struct lump* anchor_lump(struct sip_msg* msg, unsigned int offset, - unsigned int len, enum _hdr_types_t type); + enum _hdr_types_t type); diff --git a/data_lump_rpl.c b/data_lump_rpl.c index 6c00292e318..998b13e0860 100644 --- a/data_lump_rpl.c +++ b/data_lump_rpl.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/data_lump_rpl.h b/data_lump_rpl.h index 5e55950473d..c1305b9baa4 100644 --- a/data_lump_rpl.h +++ b/data_lump_rpl.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/db/db.c b/db/db.c index b8e81c81ddc..64068dd7989 100644 --- a/db/db.c +++ b/db/db.c @@ -3,7 +3,7 @@ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG - * + * * This file is part of opensips, a free SIP server. * * opensips is free software; you can redistribute it and/or modify @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* @@ -271,7 +271,7 @@ db_con_t* db_do_init(const str* url, void* (*new_connection)()) LM_ERR("SQL URL too long\n"); return 0; } - + /* this is the root memory for this database connection. */ res = (db_con_t*)pkg_malloc(con_size); if (!res) { @@ -373,10 +373,10 @@ int db_table_version(const db_func_t* dbf, db_con_t* connection, const str* tabl VAL_TYPE(val) = DB_STR; VAL_NULL(val) = 0; VAL_STR(val) = *table; - + str tmp2 = str_init(VERSION_COLUMN); col[0] = &tmp2; - + if (dbf->query(connection, key, 0, val, col, 1, 1, 0, &res) < 0) { LM_ERR("error in db_query\n"); return -1; diff --git a/db/db.h b/db/db.h index d53295aec14..a893bdd5514 100644 --- a/db/db.h +++ b/db/db.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -53,7 +53,7 @@ /** * \brief Specify table name that will be used for subsequent operations. - * + * * The function db_use_table takes a table name and stores it db_con_t structure. * All subsequent operations (insert, delete, update, query) are performed on * that table. @@ -69,11 +69,11 @@ typedef int (*db_use_table_f)(db_con_t* _h, const str * _t); * This function initialize the database API and open a new database * connection. This function must be called after bind_dbmod but before any * other database API function is called. - * + * * The function takes one parameter, the parameter must contain the database - * connection URL. The URL is of the form + * connection URL. The URL is of the form * mysql://username:password\@host:port/database where: - * + * * username: Username to use when logging into database (optional). * password: password if it was set (optional) * host: Hosname or IP address of the host where database server lives (mandatory) @@ -90,11 +90,11 @@ typedef db_con_t* (*db_init_f) (const str* _sqlurl); /** * \brief Close a database connection and free all memory used. * - * The function closes previously open connection and frees all previously + * The function closes previously open connection and frees all previously * allocated memory. The function db_close must be the very last function called. * \param _h db_con_t structure representing the database connection */ -typedef void (*db_close_f) (db_con_t* _h); +typedef void (*db_close_f) (db_con_t* _h); /** @@ -132,7 +132,7 @@ typedef int (*db_query_f) (const db_con_t* _h, const db_key_t* _k, const db_op_t /** * \brief Fetch a number of rows from a result. - * + * * The function fetches a number of rows from a database result. If the number * of wanted rows is zero, the function returns anything with a result of zero. * \param _h structure representing database connection @@ -176,11 +176,11 @@ typedef int (*db_free_result_f) (db_con_t* _h, db_res_t* _r); /** * \brief Insert a row into the specified table. - * + * * This function implements INSERT SQL directive, you can insert one or more * rows in a table using this function. * \param _h database connection handle - * \param _k array of keys (column names) + * \param _k array of keys (column names) * \param _v array of values for keys specified in _k parameter * \param _n number of keys-value pairs int _k and _v parameters * \return returns 0 if everything is OK, otherwise returns value < 0 @@ -197,7 +197,7 @@ typedef int (*db_insert_f) (const db_con_t* _h, const db_key_t* _k, * If _k is NULL and _v is NULL and _n is zero, all rows are deleted, the * resulting table will be empty. * If _o is NULL, the equal operator "=" will be used for the comparison. - * + * * \param _h database connection handle * \param _k array of keys (column names) that will be matched * \param _o array of operators to be used with key-value pairs @@ -249,7 +249,7 @@ typedef int (*db_replace_f) (const db_con_t* handle, const db_key_t* keys, * \brief Retrieve the last inserted ID in a table. * * The function returns the value generated for an AUTO_INCREMENT column by the - * previous INSERT or UPDATE statement. Use this function after you have + * previous INSERT or UPDATE statement. Use this function after you have * performed an INSERT statement into a table that contains an AUTO_INCREMENT * field. * \param _h structure representing database connection @@ -261,7 +261,7 @@ typedef int (*db_last_inserted_id_f) (const db_con_t* _h); /** * \brief Insert a row into specified table, update on duplicate key. - * + * * The function implements the INSERT ON DUPLICATE KEY UPDATE SQL directive. * It is possible to insert a row and update if one already exists. * The old row will not deleted before the insertion of the new data. @@ -277,7 +277,7 @@ typedef int (*db_insert_update_f) (const db_con_t* _h, const db_key_t* _k, /** * \brief Database module callbacks - * + * * This structure holds function pointer to all database functions. Before this * structure can be used it must be initialized with bind_dbmod. * \see bind_dbmod @@ -292,12 +292,12 @@ typedef struct db_func { db_raw_query_f raw_query; /* Raw query - SQL */ db_free_result_f free_result; /* Free a query result */ db_insert_f insert; /* Insert into table */ - db_delete_f delete; /* Delete from table */ + db_delete_f delete; /* Delete from table */ db_update_f update; /* Update table */ db_replace_f replace; /* Replace row in a table */ db_last_inserted_id_f last_inserted_id; /* Retrieve the last inserted ID in a table */ - db_insert_update_f insert_update; /* Insert into table, update on duplicate key */ + db_insert_update_f insert_update; /* Insert into table, update on duplicate key */ } db_func_t; @@ -305,7 +305,7 @@ typedef struct db_func { * \brief Bind database module functions * * This function is special, it's only purpose is to call find_export function in - * the core and find the addresses of all other database related functions. The + * the core and find the addresses of all other database related functions. The * db_func_t callback given as parameter is updated with the found addresses. * * This function must be called before any other database API call! @@ -338,7 +338,7 @@ db_con_t* db_do_init(const str* url, void* (*new_connection)()); /** * \brief Helper for db_close function. * - * This helper method does some work for the closing of a database + * This helper method does some work for the closing of a database * connection. No function should be called after this * \param _h database connection handle * \param (*free_connection) Pointer to the db specifc free_connection method @@ -400,7 +400,7 @@ typedef int (*db_bind_api_f)(const str* mod, db_func_t *dbb); * payload_size: the total size of data that will be stored in a row * column_count: the column count, used for aproximating the overhead * return > 0 : estimate of how many rows may be allocated - * = 0 : allocator does not support statistics. + * = 0 : allocator does not support statistics. * < 0 : allocator internal error when counting. -> you should ignore it */ int estimate_available_rows( int payload_size, int column_count); diff --git a/db/db_cap.h b/db/db_cap.h index 0eeb52b6f06..36522f8c952 100644 --- a/db/db_cap.h +++ b/db/db_cap.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -52,7 +52,7 @@ typedef enum db_cap { /** - * All database capabilities except raw_query, replace, insert_update and + * All database capabilities except raw_query, replace, insert_update and * last_inserted_id which should be checked separately when needed */ #define DB_CAP_ALL (DB_CAP_QUERY | DB_CAP_INSERT | DB_CAP_DELETE | DB_CAP_UPDATE) diff --git a/db/db_con.h b/db/db_con.h index 8588210a7f2..bd22b84b9b2 100644 --- a/db/db_con.h +++ b/db/db_con.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_id.c b/db/db_id.c index ddc374f9b2d..fbbb081694e 100644 --- a/db/db_id.c +++ b/db/db_id.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2005 iptel.org @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -56,7 +56,7 @@ static int dupl_string(char** dst, const char* begin, const char* end) /** - * Parse a database URL of form + * Parse a database URL of form * scheme://[username[:password]@]hostname[:port]/database * * \param id filled id struct @@ -127,7 +127,7 @@ static int parse_db_url(struct db_id* id, const str* url) st = ST_USER_HOST; begin = url->s + i + 1; break; - + default: goto err; } @@ -194,7 +194,7 @@ static int parse_db_url(struct db_id* id, const str* url) return 0; } break; - + case ST_DB: break; } diff --git a/db/db_id.h b/db/db_id.h index 0c2304ff638..5bc8d9d23e4 100644 --- a/db/db_id.h +++ b/db/db_id.h @@ -1,9 +1,9 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2005 iptel.org * Copyright (C) 2007-2008 1&1 Internet AG - * + * * This file is part of opensips, a free SIP server. * * opensips is free software; you can redistribute it and/or modify @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_insertq.c b/db/db_insertq.c index 16ecc262953..3ad9cba2476 100644 --- a/db/db_insertq.c +++ b/db/db_insertq.c @@ -33,7 +33,7 @@ query_list_t **query_list = NULL; query_list_t **last_query = NULL; gen_lock_t *ql_lock; -/* inits all the global variables needed for the insert query lists */ +/* inits all the global variables needed for the insert query lists */ int init_query_list(void) { query_list = shm_malloc(sizeof(query_list_t *)); @@ -81,12 +81,12 @@ int init_query_list(void) * inherit same queue */ int init_ql_support(void) { - if (query_buffer_size > 1) + if (query_buffer_size > 1) { if (init_query_list() != 0 || register_timer_process("querydb-flush", ql_timer_routine,NULL, query_flush_time>0?query_flush_time:DEF_FLUSH_TIME, - TIMER_PROC_INIT_FLAG) < 0 ) + TIMER_PROC_INIT_FLAG) < 0 ) { LM_ERR("failed initializing ins list support\n"); return -1; @@ -109,7 +109,7 @@ void flush_query_list(void) if (it->no_rows > 0) { memset(&it->dbf,0,sizeof(db_func_t)); - if (db_bind_mod(&it->url,&it->dbf) < 0) + if (db_bind_mod(&it->url,&it->dbf) < 0) { LM_ERR("failed to bind to db at shutdown\n"); lock_release(it->lock); @@ -125,6 +125,10 @@ void flush_query_list(void) } it->dbf.use_table(it->conn,&it->table); + + //Reset prepared statement between query lists/connections + my_ps = NULL; + CON_PS_REFERENCE(it->conn) = &my_ps; /* and let's insert the rows */ @@ -148,7 +152,7 @@ void flush_query_list(void) void destroy_query_list(void) { query_list_t *it; - + for (it=*query_list;it;it=it->next) { lock_destroy(it->lock); @@ -172,7 +176,7 @@ void handle_ql_shutdown(void) } } -/* adds a new type of query to the list +/* adds a new type of query to the list * assumes ql_lock is acquired*/ void ql_add_unsafe(query_list_t *entry) { @@ -222,7 +226,7 @@ int ql_detach_rows_unsafe(query_list_t *entry,db_val_t ***ins_rows) return no_rows; } -/* safely adds a new row to the insert list +/* safely adds a new row to the insert list * also checks if the queue is full and returns all the rows that need to * be flushed to DB to the caller * @@ -332,7 +336,7 @@ query_list_t *ql_init(db_con_t *con,db_key_t *cols,int col_no) key_size += cols[i]->len; row_q_size = sizeof(db_val_t *) * query_buffer_size; - size = sizeof(query_list_t) + con->table->len + key_size + + size = sizeof(query_list_t) + con->table->len + key_size + row_q_size + con->url.len; entry = shm_malloc(size); @@ -360,7 +364,7 @@ query_list_t *ql_init(db_con_t *con,db_key_t *cols,int col_no) shm_free(entry); return NULL; } - + /* deal with the table name */ entry->table.s = (char *)entry+sizeof(query_list_t); entry->table.len = con->table->len; @@ -374,10 +378,10 @@ query_list_t *ql_init(db_con_t *con,db_key_t *cols,int col_no) pos = (char *)(entry->cols + col_no) + col_no * sizeof(str); for (i=0;icols[i] = (str *)((char *)(entry->cols + col_no) + + entry->cols[i] = (str *)((char *)(entry->cols + col_no) + i * sizeof(str)); entry->cols[i]->len = cols[i]->len; - entry->cols[i]->s = pos; + entry->cols[i]->s = pos; memcpy(pos,cols[i]->s,cols[i]->len); pos += cols[i]->len; } @@ -420,14 +424,14 @@ query_list_t *find_query_list_unsafe(const str *table,db_key_t *cols,int col_no) } /* match table name */ - if (it->table.len != table->len || + if (it->table.len != table->len || memcmp(it->table.s,table->s,table->len) != 0) { LM_DBG("different tables - [%.*s] - [%.*s] \n",it->table.len,it->table.s, table->len,table->s); continue; } - + /* match columns */ for (i=0;inext) { lock_get(it->lock); - + /* are there any old queries in queue ? */ if (it->oldest_query && (now - it->oldest_query > query_flush_time)) { @@ -558,7 +562,7 @@ void ql_timer_routine(unsigned int ticks,void *param) if (it->conn == NULL) { /* first time timer kicked in for this query */ - if (db_bind_mod(&it->url,&it->dbf) < 0) + if (db_bind_mod(&it->url,&it->dbf) < 0) { LM_ERR("timer failed to bind to db\n"); lock_release(it->lock); diff --git a/db/db_insertq.h b/db/db_insertq.h index 2916e3de27c..1de3b0efbda 100644 --- a/db/db_insertq.h +++ b/db/db_insertq.h @@ -30,16 +30,16 @@ #include "db_query.h" #include "../locking.h" -extern int query_buffer_size; /* number of insert queries that will be - held in memory once this number of same - type of queries pile up to this number, +extern int query_buffer_size; /* number of insert queries that will be + held in memory once this number of same + type of queries pile up to this number, they will be flushed to DB */ extern int query_flush_time; /* if the query contains inserts older that query_flush_time seconds, the timer will kick in and flush to DB, to maintain "real time" sync with DB */ -#define CON_HAS_INSLIST(cn) ((cn)->ins_list) +#define CON_HAS_INSLIST(cn) ((cn)->ins_list) #define DEF_FLUSH_TIME 10 /* seconds */ typedef struct query_list { @@ -90,7 +90,7 @@ inline int ql_flush_rows(db_func_t *dbf,db_con_t *conn,query_list_t *entry); do { \ *((int *)&(con)->flags) &= ~CON_INSTANT_FLUSH; \ lock_release((entry)->lock); \ - } while (0) + } while (0) inline void cleanup_rows(db_val_t **rows); void handle_ql_shutdown(void); diff --git a/db/db_key.h b/db/db_key.h index f1406230595..b6dff87632d 100644 --- a/db/db_key.h +++ b/db/db_key.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_op.h b/db/db_op.h index e98b4b8403d..02ade3c4ee6 100644 --- a/db/db_op.h +++ b/db/db_op.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_pool.c b/db/db_pool.c index 48cf3219e1f..0ede955c6e9 100644 --- a/db/db_pool.c +++ b/db/db_pool.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2005 iptel.org @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_pool.h b/db/db_pool.h index af036b4902d..d7f96db3569 100644 --- a/db/db_pool.h +++ b/db/db_pool.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2005 iptel.org @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -59,7 +59,7 @@ struct pool_con* pool_get(const struct db_id* id); /** * Insert a new connection into the pool. - * \param con the inserted connection + * \param con the inserted connection */ void pool_insert(struct pool_con* con); diff --git a/db/db_ps.h b/db/db_ps.h index 32a60ab0f44..2358396cd82 100644 --- a/db/db_ps.h +++ b/db/db_ps.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_query.c b/db/db_query.c index 78e7a258ec9..d524fb8c170 100644 --- a/db/db_query.c +++ b/db/db_query.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -159,7 +159,7 @@ int db_do_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, LM_ERR("invalid parameter value\n"); return -1; } - + /* insert buffering is enabled ? */ if (CON_HAS_INSLIST(_h) && !CON_HAS_PS(_h)) { @@ -167,8 +167,8 @@ int db_do_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, if (IS_INSTANT_FLUSH(_h)) { LM_DBG("timer wishing to flush \n"); - /* if caller signals it's flush time ( timer, etc ), - * detach rows in queue + /* if caller signals it's flush time ( timer, etc ), + * detach rows in queue * the caller is holding the lock at this point */ no_rows = ql_detach_rows_unsafe(_h->ins_list,&buffered_rows); CON_FLUSH_RESET(_h,_h->ins_list); @@ -188,7 +188,7 @@ int db_do_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, return 0; } } - + /* if connection has prepared statement, leave the row insertion to the proper module func, as the submit_query func provided is a dummy one*/ @@ -220,8 +220,8 @@ int db_do_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, { if (buffered_rows != NULL || CON_HAS_PS(_h)) { - /* if we have to insert now, build the query - * + /* if we have to insert now, build the query + * * if a prep stmt is provided, * build a prep stmt with query_buffer_size elements */ @@ -246,8 +246,10 @@ int db_do_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, /* if we have a PS, leave the function handling prep stmts in the module to free the rows once it's done */ - if (!CON_HAS_PS(_h)) + if (!CON_HAS_PS(_h)) { shm_free(buffered_rows[i]); + buffered_rows[i] = NULL; + } } if (off + 1 > SQL_BUF_LEN) goto error0; @@ -257,7 +259,7 @@ int db_do_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, goto submit; } - else + else { /* wait for queries to pile up */ return 0; @@ -382,7 +384,7 @@ int db_do_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o, LM_ERR("error while submitting query\n"); CON_OR_RESET(_h); return -2; - } + } CON_OR_RESET(_h); return 0; diff --git a/db/db_query.h b/db/db_query.h index ae54a5d469c..de06f694008 100644 --- a/db/db_query.h +++ b/db/db_query.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -103,7 +103,7 @@ int db_do_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r, * \param _h structure representing database connection * \param _k key names * \param _v values of the keys - * \param _n number of key/value pairs + * \param _n number of key/value pairs * \param (*val2str) function pointer to the db specific val conversion function * \param (*submit_query) function pointer to the db specific query submit function * \return zero on success, negative on errors diff --git a/db/db_res.c b/db/db_res.c index cbba30f80bf..0424664de5c 100644 --- a/db/db_res.c +++ b/db/db_res.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_res.h b/db/db_res.h index eeb3d446abd..c190d793622 100644 --- a/db/db_res.h +++ b/db/db_res.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -40,7 +40,7 @@ struct db_row; /** - * This type represents a result returned by db_query function (see below). The + * This type represents a result returned by db_query function (see below). The * result can consist of zero or more rows (see db_row_t description). * * Note: A variable of type db_res_t returned by db_query function uses dynamicaly diff --git a/db/db_row.c b/db/db_row.c index 5709fba7757..944c81553bd 100644 --- a/db/db_row.c +++ b/db/db_row.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_row.h b/db/db_row.h index 55caa31f02b..be5972df7d7 100644 --- a/db/db_row.h +++ b/db/db_row.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_ut.c b/db/db_ut.c index 5e95e3d9b36..16caa7c7763 100644 --- a/db/db_ut.c +++ b/db/db_ut.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -43,18 +43,23 @@ inline int db_str2int(const char* _s, int* _v) { long tmp; + char* p = NULL; if (!_s || !_v) { LM_ERR("Invalid parameter value\n"); return -1; } - tmp = strtol(_s, 0, 10); + tmp = strtol(_s, &p, 10); if (((tmp == LONG_MAX || tmp == LONG_MIN) && errno == ERANGE) || (tmp < INT_MIN) || (tmp > INT_MAX)) { LM_ERR("Value out of range\n"); return -1; } + if (p && *p != '\0') { + LM_ERR("Unexpected characters: [%s]\n", p); + return -2; + } *_v = (int)tmp; return 0; @@ -63,17 +68,22 @@ inline int db_str2int(const char* _s, int* _v) inline int db_str2bigint(const char* _s, long long* _v) { long long tmp; + char* p = NULL; if (!_s || !_v) { LM_ERR("Invalid parameter value\n"); return -1; } - tmp = strtoll(_s, 0, 10); + tmp = strtoll(_s, &p, 10); if ((tmp == LLONG_MIN || tmp == LLONG_MAX) && errno == ERANGE) { LM_ERR("Value out of range\n"); return -1; } + if (p && *p != '\0') { + LM_ERR("Unexpected characters: [%s]\n", p); + return -2; + } *_v = tmp; return 0; @@ -165,7 +175,7 @@ inline int db_double2str(double _v, char* _s, int* _l) } -/* +/* * Convert a string to time_t */ inline int db_str2time(const char* _s, time_t* _v) @@ -189,7 +199,7 @@ inline int db_str2time(const char* _s, time_t* _v) * so let mktime to guess it. This eliminates the bug when * contacts reloaded from the database have different time * of expiration by one hour when daylight saving is used - */ + */ time.tm_isdst = -1; *_v = mktime(&time); @@ -323,7 +333,7 @@ int db_print_where(const db_con_t* _c, char* _b, const int _l, const db_key_t* _ for(i = 0; i < _n; i++) { if (_o) { - ret = snprintf(_b + len, _l - len, "%.*s%s", + ret = snprintf(_b + len, _l - len, "%.*s%s", _k[i]->len, _k[i]->s, _o[i]); if (ret < 0 || ret >= (_l - len)) goto error; len += ret; diff --git a/db/db_ut.h b/db/db_ut.h index 49e13aaff02..c3f29fe6c45 100644 --- a/db/db_ut.h +++ b/db/db_ut.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/db_val.h b/db/db_val.h index 1e4b94cec14..4c7ab1fdcd7 100644 --- a/db/db_val.h +++ b/db/db_val.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2007-2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/db/example/dbexample.c b/db/example/dbexample.c index e5b4ebe8da1..0a0bd1de22a 100644 --- a/db/example/dbexample.c +++ b/db/example/dbexample.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -38,8 +38,8 @@ */ -static struct module_exports dbex_exports= { - "DBExample", +static struct module_exports dbex_exports= { + "DBExample", (char*[]) { }, (cmd_function[]) { @@ -87,7 +87,7 @@ static int print_res(db_res_t* _r) printf("%s ", RES_ROWS(_r)[i].values[j].val.string_val); break; case DB_STR: - printf("%.*s ", + printf("%.*s ", RES_ROWS(_r)[i].values[j].val.str_val.len, RES_ROWS(_r)[i].values[j].val.str_val.s); break; @@ -102,11 +102,11 @@ static int print_res(db_res_t* _r) printf("%d ", RES_ROWS(_r)[i].values[j].val.bitmap_val); break; } - + } printf("\n"); } - + return TRUE; } @@ -124,7 +124,7 @@ struct module_exports* mod_register() db_key_t keys3[] = {"username", "contact"}; db_key_t keys4[] = {"contact", "q"}; - db_val_t vals1[] = { + db_val_t vals1[] = { { DB_STRING , 0, { .string_val = "foo@bar.com" } }, { DB_STR , 0, { .str_val = { "real@foo.bar.com", 18 } } }, { DB_DOUBLE , 0, { .double_val = 1.2 } }, @@ -133,7 +133,7 @@ struct module_exports* mod_register() { DB_BITMAP , 0, { .bitmap_val = FLAG_NAT | FLAG_INVITE } } }; - db_val_t vals2[] = { + db_val_t vals2[] = { { DB_STRING , 0, { .string_val = "foo2@bar2.com" } }, { DB_STR , 0, { .str_val = { "real2@foo.bar2.com", 18 } } }, { DB_DOUBLE , 0, { .double_val = 1.3 } }, @@ -142,7 +142,7 @@ struct module_exports* mod_register() { DB_BITMAP , 0, { .bitmap_val = FLAG_NAT, FLAG_NOT_INVITE } } }; - db_val_t vals3[] = { + db_val_t vals3[] = { { DB_STRING , 0, { .string_val = "foo3@bar3.com" } }, { DB_STR , 0, { .str_val = { "real3@foo.bar3.com", 18 } } }, { DB_DOUBLE , 0, { .double_val = 1.5 } }, @@ -155,7 +155,7 @@ struct module_exports* mod_register() { DB_STRING, 0, { .string_val = "foo2@bar2.com" } }, { DB_DOUBLE, 0, { .double_val = 1.30 } } }; - + db_val_t vals5[] = { { DB_STRING, 0, { .string_val = "foo3@bar3.com" } }, { DB_STRING, 0, { .string_val = "real3@foo.bar3.com" } } @@ -193,7 +193,7 @@ struct module_exports* mod_register() return &dbex_exports; } - /* + /* * Specify a table name, that will * be used for manipulations */ @@ -265,7 +265,7 @@ struct module_exports* mod_register() /* * Close existing database connection - * and free previously allocated + * and free previously allocated * memory */ db_close(h); diff --git a/db/schema/Makefile b/db/schema/Makefile index 763ebb94269..f6e546b527e 100644 --- a/db/schema/Makefile +++ b/db/schema/Makefile @@ -127,19 +127,19 @@ dbtext: --stringparam db "dbtext" \ $(DBTEXT_XSL) opensips-"$$FILE".xml ; \ done - TMPFILE=`mktemp -t opensips-test.XXXXXXXXXX` - # small hack to create the version table entries, this is here easier as with XSL - for FILE in $(wildcard $(ROOT)/scripts/dbtext/opensips/*) ; do \ + set -e; \ + TMPFILE=`mktemp -t opensips-test.XXXXXXXXXX`; \ + for FILE in $(sort $(wildcard $(ROOT)/scripts/dbtext/opensips/*)) ; do \ if [ -f "$$FILE" ]; then \ if [ "$$FILE" != "$(ROOT)/scripts/dbtext/opensips/version" -a \ `wc -l "$$FILE" | cut -f 1 -d ' '` -gt 1 ]; then \ tail -1 "$$FILE" >> "$(ROOT)/scripts/dbtext/opensips/version" ; \ - head -n 1 "$$FILE" > $TMPFILE ; \ - cp $TMPFILE "$$FILE" ; \ + head -n 1 "$$FILE" > "$$TMPFILE" ; \ + cp "$$TMPFILE" "$$FILE" ; \ fi ; \ fi ; \ done ; \ - rm -f $TMPFILE + rm -f "$$TMPFILE" dbtext_clean: -@rm -f $(ROOT)/scripts/dbtext/opensips/* @@ -153,18 +153,18 @@ db_berkeley: --stringparam db "db_berkeley" \ $(DB_BERKELEY_XSL) opensips-"$$FILE".xml ; \ done - TMPFILE=`mktemp -t opensips-test.XXXXXXXXXX` - # small hack to create the version table entries, this is here easier as with XSL - for FILE in $(wildcard $(ROOT)/scripts/db_berkeley/opensips/*) ; do \ + set -e; \ + TMPFILE=`mktemp -t opensips-test.XXXXXXXXXX`; \ + for FILE in $(sort $(wildcard $(ROOT)/scripts/db_berkeley/opensips/*)) ; do \ if [ -f "$$FILE" ]; then \ if [ "$$FILE" != "$(ROOT)/scripts/db_berkeley/opensips/version" ]; then \ tail -2 "$$FILE" >> "$(ROOT)/scripts/db_berkeley/opensips/version" ; \ - head -n 10 "$$FILE" > $TMPFILE ; \ - cp $TMPFILE "$$FILE" ; \ + head -n 10 "$$FILE" > "$$TMPFILE" ; \ + cp "$$TMPFILE" "$$FILE" ; \ fi ; \ fi ; \ done ; \ - rm -f $TMPFILE + rm -f "$$TMPFILE" db_berkeley_clean: -@rm -f $(ROOT)/scripts/db_berkeley/opensips/* diff --git a/db/schema/b2b_sca.xml b/db/schema/b2b_sca.xml new file mode 100644 index 00000000000..32b702e1a56 --- /dev/null +++ b/db/schema/b2b_sca.xml @@ -0,0 +1,511 @@ + + +%entities; + +]> + + + b2b_sca + 1 + &MYSQL_TABLE_TYPE; + + Persistent sca information for the b2b_sca module. More + information can be found at: &OPENSIPS_MOD_DOC;b2b_sca.html + + + + + id + unsigned int + &table_id_len; + + + int,auto + unique ID + + + + shared_line + string + &user_len; + The shared line. + + + + + watchers + string + 255 + The URI list of watchers + + + + + app1_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app1_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app1_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app1_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app1_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app2_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app2_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app2_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app2_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app2_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app3_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app3_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app3_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app3_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app3_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app4_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app4_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app4_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app4_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app4_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app5_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app5_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app5_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app5_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app5_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app6_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app6_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app6_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app6_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app6_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app7_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app7_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app7_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app7_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app7_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app8_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app8_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app8_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app8_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app8_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app9_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app9_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app9_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app9_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app9_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + app10_shared_entity + unsigned int + 1 + + + The entity to keep. + + + + app10_call_state + unsigned int + 1 + + + The state of the appearance index. + + + + app10_call_info_uri + string + &uri_len; + + + The URI of the Call-Info header + + + + app10_call_info_appearance_uri + string + &uri_len; + + + The URI of the appearance in Call-Info header + + + + app10_b2bl_key + string + &user_len; + + + The b2b_logic key. + + + + + sca_idx + + + +
diff --git a/db/schema/cachedb_sql.xml b/db/schema/cachedb_sql.xml index f0d241a7991..5e4ad2d6c43 100644 --- a/db/schema/cachedb_sql.xml +++ b/db/schema/cachedb_sql.xml @@ -9,7 +9,7 @@ cachedb - 1 + 2&MYSQL_TABLE_TYPE; DB implementation of the CacheDB interface: &OPENSIPS_MOD_DOC;cachedb_sql.html @@ -20,6 +20,7 @@ keyname string 255 + The Key diff --git a/db/schema/carrierfailureroute.xml b/db/schema/carrierfailureroute.xml index dc70058b984..41544ffb4e9 100644 --- a/db/schema/carrierfailureroute.xml +++ b/db/schema/carrierfailureroute.xml @@ -12,7 +12,7 @@ 2 &MYSQL_TABLE_TYPE; - This table is used by the carrierroute module to provide failure routing capabilities. More information is available at: http://www.opensips.org/docs/modules/devel/carrierroute.html + This table is used by the carrierroute module to provide failure routing capabilities. More information is available at: &OPENSIPS_MOD_DOC;carrierroute.html diff --git a/db/schema/carrierroute.xml b/db/schema/carrierroute.xml index c0a4f2bccbe..93762dd34f8 100644 --- a/db/schema/carrierroute.xml +++ b/db/schema/carrierroute.xml @@ -12,7 +12,7 @@ 3 &MYSQL_TABLE_TYPE; - This table is used by the carrierroute module to provides routing, balancing and blacklisting capabilities. More information is available at: http://www.opensips.org/docs/modules/devel/carrierroute.html + This table is used by the carrierroute module to provides routing, balancing and blacklisting capabilities. More information is available at: &OPENSIPS_MOD_DOC;carrierroute.html diff --git a/db/schema/cc_agents.xml b/db/schema/cc_agents.xml new file mode 100644 index 00000000000..04e36a68bad --- /dev/null +++ b/db/schema/cc_agents.xml @@ -0,0 +1,92 @@ + + +%entities; + +]> + +
+ cc_agents + 1 + &MYSQL_TABLE_TYPE; + + This table is used by the Call Center module to store + the definition of the agents serving the flows/queues. + More information can be found at: &OPENSIPS_MOD_DOC;call_center.html. + + + + + id + unsigned int + &table_id_len; + + + int,auto + Agent unique ID in DB + + + + + agentid + string + 128 + The unique ID of the agent in the + Call Center module - to be used to identify the + agent in the module and from outside the module; + It is an alphanumerical string. + + + + + location + string + 128 + SIP URI point to the agent location; + All calls for this agents will be sent to this + SIP address. + + + + logstate + unsigned int + 10 + 0 + The login state of the agent; + 0 - not logged in; 1 - logged in ; Agent will + start receiving calls only if logged in. + + + + + skills + string + 255 + Comma separated list of skills offered + by the agent; these skills must match the skills used + in the queues/flows definition; In order to receive + calls from a flow, the agent must have the skill required + by that flow. + + + + + last_call_end + int + 11 + 0 + The timestamp of the last call of an agent. + If different than 0, the agent will only receive calls after + wrapup seconds pass after this timestamp. + + + + + unique_agentid + + + + +
diff --git a/db/schema/cc_calls.xml b/db/schema/cc_calls.xml new file mode 100644 index 00000000000..ef2620502aa --- /dev/null +++ b/db/schema/cc_calls.xml @@ -0,0 +1,137 @@ + + +%entities; + +]> + + + cc_calls + &MYSQL_TABLE_TYPE; + + This table is used by the Call Center module to store ongoing calls for restart persitancy. + It consists only of runtime data and should not be manually provisioned. + More information can be found at: &OPENSIPS_MOD_DOC;call_center.html. + + + + + id + unsigned int + &table_id_len; + + + int,auto + unique ID of the call. + + + + + state + int + 11 + The state of the call. + + + + + ig_cback + int + 11 + Indicates if the call should be ignored. + + + + + no_rej + int + 11 + Indicates whether the call can be rejected or not. + + + + + setup_time + int + 11 + Stores the call setup time. + + + + + eta + int + 11 + The estimated wait time for a call until + it is answered by an agent. + + + + + last_start + int + 11 + Stores the timestamp when the last call has started. + + + + + recv_time + int + 11 + Stores the timestamp when the call was received by the + call center. + + + + + caller_dn + string + 128 + Caller Display Name. + + + + + caller_un + string + 128 + Caller User Name. + + + + + b2buaid + string + 128 + + + The B2B id internally used by the B2B module to identify + the call. + + + + + flow + string + 128 + The flow/queue this call belongs to. + + + + + agent + string + 128 + The agent that handles the call. + + + + + unique_id + + + +
diff --git a/db/schema/cc_cdrs.xml b/db/schema/cc_cdrs.xml new file mode 100644 index 00000000000..7c3db14f551 --- /dev/null +++ b/db/schema/cc_cdrs.xml @@ -0,0 +1,142 @@ + + +%entities; + +]> + + + cc_cdrs + 1 + &MYSQL_TABLE_TYPE; + + This table is used by the Call Center module to store + the Call Data Records (CDRs) for all the handled calls. + More information can be found at: &OPENSIPS_MOD_DOC;call_center.html. + + + + + id + unsigned int + &table_id_len; + + + + int,auto + CDR unique ID in DB + + + + + caller + string + 64 + The SIP URI identifing the caller. + + + + + received_timestamp + datetime + When the call was received. + + + + + wait_time + unsigned int + 11 + 0 + Time (in seconds) spent by the call + in queue (onhold). + + + + + pickup_time + unsigned int + 11 + 0 + Time (in seconds) spent by the call + in ringing to the agent. + + + + + talk_time + unsigned int + 11 + 0 + The duration (in seconds) of the call. + + + + + flow_id + string + 128 + The ID of the flow the call was + received on. + + + + + agent_id + string + 128 + + + The ID of the agent who picked + this call (if any). + + + + + call_type + int + 11 + -1 + Type of call: -2 - call rejected by agent; + -1 - call dropped because of internal error; + 0 - call handled by agent; + 1 - call dropped while in queue; + + + + + rejected + unsigned int + 11 + 0 + How many times the call was rejected by agents + (agent not answering his phone). + + + + + fstats + unsigned int + 11 + 0 + Bitmask of the following binary flags: + 0 - it is inbound call; + 1 - call was distributed to agents; + 2 - call was answered; + 3 - call was abandoned. + + + + + cid + unsigned int + 11 + 0 + + Sequence number of the call. + + + +
diff --git a/db/schema/cc_flows.xml b/db/schema/cc_flows.xml new file mode 100644 index 00000000000..6854642bd86 --- /dev/null +++ b/db/schema/cc_flows.xml @@ -0,0 +1,101 @@ + + +%entities; + +]> + + + cc_flows + 1 + &MYSQL_TABLE_TYPE; + + This table is used by the Call Center module to store + the definition of the call queues / flows. + More information can be found at: &OPENSIPS_MOD_DOC;call_center.html. + + + + + id + unsigned int + &table_id_len; + + + int,auto + Flow unique ID in DB + + + + + flowid + string + 64 + The unique ID of the flow in the + Call Center module - to be used to identify the + flow/queue in the module and from outside the module; + It is an alphanumerical string. + + + + + priority + unsigned int + 11 + 256 + The priority of the flow (in relation to + the other flows); 0 is maximum priority and calls for + this flow will be processed first all the time. + + + + + skill + string + 64 + The skill required from an agent in order + to receive calls from this flow/queue. + + + + + prependcid + string + 32 + Aphanumerical prefix to be added to the + caller displayname when sending calls from this flow + to agents (so agent - serving muliple flows - can see + what was the flow the call was received on. + + + + + message_welcome + string + 128 + + + SIP URI point to a media server; this is + used for playing the welcome message for this + flow. + + + + message_queue + string + 128 + SIP URI point to a media server; this is + used for playing the onhold message for this + flow. IMPORTANT - this message must cycle and media + server must never hung up on it. + + + + unique_flowid + + + + +
diff --git a/db/schema/dialog.xml b/db/schema/dialog.xml index 5aa611f72f2..cf8e3b96009 100644 --- a/db/schema/dialog.xml +++ b/db/schema/dialog.xml @@ -1,5 +1,5 @@ - @@ -9,10 +9,10 @@ dialog - 8 + 10&MYSQL_TABLE_TYPE; - Persistent dialog information for the dialog module. More + Persistent dialog information for the dialog module. More information can be found at: &OPENSIPS_MOD_DOC;dialog.html @@ -22,7 +22,7 @@ unsigned long&table_id_len; - long,auto + long h_entry | h_id @@ -31,7 +31,7 @@ string &hf_len; Call-ID of the dialog - + @@ -45,8 +45,8 @@ from_tag string &user_len; - The tag parameter serves as a general mechanism to - identify a dialog, which is the combination of the Call-ID along + The tag parameter serves as a general mechanism to + identify a dialog, which is the combination of the Call-ID along with two tags, one from participant in the dialog. @@ -61,8 +61,8 @@ to_tag string &user_len; - The tag parameter serves as a general mechanism to - identify a dialog, which is the combination of the Call-ID along + The tag parameter serves as a general mechanism to + identify a dialog, which is the combination of the Call-ID along with two tags, one from participant in the dialog. @@ -184,8 +184,8 @@ vars - text - 512 + binary + 4096 Variables attached to this dialog. @@ -208,6 +208,14 @@ Script flags for the dialog. + + module_flags + unsigned int + 10 + 0 + Module flags for the dialog. + + flags unsigned int diff --git a/db/schema/dialplan.xml b/db/schema/dialplan.xml index 9b6d783900b..d18c996fded 100644 --- a/db/schema/dialplan.xml +++ b/db/schema/dialplan.xml @@ -76,6 +76,13 @@ Replacement expresion (sed like). + + timerec + string + 255 + Time recurrence used to match this rule. + + disabled int diff --git a/db/schema/dispatcher.xml b/db/schema/dispatcher.xml index 20cf25fa3c4..1a84389c2d6 100644 --- a/db/schema/dispatcher.xml +++ b/db/schema/dispatcher.xml @@ -9,7 +9,7 @@
dispatcher - 5 + 7&MYSQL_TABLE_TYPE; This table is used by the dispatcher module. It contains the sets of destinations used for load balancing and dispatching. More information about the dispatcher module can be found at: &OPENSIPS_MOD_DOC;dispatcher.html @@ -53,10 +53,10 @@ - - flags + + state int - Flags of destination SIP address + The state of the destination (0 enabled, 1 disabled , 2 probing) 0 @@ -69,6 +69,14 @@ + + priority + int + The priority of each destination (only useful with algorithm 8) + 0 + + + attrs string diff --git a/db/schema/domain.xml b/db/schema/domain.xml index 61c9a38905d..192c18dc977 100644 --- a/db/schema/domain.xml +++ b/db/schema/domain.xml @@ -9,7 +9,7 @@
domain - 2 + 3&MYSQL_TABLE_TYPE; This table is used by the domain module to determine if a host part of a URI is "local" or not. More information about the domain module can be found at: &OPENSIPS_MOD_DOC;domain.html @@ -35,6 +35,16 @@ + + attrs + string + 255 + Domain Attributes + + + + + last_modified datetime diff --git a/db/schema/dr_carriers.xml b/db/schema/dr_carriers.xml index 7ba307a2490..4c3c163e24b 100644 --- a/db/schema/dr_carriers.xml +++ b/db/schema/dr_carriers.xml @@ -9,7 +9,7 @@
dr_carriers - 1 + 2&MYSQL_TABLE_TYPE; This table is used by the Dynamic Routing module to define @@ -54,6 +54,15 @@ + + state + unsigned int + &flag_len; + 0 + The state of the carrier (on / off). + + + attrs string diff --git a/db/schema/dr_gateways.xml b/db/schema/dr_gateways.xml index d4ebf6d307d..ab83c66ab63 100644 --- a/db/schema/dr_gateways.xml +++ b/db/schema/dr_gateways.xml @@ -9,7 +9,7 @@
dr_gateways - 5 + 6&MYSQL_TABLE_TYPE; This table is used by the Dynamic Routing module to store @@ -91,6 +91,26 @@ 0- No probing; 1-Probe on disable only ; 2-Always probe; + + state + unsigned int + 11 + 0 + State of the gateway: 0 - enabled; 1 - permanent disabled; + 2 - temporary disabled (probing) + + + + socket + string + 128 + + + Local Socket to be used when sending requests (traffic and probes) + to the destination - must be an listener configured in opensips. + + + description string diff --git a/db/schema/dr_partitions.xml b/db/schema/dr_partitions.xml new file mode 100644 index 00000000000..f6f952ce646 --- /dev/null +++ b/db/schema/dr_partitions.xml @@ -0,0 +1,138 @@ + + +%entities; + +]> + +
+ dr_partitions + 1 + &MYSQL_TABLE_TYPE; + + This table is used by the Dynamic Routing module to store + information about the partitions used in routing (url to database, + table names and AVP names for each partition). + More information can be found at: &OPENSIPS_MOD_DOC;drouting.html. + + + + + id + unsigned int + &table_id_len; + + + + int,auto + Partition unique ID + + + + + partition_name + string + 255 + The name of the partition. + + + + + db_url + string + 255 + The url to the database containing the tables: dr_rules, dr_groups, + dr_carriers and dr_gateways + + + + drd_table + string + 255 + + The name of the dr_gateways table in the given database (for the given partition). + + + + drr_table + string + 255 + + The name of the dr_rules table in the given database (for the given partition). + + + + drg_table + string + 255 + + The name of the dr_groups table in the given database (for the given partition). + + + + drc_table + string + 255 + + The name of the dr_carriers table in the given database (for the given partition). + + + + ruri_avp + string + 255 + + The name of ruri_avp AVP. + + + + gw_id_avp + string + 255 + + The name of gw_id_avp AVP + + + + gw_priprefix_avp + string + 255 + + The name of gw_priprefix_avp AVP. + + + + gw_sock_avp + string + 255 + + The name of gw_sock_avp AVP. + + + + rule_id_avp + string + 255 + + The name of rule_id_avp AVP. + + + + rule_prefix_avp + string + 255 + + The name of rule_prefix_avp AVP. + + + + carrier_id_avp + string + 255 + + The name of carrier_id_avp AVP. + + +
diff --git a/db/schema/entities.xml b/db/schema/entities.xml index 38fac98f68e..8a2eb31a64a 100644 --- a/db/schema/entities.xml +++ b/db/schema/entities.xml @@ -26,4 +26,4 @@ - + diff --git a/db/schema/location.xml b/db/schema/location.xml index 2214bfc909a..0c5e609bf63 100644 --- a/db/schema/location.xml +++ b/db/schema/location.xml @@ -9,7 +9,7 @@ location - 1007 + 1009&MYSQL_TABLE_TYPE; Persistent user location information for the usrloc module. More information can be found at: &OPENSIPS_MOD_DOC;usrloc.html @@ -64,7 +64,7 @@ path string - &uri_len; + &hf_len; Path Header(s) per RFC 3327 @@ -120,9 +120,10 @@ cflags - int - &flag_len; - 0 + string + 255 + + CFlags @@ -161,6 +162,15 @@ SIP Instance for this particular contact + + attr + string + 255 + + + Optional information specific to each registration + + account_contact_idx diff --git a/db/schema/opensips-b2b_sca.xml b/db/schema/opensips-b2b_sca.xml new file mode 100644 index 00000000000..9c718e8857a --- /dev/null +++ b/db/schema/opensips-b2b_sca.xml @@ -0,0 +1,12 @@ + + + %entities; +]> + + + SCA support + + diff --git a/db/schema/opensips-call_center.xml b/db/schema/opensips-call_center.xml new file mode 100644 index 00000000000..71f0a198190 --- /dev/null +++ b/db/schema/opensips-call_center.xml @@ -0,0 +1,16 @@ + + +%entities; + +]> + + + Call Center + + + + + diff --git a/db/schema/opensips-drouting.xml b/db/schema/opensips-drouting.xml index 1df747712c4..e2ccb651bde 100644 --- a/db/schema/opensips-drouting.xml +++ b/db/schema/opensips-drouting.xml @@ -13,4 +13,5 @@ + diff --git a/db/schema/pr_pua.xml b/db/schema/pr_pua.xml index 46868d632d0..61de3ba84ee 100644 --- a/db/schema/pr_pua.xml +++ b/db/schema/pr_pua.xml @@ -26,7 +26,7 @@ Unique ID - + pres_uri string &uri_len; @@ -34,14 +34,14 @@ - + pres_id string 255 ID - + event int 11 @@ -49,7 +49,7 @@ - + expires int &expires_len; @@ -63,7 +63,7 @@ Desired Expires - + flag int &flag_len; @@ -170,4 +170,23 @@ Extra Headers + + del1_idx + + + + + + del2_idx + + + + + update_idx + + + + + +
diff --git a/db/schema/silo.xml b/db/schema/silo.xml index 5c0a1fc8496..b9e6f93e197 100644 --- a/db/schema/silo.xml +++ b/db/schema/silo.xml @@ -84,15 +84,15 @@ ctype string - 32 - text/plain + 255 + + Content type body binary - Body of the message diff --git a/db/schema/sip_trace.xml b/db/schema/sip_trace.xml index 8b4585553e8..5b06e44950f 100644 --- a/db/schema/sip_trace.xml +++ b/db/schema/sip_trace.xml @@ -1,5 +1,5 @@ - @@ -9,7 +9,7 @@ sip_trace - 3 + 4&MYSQL_TABLE_TYPE; This table is used to store incoming/outgoing SIP messages in database. More informations can be found in the siptrace module documentation at: &OPENSIPS_MOD_DOC;siptrace.html. @@ -75,8 +75,15 @@ SIP reply status + + from_proto + string + 5 + Source protocol + + - fromip + from_ip string &ip_add_len; @@ -84,13 +91,34 @@ - toip + from_port + unsigned int + 5 + Source port + + + + to_proto + string + 5 + Destination protocol + + + + to_ip string &ip_add_len; Destination IP address + + to_port + unsigned int + 5 + Destination port + + fromtag string diff --git a/doc/dbschema/bookinfo.xml b/doc/dbschema/bookinfo.xml index e242389dc40..0eb79705b72 100644 --- a/doc/dbschema/bookinfo.xml +++ b/doc/dbschema/bookinfo.xml @@ -11,7 +11,7 @@ - 2007-2012 + 2007-2014 OpenSIPS development Team diff --git a/doc/dbschema/xsl/dbtext.xsl b/doc/dbschema/xsl/dbtext.xsl index 330b292455b..59debc0a981 100644 --- a/doc/dbschema/xsl/dbtext.xsl +++ b/doc/dbschema/xsl/dbtext.xsl @@ -89,9 +89,11 @@ double + $type='text'"> string + + + blob diff --git a/doc/dbschema/xsl/pi_framework_mod.xsl b/doc/dbschema/xsl/pi_framework_mod.xsl index 93bc8882258..ab53f5ce5bc 100644 --- a/doc/dbschema/xsl/pi_framework_mod.xsl +++ b/doc/dbschema/xsl/pi_framework_mod.xsl @@ -46,22 +46,104 @@ <mod><mod_name> </mod_name> + + <cmd><cmd_name>show</cmd_name> <db_table_id> </db_table_id> <cmd_type>DB_QUERY</cmd_type> <query_cols> - + + + + <col><field> + + </field><link_cmd>update</link_cmd></col> + + + <col><field> + + </field></col> + + + </query_cols> </cmd> - </mod> - - - <col><field> - - </field></col> + + <cmd><cmd_name>add</cmd_name> + <db_table_id> + + </db_table_id> + <cmd_type>DB_INSERT</cmd_type> + <query_cols> + + + + + + <col><field> + + </field></col> + + + + </query_cols> + </cmd> + + + + <cmd><cmd_name>update</cmd_name> + <db_table_id> + + </db_table_id> + <cmd_type>DB_UPDATE</cmd_type> + <clause_cols> + + + <col><field> + + </field><operator>=</operator></col> + + + </clause_cols> + <query_cols> + + + + + + <col><field> + + </field></col> + + + + </query_cols> + </cmd> + + + + + <cmd><cmd_name>delete</cmd_name> + <db_table_id> + + </db_table_id> + <cmd_type>DB_DELETE</cmd_type> + <clause_cols> + + + <col><field> + + </field><operator>=</operator></col> + + + </clause_cols> + </cmd> + + + </mod> diff --git a/doc/dbschema/xsl/postgres.xsl b/doc/dbschema/xsl/postgres.xsl index dd45af08d5e..be6cd8c291f 100644 --- a/doc/dbschema/xsl/postgres.xsl +++ b/doc/dbschema/xsl/postgres.xsl @@ -40,7 +40,12 @@ Type= - ; + ; + + + + + @@ -89,7 +94,6 @@ BYTEA - @@ -130,4 +134,24 @@ + + + + + + + + + + + + + ALTER SEQUENCE + + _ + + _seq MAXVALUE 2147483647 CYCLE; + + + diff --git a/doc/entities.xml b/doc/entities.xml index eb750e72737..58c5e55f860 100644 --- a/doc/entities.xml +++ b/doc/entities.xml @@ -9,11 +9,11 @@ -"> + www.opensips-solutions.com"> - + @@ -45,6 +45,7 @@ RTP"> PSTN"> HTTP"> +R-URI"> URI"> URL"> UAC"> diff --git a/dprint.c b/dprint.c index c778eed81e9..542a250d1d6 100644 --- a/dprint.c +++ b/dprint.c @@ -1,7 +1,7 @@ /* * $Id$ * - * debug print + * debug print * * Copyright (C) 2001-2003 FhG Fokus * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -31,11 +31,19 @@ #include "dprint.h" #include "globals.h" #include "pt.h" - + #include #include #include +static int debug_init = L_NOTICE; + +/* current logging level for this process */ +int *debug = &debug_init; + +/* used when resetting the logging level of this process */ +static int *default_debug; + static char* str_fac[]={"LOG_AUTH","LOG_CRON","LOG_DAEMON", "LOG_KERN","LOG_LOCAL0","LOG_LOCAL1", "LOG_LOCAL2","LOG_LOCAL3","LOG_LOCAL4","LOG_LOCAL5", @@ -87,43 +95,54 @@ void dprint(char * format, ...) va_end(ap); } +int init_debug(void) +{ + debug = &pt[process_no].debug; + *debug = debug_init; + default_debug = &pt[process_no].default_debug; + *default_debug = debug_init; -#ifndef CHANGEABLE_DEBUG_LEVEL -static int old_proc_level; -#else -static int *old_proc_level=NULL; -#endif + return 0; +} -void set_proc_debug_level(int level) +/* call before pt is freed */ +void cleanup_debug(void) { -#ifndef CHANGEABLE_DEBUG_LEVEL - static int proc_level_saved=0; + static int debug_level; - if (!proc_level_saved) { - old_proc_level = debug; - proc_level_saved = 1; - } - debug = level; -#else - static int proc_level; - - proc_level = level; - if (old_proc_level==NULL) { - old_proc_level = debug; - debug = &proc_level; - } -#endif + debug_level = *debug; + debug = &debug_level; +} + +/* change the default log level of a given process */ +inline void __set_proc_default_debug(int proc_idx, int level) +{ + pt[proc_idx].default_debug = level; +} + +/* change the actual log level of the current process */ +inline void set_proc_debug_level(int level) +{ + __set_proc_debug_level(process_no, level); } +/* change the actual log level of a given process */ +inline void __set_proc_debug_level(int proc_idx, int level) +{ + pt[proc_idx].debug = level; +} -void reset_proc_debug_level(void) +inline void set_global_debug_level(int level) { -#ifndef CHANGEABLE_DEBUG_LEVEL - debug = old_proc_level; -#else - if (old_proc_level) { - debug = old_proc_level; - old_proc_level = NULL; + int i; + + for (i = 0; i < counted_processes; i++) { + __set_proc_default_debug(i, level); + __set_proc_debug_level(i, level); } -#endif +} + +inline void reset_proc_debug_level(void) +{ + *debug = *default_debug; } diff --git a/dprint.h b/dprint.h index b03d75bae06..b3c8f0a0a9e 100644 --- a/dprint.h +++ b/dprint.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -31,7 +31,7 @@ /*! \page DebugLogFunction Description of the logging functions: * * A) macros to log on a predefine log level and with standard prefix - * for with additional info: [time] + * for with additional info: [time] * No dynamic FMT is accepted (due macro processing). * LM_ALERT( fmt, ....) * LM_CRIT( fmt, ....) @@ -97,16 +97,20 @@ /* vars:*/ -#if CHANGEABLE_DEBUG_LEVEL extern int *debug; -#else -extern int debug; -#endif extern int log_stderr; extern int log_facility; extern char* log_name; extern char ctime_buf[]; +/* + * must be called after init_multi_proc_support() + * must be called once for each OpenSIPS process + */ +int init_debug(void); + +/* must be called once, before the "pt" process table is freed */ +void cleanup_debug(void); int dp_my_pid(void); @@ -114,9 +118,22 @@ void dprint (char* format, ...); int str2facility(char *s); -void set_proc_debug_level(int level); +/* set the current and default log levels for all OpenSIPS processes */ +inline void set_global_debug_level(int level); + +/* set the log level of the current process */ +inline void set_proc_debug_level(int level); + +/* + * set the (default) log level of a given process + * + * Note: the index param is not validated! + */ +inline void __set_proc_debug_level(int proc_idx, int level); +inline void __set_proc_default_debug(int proc_idx, int level); -void reset_proc_debug_level(void); +/* changes the logging level to the default value for the current process */ +inline void reset_proc_debug_level(void); inline static char* dp_time(void) { @@ -129,13 +146,7 @@ inline static char* dp_time(void) return ctime_buf+4; /* remove name of day*/ } - - -#if CHANGEABLE_DEBUG_LEVEL - #define is_printable(_level) ((*debug)>=(_level)) -#else - #define is_printable(_level) (debug>=(_level)) -#endif +#define is_printable(_level) (((int)(*debug)) >= ((int)(_level))) #if defined __GNUC__ #define __DP_FUNC __FUNCTION__ diff --git a/dset.c b/dset.c index 1f171c62488..a27b604290c 100644 --- a/dset.c +++ b/dset.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -78,7 +78,7 @@ static unsigned char dset_state = 1 /*enabled*/ ; unsigned int nr_branches = 0; /*! The q parameter of the Request-URI */ -static qvalue_t ruri_q = Q_UNSPECIFIED; +static qvalue_t ruri_q = Q_UNSPECIFIED; /*! Branch flags of the Request-URI */ @@ -248,7 +248,7 @@ void clear_branches(void) /* ! \brief - * Add a new branch to current transaction + * Add a new branch to current transaction */ int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path, qvalue_t q, unsigned int flags, struct socket_info* force_socket) @@ -259,7 +259,7 @@ int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path, return -1; /* if we have already set up the maximum number - * of branches, don't try new ones + * of branches, don't try new ones */ if (nr_branches == MAX_BRANCHES - 1) { LM_ERR("max nr of branches exceeded\n"); @@ -405,7 +405,7 @@ int remove_branch( unsigned int idx) if ( idx+1!=nr_branches ) memmove( branches+idx , branches+idx+1, (nr_branches-idx-1)*sizeof(struct branch) ); - + nr_branches--; return 0; @@ -416,7 +416,7 @@ int remove_branch( unsigned int idx) * Create a Contact header field from the dset * array */ -char* print_dset(struct sip_msg* msg, int* len) +char* print_dset(struct sip_msg* msg, int* len) { int cnt, i, idx; unsigned int qlen; diff --git a/dset.h b/dset.h index 80354501e7b..444c33cd599 100644 --- a/dset.h +++ b/dset.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -37,8 +37,8 @@ struct sip_msg; extern unsigned int nr_branches; -/*! \brief - * Add a new branch to current transaction +/*! \brief + * Add a new branch to current transaction */ int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path, qvalue_t q, unsigned int flags, struct socket_info* force_socket); @@ -84,13 +84,13 @@ void clear_branches(void); char* print_dset(struct sip_msg* msg, int* len); -/*! \brief +/*! \brief * Set the q value of the Request-URI */ void set_ruri_q(qvalue_t q); -/*! \brief +/*! \brief * Get the q value of the Request-URI */ qvalue_t get_ruri_q(void); diff --git a/errinfo.c b/errinfo.c index fca74bb290d..b08c61df984 100644 --- a/errinfo.c +++ b/errinfo.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/errinfo.h b/errinfo.h index 0fb16a4a492..235e571ac8d 100644 --- a/errinfo.h +++ b/errinfo.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -35,6 +35,7 @@ #define OSER_EC_PARSER 1 /*!< parse error */ #define OSER_EC_PMEMORY 2 /*!< private memory error */ #define OSER_EC_SMEMORY 3 /*!< share memory error */ +#define OSER_EC_ASSERT 4 /*!< assertion error */ #define OSER_EL_CRITIC 1 #define OSER_EL_HIGH 2 diff --git a/error.c b/error.c index c16e73c1f1e..9042be3ac1a 100644 --- a/error.c +++ b/error.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -46,7 +46,7 @@ int ser_error=-1; /*! previous error */ int prev_ser_error=-1; -int err2reason_phrase( +int err2reason_phrase( int ser_error, /*!< current internal ser error */ int *sip_error, /*!< the sip error code to which ser error will be turned */ char *phrase, /*!< resulting error text */ @@ -125,7 +125,7 @@ int err2reason_phrase( *sip_error=-E_BAD_SERVER; break; } - return snprintf( phrase, etl, "%s (%d/%s)", error_txt, + return snprintf( phrase, etl, "%s (%d/%s)", error_txt, -ser_error, signature ); } @@ -231,7 +231,7 @@ void get_reply_status( str *status, struct sip_msg *reply, int code ) } else { phrase=reply->first_line.u.reply.reason; } - status->len=phrase.len+3/*code*/+1/*space*/; + status->len=phrase.len+3/*code*/+1/*space*/; status->s=pkg_malloc(status->len+1/*ZT */); if (!status->s) { LM_ERR("no pkg mem\n"); diff --git a/error.h b/error.h index 6215116292e..de9fee1612f 100644 --- a/error.h +++ b/error.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -60,6 +60,11 @@ #define E_BAD_SERVER -500 /*!< error in server */ +#define report_programming_bug(format, args...) \ + LM_CRIT("\n!!! " format " !!!\nIt seems you have hit a programming bug.\n" \ + "Please help us make OpenSIPS better by reporting it at " \ + "https://github.com/OpenSIPS/opensips/issues\n\n", ##args); +#define LM_BUG report_programming_bug #define MAX_REASON_LEN 128 @@ -72,7 +77,7 @@ extern int prev_ser_error; struct sip_msg; /*! \brief ser error -> SIP error */ -int err2reason_phrase( int ser_error, int *sip_error, +int err2reason_phrase( int ser_error, int *sip_error, char *phrase, int etl, char *signature ); /*! \brief SIP error core -> SIP text */ diff --git a/etc/opensips.cfg b/etc/opensips.cfg index 5c7b046f91f..f4f1199736f 100644 --- a/etc/opensips.cfg +++ b/etc/opensips.cfg @@ -63,8 +63,8 @@ loadmodule "sl.so" #### Transaction Module loadmodule "tm.so" -modparam("tm", "fr_timer", 5) -modparam("tm", "fr_inv_timer", 30) +modparam("tm", "fr_timeout", 5) +modparam("tm", "fr_inv_timeout", 30) modparam("tm", "restart_fr_on_each_reply", 0) modparam("tm", "onreply_avp_mode", 1) @@ -82,25 +82,21 @@ loadmodule "sipmsgops.so" #### FIFO Management Interface loadmodule "mi_fifo.so" modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo") +modparam("mi_fifo", "fifo_mode", 0666) #### URI module loadmodule "uri.so" modparam("uri", "use_uri_table", 0) - - - - - #### USeR LOCation module loadmodule "usrloc.so" -modparam("usrloc", "nat_bflag", 10) +modparam("usrloc", "nat_bflag", "NAT") modparam("usrloc", "db_mode", 0) #### REGISTRAR module loadmodule "registrar.so" -modparam("registrar", "tcp_persistent_flag", 7) +modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT") /* uncomment the next line not to allow more than 10 contacts per AOR */ #modparam("registrar", "max_contacts", 10) @@ -114,28 +110,10 @@ modparam("acc", "report_cancels", 0) if you enable this parameter, be sure the enable "append_fromtag" in "rr" module */ modparam("acc", "detect_direction", 0) -modparam("acc", "failed_transaction_flag", 3) +modparam("acc", "failed_transaction_flag", "ACC_FAILED") /* account triggers (flags) */ -modparam("acc", "log_flag", 1) -modparam("acc", "log_missed_flag", 2) - - - - - - - - - - - - - - - - - - +modparam("acc", "log_flag", "ACC_DO") +modparam("acc", "log_missed_flag", "ACC_MISSED") ####### Routing Logic ######## @@ -143,21 +121,19 @@ modparam("acc", "log_missed_flag", 2) # main request routing logic route{ - - if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); exit; } if (has_totag()) { - # sequential request withing a dialog should + # sequential requests within a dialog should # take the path determined by record-routing if (loose_route()) { if (is_method("BYE")) { - setflag(1); # do accounting ... - setflag(3); # ... even if the transaction fails + setflag(ACC_DO); # do accounting ... + setflag(ACC_FAILED); # ... even if the transaction fails } else if (is_method("INVITE")) { # even if in most of the cases is useless, do RR for # re-INVITEs alos, as some buggy clients do change route set @@ -165,11 +141,9 @@ route{ record_route(); } - - # route it out to whatever destination was set by loose_route() # in $du (destination URI). - route(1); + route(relay); } else { if ( is_method("ACK") ) { @@ -200,20 +174,15 @@ route{ t_check_trans(); if ( !(is_method("REGISTER") ) ) { - if (from_uri==myself) - { - } else { # if caller is not local, then called number must be local - if (!uri==myself) { send_reply("403","Rely forbidden"); exit; } } - } # preloaded route checking @@ -232,18 +201,15 @@ route{ # account only INVITEs if (is_method("INVITE")) { - setflag(1); # do accounting + setflag(ACC_DO); # do accounting } - if (!uri==myself) { append_hf("P-hint: outbound\r\n"); - - route(1); + route(relay); } # requests for my domain - if (is_method("PUBLISH|SUBSCRIBE")) { sl_send_reply("503", "Service Unavailable"); @@ -252,10 +218,7 @@ route{ if (is_method("REGISTER")) { - - - if ( 0 ) setflag(7); - + if ( 0 ) setflag(TCP_PERSISTENT); if (!save("location")) sl_reply_error(); @@ -268,42 +231,27 @@ route{ exit; } - - - - - - # do lookup with method filtering if (!lookup("location","m")) { - - t_newtran(); t_reply("404", "Not Found"); exit; } - - # when routing via usrloc, log the missed calls also - setflag(2); - route(1); + setflag(ACC_MISSED); + route(relay); } -route[1] { +route[relay] { # for INVITEs enable some additional helper routes if (is_method("INVITE")) { - - - - t_on_branch("2"); - t_on_reply("2"); - t_on_failure("1"); + t_on_branch("per_branch_ops"); + t_on_reply("handle_nat"); + t_on_failure("missed_call"); } - - if (!t_relay()) { send_reply("500","Internal Error"); }; @@ -313,18 +261,18 @@ route[1] { -branch_route[2] { +branch_route[per_branch_ops] { xlog("new branch at $ru\n"); } -onreply_route[2] { +onreply_route[handle_nat] { xlog("incoming reply\n"); } -failure_route[1] { +failure_route[missed_call] { if (t_was_cancelled()) { exit; } @@ -336,7 +284,6 @@ failure_route[1] { ## exit; ##} - } diff --git a/etc/tls/README b/etc/tls/README index b64eb0404c3..fd4cd82ab84 100644 --- a/etc/tls/README +++ b/etc/tls/README @@ -1,22 +1,22 @@ This directory contains an already generated TLS certificate that can be -used in your OpenSIPS configuration. It's a generic certificate with the -main purpose of serving as example and for testings. +used in your OpenSIPS configuration. It is a generic certificate with the +main purpose of serving both as an example and a testing sample. -IMPORTANT: it's not a trustable certificate - the CA is also an example. +IMPORTANT: it is not a trustable certificate - the CA is also an example. -All TLS configuration file may be found in "user" directory. If you want to -generate your own certificate, you may find in the "rootCA" directory the -root CA to sign your request with. Use "opensipsctl tls userCERT" command to -create a new certificate; the rootCA password is "opensips". +All TLS configuration files may be found in the "user" directory. If you want +to generate your own certificate, a CA you may sign your request with can +be found in the "rootCA" directory. Use the "opensipsctl tls userCERT" command +to create a new certificate; the rootCA passphrase is "opensips". -What is the purpose of these default CA and certificate? First to make an +What is the purpose of the default CA and certificate? Firstly, to make an out-of-the box TLS configuration for users not so familiar with SSL/TLS. -Second, to give access to the same CA root to a large community in order to -encourage testings and interconnections via TLS with minimum of troubles. +Secondly, to give access to the same CA root to a large community in order to +encourage testings and interconnections via TLS with a minimum of troubles. -For any questions, please address to : +If you have any questions, please address them to: team@opensips.org (if you want to keep your question private) users@opensips.org (public mailing list) diff --git a/etc/tls/rootCA/cacert.pem b/etc/tls/rootCA/cacert.pem index 43e95425c3f..892d552acb5 100644 --- a/etc/tls/rootCA/cacert.pem +++ b/etc/tls/rootCA/cacert.pem @@ -1,22 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIDlTCCAn2gAwIBAgIJAIajPSGooWsRMA0GCSqGSIb3DQEBBQUAMGQxEDAOBgNV -BAMTB09wZW5TRVIxDDAKBgNVBAgTA1NJUDELMAkGA1UEBhMCSVAxHzAdBgkqhkiG -9w0BCQEWEHRlYW1Ab3BlbnNlci5vcmcxFDASBgNVBAoTC29wZW5zZXIub3JnMB4X -DTA1MTAyODE5MDk0NFoXDTA2MTAyODE5MDk0NFowZDEQMA4GA1UEAxMHT3BlblNF -UjEMMAoGA1UECBMDU0lQMQswCQYDVQQGEwJJUDEfMB0GCSqGSIb3DQEJARYQdGVh -bUBvcGVuc2VyLm9yZzEUMBIGA1UEChMLb3BlbnNlci5vcmcwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCtOHaQSReSuBpet7hGSJtAtqoKzPYpYdoIijiw -9tlB/ODBFWjz583MKJuUxIWt7cqnUheBNgBGvrtZYVB6bUxjyTS4m3g8NrrIcWuw -ASTYqYWRmdWbiyLraC6MeoNd8fUG50kbfZa6fh/pkBzZDQb/4Z1cfqIEJ4VpVTLO -CRDreGNfTmG1BREtX+DnzGiKKpGCJVUs/ffX+pTViVC9Y9TDwinJyV9fdtwtI42U -pAxJA+iiG1oOTuk5yjxKOkxKlHju4DIKND3XnPriU3cjdh/93XhMQDxb/jNZhL6R -Y/XhcEsS567ZL3VMUw2VxaDiA+exjAaS/wA8b/rHR8af8+svAgMBAAGjSjBIMAwG -A1UdEwQFMAMBAf8wGwYDVR0RBBQwEoEQdGVhbUBvcGVuc2VyLm9yZzAbBgNVHRIE -FDASgRB0ZWFtQG9wZW5zZXIub3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAabH/C3EiJ -1Dc3uq9KlF7hp2OODAI4928Yy6+pzcbppGoOhAzmDaEoXmlhIMomgeoD031rsESg -+WNavXs2IFCD0U4ocpCa7L0AKDYr8U+5lUtEi7DzXYkqNW17TB+HxkaQVdzvhGrh -+R3WasX0AIc+inxvgkXgzjm5M6IyRUE0FK3wDcACNfnjrDzzXVvdccrM0ZpCFr5T -NWJjQYpGcqDB1HDXVBMPFxQ7XyqKOTOgDCMh4J9g9Ye8eL8uukKJx1eEjHoG4RbM -uQmCYQcCWO0Z/oqiI0FObzsZigf8Xoi9GjK2RjdPEukG3QOflnAm7IjPOLMGzFBn -peqgBkp+jZv5 +MIIDrzCCApegAwIBAgIJAN/zeAp5dQqGMA0GCSqGSIb3DQEBBQUAMHAxETAPBgNV +BAMTCE9wZW5TSVBTMRUwEwYDVQQIEwxvcGVuc2lwcy5vcmcxCzAJBgNVBAYTAklQ +MSAwHgYJKoZIhvcNAQkBFhF0ZWFtQG9wZW5zaXBzLm9yZzEVMBMGA1UEChMMb3Bl +bnNpcHMub3JnMB4XDTE0MDQxNzEwMzgzMVoXDTE1MDQxNzEwMzgzMVowcDERMA8G +A1UEAxMIT3BlblNJUFMxFTATBgNVBAgTDG9wZW5zaXBzLm9yZzELMAkGA1UEBhMC +SVAxIDAeBgkqhkiG9w0BCQEWEXRlYW1Ab3BlbnNpcHMub3JnMRUwEwYDVQQKEwxv +cGVuc2lwcy5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAN3Af +3Od5ioNYL6AAmW1CIAox7MUnmzoEbQvJtTFatCKkYRSihzfV5VhPBV2Jw/3wdZjT +umZsc+jjZNuJexCVlcS0oS14ppLcov7E/gKYfEuPp3oFxG/f+KDHAIPwL3Xr0Jfl +0DYNWQRIh9ixx84FQPYzoEghfzcPVqjjNm6DMLZ2zqa5MgnCfoaBeUsrtvWDX1xj +tGgYSte9piqjTHDDuZNDLxZKmxNirwMP1XAwK2ZTWLNDMesztNyRhvMl6N8vC0Mf +ws69I4P6F2S20hm7PDx3FC5X6NV/vYF4F9cOpXBy6Nsi3Ocdggr0qlFEiQOL1Fpb +BjIzz/3BZ1xnGntZAgMBAAGjTDBKMAwGA1UdEwQFMAMBAf8wHAYDVR0RBBUwE4ER +dGVhbUBvcGVuc2lwcy5vcmcwHAYDVR0SBBUwE4ERdGVhbUBvcGVuc2lwcy5vcmcw +DQYJKoZIhvcNAQEFBQADggEBAGmtjRfQJ4GscNru9mnMWPB4AC5aKEyJ8pQvek9f +jmEfg9loYu1nXuhfC9MPXG3zGIFY0+uLqWD190i13bIgOeISNx3bE9WGwaHq7Tf1 +06pomvN6LH1KDNkF/1iYtKIWEVva1b3RsxT0v+a8HhOExFU4Bj6j7aJT5Dg9+pum +nhgAqlA1fUcb37YbSWjBgdg8W/1DIIQeQkB0wVzN8ilhK/GgHraHnt+DrUZH+RRL +GqMbL2FOSNBD+pecEvi8jsPHudpz4vt/+YlbFtbyDQfCcNE01Ei+HxOAIqcF2H50 +55fD3a7ZE+VZC92WA6wNUf9HySR68cBUGGG4m0atCJGQkcA= -----END CERTIFICATE----- diff --git a/etc/tls/rootCA/certs/01.pem b/etc/tls/rootCA/certs/01.pem index 7bc4c6eb8a6..5fb3e64988f 100644 --- a/etc/tls/rootCA/certs/01.pem +++ b/etc/tls/rootCA/certs/01.pem @@ -2,55 +2,55 @@ Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: CN=OpenSIPS, ST=SIP, C=IP/emailAddress=team@opensips.org, O=opensips.org + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=OpenSIPS, ST=opensips.org, C=IP/emailAddress=team@opensips.org, O=opensips.org Validity - Not Before: Oct 28 19:16:29 2005 GMT - Not After : Oct 28 19:16:29 2006 GMT + Not Before: Apr 17 10:38:36 2014 GMT + Not After : Apr 17 10:38:36 2015 GMT Subject: C=IP, ST=SIP, O=OpenSIPS project, OU=OpenSIPS TLS tester, CN=OpenSIPS/emailAddress=team@opensips.org Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public Key: (512 bit) - Modulus (512 bit): - 00:b6:13:f8:54:99:2a:c3:39:2d:fa:b0:5a:cc:4d: - ca:8b:d0:53:9d:c9:59:ce:17:1e:ba:0a:8e:82:eb: - 9b:c2:69:33:93:3a:b1:68:aa:da:40:bd:de:b5:6f: - c2:5e:99:72:59:f4:68:75:4c:01:05:94:1b:ba:1d: - f2:bb:10:67:d7 + Public-Key: (512 bit) + Modulus: + 00:ab:fd:ac:cd:b4:0d:f7:59:61:46:55:18:be:4e: + d2:8b:89:07:f6:9e:47:50:de:87:eb:f8:e5:6b:98: + 0a:b2:92:88:a4:5b:71:25:07:f3:b2:82:45:b7:e7: + 34:01:3b:ef:7b:b9:f9:b7:26:8e:96:45:03:44:53: + 1b:ad:bb:3c:45 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Signature Algorithm: sha1WithRSAEncryption - 3d:41:b5:28:a4:10:c7:c8:de:29:6f:2e:ed:a8:30:28:2f:9e: - 3c:a9:95:c4:df:73:7b:2e:1c:51:84:a2:bd:ff:56:94:6f:5b: - ac:e2:8f:77:31:74:82:29:8d:e7:a8:c7:da:14:7d:6c:62:dc: - 2f:2e:70:0c:eb:53:67:fa:1b:0a:e5:e8:58:41:5e:dd:84:3d: - 3d:22:c2:c3:b5:69:e5:11:86:2a:a6:4c:f3:07:98:00:f5:cf: - c8:f1:ea:a3:62:f6:40:ef:08:74:93:de:5b:f2:dc:01:dc:0f: - 2a:81:e3:03:56:d1:ef:ca:22:fc:18:29:4f:b0:45:b1:d0:30: - 6b:63:1b:72:ef:9d:ae:bf:ef:b3:0d:fa:39:49:25:48:46:6d: - 68:a1:12:7a:23:1e:ba:53:8e:a5:a2:38:8e:3b:0f:df:b1:b6: - 1e:61:69:80:57:c1:f1:8d:62:69:e0:85:e9:6b:e0:10:4d:37: - b0:3e:98:cc:b5:b5:ea:db:2f:a2:02:51:85:27:1d:65:74:2e: - e3:f4:1f:0c:52:3e:f8:86:6b:50:f1:38:1d:23:97:53:3c:84: - 03:4e:25:a0:66:3a:16:aa:94:77:f2:c8:65:db:ce:c7:0d:c2: - 44:7a:8e:af:ee:c5:bc:4e:aa:2f:29:c5:02:33:ea:c7:78:76: - 02:d4:b4:ca + 5f:cc:bc:e2:c5:e9:81:2d:40:17:80:58:f4:03:7f:30:42:84: + 92:93:13:d9:61:45:84:69:9b:9c:37:a8:b4:74:da:65:2f:ea: + 13:d6:ad:48:b4:57:00:c4:78:f4:2b:35:5a:1a:78:8c:f1:2e: + 0b:44:31:8a:47:4f:3c:97:c8:82:95:9d:2e:88:7e:d8:45:57: + c6:e6:43:62:d9:0c:53:52:b3:68:58:4f:db:f2:17:9f:15:7d: + 39:2f:43:88:c3:28:94:05:f1:b5:74:ab:a5:83:d3:de:89:6f: + 19:13:22:ce:46:d1:7a:8f:cf:74:ff:b4:42:8a:b6:87:ca:ec: + 86:ed:11:8e:1d:c3:88:8f:db:b6:6d:7e:69:f9:0c:19:61:23: + 67:ec:60:91:97:29:0e:23:7a:f0:6c:c6:b6:6c:f2:d8:89:5c: + b6:8f:da:c8:ce:19:8c:38:64:70:92:20:ec:c0:29:8d:80:9c: + 05:ef:22:39:b6:40:27:4c:19:32:a0:23:ac:f8:6a:90:a0:a8: + b9:d6:d2:2d:dc:f8:2a:8d:17:3b:a6:92:12:45:45:03:39:73: + ee:1f:ef:1c:2e:64:a5:1c:44:94:15:10:1c:fd:f3:05:f9:fd: + 0e:ac:9f:c8:e6:28:fc:55:6a:a5:55:c6:57:4b:e9:5f:72:e9: + f2:0e:e2:e6 -----BEGIN CERTIFICATE----- -MIICqjCCAZKgAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMRAwDgYDVQQDEwdPcGVu -U0VSMQwwCgYDVQQIEwNTSVAxCzAJBgNVBAYTAklQMR8wHQYJKoZIhvcNAQkBFhB0 -ZWFtQG9wZW5zZXIub3JnMRQwEgYDVQQKEwtvcGVuc2VyLm9yZzAeFw0wNTEwMjgx -OTE2MjlaFw0wNjEwMjgxOTE2MjlaMIGFMQswCQYDVQQGEwJJUDEMMAoGA1UECBMD -U0lQMRgwFgYDVQQKEw9PcGVuU0VSIHByb2plY3QxGzAZBgNVBAsTEk9wZW5TRVIg -VExTIHRlc3RlcjEQMA4GA1UEAxMHT3BlblNFUjEfMB0GCSqGSIb3DQEJARYQdGVh -bUBvcGVuc2VyLm9yZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC2E/hUmSrDOS36 -sFrMTcqL0FOdyVnOFx66Co6C65vCaTOTOrFoqtpAvd61b8JemXJZ9Gh1TAEFlBu6 -HfK7EGfXAgMBAAGjDTALMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAD1B -tSikEMfI3ilvLu2oMCgvnjyplcTfc3suHFGEor3/VpRvW6zij3cxdIIpjeeox9oU -fWxi3C8ucAzrU2f6Gwrl6FhBXt2EPT0iwsO1aeURhiqmTPMHmAD1z8jx6qNi9kDv -CHST3lvy3AHcDyqB4wNW0e/KIvwYKU+wRbHQMGtjG3Lvna6/77MN+jlJJUhGbWih -EnojHrpTjqWiOI47D9+xth5haYBXwfGNYmnghelr4BBNN7A+mMy1terbL6ICUYUn -HWV0LuP0HwxSPviGa1DxOB0jl1M8hANOJaBmOhaqlHfyyGXbzscNwkR6jq/uxbxO -qi8pxQIz6sd4dgLUtMo= +MIICujCCAaKgAwIBAgIBATANBgkqhkiG9w0BAQUFADBwMREwDwYDVQQDEwhPcGVu +U0lQUzEVMBMGA1UECBMMb3BlbnNpcHMub3JnMQswCQYDVQQGEwJJUDEgMB4GCSqG +SIb3DQEJARYRdGVhbUBvcGVuc2lwcy5vcmcxFTATBgNVBAoTDG9wZW5zaXBzLm9y +ZzAeFw0xNDA0MTcxMDM4MzZaFw0xNTA0MTcxMDM4MzZaMIGJMQswCQYDVQQGEwJJ +UDEMMAoGA1UECBMDU0lQMRkwFwYDVQQKExBPcGVuU0lQUyBwcm9qZWN0MRwwGgYD +VQQLExNPcGVuU0lQUyBUTFMgdGVzdGVyMREwDwYDVQQDEwhPcGVuU0lQUzEgMB4G +CSqGSIb3DQEJARYRdGVhbUBvcGVuc2lwcy5vcmcwXDANBgkqhkiG9w0BAQEFAANL +ADBIAkEAq/2szbQN91lhRlUYvk7Si4kH9p5HUN6H6/jla5gKspKIpFtxJQfzsoJF +t+c0ATvve7n5tyaOlkUDRFMbrbs8RQIDAQABow0wCzAJBgNVHRMEAjAAMA0GCSqG +SIb3DQEBBQUAA4IBAQBfzLzixemBLUAXgFj0A38wQoSSkxPZYUWEaZucN6i0dNpl +L+oT1q1ItFcAxHj0KzVaGniM8S4LRDGKR088l8iClZ0uiH7YRVfG5kNi2QxTUrNo +WE/b8hefFX05L0OIwyiUBfG1dKulg9PeiW8ZEyLORtF6j890/7RCiraHyuyG7RGO +HcOIj9u2bX5p+QwZYSNn7GCRlykOI3rwbMa2bPLYiVy2j9rIzhmMOGRwkiDswCmN +gJwF7yI5tkAnTBkyoCOs+GqQoKi51tIt3PgqjRc7ppISRUUDOXPuH+8cLmSlHESU +FRAc/fMF+f0OrJ/I5ij8VWqlVcZXS+lfcunyDuLm -----END CERTIFICATE----- diff --git a/etc/tls/rootCA/index.txt b/etc/tls/rootCA/index.txt index 9fee07ba3ea..c7ebb26ce39 100644 --- a/etc/tls/rootCA/index.txt +++ b/etc/tls/rootCA/index.txt @@ -1 +1 @@ -V 061028191629Z 01 unknown /C=IP/ST=SIP/O=OpenSIPS project/OU=OpenSIPS TLS tester/CN=OpenSIPS/emailAddress=team@opensips.org +V 150417103836Z 01 unknown /C=IP/ST=SIP/O=OpenSIPS project/OU=OpenSIPS TLS tester/CN=OpenSIPS/emailAddress=team@opensips.org diff --git a/etc/tls/rootCA/private/cakey.pem b/etc/tls/rootCA/private/cakey.pem index ca5190879fb..1282c499332 100644 --- a/etc/tls/rootCA/private/cakey.pem +++ b/etc/tls/rootCA/private/cakey.pem @@ -1,30 +1,30 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,4FF5A11F3774B0A0 - -55A4nhjLcx9PgAAnxRoYwkzCtM1D/2Rb3cLtUo6GTG8E+RzsKgo9PIZDDSDJAy9k -39UXsC69C7jxmqP7oBQgU8M15yAKQwX9zIsi82tRb/oh58f331fK3vtCzvZrJCwQ -5ZWUcmLCrtxVoDj2N9pItB3OizHcUYGmPVxhwWzLyA0Wnq5/EScVaIVEEUQUHZtU -3iJCTUkgc8tFDsFAXEyfO9Y5MabQ3AKSYBgUklGJs0+4facYyCgfYWDwuoanxveQ -2XIVtv2dcV0WOklGA/G+2tfwtRa0G0GBl4Jf49/bv2fONrhGX4KE4aJb7jp8LTZA -nFokO8L/OPHQQDatZ4r9gqIJMzY8uMtzRdkccZvV+xecDieZ6PN4MW36s/AzMp3q -oS72x413GSlDOLlrmDyy7NWo81yD5aYUCgoW6QOOtDCMwFGIJ+lEbt7vPasVp0GJ -Qpsni2Kz7knpjZJHoAyARfm7rPX9Dsk60A16Up9/4LHyy2vsNfD8uXwRcYSTx3nF -d5ClZYtwQp88cfe2qK2L5pegN+YoghXukE191OruZ3cU/ialPqGHefHTd46JyWsZ -k1k0IxXwyAyLbWcFRJ0IKogYK/p/Jz2vAggGS/4utH6OWPkDObo6mclKO3nQk/AK -YGtcAvbN+MOB9US6v/gqHSbh3FvjKtdeSdzkgOqJD0v9sYoshk9XlAcMKljPAqxt -QuFlsNC221z9jpIPVWDoHiufVtuX2/qif0cYhy0T3ey1crgZ1Wf5Xt2VxRk8xCGs -FN5bOmpQcFHhEAmeBS0/cRTM+P0RZ0qLoJUWgedxF9UHweNgpu/JgE8ReF7xIfbV -OHi2ZEziydYuqAQaLi5rDditDJVz+8lnH9k8qWk9WKbFE+Oz/7i5/f10t+062aC2 -0pTg6dptI/X49p0TWuxrI/UTqQjreauTaNaR32pOZlKuCWngtcxLTg/XGfTahsLN -EUKEdQk4T/2OzCICwStkwlayjs+O2osNEE2n79e9IxPG/L7KzWA4RF6dwuJ2Zh5J -8xF/dAiL9C7EBIOQsPxLpjqQUUipedophsndkR5ADP4R3a97d2ZVsk6N0gGMfXHH -6UghbSAcDQ3xj1eSBXYmb2cq36A0g6j3B9Clkh0yO07H7C6jlHeUbGw/5uaa69pX -H9kyPDpPP/sJ26jIBDCC1hzWX2v3/wl7CZRBgf9OQ6lY3x1Mk6eQbxW+G0itI5T2 -MNWV0ae8Nr+vAi9OVmVUo3s0D2kUGtMRXC0ECwJUhXq68GDfLUy9y0ixeVrLnkix -P1OHIu7VLawDvhWx+qQJRI6i0apAEWPTw+A9DiiwtrmILDTQJJWDHky+lja3zkt1 -heVVfeSuyPeS/EgzQgN2kkpr+3ZgNcLSRuKpFdpN2olSyxXt+fRcTj0kluZqJkBn -7UpojLvzl6ODLZvIYFhHPrlZGVPer+YyuEQGt8Ni4NgFooJmOhzNlUOMQtEvo3kO -lsll1jPUGO/5TIxoteHepTT/2nLhlbd2g6xsMNEMqqzmH/Q7OnLknI8IVE7AjkEv -u138yr3yQfdZ+Q9/KDL9RICy/swCZct/dyIhZ6u6NGun2v6Kzzb3lw== ------END RSA PRIVATE KEY----- +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI5W+GzXQEqQ4CAggA +MBQGCCqGSIb3DQMHBAhIzdL1dc/NTgSCBMjSFKYuL0R8JfirXWxr+lqPZ+a8YnpV +8lIdsrKlw2vSLm9UzhIP0daaCc+OOqLh3R1pkwcXBOJVfWRE0oCFhUr/hywG+NXN +sodyD36nXw3o6jfrbn5PDh84X/EHyKk+8kb/Klhfq5ec5Y0mRJoNDSoV40K6qU2I +7lbItIA9JdFL/DXqBR2E/5BEqSk/PMQKBjHDyfBmj0xpSKO0udkhX8vngXgdGH3b +sr3+vQ57PhYFXSnwaKEuxb2ruEwlalsUgVmm8sP1t7ifNWm3gTE6uikGbdHpBcIF +sD3vErCAGzgRo0zwAgA22RaNppA/8FwIxiRg4hmxFblE7Wwh3o8gRC3xg+yD5hZO +y+iaK2YIeVd3icTNj2mz6b+BQQm9xuCIr4ncmocKxlb2k7kLVTLARYdNJTXDifBS +x2LxBEoRj4CmlUYjWzV9HdSs3jMftuhdhehpAhojL12RPYh2EV4M3HknIkI8aOLs +hvVkZcmlRswj3vOJPl1jMe1Lk5CD4Fo+FFDoLYY/nYQhmJhjm9hekBNDptNyG7Ip +GGkWxLQPV0Jzh2Q1H2tKF6IRBNMG/EDcneaq0B8J2r2WjFgHwkQ3DE6xyLRhYn3X +kWD9JNkj2sFmA3p2L8c/RrLMI1LwK+kpJfO9Q1ne1KPKylaYxcAkZajo7+XVotlk +LPKc8Vt2VjYiwsXwmQ7eDQIwMDeGG08O0g70Bm2UXHGr23eijw5O5d9pZ9L2D2Vz +zCeCe9Tg5SggZ9JshgJMxUisDaeA+8/LEY3BOWfOWXfv9+zK+vjkfeP62+0QJJy8 +0FCMaguDVsMtb0KqCZM3wJDhdFGqTIMsJgDn+xV3OltM1xaype99IJOW70RbFD+8 +GQePCMxtbaE5yQkmcaV2VUjHQ8FPiQhcnug7t+AZxO4oThrWK6r/UmfmOI2PYaVP +aFhal3mew3oMhT6u1RjPzxA0fuJFCW4B7ze7PtoiM00DWkfcUZU+IyZCFDVF1JZ8 +tfN3RzFnXiJLn0lhxykpW1u3V3EMZkXqOc4M+5qKoZKskro4kKtkN3UEgjBuwETU +qibKb6Z+YXqMIQOg5XBONeOtx+06Tru5tOXgxghHojvU7O8i4JVIUfHR99y5/yqD +XEkISyos+3Oa5kV3UR/0A2REFzezvIhjXBzZgF8hn3UJufWTaY9bk39+a1FQxAfr +R5y4UmSUAbXwCblHyDp3SXwQMP3K0ozeb8L4dfIVxYehE3DJDPoEdtHYVuhFKIIH +HAa23vfONK079FhEDZts0hh27+cXFzY7DZ/N18/InLH+hI9XbTNia9nOH9AoQFDm +he6eeNr9DK6pZ8PfvaCsJIrMYCGWn8DYAULRCDVz7TMnHm+VWu9MbYdQmPKthb+1 +BJHcRgGP0fNMecVaILSW8LBIKWLQ1erdrjNW2Bm9mQ4H2/D98/5019LmPXvVsfDs +P7FxiOgQNlzfg3FzXcOlzFLkfLqZ8tTu25k9iOTiv3KowUJkSGszTthjlPmVJiuc +P8IiMoPWyXfw54QDNf88H8+Txua/x3fCnTXvFeIssLJiLyyXfDhW8EejGsKSwARt +FDcc7GU6I3vfqXNuGVwZt9N9P8RCngaQ9VCpFVhBpiLjXkYyUkbpapfg3A0OB05r +wLs= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/etc/tls/user/user-calist.pem b/etc/tls/user/user-calist.pem index 43e95425c3f..892d552acb5 100644 --- a/etc/tls/user/user-calist.pem +++ b/etc/tls/user/user-calist.pem @@ -1,22 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIDlTCCAn2gAwIBAgIJAIajPSGooWsRMA0GCSqGSIb3DQEBBQUAMGQxEDAOBgNV -BAMTB09wZW5TRVIxDDAKBgNVBAgTA1NJUDELMAkGA1UEBhMCSVAxHzAdBgkqhkiG -9w0BCQEWEHRlYW1Ab3BlbnNlci5vcmcxFDASBgNVBAoTC29wZW5zZXIub3JnMB4X -DTA1MTAyODE5MDk0NFoXDTA2MTAyODE5MDk0NFowZDEQMA4GA1UEAxMHT3BlblNF -UjEMMAoGA1UECBMDU0lQMQswCQYDVQQGEwJJUDEfMB0GCSqGSIb3DQEJARYQdGVh -bUBvcGVuc2VyLm9yZzEUMBIGA1UEChMLb3BlbnNlci5vcmcwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCtOHaQSReSuBpet7hGSJtAtqoKzPYpYdoIijiw -9tlB/ODBFWjz583MKJuUxIWt7cqnUheBNgBGvrtZYVB6bUxjyTS4m3g8NrrIcWuw -ASTYqYWRmdWbiyLraC6MeoNd8fUG50kbfZa6fh/pkBzZDQb/4Z1cfqIEJ4VpVTLO -CRDreGNfTmG1BREtX+DnzGiKKpGCJVUs/ffX+pTViVC9Y9TDwinJyV9fdtwtI42U -pAxJA+iiG1oOTuk5yjxKOkxKlHju4DIKND3XnPriU3cjdh/93XhMQDxb/jNZhL6R -Y/XhcEsS567ZL3VMUw2VxaDiA+exjAaS/wA8b/rHR8af8+svAgMBAAGjSjBIMAwG -A1UdEwQFMAMBAf8wGwYDVR0RBBQwEoEQdGVhbUBvcGVuc2VyLm9yZzAbBgNVHRIE -FDASgRB0ZWFtQG9wZW5zZXIub3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAabH/C3EiJ -1Dc3uq9KlF7hp2OODAI4928Yy6+pzcbppGoOhAzmDaEoXmlhIMomgeoD031rsESg -+WNavXs2IFCD0U4ocpCa7L0AKDYr8U+5lUtEi7DzXYkqNW17TB+HxkaQVdzvhGrh -+R3WasX0AIc+inxvgkXgzjm5M6IyRUE0FK3wDcACNfnjrDzzXVvdccrM0ZpCFr5T -NWJjQYpGcqDB1HDXVBMPFxQ7XyqKOTOgDCMh4J9g9Ye8eL8uukKJx1eEjHoG4RbM -uQmCYQcCWO0Z/oqiI0FObzsZigf8Xoi9GjK2RjdPEukG3QOflnAm7IjPOLMGzFBn -peqgBkp+jZv5 +MIIDrzCCApegAwIBAgIJAN/zeAp5dQqGMA0GCSqGSIb3DQEBBQUAMHAxETAPBgNV +BAMTCE9wZW5TSVBTMRUwEwYDVQQIEwxvcGVuc2lwcy5vcmcxCzAJBgNVBAYTAklQ +MSAwHgYJKoZIhvcNAQkBFhF0ZWFtQG9wZW5zaXBzLm9yZzEVMBMGA1UEChMMb3Bl +bnNpcHMub3JnMB4XDTE0MDQxNzEwMzgzMVoXDTE1MDQxNzEwMzgzMVowcDERMA8G +A1UEAxMIT3BlblNJUFMxFTATBgNVBAgTDG9wZW5zaXBzLm9yZzELMAkGA1UEBhMC +SVAxIDAeBgkqhkiG9w0BCQEWEXRlYW1Ab3BlbnNpcHMub3JnMRUwEwYDVQQKEwxv +cGVuc2lwcy5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAN3Af +3Od5ioNYL6AAmW1CIAox7MUnmzoEbQvJtTFatCKkYRSihzfV5VhPBV2Jw/3wdZjT +umZsc+jjZNuJexCVlcS0oS14ppLcov7E/gKYfEuPp3oFxG/f+KDHAIPwL3Xr0Jfl +0DYNWQRIh9ixx84FQPYzoEghfzcPVqjjNm6DMLZ2zqa5MgnCfoaBeUsrtvWDX1xj +tGgYSte9piqjTHDDuZNDLxZKmxNirwMP1XAwK2ZTWLNDMesztNyRhvMl6N8vC0Mf +ws69I4P6F2S20hm7PDx3FC5X6NV/vYF4F9cOpXBy6Nsi3Ocdggr0qlFEiQOL1Fpb +BjIzz/3BZ1xnGntZAgMBAAGjTDBKMAwGA1UdEwQFMAMBAf8wHAYDVR0RBBUwE4ER +dGVhbUBvcGVuc2lwcy5vcmcwHAYDVR0SBBUwE4ERdGVhbUBvcGVuc2lwcy5vcmcw +DQYJKoZIhvcNAQEFBQADggEBAGmtjRfQJ4GscNru9mnMWPB4AC5aKEyJ8pQvek9f +jmEfg9loYu1nXuhfC9MPXG3zGIFY0+uLqWD190i13bIgOeISNx3bE9WGwaHq7Tf1 +06pomvN6LH1KDNkF/1iYtKIWEVva1b3RsxT0v+a8HhOExFU4Bj6j7aJT5Dg9+pum +nhgAqlA1fUcb37YbSWjBgdg8W/1DIIQeQkB0wVzN8ilhK/GgHraHnt+DrUZH+RRL +GqMbL2FOSNBD+pecEvi8jsPHudpz4vt/+YlbFtbyDQfCcNE01Ei+HxOAIqcF2H50 +55fD3a7ZE+VZC92WA6wNUf9HySR68cBUGGG4m0atCJGQkcA= -----END CERTIFICATE----- diff --git a/etc/tls/user/user-cert.pem b/etc/tls/user/user-cert.pem index 7bc4c6eb8a6..5fb3e64988f 100644 --- a/etc/tls/user/user-cert.pem +++ b/etc/tls/user/user-cert.pem @@ -2,55 +2,55 @@ Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: CN=OpenSIPS, ST=SIP, C=IP/emailAddress=team@opensips.org, O=opensips.org + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=OpenSIPS, ST=opensips.org, C=IP/emailAddress=team@opensips.org, O=opensips.org Validity - Not Before: Oct 28 19:16:29 2005 GMT - Not After : Oct 28 19:16:29 2006 GMT + Not Before: Apr 17 10:38:36 2014 GMT + Not After : Apr 17 10:38:36 2015 GMT Subject: C=IP, ST=SIP, O=OpenSIPS project, OU=OpenSIPS TLS tester, CN=OpenSIPS/emailAddress=team@opensips.org Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public Key: (512 bit) - Modulus (512 bit): - 00:b6:13:f8:54:99:2a:c3:39:2d:fa:b0:5a:cc:4d: - ca:8b:d0:53:9d:c9:59:ce:17:1e:ba:0a:8e:82:eb: - 9b:c2:69:33:93:3a:b1:68:aa:da:40:bd:de:b5:6f: - c2:5e:99:72:59:f4:68:75:4c:01:05:94:1b:ba:1d: - f2:bb:10:67:d7 + Public-Key: (512 bit) + Modulus: + 00:ab:fd:ac:cd:b4:0d:f7:59:61:46:55:18:be:4e: + d2:8b:89:07:f6:9e:47:50:de:87:eb:f8:e5:6b:98: + 0a:b2:92:88:a4:5b:71:25:07:f3:b2:82:45:b7:e7: + 34:01:3b:ef:7b:b9:f9:b7:26:8e:96:45:03:44:53: + 1b:ad:bb:3c:45 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Signature Algorithm: sha1WithRSAEncryption - 3d:41:b5:28:a4:10:c7:c8:de:29:6f:2e:ed:a8:30:28:2f:9e: - 3c:a9:95:c4:df:73:7b:2e:1c:51:84:a2:bd:ff:56:94:6f:5b: - ac:e2:8f:77:31:74:82:29:8d:e7:a8:c7:da:14:7d:6c:62:dc: - 2f:2e:70:0c:eb:53:67:fa:1b:0a:e5:e8:58:41:5e:dd:84:3d: - 3d:22:c2:c3:b5:69:e5:11:86:2a:a6:4c:f3:07:98:00:f5:cf: - c8:f1:ea:a3:62:f6:40:ef:08:74:93:de:5b:f2:dc:01:dc:0f: - 2a:81:e3:03:56:d1:ef:ca:22:fc:18:29:4f:b0:45:b1:d0:30: - 6b:63:1b:72:ef:9d:ae:bf:ef:b3:0d:fa:39:49:25:48:46:6d: - 68:a1:12:7a:23:1e:ba:53:8e:a5:a2:38:8e:3b:0f:df:b1:b6: - 1e:61:69:80:57:c1:f1:8d:62:69:e0:85:e9:6b:e0:10:4d:37: - b0:3e:98:cc:b5:b5:ea:db:2f:a2:02:51:85:27:1d:65:74:2e: - e3:f4:1f:0c:52:3e:f8:86:6b:50:f1:38:1d:23:97:53:3c:84: - 03:4e:25:a0:66:3a:16:aa:94:77:f2:c8:65:db:ce:c7:0d:c2: - 44:7a:8e:af:ee:c5:bc:4e:aa:2f:29:c5:02:33:ea:c7:78:76: - 02:d4:b4:ca + 5f:cc:bc:e2:c5:e9:81:2d:40:17:80:58:f4:03:7f:30:42:84: + 92:93:13:d9:61:45:84:69:9b:9c:37:a8:b4:74:da:65:2f:ea: + 13:d6:ad:48:b4:57:00:c4:78:f4:2b:35:5a:1a:78:8c:f1:2e: + 0b:44:31:8a:47:4f:3c:97:c8:82:95:9d:2e:88:7e:d8:45:57: + c6:e6:43:62:d9:0c:53:52:b3:68:58:4f:db:f2:17:9f:15:7d: + 39:2f:43:88:c3:28:94:05:f1:b5:74:ab:a5:83:d3:de:89:6f: + 19:13:22:ce:46:d1:7a:8f:cf:74:ff:b4:42:8a:b6:87:ca:ec: + 86:ed:11:8e:1d:c3:88:8f:db:b6:6d:7e:69:f9:0c:19:61:23: + 67:ec:60:91:97:29:0e:23:7a:f0:6c:c6:b6:6c:f2:d8:89:5c: + b6:8f:da:c8:ce:19:8c:38:64:70:92:20:ec:c0:29:8d:80:9c: + 05:ef:22:39:b6:40:27:4c:19:32:a0:23:ac:f8:6a:90:a0:a8: + b9:d6:d2:2d:dc:f8:2a:8d:17:3b:a6:92:12:45:45:03:39:73: + ee:1f:ef:1c:2e:64:a5:1c:44:94:15:10:1c:fd:f3:05:f9:fd: + 0e:ac:9f:c8:e6:28:fc:55:6a:a5:55:c6:57:4b:e9:5f:72:e9: + f2:0e:e2:e6 -----BEGIN CERTIFICATE----- -MIICqjCCAZKgAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMRAwDgYDVQQDEwdPcGVu -U0VSMQwwCgYDVQQIEwNTSVAxCzAJBgNVBAYTAklQMR8wHQYJKoZIhvcNAQkBFhB0 -ZWFtQG9wZW5zZXIub3JnMRQwEgYDVQQKEwtvcGVuc2VyLm9yZzAeFw0wNTEwMjgx -OTE2MjlaFw0wNjEwMjgxOTE2MjlaMIGFMQswCQYDVQQGEwJJUDEMMAoGA1UECBMD -U0lQMRgwFgYDVQQKEw9PcGVuU0VSIHByb2plY3QxGzAZBgNVBAsTEk9wZW5TRVIg -VExTIHRlc3RlcjEQMA4GA1UEAxMHT3BlblNFUjEfMB0GCSqGSIb3DQEJARYQdGVh -bUBvcGVuc2VyLm9yZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC2E/hUmSrDOS36 -sFrMTcqL0FOdyVnOFx66Co6C65vCaTOTOrFoqtpAvd61b8JemXJZ9Gh1TAEFlBu6 -HfK7EGfXAgMBAAGjDTALMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAD1B -tSikEMfI3ilvLu2oMCgvnjyplcTfc3suHFGEor3/VpRvW6zij3cxdIIpjeeox9oU -fWxi3C8ucAzrU2f6Gwrl6FhBXt2EPT0iwsO1aeURhiqmTPMHmAD1z8jx6qNi9kDv -CHST3lvy3AHcDyqB4wNW0e/KIvwYKU+wRbHQMGtjG3Lvna6/77MN+jlJJUhGbWih -EnojHrpTjqWiOI47D9+xth5haYBXwfGNYmnghelr4BBNN7A+mMy1terbL6ICUYUn -HWV0LuP0HwxSPviGa1DxOB0jl1M8hANOJaBmOhaqlHfyyGXbzscNwkR6jq/uxbxO -qi8pxQIz6sd4dgLUtMo= +MIICujCCAaKgAwIBAgIBATANBgkqhkiG9w0BAQUFADBwMREwDwYDVQQDEwhPcGVu +U0lQUzEVMBMGA1UECBMMb3BlbnNpcHMub3JnMQswCQYDVQQGEwJJUDEgMB4GCSqG +SIb3DQEJARYRdGVhbUBvcGVuc2lwcy5vcmcxFTATBgNVBAoTDG9wZW5zaXBzLm9y +ZzAeFw0xNDA0MTcxMDM4MzZaFw0xNTA0MTcxMDM4MzZaMIGJMQswCQYDVQQGEwJJ +UDEMMAoGA1UECBMDU0lQMRkwFwYDVQQKExBPcGVuU0lQUyBwcm9qZWN0MRwwGgYD +VQQLExNPcGVuU0lQUyBUTFMgdGVzdGVyMREwDwYDVQQDEwhPcGVuU0lQUzEgMB4G +CSqGSIb3DQEJARYRdGVhbUBvcGVuc2lwcy5vcmcwXDANBgkqhkiG9w0BAQEFAANL +ADBIAkEAq/2szbQN91lhRlUYvk7Si4kH9p5HUN6H6/jla5gKspKIpFtxJQfzsoJF +t+c0ATvve7n5tyaOlkUDRFMbrbs8RQIDAQABow0wCzAJBgNVHRMEAjAAMA0GCSqG +SIb3DQEBBQUAA4IBAQBfzLzixemBLUAXgFj0A38wQoSSkxPZYUWEaZucN6i0dNpl +L+oT1q1ItFcAxHj0KzVaGniM8S4LRDGKR088l8iClZ0uiH7YRVfG5kNi2QxTUrNo +WE/b8hefFX05L0OIwyiUBfG1dKulg9PeiW8ZEyLORtF6j890/7RCiraHyuyG7RGO +HcOIj9u2bX5p+QwZYSNn7GCRlykOI3rwbMa2bPLYiVy2j9rIzhmMOGRwkiDswCmN +gJwF7yI5tkAnTBkyoCOs+GqQoKi51tIt3PgqjRc7ppISRUUDOXPuH+8cLmSlHESU +FRAc/fMF+f0OrJ/I5ij8VWqlVcZXS+lfcunyDuLm -----END CERTIFICATE----- diff --git a/etc/tls/user/user-cert_req.pem b/etc/tls/user/user-cert_req.pem index f595a04c77e..0ab64f86793 100644 --- a/etc/tls/user/user-cert_req.pem +++ b/etc/tls/user/user-cert_req.pem @@ -1,9 +1,9 @@ -----BEGIN CERTIFICATE REQUEST----- -MIIBQDCB6wIBADCBhTEQMA4GA1UEAxMHT3BlblNFUjEMMAoGA1UECBMDU0lQMQsw -CQYDVQQGEwJJUDEfMB0GCSqGSIb3DQEJARYQdGVhbUBvcGVuc2VyLm9yZzEYMBYG -A1UEChMPT3BlblNFUiBwcm9qZWN0MRswGQYDVQQLExJPcGVuU0VSIFRMUyB0ZXN0 -ZXIwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAthP4VJkqwzkt+rBazE3Ki9BTnclZ -zhceugqOguubwmkzkzqxaKraQL3etW/CXplyWfRodUwBBZQbuh3yuxBn1wIDAQAB -oAAwDQYJKoZIhvcNAQEFBQADQQA0mFBhg/bbxznLbLcc2nQo0022x0HeT3Qxl0lm -SlIvfG2YphvBYuc54HFjqHfRNrmckAVoSrVpEpcVXSO/g+L6 +MIIBRDCB7wIBADCBiTERMA8GA1UEAxMIT3BlblNJUFMxDDAKBgNVBAgTA1NJUDEL +MAkGA1UEBhMCSVAxIDAeBgkqhkiG9w0BCQEWEXRlYW1Ab3BlbnNpcHMub3JnMRkw +FwYDVQQKExBPcGVuU0lQUyBwcm9qZWN0MRwwGgYDVQQLExNPcGVuU0lQUyBUTFMg +dGVzdGVyMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKv9rM20DfdZYUZVGL5O0ouJ +B/aeR1Deh+v45WuYCrKSiKRbcSUH87KCRbfnNAE773u5+bcmjpZFA0RTG627PEUC +AwEAAaAAMA0GCSqGSIb3DQEBBQUAA0EAl3vd4CfyZHjs4xXrJhUSPRd5atsHLCGU +CYyGubH+4B/Koc/ei1xH9plhFYLAOgNbnvKBQ7sy2SUM2xwo8LG+OQ== -----END CERTIFICATE REQUEST----- diff --git a/etc/tls/user/user-privkey.pem b/etc/tls/user/user-privkey.pem index 16f884efab6..5f0d4f6dbd7 100644 --- a/etc/tls/user/user-privkey.pem +++ b/etc/tls/user/user-privkey.pem @@ -1,9 +1,10 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBALYT+FSZKsM5LfqwWsxNyovQU53JWc4XHroKjoLrm8JpM5M6sWiq -2kC93rVvwl6Zcln0aHVMAQWUG7od8rsQZ9cCAwEAAQJBALCEy8u4cmyxkpHnRx+q -iyLg5S+jdR0H7RIQCfmC0Y63LFIAsXasHQorV83r2br4eRRaeU87CsVLXdBUjvbe -ywECIQDaq7ojtDBTGhNKILZ9CBOTk18jDdHgTJAC7ZpGvdGt+QIhANUpE9j5JWqA -kIcR55eSJXmjoKB1IGnTz0kaMB/8B3hPAiEAw0351IXNW4vAisao9wdNpNNNd5uS -RklbnqHk1yYWrtECIEXqi1AHqHYeZUloXgYhMZmMSgtXX6JWjw7zQAW9rNWRAiBe -Xmwo0k9fY/KawVSsnY4rgYqk6PDWK98jl5/x/veDZA== ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAq/2szbQN91lhRlUY +vk7Si4kH9p5HUN6H6/jla5gKspKIpFtxJQfzsoJFt+c0ATvve7n5tyaOlkUDRFMb +rbs8RQIDAQABAkB58TgN+LVWRHblqPwMIlLBP/z3bC1gNwbj1erDqF8dUAEppJ9c +xmAQuuubtCW/K9eY/uVP5XCJwhrTyPYdkgJZAiEA47xx9mt4ZUndBfG8XEh91hQ3 +MjX+148rgZTkN45gEAMCIQDBVhzBYXpUVWPlCrHWTdF89GUG3ovicj40/rb0ZPNE +FwIgGgxL3KueMbepGCz2JngELKBTT+LtKyqtBz1IfTJDupECIQCsh6AZold8Msd2 +edjBmag8jgwp2SeT6MdCm5vA9OVx+QIhAMk9LAclXbdrkcU5qOMNLv2IrsGZH0Mt +4bsWq7J1jD5T +-----END PRIVATE KEY----- diff --git a/evi/event_interface.c b/evi/event_interface.c index 503e4824f2b..ad197833c57 100644 --- a/evi/event_interface.c +++ b/evi/event_interface.c @@ -65,7 +65,7 @@ event_id_t evi_publish_event(str event_name) } } else if (events_no == max_alloc_events) { max_alloc_events *= 2; - events = shm_realloc(events, max_alloc_events); + events = shm_realloc(events, max_alloc_events * sizeof(evi_event_t)); if (!events) { LM_ERR("no more shm memory to hold %d events\n", max_alloc_events); return EVI_ERROR; @@ -110,13 +110,13 @@ int evi_raise_event(event_id_t id, evi_params_t* params) return -1; } memset(req, 0, sizeof(struct sip_msg)); - + req->first_line.type = SIP_REQUEST; req->first_line.u.request.method.s= "DUMMY"; req->first_line.u.request.method.len= 5; req->first_line.u.request.uri.s= "sip:user@domain.com"; req->first_line.u.request.uri.len= 19; - + bak_avps = set_avp_list(&event_avps); status = evi_raise_event_msg(req, id, params); @@ -486,6 +486,8 @@ struct mi_root * mi_events_list(struct mi_root *cmd_tree, void *param) if (rpl_tree==0) return 0; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; + for (i = 0; i < events_no; i++) { node = add_mi_node_child(rpl, 0, "Event", 5, events[i].name.s, events[i].name.len); @@ -495,7 +497,7 @@ struct mi_root * mi_events_list(struct mi_root *cmd_tree, void *param) if (!addf_mi_attr(node, 0, "id", 2, "%d", events[i].id)) goto error; - if (i % 50 == 0) { + if ((i + 1) % 50 == 0) { flush_mi_tree(rpl_tree); } } @@ -559,7 +561,13 @@ static int evi_print_event(struct evi_mi_param *param, { struct mi_node *node=NULL; struct mi_node *rpl = param->node; - node = add_mi_node_child(rpl, 0, "Event", 5, ev->name.s, ev->name.len); + + /* add event only if there are subscribers */ + if (!subs && !ev->subscribers) + return 0; + + node = add_mi_node_child(rpl, MI_IS_ARRAY, "Event", 5, + ev->name.s, ev->name.len); if(node == NULL) goto error; @@ -646,6 +654,7 @@ struct mi_root * mi_subscribers_list(struct mi_root *cmd_tree, void *param) memset(&prm, 0, sizeof(struct evi_mi_param)); rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; node = cmd_tree->node.kids; prm.node = rpl; prm.root = rpl_tree; diff --git a/evi/event_interface.h b/evi/event_interface.h index 882cff0b8b7..26c0bbe7d75 100644 --- a/evi/event_interface.h +++ b/evi/event_interface.h @@ -37,7 +37,7 @@ typedef struct evi_subscriber { evi_export_t* trans_mod; /* transport module */ evi_reply_sock* reply_sock; /* reply socket */ - struct evi_subscriber *next; /* next subscriber */ + struct evi_subscriber *next; /* next subscriber */ } evi_subs_t, *evi_subs_p; diff --git a/evi/evi_modules.h b/evi/evi_modules.h index 4760b67e864..d41d3e8c937 100644 --- a/evi/evi_modules.h +++ b/evi/evi_modules.h @@ -33,7 +33,7 @@ struct sip_msg; /* functions used by modules */ -/* +/* * Used to register a new event * Parameters: * + Event name @@ -120,7 +120,7 @@ int evi_probe_event(event_id_t id); * Returns: * - event_id or error */ -event_id_t evi_get_id(str *name); +event_id_t evi_get_id(str *name); /* * Used to return an event with a specific name @@ -130,6 +130,6 @@ event_id_t evi_get_id(str *name); * Returns: * - event_id or error */ -evi_event_p evi_get_event(str *name); +evi_event_p evi_get_event(str *name); #endif /* _EVI_MODULES_H_ */ diff --git a/evi/evi_transport.c b/evi/evi_transport.c index 8140b825b43..76c7a793031 100644 --- a/evi/evi_transport.c +++ b/evi/evi_transport.c @@ -72,15 +72,15 @@ int register_event_mod(evi_export_t *ev) LM_ERR("duplicate flag %x\n", ev->flags); goto error; } - if (ev->proto.len == trans_mod->module->proto.len && + if (ev->proto.len == trans_mod->module->proto.len && !memcmp(ev->proto.s,trans_mod->module->proto.s,ev->proto.len)){ - LM_ERR("duplicate transport module protocol <%.*s>\n", + LM_ERR("duplicate transport module protocol <%.*s>\n", ev->proto.len, ev->proto.s); goto error; } } } - + trans_mod = shm_malloc(sizeof(evi_trans_t)); if (!trans_mod) { LM_ERR("no more shm memory\n"); diff --git a/evi/evi_transport.h b/evi/evi_transport.h index c692c4504d3..5219b46eadb 100644 --- a/evi/evi_transport.h +++ b/evi/evi_transport.h @@ -90,7 +90,7 @@ typedef struct evi_trans_ { /* functions used by the transport modules */ -/* +/* * Used to register a transport module * Parameters: * + export functions diff --git a/examples/httpd.cfg b/examples/httpd.cfg index f6a911b9fc4..dcef6d9ba07 100644 --- a/examples/httpd.cfg +++ b/examples/httpd.cfg @@ -15,6 +15,7 @@ loadmodule "httpd.so" loadmodule "mi_http.so" loadmodule "pi_http.so" modparam("pi_http", "framework", "/usr/local/src/opensips/examples/pi_framework.xml") +loadmodule "mi_xmlrpc_ng.so" # ------------------------- request routing logic ------------------- diff --git a/fastlock.h b/fastlock.h index 95bf0399da5..8866e40166f 100644 --- a/fastlock.h +++ b/fastlock.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -85,7 +85,7 @@ inline static int tsl(fl_lock_t* lock) ); #else val=1; - asm volatile( + asm volatile( " xchg %1, %0" : "=q" (val), "=m" (*lock) : "0" (val) : "memory" ); #endif /*NOSMP*/ @@ -97,7 +97,7 @@ inline static int tsl(fl_lock_t* lock) #endif : "=r"(val) : "r"(lock):"memory" ); - + #elif defined __CPU_arm asm volatile( "# here \n\t" @@ -105,7 +105,7 @@ inline static int tsl(fl_lock_t* lock) : "=&r" (val) : "r"(1), "r" (lock) : "memory" ); - + #elif defined(__CPU_ppc) || defined(__CPU_ppc64) asm volatile( "1: lwarx %0, 0, %2\n\t" @@ -125,7 +125,7 @@ inline static int tsl(fl_lock_t* lock) #elif defined __CPU_mips2 long tmp; tmp=1; /* just to kill a gcc 2.95 warning */ - + asm volatile( ".set noreorder\n\t" "1: ll %1, %2 \n\t" @@ -134,8 +134,8 @@ inline static int tsl(fl_lock_t* lock) " beqz %0, 1b \n\t" " nop \n\t" ".set reorder\n\t" - : "=&r" (tmp), "=&r" (val), "=m" (*lock) - : "0" (tmp), "2" (*lock) + : "=&r" (tmp), "=&r" (val), "=m" (*lock) + : "0" (tmp), "2" (*lock) : "cc" ); #elif defined __CPU_alpha @@ -146,7 +146,7 @@ inline static int tsl(fl_lock_t* lock) "1: ldl %0, %1 \n\t" " blbs %0, 2f \n\t" /* optimization if locked */ " ldl_l %0, %1 \n\t" - " blbs %0, 2f \n\t" + " blbs %0, 2f \n\t" " lda %2, 1 \n\t" /* or: or $31, 1, %2 ??? */ " stl_c %2, %1 \n\t" " beq %2, 1b \n\t" @@ -174,7 +174,7 @@ inline static void get_lock(fl_lock_t* lock) #ifdef ADAPTIVE_WAIT int i=ADAPTIVE_WAIT_LOOPS; #endif - + while(tsl(lock)){ #ifdef BUSY_WAIT #elif defined ADAPTIVE_WAIT @@ -199,7 +199,7 @@ inline static void release_lock(fl_lock_t* lock) asm volatile( " movb $0, (%0)" : /*no output*/ : "r"(lock): "memory" /*" xchg %b0, %1" : "=q" (val), "=m" (*lock) : "0" (val) : "memory"*/ - ); + ); #elif defined(__CPU_sparc64) || defined(__CPU_sparc) asm volatile( #ifndef NOSMP @@ -212,8 +212,8 @@ inline static void release_lock(fl_lock_t* lock) ); #elif defined __CPU_arm asm volatile( - " str %0, [%1] \n\r" - : /*no outputs*/ + " str %0, [%1] \n\r" + : /*no outputs*/ : "r"(0), "r"(lock) : "memory" ); @@ -243,7 +243,7 @@ inline static void release_lock(fl_lock_t* lock) " mb \n\t" " stl $31, %0 \n\t" : "=m"(*lock) :/* no input*/ : "memory" /* because of the mb */ - ); + ); #else #error "unknown architecture" #endif diff --git a/flags.c b/flags.c index a607c2a9b1b..a1c7830becd 100644 --- a/flags.c +++ b/flags.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -42,6 +42,9 @@ /* several lists of maximum MAX_FLAG flags */ struct flag_entry *flag_lists[FLAG_LIST_COUNT]; +/* buffer used to offer string representations of flag bitmasks */ +static char print_buffer[PRINT_BUFFER_SIZE]; + /*********************** msg flags ****************************/ int setflag( struct sip_msg* msg, flag_t flag ) { @@ -80,6 +83,64 @@ int flag_idx2mask(int *flag) return 0; } +str bitmask_to_flag_list(enum flag_type type, int bitmask) +{ + struct flag_entry *entry; + str ret; + + ret.s = print_buffer; + ret.len = 0; + for (entry = flag_lists[type]; entry; entry = entry->next) { + + if (bitmask & (1 << entry->bit)) { + memcpy(ret.s + ret.len, entry->name.s, entry->name.len); + ret.len += entry->name.len; + + ret.s[ret.len++] = FLAG_DELIM; + } + } + + if (ret.len > 0) + ret.len--; + + return ret; +} + +int flag_list_to_bitmask(str *flags, enum flag_type type, char delim) +{ + char *p, *lim; + char *crt_flag; + str name; + struct flag_entry *e; + int ret = 0; + + if (flags->len < 0) + return 0; + + lim = flags->s + flags->len; + crt_flag = flags->s; + for (p = flags->s; p <= lim; p++) { + + if (p == lim || *p == delim) { + + name.s = crt_flag; + name.len = p - crt_flag; + for (e = flag_lists[type]; e; e = e->next) { + if (e->name.len == p - crt_flag && + str_strcmp(&e->name, &name) == 0) { + + ret |= 1 << e->bit; + break; + } + } + + crt_flag = p + 1; + } + } + + return ret; +} + /** * The function MUST be called only in the pre-forking phases of OpenSIPS * (mod_init() or in function fixups) @@ -94,14 +155,19 @@ int get_flag_id_by_name(int flag_type, char *flag_name) return -1; } + fn.s = flag_name; + fn.len = strlen(flag_name); + + if (fn.len == 0) { + LM_WARN("found empty string flag modparam! possible scripting error?\n"); + return -1; + } + if (flag_type < 0 || flag_type > FLAG_LIST_COUNT) { LM_ERR("Invalid flag list: %d\n", flag_type); return -2; } - fn.s = flag_name; - fn.len = strlen(flag_name); - flag_list = flag_lists + flag_type; if (*flag_list && (*flag_list)->bit == MAX_FLAG) { @@ -131,6 +197,7 @@ int get_flag_id_by_name(int flag_type, char *flag_name) it->next = *flag_list; *flag_list = it; + LM_DBG("New flag: [ %.*s : %d ][%d]\n", fn.len, fn.s, it->bit, flag_type); return it->bit; } diff --git a/flags.h b/flags.h index 23b9b473473..5dc86798221 100644 --- a/flags.h +++ b/flags.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -34,18 +34,25 @@ typedef unsigned int flag_t; #define MAX_FLAG ((unsigned int)( sizeof(flag_t) * CHAR_BIT - 1 )) +#define PRINT_BUFFER_SIZE 2048 #define NAMED_FLAG_ERROR 33 +#define FLAG_DELIM ' ' -#define fix_flag_name(_s, _flag) \ - do { \ - if (!*_s && _flag > 0) { \ +#define fix_flag_name(_s, _flag) \ + do { \ + if (!_s && _flag > 0) { \ LM_WARN("Integer flags are now deprecated! " \ - "Use unique quoted strings!\n"); \ - *_s = int2str(_flag, NULL); \ - } \ + "Use unique quoted strings!\n"); \ + _s = int2str(_flag, NULL); \ + } \ } while (0) -enum { FLAG_TYPE_MSG=0, FLAG_TYPE_SCRIPT, FLAG_TYPE_BRANCH, FLAG_LIST_COUNT }; +enum flag_type { + FLAG_TYPE_MSG=0, + FLAG_TYPE_SCRIPT, + FLAG_TYPE_BRANCH, + FLAG_LIST_COUNT, +}; struct sip_msg; @@ -63,6 +70,20 @@ int resetflag( struct sip_msg* msg, flag_t flag ); int isflagset( struct sip_msg* msg, flag_t flag ); int flag_idx2mask(int *flag); +/** + * returns a string representation of the named flags set in the bitmask + * + * Note: prints data in a static buffer, flags are delimited by FLAG_DELIM + */ +str bitmask_to_flag_list(enum flag_type type, int bitmask); + +/** + * parses a list of named flags and returns the corresponding bitmask + * + * Note: flags which are not used at script level and are not instantiated with + * get_flag_id_by_name will be ignored + */ +int flag_list_to_bitmask(str *flags, enum flag_type type, char delim); unsigned int fixup_flag(int flag_type, str *flag_name); int get_flag_id_by_name(int flag_type, char *flag_name); diff --git a/forward.c b/forward.c index 3a18244b5c8..6a11ae3e2fd 100644 --- a/forward.c +++ b/forward.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -42,7 +42,7 @@ * 2003-10-24 converted to the new socket_info lists (andrei) * 2004-10-10 modified check_self to use grep_sock_info (andrei) * 2004-11-08 added force_send_socket support in get_send_socket (andrei) - * 2006-09-06 added new algorithm for building VIA branch parameter for + * 2006-09-06 added new algorithm for building VIA branch parameter for * stateless requests - it complies to RFC3261 requirement to be * unique through time and space (bogdan) */ @@ -142,7 +142,7 @@ struct socket_info* get_out_socket(union sockaddr_union* to, int proto) { int temp_sock; socklen_t len; - union sockaddr_union from; + union sockaddr_union from; struct socket_info* si; struct ip_addr ip; @@ -150,7 +150,7 @@ struct socket_info* get_out_socket(union sockaddr_union* to, int proto) LM_CRIT("can only be called for UDP\n"); return 0; } - + temp_sock=socket(to->s.sa_family, SOCK_DGRAM, 0 ); if (temp_sock==-1) { LM_ERR("socket() failed: %s\n", strerror(errno)); @@ -182,15 +182,15 @@ struct socket_info* get_out_socket(union sockaddr_union* to, int proto) /*! \brief returns a socket_info pointer to the sending socket or 0 on error * \param msg SIP message (can be null) * \param to destination socket_union pointer - * \param proto protocol + * \param proto protocol * * \note if msg!=null and msg->force_send_socket, the force_send_socket will be used */ -struct socket_info* get_send_socket(struct sip_msg *msg, +struct socket_info* get_send_socket(struct sip_msg *msg, union sockaddr_union* to, int proto) { struct socket_info* send_sock; - + /* check if send interface is not forced */ if (msg && msg->force_send_socket){ if (msg->force_send_socket->proto!=proto){ @@ -199,7 +199,7 @@ struct socket_info* get_send_socket(struct sip_msg *msg, msg->force_send_socket->port_no, proto); } - if (msg->force_send_socket && (msg->force_send_socket->socket!=-1)) + if (msg->force_send_socket && (msg->force_send_socket->socket!=-1)) return msg->force_send_socket; else{ if (msg->force_send_socket && msg->force_send_socket->socket==-1) @@ -236,7 +236,7 @@ struct socket_info* get_send_socket(struct sip_msg *msg, case AF_INET6: send_sock=sendipv6_tcp; break; #endif - default: LM_ERR("don't know how to forward to af %d\n", + default: LM_ERR("don't know how to forward to af %d\n", to->s.sa_family); } break; @@ -265,7 +265,7 @@ struct socket_info* get_send_socket(struct sip_msg *msg, case AF_INET6: send_sock=sendipv6_sctp; break; #endif - default: LM_ERR("don't know how to forward to af %d\n", + default: LM_ERR("don't know how to forward to af %d\n", to->s.sa_family); } break; @@ -283,7 +283,8 @@ struct socket_info* get_send_socket(struct sip_msg *msg, default: LM_ERR("don't know how to forward to af %d\n", to->s.sa_family); } - }else send_sock = msg ? msg->rcv.bind_address : bind_address; + }else send_sock = (msg && msg->rcv.bind_address->address.af==bind_address->address.af && + msg->rcv.bind_address->proto==bind_address->proto)? msg->rcv.bind_address : bind_address; break; default: LM_CRIT("unknown proto %d\n", proto); @@ -379,7 +380,7 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p) buf=0; /* calculate branch for outbound request - if the branch buffer is already - * set (maybe by an upper level as TM), used it; otherwise computes + * set (maybe by an upper level as TM), used it; otherwise computes * the branch for stateless fwd. . According to the latest discussions * on the topic, you should reuse the latest statefull branch * --bogdan */ @@ -485,7 +486,7 @@ int update_sock_struct_from_via( union sockaddr_union* to, unsigned short port; port=0; - if(via==msg->via1){ + if(via==msg->via1){ /* _local_ reply, we ignore any rport or received value * (but we will send back to the original port if rport is * present) */ @@ -511,12 +512,12 @@ int update_sock_struct_from_via( union sockaddr_union* to, if (via->maddr){ name= &(via->maddr->value); - if (port==0) port=via->port?via->port:SIP_PORT; + if (port==0) port=via->port?via->port:SIP_PORT; } else if (via->received){ LM_DBG("using 'received'\n"); name=&(via->received->value); /* making sure that we won't do SRV lookup on "received" */ - if (port==0) port=via->port?via->port:SIP_PORT; + if (port==0) port=via->port?via->port:SIP_PORT; }else{ LM_DBG("using via host\n"); name=&(via->host); @@ -530,7 +531,7 @@ int update_sock_struct_from_via( union sockaddr_union* to, LM_NOTICE("resolve_host(%.*s) failure\n", name->len, name->s); return -1; } - + hostent2su( to, he, 0, port); return 1; } @@ -551,7 +552,7 @@ int forward_reply(struct sip_msg* msg) char* s; int len; #endif - + to=0; id=0; new_buf=0; @@ -560,7 +561,7 @@ int forward_reply(struct sip_msg* msg) if (check_self(&msg->via1->host, msg->via1->port?msg->via1->port:SIP_PORT, msg->via1->proto)!=1){ - LM_ERR("host in first via!=me : %.*s:%d\n", + LM_ERR("host in first via!=me : %.*s:%d\n", msg->via1->host.len, msg->via1->host.s, msg->via1->port); /* send error msg back? */ goto error; @@ -580,7 +581,7 @@ int forward_reply(struct sip_msg* msg) goto skip; /* we have to forward the reply stateless, so we need second via -bogdan*/ - if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 + if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) { /* no second via => error */ @@ -614,7 +615,7 @@ int forward_reply(struct sip_msg* msg) send_sock = get_send_socket(msg, to, proto); - new_buf = build_res_buf_from_sip_res( msg, &new_len, send_sock); + new_buf = build_res_buf_from_sip_res( msg, &new_len, send_sock,0); if (!new_buf){ LM_ERR("failed to build rpl from req failed\n"); goto error; @@ -631,7 +632,7 @@ int forward_reply(struct sip_msg* msg) * the correct port is choosen in update_sock_struct_from_via, * as its visible with su_getport(to); . */ - LM_DBG("reply forwarded to %.*s:%d\n", msg->via2->host.len, + LM_DBG("reply forwarded to %.*s:%d\n", msg->via2->host.len, msg->via2->host.s, (unsigned short) msg->via2->port); pkg_free(new_buf); diff --git a/forward.h b/forward.h index ce1e0961981..d685556d3d8 100644 --- a/forward.h +++ b/forward.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -53,6 +53,9 @@ #include "sctp_server.h" #endif +#include "script_cb.h" + +#include "mem/mem.h" struct socket_info* get_send_socket(struct sip_msg* msg, union sockaddr_union* su, int proto); @@ -76,12 +79,12 @@ int forward_reply( struct sip_msg* msg); /*! \brief * - * \param send_sock = 0 if already known (e.g. for udp in some cases), + * \param send_sock = 0 if already known (e.g. for udp in some cases), * non-0 otherwise * \param proto =TCP|UDP * \param to = sockaddr-like description of the destination - * \param id - only used on tcp, it will force sending on connection "id" - * if id!=0 and the connection exists, else it will send to "to" + * \param id - only used on tcp, it will force sending on connection "id" + * if id!=0 and the connection exists, else it will send to "to" * (useful for sending replies on the same connection as the request * that generated them; use 0 if you don't want this) * \param buf - the buffer containing the message to be sent @@ -92,6 +95,8 @@ static inline int msg_send( struct socket_info* send_sock, int proto, union sockaddr_union* to, int id, char* buf, int len) { + str out_buff; + if (send_sock==0) send_sock=get_send_socket(0, to, proto); if (send_sock==0){ @@ -99,8 +104,18 @@ static inline int msg_send( struct socket_info* send_sock, int proto, goto error; } + out_buff.len = len; + out_buff.s = buf; + + /* the raw processing callbacks are free to change whatever inside the buffer + further use out_buff.s and at the end try to free out_buff.s + if changed by callbacks */ + run_raw_processing_cb(POST_RAW_PROCESSING,&out_buff); + /* update the length for further processing */ + len = out_buff.len; + if (proto==PROTO_UDP){ - if (udp_send(send_sock, buf, len, to)==-1){ + if (udp_send(send_sock, out_buff.s, out_buff.len, to)==-1){ LM_ERR("udp_send failed\n"); goto error; } @@ -112,7 +127,7 @@ static inline int msg_send( struct socket_info* send_sock, int proto, " support is disabled\n"); goto error; }else{ - if (tcp_send(send_sock, proto, buf, len, to, id)<0){ + if (tcp_send(send_sock, proto, out_buff.s, out_buff.len, to, id)<0){ LM_ERR("tcp_send failed\n"); goto error; } @@ -125,7 +140,7 @@ static inline int msg_send( struct socket_info* send_sock, int proto, " support is disabled\n"); goto error; }else{ - if (tcp_send(send_sock, proto, buf, len, to, id)<0){ + if (tcp_send(send_sock, proto, out_buff.s, out_buff.len, to, id)<0){ LM_ERR("tcp_send failed\n"); goto error; } @@ -140,7 +155,7 @@ static inline int msg_send( struct socket_info* send_sock, int proto, " support is disabled\n"); goto error; }else{ - if (sctp_server_send(send_sock, buf, len, to)<0){ + if (sctp_server_send(send_sock, out_buff.s, out_buff.len, to)<0){ LM_ERR("sctp_send failed\n"); goto error; } @@ -151,8 +166,15 @@ static inline int msg_send( struct socket_info* send_sock, int proto, LM_CRIT("unknown proto %d\n", proto); goto error; } + + /* potentially allocated by the out raw processing */ + if (out_buff.s != buf) + pkg_free(out_buff.s); + return 0; error: + if (out_buff.s != buf) + pkg_free(out_buff.s); return -1; } diff --git a/futex_lock.h b/futex_lock.h index 63f933fdca8..352946b120d 100644 --- a/futex_lock.h +++ b/futex_lock.h @@ -13,8 +13,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -101,7 +101,7 @@ inline static int _atomic_xchg(fx_lock_t* lock, int val) : "=q" (val), "=m" (*lock) : "0"(val) : "memory", "cc" /* "cc" */ ); #else - asm volatile( + asm volatile( " xchg %1, %0" : "=q" (val), "=m" (*lock) : "0" (val) : "memory" ); #endif /*NOSMP*/ @@ -150,8 +150,8 @@ inline static int _atomic_xchg(fx_lock_t* lock, int val) " beqz %0, 1b \n\t" " nop \n\t" ".set reorder\n\t" - : "=&r" (tmp), "=&r" (val), "=m" (*lock) - : "0" (tmp), "2" (*lock) + : "=&r" (tmp), "=&r" (val), "=m" (*lock) + : "0" (tmp), "2" (*lock) : "cc" ); #elif defined __CPU_alpha @@ -162,7 +162,7 @@ inline static int _atomic_xchg(fx_lock_t* lock, int val) "1: ldl %0, %1 \n\t" " blbs %0, 2f \n\t" /* optimization if locked */ " ldl_l %0, %1 \n\t" - " blbs %0, 2f \n\t" + " blbs %0, 2f \n\t" " lda %2, 1 \n\t" /* or: or $31, 1, %2 ??? */ " stl_c %2, %1 \n\t" " beq %2, 1b \n\t" diff --git a/globals.h b/globals.h index 7167d7ff7bc..184eb61943e 100644 --- a/globals.h +++ b/globals.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -81,6 +81,12 @@ extern int tcp_keepalive; extern int tcp_keepcount; extern int tcp_keepidle; extern int tcp_keepinterval; +extern int tcp_max_msg_chunks; +extern int tcp_max_msg_time; +extern int tcp_async; +extern int tcp_async_local_connect_timeout; +extern int tcp_async_local_write_timeout; +extern int tcp_async_max_postponed_chunks; #endif #ifdef USE_TLS extern int tls_disable; @@ -90,9 +96,9 @@ extern unsigned short tls_port_no; extern int sctp_disable; #endif extern int dont_fork; +extern int no_daemon_mode; extern int check_via; extern int received_dns; -/* extern int process_no; */ extern int sip_warning; extern int server_signature; extern str server_header; @@ -120,7 +126,13 @@ extern int disable_dns_blacklist; extern int cfg_errors; extern unsigned long shm_mem_size; +extern unsigned int shm_hash_split_percentage; +extern unsigned int shm_hash_split_factor; +extern unsigned int shm_secondary_hash_size; extern unsigned long pkg_mem_size; +extern char *mem_warming_pattern_file; +extern int mem_warming_percentage; +extern int mem_warming_enabled; extern int reply_to_via; @@ -159,4 +171,7 @@ extern char *db_version_table; extern char *db_default_url; extern int disable_503_translation; + +extern int enable_asserts; +extern int abort_on_assert; #endif diff --git a/hash_func.h b/hash_func.h index 8d55ad49ee4..bc2d956eef4 100644 --- a/hash_func.h +++ b/hash_func.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/help_msg.h b/help_msg.h index a0fcf49531b..8f897afdf76 100644 --- a/help_msg.h +++ b/help_msg.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -34,7 +34,7 @@ * * This page tries to give some starting points for developers that want to * understand the server structure and create their own extensions or modules. - * + * * \section db_sec Database interface * The server uses a own database interface to hide the differences of the * supported db engines. Every module that implementst this API can use all @@ -82,6 +82,7 @@ Options:\n\ -v Turn on \"via:\" host checking when forwarding replies\n\ -d Debugging mode (multiple -d increase the level)\n\ -D Do not fork into daemon mode\n\ + -F Daemon mode, but leave main process foreground\n\ -E Log to stderr\n" #ifdef USE_TCP " -T Disable tcp\n\ diff --git a/io_wait.c b/io_wait.c index 1ee77e564f6..1b1caf41e35 100644 --- a/io_wait.c +++ b/io_wait.c @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Copyright (C) 2005 iptelorg GmbH * * This file is part of opensips, a free SIP server. @@ -78,7 +78,7 @@ char* poll_support="poll" ; /*! supported poll methods */ -char* poll_method_str[POLL_END]={ "none", "poll", "epoll_lt", "epoll_et", +char* poll_method_str[POLL_END]={ "none", "poll", "epoll_lt", "epoll_et", "sigio_rt", "select", "kqueue", "/dev/poll" }; @@ -104,14 +104,14 @@ static int init_sigio(io_wait_h* h, int rsig) int signo; int start_sig; sigset_t oldset; - + if (!_sigio_init){ _sigio_init=1; _sigio_crt_rtsig=SIGRTMIN; sigemptyset(&_sigio_rtsig_used); } h->signo=0; - + if (rsig==0){ start_sig=_sigio_crt_rtsig; n=SIGRTMAX-SIGRTMIN; @@ -124,7 +124,7 @@ static int init_sigio(io_wait_h* h, int rsig) start_sig=rsig; n=0; } - + sigemptyset(&h->sset); sigemptyset(&oldset); retry1: @@ -135,7 +135,7 @@ static int init_sigio(io_wait_h* h, int rsig) strerror(errno), errno); /* try to continue */ } - + for (r=start_sig; r<=(n+start_sig); r++){ signo=(r>SIGRTMAX)?r-SIGRTMAX+SIGRTMIN:r; if (! sigismember(&_sigio_rtsig_used, signo) && @@ -146,7 +146,7 @@ static int init_sigio(io_wait_h* h, int rsig) break; } } - + if (h->signo==0){ LM_CRIT("init_sigio: %s\n", rsig?"could not assign requested real-time signal": @@ -155,7 +155,7 @@ static int init_sigio(io_wait_h* h, int rsig) } LM_DBG("trying signal %d... \n", h->signo); - + if (sigaddset(&h->sset, h->signo)==-1){ LM_ERR("sigaddset failed for %d: %s [%d]\n", h->signo, strerror(errno), errno); @@ -183,7 +183,7 @@ static int init_sigio(io_wait_h* h, int rsig) /*! - * \brief sigio specific destroy + * \brief sigio specific destroy * \param h IO handle */ static void destroy_sigio(io_wait_h* h) @@ -305,7 +305,7 @@ static void destroy_devpoll(io_wait_h* h) #ifdef HAVE_SELECT /*! * \brief select specific init - * \param h IO handle + * \param h IO handle * \return zero * \todo make this method void, and remove the check in io_wait.c */ @@ -322,7 +322,7 @@ static int init_select(io_wait_h* h) * \brief return system version * Return system version (major.minor.minor2) as (major<<16)|(minor)<<8|(minor2) * (if some of them are missing, they are set to 0) - * if the parameters are not null they are set to the coresp. part + * if the parameters are not null they are set to the coresp. part * \param major major version * \param minor minor version * \param minor2 minor2 version @@ -335,7 +335,7 @@ static unsigned int get_sys_version(int* major, int* minor, int* minor2) int m2; int m3; char* p; - + memset (&un, 0, sizeof(un)); m1=m2=m3=0; /* get sys version */ @@ -368,7 +368,8 @@ char* check_poll_method(enum poll_types poll_method) unsigned int os_ver; ret=0; - os_ver=get_sys_version(0,0,0); + os_ver=get_sys_version(0,0,0); + (void)os_ver; switch(poll_method){ case POLL_NONE: break; @@ -448,11 +449,12 @@ enum poll_types choose_poll_method(void) unsigned int os_ver; os_ver=get_sys_version(0,0,0); + (void)os_ver; poll_method=0; #ifdef HAVE_EPOLL if (os_ver>=0x020542) /* if ver >= 2.5.66 */ poll_method=POLL_EPOLL_LT; /* or POLL_EPOLL_ET */ - + #endif #ifdef HAVE_KQUEUE if (poll_method==0) @@ -475,7 +477,7 @@ enum poll_types choose_poll_method(void) #endif #endif #ifdef HAVE_SIGIO_RT - if (poll_method==0) + if (poll_method==0) if (os_ver>=0x020200) /* if ver >= 2.2.0 */ poll_method=POLL_SIGIO_RT; #endif @@ -502,19 +504,19 @@ char* poll_method_name(enum poll_types poll_method) /*! * \brief converts a string into a poll_method * \param s converted string - * \return POLL_NONE (0) on error, else the corresponding poll type + * \return POLL_NONE (0) on error, else the corresponding poll type */ enum poll_types get_poll_type(char* s) { int r; unsigned int l; - + l=strlen(s); for (r=POLL_END-1; r>POLL_NONE; r--) if ((strlen(poll_method_str[r])==l) && (strncasecmp(poll_method_str[r], s, l)==0)) break; - return r; + return r; } @@ -528,7 +530,7 @@ enum poll_types get_poll_type(char* s) int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method) { char * poll_err; - + memset(h, 0, sizeof(*h)); h->max_fd_no=max_fd; #ifdef HAVE_EPOLL @@ -541,7 +543,7 @@ int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method) h->dpoll_fd=-1; #endif poll_err=check_poll_method(poll_method); - + /* set an appropiate poll method */ if (poll_err || (poll_method==0)){ poll_method=choose_poll_method(); @@ -553,9 +555,17 @@ int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method) " (auto detected)\n", poll_method_str[poll_method]); } } - + h->poll_method=poll_method; - + + if (h->poll_method != POLL_POLL && h->poll_method != POLL_EPOLL_LT && + h->poll_method != POLL_EPOLL_ET) { + if (tcp_async) + LM_WARN("Tried to enable async TCP but current poll method is %d." + " Currently we only support POLL and EPOLL \n",h->poll_method); + tcp_async=0; + } + /* common stuff, everybody has fd_hash */ h->fd_hash=local_malloc(sizeof(*(h->fd_hash))*h->max_fd_no); if (h->fd_hash==0){ @@ -564,7 +574,7 @@ int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method) goto error; } memset((void*)h->fd_hash, 0, sizeof(*(h->fd_hash))*h->max_fd_no); - + switch(poll_method){ case POLL_POLL: #ifdef HAVE_SELECT @@ -601,7 +611,7 @@ int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method) goto error; } #endif - + break; #ifdef HAVE_EPOLL case POLL_EPOLL_LT: diff --git a/io_wait.h b/io_wait.h index d32ca15542d..1aed8c817f8 100644 --- a/io_wait.h +++ b/io_wait.h @@ -47,7 +47,7 @@ * this assumption) * - local_malloc (defaults to pkg_malloc) * - local_free (defaults to pkg_free) - * + * */ @@ -76,8 +76,8 @@ #endif #ifdef HAVE_SELECT /* needed on openbsd for select*/ -#include -#include +#include +#include #include /* needed according to POSIX for select*/ #include @@ -86,6 +86,7 @@ #include #include "dprint.h" +#include "globals.h" /* tcp_async */ #include "poll_types.h" /* poll_types*/ #ifdef HAVE_SIGIO_RT @@ -95,7 +96,7 @@ #if 0 enum fd_types; /* this should be defined from the including file, - see tcp_main.c for an example, + see tcp_main.c for an example, 0 has a special meaning: not used/empty*/ #endif @@ -106,10 +107,11 @@ typedef int fd_type; /*! \brief maps a fd to some other structure; used in almost all cases * except epoll and maybe kqueue or /dev/poll */ -struct fd_map{ +struct fd_map { int fd; /* fd no */ fd_type type; /* "data" type */ void* data; /* pointer to the corresponding structure */ + int flags; /* so far used to indicate whether we should read, write or both */ }; @@ -127,6 +129,8 @@ struct fd_map{ #endif +#define IO_FD_CLOSING 16 + /*! \brief handler structure */ struct io_wait_handler{ #ifdef HAVE_EPOLL @@ -171,21 +175,38 @@ typedef struct io_wait_handler io_wait_h; /*! \brief remove a fd_map structure from the hash; * the pointer must be returned by get_fd_map or hash_fd_map */ -#define unhash_fd_map(pfm) \ +#define unhash_fd_map(pfm,c_flags,sock_flags,erase) \ do{ \ - (pfm)->type=0 /*F_NONE */; \ - (pfm)->fd=-1; \ + if ((c_flags & IO_FD_CLOSING) || pfm->flags == sock_flags) { \ + (pfm)->type=0 /*F_NONE */; \ + (pfm)->fd=-1; \ + (pfm)->flags = 0; \ + erase = 1; \ + } else { \ + (pfm)->flags &= ~sock_flags; \ + erase = 0; \ + } \ }while(0) /*! \brief add a fd_map structure to the fd hash */ static inline struct fd_map* hash_fd_map( io_wait_h* h, int fd, fd_type type, - void* data) + void* data, + int flags, + int *already) { + if (h->fd_hash[fd].fd <= 0) { + *already = 0; + } else { + *already = 1; + } + h->fd_hash[fd].fd=fd; h->fd_hash[fd].type=type; h->fd_hash[fd].data=data; + h->fd_hash[fd].flags|=flags; + return &h->fd_hash[fd]; } @@ -199,16 +220,16 @@ static inline struct fd_map* hash_fd_map( io_wait_h* h, * \param fm pointer to a fd hash entry * \param idx index in the fd_array (or -1 if not known) * \return return: -1 on error - * 0 on EAGAIN or when by some other way it is known that no more + * 0 on EAGAIN or when by some other way it is known that no more * io events are queued on the fd (the receive buffer is empty). * Usefull to detect when there are no more io events queued for * sigio_rt, epoll_et, kqueue. * >0 on successfull read from the fd (when there might be more io * queued -- the receive buffer might still be non-empty) */ -inline static int handle_io(struct fd_map* fm, int idx); +inline static int handle_io(struct fd_map* fm, int idx,int event_type); #else -static int handle_io(struct fd_map* fm, int idx) { +static int handle_io(struct fd_map* fm, int idx,int event_type) { return 0; } #endif @@ -221,7 +242,7 @@ static int handle_io(struct fd_map* fm, int idx) { * (adds a change to the kevent change array, and if full flushes it first) * returns: -1 on error, 0 on success */ -static inline int kq_ev_change(io_wait_h* h, int fd, int filter, int flag, +static inline int kq_ev_change(io_wait_h* h, int fd, int filter, int flag, void* data) { int n; @@ -236,7 +257,7 @@ static inline int kq_ev_change(io_wait_h* h, int fd, int filter, int flag, n=kevent(h->kq_fd, h->kq_changes, h->kq_nchanges, 0, 0, &tspec); if (n==-1){ if (errno==EINTR) goto again; - LM_ERR("kevent flush changes failed: %s [%d]\n", + LM_ERR("kevent flush changes failed: %s [%d]\n", strerror(errno), errno); return -1; } @@ -250,6 +271,9 @@ static inline int kq_ev_change(io_wait_h* h, int fd, int filter, int flag, #endif +#define IO_WATCH_READ 1 +#define IO_WATCH_WRITE 2 +#define IO_WATCH_ERROR 3 /*! \brief generic io_watch_add function * \return 0 on success, -1 on error @@ -261,17 +285,23 @@ static inline int kq_ev_change(io_wait_h* h, int fd, int filter, int flag, inline static int io_watch_add( io_wait_h* h, int fd, fd_type type, - void* data) + void* data, + int flags) { /* helper macros */ #define fd_array_setup \ do{ \ h->fd_array[h->fd_no].fd=fd; \ - h->fd_array[h->fd_no].events=POLLIN; /* useless for select */ \ + if (!already) \ + h->fd_array[h->fd_no].events=0; \ + if (flags & IO_WATCH_READ) \ + h->fd_array[h->fd_no].events|=POLLIN; /* useless for select */ \ + if (flags & IO_WATCH_WRITE) \ + h->fd_array[h->fd_no].events|=POLLOUT; /* useless for select */ \ h->fd_array[h->fd_no].revents=0; /* useless for select */ \ }while(0) - + #define set_fd_flags(f) \ do{ \ flags=fcntl(fd, F_GETFL); \ @@ -286,10 +316,10 @@ inline static int io_watch_add( io_wait_h* h, goto error; \ } \ }while(0) - - + + struct fd_map* e; - int flags; + int already; #ifdef HAVE_EPOLL struct epoll_event ep_event; #endif @@ -301,12 +331,13 @@ inline static int io_watch_add( io_wait_h* h, int idx; int check_io; struct pollfd pf; - + check_io=0; /* set to 1 if we need to check for pre-existing queued io/data on the fd */ idx=-1; #endif e=0; + if (fd==-1){ LM_CRIT("fd is -1!\n"); goto error; @@ -317,18 +348,24 @@ inline static int io_watch_add( io_wait_h* h, " %d/%d\n", h->fd_no, h->max_fd_no); goto error; } - LM_DBG("io_watch_add(%p, %d, %d, %p), fd_no=%d\n", - h, fd, type, data, h->fd_no); + LM_DBG("io_watch_add op on %d (%p, %d, %d, %p,%d), fd_no=%d\n", + fd,h,fd,type,data,flags,h->fd_no); /* hash sanity check */ e=get_fd_map(h, fd); - if (e && (e->type!=0 /*F_NONE*/)){ - LM_ERR("trying to overwrite entry %d" - " in the hash(%d, %d, %p) with (%d, %d, %p)\n", - fd, e->fd, e->type, e->data, fd, type, data); - goto error; + + if (e->flags & flags){ + if (e->data != data) { + LM_ERR("BUG trying to overwrite entry %d" + " in the hash(%d, %d, %p,%d) with (%d, %d, %p,%d)\n", + fd, e->fd, e->type, e->data,e->flags, fd, type, data,flags); + goto error; + } + LM_DBG("Socket %d is already being listened on for flags %d\n", + fd,flags); + return 0; } - - if ((e=hash_fd_map(h, fd, type, data))==0){ + + if ((e=hash_fd_map(h, fd, type, data,flags,&already))==0){ LM_ERR("failed to hash the fd %d\n", fd); goto error; } @@ -347,7 +384,7 @@ inline static int io_watch_add( io_wait_h* h, #ifdef HAVE_SIGIO_RT case POLL_SIGIO_RT: fd_array_setup; - /* re-set O_ASYNC might be needed, if not done from + /* re-set O_ASYNC might be needed, if not done from * io_watch_del (or if somebody wants to add a fd which has * already O_ASYNC/F_SETSIG set on a dupplicate) */ @@ -380,31 +417,61 @@ inline static int io_watch_add( io_wait_h* h, #endif #ifdef HAVE_EPOLL case POLL_EPOLL_LT: - ep_event.events=EPOLLIN; ep_event.data.ptr=e; + ep_event.events=0; + if (e->flags & IO_WATCH_READ) + ep_event.events|=EPOLLIN; + if (e->flags & IO_WATCH_WRITE) + ep_event.events|=EPOLLOUT; + if (!already) { again1: - n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event); - if (n==-1){ - if (errno==EAGAIN) goto again1; - LM_ERR("epoll_ctl failed: %s [%d]\n", - strerror(errno), errno); - goto error; + n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event); + if (n==-1){ + if (errno==EAGAIN) goto again1; + LM_ERR("epoll_ctl failed: %s [%d]\n", + strerror(errno), errno); + goto error; + } + } else { +again11: + n=epoll_ctl(h->epfd, EPOLL_CTL_MOD, fd, &ep_event); + if (n==-1){ + if (errno==EAGAIN) goto again11; + LM_ERR("epoll_ctl failed: %s [%d]\n", + strerror(errno), errno); + goto error; + } } break; case POLL_EPOLL_ET: set_fd_flags(O_NONBLOCK); - ep_event.events=EPOLLIN|EPOLLET; + ep_event.events=EPOLLET; ep_event.data.ptr=e; + if (e->flags & IO_WATCH_READ) + ep_event.events|=EPOLLIN; + if (e->flags & IO_WATCH_WRITE) + ep_event.events|=EPOLLOUT; again2: - n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event); - if (n==-1){ - if (errno==EAGAIN) goto again2; - LM_ERR("epoll_ctl failed: %s [%d]\n", - strerror(errno), errno); - goto error; + if (!already) { + n=epoll_ctl(h->epfd, EPOLL_CTL_ADD, fd, &ep_event); + if (n==-1){ + if (errno==EAGAIN) goto again2; + LM_ERR("epoll_ctl failed: %s [%d]\n", + strerror(errno), errno); + goto error; + } + check_io=1; + } else { +again22: + n=epoll_ctl(h->epfd, EPOLL_CTL_MOD, fd, &ep_event); + if (n==-1){ + if (errno==EAGAIN) goto again22; + LM_ERR("epoll_ctl failed: %s [%d]\n", + strerror(errno), errno); + goto error; + } } idx=-1; - check_io=1; break; #endif #ifdef HAVE_KQUEUE @@ -427,23 +494,26 @@ inline static int io_watch_add( io_wait_h* h, } break; #endif - + default: LM_CRIT("no support for poll method " " %s (%d)\n", poll_method_str[h->poll_method], h->poll_method); goto error; } - - h->fd_no++; /* "activate" changes, for epoll/kqueue/devpoll it - has only informative value */ + + if (!already) { + h->fd_no++; /* "activate" changes, for epoll/kqueue/devpoll it + has only informative value */ + } + #if defined(HAVE_SIGIO_RT) || defined (HAVE_EPOLL) if (check_io){ /* handle possible pre-existing events */ pf.fd=fd; pf.events=POLLIN; check_io_again: - while( ((n=poll(&pf, 1, 0))>0) && (handle_io(e, idx)>0)); + while( ((n=poll(&pf, 1, 0))>0) && (handle_io(e, idx,IO_WATCH_READ)>0)); if (n==-1){ if (errno==EINTR) goto check_io_again; LM_ERR("check_io poll: %s [%d]\n", @@ -453,23 +523,21 @@ inline static int io_watch_add( io_wait_h* h, #endif return 0; error: - if (e) unhash_fd_map(e); + if (e) unhash_fd_map(e,0,flags,already); return -1; #undef fd_array_setup -#undef set_fd_flags +#undef set_fd_flags } -#define IO_FD_CLOSING 16 - /*! * \brief * \param h handler * \param fd file descriptor * \param idx index in the fd_array if known, -1 if not * (if index==-1 fd_array will be searched for the - * corresponding fd* entry -- slower but unavoidable in + * corresponding fd* entry -- slower but unavoidable in * some cases). index is not used (no fd_array) for epoll, * /dev/poll and kqueue * \param flags optimization flags, e.g. IO_FD_CLOSING, the fd was or will @@ -477,9 +545,9 @@ inline static int io_watch_add( io_wait_h* h, * remove operations (e.g.: epoll, kqueue, sigio) * \return 0 if ok, -1 on error */ -inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags) +inline static int io_watch_del(io_wait_h* h, int fd, int idx, + int flags,int sock_flags) { - #define fix_fd_array \ do{\ if (idx==-1){ \ @@ -488,11 +556,20 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags) (h->fd_array[idx].fd!=fd); idx++); \ } \ if (idxfd_no){ \ - memmove(&h->fd_array[idx], &h->fd_array[idx+1], \ - (h->fd_no-(idx+1))*sizeof(*(h->fd_array))); \ + if (erase) \ + memmove(&h->fd_array[idx], &h->fd_array[idx+1], \ + (h->fd_no-(idx+1))*sizeof(*(h->fd_array))); \ + else { \ + h->fd_array[idx].events = 0; \ + if (e->flags & IO_WATCH_READ) \ + h->fd_array[idx].events|=POLLIN; /* useless for select */ \ + if (flags & IO_WATCH_WRITE) \ + h->fd_array[idx].events|=POLLOUT; /* useless for select */ \ + h->fd_array[idx].revents = 0; \ + } \ } \ }while(0) - + struct fd_map* e; #ifdef HAVE_EPOLL int n; @@ -504,13 +581,14 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags) #ifdef HAVE_SIGIO_RT int fd_flags; #endif - + int erase = 0; + if ((fd<0) || (fd>=h->max_fd_no)){ LM_CRIT("invalid fd %d, not in [0, %d) \n", fd, h->fd_no); goto error; } - LM_DBG("io_watch_del (%p, %d, %d, 0x%x) fd_no=%d called\n", - h, fd, idx, flags, h->fd_no); + LM_DBG("io_watch_del op on index %d %d (%p, %d, %d, 0x%x,0x%x) fd_no=%d called\n", + idx,fd, h, fd, idx, flags,sock_flags,h->fd_no); e=get_fd_map(h, fd); /* more sanity checks */ if (e==0){ @@ -523,9 +601,15 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags) fd, e->fd, e->type, e->data); goto error; } - - unhash_fd_map(e); - + + if ((e->flags & sock_flags) == 0) { + LM_ERR("BUG - trying to del fd %d with flags %d %d\n",fd, + e->flags,sock_flags); + goto error; + } + + unhash_fd_map(e,flags,sock_flags,erase); + switch(h->poll_method){ case POLL_POLL: fix_fd_array; @@ -536,7 +620,7 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags) FD_CLR(fd, &h->master_set); if (h->max_fd_select && (h->max_fd_select==fd)) /* we don't know the prev. max, so we just decrement it */ - h->max_fd_select--; + h->max_fd_select--; break; #endif #ifdef HAVE_SIGIO_RT @@ -550,17 +634,17 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags) */ /*if (!(flags & IO_FD_CLOSING)){*/ /* reset ASYNC */ - fd_flags=fcntl(fd, F_GETFL); - if (fd_flags==-1){ - LM_ERR("fnctl: GETFL failed:" - " %s [%d]\n", strerror(errno), errno); - goto error; - } - if (fcntl(fd, F_SETFL, fd_flags&(~O_ASYNC))==-1){ - LM_ERR("fnctl: SETFL" - " failed: %s [%d]\n", strerror(errno), errno); - goto error; - } + fd_flags=fcntl(fd, F_GETFL); + if (fd_flags==-1){ + LM_ERR("fnctl: GETFL failed:" + " %s [%d]\n", strerror(errno), errno); + goto error; + } + if (fcntl(fd, F_SETFL, fd_flags&(~O_ASYNC))==-1){ + LM_ERR("fnctl: SETFL" + " failed: %s [%d]\n", strerror(errno), errno); + goto error; + } break; #endif #ifdef HAVE_EPOLL @@ -569,16 +653,31 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags) /* epoll doesn't seem to automatically remove sockets, * if the socket is a dupplicate/moved and the original * is still open. The fd is removed from the epoll set - * only when the original (and all the copies?) is/are + * only when the original (and all the copies?) is/are * closed. This is probably a bug in epoll. --andrei */ #ifdef EPOLL_NO_CLOSE_BUG if (!(flags & IO_FD_CLOSING)){ #endif - n=epoll_ctl(h->epfd, EPOLL_CTL_DEL, fd, &ep_event); - if (n==-1){ - LM_ERR("removing fd from epoll " - "list failed: %s [%d]\n", strerror(errno), errno); - goto error; + if (erase) { + n=epoll_ctl(h->epfd, EPOLL_CTL_DEL, fd, &ep_event); + if (n==-1){ + LM_ERR("removing fd from epoll " + "list failed: %s [%d]\n", strerror(errno), errno); + goto error; + } + } else { + ep_event.data.ptr=e; + ep_event.events=0; + if (e->flags & IO_WATCH_READ) + ep_event.events|=EPOLLIN; + if (e->flags & IO_WATCH_WRITE) + ep_event.events|=EPOLLOUT; + n=epoll_ctl(h->epfd, EPOLL_CTL_MOD, fd, &ep_event); + if (n==-1){ + LM_ERR("epoll_ctl failed: %s [%d]\n", + strerror(errno), errno); + goto error; + } } #ifdef EPOLL_NO_CLOSE_BUG } @@ -614,7 +713,10 @@ inline static int io_watch_del(io_wait_h* h, int fd, int idx, int flags) poll_method_str[h->poll_method], h->poll_method); goto error; } - h->fd_no--; + if (erase) { + h->fd_no--; + } + return 0; error: return -1; @@ -644,7 +746,7 @@ inline static int io_wait_loop_poll(io_wait_h* h, int t, int repeat) } } for (r=0; (rfd_no) && n; r++){ - if (h->fd_array[r].revents & (POLLIN|POLLERR|POLLHUP)){ + if (h->fd_array[r].revents & POLLOUT) { n--; /* sanity checks */ if ((h->fd_array[r].fd >= h->max_fd_no)|| @@ -655,7 +757,20 @@ inline static int io_wait_loop_poll(io_wait_h* h, int t, int repeat) h->fd_array[r].events=0; /* clear the events */ continue; } - while((handle_io(get_fd_map(h, h->fd_array[r].fd), r) > 0) + handle_io(get_fd_map(h, h->fd_array[r].fd),r,IO_WATCH_WRITE); + } else if (h->fd_array[r].revents & (POLLIN|POLLERR|POLLHUP)){ + n--; + /* sanity checks */ + if ((h->fd_array[r].fd >= h->max_fd_no)|| + (h->fd_array[r].fd < 0)){ + LM_CRIT("bad fd %d (no in the 0 - %d range)\n", + h->fd_array[r].fd, h->max_fd_no); + /* try to continue anyway */ + h->fd_array[r].events=0; /* clear the events */ + continue; + } + + while((handle_io(get_fd_map(h, h->fd_array[r].fd), r,IO_WATCH_READ) > 0) && repeat); } } @@ -673,7 +788,7 @@ inline static int io_wait_loop_select(io_wait_h* h, int t, int repeat) int n, ret; struct timeval timeout; int r; - + again: sel_set=h->master_set; timeout.tv_sec=t; @@ -688,7 +803,7 @@ inline static int io_wait_loop_select(io_wait_h* h, int t, int repeat) /* use poll fd array */ for(r=0; (rmax_fd_no) && n; r++){ if (FD_ISSET(h->fd_array[r].fd, &sel_set)){ - while((handle_io(get_fd_map(h, h->fd_array[r].fd), r)>0) + while((handle_io(get_fd_map(h, h->fd_array[r].fd), r,IO_WATCH_READ)>0) && repeat); n--; } @@ -703,13 +818,13 @@ inline static int io_wait_loop_select(io_wait_h* h, int t, int repeat) inline static int io_wait_loop_epoll(io_wait_h* h, int t, int repeat) { int n, r; - + again: n=epoll_wait(h->epfd, h->ep_array, h->fd_no, t*1000); if (n==-1){ if (errno==EINTR) goto again; /* signal, ignore it */ else{ - LM_ERR("epoll_wait(%d, %p, %d, %d): %s [%d]\n", + LM_ERR("epoll_wait(%d, %p, %d, %d): %s [%d]\n", h->epfd, h->ep_array, h->fd_no, t*1000, strerror(errno), errno); goto error; @@ -723,12 +838,14 @@ inline static int io_wait_loop_epoll(io_wait_h* h, int t, int repeat) } } #endif - for (r=0; rep_array[r].events & (EPOLLIN|EPOLLERR|EPOLLHUP)){ - while((handle_io((struct fd_map*)h->ep_array[r].data.ptr,-1)>0) + for (r=0; rep_array[r].events & EPOLLOUT) { + handle_io((struct fd_map*)h->ep_array[r].data.ptr,-1,IO_WATCH_WRITE); + } else if (h->ep_array[r].events & (EPOLLIN|EPOLLERR|EPOLLHUP)){ + while((handle_io((struct fd_map*)h->ep_array[r].data.ptr,-1,IO_WATCH_READ)>0) && repeat); }else{ - LM_ERR("unexpected event %x on %d/%d, data=%p\n", + LM_ERR("unexpected event %x on %d/%d, data=%p\n", h->ep_array[r].events, r+1, n, h->ep_array[r].data.ptr); } } @@ -744,7 +861,7 @@ inline static int io_wait_loop_kqueue(io_wait_h* h, int t, int repeat) { int n, r; struct timespec tspec; - + tspec.tv_sec=t; tspec.tv_nsec=0; again: @@ -774,7 +891,7 @@ inline static int io_wait_loop_kqueue(io_wait_h* h, int t, int repeat) strerror(h->kq_array[r].data), (long)h->kq_array[r].data); }else /* READ/EOF */ - while((handle_io((struct fd_map*)h->kq_array[r].udata, -1)>0) + while((handle_io((struct fd_map*)h->kq_array[r].udata, -1,IO_WATCH_READ)>0) && repeat); } error: @@ -795,8 +912,8 @@ inline static int io_wait_loop_sigio_rt(io_wait_h* h, int t) int sigio_band; int sigio_fd; struct fd_map* fm; - - + + ret=1; /* 1 event per call normally */ ts.tv_sec=t; ts.tv_nsec=0; @@ -842,13 +959,13 @@ inline static int io_wait_loop_sigio_rt(io_wait_h* h, int t) /* we can have queued signals generated by fds not watched * any more, or by fds in transition, to a child => ignore them*/ if (fm->type) - handle_io(fm, -1); + handle_io(fm, -1,IO_WATCH_READ); }else{ #ifdef EXTRA_DEBUG LM_DBG("siginfo: signal=%d (%d)," " si_code=%d, si_band=0x%x," " si_fd=%d\n", - siginfo.si_signo, n, siginfo.si_code, + siginfo.si_signo, n, siginfo.si_code, (unsigned)sigio_band, sigio_fd); #endif @@ -858,10 +975,10 @@ inline static int io_wait_loop_sigio_rt(io_wait_h* h, int t) if (sigio_band/*&(POLL_IN|POLL_ERR|POLL_HUP)*/){ fm=get_fd_map(h, sigio_fd); /* we can have queued signals generated by fds not watched - * any more, or by fds in transition, to a child + * any more, or by fds in transition, to a child * => ignore them */ if (fm->type) - handle_io(fm, -1); + handle_io(fm, -1,IO_WATCH_READ); else LM_ERR("ignoring event" " %x on fd %d (fm->fd=%d, fm->data=%p)\n", @@ -871,7 +988,7 @@ inline static int io_wait_loop_sigio_rt(io_wait_h* h, int t) } } }else{ - /* signal queue overflow + /* signal queue overflow * TODO: increase signal queue size: 2.4x /proc/.., 2.6x -rlimits */ LM_WARN("signal queue overflowed- falling back to poll\n"); /* clear real-time signal queue @@ -880,7 +997,7 @@ inline static int io_wait_loop_sigio_rt(io_wait_h* h, int t) if (signal(h->signo, SIG_IGN)==SIG_ERR){ LM_CRIT("couldn't reset signal to IGN\n"); } - + if (signal(h->signo, SIG_DFL)==SIG_ERR){ LM_CRIT("couldn't reset signal to DFL\n"); } @@ -921,7 +1038,7 @@ inline static int io_wait_loop_devpoll(io_wait_h* h, int t, int repeat) h->fd_array[r].fd, h->fd_array[r].revents); } /* POLLIN|POLLHUP just go through */ - while((handle_io(get_fd_map(h, h->fd_array[r].fd), r) > 0) && + while((handle_io(get_fd_map(h, h->fd_array[r].fd), r,IO_WATCH_READ) > 0) && repeat); } error: diff --git a/ip_addr.c b/ip_addr.c index 0c08e07a422..5c161dd1371 100644 --- a/ip_addr.c +++ b/ip_addr.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -46,7 +46,7 @@ struct net* mk_net(struct ip_addr* ip, struct ip_addr* mask) struct net* n; int warning; unsigned int r; - + warning=0; if ((ip->af != mask->af) || (ip->len != mask->len)){ LM_CRIT("trying to use a different mask family" @@ -54,7 +54,7 @@ struct net* mk_net(struct ip_addr* ip, struct ip_addr* mask) goto error; } n=(struct net*)pkg_malloc(sizeof(struct net)); - if (n==0){ + if (n==0){ LM_CRIT("memory allocation failure\n"); goto error; } @@ -83,7 +83,7 @@ struct net* mk_net_bitlen(struct ip_addr* ip, unsigned int bitlen) { struct ip_addr mask; unsigned int r; - + if (bitlen>ip->len*8){ LM_CRIT("bad bitlen number %d\n", bitlen); goto error; @@ -93,7 +93,7 @@ struct net* mk_net_bitlen(struct ip_addr* ip, unsigned int bitlen) if (bitlen%8) mask.u.addr[r]= ~((1<<(8-(bitlen%8)))-1); mask.af=ip->af; mask.len=ip->len; - + return mk_net(ip, &mask); error: return 0; diff --git a/ip_addr.h b/ip_addr.h index 6a3208f0503..e7c84df8fe8 100644 --- a/ip_addr.h +++ b/ip_addr.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -56,7 +56,7 @@ enum sip_protos { PROTO_NONE, PROTO_UDP, PROTO_TCP, PROTO_TLS, PROTO_SCTP, PROTO struct ip_addr{ unsigned int af; /*!< address family: AF_INET6 or AF_INET */ unsigned int len; /*!< address len, 16 or 4 */ - + /*! \brief 64 bits aligned address */ union { unsigned long addrl[16/sizeof(long)]; /*!< long format*/ @@ -123,7 +123,7 @@ struct receive_info { struct dest_info { int proto; - int proto_reserved1; /*!< tcp stores the connection id here */ + int proto_reserved1; /*!< tcp stores the connection id here */ union sockaddr_union to; struct socket_info* send_sock; }; @@ -153,7 +153,7 @@ struct socket_id { #define sockaddru_len(su) sizeof(struct sockaddr_in) #endif /*USE_IPV6*/ #endif /* HAVE_SOCKADDR_SA_LEN*/ - + /*! \brief inits an ip_addr with the addr. info from a hostent structure * ip = struct ip_addr* * he= struct hostent* @@ -164,7 +164,7 @@ struct socket_id { (ip)->len=(he)->h_length; \ memcpy((ip)->u.addr, (he)->h_addr_list[(addr_no)], (ip)->len); \ }while(0) - + @@ -192,13 +192,13 @@ void print_net(struct net* net); int is_mcast(struct ip_addr* ip); #endif /* USE_MCAST */ -/*! \brief returns 1 if ip & net.mask == net.ip ; 0 otherwise & -1 on error +/*! \brief returns 1 if ip & net.mask == net.ip ; 0 otherwise & -1 on error [ diff. address families ]) */ inline static int matchnet(struct ip_addr* ip, struct net* net) { unsigned int r; /* int ret; - + ret=-1; */ if (ip->af == net->ip.af){ for(r=0; rlen/4; r++){ /* ipv4 & ipv6 addresses are @@ -308,7 +308,7 @@ static inline void su_setport(union sockaddr_union* su, unsigned short port) static inline void su2ip_addr(struct ip_addr* ip, union sockaddr_union* su) { switch(su->s.sa_family){ - case AF_INET: + case AF_INET: ip->af=AF_INET; ip->len=4; memcpy(ip->u.addr, &su->sin.sin_addr, 4); @@ -322,6 +322,8 @@ static inline void su2ip_addr(struct ip_addr* ip, union sockaddr_union* su) #endif default: LM_CRIT("Unknown address family %d\n", su->s.sa_family); + ip->af=0; + ip->len=0; } } @@ -329,19 +331,19 @@ static inline void su2ip_addr(struct ip_addr* ip, union sockaddr_union* su) /*! \brief ip_addr2su -> the same as \ref init_su() */ #define ip_addr2su init_su -/*! \brief inits a struct sockaddr_union from a struct ip_addr and a port no +/*! \brief inits a struct sockaddr_union from a struct ip_addr and a port no * \return 0 if ok, -1 on error (unknown address family) * \note the port number is in host byte order */ static inline int init_su( union sockaddr_union* su, struct ip_addr* ip, - unsigned short port ) + unsigned short port ) { memset(su, 0, sizeof(union sockaddr_union));/*needed on freebsd*/ su->s.sa_family=ip->af; switch(ip->af){ #ifdef USE_IPV6 case AF_INET6: - memcpy(&su->sin6.sin6_addr, ip->u.addr, ip->len); + memcpy(&su->sin6.sin6_addr, ip->u.addr, ip->len); #ifdef HAVE_SOCKADDR_SA_LEN su->sin6.sin6_len=sizeof(struct sockaddr_in6); #endif @@ -371,7 +373,7 @@ static inline int init_su( union sockaddr_union* su, static inline int hostent2su( union sockaddr_union* su, struct hostent* he, unsigned int idx, - unsigned short port ) + unsigned short port ) { memset(su, 0, sizeof(union sockaddr_union)); /*needed on freebsd*/ su->s.sa_family=he->h_addrtype; @@ -416,8 +418,8 @@ static inline char* ip_addr2a(struct ip_addr* ip) #endif int r; #define HEXDIG(x) (((x)>=10)?(x)-10+'A':(x)+'0') - - + + offset=0; switch(ip->af){ #ifdef USE_IPV6 @@ -519,12 +521,12 @@ static inline char* ip_addr2a(struct ip_addr* ip) _ip_addr_A_buff[offset+1]=0; } break; - + default: LM_CRIT("unknown address family %d\n", ip->af); return 0; } - + return _ip_addr_A_buff; } @@ -540,7 +542,7 @@ static inline struct hostent* ip_addr2he(str* name, struct ip_addr* ip) static char* p_addr[2]; static char address[16]; int len; - + p_aliases[0]=0; /* no aliases*/ p_addr[1]=0; /* only one address*/ p_addr[0]=address; @@ -549,7 +551,7 @@ static inline struct hostent* ip_addr2he(str* name, struct ip_addr* ip) hostname[len] = 0; if (ip->len>16) return 0; memcpy(address, ip->u.addr, ip->len); - + he.h_addrtype=ip->af; he.h_length=ip->len; he.h_addr_list=p_addr; diff --git a/lock_alloc.h b/lock_alloc.h index 763b980a5a3..3f3aa06c007 100644 --- a/lock_alloc.h +++ b/lock_alloc.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -45,7 +45,7 @@ * lock sets: [implemented only for FL & SYSV so far] * - gen_lock_set_t* lock_set_alloc(no) - allocs a lock set in shm. * - void lock_set_dealloc(gen_lock_set_t* s); - deallocs the lock set shm. - * + * * \see locking.h */ diff --git a/lock_ops.h b/lock_ops.h index 84e3ab8b0fc..91023743cdf 100644 --- a/lock_ops.h +++ b/lock_ops.h @@ -15,13 +15,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * History: * -------- * 2002-12-16 created by andrei - * 2003-02-20 s/gen_lock_t/gen_lock_t/ to avoid a type conflict + * 2003-02-20 s/gen_lock_t/gen_lock_t/ to avoid a type conflict * on solaris (andrei) * 2003-03-05 lock set support added for FAST_LOCK & SYSV (andrei) * 2003-03-06 removed *_alloc,*_dealloc & moved them to lock_alloc.h @@ -53,7 +53,7 @@ * - void lock_set_release(gen_lock_set_t* s, int i)- unlocks sem i from the set * * WARNING: - * - lock_set_init may fail for large number of sems (e.g. sysv). + * - lock_set_init may fail for large number of sems (e.g. sysv). * - signals are not treated! (some locks are "awakened" by the signals) * * \note Warning: do not include this file directly, use instead locking.h @@ -80,7 +80,7 @@ typedef fl_lock_t gen_lock_t; #endif -#define lock_destroy(lock) /* do nothing */ +#define lock_destroy(lock) /* do nothing */ inline static gen_lock_t* lock_init(gen_lock_t* lock) { @@ -96,7 +96,7 @@ inline static gen_lock_t* lock_init(gen_lock_t* lock) typedef pthread_mutex_t gen_lock_t; -#define lock_destroy(lock) /* do nothing */ +#define lock_destroy(lock) /* do nothing */ inline static gen_lock_t* lock_init(gen_lock_t* lock) { @@ -114,7 +114,7 @@ inline static gen_lock_t* lock_init(gen_lock_t* lock) typedef sem_t gen_lock_t; -#define lock_destroy(lock) /* do nothing */ +#define lock_destroy(lock) /* do nothing */ inline static gen_lock_t* lock_init(gen_lock_t* lock) { @@ -137,8 +137,8 @@ inline static gen_lock_t* lock_init(gen_lock_t* lock) #include "dprint.h" extern int uid; /* from main.c */ -#if ((defined(HAVE_UNION_SEMUN) || defined(__GNU_LIBRARY__) )&& !defined(_SEM_SEMUN_UNDEFINED)) - +#if ((defined(HAVE_UNION_SEMUN) || defined(__GNU_LIBRARY__) )&& !defined(_SEM_SEMUN_UNDEFINED)) + /* union semun is defined by including sem.h */ #else /* according to X/OPEN we have to define it ourselves */ @@ -159,7 +159,7 @@ inline static gen_lock_t* lock_init(gen_lock_t* lock) { union semun su; int euid; - + euid=geteuid(); if (uid && uid!=euid) seteuid(uid); /* set euid to the cfg. requested one */ @@ -190,7 +190,7 @@ inline static void lock_get(gen_lock_t* lock) sop.sem_num=0; sop.sem_op=-1; /* down */ - sop.sem_flg=0; + sop.sem_flg=0; tryagain: if (semop(*lock, &sop, 1)==-1){ if (errno==EINTR){ @@ -205,10 +205,10 @@ inline static void lock_get(gen_lock_t* lock) inline static void lock_release(gen_lock_t* lock) { struct sembuf sop; - + sop.sem_num=0; sop.sem_op=1; /* up */ - sop.sem_flg=0; + sop.sem_flg=0; tryagain: if (semop(*lock, &sop, 1)==-1){ if (errno==EINTR){ @@ -282,7 +282,7 @@ inline static gen_lock_set_t* lock_set_init(gen_lock_set_t* s) su.val=1; for (r=0; rsize; r++){ if (semctl(s->semid, r, SETVAL, su)==-1){ - LM_CRIT("semctl failed on sem %d: %s\n", + LM_CRIT("semctl failed on sem %d: %s\n", r, strerror(errno)); su.val = 0; semctl(s->semid, 0, IPC_RMID, su); @@ -334,7 +334,7 @@ inline static void lock_set_release(gen_lock_set_t* s, int n) } } } -#else +#else #error "no lock set method selected" #endif diff --git a/locking.h b/locking.h index 78a047ea21a..b3b794593d4 100644 --- a/locking.h +++ b/locking.h @@ -15,14 +15,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- * 2002-12-16 created by andrei - * 2003-02-20 s/gen_lock_t/gen_lock_t/ to avoid a type conflict + * 2003-02-20 s/gen_lock_t/gen_lock_t/ to avoid a type conflict * on solaris (andrei) * 2003-03-05 lock set support added for FAST_LOCK & SYSV (andrei) * 2003-03-06 split in two: lock_ops.h & lock_alloc.h, to avoid @@ -56,7 +56,7 @@ * - void lock_set_release(gen_lock_set_t* s, int i)- unlocks sem i from the set * * WARNING: - * - lock_set_init may fail for large number of sems (e.g. sysv). + * - lock_set_init may fail for large number of sems (e.g. sysv). * - signals are not treated! (some locks are "awakened" by the signals) */ diff --git a/lump_struct.h b/lump_struct.h index f5d9d7024b8..b860dd27fa4 100644 --- a/lump_struct.h +++ b/lump_struct.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -83,7 +83,7 @@ enum lump_flag { LUMPFLAG_NONE=0, LUMPFLAG_DUPED=1, struct lump{ enum _hdr_types_t type; /*!< HDR_VIA_T, HDR_OTHER_T (0), ... */ enum lump_op op; /*!< DEL, ADD, NOP, UNSPEC(=0) */ - + union{ unsigned int offset; /*!< used for DEL, MODIFY */ enum lump_subst subst; /*!< what to subst: ip addr, port, proto*/ @@ -91,8 +91,8 @@ struct lump{ char * value; /*!< used for ADD */ }u; unsigned int len; /*!< length of this header field */ - - + + struct lump* before; /*!< list of headers to be inserted in front of the current one */ struct lump* after; /*!< list of headers to be inserted immediately after @@ -106,7 +106,7 @@ struct lump{ /* * hdrs must be kept sorted after their offset (DEL, NOP, UNSPEC) * and/or their position (ADD). E.g.: - * - to delete header Z insert it in to the list according to its offset + * - to delete header Z insert it in to the list according to its offset * and with op=DELETE * - if you want to add a new header X after a header Y, insert Y in the list * with op NOP and after it X (op ADD). @@ -115,11 +115,11 @@ struct lump{ * -if you want to replace Y with X, insert Y with op=DELETE and then X with * op=ADD. * before and after must contain only ADD ops! - * + * * Difference between "after" & "next" when Adding: * "after" forces the new header immediately after the current one while * "next" means another header can be inserted between them. - * + * */ /*! \brief frees the content of a lump struct */ diff --git a/main.c b/main.c index 4493a362451..c3b6bb4b6f4 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2005-2006 Voice Sistem S.R.L * @@ -16,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -28,10 +26,10 @@ * 2003-03-29 pkg cleaners for fifo and script callbacks introduced (jiri) * 2003-03-31 removed snmp part (obsolete & no place in core) (andrei) * 2003-04-06 child_init called in all processes (janakj) - * 2003-04-08 init_mallocs split into init_{pkg,shm}_mallocs and + * 2003-04-08 init_mallocs split into init_{pkg,shm}_mallocs and * init_shm_mallocs called after cmd. line parsing (andrei) * 2003-04-15 added tcp_disable support (andrei) - * 2003-05-09 closelog() before openlog to force opening a new fd + * 2003-05-09 closelog() before openlog to force opening a new fd * (needed on solaris) (andrei) * 2003-06-11 moved all signal handlers init. in install_sigs and moved it * after daemonize (so that we won't catch anymore our own @@ -106,6 +104,7 @@ #include "daemonize.h" #include "route.h" #include "udp_server.h" +#include "bin_interface.h" #include "globals.h" #include "mem/mem.h" #ifdef SHM_MEM @@ -133,6 +132,7 @@ #ifdef USE_TCP #include "poll_types.h" #include "tcp_init.h" +#include "tcp_conn.h" #ifdef USE_TLS #include "tls/tls_init.h" #endif @@ -146,7 +146,6 @@ #include "mi/mi_core.h" #include "db/db_insertq.h" -static char id[]="@(#) $Id$"; static char* version=OPENSIPS_FULL_VERSION; static char* flags=OPENSIPS_COMPILE_FLAGS; char compiled[]= __TIME__ " " __DATE__ ; @@ -166,13 +165,9 @@ void print_ct_constants(void) #ifdef USE_TCP printf("poll method support: %s.\n", poll_support); #endif - printf("svnrevision: %s\n", -#ifdef SVNREVISION - SVNREVISION -#else - "unknown" +#ifdef VERSIONTYPE + printf("%s revision: %s\n", VERSIONTYPE, THISREVISION); #endif - ); } /* global vars */ @@ -182,13 +177,36 @@ int own_pgid = 0; /* whether or not we have our own pgid (and it's ok char* cfg_file = 0; unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do not want to exceed during the - auto-probing procedure; may + auto-probing procedure; may be re-configured */ int children_no = 0; /* number of children processing requests */ #ifdef USE_TCP int tcp_children_no = 0; int tcp_disable = 0; /* 1 if tcp is disabled */ int tcp_crlf_pingpong = 1; /* 0: send CRLF pong to incoming CRLFCRLF ping */ +int tcp_max_msg_chunks = TCP_CHILD_MAX_MSG_CHUNK; /* Max number of chunks that + we except to receive a SIP + message - anything above will + lead to the connection + being treat as broken & closed */ +int tcp_max_msg_time = TCP_CHILD_MAX_MSG_TIME; /* Max number of seconds that + we except a full SIP message + to arrive in - anything above + will lead to the connection to + closed */ +int tcp_async = 0; /* 1 if TCP connect & write should be async */ +int tcp_async_local_connect_timeout = 10000; /* Number of microseconds that a + worker will block waiting for a local + connect - if connect op exceeds this, it + will get passed to TCP main*/ +int tcp_async_local_write_timeout = 10000; /* Number of microseconds that a + worker will block waiting for a local + write - if write op exceeds this, it + will get passed to TCP main*/ +int tcp_async_max_postponed_chunks = 32; /* maximum number of write chunks that + will be queued per TCP connection - + if we exceed this number, we just + drop the connection */ #endif #ifdef USE_TLS int tls_disable = 1; /* 1 if tls is disabled */ @@ -197,13 +215,13 @@ int tls_disable = 1; /* 1 if tls is disabled */ int sctp_disable = 0; /* 1 if sctp is disabled */ #endif int sig_flag = 0; /* last signal received */ -#ifdef CHANGEABLE_DEBUG_LEVEL -int debug_init = L_NOTICE; -int *debug = &debug_init; -#else -int debug = L_NOTICE; -#endif + int dont_fork = 0; +int no_daemon_mode = 0; +/* assertion statements in script. disabled by default */ +int enable_asserts = 0; +/* abort process on failed assertion. disabled by default */ +int abort_on_assert = 0; /* start by logging to stderr */ int log_stderr = 1; /* log facility (see syslog(3)) */ @@ -240,7 +258,7 @@ str user_agent_header = {USER_AGENT,sizeof(USER_AGENT)-1}; * host? by default not -- too expensive */ int mhomed=0; -/* use dns and/or rdns or to see if we need to add +/* use dns and/or rdns or to see if we need to add a ;received=x.x.x.x to via: */ int received_dns = 0; char* working_dir = 0; @@ -277,8 +295,8 @@ struct socket_info* bind_address=0; /* pointer to the crt. proc. struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/ struct socket_info* sendipv6; /* same as above for ipv6 */ #ifdef USE_TCP -struct socket_info* sendipv4_tcp; -struct socket_info* sendipv6_tcp; +struct socket_info* sendipv4_tcp; +struct socket_info* sendipv6_tcp; #endif #ifdef USE_TLS struct socket_info* sendipv4_tls; @@ -290,11 +308,11 @@ struct socket_info* sendipv6_sctp; #endif -/* if aliases should be automatically discovered and added +/* if aliases should be automatically discovered and added * during fixing listening sockets */ int auto_aliases=1; -/* if the stateless forwarding support in core should be +/* if the stateless forwarding support in core should be * disabled or not */ int sl_fwd_disabled=-1; @@ -314,10 +332,26 @@ time_t startup_time = 0; /* shared memory (in MB) */ unsigned long shm_mem_size=SHM_MEM_SIZE * 1024 * 1024; +unsigned int shm_hash_split_percentage = DEFAULT_SHM_HASH_SPLIT_PERCENTAGE; +unsigned int shm_secondary_hash_size = DEFAULT_SHM_SECONDARY_HASH_SIZE; -/* shared memory (in MB) */ +/* packaged memory (in MB) */ unsigned long pkg_mem_size=PKG_MEM_SIZE * 1024 * 1024; +/* + * adaptive image of OpenSIPS's memory usage during runtime + * used to fragment the shared memory pool at daemon startup + */ +char *mem_warming_pattern_file; +int mem_warming_enabled; + +/* + * percentage of shared memory which will be fragmented at startup + * common values are between [0, 75] + */ +int mem_warming_percentage = -1; + + /* export command-line to anywhere else */ int my_argc; char **my_argv; @@ -334,16 +368,28 @@ char* pgid_file = 0; /** * Clean up on exit. This should be called before exiting. - * \param show_status set to one to display the mem status + * \param show_status set to one to display the mem status */ void cleanup(int show_status) { LM_INFO("cleanup\n"); /*clean-up*/ - if (mem_lock) - shm_unlock(); /* hack: force-unlock the shared memory lock in case - some process crashed and let it locked; this will - allow an almost gracious shutdown */ + + /* hack: force-unlock the shared memory lock in case + some process crashed and let it locked; this will + allow an almost gracious shutdown */ + if (mem_lock) +#ifdef HP_MALLOC + { + int i; + + for (i = 0; i < HP_HASH_SIZE; i++) + shm_unlock(i); + } +#else + shm_unlock(); +#endif + handle_ql_shutdown(); destroy_modules(); #ifdef USE_TCP @@ -358,14 +404,6 @@ void cleanup(int show_status) pv_free_extra_list(); destroy_argv_list(); destroy_black_lists(); -#ifdef CHANGEABLE_DEBUG_LEVEL - if (debug!=&debug_init) { - reset_proc_debug_level(); - debug_init = *debug; - shm_free(debug); - debug = &debug_init; - } -#endif #ifdef PKG_MALLOC if (show_status){ LM_GEN1(memdump, "Memory status (pkg):\n"); @@ -373,12 +411,15 @@ void cleanup(int show_status) } #endif #ifdef SHM_MEM + cleanup_debug(); + if (pt) shm_free(pt); pt=0; if (show_status){ LM_GEN1(memdump, "Memory status (shm):\n"); shm_status(); } + /* zero all shmem alloc vars that we still use */ shm_mem_destroy(); #endif @@ -387,14 +428,14 @@ void cleanup(int show_status) } -/** +/** * Tries to send a signal to all our processes * If daemonized is ok to send the signal to all the process group, * however if not daemonized we might end up sending the signal also - * to the shell which launched us => most signals will kill it if - * it's not in interactive mode and we don't want this. The non-daemonized - * case can occur when an error is encountered before daemonize is called - * (e.g. when parsing the config file) or when opensips is started in + * to the shell which launched us => most signals will kill it if + * it's not in interactive mode and we don't want this. The non-daemonized + * case can occur when an error is encountered before daemonize is called + * (e.g. when parsing the config file) or when opensips is started in * "dont-fork" mode. * \param signum signal for killing the children */ @@ -410,7 +451,7 @@ static void kill_all_children(int signum) /** - * Timeout handler during wait for children exit. + * Timeout handler during wait for children exit. * If this handler is called, a critical timeout has occured while * waiting for the children to finish => we should kill everything and exit * \param signo signal for killing the children @@ -426,7 +467,7 @@ static void sig_alarm_kill(int signo) /** - * Timeout handler during wait for children exit. + * Timeout handler during wait for children exit. * like sig_alarm_kill, but the timeout has occured when cleaning up, * try to leave a core for future diagnostics * \param signo signal for killing the children @@ -466,7 +507,7 @@ void handle_sigs(void) LM_DBG("INT received, program terminates\n"); else LM_DBG("SIGTERM received, program terminates\n"); - + /* first of all, kill the children also */ kill_all_children(SIGTERM); if (signal(SIGALRM, sig_alarm_kill) == SIG_ERR ) { @@ -484,7 +525,7 @@ void handle_sigs(void) dprint("Thank you for flying " NAME "\n"); exit(0); break; - + case SIGUSR1: #ifdef PKG_MALLOC LM_GEN1(memdump, "Memory status (pkg):\n"); @@ -495,13 +536,13 @@ void handle_sigs(void) shm_status(); #endif break; - + case SIGUSR2: #ifdef PKG_MALLOC set_pkg_stats( get_pkg_status_holder(process_no) ); #endif break; - + case SIGCHLD: do_exit = 0; while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) { @@ -517,9 +558,9 @@ void handle_sigs(void) overall_status |= chld_status; LM_DBG("status = %d\n",overall_status); - if (WIFEXITED(chld_status)) + if (WIFEXITED(chld_status)) LM_INFO("child process %d exited normally," - " status=%d\n", chld, + " status=%d\n", chld, WEXITSTATUS(chld_status)); else if (WIFSIGNALED(chld_status)) { LM_INFO("child process %d exited by a signal" @@ -528,7 +569,7 @@ void handle_sigs(void) LM_INFO("core was %sgenerated\n", WCOREDUMP(chld_status) ? "" : "not " ); #endif - }else if (WIFSTOPPED(chld_status)) + }else if (WIFSTOPPED(chld_status)) LM_INFO("child process %d stopped by a" " signal %d\n", chld, WSTOPSIG(chld_status)); @@ -552,7 +593,7 @@ void handle_sigs(void) LM_DBG("terminating due to SIGCHLD\n"); exit(overall_status ? -1 : 0); break; - + case SIGHUP: /* ignoring it*/ LM_DBG("SIGHUP received, ignoring it\n"); break; @@ -576,7 +617,7 @@ static void sig_usr(int signo) if (sig_flag==0) sig_flag=signo; else /* previous sig. not processed yet, ignoring? */ return; ; - if (dont_fork) + if (dont_fork) /* only one proc, doing everything from the sig handler, unsafe, but this is only for debugging mode*/ handle_sigs(); @@ -622,7 +663,7 @@ static void sig_usr(int signo) /** * Install the signal handlers. - * \return 0 on success, -1 on error + * \return 0 on success, -1 on error */ int install_sigs(void) { @@ -636,7 +677,7 @@ int install_sigs(void) LM_ERR("no SIGINT signal handler can be installed\n"); goto error; } - + if (signal(SIGUSR1, sig_usr) == SIG_ERR ) { LM_ERR("no SIGUSR1 signal handler can be installed\n"); goto error; @@ -679,6 +720,11 @@ static int main_loop(void) chd_rank=0; + if (init_debug() != 0) { + LM_ERR("failed to init logging levels\n"); + goto error; + } + if (dont_fork){ if (create_status_pipe() < 0) { @@ -716,7 +762,7 @@ static int main_loop(void) } /* main process, receive loop */ - set_proc_attrs("stand-alone SIP receiver %.*s", + set_proc_attrs("stand-alone SIP receiver %.*s", bind_address->sock_str.len, bind_address->sock_str.s ); /* We will call child_init even if we @@ -829,6 +875,17 @@ static int main_loop(void) *startup_done = 0; } + if (fix_socket_list(&bin) != 0) { + LM_ERR("failed to initialize binary interface socket list!\n"); + goto error; + } + + /* OpenSIPS <--> OpenSIPS communication interface */ + if (bin && start_bin_receivers() != 0) { + LM_CRIT("cannot start binary interface receiver processes!\n"); + goto error; + } + /* udp processes */ for(si=udp_listen; si; si=si->next){ @@ -854,23 +911,30 @@ static int main_loop(void) if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); + if (chd_rank == 1 && startup_done) + *startup_done = -1; exit(-1); } - if (send_status_code(0) < 0) - LM_ERR("failed to send status code\n"); - clean_write_pipeend(); - /* first UDP proc runs statup_route (if defined) */ if(chd_rank == 1 && startup_done!=NULL) { LM_DBG("runing startup for first UDP\n"); if(run_startup_route()< 0) { + if (send_status_code(-1) < 0) + LM_ERR("failed to send status code\n"); + clean_write_pipeend(); + *startup_done = -1; LM_ERR("Startup route processing failed\n"); exit(-1); } *startup_done = 1; } + if (!no_daemon_mode && send_status_code(0) < 0) + LM_ERR("failed to send status code\n"); + clean_write_pipeend(); + + /* all UDP listeners on same interface * have same SHM load pointer */ pt[process_no].load = load_p; @@ -880,7 +944,7 @@ static int main_loop(void) else { /* wait for first proc to finish the startup route */ if(chd_rank == 1 && startup_done!=NULL) - while( !(*startup_done) ) usleep(5); + while( !(*startup_done) ) {usleep(5);handle_sigs();} } } } @@ -908,21 +972,27 @@ static int main_loop(void) if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); + if( (si==sctp_listen && i==0) && startup_done) + *startup_done = -1; exit(-1); } - /* was startup route executed so far ? if not, run it only by the + /* was startup route executed so far ? if not, run it only by the * first SCTP proc (first proc from first interface) */ if( (si==sctp_listen && i==0) && startup_done!=NULL && *startup_done==0) { LM_DBG("runing startup for first SCTP\n"); if(run_startup_route()< 0) { LM_ERR("Startup route processing failed\n"); + if (send_status_code(-1) < 0) + LM_ERR("failed to send status code\n"); + clean_write_pipeend(); + *startup_done = -1; exit(-1); } *startup_done = 1; } - if (send_status_code(0) < 0) + if (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); @@ -931,7 +1001,7 @@ static int main_loop(void) } else { /* wait for first proc to finish the startup route */ if( (si==sctp_listen && i==0) && startup_done!=NULL) - while( !(*startup_done) ) usleep(5); + while( !(*startup_done) ) {usleep(5);handle_sigs();} } } } @@ -953,7 +1023,7 @@ static int main_loop(void) if (tcp_init_children(&chd_rank, startup_done)<0) goto error; /* wait for the startup route to be executed */ if( startup_done!=NULL) - while( !(*startup_done) ) usleep(5); + while( !(*startup_done) ) {usleep(5);handle_sigs();} /* start tcp+tls master proc */ if ( (pid=internal_fork( "TCP main"))<0 ) { LM_CRIT("cannot fork tcp main process\n"); @@ -975,7 +1045,7 @@ static int main_loop(void) exit(-1); } - if (send_status_code(0) < 0) + if (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); @@ -986,7 +1056,7 @@ static int main_loop(void) #endif if (startup_done) { - if (*startup_done!=1) + if (*startup_done==0) LM_CRIT("BUG: startup route defined, but not run :( \n"); shm_free(startup_done); } @@ -996,11 +1066,14 @@ static int main_loop(void) set_proc_attrs("attendant"); if (init_child(PROC_MAIN) < 0) { + if (send_status_code(-1) < 0) + LM_ERR("failed to send status code\n"); + clean_write_pipeend(); LM_ERR("error in init_child for PROC_MAIN\n"); goto error; } - if (send_status_code(0) < 0) + if (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); @@ -1052,7 +1125,7 @@ int main(int argc, char** argv) /* process pkg mem size from command line */ opterr=0; - options="f:cCm:M:b:l:n:N:rRvdDETSVhw:t:u:g:P:G:W:o:"; + options="f:cCm:M:b:l:n:N:rRvdDFETSVhw:t:u:g:P:G:W:o:"; while((c=getopt(argc,argv,options))!=-1){ switch(c){ @@ -1135,15 +1208,14 @@ int main(int argc, char** argv) case 'R': received_dns|=DO_REV_DNS; case 'd': -#ifdef CHANGEABLE_DEBUG_LEVEL (*debug)++; -#else - debug++; -#endif break; case 'D': dont_fork=1; break; + case 'F': + no_daemon_mode=1; + break; case 'E': cfg_log_stderr=1; break; @@ -1188,10 +1260,9 @@ int main(int argc, char** argv) printf("version: %s\n", version); printf("flags: %s\n", flags ); print_ct_constants(); - printf("%s\n",id); printf("%s compiled on %s with %s\n", __FILE__, compiled, COMPILER ); - + exit(0); break; case 'h': @@ -1311,6 +1382,11 @@ int main(int argc, char** argv) print_rl(); #endif + if (no_daemon_mode+dont_fork > 1) { + LM_ERR("cannot use -D (fork=no) and -F together\n"); + return ret; + } + /* init the resolver, before fixing the config */ resolv_init(); @@ -1319,15 +1395,15 @@ int main(int argc, char** argv) #ifdef USE_TLS if (tls_port_no<=0) tls_port_no=SIPS_PORT; #endif - - + + if (children_no<=0) children_no=CHILD_NO; #ifdef USE_TCP if (!tcp_disable){ if (tcp_children_no<=0) tcp_children_no=children_no; } #endif - + if (working_dir==0) working_dir="/"; /* get uid/gid */ @@ -1354,9 +1430,9 @@ int main(int argc, char** argv) /*print_aliases();*/ print_aliases(); printf("\n"); - + if (dont_fork){ - LM_WARN("no fork mode %s\n", + LM_WARN("no fork mode %s\n", (udp_listen)?( (udp_listen->next)?" and more than one listen address found" "(will use only the first one)":"" @@ -1370,8 +1446,16 @@ int main(int argc, char** argv) time(&startup_time); + if (mem_warming_enabled) { + if (!mem_warming_pattern_file) + mem_warming_pattern_file = MEM_WARMING_DEFAULT_PATTERN_FILE; + + if (mem_warming_percentage == -1) + mem_warming_percentage = MEM_WARMING_DEFAULT_PERCENTAGE; + } + /*init shm mallocs - * this must be here + * this must be here * -to allow setting shm mem size from the command line * => if shm_mem should be settable from the cfg file move * everything after @@ -1381,12 +1465,21 @@ int main(int argc, char** argv) * --andrei */ if (init_shm_mallocs()==-1) goto error; + + /* Init statistics */ + if (init_stats_collector()<0) { + LM_ERR("failed to initialize statistics\n"); + goto error; + } + + init_shm_statistics(); + /*init timer, before parsing the cfg!*/ if (init_timer()<0){ LM_CRIT("could not initialize timer, exiting...\n"); goto error; } - + #ifdef USE_TCP if (!tcp_disable){ /*init tcp*/ @@ -1418,24 +1511,10 @@ int main(int argc, char** argv) goto error; } -#ifdef CHANGEABLE_DEBUG_LEVEL -#ifdef SHM_MEM - debug=shm_malloc(sizeof(int)); - if (debug==0) { - LM_ERR("ERROR: out of memory\n"); - goto error; - } - *debug = debug_init; -#else - LM_WARN("no shm mem support compiled -> changeable debug " - "level turned off\n"); -#endif -#endif - if (disable_core_dump) set_core_dump(0, 0); else set_core_dump(1, shm_mem_size+pkg_mem_size+4*1024*1024); if (open_files_limit>0){ - if(increase_open_fds(open_files_limit)<0){ + if(increase_open_fds(open_files_limit)<0){ LM_ERR("ERROR: error could not increase file limits\n"); goto error; } @@ -1443,7 +1522,7 @@ int main(int argc, char** argv) /* print OpenSIPS version to log for history tracking */ LM_NOTICE("version: %s\n", version); - + /* print some data about the configuration */ #ifdef SHM_MEM LM_INFO("using %ld Mb shared memory\n", ((shm_mem_size/1024)/1024)); @@ -1455,11 +1534,6 @@ int main(int argc, char** argv) LM_ERR("failed to initialize serialization\n"); goto error; } - /* Init statistics */ - if (init_stats_collector()<0) { - LM_ERR("failed to initialize statistics\n"); - goto error; - } /* Init MI */ if (init_mi_core()<0) { LM_ERR("failed to initialize MI core\n"); @@ -1474,7 +1548,7 @@ int main(int argc, char** argv) /* init black list engine */ if (init_black_lists()!=0) { - LM_CRIT("failed to init black lists\n"); + LM_CRIT("failed to init blacklists\n"); goto error; } /* init resolver's blacklist */ @@ -1503,7 +1577,7 @@ int main(int argc, char** argv) /* init query list now in shm * so all processes that will be forked from now on - * will have access to it + * will have access to it * * if it fails, give it a try and carry on */ if (init_ql_support() != 0) { diff --git a/map.c b/map.c index 576479f3af9..d98b404f3b2 100644 --- a/map.c +++ b/map.c @@ -64,7 +64,7 @@ static int str_cmp(str s1, str s2) if( ret == 0) ret = s1.len - s2.len; - + return ret; } @@ -86,7 +86,7 @@ map_t map_create(int flags) tree->avl_root = NULL; tree->flags = flags; tree->avl_count = 0; - + return tree; } @@ -139,7 +139,7 @@ void ** map_get( map_t tree, str key) } avl_malloc( n, sizeof *n, tree->flags ); - + if (n == NULL) return NULL; @@ -157,7 +157,7 @@ void ** map_get( map_t tree, str key) } else n->key = key; - + n->val = NULL; if (q != NULL) q->avl_link[dir] = n; @@ -268,7 +268,7 @@ void * map_put( map_t table, str key, void *item) ret = *p; *p = item; - + return ret == item ? NULL : ret; } @@ -449,7 +449,7 @@ void * map_remove( map_t tree, str key) { struct avl_node *p; /* Traverses tree to find node to delete. */ int dir; /* Side of |q| on which |p| is linked. */ - + if (tree->avl_root == NULL) return NULL; @@ -466,7 +466,7 @@ void * map_remove( map_t tree, str key) } return delete_node( tree, p ); - + } @@ -570,7 +570,7 @@ str * iterator_key( map_iterator_t * it ) { if( it == NULL ) return NULL; - + return &it->node->key; } @@ -586,7 +586,7 @@ int iterator_is_valid( map_iterator_t * it ) { if( it == NULL || it->map ==NULL || it->node == NULL) return 0; - + return 1; } diff --git a/map.h b/map.h index edc4797c07b..8dfad344639 100644 --- a/map.h +++ b/map.h @@ -29,7 +29,7 @@ #include #ifndef AVL_H -#define AVL_H +#define AVL_H @@ -53,7 +53,7 @@ typedef struct avl_table { struct avl_node *avl_root; /* Tree's root. */ size_t avl_count; /* Number of items in tree. */ int ret_code; - + } *map_t; /* Iterator data structure. */ @@ -86,7 +86,7 @@ typedef void (* value_destroy_func)(void *); * * Should return 0. A non-zero return code will cause the processing to stop * and the it will be returned by map_for_each(); - * + * */ typedef int (* process_each_func )(void * param, str key, void * value); @@ -100,7 +100,7 @@ typedef int (* process_each_func )(void * param, str key, void * value); * * AVLMAP_SHARED -> flag for shared memory * AVLMAP_NO_DUPLICATE -> flag for key duplication - * + * */ map_t map_create ( int flags ); diff --git a/md5utils.c b/md5utils.c index c563ea0004e..441a3d6aa09 100644 --- a/md5utils.c +++ b/md5utils.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -82,7 +82,7 @@ int MD5File(char *dest, const char *file_name) unsigned char buffer[32768]; unsigned char hash[16]; unsigned int counter, size; - + struct stat stats; if (stat(file_name, &stats) != 0) { LM_ERR("could not stat file %s\n", file_name); diff --git a/md5utils.h b/md5utils.h index ba1f300ddc2..6e613fd0dee 100644 --- a/md5utils.h +++ b/md5utils.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2007 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/mem/f_malloc.c b/mem/f_malloc.c index 53257e7bab6..88e38de58ac 100644 --- a/mem/f_malloc.c +++ b/mem/f_malloc.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -23,7 +23,7 @@ * created by andrei * 2003-07-06 added fm_realloc (andrei) * 2004-07-19 fragments book keeping code and support for 64 bits - * memory blocks (64 bits machine & size >=2^32) + * memory blocks (64 bits machine & size >=2^32) * GET_HASH s/ 4Gb mem., switched to long (andrei) * 2005-03-02 added fm_info() (andrei) @@ -115,7 +115,7 @@ static inline void free_plus(struct fm_block* qm, unsigned long size ) inline static unsigned long big_hash_idx(unsigned long s) { unsigned long idx; - /* s is rounded => s = k*2^n (ROUNDTO=2^n) + /* s is rounded => s = k*2^n (ROUNDTO=2^n) * index= i such that 2^i > s >= 2^(i-1) * * => index = number of the first non null bit in s*/ @@ -137,7 +137,7 @@ static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag) { struct fm_frag** f; int hash; - + hash=GET_HASH(frag->size); f=&(qm->free_hash[hash].first); if (frag->size > F_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH, @@ -147,7 +147,7 @@ static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag) if (frag->size <= (*f)->size) break; } } - + /*insert it here*/ frag->prev = f; frag->u.nxt_free=*f; @@ -156,8 +156,8 @@ static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag) *f=frag; qm->free_hash[hash].no++; - free_plus(qm , frag->size); - + + free_plus(qm, frag->size); } static inline void fm_remove_free(struct fm_block* qm, struct fm_frag* n) @@ -179,13 +179,13 @@ static inline void fm_remove_free(struct fm_block* qm, struct fm_frag* n) n->prev = NULL; free_minus(qm , n->size); - + }; /* size should be already rounded-up */ static inline -#ifdef DBG_F_MALLOC +#ifdef DBG_F_MALLOC void fm_split_frag(struct fm_block* qm, struct fm_frag* frag, unsigned long size, const char* file, const char* func, unsigned int line) @@ -219,7 +219,9 @@ void fm_split_frag(struct fm_block* qm, struct fm_frag* frag, #endif */ + #if defined(DBG_F_MALLOC) || defined(STATISTICS) qm->used-=FRAG_OVERHEAD; + #endif #ifdef DBG_F_MALLOC /* frag created by malloc, mark it*/ @@ -244,7 +246,7 @@ struct fm_block* fm_malloc_init(char* address, unsigned long size) char* end; struct fm_block* qm; unsigned long init_overhead; - + /* make address and size multiple of 8*/ start=(char*)ROUNDUP((unsigned long) address); LM_DBG("F_OPTIMIZE=%lu, /ROUNDTO=%lu\n", @@ -259,8 +261,8 @@ struct fm_block* fm_malloc_init(char* address, unsigned long size) size=ROUNDDOWN(size); init_overhead=(ROUNDUP(sizeof(struct fm_block))+ 2 * FRAG_OVERHEAD); - - + + if (size < init_overhead) { /* not enough mem to create our control structures !!!*/ @@ -277,21 +279,21 @@ struct fm_block* fm_malloc_init(char* address, unsigned long size) qm->real_used=size; qm->max_real_used=init_overhead; #endif - + qm->first_frag=(struct fm_frag*)(start+ROUNDUP(sizeof(struct fm_block))); qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag)); /* init initial fragment*/ - qm->first_frag->size=qm->used; + qm->first_frag->size=size-init_overhead; qm->last_frag->size=0; qm->last_frag->prev=NULL; qm->first_frag->prev=NULL; - + #ifdef DBG_F_MALLOC qm->first_frag->check=ST_CHECK_PATTERN; qm->last_frag->check=END_CHECK_PATTERN1; #endif - + /* link initial fragment into the free list*/ qm->large_space = 0; @@ -301,8 +303,8 @@ struct fm_block* fm_malloc_init(char* address, unsigned long size) qm->large_limit = F_MALLOC_DEFRAG_LIMIT; fm_insert_free(qm, qm->first_frag); - - + + return qm; } @@ -317,15 +319,15 @@ void* fm_malloc(struct fm_block* qm, unsigned long size) { struct fm_frag* frag,*n; unsigned int hash; - + #ifdef DBG_F_MALLOC LM_DBG("params (%p, %lu), called from %s: %s(%d)\n", qm, size, file, func, line); #endif - + /*size must be a multiple of 8*/ size=ROUNDUP(size); - + /*search for a suitable free frag*/ for(hash=GET_HASH(size);hashfirst_frag; (char*)frag < (char*)qm->last_frag; ) { @@ -346,26 +348,27 @@ void* fm_malloc(struct fm_block* qm, unsigned long size) { /* detach frag*/ fm_remove_free(qm, frag); - + do { fm_remove_free(qm, n); frag->size += n->size + FRAG_OVERHEAD; #if defined(DBG_F_MALLOC) || defined(STATISTICS) - qm->real_used -= FRAG_OVERHEAD; + //qm->real_used -= FRAG_OVERHEAD; + qm->used += FRAG_OVERHEAD; #endif if( frag->size >size ) goto solved; - + n = FRAG_NEXT(frag); } while ( ((char*)n < (char*)qm->last_frag) && n->prev); fm_insert_free(qm,frag); - + } frag = n; @@ -375,15 +378,15 @@ void* fm_malloc(struct fm_block* qm, unsigned long size) return 0; - + found: /* we found it!*/ - + fm_remove_free(qm,frag); - + /*see if we'll use full frag, or we'll split it in 2*/ - + #ifdef DBG_F_MALLOC fm_split_frag(qm, frag, size, file, func, line); @@ -411,14 +414,14 @@ void* fm_malloc(struct fm_block* qm, unsigned long size) #ifdef DBG_F_MALLOC -void fm_free(struct fm_block* qm, void* p, const char* file, const char* func, +void fm_free(struct fm_block* qm, void* p, const char* file, const char* func, unsigned int line) #else void fm_free(struct fm_block* qm, void* p) #endif { struct fm_frag* f,*n; - + #ifdef DBG_F_MALLOC LM_DBG("params(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line); if (p>(void*)qm->last_frag || p<(void*)qm->first_frag){ @@ -431,7 +434,7 @@ void fm_free(struct fm_block* qm, void* p) return; } f=(struct fm_frag*) ((char*)p-sizeof(struct fm_frag)); - + #ifdef DBG_F_MALLOC LM_DBG("freeing block alloc'ed from %s: %s(%ld)\n", f->file, f->func, f->line); @@ -446,7 +449,7 @@ void fm_free(struct fm_block* qm, void* p) goto no_join; n = FRAG_NEXT(f); - + if (((char*)n < (char*)qm->last_frag) && n->prev ) { @@ -455,7 +458,8 @@ void fm_free(struct fm_block* qm, void* p) f->size += n->size + FRAG_OVERHEAD; #if defined(DBG_F_MALLOC) || defined(STATISTICS) - qm->real_used -= FRAG_OVERHEAD; + //qm->real_used -= FRAG_OVERHEAD; + qm->used += FRAG_OVERHEAD; #endif goto join; @@ -480,8 +484,8 @@ void* fm_realloc(struct fm_block* qm, void* p, unsigned long size) unsigned long orig_size; struct fm_frag *n; void *ptr; - - + + #ifdef DBG_F_MALLOC LM_DBG("params(%p, %p, %lu), called from %s: %s(%d)\n", qm, p, size, file, func, line); @@ -524,14 +528,14 @@ void* fm_realloc(struct fm_block* qm, void* p, unsigned long size) }else if (f->sizesize, size); #endif - + diff=size-f->size; n=FRAG_NEXT(f); - + if (((char*)n < (char*)qm->last_frag) && n->prev && ((n->size+FRAG_OVERHEAD)>=diff)){ @@ -540,7 +544,8 @@ void* fm_realloc(struct fm_block* qm, void* p, unsigned long size) f->size += n->size + FRAG_OVERHEAD; #if defined(DBG_F_MALLOC) || defined(STATISTICS) - qm->real_used -= FRAG_OVERHEAD; + //qm->real_used -= FRAG_OVERHEAD; + qm->used += FRAG_OVERHEAD; #endif /* split it if necessary */ @@ -643,7 +648,7 @@ void fm_info(struct fm_block* qm, struct mem_info* info) #if !defined(DBG_F_MALLOC) && !defined(STATISTICS) struct fm_frag* f; #endif - + memset(info,0, sizeof(*info)); total_frags=0; info->total_size=qm->size; diff --git a/mem/f_malloc.h b/mem/f_malloc.h index 398105ff6de..7a919fe1ec3 100644 --- a/mem/f_malloc.h +++ b/mem/f_malloc.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -30,7 +30,7 @@ */ -#if !defined(f_malloc_h) && !defined(VQ_MALLOC) +#if !defined(f_malloc_h) && !defined(VQ_MALLOC) #define f_malloc_h #ifdef DBG_QM_MALLOC @@ -102,10 +102,10 @@ struct fm_block{ unsigned long real_used; /* used+malloc overhead*/ unsigned long max_real_used; #endif - + struct fm_frag* first_frag; struct fm_frag* last_frag; - + struct fm_frag_lnk free_hash[F_HASH_SIZE]; }; @@ -121,14 +121,14 @@ void* fm_malloc(struct fm_block*, unsigned long size); #endif #ifdef DBG_F_MALLOC -void fm_free(struct fm_block*, void* p, const char* file, const char* func, +void fm_free(struct fm_block*, void* p, const char* file, const char* func, unsigned int line); #else void fm_free(struct fm_block*, void* p); #endif #ifdef DBG_F_MALLOC -void* fm_realloc(struct fm_block*, void* p, unsigned long size, +void* fm_realloc(struct fm_block*, void* p, unsigned long size, const char* file, const char* func, unsigned int line); #else void* fm_realloc(struct fm_block*, void* p, unsigned long size); diff --git a/mem/hp_malloc.c b/mem/hp_malloc.c new file mode 100644 index 00000000000..4256b9b4a20 --- /dev/null +++ b/mem/hp_malloc.c @@ -0,0 +1,1091 @@ +/** + * the truly parallel memory allocator + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-01-19 initial version (liviu) + */ + +#if !defined(q_malloc) && !(defined VQ_MALLOC) && !(defined F_MALLOC) && \ + (defined HP_MALLOC) + +#include +#include +#include + +#include "sys/time.h" + +#include "../dprint.h" +#include "../globals.h" +#include "../statistics.h" +#include "../locking.h" + +#include "hp_malloc.h" + +extern unsigned long *mem_hash_usage; + +#if defined(HP_MALLOC) && !defined(HP_MALLOC_FAST_STATS) +stat_var *shm_used; +stat_var *shm_rused; +stat_var *shm_frags; +#endif + +/* ROUNDTO= 2^k so the following works */ +#define ROUNDTO_MASK (~((unsigned long)ROUNDTO-1)) +#define ROUNDUP(s) (((s)+(ROUNDTO-1))&ROUNDTO_MASK) +#define ROUNDDOWN(s) ((s)&ROUNDTO_MASK) + +#define SHM_LOCK(i) lock_get(&mem_lock[i]) +#define SHM_UNLOCK(i) lock_release(&mem_lock[i]) + +#define MEM_FRAG_AVOIDANCE + +#define HP_MALLOC_LARGE_LIMIT HP_MALLOC_OPTIMIZE +#define HP_MALLOC_DEFRAG_LIMIT (HP_MALLOC_LARGE_LIMIT * 5) +#define HP_MALLOC_DEFRAG_PERCENT 5 + +#define can_split_frag(frag, wanted_size) \ + ((frag)->size - wanted_size > (FRAG_OVERHEAD + MIN_FRAG_SIZE)) + +/* + * the *_split functions try to split a fragment in an attempt + * to minimize memory usage + */ +#define pkg_frag_split(blk, frag, sz) \ + do { \ + if (can_split_frag(frag, sz)) { \ + __pkg_frag_split(blk, frag, sz); \ + update_stats_pkg_frag_split(blk); \ + } \ + } while (0) + +#define shm_frag_split_unsafe(blk, frag, sz) \ + do { \ + if (can_split_frag(frag, sz)) { \ + __shm_frag_split_unsafe(blk, frag, sz); \ + if (stats_are_ready()) { \ + update_stats_shm_frag_split(); \ + } else { \ + (blk)->real_used += FRAG_OVERHEAD; \ + (blk)->total_fragments++; \ + } \ + } \ + } while (0) + +/* Note: the shm lock on "hash" must be acquired when this is called */ +#define shm_frag_split(blk, frag, sz, hash) \ + do { \ + if (can_split_frag(frag, sz)) { \ + __shm_frag_split(blk, frag, sz, hash); \ + update_stats_shm_frag_split(); \ + } \ + } while (0) + +/* computes hash number for big buckets */ +inline static unsigned long big_hash_idx(unsigned long s) +{ + unsigned long idx; + + /* s is rounded => s = k*2^n (ROUNDTO=2^n) + * index= i such that 2^i > s >= 2^(i-1) + * + * => index = number of the first non null bit in s*/ + idx = 8 * sizeof(long) - 1; + + for (; !(s & (1UL << (8 * sizeof(long) - 1))); s <<= 1, idx--) + ; + + return idx; +} + +static inline void hp_frag_attach(struct hp_block *qm, struct hp_frag *frag) +{ + struct hp_frag **f; + unsigned int hash; + + hash = GET_HASH_RR(qm, frag->size); + f = &(qm->free_hash[hash].first); + + if (frag->size > HP_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH, + purpose --andrei ) */ + for(; *f; f=&((*f)->u.nxt_free)){ + if (frag->size <= (*f)->size) break; + } + } + + /*insert it here*/ + frag->prev = f; + frag->u.nxt_free=*f; + if (*f) + (*f)->prev = &(frag->u.nxt_free); + + *f = frag; + +#ifdef HP_MALLOC_FAST_STATS + qm->free_hash[hash].no++; +#endif +} + +static inline void hp_frag_detach(struct hp_block *qm, struct hp_frag *frag) +{ + struct hp_frag **pf; + + pf = frag->prev; + + /* detach */ + *pf = frag->u.nxt_free; + + if (frag->u.nxt_free) + frag->u.nxt_free->prev = pf; + + frag->prev = NULL; + +#ifdef HP_MALLOC_FAST_STATS + unsigned int hash; + + hash = GET_HASH_RR(qm, frag->size); + qm->free_hash[hash].no--; +#endif +}; + +void __pkg_frag_split(struct hp_block *qm, struct hp_frag *frag, + unsigned long size) +{ + unsigned long rest; + struct hp_frag *n; + + rest = frag->size - size; + frag->size = size; + + /* split the fragment */ + n = FRAG_NEXT(frag); + n->size = rest - FRAG_OVERHEAD; + + hp_frag_attach(qm, n); + update_stats_pkg_frag_attach(qm, n); +} + +void __shm_frag_split_unsafe(struct hp_block *qm, struct hp_frag *frag, + unsigned long size) +{ + unsigned long rest; + struct hp_frag *n; + +#ifdef HP_MALLOC_FAST_STATS + qm->free_hash[PEEK_HASH_RR(qm, frag->size)].total_no--; + qm->free_hash[PEEK_HASH_RR(qm, size)].total_no++; +#endif + + rest = frag->size - size; + frag->size = size; + + /* split the fragment */ + n = FRAG_NEXT(frag); + n->size = rest - FRAG_OVERHEAD; + +#ifdef HP_MALLOC_FAST_STATS + qm->free_hash[PEEK_HASH_RR(qm, n->size)].total_no++; +#endif + + hp_frag_attach(qm, n); + + if (stats_are_ready()) + update_stats_shm_frag_attach(n); + else { + qm->used -= n->size; + qm->real_used -= n->size; + } +} + + /* size should already be rounded-up */ +void __shm_frag_split(struct hp_block *qm, struct hp_frag *frag, + unsigned long size, unsigned int old_hash) +{ + unsigned long rest, hash; + struct hp_frag *n; + +#ifdef HP_MALLOC_FAST_STATS + qm->free_hash[PEEK_HASH_RR(qm, frag->size)].total_no--; + qm->free_hash[PEEK_HASH_RR(qm, size)].total_no++; +#endif + + rest = frag->size - size; + frag->size = size; + + /* split the fragment */ + n = FRAG_NEXT(frag); + n->size = rest - FRAG_OVERHEAD; + + /* insert the newly obtained hp_frag in its free list */ + hash = PEEK_HASH_RR(qm, n->size); + + if (hash != old_hash) + SHM_LOCK(hash); + + hp_frag_attach(qm, n); + +#ifdef HP_MALLOC_FAST_STATS + qm->free_hash[hash].total_no++; +#endif + + if (hash != old_hash) + SHM_UNLOCK(hash); +} + +/** + * dumps the current memory allocation pattern of OpenSIPS into a pattern file + */ +void hp_update_mem_pattern_file(void) +{ + int i; + FILE *f; + unsigned long long sum = 0; + double verification = 0; + + if (!mem_warming_enabled) + return; + + f = fopen(mem_warming_pattern_file, "w+"); + if (!f) { + LM_ERR("failed to open pattern file %s for writing: %d - %s\n", + mem_warming_pattern_file, errno, strerror(errno)); + return; + } + + if (fprintf(f, "%lu %lu\n", ROUNDTO, HP_HASH_SIZE) < 0) + goto write_error; + + /* first compute sum of all malloc requests since startup */ + for (i = 0; i < HP_MALLOC_OPTIMIZE / ROUNDTO; i++) + sum += mem_hash_usage[i] * (i * ROUNDTO + FRAG_OVERHEAD); + + LM_DBG("mem warming hash sum: %llu\n", sum); + + /* save the usage rate of each bucket to the memory pattern file */ + for (i = 0; i < HP_MALLOC_OPTIMIZE / ROUNDTO; i++) { + LM_DBG("[%d] %lf %.8lf\n", i, (double)mem_hash_usage[i], + (double)mem_hash_usage[i] / sum * (i * ROUNDTO + FRAG_OVERHEAD)); + + verification += (double)mem_hash_usage[i] / + sum * (i * ROUNDTO + FRAG_OVERHEAD); + + if (fprintf(f, "%.12lf ", + (double)mem_hash_usage[i] / sum * (i * ROUNDTO + FRAG_OVERHEAD)) < 0) + goto write_error; + + if (i % 10 == 9) + fprintf(f, "\n"); + } + + if (verification < 0.99 || verification > 1.01) + LM_INFO("memory pattern file appears to be incorrect: %lf\n", verification); + + LM_INFO("updated memory pattern file %s\n", mem_warming_pattern_file); + + fclose(f); + return; + +write_error: + LM_ERR("failed to update pattern file %s\n", mem_warming_pattern_file); + fclose(f); +} + +/** + * on-demand memory fragmentation, based on an input pattern file + */ +int hp_mem_warming(struct hp_block *qm) +{ + struct size_fraction { + int hash_index; + + double amount; + unsigned long fragments; + + struct size_fraction *next; + }; + + struct size_fraction *sf, *it, *sorted_sf = NULL; + FILE *f; + size_t rc; + unsigned long roundto, hash_size; + long long bucket_mem; + int i, c = 0; + unsigned int current_frag_size; + struct hp_frag *big_frag; + unsigned int optimized_buckets; + + f = fopen(mem_warming_pattern_file, "r"); + if (!f) { + LM_ERR("failed to open pattern file %s: %d - %s\n", + mem_warming_pattern_file, errno, strerror(errno)); + return -1; + } + + rc = fscanf(f, "%lu %lu\n", &roundto, &hash_size); + if (rc != 2) { + LM_ERR("failed to read from %s: bad file format\n", + mem_warming_pattern_file); + goto out; + } + rc = 0; + + if (roundto != ROUNDTO || hash_size != HP_HASH_SIZE) { + LM_ERR("incompatible pattern file data: [HP_HASH_SIZE: %lu-%lu] " + "[ROUNDTO: %lu-%lu]\n", hash_size, HP_HASH_SIZE, roundto, ROUNDTO); + rc = -1; + goto out; + } + + /* read bucket usage percentages and sort them by number of fragments */ + for (i = 0; i < HP_LINEAR_HASH_SIZE; i++) { + + sf = malloc(sizeof *sf); + if (!sf) { + LM_INFO("malloc failed, skipping shm warming\n"); + rc = -1; + goto out_free; + } + + sf->hash_index = i; + sf->next = NULL; + + if (fscanf(f, "%lf", &sf->amount) != 1) { + LM_CRIT("%s appears to be corrupt. Please remove it first\n", + mem_warming_pattern_file); + abort(); + } + + if (i == 0) + sf->fragments = 0; + else + sf->fragments = sf->amount * qm->size / (ROUNDTO * i); + + if (!sorted_sf) + sorted_sf = sf; + else { + for (it = sorted_sf; + it->next && it->next->fragments > sf->fragments; + it = it->next) + ; + + if (it->fragments < sf->fragments) { + sf->next = sorted_sf; + sorted_sf = sf; + } else { + sf->next = it->next; + it->next = sf; + } + } + } + + /* only optimize the configured number of buckets */ + optimized_buckets = (float)shm_hash_split_percentage / 100 * HP_LINEAR_HASH_SIZE; + + LM_INFO("Optimizing %u / %lu mem buckets\n", optimized_buckets, + HP_LINEAR_HASH_SIZE); + + sf = sorted_sf; + for (i = 0; i < optimized_buckets; i++) { + qm->free_hash[sf->hash_index].is_optimized = 1; + sf = sf->next; + } + + big_frag = qm->first_frag; + + /* populate each free hash bucket with proper number of fragments */ + for (sf = sorted_sf; sf; sf = sf->next) { + LM_INFO("[%d][%s] fraction: %.12lf total mem: %llu, %lu\n", sf->hash_index, + qm->free_hash[sf->hash_index].is_optimized ? "X" : " ", + sf->amount, (unsigned long long) (sf->amount * + qm->size * mem_warming_percentage / 100), + ROUNDTO * sf->hash_index); + + current_frag_size = ROUNDTO * sf->hash_index; + bucket_mem = sf->amount * qm->size * mem_warming_percentage / 100; + + /* create free fragments worth of 'bucket_mem' memory */ + while (bucket_mem >= FRAG_OVERHEAD + current_frag_size) { + hp_frag_detach(qm, big_frag); + if (stats_are_ready()) + update_stats_shm_frag_detach(big_frag); + else { + qm->used += big_frag->size; + qm->real_used += big_frag->size + FRAG_OVERHEAD; + } + + /* trim-insert operation on the big free fragment */ + shm_frag_split_unsafe(qm, big_frag, current_frag_size); + + /* + * "big_frag" now points to a smaller, free and detached frag. + * + * With optimized buckets, inserts will be automagically + * balanced within their dedicated hashes + */ + hp_frag_attach(qm, big_frag); + if (stats_are_ready()) + update_stats_shm_frag_attach(big_frag); + else { + qm->used -= big_frag->size; + qm->real_used -= big_frag->size + FRAG_OVERHEAD; + } + + big_frag = FRAG_NEXT(big_frag); + + bucket_mem -= FRAG_OVERHEAD + current_frag_size; + + if (c % 1000000 == 0) + LM_INFO("%d| %lld %p\n", c, bucket_mem, big_frag); + + c++; + } + } + +out_free: + while (sorted_sf) { + sf = sorted_sf; + sorted_sf = sorted_sf->next; + free(sf); + } + +out: + fclose(f); + return rc; +} + +/* initialise the allocator and return its main block */ +static struct hp_block *hp_malloc_init(char *address, unsigned long size) +{ + char *start; + char *end; + struct hp_block *qm; + unsigned long init_overhead; + + /* make address and size multiple of 8*/ + start = (char *)ROUNDUP((unsigned long) address); + LM_DBG("HP_OPTIMIZE=%lu, HP_LINEAR_HASH_SIZE=%lu\n", + HP_MALLOC_OPTIMIZE, HP_LINEAR_HASH_SIZE); + LM_DBG("HP_HASH_SIZE=%lu, HP_EXTRA_HASH_SIZE=%lu, hp_block size=%zu\n", + HP_HASH_SIZE, HP_EXTRA_HASH_SIZE, sizeof(struct hp_block)); + LM_DBG("params (%p, %lu), start=%p\n", address, size, start); + + if (size < (unsigned long)(start - address)) + return NULL; + + size -= start - address; + + if (size < (MIN_FRAG_SIZE+FRAG_OVERHEAD)) + return NULL; + + size = ROUNDDOWN(size); + + init_overhead = (ROUNDUP(sizeof(struct hp_block)) + 2 * FRAG_OVERHEAD); + + if (size < init_overhead) + { + LM_ERR("not enough memory for the basic structures! " + "need %lu bytes\n", init_overhead); + /* not enough mem to create our control structures !!!*/ + return NULL; + } + + end = start + size; + qm = (struct hp_block *)start; + memset(qm, 0, sizeof(struct hp_block)); + qm->size = size; + + qm->used = 0; + qm->real_used = init_overhead; + qm->max_real_used = init_overhead; + gettimeofday(&qm->last_updated, NULL); + + qm->first_frag = (struct hp_frag *)(start + ROUNDUP(sizeof(struct hp_block))); + qm->last_frag = (struct hp_frag *)(end - sizeof(struct hp_frag)); + /* init initial fragment*/ + qm->first_frag->size = size - init_overhead; + qm->last_frag->size = 0; + + qm->last_frag->prev = NULL; + qm->first_frag->prev = NULL; + + /* link initial fragment into the free list*/ + + qm->large_space = 0; + qm->large_limit = qm->size / 100 * HP_MALLOC_DEFRAG_PERCENT; + + if (qm->large_limit < HP_MALLOC_DEFRAG_LIMIT) + qm->large_limit = HP_MALLOC_DEFRAG_LIMIT; + + return qm; +} + +struct hp_block *hp_pkg_malloc_init(char *address, unsigned long size) +{ + struct hp_block *hpb; + + hpb = hp_malloc_init(address, size); + if (!hpb) { + LM_ERR("failed to initialize shm block\n"); + return NULL; + } + + hp_frag_attach(hpb, hpb->first_frag); + + /* first fragment attach is the equivalent of a split */ + update_stats_pkg_frag_split(hpb, hpb->first_frag); + + return hpb; +} + +struct hp_block *hp_shm_malloc_init(char *address, unsigned long size) +{ + struct hp_block *hpb; + + hpb = hp_malloc_init(address, size); + if (!hpb) { + LM_ERR("failed to initialize shm block\n"); + return NULL; + } + +#ifdef HP_MALLOC_FAST_STATS + hpb->free_hash[PEEK_HASH_RR(hpb, hpb->first_frag->size)].total_no++; +#endif + + hp_frag_attach(hpb, hpb->first_frag); + + /* first fragment attach is the equivalent of a split */ + if (stats_are_ready()) + update_stats_shm_frag_split(hpb, hpb->first_frag); + else { + hpb->real_used += FRAG_OVERHEAD; + hpb->total_fragments++; + } + + /* if memory warming is on, pre-populate the hash with free fragments */ + if (mem_warming_enabled) { + if (hp_mem_warming(hpb) != 0) + LM_INFO("skipped memory warming\n"); + } + + hp_stats_lock = hp_shm_malloc_unsafe(hpb, sizeof *hp_stats_lock); + if (!hp_stats_lock) { + LM_ERR("failed to alloc hp statistics lock\n"); + return NULL; + } + + if (!lock_init(hp_stats_lock)) { + LM_CRIT("could not initialize hp statistics lock\n"); + return NULL; + } + + return hpb; +} + + +void *hp_pkg_malloc(struct hp_block *qm, unsigned long size) +{ + struct hp_frag *frag; + unsigned int hash; + + /* size must be a multiple of ROUNDTO */ + size = ROUNDUP(size); + + /* search for a suitable free frag */ + for (hash = GET_HASH(size); hash < HP_HASH_SIZE; hash++) { + frag = qm->free_hash[hash].first; + + for (; frag; frag = frag->u.nxt_free) + if (frag->size >= size) + goto found; + + /* try in a bigger bucket */ + } + + /* out of memory... we have to shut down */ + LM_CRIT("not enough memory, please increase the \"-M\" parameter!\n"); + abort(); + +found: + hp_frag_detach(qm, frag); + update_stats_pkg_frag_detach(qm, frag); + + /* split the fragment if possible */ + pkg_frag_split(qm, frag, size); + + if (qm->real_used > qm->max_real_used) + qm->max_real_used = qm->real_used; + + pkg_threshold_check(); + + return (char *)frag + sizeof *frag; +} + +/* + * although there is a lot of duplicate code, we get the best performance: + * + * - the _unsafe version will not be used too much anyway (usually at startup) + * - hp_shm_malloc is faster (no 3rd parameter, no extra if blocks) + */ +void *hp_shm_malloc_unsafe(struct hp_block *qm, unsigned long size) +{ + struct hp_frag *frag; + unsigned int init_hash, hash, sec_hash; + int i; + + /* size must be a multiple of ROUNDTO */ + size = ROUNDUP(size); + + /*search for a suitable free frag*/ + + for (hash = GET_HASH(size), init_hash = hash; hash < HP_HASH_SIZE; hash++) { + if (!qm->free_hash[hash].is_optimized) { + frag = qm->free_hash[hash].first; + + for (; frag; frag = frag->u.nxt_free) + if (frag->size >= size) + goto found; + + } else { + /* optimized size. search through its own hash! */ + for (i = 0, sec_hash = HP_HASH_SIZE + + hash * shm_secondary_hash_size + + optimized_get_indexes[hash]; + i < shm_secondary_hash_size; + i++, sec_hash = (sec_hash + 1) % shm_secondary_hash_size) { + + frag = qm->free_hash[sec_hash].first; + for (; frag; frag = frag->u.nxt_free) + if (frag->size >= size) { + /* free fragments are detached in a simple round-robin manner */ + optimized_get_indexes[hash] = + (optimized_get_indexes[hash] + i + 1) + % shm_secondary_hash_size; + hash = sec_hash; + goto found; + } + } + } + + /* try in a bigger bucket */ + } + + /* out of memory... we have to shut down */ + LM_CRIT("not enough shared memory, please increase the \"-m\" parameter!\n"); + abort(); + +found: + hp_frag_detach(qm, frag); + if (stats_are_ready()) + update_stats_shm_frag_detach(frag); + else { + qm->used += frag->size; + qm->real_used += frag->size + FRAG_OVERHEAD; + } + + /* split the fragment if possible */ + shm_frag_split_unsafe(qm, frag, size); + +#ifndef HP_MALLOC_FAST_STATS + if (stats_are_ready()) { + unsigned long real_used; + + real_used = get_stat_val(shm_rused); + if (real_used > qm->max_real_used) + qm->max_real_used = real_used; + } else + if (qm->real_used > qm->max_real_used) + qm->max_real_used = qm->real_used; +#endif + + if (mem_hash_usage) + mem_hash_usage[init_hash]++; + + return (char *)frag + sizeof *frag; +} + +/* + * Note: as opposed to hp_shm_malloc_unsafe(), + * hp_shm_malloc() assumes that the core statistics are initialized + */ +void *hp_shm_malloc(struct hp_block *qm, unsigned long size) +{ + struct hp_frag *frag; + unsigned int init_hash, hash, sec_hash; + int i; + + /* size must be a multiple of ROUNDTO */ + size = ROUNDUP(size); + + /*search for a suitable free frag*/ + + for (hash = GET_HASH(size), init_hash = hash; hash < HP_HASH_SIZE; hash++) { + if (!qm->free_hash[hash].is_optimized) { + SHM_LOCK(hash); + frag = qm->free_hash[hash].first; + + for (; frag; frag = frag->u.nxt_free) + if (frag->size >= size) + goto found; + + SHM_UNLOCK(hash); + } else { + /* optimized size. search through its own hash! */ + for (i = 0, sec_hash = HP_HASH_SIZE + + hash * shm_secondary_hash_size + + optimized_get_indexes[hash]; + i < shm_secondary_hash_size; + i++, sec_hash = (sec_hash + 1) % shm_secondary_hash_size) { + + SHM_LOCK(sec_hash); + frag = qm->free_hash[sec_hash].first; + for (; frag; frag = frag->u.nxt_free) + if (frag->size >= size) { + /* free fragments are detached in a simple round-robin manner */ + optimized_get_indexes[hash] = + (optimized_get_indexes[hash] + i + 1) + % shm_secondary_hash_size; + hash = sec_hash; + goto found; + } + + SHM_UNLOCK(sec_hash); + } + } + + /* try in a bigger bucket */ + } + + /* out of memory... we have to shut down */ + LM_CRIT("not enough shared memory, please increase the \"-m\" parameter!\n"); + abort(); + +found: + hp_frag_detach(qm, frag); + + /* split the fragment if possible */ + shm_frag_split(qm, frag, size, hash); + + SHM_UNLOCK(hash); + + update_stats_shm_frag_detach(frag); + +#ifndef HP_MALLOC_FAST_STATS + unsigned long real_used; + + real_used = get_stat_val(shm_rused); + if (real_used > qm->max_real_used) + qm->max_real_used = real_used; +#endif + + /* ignore concurrency issues, simply obtaining an estimate is enough */ + mem_hash_usage[init_hash]++; + + return (char *)frag + sizeof *frag; +} + +void hp_pkg_free(struct hp_block *qm, void *p) +{ + struct hp_frag *f, *next; + + if (!p) { + LM_WARN("free(0) called\n"); + return; + } + + f = FRAG_OF(p); + + /* + * for private memory, coalesce as many consecutive fragments as possible + * The same operation is not performed for shared memory, because: + * - performance penalties introduced by additional locking logic + * - the allocator itself actually favours fragmentation and reusage + */ + for (;;) { + next = FRAG_NEXT(f); + if (next >= qm->last_frag || !next->prev) + break; + + hp_frag_detach(qm, next); + update_stats_pkg_frag_detach(qm, next); + + f->size += next->size + FRAG_OVERHEAD; + update_stats_pkg_frag_merge(qm); + } + + hp_frag_attach(qm, f); + update_stats_pkg_frag_attach(qm, f); +} + +void hp_shm_free_unsafe(struct hp_block *qm, void *p) +{ + struct hp_frag *f; + + if (!p) { + LM_WARN("free(0) called\n"); + return; + } + + f = FRAG_OF(p); + + hp_frag_attach(qm, f); + update_stats_shm_frag_attach(f); +} + +void hp_shm_free(struct hp_block *qm, void *p) +{ + struct hp_frag *f; + unsigned int hash; + + if (!p) { + LM_WARN("free(0) called\n"); + return; + } + + f = FRAG_OF(p); + hash = PEEK_HASH_RR(qm, f->size); + + SHM_LOCK(hash); + hp_frag_attach(qm, f); + SHM_UNLOCK(hash); + + update_stats_shm_frag_attach(f); +} + + +void *hp_pkg_realloc(struct hp_block *qm, void *p, unsigned long size) +{ + struct hp_frag *f; + unsigned long diff; + unsigned long orig_size; + struct hp_frag *next; + void *ptr; + + if (size == 0) { + if (p) + hp_pkg_free(qm, p); + + return NULL; + } + + if (!p) + return hp_pkg_malloc(qm, size); + + f = FRAG_OF(p); + + size = ROUNDUP(size); + orig_size = f->size; + + /* shrink operation */ + if (orig_size > size) { + pkg_frag_split(qm, f, size); + + /* grow operation */ + } else if (orig_size < size) { + + diff = size - orig_size; + next = FRAG_NEXT(f); + + /* try to join with a large enough adjacent free fragment */ + if (next < qm->last_frag && next->prev && + (next->size + FRAG_OVERHEAD) >= diff) { + + hp_frag_detach(qm, next); + update_stats_pkg_frag_detach(qm, next); + + f->size += next->size + FRAG_OVERHEAD; + + /* split the result if necessary */ + if (f->size > size) + pkg_frag_split(qm, f, size); + + } else { + /* could not join => realloc */ + ptr = hp_pkg_malloc(qm, size); + if (ptr) { + /* copy, need by libssl */ + memcpy(ptr, p, orig_size); + hp_pkg_free(qm, p); + } + p = ptr; + } + + if (qm->real_used > qm->max_real_used) + qm->max_real_used = qm->real_used; + } + + pkg_threshold_check(); + return p; +} + +void *hp_shm_realloc_unsafe(struct hp_block *qm, void *p, unsigned long size) +{ + struct hp_frag *f; + unsigned long orig_size; + void *ptr; + + if (size == 0) { + if (p) + hp_shm_free_unsafe(qm, p); + + return NULL; + } + + if (!p) + return hp_shm_malloc_unsafe(qm, size); + + f = FRAG_OF(p); + size = ROUNDUP(size); + + orig_size = f->size; + + /* shrink operation? */ + if (orig_size > size) + shm_frag_split_unsafe(qm, f, size); + else if (orig_size < size) { + ptr = hp_shm_malloc_unsafe(qm, size); + if (ptr) { + /* copy, need by libssl */ + memcpy(ptr, p, orig_size); + hp_shm_free_unsafe(qm, p); + } + + p = ptr; + } + + return p; +} + +void *hp_shm_realloc(struct hp_block *qm, void *p, unsigned long size) +{ + struct hp_frag *f; + unsigned long orig_size; + unsigned int hash; + void *ptr; + + if (size == 0) { + if (p) + hp_shm_free(qm, p); + + return NULL; + } + + if (!p) + return hp_shm_malloc(qm, size); + + f = FRAG_OF(p); + size = ROUNDUP(size); + + hash = PEEK_HASH_RR(qm, f->size); + + SHM_LOCK(hash); + orig_size = f->size; + + if (orig_size > size) { + /* shrink */ + shm_frag_split_unsafe(qm, f, size); + + } else if (orig_size < size) { + SHM_UNLOCK(hash); + + ptr = hp_shm_malloc(qm, size); + if (ptr) { + /* copy, need by libssl */ + memcpy(ptr, p, orig_size); + hp_shm_free(qm, p); + } + + return ptr; + } + + SHM_UNLOCK(hash); + return p; +} + + + +void hp_status(struct hp_block *qm) +{ + struct hp_frag* f; + unsigned int i,j; + unsigned int h; + int unused; + unsigned long size; + + LM_GEN1(memdump, "hp_status (%p):\n", qm); + if (!qm) return; + + LM_GEN1(memdump, " heap size= %ld\n", qm->size); + +#ifdef STATISTICS + LM_GEN1(memdump, " used= %lu, used+overhead=%lu, free=%lu\n", + qm->used, qm->real_used, qm->size-qm->used); + LM_GEN1(memdump, " max used (+overhead)= %lu\n", qm->max_real_used); +#endif + + LM_GEN1(memdump, "dumping free list:\n"); + for(h=0,i=0,size=0;hfree_hash[h].first,j=0; f; + size+=f->size,f=f->u.nxt_free,i++,j++){ } + if (j) LM_GEN1(memdump,"hash = %3d fragments no.: %5d, unused: %5d\n\t\t" + " bucket size: %9lu - %9lu (first %9lu)\n", + h, j, unused, UN_HASH(h), + ((h<=HP_MALLOC_OPTIMIZE/ROUNDTO)?1:2)* UN_HASH(h), + qm->free_hash[h].first->size + ); + if (j!=qm->free_hash[h].no){ + LM_CRIT("different free frag. count: %d!=%ld" + " for hash %3d\n", j, qm->free_hash[h].no, h); + } + + } + LM_GEN1(memdump, "TOTAL: %6d free fragments = %6lu free bytes\n", i, size); + LM_GEN1(memdump, "TOTAL: %ld large bytes\n", qm->large_space ); + LM_GEN1(memdump, "TOTAL: %u overhead\n", (unsigned int)FRAG_OVERHEAD ); + LM_GEN1(memdump, "-----------------------------\n"); +} + + + +/* fills a malloc info structure with info about the memory block */ +void hp_info(struct hp_block *qm, struct mem_info *info) +{ + memset(info, 0, sizeof *info); + + info->total_size = qm->size; + info->min_frag = MIN_FRAG_SIZE; + +#ifdef HP_MALLOC_FAST_STATS + if (stats_are_expired(qm)) + update_shm_stats(qm); +#endif + + info->used = qm->used; + info->real_used = qm->real_used; + info->free = qm->size - qm->real_used; + info->total_frags = qm->total_fragments; + + LM_DBG("mem_info: (sz: %ld | us: %ld | rus: %ld | free: %ld | frags: %ld)\n", + info->total_size, info->used, info->real_used, info->free, + info->total_frags); +} + +#endif diff --git a/mem/hp_malloc.h b/mem/hp_malloc.h new file mode 100644 index 00000000000..7f939013486 --- /dev/null +++ b/mem/hp_malloc.h @@ -0,0 +1,213 @@ +/** + * the truly parallel memory allocator + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-01-19 initial version (liviu) + */ + +#if !defined(HP_MALLOC_H) && !defined(f_malloc_h) && !defined(VQ_MALLOC) +#define HP_MALLOC_H + +#include "../statistics.h" +#include "../config.h" +#include "../globals.h" + +struct hp_frag; +struct hp_frag_lnk; +struct hp_block; + +#ifndef HP_MALLOC_FAST_STATS +extern stat_var *shm_used; +extern stat_var *shm_rused; +extern stat_var *shm_frags; +#endif + +#include "hp_malloc_stats.h" +#include "meminfo.h" + +#define ROUNDTO 8UL +#define MIN_FRAG_SIZE ROUNDTO + +#define FRAG_NEXT(f) ((struct hp_frag *) \ + ((char *)(f) + sizeof(struct hp_frag) + ((struct hp_frag *)(f))->size)) + +/* get the fragment which corresponds to a pointer */ +#define FRAG_OF(p) \ + ((struct hp_frag *)((char *)(p) - sizeof(struct hp_frag))) + +#define FRAG_OVERHEAD (sizeof(struct hp_frag)) + +#define HP_MALLOC_OPTIMIZE_FACTOR 14UL /*used below */ +#define HP_MALLOC_OPTIMIZE (1UL << HP_MALLOC_OPTIMIZE_FACTOR) + /* size to optimize for, + (most allocs <= this size), + must be 2^k */ + +#define HP_LINEAR_HASH_SIZE (HP_MALLOC_OPTIMIZE/ROUNDTO) +#define HP_EXPONENTIAL_HASH_SIZE ((sizeof(long)*8-HP_MALLOC_OPTIMIZE_FACTOR)+1) + +#define HP_HASH_SIZE (HP_LINEAR_HASH_SIZE + HP_EXPONENTIAL_HASH_SIZE) +#define HP_EXTRA_HASH_SIZE (HP_LINEAR_HASH_SIZE * SHM_MAX_SECONDARY_HASH_SIZE) + +#define HP_TOTAL_HASH_SIZE (HP_HASH_SIZE + HP_EXTRA_HASH_SIZE) + +/* hash structure: + * 0 .... HP_MALLOC_OPTIMIZE/ROUNDTO - small buckets, size increases with + * ROUNDTO from bucket to bucket + * +1 .... end - size = 2^k, big buckets + * (0 0 0 0 0 ... 0) (ROUNDTO ROUNDTO ...) (2*ROUNDTO...) .... (...) - additional array of hashes! + * | | | | | | | | | + * | | | | | | | | | + * | | | | | | | | | + * | | | | | | | | | + * v v v v v v v v v + * + * ^------- sshs ----------^ ^------ sshs -------^ ^--- sshs ---^ ^---^ + * + * sshs = "shm_secondary_hash_size" script parameter + */ + +/* used when detaching free fragments */ +unsigned int optimized_get_indexes[HP_HASH_SIZE]; + +/* used when attaching free fragments */ +unsigned int optimized_put_indexes[HP_HASH_SIZE]; + +/* finds the hash value for s, s=ROUNDTO multiple */ +#define GET_HASH(s) (((unsigned long)(s) <= HP_MALLOC_OPTIMIZE) ? \ + (unsigned long)(s) / ROUNDTO : \ + HP_LINEAR_HASH_SIZE + big_hash_idx((s)) - HP_MALLOC_OPTIMIZE_FACTOR + 1) + +/* + * - for heavily used sizes (which need some optimizing) it returns + * a hash entry for the given size in a round-robin manner + * - for the non-optimized sizes, behaviour is identical to GET_HASH + */ +#define GET_HASH_RR(fmb, s) (((unsigned long)(s) <= HP_MALLOC_OPTIMIZE) ? \ + ({ \ + unsigned int ___hash, ___idx, ___ret; \ + ___hash = (unsigned long)(s) / ROUNDTO; \ + !fmb->free_hash[___hash].is_optimized ? \ + ___hash : \ + ({ \ + ___idx = optimized_put_indexes[___hash]; \ + ___ret = HP_HASH_SIZE + \ + ___hash * shm_secondary_hash_size + ___idx; \ + optimized_put_indexes[___hash] = \ + (___idx + 1) % shm_secondary_hash_size; \ + ___ret; \ + }); \ + }) : \ + HP_LINEAR_HASH_SIZE + big_hash_idx((s)) - HP_MALLOC_OPTIMIZE_FACTOR + 1) + +/* + * peek at the next round-robin assigned hash + * + * unlike GET_HASH_RR, it always returns the same result + */ +#define PEEK_HASH_RR(fmb, s) (((unsigned long)(s) <= HP_MALLOC_OPTIMIZE) ? \ + ({ \ + unsigned int ___hash; \ + ___hash = (unsigned long)(s) / ROUNDTO; \ + !fmb->free_hash[___hash].is_optimized ? \ + ___hash : \ + HP_HASH_SIZE + ___hash * shm_secondary_hash_size + \ + optimized_put_indexes[___hash]; \ + }) : \ + HP_LINEAR_HASH_SIZE + big_hash_idx((s)) - HP_MALLOC_OPTIMIZE_FACTOR + 1) + +#define UN_HASH(h) (((unsigned long)(h) <= (HP_MALLOC_OPTIMIZE/ROUNDTO)) ?\ + (unsigned long)(h)*ROUNDTO: \ + 1UL<<((unsigned long)(h)-HP_MALLOC_OPTIMIZE/ROUNDTO+\ + HP_MALLOC_OPTIMIZE_FACTOR - 1)\ + ) + +struct hp_frag { + unsigned long size; + union { + struct hp_frag *nxt_free; + long reserved; + } u; + struct hp_frag **prev; +}; + +struct hp_frag_lnk { + /* + * optimized buckets are further split into + * "shm_secondary_hash_size" buckets + */ + char is_optimized; + + struct hp_frag *first; + + /* + * no - current number of free fragments in this bucket + * total_no - (no + allocated) free fragments in this bucket + */ + long no; + long total_no; +}; + +struct hp_block { + unsigned long size; /* total size */ + unsigned long large_space; + unsigned long large_limit; + + unsigned long used; /* alloc'ed size */ + unsigned long real_used; /* used+malloc overhead */ + unsigned long max_real_used; + unsigned long total_fragments; + + struct timeval last_updated; + + struct hp_frag *first_frag; + struct hp_frag *last_frag; + + /* + * the extra hash further divides the heavily used buckets + * in order to achieve an even finer-grained locking + */ + struct hp_frag_lnk free_hash[HP_HASH_SIZE + HP_EXTRA_HASH_SIZE]; +}; + +struct hp_block *hp_pkg_malloc_init(char *addr, unsigned long size); +struct hp_block *hp_shm_malloc_init(char *addr, unsigned long size); + +int hp_mem_warming(struct hp_block *); +void hp_update_mem_pattern_file(void); + +void *hp_shm_malloc(struct hp_block *, unsigned long size); +void *hp_shm_malloc_unsafe(struct hp_block *, unsigned long size); +void *hp_pkg_malloc(struct hp_block *, unsigned long size); + +void hp_shm_free(struct hp_block *, void *p); +void hp_shm_free_unsafe(struct hp_block *qm, void *p); +void hp_pkg_free(struct hp_block *, void *p); + +void *hp_shm_realloc(struct hp_block *, void *p, unsigned long size); +void *hp_shm_realloc_unsafe(struct hp_block *qm, void *p, unsigned long size); +void *hp_pkg_realloc(struct hp_block *, void *p, unsigned long size); + +void hp_status(struct hp_block *); +void hp_info(struct hp_block *, struct mem_info *); + +#endif /* HP_MALLOC_H */ diff --git a/mem/hp_malloc_stats.c b/mem/hp_malloc_stats.c new file mode 100644 index 00000000000..ce2ae1f8962 --- /dev/null +++ b/mem/hp_malloc_stats.c @@ -0,0 +1,228 @@ +/** + * the truly parallel memory allocator + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-01-19 initial version (liviu) + */ + +#if !defined(q_malloc) && !(defined VQ_MALLOC) && !(defined F_MALLOC) && \ + (defined HP_MALLOC) + +#include +#include +#include + +#include "sys/time.h" + +#include "../lock_ops.h" +#include "hp_malloc.h" +#include "hp_malloc_stats.h" + +gen_lock_t *hp_stats_lock; + +#ifdef STATISTICS + +int stats_are_expired(struct hp_block *qm) +{ + struct timeval now; + + gettimeofday(&now, NULL); + + return (now.tv_sec * 1000000L + now.tv_usec) - + (qm->last_updated.tv_sec * 1000000L + qm->last_updated.tv_usec) + + > SHM_STATS_SAMPLING_PERIOD; +} + +void update_shm_stats(struct hp_block *qm) +{ + struct hp_frag_lnk *bucket, *it; + int i, j, used_mem; + unsigned long in_use_frags; + long size = 0; + + lock_get(hp_stats_lock); + + qm->used = qm->real_used = qm->total_fragments = 0; + + for (i = 0, bucket = qm->free_hash; + bucket < &qm->free_hash[HP_HASH_SIZE]; + i++, bucket++) { + + size = UN_HASH(i); + + if (!bucket->is_optimized) { + in_use_frags = bucket->total_no - bucket->no; + used_mem = in_use_frags * size; + + qm->used += used_mem; + qm->real_used += used_mem + bucket->total_no * FRAG_OVERHEAD; + qm->total_fragments += bucket->total_no; + } else { + for (j = 0, it = &qm->free_hash[HP_HASH_SIZE + i * shm_secondary_hash_size]; + j < shm_secondary_hash_size; + j++, it++) { + + in_use_frags = it->total_no - it->no; + used_mem = in_use_frags * size; + + qm->used += used_mem; + qm->real_used += used_mem + it->total_no * FRAG_OVERHEAD; + qm->total_fragments += it->total_no; + } + } + } + + if (qm->real_used > qm->max_real_used) + qm->max_real_used = qm->real_used; + + LM_DBG("updated shm statistics: [ us: %ld | rus: %ld | frags: %ld ]\n", + qm->used, qm->real_used, qm->total_fragments); + + gettimeofday(&qm->last_updated, NULL); + + lock_release(hp_stats_lock); +} + +unsigned long hp_shm_get_size(struct hp_block *qm) +{ + return qm->size; +} + +#ifdef HP_MALLOC_FAST_STATS +unsigned long hp_shm_get_used(struct hp_block *qm) +{ + if (stats_are_expired(qm)) + update_shm_stats(qm); + + return qm->used; +} + +unsigned long hp_shm_get_real_used(struct hp_block *qm) +{ + if (stats_are_expired(qm)) + update_shm_stats(qm); + + return qm->real_used; +} + +unsigned long hp_shm_get_max_real_used(struct hp_block *qm) +{ + if (stats_are_expired(qm)) + update_shm_stats(qm); + + return qm->max_real_used; +} + +unsigned long hp_shm_get_free(struct hp_block *qm) +{ + if (stats_are_expired(qm)) + update_shm_stats(qm); + + return qm->size - qm->real_used; +} + +unsigned long hp_shm_get_frags(struct hp_block *qm) +{ + if (stats_are_expired(qm)) + update_shm_stats(qm); + + return qm->total_fragments; +} + +void hp_init_shm_statistics(struct hp_block *qm) +{ + update_shm_stats(qm); +} + +#else /* HP_MALLOC_FAST_STATS */ + +void hp_init_shm_statistics(struct hp_block *qm) +{ + update_stat(shm_used, qm->used); + update_stat(shm_rused, qm->real_used); + update_stat(shm_frags, qm->total_fragments); + + LM_DBG("initializing atomic shm statistics: " + "[ us: %ld | rus: %ld | frags: %ld ]\n", qm->used, qm->real_used, qm->total_fragments); +} + +unsigned long hp_shm_get_used(struct hp_block *qm) +{ + return get_stat_val(shm_used); +} + +unsigned long hp_shm_get_real_used(struct hp_block *qm) +{ + return get_stat_val(shm_rused); +} + +unsigned long hp_shm_get_max_real_used(struct hp_block *qm) +{ + return qm->max_real_used; +} + +unsigned long hp_shm_get_free(struct hp_block *qm) +{ + return qm->size - get_stat_val(shm_rused); +} + +unsigned long hp_shm_get_frags(struct hp_block *qm) +{ + return get_stat_val(shm_frags); +} +#endif /* HP_MALLOC_FAST_STATS */ + + +unsigned long hp_pkg_get_size(struct hp_block *qm) +{ + return qm->size; +} + +unsigned long hp_pkg_get_used(struct hp_block *qm) +{ + return qm->used; +} + +unsigned long hp_pkg_get_real_used(struct hp_block *qm) +{ + return qm->real_used; +} + +unsigned long hp_pkg_get_max_real_used(struct hp_block *qm) +{ + return qm->max_real_used; +} + +unsigned long hp_pkg_get_free(struct hp_block *qm) +{ + return qm->size - qm->real_used; +} + +unsigned long hp_pkg_get_frags(struct hp_block *qm) +{ + return qm->total_fragments; +} + +#endif /* STATISTICS */ + +#endif diff --git a/mem/hp_malloc_stats.h b/mem/hp_malloc_stats.h new file mode 100644 index 00000000000..778c8c9dc56 --- /dev/null +++ b/mem/hp_malloc_stats.h @@ -0,0 +1,119 @@ +/** + * the truly parallel memory allocator + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-01-19 initial version (liviu) + */ + +#ifndef HP_MALLOC_STATS_H +#define HP_MALLOC_STATS_H + +#include "../lock_ops.h" + +/* specified in microseconds */ +#define SHM_STATS_SAMPLING_PERIOD 200000L + +extern gen_lock_t *hp_stats_lock; + +#ifdef STATISTICS +int stats_are_expired(struct hp_block *qm); +void update_shm_stats(struct hp_block *qm); +void hp_init_shm_statistics(struct hp_block *qm); + +unsigned long hp_shm_get_size(struct hp_block *qm); +unsigned long hp_shm_get_used(struct hp_block *qm); +unsigned long hp_shm_get_free(struct hp_block *qm); +unsigned long hp_shm_get_real_used(struct hp_block *qm); +unsigned long hp_shm_get_max_real_used(struct hp_block *qm); +unsigned long hp_shm_get_frags(struct hp_block *qm); + +unsigned long hp_pkg_get_size(struct hp_block *qm); +unsigned long hp_pkg_get_used(struct hp_block *qm); +unsigned long hp_pkg_get_free(struct hp_block *qm); +unsigned long hp_pkg_get_real_used(struct hp_block *qm); +unsigned long hp_pkg_get_max_real_used(struct hp_block *qm); +unsigned long hp_pkg_get_frags(struct hp_block *qm); + +#define update_stats_pkg_frag_attach(blk, frag) \ + do { \ + (blk)->used -= (frag)->size; \ + (blk)->real_used -= (frag)->size + FRAG_OVERHEAD; \ + } while (0) + +#define update_stats_pkg_frag_detach(blk, frag) \ + do { \ + (blk)->used += (frag)->size; \ + (blk)->real_used += (frag)->size + FRAG_OVERHEAD; \ + } while (0) + +#define update_stats_pkg_frag_split(blk, ...) \ + do { \ + (blk)->real_used += FRAG_OVERHEAD; \ + (blk)->total_fragments++; \ + } while (0) + +#define update_stats_pkg_frag_merge(blk, ...) \ + do { \ + (blk)->real_used -= FRAG_OVERHEAD; \ + (blk)->total_fragments--; \ + } while (0) + +#ifdef HP_MALLOC_FAST_STATS + #define update_stats_shm_frag_attach(frag) + #define update_stats_shm_frag_detach(frag) + #define update_stats_shm_frag_split() + +#else /* HP_MALLOC_FAST_STATS */ + #define update_stats_shm_frag_attach(frag) \ + do { \ + update_stat(shm_used, -(frag)->size); \ + update_stat(shm_rused, -((frag)->size + FRAG_OVERHEAD)); \ + } while (0) + + #define update_stats_shm_frag_detach(frag) \ + do { \ + update_stat(shm_used, (frag)->size); \ + update_stat(shm_rused, (frag)->size + FRAG_OVERHEAD); \ + } while (0) + + #define update_stats_shm_frag_split(...) \ + do { \ + update_stat(shm_rused, FRAG_OVERHEAD); \ + update_stat(shm_frags, 1); \ + } while (0) +#endif /* HP_MALLOC_FAST_STATS */ + +#else /* STATISTICS */ + #define stats_are_expired(...) 0 + #define update_shm_stats(...) + + #define hp_init_shm_statistics(...) + #define update_stats_pkg_frag_attach(blk, frag) + #define update_stats_pkg_frag_detach(blk, frag) + #define update_stats_pkg_frag_split(blk, ...) + #define update_stats_pkg_frag_merge(blk, ...) + #define update_stats_shm_frag_attach(frag) + #define update_stats_shm_frag_detach(frag) + #define update_stats_shm_frag_split(...) +#endif + +#endif /* HP_MALLOC_STATS_H */ diff --git a/mem/mem.c b/mem/mem.c index 995686db8ed..3b90dac8006 100644 --- a/mem/mem.c +++ b/mem/mem.c @@ -15,15 +15,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * History: * -------- * 2003-04-08 init_mallocs split into init_{pkg,shm}_malloc (andrei) - * + * */ @@ -52,6 +52,8 @@ struct vqm_block* mem_block; #elif defined F_MALLOC struct fm_block* mem_block; + #elif defined HP_MALLOC + struct hp_block* mem_block; #else struct qm_block* mem_block; #endif @@ -72,12 +74,14 @@ int init_pkg_mallocs(void) mem_block=vqm_malloc_init(mem_pool, pkg_mem_size); #elif F_MALLOC mem_block=fm_malloc_init(mem_pool, pkg_mem_size); + #elif HP_MALLOC + mem_block=hp_pkg_malloc_init(mem_pool, pkg_mem_size); #else mem_block=qm_malloc_init(mem_pool, pkg_mem_size); #endif if (mem_block==0){ LM_CRIT("could not initialize memory pool\n"); - fprintf(stderr, "Too much pkg memory demanded: %ld\n", + fprintf(stderr, "Given PKG mem size is not enough: %ld\n", pkg_mem_size ); return -1; } diff --git a/mem/mem.h b/mem/mem.h index 9b261dbae1d..1ce5a7e5f32 100644 --- a/mem/mem.h +++ b/mem/mem.h @@ -16,15 +16,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-03-10 __FUNCTION__ is a gcc-ism, defined it to "" for sun cc * (andrei) - * 2003-03-07 split init_malloc into init_pkg_mallocs & init_shm_mallocs + * 2003-03-07 split init_malloc into init_pkg_mallocs & init_shm_mallocs * (andrei) */ @@ -53,6 +53,9 @@ # elif defined F_MALLOC # include "f_malloc.h" extern struct fm_block* mem_block; +# elif defined HP_MALLOC +# include "hp_malloc.h" + extern struct hp_block* mem_block; # else # include "q_malloc.h" extern struct qm_block* mem_block; @@ -113,6 +116,11 @@ void set_pkg_stats(pkg_status_holder*); # define pkg_realloc(p, s) fm_realloc(mem_block, (p), (s)) # define pkg_free(p) fm_free(mem_block, (p)) # define pkg_info(i) fm_info(mem_block,i) +# elif defined HP_MALLOC +# define pkg_malloc(s) hp_pkg_malloc(mem_block, (s)) +# define pkg_realloc(p, s) hp_pkg_realloc(mem_block, (p), (s)) +# define pkg_free(p) hp_pkg_free(mem_block, (p)) +# define pkg_info(i) hp_info(mem_block,i) # else # define pkg_malloc(s) qm_malloc(mem_block, (s)) # define pkg_realloc(p, s) qm_realloc(mem_block, (p), (s)) @@ -130,6 +138,14 @@ void set_pkg_stats(pkg_status_holder*); # define MY_PKG_GET_MUSED() fm_get_max_real_used(mem_block) # define MY_PKG_GET_FREE() fm_get_free(mem_block) # define MY_PKG_GET_FRAGS() fm_get_frags(mem_block) +# elif defined HP_MALLOC +# define pkg_status() hp_status(mem_block) +# define MY_PKG_GET_SIZE() hp_pkg_get_size(mem_block) +# define MY_PKG_GET_USED() hp_pkg_get_used(mem_block) +# define MY_PKG_GET_RUSED() hp_pkg_get_real_used(mem_block) +# define MY_PKG_GET_MUSED() hp_pkg_get_max_real_used(mem_block) +# define MY_PKG_GET_FREE() hp_pkg_get_free(mem_block) +# define MY_PKG_GET_FRAGS() hp_pkg_get_frags(mem_block) # else # define pkg_status() qm_status(mem_block) # define MY_PKG_GET_SIZE() qm_get_size(mem_block) diff --git a/mem/meminfo.h b/mem/meminfo.h index dd73ba82c08..dd6e6416614 100644 --- a/mem/meminfo.h +++ b/mem/meminfo.h @@ -1,6 +1,6 @@ /* $Id$* * - * mem (malloc) info + * mem (malloc) info * * Copyright (C) 2001-2003 FhG Fokus * @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -41,7 +41,7 @@ struct mem_info{ unsigned long total_frags; /* total fragment no */ }; -#ifdef STATISTICS +#if defined(PKG_MALLOC) && defined(STATISTICS) // threshold percentage checked extern long event_pkg_threshold; // events are used only if STATISTICS are used diff --git a/mem/memtest.c b/mem/memtest.c index af4236cab1f..44a06fcc05f 100644 --- a/mem/memtest.c +++ b/mem/memtest.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -66,11 +66,7 @@ void memtest() char *p[TEST_RUN]; int t; -#ifdef CHANGEABLE_DEBUG_LEVEL - *debug=7; -#else - debug=7; -#endif + set_global_debug_level(7); log_stderr=1; printf("entering test\n"); @@ -116,7 +112,7 @@ void memtest() mf(p2); mf(p5); mf(p6); - + // MY_STATUS(mem_block); mf(p1); @@ -158,7 +154,7 @@ void memtest() printf("now I'm really done\n"); MY_STATUS(mem_block); printf("And I'm done with dumping final report too\n"); - + exit(0); } #endif diff --git a/mem/q_malloc.c b/mem/q_malloc.c index 2052878c436..034f43ac865 100644 --- a/mem/q_malloc.c +++ b/mem/q_malloc.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -35,7 +35,7 @@ */ -#if !defined(q_malloc) && !(defined VQ_MALLOC) && !(defined F_MALLOC) +#if !defined(q_malloc) && !(defined VQ_MALLOC) && !(defined F_MALLOC) && !defined(HP_MALLOC) #define q_malloc #include @@ -55,7 +55,7 @@ #define FRAG_NEXT(f) \ ((struct qm_frag*)((char*)(f)+sizeof(struct qm_frag)+(f)->size+ \ sizeof(struct qm_frag_end))) - + #define FRAG_PREV(f) \ ( (struct qm_frag*) ( ((char*)(f)-sizeof(struct qm_frag_end))- \ ((struct qm_frag_end*)((char*)(f)-sizeof(struct qm_frag_end)))->size- \ @@ -98,7 +98,7 @@ #define FRAG_WAS_USED(f) (1) /* other frag related defines: - * MEM_COALESCE_FRAGS + * MEM_COALESCE_FRAGS * MEM_FRAG_AVOIDANCE */ @@ -110,7 +110,7 @@ inline static unsigned long big_hash_idx(unsigned long s) { int idx; - /* s is rounded => s = k*2^n (ROUNDTO=2^n) + /* s is rounded => s = k*2^n (ROUNDTO=2^n) * index= i such that 2^i > s >= 2^(i-1) * * => index = number of the first non null bit in s*/ @@ -121,9 +121,17 @@ inline static unsigned long big_hash_idx(unsigned long s) #ifdef DBG_QM_MALLOC + +#ifdef __CPU_x86_64 +#define ST_CHECK_PATTERN 0xf0f0f0f0f0f0f0f0 +#define END_CHECK_PATTERN1 0xc0c0c0c0c0c0c0c0 +#define END_CHECK_PATTERN2 0xabcdefedabcdefed +#else +#warning "assuming sizeof(long) = 4" #define ST_CHECK_PATTERN 0xf0f0f0f0 #define END_CHECK_PATTERN1 0xc0c0c0c0 #define END_CHECK_PATTERN2 0xabcdefed +#endif static void qm_debug_frag(struct qm_block* qm, struct qm_frag* f) @@ -140,7 +148,7 @@ static void qm_debug_frag(struct qm_block* qm, struct qm_frag* f) (FRAG_END(f)->check2!=END_CHECK_PATTERN2)){ LM_CRIT("qm_*: fragm. %p (address %p)" " end overwritten(%lx, %lx)!\n", - f, (char*)f+sizeof(struct qm_frag), + f, (char*)f+sizeof(struct qm_frag), FRAG_END(f)->check1, FRAG_END(f)->check2); qm_status(qm); abort(); @@ -148,9 +156,10 @@ static void qm_debug_frag(struct qm_block* qm, struct qm_frag* f) if ((f>qm->first_frag)&& ((PREV_FRAG_END(f)->check1!=END_CHECK_PATTERN1) || (PREV_FRAG_END(f)->check2!=END_CHECK_PATTERN2) ) ){ - LM_CRIT(" qm_*: prev. fragm. tail overwritten(%lx, %lx)[%p:%p]!\n", + LM_CRIT(" qm_*: prev. fragm. tail overwritten(%lx, %lx)[%p:%p] (%s, %s:%ld)!\n", PREV_FRAG_END(f)->check1, PREV_FRAG_END(f)->check2, f, - (char*)f+sizeof(struct qm_frag)); + (char*)f+sizeof(struct qm_frag), FRAG_PREV(f)->func, + FRAG_PREV(f)->file,FRAG_PREV(f)->line); qm_status(qm); abort(); } @@ -164,7 +173,7 @@ static inline void qm_insert_free(struct qm_block* qm, struct qm_frag* frag) struct qm_frag* f; struct qm_frag* prev; int hash; - + hash=GET_HASH(frag->size); for(f=qm->free_hash[hash].head.u.nxt_free; f!=&(qm->free_hash[hash].head); f=f->u.nxt_free){ @@ -177,6 +186,9 @@ static inline void qm_insert_free(struct qm_block* qm, struct qm_frag* frag) frag->u.nxt_free=f; FRAG_END(f)->prev_free=frag; qm->free_hash[hash].no++; + + qm->real_used-=frag->size; + qm->used-=frag->size; } @@ -189,7 +201,7 @@ struct qm_block* qm_malloc_init(char* address, unsigned long size) struct qm_block* qm; unsigned long init_overhead; int h; - + /* make address and size multiple of 8*/ start=(char*)ROUNDUP((unsigned long) address); LM_DBG("QM_OPTIMIZE=%lu, /ROUNDTO=%lu\n", @@ -201,11 +213,11 @@ struct qm_block* qm_malloc_init(char* address, unsigned long size) size-=(start-address); if (size <(MIN_FRAG_SIZE+FRAG_OVERHEAD)) return 0; size=ROUNDDOWN(size); - + init_overhead=ROUNDUP(sizeof(struct qm_block))+sizeof(struct qm_frag)+ sizeof(struct qm_frag_end); LM_DBG("size= %lu, init_overhead=%lu\n", size, init_overhead); - + if (size < init_overhead) { /* not enough mem to create our control structures !!!*/ @@ -215,16 +227,17 @@ struct qm_block* qm_malloc_init(char* address, unsigned long size) qm=(struct qm_block*)start; memset(qm, 0, sizeof(struct qm_block)); qm->size=size; - qm->real_used=init_overhead; - qm->max_real_used=qm->real_used; + qm->used=size-init_overhead; + qm->real_used=size; + qm->max_real_used = 0; size-=init_overhead; - + qm->first_frag=(struct qm_frag*)(start+ROUNDUP(sizeof(struct qm_block))); qm->last_frag_end=(struct qm_frag_end*)(end-sizeof(struct qm_frag_end)); /* init initial fragment*/ qm->first_frag->size=size; qm->last_frag_end->size=size; - + #ifdef DBG_QM_MALLOC qm->first_frag->check=ST_CHECK_PATTERN; qm->last_frag_end->check1=END_CHECK_PATTERN1; @@ -237,16 +250,15 @@ struct qm_block* qm_malloc_init(char* address, unsigned long size) qm->free_hash[h].head.size=0; qm->free_hash[h].tail.size=0; } - + /* link initial fragment into the free list*/ - + qm_insert_free(qm, qm->first_frag); - + /*qm->first_frag->u.nxt_free=&(qm->free_lst); qm->last_frag_end->prev_free=&(qm->free_lst); */ - - + return qm; } @@ -256,23 +268,25 @@ static inline void qm_detach_free(struct qm_block* qm, struct qm_frag* frag) { struct qm_frag *prev; struct qm_frag *next; - + prev=FRAG_END(frag)->prev_free; next=frag->u.nxt_free; prev->u.nxt_free=next; FRAG_END(next)->prev_free=prev; - + + qm->real_used+=frag->size; + qm->used+=frag->size; } #ifdef DBG_QM_MALLOC -static inline struct qm_frag* qm_find_free(struct qm_block* qm, +static inline struct qm_frag* qm_find_free(struct qm_block* qm, unsigned long size, int *h, unsigned int *count) #else -static inline struct qm_frag* qm_find_free(struct qm_block* qm, +static inline struct qm_frag* qm_find_free(struct qm_block* qm, unsigned long size, int* h) #endif @@ -281,7 +295,7 @@ static inline struct qm_frag* qm_find_free(struct qm_block* qm, struct qm_frag* f; for (hash=GET_HASH(size); hashfree_hash[hash].head.u.nxt_free; + for (f=qm->free_hash[hash].head.u.nxt_free; f!=&(qm->free_hash[hash].head); f=f->u.nxt_free){ #ifdef DBG_QM_MALLOC *count+=1; /* *count++ generates a warning with gcc 2.9* -Wall */ @@ -308,7 +322,7 @@ int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned long new_size) unsigned long rest; struct qm_frag* n; struct qm_frag_end* end; - + rest=f->size-new_size; #ifdef MEM_FRAG_AVOIDANCE if ((rest> (FRAG_OVERHEAD+QM_MALLOC_OPTIMIZE))|| @@ -324,7 +338,7 @@ int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned long new_size) n->size=rest-FRAG_OVERHEAD; FRAG_END(n)->size=n->size; FRAG_CLEAR_USED(n); /* never used */ - qm->real_used+=FRAG_OVERHEAD; + qm->used-=FRAG_OVERHEAD; #ifdef DBG_QM_MALLOC end->check1=END_CHECK_PATTERN1; end->check2=END_CHECK_PATTERN2; @@ -354,7 +368,7 @@ void* qm_malloc(struct qm_block* qm, unsigned long size) { struct qm_frag* f; int hash; - + #ifdef DBG_QM_MALLOC unsigned int list_cntr; @@ -390,8 +404,6 @@ void* qm_malloc(struct qm_block* qm, unsigned long size) #else split_frag(qm, f, size); #endif - qm->real_used+=f->size; - qm->used+=f->size; if (qm->max_real_usedreal_used) qm->max_real_used=qm->real_used; #ifdef DBG_QM_MALLOC @@ -415,17 +427,15 @@ void* qm_malloc(struct qm_block* qm, unsigned long size) #ifdef DBG_QM_MALLOC -void qm_free(struct qm_block* qm, void* p, const char* file, const char* func, +void qm_free(struct qm_block* qm, void* p, const char* file, const char* func, unsigned int line) #else void qm_free(struct qm_block* qm, void* p) #endif { struct qm_frag* f; -#ifdef QM_JOIN_FREE struct qm_frag* prev; struct qm_frag* next; -#endif unsigned long size; #ifdef DBG_QM_MALLOC @@ -452,11 +462,8 @@ void qm_free(struct qm_block* qm, void* p) LM_GEN1( memlog, "freeing frag. %p alloc'ed from %s: %s(%ld)\n", f, f->file, f->func, f->line); #endif - size=f->size; - qm->used-=size; - qm->real_used-=size; -#ifdef QM_JOIN_FREE + size=f->size; /* join packets if possible*/ prev=next=0; next=FRAG_NEXT(f); @@ -467,10 +474,10 @@ void qm_free(struct qm_block* qm, void* p) #endif qm_detach_free(qm, next); size+=next->size+FRAG_OVERHEAD; - qm->real_used-=FRAG_OVERHEAD; + qm->used+=FRAG_OVERHEAD; qm->free_hash[GET_HASH(next->size)].no--; /* FIXME slow */ } - + if (f > qm->first_frag){ prev=FRAG_PREV(f); /* (struct qm_frag*)((char*)f - (struct qm_frag_end*)((char*)f- @@ -482,14 +489,13 @@ void qm_free(struct qm_block* qm, void* p) /*join*/ qm_detach_free(qm, prev); size+=prev->size+FRAG_OVERHEAD; - qm->real_used-=FRAG_OVERHEAD; + qm->used+=FRAG_OVERHEAD; qm->free_hash[GET_HASH(prev->size)].no--; /* FIXME slow */ f=prev; } } f->size=size; FRAG_END(f)->size=f->size; -#endif /* QM_JOIN_FREE*/ #ifdef DBG_QM_MALLOC f->file=file; f->func=func; @@ -513,8 +519,8 @@ void* qm_realloc(struct qm_block* qm, void* p, unsigned long size) unsigned long orig_size; struct qm_frag* n; void* ptr; - - + + #ifdef DBG_QM_MALLOC LM_GEN1( memlog, "params (%p, %p, %lu), called from %s: %s(%d)\n", qm, p, size, file, func, line); @@ -523,7 +529,7 @@ void* qm_realloc(struct qm_block* qm, void* p, unsigned long size) abort(); } #endif - + if (size==0) { if (p) #ifdef DBG_QM_MALLOC @@ -560,14 +566,11 @@ void* qm_realloc(struct qm_block* qm, void* p, unsigned long size) LM_GEN1(memlog,"shrinking from %lu to %lu\n", f->size, size); if(split_frag(qm, f, size, file, "fragm. from qm_realloc", line)!=0){ LM_GEN1(memlog,"shrinked successful\n"); + } #else - if(split_frag(qm, f, size)!=0){ + split_frag(qm, f, size); #endif - /* update used sizes: freed the spitted frag */ - qm->real_used-=(orig_size-f->size-FRAG_OVERHEAD); - qm->used-=(orig_size-f->size); - } - + }else if (f->size < size){ /* grow */ #ifdef DBG_QM_MALLOC @@ -576,13 +579,13 @@ void* qm_realloc(struct qm_block* qm, void* p, unsigned long size) orig_size=f->size; diff=size-f->size; n=FRAG_NEXT(f); - if (((char*)n < (char*)qm->last_frag_end) && + if (((char*)n < (char*)qm->last_frag_end) && (n->u.is_free)&&((n->size+FRAG_OVERHEAD)>=diff)){ /* join */ qm_detach_free(qm, n); qm->free_hash[GET_HASH(n->size)].no--; /*FIXME: slow*/ f->size+=n->size+FRAG_OVERHEAD; - qm->real_used-=FRAG_OVERHEAD; + qm->used+=FRAG_OVERHEAD; FRAG_END(f)->size=f->size; /* end checks should be ok */ /* split it if necessary */ @@ -594,8 +597,6 @@ void* qm_realloc(struct qm_block* qm, void* p, unsigned long size) split_frag(qm, f, size); #endif } - qm->real_used+=(f->size-orig_size); - qm->used+=(f->size-orig_size); }else{ /* could not join => realloc */ #ifdef DBG_QM_MALLOC @@ -644,13 +645,13 @@ void qm_status(struct qm_block* qm) LM_GEN1(memdump, " used= %lu, used+overhead=%lu, free=%lu\n", qm->used, qm->real_used, qm->size-qm->real_used); LM_GEN1(memdump, " max used (+overhead)= %lu\n", qm->max_real_used); - + LM_GEN1(memdump, "dumping all alloc'ed. fragments:\n"); for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;f=FRAG_NEXT(f) ,i++){ if (! f->u.is_free){ LM_GEN1(memdump," %3d. %c address=%p frag=%p size=%lu used=%d\n", - i, + i, (f->u.is_free)?'a':'N', (char*)f+sizeof(struct qm_frag), f, f->size, FRAG_WAS_USED(f)); #ifdef DBG_QM_MALLOC @@ -664,7 +665,7 @@ void qm_status(struct qm_block* qm) LM_GEN1(memdump, "dumping free list stats :\n"); for(h=0,i=0;hfree_hash[h].head.u.nxt_free,j=0; + for (f=qm->free_hash[h].head.u.nxt_free,j=0; f!=&(qm->free_hash[h].head); f=f->u.nxt_free, i++, j++){ if (!FRAG_WAS_USED(f)){ unused++; @@ -699,7 +700,7 @@ void qm_info(struct qm_block* qm, struct mem_info* info) { int r; long total_frags; - + total_frags=0; memset(info,0, sizeof(*info)); info->total_size=qm->size; @@ -714,6 +715,21 @@ void qm_info(struct qm_block* qm, struct mem_info* info) info->total_frags=total_frags; } +int qm_mem_check(struct qm_block *qm) +{ + struct qm_frag *f; + int i = 0; + + for (f = qm->first_frag; (char *)f < (char *)qm->last_frag_end; + f = FRAG_NEXT(f), i++) { + + qm_debug_frag(qm, f); + } + + LM_DBG("fragments: %d\n", i); + + return i; +} #endif diff --git a/mem/q_malloc.h b/mem/q_malloc.h index 7b5d8de2fce..b8633c7f9d0 100644 --- a/mem/q_malloc.h +++ b/mem/q_malloc.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -30,7 +30,7 @@ */ -#if !defined(q_malloc_h) && !defined(VQ_MALLOC) && !defined(F_MALLOC) +#if !defined(q_malloc_h) && !defined(VQ_MALLOC) && !defined(F_MALLOC) && !defined(HP_MALLOC) #define q_malloc_h #include "meminfo.h" @@ -43,9 +43,9 @@ * aligned memory */ #define ROUNDTO sizeof(long long) #else - #define ROUNDTO sizeof(void*) /* minimum possible ROUNDTO ->heavy + #define ROUNDTO sizeof(void*) /* minimum possible ROUNDTO ->heavy debugging*/ -#endif +#endif #else /* DBG_QM_MALLOC */ #define ROUNDTO 16UL /* size we round to, must be = 2^n and also sizeof(qm_frag)+sizeof(qm_frag_end) @@ -109,10 +109,10 @@ struct qm_block{ unsigned long used; /* alloc'ed size*/ unsigned long real_used; /* used+malloc overhead*/ unsigned long max_real_used; - + struct qm_frag* first_frag; struct qm_frag_end* last_frag_end; - + struct qm_frag_lnk free_hash[QM_HASH_SIZE]; /*struct qm_frag_end free_lst_end;*/ }; @@ -129,7 +129,7 @@ void* qm_malloc(struct qm_block*, unsigned long size); #endif #ifdef DBG_QM_MALLOC -void qm_free(struct qm_block*, void* p, const char* file, const char* func, +void qm_free(struct qm_block*, void* p, const char* file, const char* func, unsigned int line); #else void qm_free(struct qm_block*, void* p); @@ -144,6 +144,12 @@ void* qm_realloc(struct qm_block*, void* p, unsigned long size); void qm_status(struct qm_block*); void qm_info(struct qm_block*, struct mem_info*); +/* + * On success, returns the currrent number of fragments + * Internally aborts on failure + */ +int qm_mem_check(struct qm_block *qm); + #ifdef STATISTICS static inline unsigned long qm_get_size(struct qm_block* qm) diff --git a/mem/shm_mem.c b/mem/shm_mem.c index ae16d06e422..dc57a149f55 100644 --- a/mem/shm_mem.c +++ b/mem/shm_mem.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -50,12 +50,25 @@ #ifdef STATISTICS stat_export_t shm_stats[] = { - {"total_size" , STAT_IS_FUNC, (stat_var**)shm_get_size }, - {"used_size" , STAT_IS_FUNC, (stat_var**)shm_get_used }, - {"real_used_size" , STAT_IS_FUNC, (stat_var**)shm_get_rused }, - {"max_used_size" , STAT_IS_FUNC, (stat_var**)shm_get_mused }, - {"free_size" , STAT_IS_FUNC, (stat_var**)shm_get_free }, - {"fragments" , STAT_IS_FUNC, (stat_var**)shm_get_frags }, + {"total_size" , STAT_IS_FUNC, (stat_var**)shm_get_size }, + +#if defined(HP_MALLOC) && !defined(HP_MALLOC_FAST_STATS) + {"used_size" , 0, &shm_used }, + {"real_used_size" , 0, &shm_rused }, +#else + {"used_size" , STAT_IS_FUNC, (stat_var**)shm_get_used }, + {"real_used_size" , STAT_IS_FUNC, (stat_var**)shm_get_rused }, +#endif + + {"max_used_size" , STAT_IS_FUNC, (stat_var**)shm_get_mused }, + {"free_size" , STAT_IS_FUNC, (stat_var**)shm_get_free }, + +#if defined(HP_MALLOC) && !defined(HP_MALLOC_FAST_STATS) + {"fragments" , 0, &shm_frags }, +#else + {"fragments" , STAT_IS_FUNC, (stat_var**)shm_get_frags }, +#endif + {0,0,0} }; #endif @@ -65,17 +78,27 @@ stat_export_t shm_stats[] = { static int shm_shmid=-1; /*shared memory id*/ #endif -gen_lock_t* mem_lock=0; +gen_lock_t *mem_lock = NULL; static void* shm_mempool=(void*)-1; #ifdef VQ_MALLOC struct vqm_block* shm_block; #elif F_MALLOC struct fm_block* shm_block; +#elif HP_MALLOC + struct hp_block* shm_block; #else struct qm_block* shm_block; #endif +/* + * - the memory fragmentation pattern of OpenSIPS + * - holds the total number of shm_mallocs requested for each + * different possible size since daemon startup + * - allows memory warming (preserving the fragmentation pattern on restarts) + */ +unsigned long long *mem_hash_usage; + #ifdef STATISTICS #include "../evi/evi_core.h" @@ -127,11 +150,22 @@ void shm_event_raise(long used, long size, long perc) * event has to be raised without the lock otherwise a deadlock will be * generated by the transport modules, or by the event_route processing */ +#ifdef HP_MALLOC + shm_unlock(0); +#else shm_unlock(); +#endif + if (evi_raise_event(EVI_SHM_THRESHOLD_ID, list)) { LM_ERR("unable to send shm threshold event\n"); } + +#ifdef HP_MALLOC + shm_lock(0); +#else shm_lock(); +#endif + list = 0; end: if (list) @@ -145,11 +179,22 @@ void shm_event_raise(long used, long size, long perc) inline static void* sh_realloc(void* p, unsigned int size) { void *r; + +#ifndef HP_MALLOC shm_lock(); shm_free_unsafe(p); - r=shm_malloc_unsafe(size); + r = shm_malloc_unsafe(size); +#else + shm_free(p); + r = shm_malloc(size); +#endif + shm_threshold_check(); - shm_unlock(); + +#ifndef HP_MALLOC + shm_unlock(); +#endif + return r; } @@ -179,7 +224,7 @@ void* _shm_resize( void* p , unsigned int s) # ifdef DBG_QM_MALLOC # ifdef VQ_MALLOC f=(struct vqm_frag*) ((char*)p-sizeof(struct vqm_frag)); - LM_DBG("params (%p, %d), called from %s: %s(%d)\n", + LM_DBG("params (%p, %d), called from %s: %s(%d)\n", p, s, file, func, line); VQM_DEBUG_FRAG(shm_block, f); if (p>(void *)shm_block->core_end || p<(void*)shm_block->init_core){ @@ -188,7 +233,7 @@ void* _shm_resize( void* p , unsigned int s) } #endif # endif - return sh_realloc( p, s ); + return sh_realloc( p, s ); } @@ -212,7 +257,7 @@ int shm_getmem(void) LM_CRIT("shm already initialized\n"); return -1; } - + #ifdef SHM_MMAP #ifdef USE_ANON_MMAP shm_mempool=mmap(0, shm_mem_size, PROT_READ|PROT_WRITE, @@ -228,7 +273,7 @@ int shm_getmem(void) close(fd); #endif /* USE_ANON_MMAP */ #else - + shm_shmid=shmget(IPC_PRIVATE, /* SHM_MEM_SIZE */ shm_mem_size , 0700); if (shm_shmid==-1){ LM_CRIT("could not allocate shared memory segment: %s\n", @@ -251,25 +296,57 @@ int shm_getmem(void) int shm_mem_init_mallocs(void* mempool, unsigned long pool_size) { +#ifdef HP_MALLOC + int i; +#endif + /* init it for malloc*/ - shm_block=shm_malloc_init(mempool, pool_size); - if (shm_block==0){ + shm_block = shm_malloc_init(mempool, pool_size); + if (!shm_block){ LM_CRIT("could not initialize shared malloc\n"); shm_mem_destroy(); return -1; } - mem_lock=shm_malloc_unsafe(sizeof(gen_lock_t)); /* skip lock_alloc, - race cond*/ - if (mem_lock==0){ - LM_CRIT("could not allocate lock\n"); + +#ifdef HP_MALLOC + /* lock_alloc cannot be used yet! */ + mem_lock = shm_malloc_unsafe(HP_TOTAL_HASH_SIZE * sizeof *mem_lock); + if (!mem_lock) { + LM_CRIT("could not allocate the shm lock array\n"); shm_mem_destroy(); return -1; } - if (lock_init(mem_lock)==0){ + + for (i = 0; i < HP_TOTAL_HASH_SIZE; i++) + if (!lock_init(&mem_lock[i])) { + LM_CRIT("could not initialize lock\n"); + shm_mem_destroy(); + return -1; + } + + mem_hash_usage = shm_malloc_unsafe(HP_TOTAL_HASH_SIZE * sizeof *mem_hash_usage); + if (!mem_hash_usage) { + LM_ERR("failed to allocate statistics array\n"); + return -1; + } + + memset(mem_hash_usage, 0, HP_TOTAL_HASH_SIZE * sizeof *mem_hash_usage); + +#else + mem_lock = shm_malloc_unsafe(sizeof *mem_lock); + if (!mem_lock) { + LM_CRIT("could not allocate the shm lock\n"); + shm_mem_destroy(); + return -1; + } + + if (!lock_init(mem_lock)) { LM_CRIT("could not initialize lock\n"); shm_mem_destroy(); return -1; } +#endif + #ifdef STATISTICS if (event_shm_threshold) { event_shm_last=shm_malloc_unsafe(sizeof(long)); @@ -281,7 +358,7 @@ int shm_mem_init_mallocs(void* mempool, unsigned long pool_size) *event_shm_last=0; event_shm_pending=shm_malloc_unsafe(sizeof(int)); if (event_shm_pending==0){ - LM_CRIT("could not allocate shm peinding flags\n"); + LM_CRIT("could not allocate shm pending flags\n"); shm_mem_destroy(); return -1; } @@ -289,9 +366,9 @@ int shm_mem_init_mallocs(void* mempool, unsigned long pool_size) } #endif /* STATISTICS */ - + LM_DBG("success\n"); - + return 0; } @@ -299,20 +376,58 @@ int shm_mem_init_mallocs(void* mempool, unsigned long pool_size) int shm_mem_init(void) { int ret; - - ret=shm_getmem(); - if (ret<0) return ret; + + LM_INFO("allocating SHM block\n"); + + ret = shm_getmem(); + if (ret < 0) + return ret; + return shm_mem_init_mallocs(shm_mempool, shm_mem_size); } +struct mi_root *mi_shm_check(struct mi_root *cmd, void *param) +{ +#ifdef DBG_QM_MALLOC + struct mi_root *root; + int ret; + + shm_lock(); + ret = qm_mem_check(shm_block); + shm_unlock(); + + /* any return means success; print the number of fragments now */ + root = init_mi_tree(200, MI_SSTR(MI_OK)); + + if (!addf_mi_node_child(&root->node, 0, MI_SSTR("total_fragments"), "%d", ret)) { + LM_ERR("failed to add MI node\n"); + free_mi_tree(root); + return NULL; + } + + return root; +#endif + + return NULL; +} + +void init_shm_statistics(void) +{ + #if defined(SHM_MEM) && defined(HP_MALLOC) + hp_init_shm_statistics(shm_block); + #endif +} void shm_mem_destroy(void) { #ifndef SHM_MMAP struct shmid_ds shm_info; #endif - - LM_DBG("\n"); + +#ifdef HP_MALLOC + update_mem_pattern_file(); +#endif + if (mem_lock){ LM_DBG("destroying the shared memory lock\n"); lock_destroy(mem_lock); /* we don't need to dealloc it*/ @@ -341,5 +456,4 @@ void shm_mem_destroy(void) #endif } - #endif diff --git a/mem/shm_mem.h b/mem/shm_mem.h index 5f34f8cf088..41162693bcf 100644 --- a/mem/shm_mem.h +++ b/mem/shm_mem.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -63,7 +63,6 @@ #endif #endif - #include "../dprint.h" #include "../lock_ops.h" /* we don't include locking.h on purpose */ @@ -92,6 +91,31 @@ # define MY_SHM_GET_FRAGS fm_get_frags # endif # define shm_malloc_init fm_malloc_init +# define MY_MALLOC_UNSAFE MY_MALLOC +# define MY_FREE_UNSAFE MY_FREE +# define MY_REALLOC_UNSAFE MY_REALLOC +#elif defined HP_MALLOC +# include "hp_malloc.h" + extern struct hp_block* shm_block; +# define MY_MALLOC hp_shm_malloc +# define MY_MALLOC_UNSAFE hp_shm_malloc_unsafe +# define MY_FREE hp_shm_free +# define MY_FREE_UNSAFE hp_shm_free_unsafe +# define MY_REALLOC hp_shm_realloc +# define MY_REALLOC_UNSAFE hp_shm_realloc_unsafe +# define MY_STATUS hp_status +# define MY_MEMINFO hp_info +# ifdef STATISTICS +# define MY_SHM_GET_SIZE hp_shm_get_size +# define MY_SHM_GET_USED hp_shm_get_used +# define MY_SHM_GET_RUSED hp_shm_get_real_used +# define MY_SHM_GET_MUSED hp_shm_get_max_real_used +# define MY_SHM_GET_FREE hp_shm_get_free +# define MY_SHM_GET_FRAGS hp_shm_get_frags +# endif +# define shm_malloc_init hp_shm_malloc_init +# define shm_mem_warming hp_mem_warming +# define update_mem_pattern_file hp_update_mem_pattern_file #else # include "q_malloc.h" extern struct qm_block* shm_block; @@ -100,6 +124,9 @@ # define MY_REALLOC qm_realloc # define MY_STATUS qm_status # define MY_MEMINFO qm_info +# define MY_MALLOC_UNSAFE MY_MALLOC +# define MY_FREE_UNSAFE MY_FREE +# define MY_REALLOC_UNSAFE MY_REALLOC # ifdef STATISTICS # define MY_SHM_GET_SIZE qm_get_size # define MY_SHM_GET_USED qm_get_used @@ -111,11 +138,18 @@ # define shm_malloc_init qm_malloc_init #endif - - extern gen_lock_t* mem_lock; + +extern gen_lock_t* mem_lock; int shm_mem_init(); /* calls shm_getmem & shm_mem_init_mallocs */ + +/* + * should be called after the statistics engine is initialized + * updates the atomic shm statistics with proper values + */ +void init_shm_statistics(void); + int shm_getmem(); /* allocates the memory (mmap or sysv shmap) */ int shm_mem_init_mallocs(void* mempool, unsigned long size); /* initialize the mallocs @@ -165,8 +199,13 @@ inline static void shm_threshold_check(void) #endif +#ifndef HP_MALLOC #define shm_lock() lock_get(mem_lock) #define shm_unlock() lock_release(mem_lock) +#else +#define shm_lock(i) lock_get(&mem_lock[i]) +#define shm_unlock(i) lock_release(&mem_lock[i]) +#endif #ifdef DBG_QM_MALLOC @@ -178,8 +217,12 @@ inline static void shm_threshold_check(void) inline static void* _shm_malloc_unsafe(unsigned int size, const char *file, const char *function, int line ) { - void *p = MY_MALLOC(shm_block, size, file, function, line); + void *p; + + p = MY_MALLOC_UNSAFE(shm_block, size, file, function, line); + shm_threshold_check(); + return p; } @@ -187,10 +230,18 @@ inline static void* _shm_malloc(unsigned int size, const char *file, const char *function, int line ) { void *p; - + +#ifndef HP_MALLOC shm_lock(); - p=_shm_malloc_unsafe(size, file, function, line ); +#endif + + p = MY_MALLOC(shm_block, size, file, function, line); + shm_threshold_check(); + +#ifndef HP_MALLOC shm_unlock(); +#endif + return p; } @@ -199,10 +250,29 @@ inline static void* _shm_realloc(void *ptr, unsigned int size, const char* file, const char* function, int line ) { void *p; + +#ifndef HP_MALLOC shm_lock(); - p=MY_REALLOC(shm_block, ptr, size, file, function, line); +#endif + + p = MY_REALLOC(shm_block, ptr, size, file, function, line); shm_threshold_check(); + +#ifndef HP_MALLOC shm_unlock(); +#endif + + return p; +} + +inline static void* _shm_realloc_unsafe(void *ptr, unsigned int size, + const char* file, const char* function, int line ) +{ + void *p; + + p = MY_REALLOC_UNSAFE(shm_block, ptr, size, file, function, line); + shm_threshold_check(); + return p; } @@ -215,6 +285,9 @@ inline static void* _shm_realloc(void *ptr, unsigned int size, #define shm_realloc( _ptr, _size ) _shm_realloc( (_ptr), (_size), \ __FILE__, __FUNCTION__, __LINE__ ) +#define shm_realloc_unsafe( _ptr, _size ) _shm_realloc_unsafe( (_ptr), (_size), \ + __FILE__, __FUNCTION__, __LINE__ ) + #define shm_free_unsafe( _p ) \ @@ -230,7 +303,7 @@ do { \ shm_unlock(); \ }while(0) - +extern unsigned long long *mem_hash_usage; void* _shm_resize(void* ptr, unsigned int size, const char* f, const char* fn, int line); @@ -243,49 +316,88 @@ void* _shm_resize(void* ptr, unsigned int size, const char* f, const char* fn, #else /*DBQ_QM_MALLOC*/ -inline static void *shm_malloc_unsafe(unsigned int size) +inline static void* shm_malloc_unsafe(unsigned int size) { - void *p = MY_MALLOC(shm_block, size); + void *p; + + p = MY_MALLOC_UNSAFE(shm_block, size); + shm_threshold_check(); + return p; } -inline static void* shm_malloc(unsigned int size) +inline static void* shm_malloc(unsigned long size) { void *p; - + +#ifndef HP_MALLOC shm_lock(); - p=shm_malloc_unsafe(size); +#endif + + p = MY_MALLOC(shm_block, size); + shm_threshold_check(); + +#ifndef HP_MALLOC shm_unlock(); - return p; -} +#endif + return p; +} inline static void* shm_realloc(void *ptr, unsigned int size) { void *p; + +#ifndef HP_MALLOC shm_lock(); - p=MY_REALLOC(shm_block, ptr, size); +#endif + + p = MY_REALLOC(shm_block, ptr, size); shm_threshold_check(); + +#ifndef HP_MALLOC shm_unlock(); +#endif + return p; } +inline static void* shm_realloc_unsafe(void *ptr, unsigned int size) +{ + void *p; + p = MY_REALLOC_UNSAFE(shm_block, ptr, size); + shm_threshold_check(); + + return p; +} #define shm_free_unsafe( _p ) \ do { \ - MY_FREE(shm_block, (_p)); \ + MY_FREE_UNSAFE(shm_block, (_p)); \ shm_threshold_check(); \ } while(0) -#define shm_free(_p) \ -do { \ - shm_lock(); \ - shm_free_unsafe(_p); \ - shm_unlock(); \ -}while(0) +/** + * FIXME: tmp hacks --liviu + */ +inline static void shm_free(void *_p) +{ +#ifndef HP_MALLOC + shm_lock(); +#endif +#ifdef HP_MALLOC + MY_FREE(shm_block, _p); +#else + shm_free_unsafe( (_p)); +#endif + +#ifndef HP_MALLOC + shm_unlock(); +#endif +} void* _shm_resize(void* ptr, unsigned int size); @@ -296,12 +408,18 @@ void* _shm_resize(void* ptr, unsigned int size); #endif -#define shm_status() \ -do { \ - shm_lock(); \ - MY_STATUS(shm_block); \ - shm_unlock(); \ -}while(0) +inline static void shm_status(void) +{ +#ifndef HP_MALLOC + shm_lock(); +#endif + + MY_STATUS(shm_block); + +#ifndef HP_MALLOC + shm_unlock(); +#endif +} #define shm_info(mi) \ @@ -311,6 +429,10 @@ do{\ shm_unlock(); \ }while(0) +/* + * performs a full shared memory pool scan for any corruptions or inconsistencies + */ +struct mi_root *mi_shm_check(struct mi_root *cmd, void *param); #ifdef STATISTICS extern stat_export_t shm_stats[]; diff --git a/mem/vq_malloc.c b/mem/vq_malloc.c index 9724b62eb3f..5c887397e85 100644 --- a/mem/vq_malloc.c +++ b/mem/vq_malloc.c @@ -14,13 +14,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * ------- - * merged from Andrei's qmalloc and many fragments from Regents + * merged from Andrei's qmalloc and many fragments from Regents * University of California NetBSD malloc used; see * http://www.ajk.tele.fi/libc/stdlib/malloc.c.html#malloc for more * details including redistribution policy; this policy asks for @@ -33,7 +33,7 @@ * aggressive, wasteful and very quick malloc library built for * servers that continuously allocate and release chunks of only * few sizes: - * - free lists are organized by size (which eliminates long list traversal + * - free lists are organized by size (which eliminates long list traversal * thru short free chunks if a long one is asked) * - quite a few sizes are supported --> this results in more waste * (unused place in a chunk) however memory can be well reused after @@ -55,12 +55,12 @@ * Horde has been heavily optimized for multi-processor machines * * References: - * - list of malloc implementations: + * - list of malloc implementations: * http://www.cs.colorado.edu/~zorn/Malloc.html * - a white-paper: http://g.oswego.edu/dl/html/malloc.html - * - Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles: + * - Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles: * ``Dynamic Storage Allocation: A Survey and Critical Review'' in - * International Workshop on Memory Management, September 1995, + * International Workshop on Memory Management, September 1995, * ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps * - ptmalloc: http://www.malloc.de/en/ * - GNU C-lib malloc: @@ -81,7 +81,7 @@ #include "../globals.h" #define BIG_BUCKET(_qm) ((_qm)->max_small_bucket+1) -#define IS_BIGBUCKET(_qm, _bucket) ((_bucket)==BIG_BUCKET(_qm)) +#define IS_BIGBUCKET(_qm, _bucket) ((_bucket)==BIG_BUCKET(_qm)) #ifdef DBG_QM_MALLOC #define ASSERT(a) \ @@ -137,7 +137,7 @@ void vqm_debug_frag(struct vqm_block* qm, struct vqm_frag* f) */ unsigned char size2bucket( struct vqm_block* qm, int *size ) { - unsigned char b; + unsigned char b; unsigned int real_size; unsigned int exceeds; @@ -153,13 +153,13 @@ unsigned char size2bucket( struct vqm_block* qm, int *size ) b = qm->s2b[ real_size ]; *size = qm->s2s[ real_size ]; /* there might be various allocations slightly 1>1k, I still - don't want to be too aggressive and increase useless + don't want to be too aggressive and increase useless allocations in small steps - */ + */ } else { - b = BIG_BUCKET(qm); - *size = MAX_FIXED_BLOCK + - (real_size-MAX_FIXED_BLOCK+BLOCK_STEP) + b = BIG_BUCKET(qm); + *size = MAX_FIXED_BLOCK + + (real_size-MAX_FIXED_BLOCK+BLOCK_STEP) / BLOCK_STEP * BLOCK_STEP; } /*size must be a multiple of 8*/ @@ -177,7 +177,7 @@ struct vqm_block* vqm_malloc_init(char* address, unsigned int size) unsigned char b; /* bucket iterator */ unsigned int s; /* size iterator */ char *end; - + /* make address and size multiple of 8*/ start=(char*)( ((unsigned int)address%8)?((unsigned int)address+8)/8*8: (unsigned int)address); @@ -218,18 +218,18 @@ struct vqm_block* vqm_malloc_init(char* address, unsigned int size) qm->core_end = end; /* allocate big chunks from end */ qm->big_chunks = end; - + return qm; } -struct vqm_frag *more_core( struct vqm_block* qm, +struct vqm_frag *more_core( struct vqm_block* qm, unsigned char bucket, unsigned int size #ifdef DBG_QM_MALLOC , char *file, char *func, unsigned int line #endif - ) + ) { struct vqm_frag *new_chunk; struct vqm_frag_end *end; @@ -239,9 +239,9 @@ struct vqm_frag *more_core( struct vqm_block* qm, /* update core */ if (IS_BIGBUCKET(qm, bucket)) { qm->big_chunks-=size; - new_chunk = (struct vqm_frag *) qm->big_chunks ; + new_chunk = (struct vqm_frag *) qm->big_chunks ; } else { - new_chunk = (struct vqm_frag *) qm->core; + new_chunk = (struct vqm_frag *) qm->core; qm->core+=size; } qm->free_core-=size; @@ -262,19 +262,19 @@ static inline void vqm_detach_free( struct vqm_block* qm, struct vqm_frag *prev, *next; - prev=FRAG_END(frag)->prv_free; + prev=FRAG_END(frag)->prv_free; next=frag->u.nxt_free; - if (prev) prev->u.nxt_free=next; + if (prev) prev->u.nxt_free=next; else qm->next_free[BIG_BUCKET(qm)]=next; - if (next) FRAG_END(next)->prv_free=prev; - + if (next) FRAG_END(next)->prv_free=prev; + } #ifdef DBG_QM_MALLOC -void* vqm_malloc(struct vqm_block* qm, unsigned int size, +void* vqm_malloc(struct vqm_block* qm, unsigned int size, char* file, char* func, unsigned int line) #else void* vqm_malloc(struct vqm_block* qm, unsigned int size) @@ -282,7 +282,7 @@ void* vqm_malloc(struct vqm_block* qm, unsigned int size) { struct vqm_frag *new_chunk, *f; unsigned char bucket; - + #ifdef DBG_QM_MALLOC unsigned int demanded_size; LM_GEN1( memlog, "params (%p, %d) called from %s: %s(%d)\n", @@ -297,7 +297,7 @@ void* vqm_malloc(struct vqm_block* qm, unsigned int size) #ifdef DBG_QM_MALLOC LM_GEN1( memlog, "processing a big fragment\n"); #endif - for (f=qm->next_free[bucket] ; f; f=f->u.nxt_free ) + for (f=qm->next_free[bucket] ; f; f=f->u.nxt_free ) if (f->size>=size) { /* first-fit */ new_chunk=f; VQM_DEBUG_FRAG(qm, f); @@ -314,10 +314,10 @@ void* vqm_malloc(struct vqm_block* qm, unsigned int size) new_chunk=MORE_CORE( qm, bucket, size ); if (!new_chunk) { #ifdef DBG_QM_MALLOC - LM_GEN1(memlog, "params (%p, %d) called from %s: %s(%d)\n", + LM_GEN1(memlog, "params (%p, %d) called from %s: %s(%d)\n", qm, size, file, func, line); #else - LM_DBG("params (%p, %d) called from %s: %s(%d)\n", + LM_DBG("params (%p, %d) called from %s: %s(%d)\n", qm, size); #endif pkg_threshold_check(); @@ -334,7 +334,7 @@ void* vqm_malloc(struct vqm_block* qm, unsigned int size) qm->usage[ bucket ]++; LM_GEN1( memlog,"params ( %p, %d ) returns address %p in bucket %d, " "real-size %d\n", - qm, demanded_size, (char*)new_chunk+sizeof(struct vqm_frag), + qm, demanded_size, (char*)new_chunk+sizeof(struct vqm_frag), bucket, size ); new_chunk->end_check=(char*)new_chunk+ @@ -347,7 +347,7 @@ void* vqm_malloc(struct vqm_block* qm, unsigned int size) } #ifdef DBG_QM_MALLOC -void vqm_free(struct vqm_block* qm, void* p, char* file, char* func, +void vqm_free(struct vqm_block* qm, void* p, char* file, char* func, unsigned int line) #else void vqm_free(struct vqm_block* qm, void* p) @@ -357,7 +357,7 @@ void vqm_free(struct vqm_block* qm, void* p) unsigned char b; #ifdef DBG_QM_MALLOC - LM_GEN1(memlog,"params (%p, %p), called from %s: %s(%d)\n", + LM_GEN1(memlog,"params (%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line); if (p>(void *)qm->core_end || p<(void*)qm->init_core){ LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p); @@ -380,10 +380,10 @@ void vqm_free(struct vqm_block* qm, void* p) if ( b>MAX_BUCKET ) { LM_CRIT("fragment with too high bucket nr: " "%d, allocated: %s: %s(%d) - aborting\n", - b, f->file, f->func, f->line); + b, f->file, f->func, f->line); abort(); } - LM_GEN1(memlog,"freeing %d bucket block alloc'ed from %s: %s(%d)\n", + LM_GEN1(memlog,"freeing %d bucket block alloc'ed from %s: %s(%d)\n", f->u.inuse.bucket, f->file, f->func, f->line); f->file=file; f->func=func; f->line=line; qm->usage[ f->u.inuse.bucket ]--; @@ -417,7 +417,7 @@ void vqm_free(struct vqm_block* qm, void* p) qm->big_chunks+=f->size; pkg_threshold_check(); return; - } + } first_big = qm->next_free[b]; /* fix reverse link (used only for BIG_BUCKET */ if (first_big) FRAG_END(first_big)->prv_free=f; @@ -430,7 +430,7 @@ void vqm_free(struct vqm_block* qm, void* p) void dump_frag( struct vqm_frag* f, int i ) { - LM_GEN1(memdump, " %3d. address=%p real size=%d bucket=%d\n", i, + LM_GEN1(memdump, " %3d. address=%p real size=%d bucket=%d\n", i, (char*)f+sizeof(struct vqm_frag), f->size, f->u.inuse.bucket); #ifdef DBG_QM_MALLOC LM_GEN1(memdump, " demanded size=%d\n", f->demanded_size ); @@ -448,7 +448,7 @@ void vqm_status(struct vqm_block* qm) LM_GEN1(memdump, "vqm_status (%p):\n", qm); if (!qm) return; - LM_GEN1(memdump, " heap size= %d, available: %d\n", + LM_GEN1(memdump, " heap size= %d, available: %d\n", qm->core_end-qm->init_core, qm->free_core ); LM_GEN1(memdump, "dumping unfreed fragments:\n"); @@ -463,7 +463,7 @@ void vqm_status(struct vqm_block* qm) LM_GEN1(memdump,"dumping bucket statistics:\n"); for (i=0; i<=BIG_BUCKET(qm); i++) { for(on_list=0, f=qm->next_free[i]; f; f=f->u.nxt_free ) on_list++; - LM_GEN1(memdump," %3d. bucket: in use: %ld, on free list: %d\n", + LM_GEN1(memdump," %3d. bucket: in use: %ld, on free list: %d\n", i, qm->usage[i], on_list ); } #endif diff --git a/mem/vq_malloc.h b/mem/vq_malloc.h index b7cc4fc4a13..002899a0d0b 100644 --- a/mem/vq_malloc.h +++ b/mem/vq_malloc.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -69,12 +69,12 @@ struct vqm_frag { /* XXX */ /* total chunk size including all overhead/bellowfoot/roundings/etc */ - /* useless as otherwise size implied by bucket (if I really want to save + /* useless as otherwise size implied by bucket (if I really want to save bytes, I'll remove it from here */ unsigned long size; union{ /* pointer to next chunk in a bucket if free */ - struct vqm_frag* nxt_free; + struct vqm_frag* nxt_free; struct { /* or bucket number if busy */ unsigned char magic; unsigned char bucket; @@ -95,7 +95,7 @@ struct vqm_frag { struct vqm_frag_end{ /* total chunk size including all overhead/bellowfoot/roundings/etc */ - unsigned long size; + unsigned long size; /* XXX */ /* used only for variable-size chunks; might have different data structures for variable/fixed length chunks */ @@ -133,9 +133,9 @@ struct vqm_block* vqm_malloc_init(char* address, unsigned int size); #ifdef DBG_QM_MALLOC void vqm_debug_frag(struct vqm_block* qm, struct vqm_frag* f); -void* vqm_malloc(struct vqm_block*, unsigned int size, char* file, char* func, +void* vqm_malloc(struct vqm_block*, unsigned int size, char* file, char* func, unsigned int line); -void vqm_free(struct vqm_block*, void* p, char* file, char* func, +void vqm_free(struct vqm_block*, void* p, char* file, char* func, unsigned int line); #else void* vqm_malloc(struct vqm_block*, unsigned int size); diff --git a/menuconfig/Makefile b/menuconfig/Makefile index 9faa5f4529f..90e967311f6 100644 --- a/menuconfig/Makefile +++ b/menuconfig/Makefile @@ -5,7 +5,7 @@ MENUCONFIG_HAVE_SOURCES?=1 CFLAGS=-g -Wall -DMENUCONFIG_CFG_PATH=\"$(MENUCONFIG_CFG_PATH)\" \ -DMENUCONFIG_GEN_PATH=\"$(MENUCONFIG_GEN_PATH)\" \ -DMENUCONFIG_HAVE_SOURCES=$(MENUCONFIG_HAVE_SOURCES) $(CC_EXTRA_OPTS) -MY_LDFLAGS=-lcurses $(LD_EXTRA_OPTS) +MY_LDFLAGS=-lncurses $(LD_EXTRA_OPTS) EXEC_NAME=configure all: $(MENUCONFIG_FILES) $(CC) -o $(EXEC_NAME) $(CFLAGS) $^ $(MY_LDFLAGS) diff --git a/menuconfig/cfg.c b/menuconfig/cfg.c index b0c9c46e059..f4a679b4cf3 100644 --- a/menuconfig/cfg.c +++ b/menuconfig/cfg.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/menuconfig/cfg.h b/menuconfig/cfg.h index 80b64b6a91e..9544620ee63 100644 --- a/menuconfig/cfg.h +++ b/menuconfig/cfg.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/menuconfig/commands.c b/menuconfig/commands.c index d3e4433c676..070622395fb 100644 --- a/menuconfig/commands.c +++ b/menuconfig/commands.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -46,9 +46,9 @@ int save_all_changes(select_menu *menu,void *arg) static char name_buf[128]; select_menu *current; cfg_gen_t *it; - + #if MENUCONFIG_HAVE_SOURCES > 0 - /* Take care of compile related options */ + /* Take care of compile related options */ if (dump_make_conf(menu,arg) < 0) fprintf(output,"Failed to save all compile related options\n"); #else @@ -61,7 +61,7 @@ int save_all_changes(select_menu *menu,void *arg) strcpy(name_buf,"Save "); strcat(name_buf,it->name); current=find_menu(name_buf,main_menu); - if (save_m4_def(current,NULL) < 0) + if (save_m4_def(current,NULL) < 0) fprintf(output,"Failed to save cfg %s\n",it->name); } @@ -94,7 +94,7 @@ int reset_unsaved_compile(select_menu *menu,void *arg) } current->child_changed=CHILD_NO_CHANGES; - + print_notice(NOTICE_Y,NOTICE_X,1,"Changes have been reset. Press any key to continue"); return 0; @@ -106,13 +106,13 @@ int run_make_install(select_menu *menu,void *arg) int ret=0,status; select_menu *current; select_item *it; - + /* save current tty modes */ def_prog_mode(); /* restore original tty modes */ endwin(); - /* temporarily ignore SIGINT + /* temporarily ignore SIGINT * in case child is killed, we do not want to also exit main app */ signal(SIGINT, SIG_IGN); @@ -155,7 +155,7 @@ int run_make_install(select_menu *menu,void *arg) end: /* Restore SIGINT handler */ - signal(SIGINT,_quit_handler); + signal(SIGINT,_quit_handler); printf("\n\nPress any key to return to menuconfig\n\n"); getch(); @@ -174,7 +174,7 @@ int run_make_proper(select_menu *menu,void *arg) /* restore original tty modes */ endwin(); - /* temporarily ignore SIGINT + /* temporarily ignore SIGINT * in case child is killed, we do not want to also exit main app */ signal(SIGINT, SIG_IGN); @@ -202,7 +202,7 @@ int run_make_proper(select_menu *menu,void *arg) end: /* Restore SIGINT handler */ - signal(SIGINT,_quit_handler); + signal(SIGINT,_quit_handler); printf("\n\nPress any key to return to menuconfig\n\n"); getch(); @@ -232,7 +232,7 @@ int generate_cfg(select_menu *menu,void *arg) fprintf(output,"Invalid menu name [%s]\n",items_menu->name); return -1; } - + p++; m4_cfg = find_cfg_entry(p); @@ -307,7 +307,7 @@ int read_install_prefix(select_menu *menu,void *arg) print_notice(NOTICE_Y,NOTICE_X,0,"%s (Current = '%s') :",query_msg, install_prefix?install_prefix:DEFAULT_INSTALL_PREFIX); - + /* print directory that user is typing */ echo(); @@ -330,7 +330,7 @@ int read_install_prefix(select_menu *menu,void *arg) fprintf(output,"No more mem\n"); return -1; } - + memset(install_prefix,0,str[len-1]=='/'?len+1:len+2); memcpy(install_prefix,str,len); if (str[len-1] != '/') @@ -347,7 +347,7 @@ int read_install_prefix(select_menu *menu,void *arg) install_prefix=NULL; print_notice(NOTICE_Y,NOTICE_X,0,"%s. Install prefix is currently [%s]",folder_ok, install_prefix?install_prefix:DEFAULT_INSTALL_PREFIX); - clrtoeol(); + clrtoeol(); print_notice(NOTICE_Y+1,NOTICE_X,1,"Press any key to continue !"); clrtoeol(); } @@ -374,10 +374,10 @@ int save_m4_def(select_menu *menu,void *arg) fprintf(output,"Invalid menu name [%s]\n",items_menu->name); return -1; } - + p++; m4_cfg = find_cfg_entry(p); - + if (!m4_cfg) { fprintf(output,"Failed to find cfg entry for %s\n",items_menu->name); return -1; @@ -387,7 +387,7 @@ int save_m4_def(select_menu *menu,void *arg) run_locally?19:MENUCONFIG_CFG_PATH_LEN); memcpy(cfg_path+(run_locally?19:MENUCONFIG_CFG_PATH_LEN), m4_cfg->defs_m4,strlen(m4_cfg->defs_m4)+1); - + f = fopen(cfg_path,"w"); if (!f) { fprintf(output,"Failed to open m4 defs\n"); @@ -418,6 +418,10 @@ int dump_make_conf(select_menu *menu,void *arg) int i,k=0; FILE *f = fopen(MAKE_CONF_FILE,"w"); + if (!f) { + fprintf(stderr,"Failed to open [%s]\n",MAKE_CONF_FILE); + return -1; + } /* START compile MODULES related options */ current = find_menu(CONF_EXCLUDED_MODS,main_menu); @@ -458,16 +462,20 @@ int dump_make_conf(select_menu *menu,void *arg) for (it=current->item_list;it;it=it->next) { fprintf(f,"%sDEFS+= -D%s #%s", it->enabled?"":"#",it->name,it->description); + if (strcmp(it->name,"USE_TLS") == 0 && it->enabled) + fprintf(f,"TLS=1\n"); + else if (strcmp(it->name,"USE_SCTP") == 0 && it->enabled) + fprintf(f,"SCTP=1\n"); it->prev_state=it->enabled; } current->child_changed=CHILD_NO_CHANGES; /* END compile DEFS related options */ - + /* START install prefix related options */ current=find_menu(CONF_INSTALL_PREFIX,main_menu); fprintf(f,"\nPREFIX=%s",install_prefix?install_prefix:DEFAULT_INSTALL_PREFIX); - + prev_prefix=install_prefix; current->child_changed=CHILD_NO_CHANGES; /* END install prefix related options */ diff --git a/menuconfig/commands.h b/menuconfig/commands.h index c48d52ea7cd..2aa8965942d 100644 --- a/menuconfig/commands.h +++ b/menuconfig/commands.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/menuconfig/configs/opensips_loadbalancer.m4 b/menuconfig/configs/opensips_loadbalancer.m4 index 90440c673ba..e88b15e8235 100644 --- a/menuconfig/configs/opensips_loadbalancer.m4 +++ b/menuconfig/configs/opensips_loadbalancer.m4 @@ -80,8 +80,8 @@ loadmodule "sl.so" #### Transaction Module loadmodule "tm.so" -modparam("tm", "fr_timer", 5) -modparam("tm", "fr_inv_timer", 30) +modparam("tm", "fr_timeout", 5) +modparam("tm", "fr_inv_timeout", 30) modparam("tm", "restart_fr_on_each_reply", 0) modparam("tm", "onreply_avp_mode", 1) @@ -120,14 +120,14 @@ modparam("acc", "report_cancels", 0) if you enable this parameter, be sure the enable "append_fromtag" in "rr" module */ modparam("acc", "detect_direction", 0) -modparam("acc", "failed_transaction_flag", 3) +modparam("acc", "failed_transaction_flag", "ACC_FAILED") /* account triggers (flags) */ -ifelse(USE_DBACC,`yes',`modparam("acc", "db_flag", 1) -modparam("acc", "db_missed_flag", 2) +ifelse(USE_DBACC,`yes',`modparam("acc", "db_flag", "ACC_DO") +modparam("acc", "db_missed_flag", "ACC_MISSED") modparam("acc", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE ME -', `modparam("acc", "log_flag", 1) -modparam("acc", "log_missed_flag", 2) +', `modparam("acc", "log_flag", "ACC_DO") +modparam("acc", "log_missed_flag", "ACC_MISSED") ') ifelse(USE_DISPATCHER,`no',`#### DIALOG module @@ -191,8 +191,8 @@ route{ } ',`') if (is_method("BYE")) { - setflag(1); # do accounting ... - setflag(3); # ... even if the transaction fails + setflag(ACC_DO); # do accounting ... + setflag(ACC_FAILED); # ... even if the transaction fails } else if (is_method("INVITE")) { # even if in most of the cases is useless, do RR for # re-INVITEs alos, as some buggy clients do change route set @@ -253,7 +253,7 @@ route{ # record routing record_route(); - setflag(1); # do accounting + setflag(ACC_DO); # do accounting ifelse(USE_DISPATCHER,`yes',` if ( !ds_select_dst("1","4") ) { diff --git a/menuconfig/configs/opensips_loadbalancer_def.m4 b/menuconfig/configs/opensips_loadbalancer_def.m4 index 8832034de58..a4922a38f5e 100644 --- a/menuconfig/configs/opensips_loadbalancer_def.m4 +++ b/menuconfig/configs/opensips_loadbalancer_def.m4 @@ -5,4 +5,4 @@ define(`USE_DBACC', `no') # OpenSIPS will save ACC entries in DB for all calls define(`USE_DISPATCHER', `no') # OpenSIPS will use DISPATCHER instead of Load-Balancer for distributing the traffic define(`DISABLE_PINGING', `yes') # OpenSIPS will not ping at all the destinations (otherwise it will ping when detected as failed) define(`USE_HTTP_MANAGEMENT_INTERFACE', `no') # OpenSIPS will provide a WEB Management Interface on port 8888 -divert +divert \ No newline at end of file diff --git a/menuconfig/configs/opensips_residential.m4 b/menuconfig/configs/opensips_residential.m4 index 2c54ed429d2..4a646aee1d3 100644 --- a/menuconfig/configs/opensips_residential.m4 +++ b/menuconfig/configs/opensips_residential.m4 @@ -74,8 +74,8 @@ loadmodule "sl.so" #### Transaction Module loadmodule "tm.so" -modparam("tm", "fr_timer", 5) -modparam("tm", "fr_inv_timer", 30) +modparam("tm", "fr_timeout", 5) +modparam("tm", "fr_inv_timeout", 30) modparam("tm", "restart_fr_on_each_reply", 0) modparam("tm", "onreply_avp_mode", 1) @@ -115,7 +115,7 @@ modparam("httpd", "port", 8888)') #### USeR LOCation module loadmodule "usrloc.so" -modparam("usrloc", "nat_bflag", 10) +modparam("usrloc", "nat_bflag", "NAT") ifelse(USE_DBUSRLOC,`yes',`modparam("usrloc", "db_mode", 2) modparam("usrloc", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE ME @@ -123,7 +123,7 @@ modparam("usrloc", "db_url", #### REGISTRAR module loadmodule "registrar.so" -modparam("registrar", "tcp_persistent_flag", 7) +modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT") ifelse(USE_NAT,`yes',`modparam("registrar", "received_avp", "$avp(received_nh)")',`') /* uncomment the next line not to allow more than 10 contacts per AOR */ #modparam("registrar", "max_contacts", 10) @@ -137,14 +137,14 @@ modparam("acc", "report_cancels", 0) if you enable this parameter, be sure the enable "append_fromtag" in "rr" module */ modparam("acc", "detect_direction", 0) -modparam("acc", "failed_transaction_flag", 3) +modparam("acc", "failed_transaction_flag", "ACC_FAILED") /* account triggers (flags) */ -ifelse(USE_DBACC,`yes',`modparam("acc", "db_flag", 1) -modparam("acc", "db_missed_flag", 2) +ifelse(USE_DBACC,`yes',`modparam("acc", "db_flag", "ACC_DO") +modparam("acc", "db_missed_flag", "ACC_MISSED") modparam("acc", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE ME -', `modparam("acc", "log_flag", 1) -modparam("acc", "log_missed_flag", 2) +', `modparam("acc", "log_flag", "ACC_DO") +modparam("acc", "log_missed_flag", "ACC_MISSED") ') ifelse(USE_AUTH,`yes',`#### AUTHentication modules @@ -172,9 +172,10 @@ modparam("auth_db|usrloc|uri", "use_domain", 1) ', `') ifelse(USE_PRESENCE,`yes',`#### PRESENCE modules +loadmodule "xcap.so" loadmodule "presence.so" loadmodule "presence_xml.so" -modparam("presence|presence_xml", "db_url", +modparam("xcap|presence", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE ME modparam("presence_xml", "force_active", 1) modparam("presence", "server_address", "sip:127.0.0.1:5060") # CUSTOMIZE ME @@ -224,10 +225,10 @@ route{ if (nat_uac_test("23")) { if (is_method("REGISTER")) { fix_nated_register(); - setbflag(10); + setbflag(NAT); } else { fix_nated_contact(); - setflag(10); + setflag(NAT); } } ',`') @@ -249,8 +250,8 @@ route{ } ',`') if (is_method("BYE")) { - setflag(1); # do accounting ... - setflag(3); # ... even if the transaction fails + setflag(ACC_DO); # do accounting ... + setflag(ACC_FAILED); # ... even if the transaction fails } else if (is_method("INVITE")) { # even if in most of the cases is useless, do RR for # re-INVITEs alos, as some buggy clients do change route set @@ -259,16 +260,16 @@ route{ } ifelse(USE_NAT,`yes',`if (check_route_param("nat=yes")) - setflag(10);',`') + setflag(NAT);',`') # route it out to whatever destination was set by loose_route() # in $du (destination URI). - route(1); + route(relay); } else { ifelse(USE_PRESENCE,`yes', `if (is_method("SUBSCRIBE") && $rd == "127.0.0.1:5060") { # CUSTOMIZE ME # in-dialog subscribe requests - route(2); + route(handle_presence); exit; }',`') if ( is_method("ACK") ) { @@ -354,7 +355,7 @@ route{ exit; } ',`') - setflag(1); # do accounting + setflag(ACC_DO); # do accounting } ifelse(USE_MULTIDOMAIN,`yes',` @@ -370,13 +371,13 @@ route{ ## force_send_socket(tls:127.0.0.1:5061); # CUSTOMIZE ##} ',`') - route(1); + route(relay); } # requests for my domain ifelse(USE_PRESENCE,`yes',` if( is_method("PUBLISH|SUBSCRIBE")) - route(2);',` + route(handle_presence);',` if (is_method("PUBLISH|SUBSCRIBE")) { sl_send_reply("503", "Service Unavailable"); @@ -399,7 +400,7 @@ route{ exit; }',`') - if ( ifelse(ENABLE_TCP,`yes',`proto==TCP ||',`') ifelse(ENABLE_TLS,`yes',`proto==TLS ||',`') 0 ) setflag(7); + if ( ifelse(ENABLE_TCP,`yes',`proto==TCP ||',`') ifelse(ENABLE_TLS,`yes',`proto==TLS ||',`') 0 ) setflag(TCP_PERSISTENT); if (!save("location")) sl_reply_error(); @@ -432,7 +433,7 @@ route{ $rd="11.22.33.44"; CUSTOMIZE ME $rp=5060; ') - route(1); + route(relay); exit; } ',`') @@ -446,35 +447,35 @@ route{ ifelse(VM_DIVERSION,`yes',` # redirect to a different VM system $du = "sip:127.0.0.2:5060"; # CUSTOMIZE ME - route(1); + route(relay); ',` t_newtran(); t_reply("404", "Not Found"); exit;') } - ifelse(USE_NAT,`yes',`if (isbflagset(10)) setflag(10);',`') + ifelse(USE_NAT,`yes',`if (isbflagset(NAT)) setflag(NAT);',`') # when routing via usrloc, log the missed calls also - setflag(2); - route(1); + setflag(ACC_MISSED); + route(relay); } -route[1] { +route[relay] { # for INVITEs enable some additional helper routes if (is_method("INVITE")) { - ifelse(USE_NAT,`yes',`if (isflagset(10)) { + ifelse(USE_NAT,`yes',`if (isflagset(NAT)) { rtpproxy_offer("ro"); }',`') - t_on_branch("2"); - t_on_reply("2"); - t_on_failure("1"); + t_on_branch("per_branch_ops"); + t_on_reply("handle_nat"); + t_on_failure("missed_call"); } - ifelse(USE_NAT,`yes',`if (isflagset(10)) { + ifelse(USE_NAT,`yes',`if (isflagset(NAT)) { add_rr_param(";nat=yes"); }',`') @@ -486,7 +487,7 @@ route[1] { ifelse(USE_PRESENCE,`yes',` # Presence route -route[2] +route[handle_presence] { if (!t_newtran()) { @@ -508,21 +509,21 @@ route[2] }',`') -branch_route[2] { +branch_route[per_branch_ops] { xlog("new branch at $ru\n"); } -onreply_route[2] { +onreply_route[handle_nat] { ifelse(USE_NAT,`yes',`if (nat_uac_test("1")) fix_nated_contact(); - if ( isflagset(10) ) + if ( isflagset(NAT) ) rtpproxy_answer("ro");',`') xlog("incoming reply\n"); } -failure_route[1] { +failure_route[missed_call] { if (t_was_cancelled()) { exit; } @@ -539,7 +540,7 @@ failure_route[1] { if (t_check_status("486|408")) { $du = "sip:127.0.0.2:5060"; # CUSTOMIZE ME # do not set the missed call flag again - route(1); + route(relay); }',`') } diff --git a/menuconfig/configs/opensips_residential_def.m4 b/menuconfig/configs/opensips_residential_def.m4 index 48da65c7816..3f7fd277550 100644 --- a/menuconfig/configs/opensips_residential_def.m4 +++ b/menuconfig/configs/opensips_residential_def.m4 @@ -15,4 +15,4 @@ define(`HAVE_INBOUND_PSTN', `no') # OpenSIPS will accept calls from PSTN gateway define(`HAVE_OUTBOUND_PSTN', `no') # OpenSIPS will send numerical dials to PSTN gateways (with static IP definition) define(`USE_DR_PSTN', `no') # OpenSIPS will use Dynamic Routing Support for PSTN interconnection define(`USE_HTTP_MANAGEMENT_INTERFACE', `no') # OpenSIPS will provide a WEB Management Interface on port 8888 -divert +divert \ No newline at end of file diff --git a/menuconfig/configs/opensips_trunking.m4 b/menuconfig/configs/opensips_trunking.m4 index 3888d1c9534..6c5776ba56b 100644 --- a/menuconfig/configs/opensips_trunking.m4 +++ b/menuconfig/configs/opensips_trunking.m4 @@ -80,8 +80,8 @@ loadmodule "sl.so" #### Transaction Module loadmodule "tm.so" -modparam("tm", "fr_timer", 5) -modparam("tm", "fr_inv_timer", 30) +modparam("tm", "fr_timeout", 5) +modparam("tm", "fr_inv_timeout", 30) modparam("tm", "restart_fr_on_each_reply", 0) modparam("tm", "onreply_avp_mode", 1) @@ -130,14 +130,14 @@ modparam("acc", "report_cancels", 0) if you enable this parameter, be sure the enable "append_fromtag" in "rr" module */ modparam("acc", "detect_direction", 0) -modparam("acc", "failed_transaction_flag", 3) +modparam("acc", "failed_transaction_flag", "ACC_FAILED") /* account triggers (flags) */ -ifelse(USE_DBACC,`yes',`modparam("acc", "db_flag", 1) -modparam("acc", "db_missed_flag", 2) +ifelse(USE_DBACC,`yes',`modparam("acc", "db_flag", "ACC_DO") +modparam("acc", "db_missed_flag", "ACC_MISSED") modparam("acc", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") # CUSTOMIZE ME -', `modparam("acc", "log_flag", 1) -modparam("acc", "log_missed_flag", 2) +', `modparam("acc", "log_flag", "ACC_DO") +modparam("acc", "log_missed_flag", "ACC_MISSED") ') ifelse(USE_DIALOG,`yes',`#### DIALOG module @@ -175,7 +175,7 @@ route{ if ( check_source_address("1","$avp(trunk_attrs)") ) { # request comes from trunks - setflag(20); + setflag(IS_TRUNK); } else if ( is_from_gw() ) { # request comes from GWs } else { @@ -195,8 +195,8 @@ route{ } ',`') if (is_method("BYE")) { - setflag(1); # do accounting ... - setflag(3); # ... even if the transaction fails + setflag(ACC_DO); # do accounting ... + setflag(ACC_FAILED); # ... even if the transaction fails } else if (is_method("INVITE")) { # even if in most of the cases is useless, do RR for # re-INVITEs alos, as some buggy clients do change route set @@ -227,7 +227,7 @@ route{ #### INITIAL REQUESTS - if ( !isflagset(20) ) { + if ( !isflagset(IS_TRUNK) ) { ## accept new calls only from trunks send_reply("403","Not from trunk"); exit; @@ -263,7 +263,7 @@ route{ # record routing record_route(); - setflag(1); # do accounting + setflag(ACC_DO); # do accounting ifelse(USE_DIALOG,`yes',` # create dialog with timeout diff --git a/menuconfig/configs/opensips_trunking_def.m4 b/menuconfig/configs/opensips_trunking_def.m4 index 366befc6b62..9699bc34ce8 100644 --- a/menuconfig/configs/opensips_trunking_def.m4 +++ b/menuconfig/configs/opensips_trunking_def.m4 @@ -6,4 +6,4 @@ define(`USE_DIALPLAN', `no') # OpenSIPS will use dialplan for transformation of define(`USE_DIALOG', `no') # OpenSIPS will keep track of active dialogs define(`DO_CALL_LIMITATION', `no') # OpenSIPS will limit the number of parallel calls per trunk define(`USE_HTTP_MANAGEMENT_INTERFACE', `no') # OpenSIPS will provide a WEB Management Interface on port 8888 -divert +divert \ No newline at end of file diff --git a/menuconfig/curses.c b/menuconfig/curses.c index 5e2412e7c54..60b00b536f5 100644 --- a/menuconfig/curses.c +++ b/menuconfig/curses.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "curses.h" @@ -88,7 +88,7 @@ int draw_sibling_menu(select_menu *menu) int max_len=0,len; again: wclear(menu_window); - + /* print title in colour */ attron(COLOR_PAIR(1)); mvprintw(HIGH_NOTICE_Y,max_x/2-20,menu->parent?menu->parent->name:"OpenSIPS Main Configuration Menu"); @@ -106,7 +106,7 @@ int draw_sibling_menu(select_menu *menu) if (len > max_len) max_len = len; } - + /* draw selection marker */ wmove(menu_window, max_y/4+cur_index, (max_x / 2) - 25); waddstr(menu_window, "--->"); @@ -153,7 +153,7 @@ int draw_sibling_menu(select_menu *menu) case 'h': case 'H': clear(); - print_notice(max_y/2,20,0,"Use UP and DOWN arrow keys to navigate."); + print_notice(max_y/2,20,0,"Use UP and DOWN arrow keys to navigate."); print_notice(max_y/2+1,20,0,"Use RIGHT arrow or ENTER key to enter a certain menu."); print_notice(max_y/2+2,20,0,"Use LEFT arror or Q key to go back."); print_notice(max_y/2+3,20,0,"Use SPACE to toggle an entry ON/OFF.\n"); @@ -163,24 +163,24 @@ int draw_sibling_menu(select_menu *menu) case KEY_LEFT: case 'q': case 'Q': - for (it=menu;it;it=it->next_sibling) { + for (it=menu;it;it=it->next_sibling) { if (it->child_changed == CHILD_CHANGED) { if (skip == 0) { /* have we asked before and got negative response ? */ print_notice(NOTICE_Y,NOTICE_X,0,"You have not saved changes. Go back anyway ? [y/n] "); c = getch(); - if (c == 'n' || c == 'N') + if (c == 'n' || c == 'N') goto again; else { it->child_changed = CHILD_CHANGE_IGNORED; skip=1; return 0; } - } else + } else it->child_changed = CHILD_CHANGE_IGNORED; } } - if (skip == 1) + if (skip == 1) return 0; return 0; } @@ -253,7 +253,7 @@ int draw_item_list(select_menu *menu) } move(max_y/4+actual_pos,max_x/2-19); - + /* draw box */ wattron(menu_window,COLOR_PAIR(2)); for (d=-1;ditem_no) { wmove(menu_window,max_y/4+max_display-1,max_x/2-5+max_len); wprintw(menu_window,"Scroll down for more"); } wattroff(menu_window,COLOR_PAIR(2)); - + wrefresh(menu_window); k=0; @@ -291,9 +291,9 @@ int draw_item_list(select_menu *menu) case KEY_UP: if (should_scroll && curopt != 0) { if (curopt == disp_start) { - disp_start--; + disp_start--; actual_pos=0; - } else + } else actual_pos--; curopt--; } else if (curopt!=0) { @@ -303,7 +303,7 @@ int draw_item_list(select_menu *menu) case KEY_DOWN: if (should_scroll && curopt < menu->item_no-1) { if (curopt == (disp_start+max_display-1)) { - disp_start++; + disp_start++; actual_pos=i-1; } else actual_pos++; diff --git a/menuconfig/curses.h b/menuconfig/curses.h index 1f9afe2686d..e2f49335838 100644 --- a/menuconfig/curses.h +++ b/menuconfig/curses.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -46,7 +46,7 @@ int draw_item_list(select_menu *menu); #define HIGH_NOTICE_Y (max_y/16) -#define NOTICE_Y (max_y*3/4) +#define NOTICE_Y (max_y*3/4) #define NOTICE_X (10) #define print_notice(y,x,prompt,...) \ diff --git a/menuconfig/items.c b/menuconfig/items.c index 39d016ad270..37117bf94aa 100644 --- a/menuconfig/items.c +++ b/menuconfig/items.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/menuconfig/items.h b/menuconfig/items.h index b639a8c429d..48181506c44 100644 --- a/menuconfig/items.h +++ b/menuconfig/items.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/menuconfig/main.c b/menuconfig/main.c index c0e63d0294c..5c3d1cc6915 100644 --- a/menuconfig/main.c +++ b/menuconfig/main.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -129,7 +129,7 @@ int init_main_menu() link_child(main_menu,aux); if (parse_make_conf() < 0) { - fprintf(output,"Failed to parse Makefile.conf"); + fprintf(output,"Failed to parse %s\n", MAKE_CONF_FILE); return -1; } #else @@ -211,7 +211,7 @@ int init_main_menu() link_child(main_menu,aux); if (parse_make_conf() < 0) { - fprintf(output,"Failed to parse Makefile.conf"); + fprintf(output,"Failed to parse %s\n", MAKE_CONF_FILE); return -1; } } else { @@ -273,11 +273,11 @@ int main(int argc,char **argv) } /* don't buffer input until the enter key is pressed */ - cbreak(); + cbreak(); /* don't echo user input to the screen */ - noecho(); + noecho(); /* allow the use of arrow keys */ - keypad(stdscr, TRUE); + keypad(stdscr, TRUE); /* Clear anything that might be on the screen */ clear(); refresh(); diff --git a/menuconfig/main.h b/menuconfig/main.h index 88621beabf1..67fff17f5e8 100644 --- a/menuconfig/main.h +++ b/menuconfig/main.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -40,7 +40,8 @@ extern char *prev_prefix; extern WINDOW *menu_window; #define MAKE_CONF_FILE "Makefile.conf" -#define DEFAULT_INSTALL_PREFIX "/usr/" +#define MAKE_TEMP_FILE "Makefile.conf.template" +#define DEFAULT_INSTALL_PREFIX "/usr/local/" #define CONF_COMPILE_OPT "Configure Compile Options" #define CONF_EXCLUDED_MODS "Configure Excluded Modules" diff --git a/menuconfig/menus.c b/menuconfig/menus.c index 9c58f6bb990..412d1b69c24 100644 --- a/menuconfig/menus.c +++ b/menuconfig/menus.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -49,7 +49,7 @@ select_menu *find_menu(char *name,select_menu *menu) if (ret) return ret; } - + /* search through the siblings */ if (menu->next_sibling) return find_menu(name,menu->next_sibling); @@ -58,10 +58,10 @@ select_menu *find_menu(char *name,select_menu *menu) } /* Allocate & Init a menu with the passed name, flags, & actions - * + * * Returns a pointer to the menu or NULL in case of failure */ -select_menu *init_menu(char *menu_name,int flags,run_action action) +select_menu *init_menu(char *menu_name,int flags,run_action action) { select_menu *ret; int len; @@ -104,7 +104,7 @@ void link_sibling(select_menu *dest,select_menu *to_link) /* Link 'to_link' to 'dest' list of childs * also link all the childs as sibling between each other */ -void link_child(select_menu *dest,select_menu *to_link) +void link_child(select_menu *dest,select_menu *to_link) { if (dest->child == NULL) { dest->child = to_link; @@ -115,7 +115,7 @@ void link_child(select_menu *dest,select_menu *to_link) } } -/* Generate menu entries for all the types of +/* Generate menu entries for all the types of * cfg entries that have been added */ int gen_scripts_menu(select_menu *parent) @@ -172,7 +172,7 @@ int gen_scripts_menu(select_menu *parent) } /* Returns 1 if the menu parameter is a top level menu - * exiting such a menu will lead to exiting the curses app + * exiting such a menu will lead to exiting the curses app */ int is_top_menu(select_menu *menu) { @@ -185,7 +185,7 @@ int is_top_menu(select_menu *menu) } /* Execute menu's associated action when the user - * enters the menu + * enters the menu */ int exec_menu_action(select_menu *menu) { diff --git a/menuconfig/menus.h b/menuconfig/menus.h index c3b6f000907..178ece98859 100644 --- a/menuconfig/menus.h +++ b/menuconfig/menus.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -41,7 +41,7 @@ typedef struct sel_menu { int item_no; /* number of items in item_list. For fast detection of scrolling */ int child_changed; /* did any of the childs for this menu suffer any changes ? */ struct sel_menu *parent; /* parent of the current menu */ - struct sel_menu *child; /* select menus that this menu displays after selection */ + struct sel_menu *child; /* select menus that this menu displays after selection */ struct sel_menu *next_sibling; /* menus that should be shown along this menu */ struct sel_menu *prev_sibling; /* menus that should be shown along this menu */ } select_menu; diff --git a/menuconfig/parser.c b/menuconfig/parser.c index ac321d8e93c..cb794793f4c 100644 --- a/menuconfig/parser.c +++ b/menuconfig/parser.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -35,6 +35,7 @@ #define MENUCONFIG_CFG_PATH_LEN strlen(MENUCONFIG_CFG_PATH) static char prev_module[MAX_MODULE_NAME_SIZE]; +static int prev_module_len=0; static select_item *prev_item; /* Parses a single module dependency line */ @@ -56,8 +57,22 @@ int parse_dep_line(char *line,select_menu *parent) mod_name[name_len]=0; /* Is this still the previous module ? */ - if (memcmp(prev_module,mod_name,name_len) != 0) { - + if (name_len == prev_module_len && memcmp(prev_module,mod_name,name_len) == 0) { + /* Previously found module with multiple deps. + * Just add the new dependency */ + fprintf(output,"found prev module %s with extra deps\n",mod_name); + + mod_dep = p+1; + dep_len = (line+len) - mod_dep; + mod_dep[dep_len]=0; + + if (add_dependency(prev_item,mod_dep) < 0) { + fprintf(output,"Failed to add dependency\n"); + return -1; + } + } else { + fprintf(output,"found new module %s\n",mod_name); + /* nope, new module, get description */ mod_desc=p+1; p = memchr(mod_desc,'|',line+len-mod_desc); @@ -65,16 +80,16 @@ int parse_dep_line(char *line,select_menu *parent) fprintf(output,"Malformed desc line\n"); return -1; } - + desc_len = p-mod_desc; - mod_desc[desc_len]=0; - + mod_desc[desc_len]=0; + item = create_item(mod_name,mod_desc); if (item == NULL) { fprintf(output,"Failed to create item\n"); return -1; } - + mod_dep = p+1; dep_len = (line+len) - mod_dep; mod_dep[dep_len]=0; @@ -90,18 +105,7 @@ int parse_dep_line(char *line,select_menu *parent) prev_item = item; strcpy(prev_module,mod_name); - } else { - /* Previously found module with multiple deps. - * Just add the new dependency */ - - mod_dep = p+1; - dep_len = (line+len) - mod_dep; - mod_dep[dep_len]=0; - - if (add_dependency(prev_item,mod_dep) < 0) { - fprintf(output,"Failed to add dependency\n"); - return -1; - } + prev_module_len = name_len; } return 0; @@ -110,7 +114,7 @@ int parse_dep_line(char *line,select_menu *parent) /* Parse the include modules line */ int parse_include_line(char *line,select_menu *parent) { - char *p,*start,*end; + char *p,*start=NULL,*end; int len = strlen(line),mod_len=0; int found_mod=0; @@ -237,7 +241,7 @@ int parse_prefix_line(char *line,select_menu *menu) memcpy(install_prefix,p,pref_len); if (p[pref_len-1] != '/') install_prefix[pref_len-1]='/'; - + /* also init the prev prefix, used for * resetting changes */ prev_prefix=install_prefix; @@ -245,7 +249,7 @@ int parse_prefix_line(char *line,select_menu *menu) } /* Parse an m4 defs line for a cfg entry */ -#define READ_BUF_SIZE 512 +#define READ_BUF_SIZE 1024 static char read_buf[READ_BUF_SIZE]; int parse_defs_m4_line(char *line,select_menu *menu) { @@ -275,7 +279,7 @@ int parse_defs_m4_line(char *line,select_menu *menu) fprintf(output,"Failed to find macro value start\n"); return -1; } - + value_start++; value_end=memchr(value_start,'\'',line+len-value_start); if (!value_end) { @@ -355,9 +359,12 @@ int parse_make_conf() int defs=0; if (!conf) { - fprintf(output,"Failed to open [%s]\n",MAKE_CONF_FILE); - return -1; - + /* if we cannot find the Makefile.conf, try the template */ + conf = fopen(MAKE_TEMP_FILE, "r"); + if (!conf) { + fprintf(output,"Failed to open [%s]\n",MAKE_TEMP_FILE); + return -1; + } } state = PARSE_DEPENDENCIES; diff --git a/menuconfig/parser.h b/menuconfig/parser.h index 52f286407c6..141de8b8421 100644 --- a/menuconfig/parser.h +++ b/menuconfig/parser.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/mi/attr.c b/mi/attr.c index 24170bb4ad6..20cd3594091 100644 --- a/mi/attr.c +++ b/mi/attr.c @@ -26,7 +26,7 @@ */ /*! - * \file + * \file * \brief MI :: Attributes * \ingroup mi */ @@ -150,7 +150,7 @@ struct mi_attr *get_mi_attr_by_name(struct mi_node *node, char *name, int len) return NULL; for(head = node->attributes ; head->next ; head = head->next) - if(len == head->name.len + if(len == head->name.len && !strncasecmp(name, head->name.s, head->name.len)) return head; diff --git a/mi/attr.h b/mi/attr.h index c21dd3812eb..f9cdca8292d 100644 --- a/mi/attr.h +++ b/mi/attr.h @@ -26,7 +26,7 @@ */ /*! - * \file + * \file * \brief MI :: Attributes * \ingroup mi */ diff --git a/mi/fmt.c b/mi/fmt.c index 925a956d009..2cd347ab2d3 100644 --- a/mi/fmt.c +++ b/mi/fmt.c @@ -26,7 +26,7 @@ */ /*! - * \file + * \file * \brief MI :: Format handling * \ingroup mi */ diff --git a/mi/fmt.h b/mi/fmt.h index 868707b0546..023d9fd63ed 100644 --- a/mi/fmt.h +++ b/mi/fmt.h @@ -26,7 +26,7 @@ */ /*! - * \file + * \file * \brief MI :: Format handling * \ingroup mi */ diff --git a/mi/mi.c b/mi/mi.c index cf9b9d0741e..967bb6081af 100644 --- a/mi/mi.c +++ b/mi/mi.c @@ -26,15 +26,15 @@ */ /*! - * \file + * \file * \brief MI :: Attributes * \ingroup mi */ /*! * \defgroup mi OpenSIPS Management Interface - * - * The OpenSIPS management interface (MI) is a plugin architecture with a few different + * + * The OpenSIPS management interface (MI) is a plugin architecture with a few different * handlers that gives access to the management interface over various transports. * * The OpenSIPS core and modules register commands to the interface at runtime. @@ -229,7 +229,7 @@ struct mi_root *mi_help(struct mi_root *root, void *param) LM_ERR("cannot add new child\n"); goto error; } - if (cmd->module.len && cmd->module.s && + if (cmd->module.len && cmd->module.s && !add_mi_node_child(rpl, 0, "Exported by", 11, cmd->module.s, cmd->module.len)) { LM_ERR("cannot add new child\n"); diff --git a/mi/mi.h b/mi/mi.h index 4cfb0f29321..69014c8b073 100644 --- a/mi/mi.h +++ b/mi/mi.h @@ -26,7 +26,7 @@ */ /*! - * \file + * \file * \brief MI :: Management * \ingroup mi */ @@ -107,7 +107,7 @@ static inline struct mi_root* run_mi_cmd(struct mi_cmd *cmd, struct mi_root *t, crt_flush_param = param; ret = cmd->f( t, cmd->param); - + /* reset the flush function */ crt_flush_fnct = 0; crt_flush_param = 0; diff --git a/mi/mi_core.c b/mi/mi_core.c index 0e5925db4ce..b3e6b561b87 100644 --- a/mi/mi_core.c +++ b/mi/mi_core.c @@ -28,8 +28,8 @@ /*! - * \file - * \brief MI :: Core + * \file + * \brief MI :: Core * \ingroup mi */ @@ -186,6 +186,7 @@ static struct mi_root *mi_arg(struct mi_root *cmd, void *param) if (rpl_tree==0) return 0; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; for ( n=0; nnode; + rpl->flags |= MI_IS_ARRAY; get_mi_cmds( &cmds, &size); for ( i=0 ; inode; + rpl->flags |= MI_IS_ARRAY; for ( i=0 ; inode.kids; if (node!=NULL) { if (str2sint( &node->value, &new_debug) < 0) - return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM)); - } else - new_debug = *debug; -#else - new_debug = debug; -#endif + goto out_bad_param; - rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK)); - if (rpl_tree==0) - return 0; + node = node->next; + if (node && str2sint( &node->value, &pid) < 0) + goto out_bad_param; - p = sint2str((long)new_debug, &len); - node = add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, - MI_SSTR("DEBUG"),p, len); - if (node==0) { - free_mi_tree(rpl_tree); - return 0; + /* if called without arguments, print the table and exit */ + } else { + rpl_tree->node.flags |= MI_IS_ARRAY; + + for (i = 0; i < counted_processes; i++) { + node = add_mi_node_child(&rpl_tree->node, 0, MI_SSTR("Process"), 0, 0); + if (node==0) + goto out; + + p = int2str((unsigned long)pt[i].pid, &len); + if (!add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("PID"), p, len)) + goto out; + + p = sint2str((unsigned long)pt[i].debug, &len); + if (!add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Debug"), p, len)) + goto out; + + if (!add_mi_attr( node, 0, MI_SSTR("Type"), pt[i].desc, + strlen(pt[i].desc))) + goto out; + } + + return rpl_tree; } -#ifdef CHANGEABLE_DEBUG_LEVEL - *debug = new_debug; -#endif + p = sint2str((long)new_debug, &len); + if (pid) + node = add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, + MI_SSTR("New debug"), p, len); + else + node = add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, + MI_SSTR("New global debug"), p, len); + + if (node==0) + goto out; + + if (pid) { + /* convert pid to OpenSIPS id */ + i = id_of_pid(pid); + if (i == -1) + goto out_bad_param; + + __set_proc_default_debug(i, new_debug); + __set_proc_debug_level(i, new_debug); + } else + set_global_debug_level(new_debug); return rpl_tree; + +out_bad_param: + free_mi_tree(rpl_tree); + return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM)); + +out: + free_mi_tree(rpl_tree); + return NULL; } @@ -349,7 +394,7 @@ static struct mi_root *mi_cachestore(struct mi_root *cmd, void *param) LM_ERR( "empty memory cache system parameter\n"); return init_mi_tree(404, MI_SSTR("Empty memory cache id")); } - + node = node->next; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); @@ -360,7 +405,7 @@ static struct mi_root *mi_cachestore(struct mi_root *cmd, void *param) LM_ERR( "empty attribute name parameter\n"); return init_mi_tree(404, MI_SSTR("Empty attribute name")); } - + node = node->next; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); @@ -388,7 +433,7 @@ static struct mi_root *mi_cachestore(struct mi_root *cmd, void *param) return init_mi_tree(404, MI_SSTR("Bad format for expires argument")); } - + node = node->next; if(node!= NULL) return init_mi_tree(404, MI_SSTR("Too many parameters")); @@ -429,7 +474,7 @@ static struct mi_root *mi_cachefetch(struct mi_root *cmd, void *param) LM_ERR( "empty memory cache system parameter\n"); return init_mi_tree(404, MI_SSTR("Empty memory cache id")); } - + node = node->next; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); @@ -440,7 +485,7 @@ static struct mi_root *mi_cachefetch(struct mi_root *cmd, void *param) LM_ERR( "empty attribute name parameter\n"); return init_mi_tree(404,MI_SSTR( "Empty attribute name")); } - + node = node->next; if(node != NULL) return init_mi_tree(404, MI_SSTR("Too many arguments")); @@ -467,9 +512,9 @@ static struct mi_root *mi_cachefetch(struct mi_root *cmd, void *param) goto done; } - addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%.*s = [%.*s]", attr.len, + addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%.*s = [%.*s]", attr.len, attr.s, value.len, value.s); - + pkg_free(value.s); done: @@ -499,7 +544,7 @@ static struct mi_root *mi_cacheremove(struct mi_root *cmd, void *param) LM_ERR( "empty memory cache system parameter\n"); return init_mi_tree(404, MI_SSTR("Empty memory cache id")); } - + node = node->next; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); @@ -510,7 +555,7 @@ static struct mi_root *mi_cacheremove(struct mi_root *cmd, void *param) LM_ERR( "empty attribute name parameter\n"); return init_mi_tree(404, MI_SSTR("Empty attribute name")); } - + node = node->next; if(node != NULL) return init_mi_tree(404, MI_SSTR("Too many parameters")); @@ -544,6 +589,11 @@ static mi_export_t mi_core_cmds[] = { mi_kill, MI_NO_INPUT_FLAG, 0, 0 }, { "debug", "gets/sets the value of the debug core variable", mi_debug, 0, 0, 0 }, +#ifdef DBG_QM_MALLOC + { "shm_check", "complete scan of the shared memory pool " + "(if any error is found, OpenSIPS will abort!)", + mi_shm_check, MI_NO_INPUT_FLAG, 0, 0 }, +#endif { "cache_store", "stores in a cache system a string value", mi_cachestore, 0, 0, 0 }, { "cache_fetch", "queries for a cache stored value", diff --git a/mi/mi_core.h b/mi/mi_core.h index 64b227bfa7f..1b0886cf3ad 100644 --- a/mi/mi_core.h +++ b/mi/mi_core.h @@ -26,7 +26,7 @@ */ /*! - * \file + * \file * \brief MI :: Core * \ingroup mi */ diff --git a/mi/tree.c b/mi/tree.c index 65b71d35c60..48d6a38c662 100644 --- a/mi/tree.c +++ b/mi/tree.c @@ -26,8 +26,8 @@ */ /*! - * \file - * \brief MI :: Tree + * \file + * \brief MI :: Tree * \ingroup mi */ @@ -176,7 +176,7 @@ static inline struct mi_node *add_next(struct mi_node *brother, if(!brother) return NULL; - + new = create_mi_node(name, name_len, value, value_len, flags); if(!new) return NULL; diff --git a/mi/tree.h b/mi/tree.h index 7f4148fc89d..b5025d0d789 100644 --- a/mi/tree.h +++ b/mi/tree.h @@ -26,7 +26,7 @@ */ /*! - * \file + * \file * \brief MI :: Tree * \ingroup mi */ @@ -48,7 +48,8 @@ struct mi_handler; #define MI_DUP_NAME (1<<0) #define MI_DUP_VALUE (1<<1) #define MI_NOT_COMPLETED (1<<2) -#define MI_WRITTEN (1<<3) +#define MI_WRITTEN (1<<3) +#define MI_IS_ARRAY (1<<4) #define MI_OK_S "OK" #define MI_OK_LEN (sizeof(MI_OK_S)-1) @@ -65,6 +66,8 @@ struct mi_handler; #define MI_MISSING_PARM MI_MISSING_PARM_S #define MI_BAD_PARM MI_BAD_PARM_S +#define MI_DATE_BUF_LEN 21 + struct mi_node { str value; str name; diff --git a/mod_fix.c b/mod_fix.c index 22bbdb5dd70..b48506e91e1 100644 --- a/mod_fix.c +++ b/mod_fix.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -28,7 +28,6 @@ #include #include -#include #include "mem/mem.h" #include "str.h" @@ -66,17 +65,17 @@ int fixup_str(void** param) { str* s; - + s = (str*)pkg_malloc(sizeof(str)); if (!s) { LM_ERR("no more pkg memory\n"); return E_UNSPEC; } - + s->s = (char*)*param; s->len = strlen(s->s); *param = (void*)s; - + return 0; } @@ -203,7 +202,6 @@ int fixup_uint_uint(void** param, int param_no) return fixup_uint(param); } -#if 0 /*! \brief * - helper function * Convert char* parameter to signed int @@ -220,7 +218,7 @@ int fixup_sint( void** param) if(str2sint(&s, &si)==0) { pkg_free(*param); - *param=(void *)si; + *param=(void *)(unsigned long)si; return 0; } LM_ERR("bad number <%s>\n", (char *)(*param)); @@ -256,6 +254,7 @@ int fixup_sint_sint(void** param, int param_no) return fixup_sint(param); } +#if 0 /*! \brief * fixup for functions that get two parameters * - first parameter is converted to signed int @@ -316,6 +315,38 @@ static int fixup_regexp(void** param, int rflags) return 0; } +static int fixup_regexp_dynamic(void** param,int rflags) +{ + gparam_p gp; + int ret; + regex_t* re; + + ret = fixup_sgp(param); + if (ret < 0) + return ret; + + gp = (gparam_p)*param; + if (gp->type == GPARAM_TYPE_STR) { + /* we can compile the regex right now */ + if ((re=pkg_malloc(sizeof(regex_t)))==0) { + LM_ERR("no more pkg memory\n"); + return E_OUT_OF_MEM; + } + if (regcomp(re, gp->v.sval.s, (REG_EXTENDED|REG_ICASE|REG_NEWLINE)&(~rflags))) { + pkg_free(re); + LM_ERR("bad re %s\n", (char*)*param); + return E_BAD_RE; + } + /* replace it with the compiled re */ + gp->type=GPARAM_TYPE_REGEX; + gp->v.re=re; + return 0; + } + + /* regex will be compiled at runtime */ + return 0; +} + /*! \brief * - helper function: free the regular expression parameter */ @@ -344,6 +375,83 @@ int fixup_regexp_null(void** param, int param_no) return fixup_regexp(param, 0); } +/*! \brief + * fixup for functions that get one parameter + * - first parameter is converted to regular expression structure - accepts non-plaintext input + */ +int fixup_regexp_dynamic_null(void** param, int param_no) +{ + if(param_no != 1) + { + LM_ERR("invalid parameter number %d\n", param_no); + return E_UNSPEC; + } + return fixup_regexp_dynamic(param, 0); +} + +static char *re_buff=NULL; +static int re_buff_len = 0; +regex_t* fixup_get_regex(struct sip_msg* msg, gparam_p gp,int *do_free) +{ + pv_value_t value; + str val; + regex_t* ret_re; + + if(gp->type==GPARAM_TYPE_REGEX) { + /* pre-allocated at startup - just return it */ + if (do_free) + *do_free=0; + return gp->v.re; + } + if(gp->type==GPARAM_TYPE_PVS) { + if(pv_get_spec_value(msg, gp->v.pvs, &value)!=0 + || value.flags&PV_VAL_NULL || !(value.flags&PV_VAL_STR)){ + LM_ERR("no valid PV value found (error in scripts)\n"); + return NULL; + } + val = value.rs; + goto build_re; + } + if(gp->type==GPARAM_TYPE_PVE){ + if(pv_printf_s( msg, gp->v.pve, &val)!=0){ + LM_ERR("cannot print the PV-formated string\n"); + return NULL; + } + goto build_re; + } + + return NULL; + +build_re: + if (val.len + 1 > re_buff_len) { + re_buff = pkg_realloc(re_buff,val.len + 1); + if (re_buff == NULL) { + LM_ERR("No more pkg \n"); + return NULL; + } + + re_buff_len = val.len + 1; + } + + memcpy(re_buff,val.s,val.len); + re_buff[val.len] = 0; + + if ((ret_re=pkg_malloc(sizeof(regex_t)))==0) { + LM_ERR("no more pkg memory\n"); + return NULL; + } + + if (regcomp(ret_re, re_buff, (REG_EXTENDED|REG_ICASE|REG_NEWLINE))) { + pkg_free(ret_re); + LM_ERR("bad re %s\n", re_buff); + return NULL; + } + + if (do_free) + *do_free=1; + return ret_re; +} + /*! \brief * fixup for functions that get one parameter * - first parameter is converted to regular expression structure @@ -527,7 +635,7 @@ int fixup_free_pvar_pvar(void** param, int param_no) { LM_ERR("invalid parameter number %d\n", param_no); return E_UNSPEC; - } + } return fixup_free_pvar(param); } @@ -617,7 +725,7 @@ int fixup_igp(void** param) { str s; gparam_p gp = NULL; - + gp = (gparam_p)pkg_malloc(sizeof(gparam_t)); if(gp == NULL) { @@ -661,7 +769,7 @@ int fixup_sgp(void** param) { str s; gparam_p gp = NULL; - + gp = (gparam_p)pkg_malloc(sizeof(gparam_t)); if(gp == NULL) { @@ -809,8 +917,8 @@ int fixup_get_ivalue(struct sip_msg* msg, gparam_p gp, int *val) *val = gp->v.ival; return 0; } - - if(pv_get_spec_value(msg, gp->v.pvs, &value)!=0 + + if(pv_get_spec_value(msg, gp->v.pvs, &value)!=0 || value.flags&PV_VAL_NULL || !(value.flags&PV_VAL_INT)) { LM_ERR("no valid PV value found (error in scripts)\n"); @@ -828,7 +936,7 @@ int fixup_spve(void** param) { str s; gparam_p gp = NULL; - + gp = (gparam_p)pkg_malloc(sizeof(gparam_t)); if(gp == NULL) { @@ -850,7 +958,7 @@ int fixup_spve(void** param) gp->v.sval = s; } else { gp->type = GPARAM_TYPE_PVE; - } + } *param = (void*)gp; return 0; } @@ -898,7 +1006,7 @@ int fixup_spve_uint(void** param, int param_no) } if (param_no == 1) return fixup_spve(param); - + return fixup_uint(param); } @@ -915,10 +1023,10 @@ int fixup_get_svalue(struct sip_msg* msg, gparam_p gp, str *val) *val = gp->v.sval; return 0; } - + if(gp->type==GPARAM_TYPE_PVS) { - if(pv_get_spec_value(msg, gp->v.pvs, &value)!=0 + if(pv_get_spec_value(msg, gp->v.pvs, &value)!=0 || value.flags&PV_VAL_NULL || !(value.flags&PV_VAL_STR)) { LM_ERR("no valid PV value found (error in scripts)\n"); @@ -941,3 +1049,64 @@ int fixup_get_svalue(struct sip_msg* msg, gparam_p gp, str *val) return -1; } +/*! \brief + * - helper function + * Return string and/or int value from a gparam_t + */ +int fixup_get_isvalue(struct sip_msg* msg, gparam_p gp, + int *i_val, str *s_val, unsigned int *flags) +{ + pv_value_t value; + + *flags = 0; + switch(gp->type) + { + case GPARAM_TYPE_INT: + *i_val = gp->v.ival; + *flags |= GPARAM_INT_VALUE_FLAG; + break; + case GPARAM_TYPE_STR: + *s_val = gp->v.sval; + *flags |= GPARAM_STR_VALUE_FLAG; + break; + case GPARAM_TYPE_PVE: + if(pv_printf_s( msg, gp->v.pve, s_val)!=0) + { + LM_ERR("cannot print the PV-formated string\n"); + return -1; + } + *flags |= GPARAM_STR_VALUE_FLAG; + break; + case GPARAM_TYPE_PVS: + if(pv_get_spec_value(msg, gp->v.pvs, &value)!=0 + || value.flags&PV_VAL_NULL) + { + LM_ERR("no valid PV value found (error in scripts)\n"); + return -1; + } + if(value.flags&PV_VAL_INT) + { + *i_val = value.ri; + *flags |= GPARAM_INT_VALUE_FLAG; + } + if(value.flags&PV_VAL_STR) + { + *s_val = value.rs; + *flags |= GPARAM_STR_VALUE_FLAG; + } + break; + default: + LM_ERR("unexpected gp->type=[%d]\n", gp->type); + return -1; + } + + /* Let's convert to int, if possible */ + if (!(*flags & GPARAM_INT_VALUE_FLAG) && (*flags & GPARAM_STR_VALUE_FLAG) + && str2sint(s_val, i_val) == 0) + *flags |= GPARAM_INT_VALUE_FLAG; + + if (!*flags) return -1; + + return 0; +} + diff --git a/mod_fix.h b/mod_fix.h index 4b28ac983dc..d69ee9abd42 100644 --- a/mod_fix.h +++ b/mod_fix.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -29,11 +29,18 @@ #define _mod_fix_h_ #include "pvar.h" +#include #define GPARAM_TYPE_INT 0 #define GPARAM_TYPE_STR 1 #define GPARAM_TYPE_PVS 2 #define GPARAM_TYPE_PVE 3 +#define GPARAM_TYPE_FLAGS 4 +#define GPARAM_TYPE_REGEX 5 + +#define GPARAM_INT_VALUE_FLAG (1U<<0) +#define GPARAM_STR_VALUE_FLAG (1U<<1) + /*! * generic parameter that holds a string, an int or a pseudo-variable @@ -46,6 +53,7 @@ typedef struct _gparam str sval; pv_spec_t *pvs; pv_elem_t *pve; + regex_t *re; } v; } gparam_t, *gparam_p; @@ -58,19 +66,21 @@ int fixup_free_str_str(void** param, int param_no); int fixup_uint_null(void** param, int param_no); int fixup_uint_uint(void** param, int param_no); -#if 0 int fixup_sint_null(void** param, int param_no); int fixup_sint_sint(void** param, int param_no); +#if 0 int fixup_sint_uint(void** param, int param_no); int fixup_uint_sint(void** param, int param_no); #endif int fixup_regexp_null(void** param, int param_no); +int fixup_regexp_dynamic_null(void** param, int param_no); int fixup_regexpNL_null(void** param, int param_no); int fixup_free_regexp_null(void** param, int param_no); int fixup_regexp_none(void** param, int param_no); int fixup_regexpNL_none(void** param, int param_no); int fixup_free_regexp_none(void** param, int param_no); +int fixup_free_regexp(void** param); int fixup_pvar_null(void **param, int param_no); int fixup_free_pvar_null(void** param, int param_no); @@ -97,11 +107,15 @@ int fixup_spve_null(void** param, int param_no); int fixup_spve_uint(void** param, int param_no); int fixup_get_svalue(struct sip_msg* msg, gparam_p gp, str *val); - +int fixup_get_isvalue(struct sip_msg* msg, gparam_p gp, + int *i_val, str *s_val, unsigned int *flags); +regex_t* fixup_get_regex(struct sip_msg* msg, gparam_p gp,int *do_free); int fixup_spve(void** param); + int fixup_pvar(void **param); int fixup_str(void **param); int fixup_uint(void** param); +int fixup_sint(void** param); int fixup_igp(void** param); int fixup_sgp(void** param); diff --git a/modparam.c b/modparam.c index 2b91129ed10..d893a1eaf8b 100644 --- a/modparam.c +++ b/modparam.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -35,17 +35,17 @@ #include "modparam.h" #include "dprint.h" #include "mem/mem.h" +#include "ut.h" #include #include #include - int set_mod_param_regex(char* regex, char* name, modparam_t type, void* val) { struct sr_module* t; param_export_t* param; regex_t preg; - int mod_found, len; + int mod_found, param_found, len; char* reg; int n; @@ -61,48 +61,66 @@ int set_mod_param_regex(char* regex, char* name, modparam_t type, void* val) reg[len + 2] = ')'; reg[len + 3] = '$'; reg[len + 4] = '\0'; - + if (regcomp(&preg, reg, REG_EXTENDED | REG_NOSUB | REG_ICASE)) { LM_ERR("failed to compile regular expression\n"); pkg_free(reg); return -2; } - + mod_found = 0; for(t = modules; t; t = t->next) { if (regexec(&preg, t->exports->name, 0, 0, 0) == 0) { LM_DBG("%s matches module %s\n",regex, t->exports->name); mod_found = 1; + param_found = 0; + for(param=t->exports->params;param && param->name ; param++) { - if ((strcmp(name, param->name) == 0) && - ( PARAM_TYPE_MASK(param->type) == type)) { - LM_DBG("found <%s> in module %s [%s]\n", - name, t->exports->name, t->path); - - if (param->type&USE_FUNC_PARAM) { - n = ((param_func_t)(param->param_pointer))(type, val ); - if (n<0) - return -4; - } else { - switch(type) { - case STR_PARAM: - *((char**)(param->param_pointer)) = - strdup((char*)val); - break; - case INT_PARAM: - *((int*)(param->param_pointer)) = - (int)(long)val; - break; + + if (strcmp(name, param->name) == 0) { + param_found = 1; + + if (PARAM_TYPE_MASK(param->type) == type) { + LM_DBG("found <%s> in module %s [%s]\n", + name, t->exports->name, t->path); + + if (param->type&USE_FUNC_PARAM) { + n = ((param_func_t)(param->param_pointer))(type, val ); + if (n<0) + return -4; + } else { + switch(type) { + case STR_PARAM: + *((char**)(param->param_pointer)) = + strdup((char*)val); + break; + case INT_PARAM: + *((int*)(param->param_pointer)) = + (int)(long)val; + break; + } + } + + /* register any module deps imposed by this parameter */ + if (add_modparam_dependencies(t, param) != 0) { + LM_ERR("failed to add modparam dependencies!\n"); + return E_BUG; } - } - break; + break; + } } } + if (!param || !param->name) { - LM_ERR("parameter <%s> not found in module <%s>\n", - name, t->exports->name); + if (param_found) + LM_ERR("type mismatch for parameter <%s> in module <%s>\n", + name, t->exports->name); + else + LM_ERR("parameter <%s> not found in module <%s>\n", + name, t->exports->name); + regfree(&preg); pkg_free(reg); return -3; diff --git a/modparam.h b/modparam.h index 62482d51b8b..2353137b39f 100644 --- a/modparam.h +++ b/modparam.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/aaa_radius/README b/modules/aaa_radius/README index 3b80576a39c..394b4215fc7 100644 --- a/modules/aaa_radius/README +++ b/modules/aaa_radius/README @@ -2,7 +2,7 @@ AAA RADIUS MODULE Irina-Maria Stanescu - OpenSIPS + OpenSIPS Solutions Edited by @@ -13,8 +13,7 @@ Irina-Maria Stanescu Copyright © 2009 Voice Sistem SRL Revision History - Revision $Revision: 5908 $ $Date: 2009-07-21 16:56:23 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5908 $ $Date$ __________________________________________________________ Table of Contents @@ -29,15 +28,15 @@ Irina-Maria Stanescu 1.3. Exported Parameters - 1.3.1. sets - 1.3.2. radius_config - 1.3.3. syslog_name + 1.3.1. sets (string) + 1.3.2. radius_config (string) + 1.3.3. syslog_name (string) + 1.3.4. fetch_all_values (integer) 1.4. Exported Functions - 1.4.1. - radius_send_auth(input_set_name,output_set_nam - e) + 1.4.1. radius_send_auth(input_set_name, + output_set_name) 1.4.2. radius_send_acct(input_set_name) @@ -46,8 +45,9 @@ Irina-Maria Stanescu 1.1. Set sets parameter 1.2. Set radius_config parameter 1.3. Set syslog_name parameter - 1.4. radius_send_auth usage - 1.5. radius_send_acct usage + 1.4. Set fetch_all_values parameter + 1.5. radius_send_auth usage + 1.6. radius_send_acct usage Chapter 1. Admin Guide @@ -85,7 +85,7 @@ Chapter 1. Admin Guide 1.3. Exported Parameters -1.3.1. sets +1.3.1. sets (string) Sets of Radius AVPs to be used when building custom RADIUS requests (set of input RADIUS AVPs) or when fetching data from @@ -121,7 +121,7 @@ modparam("aaa_radius","sets","set2 = (Sip-Group = $var(sipgrup)) ") ... -1.3.2. radius_config +1.3.2. radius_config (string) Radiusclient configuration file. @@ -136,7 +136,7 @@ nt.conf") ... -1.3.3. syslog_name +1.3.3. syslog_name (string) Enable logging of the client library to syslog, using the given log name. @@ -154,9 +154,25 @@ nt.conf") modparam("aaa_radius", "syslog_name", "aaa-radius") ... +1.3.4. fetch_all_values (integer) + + For the output sets, this parameter controls if all the values + (for the same RADIUS AVP) should be returned (otherwise only + the first value will be returned). When enabling this options, + be sure that the variable you use to get the RADIUS output can + store multiple values (like the AVP variables). + + By default this parameter is disabled (set to 0) for backward + compatibility reasons. + + Example 1.4. Set fetch_all_values parameter +... +modparam("aaa_radius", "fetch_all_values", 1) +... + 1.4. Exported Functions -1.4.1. radius_send_auth(input_set_name,output_set_name) +1.4.1. radius_send_auth(input_set_name, output_set_name) This function can be used from the script to make custom radius authentication request. The function takes two parameters. @@ -180,7 +196,7 @@ modparam("aaa_radius", "syslog_name", "aaa-radius") This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE, ERROR_ROUTE and LOCAL_ROUTE. - Example 1.4. radius_send_auth usage + Example 1.5. radius_send_auth usage ... radius_send_auth("set1","set2"); @@ -213,7 +229,7 @@ switch ($rc) { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE, ERROR_ROUTE and LOCAL_ROUTE. - Example 1.5. radius_send_acct usage + Example 1.6. radius_send_acct usage ... radius_send_acct("set1"); diff --git a/modules/aaa_radius/aaa_radius.c b/modules/aaa_radius/aaa_radius.c index b928d1e1a00..8fb2a05db92 100644 --- a/modules/aaa_radius/aaa_radius.c +++ b/modules/aaa_radius/aaa_radius.c @@ -28,8 +28,8 @@ */ /* - * This is an implementation of the generic AAA Interface that also provides - * via script functions the possibility to run custom RADIUS requests and + * This is an implementation of the generic AAA Interface that also provides + * via script functions the possibility to run custom RADIUS requests and * to get information from the RADIUS reply. */ @@ -66,6 +66,7 @@ char* config_file = NULL; char* syslog_name = NULL; rc_handle *rh = NULL; DICT_ATTR *attr; +static int fetch_all_values = 0; int mod_init(void); int init_radius_handle(void); @@ -95,17 +96,20 @@ static cmd_export_t cmds[]= { static param_export_t params[] = { - {"sets", STR_PARAM|USE_FUNC_PARAM, parse_sets_func}, - {"radius_config", STR_PARAM, &config_file}, - {"syslog_name", STR_PARAM, &syslog_name}, + {"sets", STR_PARAM|USE_FUNC_PARAM, parse_sets_func}, + {"radius_config", STR_PARAM, &config_file}, + {"syslog_name", STR_PARAM, &syslog_name}, + {"fetch_all_values", INT_PARAM, &fetch_all_values}, {0, 0, 0} }; struct module_exports exports= { "aaa_radius", /* module name */ + MOD_TYPE_AAA, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -263,7 +267,7 @@ int make_send_message(struct sip_msg* msg, int index, VALUE_PAIR **send) { pv_get_spec_value(msg, mp->pv, &pt); if (pt.flags & PV_VAL_INT) { - //LM_DBG("%.*s---->%d---->%d---->%d\n",mp->name.len, mp->name.s, + //LM_DBG("%.*s---->%d---->%d---->%d\n",mp->name.len, mp->name.s, // pt.ri, mp->value, pt.flags); if (!rc_avpair_add(rh, send, ATTRID(mp->value), &pt.ri, -1, VENDOR(mp->value))) @@ -271,7 +275,7 @@ int make_send_message(struct sip_msg* msg, int index, VALUE_PAIR **send) { } else if (pt.flags & PV_VAL_STR) { - //LM_DBG("%.*s----->%.*s---->%d---->%d---->%d\n",mp->name.len, + //LM_DBG("%.*s----->%.*s---->%d---->%d---->%d\n",mp->name.len, // mp->name.s, pt.rs.len, pt.rs.s, mp->value, pt.flags, pt.rs.len); if (rc_dict_getattr(rh,mp->value)->type == PW_TYPE_IPADDR) { uint32_t ipaddr=rc_get_ipaddr(pt.rs.s); @@ -329,15 +333,16 @@ int send_auth_func(struct sip_msg* msg, str* s1, str* s2) { } res = rc_auth(rh, SIP_PORT, send, &recv, mess); - if (res!=OK_RC && res!=BADRESP_RC) { + if (res!=OK_RC && res!=REJECT_RC) { LM_ERR("radius authentication message failed with %s\n", - (res==TIMEOUT_RC)?"TIMEOUT":"ERROR"); + (res==TIMEOUT_RC)?"TIMEOUT":((res==BADRESP_RC)?"BAD REPLY":"ERROR")); }else{ LM_DBG("radius authentication message sent\n"); } for ( mp=sets[index2]->parsed; mp ; mp = mp->next) { - if ((vp = rc_avpair_get(recv, ATTRID(mp->value), VENDOR(mp->value)))) { + vp = recv; + while ( (vp=rc_avpair_get(vp, ATTRID(mp->value), VENDOR(mp->value)))!=NULL ) { memset(&pvt, 0, sizeof(pv_value_t)); if (vp->type == PW_TYPE_INTEGER) { pvt.flags = PV_VAL_INT|PV_TYPE_INT; @@ -352,8 +357,7 @@ int send_auth_func(struct sip_msg* msg, str* s1, str* s2) { if (pv_set_value(msg, mp->pv, (int)EQ_T, &pvt) < 0) { LM_ERR("setting avp failed....skipping\n"); } - } else { - LM_DBG("attribute was not found in received radius message\n"); + vp = fetch_all_values ? vp->next : NULL; } } @@ -362,9 +366,9 @@ int send_auth_func(struct sip_msg* msg, str* s1, str* s2) { for(; (vp = rc_avpair_get(vp, attr->value, 0)); vp = vp->next) extract_avp(vp); - if ( res!=OK_RC && res!=BADRESP_RC) + if ( res!=OK_RC && res!=REJECT_RC) goto error; - + if (send) rc_avpair_free(send); if (recv) rc_avpair_free(recv); diff --git a/modules/aaa_radius/doc/aaa_radius_admin.xml b/modules/aaa_radius/doc/aaa_radius_admin.xml index 7bfae0d1fd2..969ee48a055 100644 --- a/modules/aaa_radius/doc/aaa_radius_admin.xml +++ b/modules/aaa_radius/doc/aaa_radius_admin.xml @@ -72,7 +72,7 @@
Exported Parameters
- <varname>sets</varname> + <varname>sets (string)</varname> Sets of Radius AVPs to be used when building custom RADIUS requests (set of input RADIUS AVPs) or when fetching data from the RADIUS reply (set of output RADIUS AVPs). @@ -120,7 +120,7 @@ modparam("aaa_radius","sets","set2 = (Sip-Group = $var(sipgrup)) ")
- <varname>radius_config</varname> + <varname>radius_config (string)</varname> Radiusclient configuration file. @@ -141,7 +141,7 @@ modparam("aaa_radius", "radius_config", "/etc/radiusclient-ng/radiusclient.conf"
- <varname>syslog_name</varname> + <varname>syslog_name (string)</varname> Enable logging of the client library to syslog, using the given log name. @@ -160,6 +160,28 @@ modparam("aaa_radius", "radius_config", "/etc/radiusclient-ng/radiusclient.conf" ... modparam("aaa_radius", "syslog_name", "aaa-radius") ... + + +
+ +
+ <varname>fetch_all_values (integer)</varname> + + For the output sets, this parameter controls if all the values (for the same + RADIUS AVP) should be returned (otherwise only the first value will be + returned). When enabling this options, be sure that the variable you use + to get the RADIUS output can store multiple values (like the AVP variables). + + + By default this parameter is disabled (set to 0) for backward compatibility + reasons. + + + Set <varname>fetch_all_values</varname> parameter + +... +modparam("aaa_radius", "fetch_all_values", 1) +...
@@ -172,7 +194,7 @@ modparam("aaa_radius", "syslog_name", "aaa-radius")
- <function moreinfo="none">radius_send_auth(input_set_name,output_set_name)</function> + <function moreinfo="none">radius_send_auth(input_set_name, output_set_name)</function> This function can be used from the script to make custom diff --git a/modules/aaa_radius/rad.c b/modules/aaa_radius/rad.c index a48ee7818bc..1bab6d13544 100644 --- a/modules/aaa_radius/rad.c +++ b/modules/aaa_radius/rad.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -54,7 +54,7 @@ For Radius, initialization consists of: - the url is parsed and a configuration structure is obtained - - the rest field from the configuration structure is, for the radius + - the rest field from the configuration structure is, for the radius module, a string for the path of the radius configuration file - obtain the connection handle - initialize the dictionary diff --git a/modules/acc/README b/modules/acc/README index 102c5ec51b7..649dc5efe26 100644 --- a/modules/acc/README +++ b/modules/acc/README @@ -18,10 +18,9 @@ Irina-Maria Stanescu Copyright © 2004-2009 Voice Sistem SRL - Copyright © 2009-2013 OpenSIPS Solutions> + Copyright © 2009-2013 OpenSIPS Solutions Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -503,7 +502,7 @@ modparam("acc", "multi_leg_info", "leg_src=$avp(src);leg_dst=$avp(dst)") # for AAA-based accounting, use the names of the AAA AVPs modparam("acc", "multi_leg_info", - "AAA_LEG_SRC=$avp(src);AAA_LEG_SRC=$avp(dst)") + "AAA_LEG_SRC=$avp(src);AAA_LEG_DST=$avp(dst)") # for DIAMETER-based accounting, use the DIAMETER AVP ID (as integer) modparam("acc", "multi_leg_info", "2345=$avp(src);2346=$avp(dst)") @@ -1202,4 +1201,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/acc/acc.c b/modules/acc/acc.c index be07432d30a..85f8717b98b 100644 --- a/modules/acc/acc.c +++ b/modules/acc/acc.c @@ -110,7 +110,7 @@ extern struct acc_extra *db_extra_bye; extern int acc_log_facility; static int build_core_dlg_values(struct dlg_cell *dlg,struct sip_msg *req); -static int build_extra_dlg_values(struct acc_extra* extra, +static int build_extra_dlg_values(struct acc_extra* extra, struct dlg_cell *dlg,struct sip_msg *req, struct sip_msg *reply); static int build_leg_dlg_values(struct dlg_cell *dlg,struct sip_msg *req); static void complete_dlg_values(str *stored_values,str *val_arr,short nr_vals); @@ -474,7 +474,7 @@ static void acc_db_init_keys(void) VAL_NULL(db_vals + i)=0; } VAL_TYPE(db_vals+time_idx)=DB_DATETIME; - + if (dlg_api.get_dlg) { db_keys[n++] = &acc_duration_col; db_keys[n++] = &acc_setuptime_col; @@ -679,7 +679,7 @@ int acc_db_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) nr_bye_vals = legs2strar(leg_bye_info,msg,val_arr+ret+nr_vals, 0); } /* there were no Invite legs */ - while (nr_bye_vals) { + while (!nr_legs && nr_bye_vals) { /* drain all the values */ for (j = ret+nr_vals; jREQ_METHOD==METHOD_INVITE || rq->REQ_METHOD==METHOD_ACK) - && code>=200 && code<300) + && code>=200 && code<300) return AAA_ACCT_START; if ((rq->REQ_METHOD==METHOD_BYE || rq->REQ_METHOD==METHOD_CANCEL)) return AAA_ACCT_STOP; - if (code>=200 && code <=300) + if (code>=200 && code <=300) return AAA_ACCT_EVENT; return -1; @@ -1189,7 +1189,7 @@ int acc_diam_request( struct sip_msg *req, struct sip_msg *rpl) } /* SIP_MSGID AVP */ mid = req->id; - if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&mid), + if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&mid), sizeof(mid), AVP_DUPLICATE_DATA)) == 0) { LM_ERR("failed to create AVP:no more free memory!\n"); goto error; @@ -1201,7 +1201,7 @@ int acc_diam_request( struct sip_msg *req, struct sip_msg *rpl) } /* SIP Service AVP */ - if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_ACCOUNTING, + if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_ACCOUNTING, SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) { LM_ERR("failed to create AVP:no more free memory!\n"); goto error; @@ -1373,6 +1373,7 @@ int init_acc_evi(void) LM_ERR("no more pkg mem\n"); return -1; } + memset(acc_event_params, 0, sizeof(evi_params_t)); n = 0; EVI_CREATE_PARAM(acc_method_evi); @@ -1416,22 +1417,18 @@ int acc_evi_request( struct sip_msg *rq, struct sip_msg *rpl) int n; int i; int backup_idx = -1, ret = -1; - event_id_t event = EVI_ERROR; /* * if the code is not set, choose the missed calls event * otherwise, check if the code is negative */ - event = (!acc_env.code || acc_env.code > 300) ? - acc_missed_event : acc_event; - - if (event == EVI_ERROR) { + if (acc_env.event == EVI_ERROR) { LM_ERR("event not registered %d\n", acc_event); return -1; } /* check if someone is interested in this event */ - if (!evi_probe_event(event)) + if (!evi_probe_event(acc_env.event)) return 1; m = core2strar( rq, val_arr ); @@ -1465,7 +1462,7 @@ int acc_evi_request( struct sip_msg *rq, struct sip_msg *rpl) backup_idx = m - 1; evi_params[backup_idx]->next = NULL; - if (evi_raise_event(event, acc_event_params) < 0) { + if (evi_raise_event(acc_env.event, acc_event_params) < 0) { LM_ERR("cannot raise ACC event\n"); goto end; } @@ -1481,7 +1478,7 @@ int acc_evi_request( struct sip_msg *rq, struct sip_msg *rpl) backup_idx = i - 1; evi_params[backup_idx]->next = NULL; - if (evi_raise_event(event, acc_event_params) < 0) { + if (evi_raise_event(acc_env.event, acc_event_params) < 0) { LM_ERR("cannot raise ACC event\n"); goto end; } @@ -1521,7 +1518,7 @@ int acc_evi_cdrs(struct dlg_cell *dlg, struct sip_msg *msg) goto end; } - + LM_DBG("XXX: nr before extra is: %d\n", ret); ret = prebuild_extra_arr(dlg, msg, &extra_s, &evi_extra_str, evi_extra_bye, ret); @@ -1674,7 +1671,7 @@ int set_dlg_value(str *value) memcpy(cdr_buf.s + cdr_buf.len + 2, value->s, value->len); cdr_buf.len += value->len + 2; - + return 1; } @@ -1712,7 +1709,7 @@ int store_core_leg_values(struct dlg_cell *dlg, struct sip_msg *req) LM_ERR("cannot build legs value string\n"); return -1; } - + if (dlg_api.store_dlg_value(dlg,&leg_str,&cdr_buf) < 0) { LM_ERR("cannot store dialog string\n"); return -1; @@ -1750,7 +1747,7 @@ static int build_core_dlg_values(struct dlg_cell *dlg,struct sip_msg *req) for (i=0; i MAX_ACC_BUFS-2 /* last one is for legs */) { LM_ERR("Invalid buffer index %d - maximum %d\n", idx, MAX_ACC_BUFS-2); return 0; } - - if (!rq) { - /* no SIP message - probably internally terminated dialog - just nullify everything and skip them */ - for (n=0; extra ; extra=extra->next,n++) { - val_arr[n].s = 0; - val_arr[n].len = 0; + + if(rq == NULL) { + if (req == NULL) { + req = (struct sip_msg*)pkg_malloc(sizeof(struct sip_msg)); + if(req == NULL) + { + LM_ERR("No more memory\n"); + return -1; + } + memset(req, 0, sizeof(struct sip_msg)); + req->first_line.type = SIP_REQUEST; + req->first_line.u.request.method.s= "DUMMY"; + req->first_line.u.request.method.len= 5; + req->first_line.u.request.uri.s= "sip:user@domain.com"; + req->first_line.u.request.uri.len= 19; } - return n; + rq = req; } for( n=0,r=0 ; extra ; extra=extra->next,n++) { @@ -341,6 +350,8 @@ int extra2strar( struct acc_extra *extra, struct sip_msg *rq, } done: + if (rq == req) + free_sip_msg(req); return n; } diff --git a/modules/acc/acc_logic.c b/modules/acc/acc_logic.c index caba14fb330..f717639cbf9 100644 --- a/modules/acc/acc_logic.c +++ b/modules/acc/acc_logic.c @@ -1,6 +1,6 @@ /* * $Id$ - * + * * Accounting module logic * * Copyright (C) 2001-2003 FhG Fokus @@ -158,6 +158,11 @@ static inline void env_set_comment(struct acc_param *accp) acc_env.reason = accp->reason; } +static inline void env_set_event(event_id_t ev) +{ + acc_env.event = ev; +} + static inline int acc_preparse_req(struct sip_msg *req) { @@ -210,7 +215,7 @@ int w_acc_aaa_request(struct sip_msg *rq, pv_elem_t* comment, char* foo) int w_acc_db_request(struct sip_msg *rq, pv_elem_t* comment, char *table) { struct acc_param accp; - int table_len = strlen(table); + int table_len; if (!table) { LM_ERR("db support not configured\n"); @@ -220,11 +225,13 @@ int w_acc_db_request(struct sip_msg *rq, pv_elem_t* comment, char *table) if (acc_preparse_req(rq)<0) return -1; + table_len = strlen(table); + acc_pvel_to_acc_param(rq, comment, &accp); env_set_to( rq->to ); env_set_comment( &accp ); - env_set_text(table, strlen(table)); + env_set_text(table, table_len); if (table_len == db_table_mc.len && (strncmp(table, db_table_mc.s, table_len) == 0)) { return acc_db_request(rq, NULL, &mc_ins_list); @@ -303,6 +310,20 @@ int acc_pvel_to_acc_param(struct sip_msg* rq, pv_elem_t* pv_el, struct acc_param return 0; } +static inline int has_totag(struct sip_msg *msg) +{ + /* check if it has to tag */ + if ( (!msg->to && parse_headers(msg, HDR_TO_F,0)<0) || !msg->to ) { + LM_ERR("bad request or missing TO hdr :-/\n"); + return 0; + } + if (get_to(msg)->tag_value.s != 0 && get_to(msg)->tag_value.len != 0) + return 1; + return 0; +} + + + /* prepare message and transaction context for later accounting */ void acc_onreq( struct cell* t, int type, struct tmcb_params *ps ) { @@ -325,7 +346,7 @@ void acc_onreq( struct cell* t, int type, struct tmcb_params *ps ) ((is_invite && is_mc_on(ps->req))?TMCB_ON_FAILURE:0) ; /* if cdr accounting is enabled */ - if (is_cdr_acc_on(ps->req)) { + if (is_cdr_acc_on(ps->req) && !has_totag(ps->req)) { if (is_invite && create_acc_dlg(ps->req) < 0) { LM_ERR("cannot use dialog accounting module\n"); return; @@ -349,7 +370,7 @@ void acc_onreq( struct cell* t, int type, struct tmcb_params *ps ) static inline int should_acc_reply(struct sip_msg *req,struct sip_msg *rpl, int code) { - /* negative transactions reported otherwise only if explicitly + /* negative transactions reported otherwise only if explicitly * demanded */ if ( !is_failed_acc_on(req) && code >=300 ) return 0; @@ -402,10 +423,11 @@ static inline void on_missed(struct cell *t, struct sip_msg *req, /* we report on missed calls when the first * forwarding attempt fails; we do not wish to - * report on every attempt; so we clear the flags; + * report on every attempt; so we clear the flags; */ if (is_evi_mc_on(req)) { + env_set_event(acc_missed_event); acc_evi_request( req, reply ); flags_to_reset |= evi_missed_flag; } @@ -463,7 +485,7 @@ void acc_loaded_callback(struct dlg_cell *dlg, int type, LM_DBG("flags were not saved in dialog\n"); return; } - flags_l = (unsigned int)*flags_s.s; + flags_l = flag_list_to_bitmask(&flags_s, FLAG_TYPE_MSG, FLAG_DELIM); /* register database callbacks */ if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED | @@ -524,8 +546,8 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, } } - if (is_invite(t) && is_cdr_acc_on(req) && code >= 200 && code < 300 - && (dlg=dlg_api.get_dlg()) != NULL) { + if (is_invite(t) && !has_totag(req) && is_cdr_acc_on(req) && + code >= 200 && code < 300 && (dlg=dlg_api.get_dlg()) != NULL) { /* if dialog module loaded and INVITE and success reply */ if (store_core_leg_values(dlg, req) < 0) { LM_ERR("cannot store core and leg values\n"); @@ -552,16 +574,15 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, return; } - flags_s.s = (char*)&req->flags; - flags_s.len = sizeof(unsigned int); - - /* store flags into dlg */ + flags_s = bitmask_to_flag_list(FLAG_TYPE_MSG, req->flags); + + /* store flags into dlg */ if ( dlg_api.store_dlg_value(dlg, &flags_str, &flags_s) < 0) { LM_ERR("cannot store flag value into dialog\n"); return; } - /* store flags into dlg */ + /* store flags into dlg */ if ( dlg_api.store_dlg_value(dlg, &table_str, &table.s) < 0) { LM_ERR("cannot store the table name into dialog\n"); return; @@ -574,8 +595,10 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, } } else { /* do old accounting */ - if ( is_evi_acc_on(req) ) + if ( is_evi_acc_on(req) ) { + env_set_event(acc_event); acc_evi_request( req, reply ); + } if ( is_log_acc_on(req) ) { env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN); @@ -584,7 +607,7 @@ static inline void acc_onreply( struct cell* t, struct sip_msg *req, if (is_aaa_acc_on(req)) acc_aaa_request( req, reply ); - + if (is_db_acc_on(req)) { env_set_text( table.s.s, table.s.len); acc_db_request( req, reply, &acc_ins_list); @@ -616,7 +639,7 @@ static void acc_dlg_callback(struct dlg_cell *dlg, int type, flags = (unsigned int)(long)(*_params->param); if (flags & evi_flag) { - + env_set_event(acc_cdr_event); if (acc_evi_cdrs(dlg, _params->msg) < 0) { LM_ERR("cannot send accounting events\n"); return; diff --git a/modules/acc/acc_logic.h b/modules/acc/acc_logic.h index e2393d075d4..50f42a783d7 100644 --- a/modules/acc/acc_logic.h +++ b/modules/acc/acc_logic.h @@ -43,6 +43,7 @@ struct acc_enviroment { struct hdr_field *to; str text; time_t ts; + event_id_t event; }; /* param trasnporter*/ diff --git a/modules/acc/acc_mod.c b/modules/acc/acc_mod.c index 4a6b64132ff..70abfb4b407 100644 --- a/modules/acc/acc_mod.c +++ b/modules/acc/acc_mod.c @@ -1,6 +1,6 @@ /* * $Id$ - * + * * Accounting module * * Copyright (C) 2001-2003 FhG Fokus @@ -25,7 +25,7 @@ * History: * ------- * 2003-03-06: aligned to change in callback names (jiri) - * 2003-03-06: fixed improper sql connection, now from + * 2003-03-06: fixed improper sql connection, now from * child_init (jiri) * 2003-03-11: New module interface (janakj) * 2003-03-16: flags export parameter added (janakj) @@ -257,7 +257,7 @@ static param_export_t params[] = { {"evi_missed_flag", INT_PARAM, &evi_missed_flag }, {"evi_extra", STR_PARAM, &evi_extra_str }, {"evi_extra_bye", STR_PARAM, &evi_extra_bye_str }, - + /* DIAMETER specific */ #ifdef DIAM_ACC {"diameter_flag", STR_PARAM, &diameter_string }, @@ -289,11 +289,56 @@ static param_export_t params[] = { {0,0,0} }; +static module_dependency_t *get_deps_aaa_url(param_export_t *param) +{ + char *aaa_url = *(char **)param->param_pointer; + + if (!aaa_url || strlen(aaa_url) == 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_AAA, NULL, DEP_WARN); +} + +static module_dependency_t *get_deps_detect_dir(param_export_t *param) +{ + if (*(int *)param->param_pointer == 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_DEFAULT, "rr", DEP_ABORT); +} + +static module_dependency_t *get_deps_cdr_flag(param_export_t *param) +{ + if (param->type == STR_PARAM) { + char *str_flag = *(char **)param->param_pointer; + + if (!str_flag || strlen(str_flag) == 0) + return NULL; + } + + return alloc_module_dep(MOD_TYPE_DEFAULT, "dialog", DEP_WARN); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_url", get_deps_sqldb_url }, + { "aaa_url", get_deps_aaa_url }, + { "detect_direction", get_deps_detect_dir }, + { "cdr_flag", get_deps_cdr_flag }, + { NULL, NULL }, + }, +}; struct module_exports exports= { "acc", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported params */ 0, /* exported statistics */ @@ -331,7 +376,7 @@ static int acc_fixup(void** param, int param_no) } s.len = strlen(s.s); - + if(pv_parse_format(&s, &model)<0) { LM_ERR("wrong format[%s]\n", s.s); return E_UNSPEC; @@ -393,14 +438,14 @@ static int mod_init( void ) /* ----------- GENERIC INIT SECTION ----------- */ - fix_flag_name(&failed_transaction_string, failed_transaction_flag); + fix_flag_name(failed_transaction_string, failed_transaction_flag); failed_transaction_flag = get_flag_id_by_name(FLAG_TYPE_MSG, failed_transaction_string); if (flag_idx2mask(&failed_transaction_flag)<0) return -1; - fix_flag_name(&cdr_string, cdr_flag); + fix_flag_name(cdr_string, cdr_flag); cdr_flag = get_flag_id_by_name(FLAG_TYPE_MSG, cdr_string); @@ -440,13 +485,6 @@ static int mod_init( void ) return -1; } - /* load callbacks */ - if (cdr_flag && dlg_api.get_dlg && dlg_api.register_dlgcb(NULL, - DLGCB_LOADED,acc_loaded_callback, NULL, NULL) < 0) - LM_ERR("cannot register callback for dialog loaded - accounting " - "for ongoing calls will be lost after restart\n"); - - /* init the extra engine */ init_acc_extra(); @@ -473,14 +511,14 @@ static int mod_init( void ) return -1; } - fix_flag_name(&log_string, log_flag); + fix_flag_name(log_string, log_flag); log_flag = get_flag_id_by_name(FLAG_TYPE_MSG, log_string); if (flag_idx2mask(&log_flag)<0) return -1; - fix_flag_name(&log_missed_string, log_missed_flag); + fix_flag_name(log_missed_string, log_missed_flag); log_missed_flag = get_flag_id_by_name(FLAG_TYPE_MSG, log_missed_string); @@ -491,7 +529,7 @@ static int mod_init( void ) /* ------------ SQL INIT SECTION ----------- */ - if (db_url.s && db_url.len > 0) { + if (db_url.s) { /* parse the extra string, if any */ if (db_extra_str && (db_extra=parse_acc_extra(db_extra_str, 1))==0 ) { LM_ERR("failed to parse db_extra param\n"); @@ -502,20 +540,22 @@ static int mod_init( void ) LM_ERR("failed to parse db_extra_bye param\n"); return -1; } + if (acc_db_init(&db_url)<0){ - LM_ERR("failed...did you load a database module?\n"); + LM_ERR("failed! bad db url / missing db module ?\n"); return -1; } + /* fix the flags */ - fix_flag_name(&db_string, db_flag); - + fix_flag_name(db_string, db_flag); + db_flag = get_flag_id_by_name(FLAG_TYPE_MSG, db_string); if (flag_idx2mask(&db_flag)<0) return -1; - fix_flag_name(&db_missed_string, db_missed_flag); - + fix_flag_name(db_missed_string, db_missed_flag); + db_missed_flag = get_flag_id_by_name(FLAG_TYPE_MSG, db_missed_string); if (flag_idx2mask(&db_missed_flag)<0) @@ -553,15 +593,15 @@ static int mod_init( void ) } /* fix the flags */ - fix_flag_name(&aaa_string, aaa_flag); - + fix_flag_name(aaa_string, aaa_flag); + aaa_flag = get_flag_id_by_name(FLAG_TYPE_MSG, aaa_string); if (flag_idx2mask(&aaa_flag)<0) return -1; - fix_flag_name(&aaa_missed_string, aaa_missed_flag); - + fix_flag_name(aaa_missed_string, aaa_missed_flag); + aaa_missed_flag = get_flag_id_by_name(FLAG_TYPE_MSG, aaa_missed_string); if (flag_idx2mask(&aaa_missed_flag)<0) @@ -581,15 +621,15 @@ static int mod_init( void ) #ifdef DIAM_ACC /* fix the flags */ - fix_flag_name(&diameter_string, diameter_flag); - + fix_flag_name(diameter_string, diameter_flag); + diameter_flag = get_flag_id_by_name(FLAG_TYPE_MSG, diameter_string); if (flag_idx2mask(&diameter_flag)<0) return -1; - fix_flag_name(&diameter_missed_string, diameter_missed_flag); - + fix_flag_name(diameter_missed_string, diameter_missed_flag); + diameter_missed_flag=get_flag_id_by_name(FLAG_TYPE_MSG, diameter_missed_string); if (flag_idx2mask(&diameter_missed_flag)<0) @@ -621,15 +661,15 @@ static int mod_init( void ) } /* fix the flags */ - fix_flag_name(&evi_string, evi_flag); - + fix_flag_name(evi_string, evi_flag); + evi_flag = get_flag_id_by_name(FLAG_TYPE_MSG, evi_string); if (flag_idx2mask(&evi_flag)<0) return -1; - fix_flag_name(&evi_missed_string, evi_missed_flag); - + fix_flag_name(evi_missed_string, evi_missed_flag); + evi_missed_flag = get_flag_id_by_name(FLAG_TYPE_MSG, evi_missed_string); if (flag_idx2mask(&evi_missed_flag)<0) @@ -639,6 +679,14 @@ static int mod_init( void ) LM_ERR("cannot init acc events\n"); return -1; } + + /* load callbacks */ + if (cdr_flag && dlg_api.get_dlg && dlg_api.register_dlgcb(NULL, + DLGCB_LOADED,acc_loaded_callback, NULL, NULL) < 0) + LM_ERR("cannot register callback for dialog loaded - accounting " + "for ongoing calls will be lost after restart\n"); + + return 0; } @@ -656,7 +704,7 @@ static int child_init(int rank) LM_DBG("initializing TCP connection\n"); sockfd = init_mytcp(diameter_client_host, diameter_client_port); - if(sockfd==-1) + if(sockfd==-1) { LM_ERR("TCP connection not established\n"); return -1; diff --git a/modules/acc/diam_avp.c b/modules/acc/diam_avp.c index 0995a565714..3e85e768c85 100644 --- a/modules/acc/diam_avp.c +++ b/modules/acc/diam_avp.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -54,13 +54,13 @@ inline void set_avp_fields( AAA_AVPCode code, AAA_AVP *avp) case 293: /*AVP Destination Host*/ case 264: /*AVP_Origin_Host*/ case 296: /*AVP Origin_Realm*/ - case 400: /* AVP_Resource */ - case 401: /* AVP_Response */ - case 402: /* AVP_Chalenge */ + case 400: /* AVP_Resource */ + case 401: /* AVP_Response */ + case 402: /* AVP_Chalenge */ case 403: /* AVP_Method */ case 404: /* Service_Type AVP */ case 405: /* User_Group AVP*/ - case 279: + case 279: avp->flags = 0x40|(0x20&avp->flags); avp->type = AAA_AVP_STRING_TYPE; break; diff --git a/modules/acc/diam_dict.h b/modules/acc/diam_dict.h index de42ec73d74..299259ab721 100644 --- a/modules/acc/diam_dict.h +++ b/modules/acc/diam_dict.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/acc/diam_message.c b/modules/acc/diam_message.c index 152940a136c..31449041410 100644 --- a/modules/acc/diam_message.c +++ b/modules/acc/diam_message.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -341,7 +341,7 @@ void AAAPrintMessage( AAAMessage *msg) } } -AAAMessage* AAAInMessage(AAACommandCode cmdCode, +AAAMessage* AAAInMessage(AAACommandCode cmdCode, AAAApplicationId appID) { AAAMessage *msg; diff --git a/modules/acc/diam_message.h b/modules/acc/diam_message.h index 58d64278cc4..e40d2ed8e5e 100644 --- a/modules/acc/diam_message.h +++ b/modules/acc/diam_message.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -221,12 +221,12 @@ typedef enum { AVP_Termination_Cause = 295, AVP_Origin_Realm = 296, AVP_Resource = 400, - AVP_Response = 401, + AVP_Response = 401, AVP_Challenge = 402, AVP_Method = 403, AVP_Service_Type = 404, AVP_User_Group = 405, - AVP_SIP_MSGID = 406 + AVP_SIP_MSGID = 406 }AAA_AVPCodeNr; @@ -310,7 +310,7 @@ typedef struct _message_t { #define is_req(_msg_) \ (((_msg_)->flags)&0x80) -AAAMessage* AAAInMessage(AAACommandCode commandCode, +AAAMessage* AAAInMessage(AAACommandCode commandCode, AAAApplicationId applicationId); AAAReturnCode AAAFreeMessage( diff --git a/modules/acc/diam_tcp.c b/modules/acc/diam_tcp.c index 79d615aeb5f..8132197cc70 100644 --- a/modules/acc/diam_tcp.c +++ b/modules/acc/diam_tcp.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -43,23 +43,23 @@ #define M_NAME "acc" -/* TCP connection setup */ +/* TCP connection setup */ int init_mytcp(char* host, int port) { int sockfd; struct sockaddr_in serv_addr; struct hostent *server; - + sockfd = socket(PF_INET, SOCK_STREAM, 0); - - if (sockfd < 0) + + if (sockfd < 0) { LM_ERR("failed to create the socket\n"); return -1; - } - + } + server = resolvehost(host,0); - if (server == NULL) + if (server == NULL) { LM_ERR("failed to find the host\n"); return -1; @@ -70,19 +70,19 @@ int init_mytcp(char* host, int port) memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, server->h_length); serv_addr.sin_port = htons(port); - - if (connect(sockfd, (const struct sockaddr *)&serv_addr, - sizeof(serv_addr)) < 0) + + if (connect(sockfd, (const struct sockaddr *)&serv_addr, + sizeof(serv_addr)) < 0) { LM_ERR("failed to connec to the DIAMETER client\n"); return -1; - } + } return sockfd; } /* send a message over an already opened TCP connection */ -int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, +int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, unsigned int waited_id) { int n, number_of_tries; @@ -95,7 +95,7 @@ int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, unsigned int m_id; /* try to write the message to the Diameter client */ - while( (n=write(sockfd, buf, len))==-1 ) + while( (n=write(sockfd, buf, len))==-1 ) { if (errno==EINTR) continue; @@ -103,7 +103,7 @@ int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, return AAA_ERROR; } - if (n!=len) + if (n!=len) { LM_ERR("write gave no error but wrote less than asked\n"); return AAA_ERROR; @@ -142,12 +142,12 @@ int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, LM_ERR("failed to read from socket\n"); return AAA_CONN_CLOSED; } - + /* obtain the structure corresponding to the message */ - msg = AAATranslateMessage(rb->buf, rb->buf_len, 0); + msg = AAATranslateMessage(rb->buf, rb->buf_len, 0); if(!msg) { - LM_ERR("message structure not obtained\n"); + LM_ERR("message structure not obtained\n"); return AAA_ERROR; } avp = AAAFindMatchingAVP(msg, NULL, AVP_SIP_MSGID, @@ -219,7 +219,7 @@ int do_read( int socket, rd_buf_t *p) ptr = p->buf + p->buf_len; } - while( (n=recv( socket, ptr, wanted_len, MSG_DONTWAIT ))>0 ) + while( (n=recv( socket, ptr, wanted_len, MSG_DONTWAIT ))>0 ) { // LM_DBG("(sock=%d) -> n=%d (expected=%d)\n", p->sock,n,wanted_len); p->buf_len += n; @@ -229,7 +229,7 @@ int do_read( int socket, rd_buf_t *p) wanted_len -= n; ptr += n; } - else + else { if (p->buf==0) { @@ -285,22 +285,22 @@ void close_tcp_connection(int sfd) shutdown(sfd, 2); } -/* - * Extract URI depending on the request from To or From header +/* + * Extract URI depending on the request from To or From header */ int get_uri(struct sip_msg* m, str** uri) { - if ((REQ_LINE(m).method.len == 8) && - (memcmp(REQ_LINE(m).method.s, "REGISTER", 8) == 0)) + if ((REQ_LINE(m).method.len == 8) && + (memcmp(REQ_LINE(m).method.s, "REGISTER", 8) == 0)) {/* REGISTER */ - if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1) || !m->to )) + if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1) || !m->to )) { LM_ERR("the To header field was not found or malformed\n"); return -1; } *uri = &(get_to(m)->uri); - } - else + } + else { if (parse_from_header(m)<0) { diff --git a/modules/acc/diam_tcp.h b/modules/acc/diam_tcp.h index 72874236f2b..df7966e593f 100644 --- a/modules/acc/diam_tcp.h +++ b/modules/acc/diam_tcp.h @@ -49,7 +49,7 @@ typedef struct rd_buf #define MAX_AAA_MSG_SIZE 65536 -#define CONN_SUCCESS 1 +#define CONN_SUCCESS 1 #define CONN_ERROR -1 #define CONN_CLOSED -2 @@ -60,10 +60,10 @@ int sockfd; int do_read( int socket, rd_buf_t *p); void reset_read_buffer(rd_buf_t *rb); -/* it initializes the TCP connection */ +/* it initializes the TCP connection */ int init_mytcp(char* host, int port); /* send a message over an already opened TCP connection */ -int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, +int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, unsigned int waited_id); void close_tcp_connection(int sfd); diff --git a/modules/acc/doc/acc_admin.xml b/modules/acc/doc/acc_admin.xml index 0807badb4a1..3b66dce91c3 100644 --- a/modules/acc/doc/acc_admin.xml +++ b/modules/acc/doc/acc_admin.xml @@ -506,7 +506,7 @@ modparam("acc", "multi_leg_info", "leg_src=$avp(src);leg_dst=$avp(dst)") # for AAA-based accounting, use the names of the AAA AVPs modparam("acc", "multi_leg_info", - "AAA_LEG_SRC=$avp(src);AAA_LEG_SRC=$avp(dst)") + "AAA_LEG_SRC=$avp(src);AAA_LEG_DST=$avp(dst)") # for DIAMETER-based accounting, use the DIAMETER AVP ID (as integer) modparam("acc", "multi_leg_info", "2345=$avp(src);2346=$avp(dst)") diff --git a/modules/alias_db/README b/modules/alias_db/README index 00a60d39b8a..15257ee49c4 100644 --- a/modules/alias_db/README +++ b/modules/alias_db/README @@ -257,4 +257,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/alias_db/alias_db.c b/modules/alias_db/alias_db.c index a8deaf95c5c..63909cb23b8 100644 --- a/modules/alias_db/alias_db.c +++ b/modules/alias_db/alias_db.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * ALIAS_DB Module @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -96,12 +96,23 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* Module interface */ struct module_exports exports = { "alias_db", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ diff --git a/modules/alias_db/alias_db.h b/modules/alias_db/alias_db.h index 886ca2366d6..5f4f2425fea 100644 --- a/modules/alias_db/alias_db.h +++ b/modules/alias_db/alias_db.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * ALIAS_DB Module @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/alias_db/alookup.c b/modules/alias_db/alookup.c index 2a682f530e8..1ada47ed477 100644 --- a/modules/alias_db/alookup.c +++ b/modules/alias_db/alookup.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * ALIAS_DB Module @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -97,7 +97,7 @@ static int alias_db_query(struct sip_msg* _msg, char* _table, db_vals[1].nul = 0; db_vals[1].val.str_val.s = puri->host.s; db_vals[1].val.str_val.len = puri->host.len; - + if (domain_prefix.s && domain_prefix.len>0 && domain_prefix.lenhost.len && strncasecmp(puri->host.s,domain_prefix.s, @@ -134,20 +134,20 @@ static int alias_db_query(struct sip_msg* _msg, char* _table, user_s.len = 4; user_s.s = useruri_buf+4; switch(RES_ROWS(db_res)[i].values[0].type) - { + { case DB_STRING: - strcpy(user_s.s, + strcpy(user_s.s, (char*)RES_ROWS(db_res)[i].values[0].val.string_val); user_s.len += strlen(user_s.s); break; case DB_STR: - strncpy(user_s.s, + strncpy(user_s.s, (char*)RES_ROWS(db_res)[i].values[0].val.str_val.s, RES_ROWS(db_res)[i].values[0].val.str_val.len); user_s.len += RES_ROWS(db_res)[i].values[0].val.str_val.len; break; case DB_BLOB: - strncpy(user_s.s, + strncpy(user_s.s, (char*)RES_ROWS(db_res)[i].values[0].val.blob_val.s, RES_ROWS(db_res)[i].values[0].val.blob_val.len); user_s.len += RES_ROWS(db_res)[i].values[0].val.blob_val.len; @@ -159,29 +159,29 @@ static int alias_db_query(struct sip_msg* _msg, char* _table, } goto err_server; } - + /* add the @*/ useruri_buf[user_s.len] = '@'; user_s.len++; - + /* add the domain */ user_s.s = useruri_buf+user_s.len; switch(RES_ROWS(db_res)[i].values[1].type) - { + { case DB_STRING: - strcpy(user_s.s, + strcpy(user_s.s, (char*)RES_ROWS(db_res)[i].values[1].val.string_val); user_s.len += strlen(user_s.s); break; case DB_STR: - strncpy(user_s.s, + strncpy(user_s.s, (char*)RES_ROWS(db_res)[i].values[1].val.str_val.s, RES_ROWS(db_res)[i].values[1].val.str_val.len); user_s.len += RES_ROWS(db_res)[i].values[1].val.str_val.len; useruri_buf[user_s.len] = '\0'; break; case DB_BLOB: - strncpy(user_s.s, + strncpy(user_s.s, (char*)RES_ROWS(db_res)[i].values[1].val.blob_val.s, RES_ROWS(db_res)[i].values[1].val.blob_val.len); user_s.len += RES_ROWS(db_res)[i].values[1].val.blob_val.len; diff --git a/modules/alias_db/alookup.h b/modules/alias_db/alookup.h index f0a6857e5d1..c6014c5efc1 100644 --- a/modules/alias_db/alookup.h +++ b/modules/alias_db/alookup.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * ALIAS_DB Module @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/auth/README b/modules/auth/README index 1073c974784..bc3bbabd4f0 100644 --- a/modules/auth/README +++ b/modules/auth/README @@ -24,8 +24,7 @@ Jan Janak Copyright © 2005 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -125,7 +124,7 @@ Chapter 1. Admin Guide The module depends on the following modules (in the other words the listed modules must be loaded before this module): - * signalign -- Signaling module + * signaling -- Signaling module 1.3.2. External Libraries or Applications @@ -312,7 +311,7 @@ modparam("auth", "disable_nonce_check", 1) Example 1.11. www_challenge usage ... -if (www_authorize("siphub.net", "subscriber")) { +if (!www_authorize("siphub.net", "subscriber")) { www_challenge("siphub.net", "1"); }; ... @@ -475,7 +474,7 @@ append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes"); ... $var(username)="abc"; $avp(password)="xyz"; -if (pv_www_authorize("opensips.org")) { +if (!pv_www_authorize("opensips.org")) { www_challenge("opensips.org", "1"); }; ... diff --git a/modules/auth/api.c b/modules/auth/api.c index 4920c1bb50d..a672568e88c 100644 --- a/modules/auth/api.c +++ b/modules/auth/api.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -134,7 +134,7 @@ static inline int find_credentials(struct sip_msg* _m, str* _realm, } else break; } } - + /* * Credentials with given realm not found */ @@ -173,7 +173,7 @@ auth_result_t pre_auth(struct sip_msg* _m, str* _realm, hdr_types_t _hftype, } return ERROR; } - + *_realm = uri->host; strip_realm(_realm); } @@ -185,7 +185,7 @@ auth_result_t pre_auth(struct sip_msg* _m, str* _realm, hdr_types_t _hftype, ret = find_credentials(_m, _realm, _hftype, _h); if (ret < 0) { LM_ERR("failed to find credentials\n"); - if (send_resp(_m, (ret == -2) ? 500 : 400, + if (send_resp(_m, (ret == -2) ? 500 : 400, (ret == -2) ? &auth_500_err : &auth_400_err, 0, 0) == -1) { LM_ERR("failed to send 400 reply\n"); } @@ -242,8 +242,8 @@ auth_result_t post_auth(struct sip_msg* _m, struct hdr_field* _h) c = (auth_body_t*)((_h)->parsed); - if ((_m->REQ_METHOD == METHOD_ACK) || - (_m->REQ_METHOD == METHOD_CANCEL)) + if ((_m->REQ_METHOD == METHOD_ACK) || + (_m->REQ_METHOD == METHOD_CANCEL)) return AUTHORIZED; if(!disable_nonce_check) { @@ -287,9 +287,9 @@ int check_response(dig_cred_t* _cred, str* _method, char* _ha1) &(_cred->nc), &(_cred->cnonce), &(_cred->qop.qop_str), _cred->qop.qop_parsed == QOP_AUTHINT_D, _method, &(_cred->uri), hent, resp); - + LM_DBG("our result = \'%s\'\n", resp); - + /* * And simply compare the strings, the user is * authorized if they match diff --git a/modules/auth/api.h b/modules/auth/api.h index 7bf3751a372..26418e76157 100644 --- a/modules/auth/api.h +++ b/modules/auth/api.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -55,9 +55,9 @@ typedef enum auth_result { * we should really authenticate (there must be no authentication for * ACK and CANCEL */ -typedef auth_result_t (*pre_auth_t)(struct sip_msg* _m, str* _realm, +typedef auth_result_t (*pre_auth_t)(struct sip_msg* _m, str* _realm, hdr_types_t _hftype, struct hdr_field** _h); -auth_result_t pre_auth(struct sip_msg* _m, str* _realm, +auth_result_t pre_auth(struct sip_msg* _m, str* _realm, hdr_types_t _hftype, struct hdr_field** _h); diff --git a/modules/auth/auth_mod.c b/modules/auth/auth_mod.c index 80f399fe314..a7b983fdb12 100644 --- a/modules/auth/auth_mod.c +++ b/modules/auth/auth_mod.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Digest Authentication Module * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -27,7 +27,7 @@ * 2003-03-10 New module interface (janakj) * 2003-03-16 flags export parameter added (janakj) * 2003-03-19 all mallocs/frees replaced w/ pkg_malloc/pkg_free (andrei) - * 2003-04-28 rpid contributed by Juha Heinanen added (janakj) + * 2003-04-28 rpid contributed by Juha Heinanen added (janakj) * 2005-05-31 general avp specification added for rpid (bogdan) * 2006-03-01 pseudo variables support for domain name (bogdan) */ @@ -117,7 +117,7 @@ int* next_index= NULL; int disable_nonce_check = 0; /* - * Exported functions + * Exported functions */ static cmd_export_t cmds[] = { {"www_challenge", (cmd_function)www_challenge, 2, @@ -160,14 +160,25 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "auth", + "auth", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, params, 0, /* exported statistics */ @@ -305,7 +316,7 @@ static int mod_init(void) return -10; } memset(nonce_buf, 255, NBUF_LEN); - + sec_monit= (int*)shm_malloc((nonce_expire +1)* sizeof(int)); if(sec_monit== NULL) { @@ -355,7 +366,7 @@ static inline int auth_get_ha1(struct sip_msg *msg, struct username* _username, str* _domain, char* _ha1) { pv_value_t sval; - + /* get username from PV */ memset(&sval, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, &user_spec, &sval)==0) @@ -366,11 +377,11 @@ static inline int auth_get_ha1(struct sip_msg *msg, struct username* _username, pv_value_destroy(&sval); return 1; } - if(sval.rs.len!= _username->user.len - || strncasecmp(sval.rs.s, _username->user.s, sval.rs.len)) + if(sval.rs.len!= _username->whole.len + || strncasecmp(sval.rs.s, _username->whole.s, sval.rs.len)) { LM_DBG("username mismatch [%.*s] [%.*s]\n", - _username->user.len, _username->user.s, sval.rs.len, sval.rs.s); + _username->whole.len, _username->whole.s, sval.rs.len, sval.rs.s); pv_value_destroy(&sval); return 1; } @@ -399,7 +410,7 @@ static inline int auth_get_ha1(struct sip_msg *msg, struct username* _username, memcpy(_ha1, sval.rs.s, sval.rs.len); _ha1[sval.rs.len] = '\0'; } - + return 0; } diff --git a/modules/auth/auth_mod.h b/modules/auth/auth_mod.h index 634d6d02ada..0a3dd952deb 100644 --- a/modules/auth/auth_mod.h +++ b/modules/auth/auth_mod.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/auth/challenge.c b/modules/auth/challenge.c index e4eccbdb8b5..153ebd6b405 100644 --- a/modules/auth/challenge.c +++ b/modules/auth/challenge.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -76,7 +76,7 @@ static str auth_500_err = str_init(MESSAGE_500); /* * Create {WWW,Proxy}-Authenticate header field */ -static inline char *build_auth_hf(int _retries, int _stale, str* _realm, +static inline char *build_auth_hf(int _retries, int _stale, str* _realm, int* _len, int _qop, char* _hf_name) { int hf_name_len; @@ -107,7 +107,7 @@ static inline char *build_auth_hf(int _retries, int _stale, str* _realm, +DIGEST_MD5_LEN #endif +CRLF_LEN ; - + p=hf=pkg_malloc(*_len+1); if (!hf) { LM_ERR("no pkg memory left\n"); @@ -135,7 +135,7 @@ static inline char *build_auth_hf(int _retries, int _stale, str* _realm, #endif memcpy(p, CRLF, CRLF_LEN ); p+=CRLF_LEN; *p=0; /* zero terminator, just in case */ - + LM_DBG("'%s'\n", hf); return hf; } @@ -158,7 +158,7 @@ static inline int challenge(struct sip_msg* _msg, gparam_p _realm, int _qop, switch(_code) { case 401: - get_authorized_cred(_msg->authorization, &h); + get_authorized_cred(_msg->authorization, &h); hftype = HDR_AUTHORIZATION_T; break; case 407: @@ -191,7 +191,7 @@ static inline int challenge(struct sip_msg* _msg, gparam_p _realm, int _qop, strip_realm(&realm); } - auth_hf = build_auth_hf(0, (cred ? cred->stale : 0), &realm, + auth_hf = build_auth_hf(0, (cred ? cred->stale : 0), &realm, &auth_hf_len, _qop, _challenge_msg); if (!auth_hf) { LM_ERR("failed to generate nonce\n"); @@ -206,7 +206,7 @@ static inline int challenge(struct sip_msg* _msg, gparam_p _realm, int _qop, LM_ERR("failed to send the response\n"); return -1; } - + return 0; } @@ -242,8 +242,8 @@ int consume_credentials(struct sip_msg* _m, char* _s1, char* _s2) get_authorized_cred(_m->authorization, &h); if (!h) { get_authorized_cred(_m->proxy_auth, &h); - if (!h) { - if (_m->REQ_METHOD!=METHOD_ACK + if (!h) { + if (_m->REQ_METHOD!=METHOD_ACK && _m->REQ_METHOD!=METHOD_CANCEL) { LM_ERR("no authorized credentials found (error in scripts)\n"); } diff --git a/modules/auth/challenge.h b/modules/auth/challenge.h index 4857b187729..54af5e422b6 100644 --- a/modules/auth/challenge.h +++ b/modules/auth/challenge.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -29,7 +29,7 @@ #include "../../parser/msg_parser.h" -/* +/* * Challenge a user agent using WWW-Authenticate header field */ int www_challenge(struct sip_msg* _msg, char* _realm, char* _str2); diff --git a/modules/auth/common.c b/modules/auth/common.c index e83e83b6441..4d74e0c6e6a 100644 --- a/modules/auth/common.c +++ b/modules/auth/common.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -40,7 +40,7 @@ #include "common.h" -/* +/* * Return parsed To or From, host part of the parsed uri is realm */ int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri** _u) @@ -48,15 +48,15 @@ int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri** _u) if(_u==NULL) return -1; - if ((REQ_LINE(_m).method.len == 8) - && !memcmp(REQ_LINE(_m).method.s, "REGISTER", 8) + if ((REQ_LINE(_m).method.len == 8) + && !memcmp(REQ_LINE(_m).method.s, "REGISTER", 8) && (_hftype == HDR_AUTHORIZATION_T) ) { if (!_m->to && ((parse_headers(_m, HDR_TO_F, 0)==-1) || (!_m->to))) { LM_ERR("failed to parse TO headers\n"); return -1; } - + /* Body of To header field is parsed automatically */ if((*_u = parse_to_uri(_m))==NULL) return -1; @@ -68,7 +68,7 @@ int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri** _u) if((*_u = parse_from_uri(_m))==NULL) return -1; } - + return 0; } diff --git a/modules/auth/common.h b/modules/auth/common.h index c963d3b6f39..de018effd6f 100644 --- a/modules/auth/common.h +++ b/modules/auth/common.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -31,7 +31,7 @@ #define MESSAGE_500 "Server Internal Error" -/* +/* * Return parsed To or From, host part of the parsed uri is realm */ int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri** _u); diff --git a/modules/auth/doc/auth_admin.xml b/modules/auth/doc/auth_admin.xml index c5406f086fc..13635f51299 100644 --- a/modules/auth/doc/auth_admin.xml +++ b/modules/auth/doc/auth_admin.xml @@ -51,7 +51,7 @@ the listed modules must be loaded before this module): - signalign -- Signaling module + signaling -- Signaling module @@ -331,7 +331,7 @@ modparam("auth", "disable_nonce_check", 1) www_challenge usage ... -if (www_authorize("siphub.net", "subscriber")) { +if (!www_authorize("siphub.net", "subscriber")) { www_challenge("siphub.net", "1"); }; ... @@ -583,7 +583,7 @@ append_rpid_hf("", ";party=calling;id-type=subscriber;screen=yes"); ... $var(username)="abc"; $avp(password)="xyz"; -if (pv_www_authorize("opensips.org")) { +if (!pv_www_authorize("opensips.org")) { www_challenge("opensips.org", "1"); }; ... diff --git a/modules/auth/index.c b/modules/auth/index.c index c2347729e57..0b299bf601e 100644 --- a/modules/auth/index.c +++ b/modules/auth/index.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -135,7 +135,7 @@ int reserve_nonce_index(void) int is_nonce_index_valid(int index) { /* if greater than MAX_NONCE_INDEX ->error */ - + if(index>= MAX_NONCE_INDEX ) { LM_ERR("index greater than buffer length\n"); @@ -185,7 +185,7 @@ int is_nonce_index_valid(int index) LM_DBG("nonce already used\n"); goto error; } - + set_buf_bit(index); lock_release(nonce_lock); return 1; diff --git a/modules/auth/index.h b/modules/auth/index.h index 9ba32d2c90a..4d5218e5581 100644 --- a/modules/auth/index.h +++ b/modules/auth/index.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/auth/nonce.c b/modules/auth/nonce.c index 67980ea278a..859f6a86594 100644 --- a/modules/auth/nonce.c +++ b/modules/auth/nonce.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -50,13 +50,13 @@ static inline void integer2hex(char* _d, int _s) _s = htonl(_s); s = (char*)&_s; - + for (i = 0; i < 4; i++) { - + j = (s[i] >> 4) & 0xf; if (j <= 9) { _d[i * 2] = (j + '0'); - } else { + } else { _d[i * 2] = (j + 'a' - 10); } @@ -94,7 +94,7 @@ static inline int hex2integer(char* _s) /* * Calculate nonce value - * Nonce value consists of the expires time (in seconds since 1.1 1970) + * Nonce value consists of the expires time (in seconds since 1.1 1970) * and a secret phrase */ void calc_nonce(char* _nonce, int _expires, int _index, str* _secret) @@ -104,7 +104,7 @@ void calc_nonce(char* _nonce, int _expires, int _index, str* _secret) unsigned int offset = 8; MD5Init(&ctx); - + integer2hex(_nonce, _expires); @@ -163,7 +163,7 @@ int check_nonce(str* _nonce, str* _secret) calc_nonce(non, expires, index, _secret); - + LM_DBG("comparing [%.*s] and [%.*s]\n", _nonce->len, ZSW(_nonce->s), ((!disable_nonce_check)?NONCE_LEN:NONCE_LEN-8), non); if (!memcmp(non, _nonce->s, _nonce->len)) { @@ -176,7 +176,7 @@ int check_nonce(str* _nonce, str* _secret) /* * Check if a nonce is stale */ -int is_nonce_stale(str* _n) +int is_nonce_stale(str* _n) { if (!_n->s) return 0; diff --git a/modules/auth/nonce.h b/modules/auth/nonce.h index b93ddcbdf30..8f24a566d15 100644 --- a/modules/auth/nonce.h +++ b/modules/auth/nonce.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/auth/rfc2617.c b/modules/auth/rfc2617.c index e7f3a7439f2..4dea4d4ed47 100644 --- a/modules/auth/rfc2617.c +++ b/modules/auth/rfc2617.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -36,7 +36,7 @@ inline void cvt_hex(HASH _b, HASHHEX _h) { unsigned short i; unsigned char j; - + for (i = 0; i < HASHLEN; i++) { j = (_b[i] >> 4) & 0xf; if (j <= 9) { @@ -58,15 +58,15 @@ inline void cvt_hex(HASH _b, HASHHEX _h) } -/* - * calculate H(A1) as per spec +/* + * calculate H(A1) as per spec */ void calc_HA1(ha_alg_t _alg, str* _username, str* _realm, str* _password, str* _nonce, str* _cnonce, HASHHEX _sess_key) { MD5_CTX Md5Ctx; HASH HA1; - + MD5Init(&Md5Ctx); MD5Update(&Md5Ctx, _username->s, _username->len); MD5Update(&Md5Ctx, ":", 1); @@ -89,8 +89,8 @@ void calc_HA1(ha_alg_t _alg, str* _username, str* _realm, str* _password, } -/* - * calculate request-digest/response-digest as per HTTP Digest spec +/* + * calculate request-digest/response-digest as per HTTP Digest spec */ void calc_response(HASHHEX _ha1, /* H(A1) */ str* _nonce, /* nonce from server */ @@ -107,7 +107,7 @@ void calc_response(HASHHEX _ha1, /* H(A1) */ HASH HA2; HASH RespHash; HASHHEX HA2Hex; - + /* calculate H(A2) */ MD5Init(&Md5Ctx); MD5Update(&Md5Ctx, _method->s, _method->len); @@ -121,7 +121,7 @@ void calc_response(HASHHEX _ha1, /* H(A1) */ MD5Final(HA2, &Md5Ctx); cvt_hex(HA2, HA2Hex); - + /* calculate response */ MD5Init(&Md5Ctx); MD5Update(&Md5Ctx, _ha1, HASHHEXLEN); diff --git a/modules/auth/rfc2617.h b/modules/auth/rfc2617.h index fd216d781f7..116b6ff5242 100644 --- a/modules/auth/rfc2617.h +++ b/modules/auth/rfc2617.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -52,8 +52,8 @@ typedef enum { void cvt_hex(HASH Bin, HASHHEX Hex); -/* - * calculate H(A1) as per HTTP Digest spec +/* + * calculate H(A1) as per HTTP Digest spec */ void calc_HA1(ha_alg_t _alg, /* Type of algorithm */ str* _username, /* username */ diff --git a/modules/auth/rpid.c b/modules/auth/rpid.c index c728de731cb..f03e524c944 100644 --- a/modules/auth/rpid.c +++ b/modules/auth/rpid.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -98,7 +98,7 @@ static inline int is_e164(str* _user) { int i; char c; - + if ((_user->len > 2) && (_user->len < 17) && ((_user->s)[0] == '+')) { for (i = 1; i < _user->len; i++) { c = (_user->s)[i]; @@ -111,24 +111,24 @@ static inline int is_e164(str* _user) } -/* +/* * Copy of append_hf_helper from textops. */ static inline int append_rpid_helper(struct sip_msg* _m, str *_s) { struct lump* anchor; - + if (parse_headers(_m, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse message\n"); return -1; } - - anchor = anchor_lump(_m, _m->unparsed - _m->buf, 0, 0); + + anchor = anchor_lump(_m, _m->unparsed - _m->buf, 0); if (!anchor) { LM_ERR("can't get anchor\n"); return -2; } - + if (!insert_new_lump_before(anchor, _s->s, _s->len, 0)) { LM_ERR("can't insert lump\n"); return -3; diff --git a/modules/auth/rpid.h b/modules/auth/rpid.h index 81eb703435d..7b2b15da4a1 100644 --- a/modules/auth/rpid.h +++ b/modules/auth/rpid.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/auth_aaa/README b/modules/auth_aaa/README index 0e072ccdcc6..f022886d275 100644 --- a/modules/auth_aaa/README +++ b/modules/auth_aaa/README @@ -32,8 +32,7 @@ Irina-Maria Stanescu Copyright © 2005, 2009 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/auth_aaa/authaaa_mod.c b/modules/auth_aaa/authaaa_mod.c index 9c5a01de615..14b5cfee5ae 100644 --- a/modules/auth_aaa/authaaa_mod.c +++ b/modules/auth_aaa/authaaa_mod.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Digest Authentication - generic AAA support * @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -89,14 +89,26 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "auth", DEP_ABORT }, + { MOD_TYPE_AAA, NULL, DEP_WARN }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "auth_aaa", + "auth_aaa", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -143,7 +155,7 @@ static int mod_init(void) attrs[A_ACCT_SESSION_ID].name = "Acct-Session-Id"; vals[V_SIP_SESSION].name = "Sip-Session"; - fix_flag_name(&use_ruri_flag_str, use_ruri_flag); + fix_flag_name(use_ruri_flag_str, use_ruri_flag); use_ruri_flag = get_flag_id_by_name(FLAG_TYPE_MSG, use_ruri_flag_str); if (!aaa_proto_url) { @@ -233,7 +245,7 @@ static int auth_fixup(void** param, int param_no) return -1; } *param = (void*)sp; - } + } return 0; } diff --git a/modules/auth_aaa/authaaa_mod.h b/modules/auth_aaa/authaaa_mod.h index a4bfa69685a..f5ad82e43b4 100644 --- a/modules/auth_aaa/authaaa_mod.h +++ b/modules/auth_aaa/authaaa_mod.h @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/auth_aaa/authorize.c b/modules/auth_aaa/authorize.c index f0d11098e9b..b43b0702fe0 100644 --- a/modules/auth_aaa/authorize.c +++ b/modules/auth_aaa/authorize.c @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -43,14 +43,14 @@ #include "authaaa_mod.h" -/* - * Extract URI depending on the request from To or From header +/* + * Extract URI depending on the request from To or From header */ static inline int get_uri_user(struct sip_msg* _m, str** _uri_user) { struct sip_uri *puri; - if ((REQ_LINE(_m).method.len == 8) && + if ((REQ_LINE(_m).method.len == 8) && (memcmp(REQ_LINE(_m).method.s, "REGISTER", 8) == 0)) { if ((puri=parse_to_uri(_m))==NULL) { LM_ERR("failed to parse To header\n"); @@ -107,7 +107,7 @@ static inline int authorize(struct sip_msg* _msg, pv_elem_t* _realm, if (_uri_user) { if (pv_get_spec_value(_msg, _uri_user, &pv_val) == 0) { if (pv_val.flags & PV_VAL_STR) { - res = aaa_authorize_sterman(_msg, &cred->digest, + res = aaa_authorize_sterman(_msg, &cred->digest, &_msg->first_line.u.request.method, &pv_val.rs); } else { @@ -129,7 +129,7 @@ static inline int authorize(struct sip_msg* _msg, pv_elem_t* _realm, return AUTH_ERROR; } un_escape(uri_user, &user); - res = aaa_authorize_sterman(_msg, &cred->digest, + res = aaa_authorize_sterman(_msg, &cred->digest, &_msg->first_line.u.request.method, &user); pkg_free(user.s); diff --git a/modules/auth_aaa/authorize.h b/modules/auth_aaa/authorize.h index 1f1f6131e2d..201132a792d 100644 --- a/modules/auth_aaa/authorize.h +++ b/modules/auth_aaa/authorize.h @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/auth_aaa/sterman.c b/modules/auth_aaa/sterman.c index e10deecd9d3..2d321499b80 100644 --- a/modules/auth_aaa/sterman.c +++ b/modules/auth_aaa/sterman.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Digest Authentication - generic AAA support @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -83,7 +83,7 @@ static int add_cisco_vsa(aaa_message** send, struct sip_msg* msg) * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ -int aaa_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) +int aaa_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) { aaa_message *send, *received; uint32_t service; @@ -232,12 +232,12 @@ int aaa_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, } /* Add CALL-ID in Acct-Session-Id Attribute */ - if ( _msg->callid==NULL && + if ( _msg->callid==NULL && (parse_headers(_msg, HDR_CALLID_F, 0)==-1 || _msg->callid==NULL) ) { LM_ERR("msg parsing failed or callid not present"); goto err; } - if (proto.avp_add(conn, send, &attrs[A_ACCT_SESSION_ID], + if (proto.avp_add(conn, send, &attrs[A_ACCT_SESSION_ID], _msg->callid->body.s, _msg->callid->body.len, 0)) { LM_ERR("unable to add CALL-ID attribute\n"); goto err; @@ -268,7 +268,7 @@ int aaa_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, err: if (send) proto.destroy_aaa_message(conn, send); - if (received) + if (received) proto.destroy_aaa_message(conn, received); return -1; } diff --git a/modules/auth_aaa/sterman.h b/modules/auth_aaa/sterman.h index c5fc67376df..44719e33ccb 100644 --- a/modules/auth_aaa/sterman.h +++ b/modules/auth_aaa/sterman.h @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -39,6 +39,6 @@ * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ -int aaa_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user); +int aaa_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user); #endif /* STERMAN_H */ diff --git a/modules/auth_db/README b/modules/auth_db/README index fcc1345acca..8828d61dc40 100644 --- a/modules/auth_db/README +++ b/modules/auth_db/README @@ -23,8 +23,7 @@ Jan Janak Copyright © 2005 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -281,7 +280,7 @@ modparam("auth_db", "skip_version_check", 1) Example 1.10. www_authorize usage ... -if (www_authorize("siphub.net", "subscriber")) { +if (!www_authorize("siphub.net", "subscriber")) { www_challenge("siphub.net", "1"); }; ... diff --git a/modules/auth_db/aaa_avps.h b/modules/auth_db/aaa_avps.h index 2be5f9d3be2..887922e5bbd 100644 --- a/modules/auth_db/aaa_avps.h +++ b/modules/auth_db/aaa_avps.h @@ -105,7 +105,7 @@ static inline int parse_aaa_avps(char *definition, goto parse_error; t = foo.s[foo.len]; foo.s[foo.len] = '\0'; - + if (pv_parse_spec(&foo, &avp_spec)==0 || avp_spec.type!=PVT_AVP) { LM_ERR("malformed or non AVP %s AVP definition\n", foo.s); diff --git a/modules/auth_db/authdb_mod.c b/modules/auth_db/authdb_mod.c index 9c024813e9d..2b4edc5087a 100644 --- a/modules/auth_db/authdb_mod.c +++ b/modules/auth_db/authdb_mod.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Digest Authentication Module @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -136,14 +136,26 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "auth", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "auth_db", + "auth_db", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ diff --git a/modules/auth_db/authdb_mod.h b/modules/auth_db/authdb_mod.h index f4c2c721369..1c90c474401 100644 --- a/modules/auth_db/authdb_mod.h +++ b/modules/auth_db/authdb_mod.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/auth_db/authorize.c b/modules/auth_db/authorize.c index a9f879a45ef..d064c066ab9 100644 --- a/modules/auth_db/authorize.c +++ b/modules/auth_db/authorize.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * history: @@ -61,7 +61,8 @@ static inline int get_ha1(struct username* _username, str* _domain, db_val_t vals[2]; db_key_t *col; str result; - static db_ps_t auth_ps = NULL; + static db_ps_t auth_ha1_ps = NULL; + static db_ps_t auth_ha1b_ps = NULL; int n, nc; @@ -75,8 +76,13 @@ static inline int get_ha1(struct username* _username, str* _domain, keys[1] = &domain_column; /* should we calculate the HA1, and is it calculated with domain? */ - col[0] = (_username->domain.len && !calc_ha1) ? - (&pass_column_2) : (&pass_column); + if (_username->domain.len && !calc_ha1) { + col[0] = &pass_column_2 ; + CON_PS_REFERENCE(auth_db_handle) = &auth_ha1b_ps; + } else { + col[0] = &pass_column; + CON_PS_REFERENCE(auth_db_handle) = &auth_ha1_ps; + } for (n = 0, cred=credentials; cred ; n++, cred=cred->next) { col[1 + n] = &cred->attr_name; @@ -100,8 +106,6 @@ static inline int get_ha1(struct username* _username, str* _domain, return -1; } - CON_PS_REFERENCE(auth_db_handle) = &auth_ps; - n = (use_domain ? 2 : 1); nc = 1 + credentials_n; if (auth_dbf.query(auth_db_handle, keys, 0, vals, col, n, nc, 0, res) < 0) { diff --git a/modules/auth_db/authorize.h b/modules/auth_db/authorize.h index b5380e72545..c7bcfa89501 100644 --- a/modules/auth_db/authorize.h +++ b/modules/auth_db/authorize.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/auth_db/doc/auth_db_admin.xml b/modules/auth_db/doc/auth_db_admin.xml index b6ad9d3de36..9546c233234 100644 --- a/modules/auth_db/doc/auth_db_admin.xml +++ b/modules/auth_db/doc/auth_db_admin.xml @@ -342,7 +342,7 @@ modparam("auth_db", "skip_version_check", 1) <function moreinfo="none">www_authorize</function> usage ... -if (www_authorize("siphub.net", "subscriber")) { +if (!www_authorize("siphub.net", "subscriber")) { www_challenge("siphub.net", "1"); }; ... diff --git a/modules/auth_diameter/README b/modules/auth_diameter/README index a2545dc021f..8f8c09f4d5e 100644 --- a/modules/auth_diameter/README +++ b/modules/auth_diameter/README @@ -10,8 +10,7 @@ Elena-Ramona Modroiu Copyright © 2003, 2004 FhG FOKUS Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/auth_diameter/auth_diameter.c b/modules/auth_diameter/auth_diameter.c index 89a662ecbb0..8f994fc87fb 100644 --- a/modules/auth_diameter/auth_diameter.c +++ b/modules/auth_diameter/auth_diameter.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id$ * * Digest Authentication - Diameter support * @@ -11,20 +11,20 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version - * + * * opensips is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- - * - * + * + * * 2006-03-01 pseudo variables support for domain name (bogdan) */ @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "../../sr_module.h" #include "../../error.h" @@ -95,14 +95,25 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { "auth_diameter", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -129,24 +140,24 @@ static int mod_init(void) return -1; } - + return 0; } static int mod_child_init(int r) -{ +{ /* open TCP connection */ LM_DBG("initializing TCP connection\n"); sockfd = init_mytcp(diameter_client_host, diameter_client_port); - if(sockfd==-1) + if(sockfd==-1) { LM_DBG("the TCP connection was not established\n"); return -1; } LM_DBG("the TCP connection was established on socket=%d\n", sockfd); - + rb = (rd_buf_t*)pkg_malloc(sizeof(rd_buf_t)); if(!rb) { @@ -216,41 +227,41 @@ static int group_fixup(void** param, int param_no) { str* s; - if (param_no == 1) + if (param_no == 1) { - if (!strcasecmp((char*)*param, "Request-URI")) + if (!strcasecmp((char*)*param, "Request-URI")) { *param = (void*)1; goto end; - } + } - if(!strcasecmp((char*)*param, "To")) + if(!strcasecmp((char*)*param, "To")) { *param = (void*)2; goto end; - } + } - if (!strcasecmp((char*)*param, "From")) + if (!strcasecmp((char*)*param, "From")) { *param = (void*)3; goto end; - } + } - if (!strcasecmp((char*)*param, "Credentials")) + if (!strcasecmp((char*)*param, "Credentials")) { *param = (void*)4; goto end; } - + LM_ERR("unsupported Header Field identifier\n"); return E_UNSPEC; - - } - - if (param_no == 2) + + } + + if (param_no == 2) { s = (str*)pkg_malloc(sizeof(str)); - if (!s) + if (!s) { LM_ERR("no pkg memory left\n"); return E_UNSPEC; diff --git a/modules/auth_diameter/auth_diameter.h b/modules/auth_diameter/auth_diameter.h index 26b1630123c..665a92818f3 100644 --- a/modules/auth_diameter/auth_diameter.h +++ b/modules/auth_diameter/auth_diameter.h @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id$ * * Digest Authentication - Diameter support * @@ -11,20 +11,20 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version - * + * * opensips is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- - * - * + * + * */ #ifndef AUTHDIAM_MOD_H @@ -47,4 +47,4 @@ extern rd_buf_t *rb; #endif /* AUTHDIAM_MOD_H */ - + diff --git a/modules/auth_diameter/authorize.c b/modules/auth_diameter/authorize.c index 0d1055289a9..785c2a83304 100644 --- a/modules/auth_diameter/authorize.c +++ b/modules/auth_diameter/authorize.c @@ -11,14 +11,14 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version - * + * * opensips is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include /* memory management */ @@ -73,20 +73,20 @@ static str dia_500_err = str_init(MESSAGE_500); /* Extract URI depending on the request from To or From header */ int get_uri(struct sip_msg* m, str** uri) { - if ((REQ_LINE(m).method.len == 8) && - (memcmp(REQ_LINE(m).method.s, "REGISTER", 8) == 0)) - { + if ((REQ_LINE(m).method.len == 8) && + (memcmp(REQ_LINE(m).method.s, "REGISTER", 8) == 0)) + { /* REGISTER */ - if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1)|| (!m->to))) + if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1)|| (!m->to))) { LM_ERR("the To header field was not found or malformed\n"); - + /* it was a REGISTER and an error appeared when parsing TO header*/ return -1; } *uri = &(get_to(m)->uri); - } - else + } + else { if (parse_from_header(m)<0) { @@ -110,23 +110,23 @@ int get_realm(struct sip_msg* m, int hftype, struct sip_uri* u) /* extracting the uri */ if ((REQ_LINE(m).method.len==8) - && !memcmp(REQ_LINE(m).method.s, "REGISTER", 8) - && (hftype == HDR_AUTHORIZATION_T) ) - { + && !memcmp(REQ_LINE(m).method.s, "REGISTER", 8) + && (hftype == HDR_AUTHORIZATION_T) ) + { /* REGISTER */ - if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1) || (!m->to))) + if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1) || (!m->to))) { LM_ERR("failed to parse TO header\n"); /* signal the error */ return -1; } - + /* Body of To header field is parsed automatically */ - uri = get_to(m)->uri; - } - else + uri = get_to(m)->uri; + } + else { - if (parse_from_header(m)<0) + if (parse_from_header(m)<0) { LM_ERR("failed to parse FROM header\n"); /* signal the error */ @@ -135,20 +135,20 @@ int get_realm(struct sip_msg* m, int hftype, struct sip_uri* u) uri = get_from(m)->uri; } - + /* parsing the uri */ - if (parse_uri(uri.s, uri.len, u) < 0) + if (parse_uri(uri.s, uri.len, u) < 0) { LM_ERR("failed to parse URI\n"); return -1; } - + /* everything was OK */ return 0; } /* Find credentials with given realm in a SIP message header */ -int find_credentials(struct sip_msg* _m, str* _realm, int _hftype, +int find_credentials(struct sip_msg* _m, str* _realm, int _hftype, struct hdr_field** _h) { struct hdr_field** hook, *ptr, *prev; @@ -156,7 +156,7 @@ int find_credentials(struct sip_msg* _m, str* _realm, int _hftype, hdr_flags_t hdr_flags; str* r; - switch(_hftype) + switch(_hftype) { case HDR_AUTHORIZATION_T: hook = &(_m->authorization); @@ -173,64 +173,64 @@ int find_credentials(struct sip_msg* _m, str* _realm, int _hftype, } /* If the credentials haven't been parsed yet, do it now */ - if (*hook == 0) - if (parse_headers(_m, hdr_flags, 0) == -1) + if (*hook == 0) + if (parse_headers(_m, hdr_flags, 0) == -1) { LM_ERR("failed to parse headers\n"); return -1; } - + ptr = *hook; - /* Iterate through the credentials of the message to find - credentials with given realm + /* Iterate through the credentials of the message to find + credentials with given realm */ - while(ptr) + while(ptr) { res = parse_credentials(ptr); - if (res < 0) + if (res < 0) { LM_ERR("failed to parse credentials\n"); return (res == -1) ? -2 : -3; } - else - if (res == 0) + else + if (res == 0) { r = &(((auth_body_t*)(ptr->parsed))->digest.realm); - - if (r->len == _realm->len) + + if (r->len == _realm->len) { - if (!strncasecmp(_realm->s, r->s, r->len)) + if (!strncasecmp(_realm->s, r->s, r->len)) { *_h = ptr; return 0; } } } - + prev = ptr; - if (parse_headers(_m, hdr_flags, 1) == -1) + if (parse_headers(_m, hdr_flags, 1) == -1) { LM_ERR("failed to parse headers\n"); return -4; } - else - { - if (prev != _m->last_header) + else + { + if (prev != _m->last_header) { if (_m->last_header->type == _hftype) ptr = _m->last_header; else break; - } + } else break; } } - + /* Credentials with given realm not found */ return 1; } -auth_result_t diam_pre_auth(struct sip_msg* _m, str* _realm, int _hftype, +auth_result_t diam_pre_auth(struct sip_msg* _m, str* _realm, int _hftype, struct hdr_field** _h) { int ret; @@ -240,39 +240,39 @@ auth_result_t diam_pre_auth(struct sip_msg* _m, str* _realm, int _hftype, return AUTHORIZED; /* if no realm supplied, find out now */ - if (_realm==0 || _realm->len == 0) + if (_realm==0 || _realm->len == 0) { - if (get_realm(_m, _hftype, &uri) < 0) + if (get_realm(_m, _hftype, &uri) < 0) { LM_ERR("failed to extract realm\n"); - if (send_resp(_m, 400, &dia_400_err, 0, 0) == -1) + if (send_resp(_m, 400, &dia_400_err, 0, 0) == -1) { LM_ERR("failed to send 400 reply\n"); } return ERROR; } - + *_realm = uri.host; } ret = find_credentials(_m, _realm, _hftype, _h); - if (ret < 0) + if (ret < 0) { LM_ERR("credentials not found\n"); - if (send_resp(_m, (ret == -2) ? 500 : 400, - (ret == -2) ? &dia_500_err : &dia_400_err, 0, 0) == -1) + if (send_resp(_m, (ret == -2) ? 500 : 400, + (ret == -2) ? &dia_500_err : &dia_400_err, 0, 0) == -1) { LM_ERR("failed to send 400 reply\n"); } return ERROR; - } - else - if (ret > 0) + } + else + if (ret > 0) { LM_ERR("credentials with given realm not found\n"); return NO_CREDENTIALS; } - + return DO_AUTHORIZATION; } @@ -301,7 +301,7 @@ int authorize(struct sip_msg* msg, pv_elem_t* realm, int hftype) /* see what is to do after a first look at the message */ ret = diam_pre_auth(msg, &domain, hftype, &h); - switch(ret) + switch(ret) { case NO_CREDENTIALS: cred = NULL; break; @@ -311,50 +311,50 @@ int authorize(struct sip_msg* msg, pv_elem_t* realm, int hftype) default: return ret; } - if (get_uri(msg, &uri) < 0) + if (get_uri(msg, &uri) < 0) { LM_ERR("From/To URI not found\n"); return AUTH_ERROR; } - - if (parse_uri(uri->s, uri->len, &puri) < 0) + + if (parse_uri(uri->s, uri->len, &puri) < 0) { LM_ERR("failed to parse From/To URI\n"); return AUTH_ERROR; } // user.s = (char *)pkg_malloc(puri.user.len); // un_escape(&(puri.user), &user); - + /* parse the ruri, if not yet */ if(msg->parsed_uri_ok==0 && parse_sip_msg_uri(msg)<0) { LM_ERR("failed to parse the Request-URI\n"); return AUTH_ERROR; } - + /* preliminary check */ if(cred) { - if (puri.host.len != cred->digest.realm.len) + if (puri.host.len != cred->digest.realm.len) { - LM_DBG("credentials realm and URI host do not match\n"); + LM_DBG("credentials realm and URI host do not match\n"); return AUTH_ERROR; } - - if (strncasecmp(puri.host.s, cred->digest.realm.s, puri.host.len) != 0) + + if (strncasecmp(puri.host.s, cred->digest.realm.s, puri.host.len) != 0) { LM_DBG("credentials realm and URI host do not match\n"); return AUTH_ERROR; } } - + if( diameter_authorize(cred?h:NULL, &msg->first_line.u.request.method, puri, msg->parsed_uri, msg->id, rb) != 1) { send_resp(msg, 500, &dia_500_err, NULL, 0); return AUTH_ERROR; } - + if( srv_response(msg, rb, hftype) != 1 ) return AUTH_ERROR; @@ -367,19 +367,19 @@ int authorize(struct sip_msg* msg, pv_elem_t* realm, int hftype) /* * This function creates and submits diameter authentication request as per - * draft-srinivas-aaa-basic-digest-00.txt. + * draft-srinivas-aaa-basic-digest-00.txt. * Service type of the request is Authenticate-Only. * Returns: * 1 - success * -1 - error - * + * */ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, struct sip_uri ruri, unsigned int m_id, rd_buf_t* rb) { str user_name; AAAMessage *req; - AAA_AVP *avp, *position; + AAA_AVP *avp, *position; int name_flag, port_flag; dig_cred_t* cred; unsigned int tmp; @@ -419,7 +419,7 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, memcpy(user_name.s, uri.host.s, uri.host.len); } - if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, + if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, user_name.len, AVP_FREE_DATA)) == 0) { LM_ERR("no more pkg memory left!\n"); @@ -436,7 +436,7 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, else /* it is a SIP message with credentials */ { /* Add Username AVP */ - if (cred->username.domain.len>0) + if (cred->username.domain.len>0) { if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, cred->username.whole.s, cred->username.whole.len, AVP_DUPLICATE_DATA)) == 0) @@ -451,31 +451,31 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, goto error1; } } - else + else { user_name.s = 0; user_name.len = cred->username.user.len + cred->realm.len; if(user_name.len>0) { user_name.s = ad_malloc(user_name.len); - if (!user_name.s) + if (!user_name.s) { LM_ERR(" no more pkg memory left\n"); goto error; } - memcpy(user_name.s, cred->username.whole.s, + memcpy(user_name.s, cred->username.whole.s, cred->username.whole.len); if(cred->username.whole.len>0) { user_name.s[cred->username.whole.len] = '@'; - memcpy(user_name.s + cred->username.whole.len + 1, + memcpy(user_name.s + cred->username.whole.len + 1, cred->realm.s, cred->realm.len); } else memcpy(user_name.s, cred->realm.s, cred->realm.len); } - if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, + if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, user_name.len, AVP_FREE_DATA)) == 0) { LM_ERR(" no more pkg memory left!\n"); @@ -495,7 +495,7 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, /* SIP_MSGID AVP */ LM_DBG("******* m_id=%d\n", m_id); tmp = m_id; - if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&tmp), + if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&tmp), sizeof(m_id), AVP_DUPLICATE_DATA)) == 0) { LM_ERR(" no more pkg memory left!\n"); @@ -507,10 +507,10 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, goto error1; } - - + + /* SIP Service AVP */ - if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_AUTHENTICATION, + if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_AUTHENTICATION, SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) { LM_ERR(" no more pkg memory left!\n"); @@ -521,7 +521,7 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, LM_ERR(" avp not added \n"); goto error1; } - + /* Destination-Realm AVP */ if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, uri.host.s, uri.host.len, AVP_DUPLICATE_DATA)) == 0) @@ -530,8 +530,8 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, goto error; } -#ifdef DEBUG - LM_DBG("Destination Realm: %.*s\n", uri.host.len, uri.host.s); +#ifdef DEBUG + LM_DBG("Destination Realm: %.*s\n", uri.host.len, uri.host.s); #endif if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) @@ -539,7 +539,7 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, LM_ERR(" avp not added \n"); goto error1; } - + /* Resource AVP */ user_name.len = ruri.user.len + ruri.host.len + ruri.port.len + 2; user_name.s = (char*)ad_malloc(user_name.len*sizeof(char)); @@ -548,20 +548,20 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, name_flag= 0; if(ruri.user.s) - { + { name_flag = 1; memcpy(user_name.s+ruri.user.len, "@", 1); - } + } memcpy(user_name.s+ruri.user.len+name_flag, ruri.host.s, ruri.host.len); port_flag=0; if(ruri.port.s) { - port_flag = 1; + port_flag = 1; memcpy(user_name.s+ruri.user.len+ruri.host.len+1, ":", 1); - } - memcpy(user_name.s+ruri.user.len+ruri.host.len+name_flag+port_flag, + } + memcpy(user_name.s+ruri.user.len+ruri.host.len+name_flag+port_flag, ruri.port.s, ruri.port.len); #ifdef DEBUG LM_DBG(": AVP_Resource=%.*s\n", user_name.len, user_name.s); @@ -590,10 +590,10 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, LM_ERR(" no more pkg memory left!\n"); goto error; } - + position = AAAGetLastAVP(&(req->avpList)); if( AAAAddAVPToMessage(req, avp, position)!= AAA_ERR_SUCCESS) - + { LM_ERR(" avp not added \n"); goto error1; @@ -606,17 +606,17 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, LM_ERR(" no more pkg memory left!\n"); goto error; } - + position = AAAGetLastAVP(&(req->avpList)); if( AAAAddAVPToMessage(req, avp, position)!= AAA_ERR_SUCCESS) - + { LM_ERR(" avp not added \n"); goto error1; } - - } + + } #ifdef DEBUG AAAPrintMessage(req); #endif @@ -627,7 +627,7 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, LM_ERR(" message buffer not created\n"); goto error; } - + if(sockfd==AAA_NO_CONNECTION) { sockfd = init_mytcp(diameter_client_host, diameter_client_port); @@ -642,10 +642,10 @@ int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, switch( tcp_send_recv(sockfd, req->buf.s, req->buf.len, rb, m_id) ) { case AAA_ERROR: /* a transmission error occurred */ - LM_ERR(" message sending to the" + LM_ERR(" message sending to the" " DIAMETER backend authorization server failed\n"); goto error; - + case AAA_CONN_CLOSED: LM_NOTICE("connection to Diameter" " client closed.It will be reopened by the next request\n"); @@ -680,7 +680,7 @@ int srv_response(struct sip_msg* msg, rd_buf_t * rb, int hftype) { case AAA_AUTHORIZED: return 1; - + case AAA_NOT_AUTHORIZED: send_resp(msg, 403, &dia_403_err, NULL, 0); return -1; @@ -688,7 +688,7 @@ int srv_response(struct sip_msg* msg, rd_buf_t * rb, int hftype) case AAA_SRVERR: send_resp(msg, 500, &dia_500_err, NULL, 0); return -1; - + case AAA_CHALENGE: if(hftype==HDR_AUTHORIZATION_T) /* SIP server */ { @@ -698,7 +698,7 @@ int srv_response(struct sip_msg* msg, rd_buf_t * rb, int hftype) memcpy(auth_hf,WWW_AUTH_CHALLENGE, WWW_AUTH_CHALLENGE_LEN); memcpy(auth_hf+WWW_AUTH_CHALLENGE_LEN, rb->chall, rb->chall_len); - + ret = send_resp(msg, 401, &dia_401_err, auth_hf, auth_hf_len); } @@ -708,23 +708,23 @@ int srv_response(struct sip_msg* msg, rd_buf_t * rb, int hftype) auth_hf = (char*)ad_malloc(auth_hf_len*(sizeof(char))); memset(auth_hf, 0, auth_hf_len); memcpy(auth_hf, PROXY_AUTH_CHALLENGE, PROXY_AUTH_CHALLENGE_LEN); - memcpy(auth_hf + PROXY_AUTH_CHALLENGE_LEN, rb->chall, + memcpy(auth_hf + PROXY_AUTH_CHALLENGE_LEN, rb->chall, rb->chall_len); ret = send_resp(msg, 407, &dia_407_err, auth_hf, auth_hf_len); } if (auth_hf) pkg_free(auth_hf); - - if (ret == -1) + + if (ret == -1) { LM_ERR("failed to send challenge to the client of SER\n"); return -1; } return -1; } - - // never reach this - return -1; + + // never reach this + return -1; } diff --git a/modules/auth_diameter/authorize.h b/modules/auth_diameter/authorize.h index f813f71279a..e80a0e84f5a 100644 --- a/modules/auth_diameter/authorize.h +++ b/modules/auth_diameter/authorize.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Digest Authentication - Diameter support @@ -11,20 +11,20 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version - * + * * opensips is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- - * - * + * + * */ #ifndef DIAMETER_AUTHORIZE_H @@ -42,15 +42,15 @@ int get_uri(struct sip_msg* m, str** uri); int get_realm(struct sip_msg* m, int hftype, struct sip_uri* u); -auth_result_t diam_pre_auth(struct sip_msg* m, str* realm, int hftype, +auth_result_t diam_pre_auth(struct sip_msg* m, str* realm, int hftype, struct hdr_field** h); -int find_credentials(struct sip_msg* m, str* realm, int hftype, +int find_credentials(struct sip_msg* m, str* realm, int hftype, struct hdr_field** h); int authorize(struct sip_msg* msg, pv_elem_t* realm, int hftype); -int diameter_authorize(struct hdr_field* cred, str* p_method, +int diameter_authorize(struct hdr_field* cred, str* p_method, struct sip_uri uri, struct sip_uri ruri, unsigned int m_id, rd_buf_t *response); @@ -60,4 +60,4 @@ int send_resp(struct sip_msg* _m, int _code, str* _reason, char* _hdr, int _hdr_len); #endif /* DIAMETER_AUTHORIZE_H */ - + diff --git a/modules/auth_diameter/avp.c b/modules/auth_diameter/avp.c index 0f5a14c963a..9d88eac0af1 100644 --- a/modules/auth_diameter/avp.c +++ b/modules/auth_diameter/avp.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -49,9 +49,9 @@ inline void set_avp_fields( AAA_AVPCode code, AAA_AVP *avp) case 293: /*AVP Destination Host*/ case 264: /*AVP_Origin_Host*/ case 296: /*AVP Origin_Realm*/ - case 400: /* AVP_Resource */ - case 401: /* AVP_Response */ - case 402: /* AVP_Chalenge */ + case 400: /* AVP_Resource */ + case 401: /* AVP_Response */ + case 402: /* AVP_Chalenge */ case 403: /* AVP_Method */ case 404: /* Service_Type AVP */ case 405: /* User_Group AVP*/ diff --git a/modules/auth_diameter/defs.h b/modules/auth_diameter/defs.h index c7a86829dbb..b76c5a336c0 100644 --- a/modules/auth_diameter/defs.h +++ b/modules/auth_diameter/defs.h @@ -1,4 +1,4 @@ -#ifndef DIAMETER_DEFS +#ifndef DIAMETER_DEFS #define DIAMETER_DEFS #define vendorID 0 @@ -22,13 +22,13 @@ #define AAA_ERROR -1 #define AAA_CONN_CLOSED -2 #define AAA_TIMEOUT -3 -#define AAA_USER_IN_GROUP 0 +#define AAA_USER_IN_GROUP 0 #define AAA_NO_CONNECTION -1 #define WWW_AUTH_CHALLENGE_LEN 18 #define PROXY_AUTH_CHALLENGE_LEN 20 - + #define WWW_AUTH_CHALLENGE "WWW-Authenticate: " #define PROXY_AUTH_CHALLENGE "Proxy-Authenticate: " @@ -44,7 +44,7 @@ typedef struct rd_buf { /* used to return a parsed response */ int ret_code; - unsigned int chall_len; + unsigned int chall_len; unsigned char *chall; /* used to read the message*/ diff --git a/modules/auth_diameter/diameter_msg.h b/modules/auth_diameter/diameter_msg.h index 022ebbaf09a..c83482d998b 100644 --- a/modules/auth_diameter/diameter_msg.h +++ b/modules/auth_diameter/diameter_msg.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -222,12 +222,12 @@ typedef enum { AVP_Origin_Realm = 296, /* begin SIP AAA with DIAMETER*/ AVP_Resource = 400, - AVP_Response = 401, + AVP_Response = 401, AVP_Challenge = 402, AVP_Method = 403, AVP_Service_Type = 404, AVP_User_Group = 405, - AVP_SIP_MSGID = 406 + AVP_SIP_MSGID = 406 /* end SIP AAA with DIAMETER */ }AAA_AVPCodeNr; diff --git a/modules/auth_diameter/message.c b/modules/auth_diameter/message.c index bbbe605ba42..9cf2730dec2 100644 --- a/modules/auth_diameter/message.c +++ b/modules/auth_diameter/message.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -323,7 +323,7 @@ AAAMessage* AAAInMessage(AAACommandCode commandCode, AAAApplicationId appId) /* we allocate a new AAAMessage structure and set it to 0 */ msg = (AAAMessage*)ad_malloc(sizeof(AAAMessage)); - if (!msg) + if (!msg) { LM_ERR("no more pkg memory!\n"); return NULL; diff --git a/modules/auth_diameter/tcp_comm.c b/modules/auth_diameter/tcp_comm.c index 10486d5e5d3..d764b4762d6 100644 --- a/modules/auth_diameter/tcp_comm.c +++ b/modules/auth_diameter/tcp_comm.c @@ -11,20 +11,20 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version - * + * * opensips is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- - * - * + * + * */ #include @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include /* memory management */ @@ -53,23 +53,23 @@ #define MAX_TRIES 10 -/* it initializes the TCP connection */ +/* it initializes the TCP connection */ int init_mytcp(char* host, int port) { int sockfd; struct sockaddr_in serv_addr; struct hostent *server; - + sockfd = socket(PF_INET, SOCK_STREAM, 0); - - if (sockfd < 0) + + if (sockfd < 0) { LM_ERR("error creating the socket\n"); return -1; - } - + } + server = resolvehost(host,0); - if (server == NULL) + if (server == NULL) { LM_ERR("error finding the host\n"); return -1; @@ -80,14 +80,14 @@ int init_mytcp(char* host, int port) memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, server->h_length); serv_addr.sin_port = htons(port); - - if (connect(sockfd, (const struct sockaddr *)&serv_addr, - sizeof(serv_addr)) < 0) + + if (connect(sockfd, (const struct sockaddr *)&serv_addr, + sizeof(serv_addr)) < 0) { LM_ERR("error connecting to the " "DIAMETER client\n"); return -1; - } + } return sockfd; } @@ -127,7 +127,7 @@ int do_read( int socket, rd_buf_t *p) ptr = p->buf + p->buf_len; } - while( (n=recv( socket, ptr, wanted_len, MSG_DONTWAIT ))>0 ) + while( (n=recv( socket, ptr, wanted_len, MSG_DONTWAIT ))>0 ) { // LM_DBG("(sock=%d) -> n=%d (expected=%d)\n", p->sock,n,wanted_len); p->buf_len += n; @@ -137,7 +137,7 @@ int do_read( int socket, rd_buf_t *p) wanted_len -= n; ptr += n; } - else + else { if (p->buf==0) { @@ -189,7 +189,7 @@ int do_read( int socket, rd_buf_t *p) /* send a message over an already opened TCP connection */ -int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, +int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, unsigned int waited_id) { int n, number_of_tries; @@ -202,7 +202,7 @@ int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, unsigned int m_id; /* try to write the message to the Diameter client */ - while( (n=write(sockfd, buf, len))==-1 ) + while( (n=write(sockfd, buf, len))==-1 ) { if (errno==EINTR) continue; @@ -210,7 +210,7 @@ int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, return AAA_ERROR; } - if (n!=len) + if (n!=len) { LM_ERR("write gave no error but wrote less than asked\n"); return AAA_ERROR; @@ -251,12 +251,12 @@ int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, LM_ERR("connection closed by diameter client!\n"); return AAA_CONN_CLOSED; } - + /* obtain the structure corresponding to the message */ - msg = AAATranslateMessage(rb->buf, rb->buf_len, 0); + msg = AAATranslateMessage(rb->buf, rb->buf_len, 0); if(!msg) { - LM_ERR("message structure not obtained\n"); + LM_ERR("message structure not obtained\n"); return AAA_ERROR; } avp = AAAFindMatchingAVP(msg, NULL, AVP_SIP_MSGID, @@ -327,8 +327,8 @@ int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, default: /* error */ rb->ret_code = AAA_SRVERR; } - - return rb->ret_code; + + return rb->ret_code; } void close_tcp_connection(int sfd) { diff --git a/modules/auth_diameter/tcp_comm.h b/modules/auth_diameter/tcp_comm.h index 461bf9c5563..b5e64f8c248 100644 --- a/modules/auth_diameter/tcp_comm.h +++ b/modules/auth_diameter/tcp_comm.h @@ -11,20 +11,20 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version - * + * * opensips is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- - * - * + * + * */ #ifndef TCP_COMM_H @@ -37,7 +37,7 @@ #define MAX_AAA_MSG_SIZE 65536 -#define CONN_SUCCESS 1 +#define CONN_SUCCESS 1 #define CONN_ERROR -1 #define CONN_CLOSED -2 @@ -45,7 +45,7 @@ void reset_read_buffer(rd_buf_t *rb); int do_read( int socket, rd_buf_t *p); -/* it initializes the TCP connection */ +/* it initializes the TCP connection */ int init_mytcp(char* host, int port); /* send a message over an already opened TCP connection */ diff --git a/modules/auth_diameter/user_in.c b/modules/auth_diameter/user_in.c index 03c295fb14c..5c6ffd6a97c 100644 --- a/modules/auth_diameter/user_in.c +++ b/modules/auth_diameter/user_in.c @@ -11,20 +11,20 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version - * + * * opensips is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- - * - * + * + * */ #include @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include /* memory management */ @@ -63,15 +63,15 @@ static inline int get_to_uri(struct sip_msg* m, str* u) { // check that the header field is there and is parsed - if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1)|| (!m->to))) + if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1)|| (!m->to))) { LM_ERR("can't get To header field\n"); return -1; } - + u->s = ((struct to_body*)m->to->parsed)->uri.s; u->len = ((struct to_body*)m->to->parsed)->uri.len; - + return 0; } @@ -84,7 +84,7 @@ static inline int get_from_uri(struct sip_msg* m, str* u) LM_ERR("failed to parse From body\n"); return -1; } - + u->s = ((struct to_body*)m->from->parsed)->uri.s; u->len = ((struct to_body*)m->from->parsed)->uri.len; @@ -100,7 +100,7 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) struct hdr_field* h; struct sip_uri puri; AAAMessage *req; - AAA_AVP *avp; + AAA_AVP *avp; int ret; unsigned int tmp; @@ -112,14 +112,14 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) uri.len = 0; /* extract the uri according with the _hf parameter */ - switch(hf_type) + switch(hf_type) { case 1: /* Request-URI */ uri = *(GET_RURI(_m)); break; case 2: /* To */ - if (get_to_uri(_m, &uri) < 0) + if (get_to_uri(_m, &uri) < 0) { LM_ERR("failed to extract To\n"); return -2; @@ -127,7 +127,7 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) break; case 3: /* From */ - if (get_from_uri(_m, &uri) < 0) + if (get_from_uri(_m, &uri) < 0) { LM_ERR("failed to extract From URI\n"); return -3; @@ -136,10 +136,10 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) case 4: /* Credentials */ get_authorized_cred(_m->authorization, &h); - if (!h) + if (!h) { get_authorized_cred(_m->proxy_auth, &h); - if (!h) + if (!h) { LM_ERR("no authorized credentials found " "(error in scripts)\n"); @@ -150,22 +150,22 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) break; } - if (hf_type != 4) + if (hf_type != 4) { - if (parse_uri(uri.s, uri.len, &puri) < 0) + if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse URI\n"); return -5; } user = puri.user; domain = puri.host; - } + } else { user = cred->username.user; domain = cred->realm; } - + /* user@domain mode */ if (use_domain) { @@ -175,12 +175,12 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) { user_name.len++; user_name.s = (char*)pkg_malloc(user_name.len); - if (!user_name.s) + if (!user_name.s) { LM_ERR("no pkg memory left\n"); return -6; } - + memcpy(user_name.s, user.s, user.len); if(user.len>0) { @@ -190,17 +190,17 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) else memcpy(user_name.s, domain.s, domain.len); } - } - else + } + else user_name = user; - - + + if ( (req=AAAInMessage(AA_REQUEST, AAA_APP_NASREQ))==NULL) { LM_ERR("can't create new AAA message!\n"); return -1; } - + /* Username AVP */ if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, user_name.len, AVP_DUPLICATE_DATA)) == 0) @@ -230,7 +230,7 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) /* SIP_MSGID AVP */ LM_DBG("******* m_id=%d\n", _m->id); tmp = _m->id; - if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&tmp), + if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&tmp), sizeof(tmp), AVP_DUPLICATE_DATA)) == 0) { LM_ERR("no more pkg memory!\n"); @@ -242,9 +242,9 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) goto error1; } - + /* ServiceType AVP */ - if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_GROUP_CHECK, + if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_GROUP_CHECK, SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) { LM_ERR("no more pkg memory!\n"); @@ -255,7 +255,7 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) LM_ERR("avp not added \n"); goto error1; } - + /* Destination-Realm AVP */ uri = *(GET_RURI(_m)); @@ -266,13 +266,13 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) LM_ERR("no more pkg memory!\n"); goto error; } - + if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) { LM_ERR("avp not added \n"); goto error1; } - + #ifdef DEBUG AAAPrintMessage(req); #endif @@ -310,7 +310,7 @@ int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group) "failed or user is not in group\n"); goto error; } - + AAAFreeMessage(&req); return 1; diff --git a/modules/avpops/README b/modules/avpops/README index 9a3463f783e..e50fedc2366 100644 --- a/modules/avpops/README +++ b/modules/avpops/README @@ -12,8 +12,7 @@ Ramona-Elena Modroiu Copyright © 2004-2008 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -43,7 +42,7 @@ Ramona-Elena Modroiu 1.5. Exported Functions - 1.5.1. avp_db_load(source,name[,db_id]) + 1.5.1. avp_db_load(source, name[, db_id[, prefix]]) 1.5.2. avp_db_store(source,name[,db_id]) 1.5.3. avp_db_delete(source,name[,db_id]) 1.5.4. avp_db_query(query[[,dest],db_id]) @@ -280,13 +279,16 @@ modparam("avpops", "buf_size", 1024) 1.5. Exported Functions -1.5.1. avp_db_load(source,name[,db_id]) +1.5.1. avp_db_load(source, name[, db_id[, prefix]]) Loads from DB into memory the AVPs corresponding to the given source. If given, it sets the script flags for loaded AVPs. It returns true if it loaded some values in AVPs, false otherwise (db error, no avp loaded ...). + AVPs may be preceded by an optional prefix, in order to avoid + some conflicts. + Meaning of the parameters is as follows: * source - what info is used for identifying the AVPs. Parameter syntax: @@ -308,18 +310,26 @@ modparam("avpops", "buf_size", 1024) naming format' chapter. * db_id - reference to a defined DB URL (a numerical id) - see the “db_url” module parameter. + * prefix - static string which will precede the names of the + AVPs populated by this function. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, LOCAL_ROUTE and ONREPLY_ROUTE. Example 1.13. avp_db_load usage ... -avp_db_load("$fu","$avp(678)"); -avp_db_load("$ru/domain","i/domain_preferences"); -avp_db_load("$avp(uuid)","$avp(404fwd)/fwd_table"); -avp_db_load("$ru","$avp(123)/$some_scheme"); +avp_db_load("$fu", "$avp(678)"); +avp_db_load("$ru/domain", "i/domain_preferences"); +avp_db_load("$avp(uuid)", "$avp(404fwd)/fwd_table"); +avp_db_load("$ru", "$avp(123)/$some_scheme"); + # use DB URL id 3 -avp_db_load("$ru","$avp(1)","3"); +avp_db_load("$ru", "$avp(1)", "3"); + +# precede all loaded AVPs by the "caller_" prefix +avp_db_load("$ru", "$avp(100)", "", "caller_"); +xlog("Loaded: $avp(caller_100)\n"); + ... 1.5.2. avp_db_store(source,name[,db_id]) diff --git a/modules/avpops/avpops.c b/modules/avpops/avpops.c index b9f9c6deac2..394a1e80b59 100644 --- a/modules/avpops/avpops.c +++ b/modules/avpops/avpops.c @@ -82,7 +82,7 @@ static int fixup_insert_avp(void** param, int param_no); static int w_print_avps(struct sip_msg* msg, char* foo, char *bar); static int w_dbload_avps(struct sip_msg* msg, char* source, - char* param, char* url); + char* param, char *url, char *prefix); static int w_dbdelete_avps(struct sip_msg* msg, char* source, char* param, char* url); static int w_dbstore_avps(struct sip_msg* msg, char* source, @@ -110,6 +110,9 @@ static cmd_export_t cmds[] = { {"avp_db_load", (cmd_function)w_dbload_avps, 3, fixup_db_load_avp, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE| STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, + {"avp_db_load", (cmd_function)w_dbload_avps, 4, fixup_db_load_avp, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"avp_db_delete", (cmd_function)w_dbdelete_avps, 2, fixup_db_delete_avp, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE| STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, @@ -177,11 +180,22 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_url", get_deps_sqldb_url }, + { NULL, NULL }, + }, +}; struct module_exports exports = { "avpops", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -263,6 +277,49 @@ static int fixup_db_url(void ** param) return 0; } +/* parse the name avp again when adding an avp name prefix (param 4) */ +struct db_param *dbp_fixup; + +static int fixup_avp_prefix(void **param) +{ + str st, *name, *prefix; + char *p; + + prefix = pkg_malloc(sizeof(*prefix)); + if (!prefix) { + LM_ERR("No more pkg\n"); + return -1; + } + + prefix->s = (char *)*param; + prefix->len = strlen(prefix->s); + + name = get_avp_name_id(dbp_fixup->a.u.sval.pvp.pvn.u.isname.name.n); + + if (name && dbp_fixup->a.type == AVPOPS_VAL_PVAR) { + + p = pkg_malloc(name->len + prefix->len + 7); + if (!p) { + LM_ERR("No more pkg mem!\n"); + return -1; + } + + memcpy(p, "$avp(", 5); + memcpy(p + 5, prefix->s, prefix->len); + memcpy(p + 5 + prefix->len, name->s, name->len); + p[name->len + prefix->len + 5] = ')'; + p[name->len + prefix->len + 6] = '\0'; + + st.s = p; + st.len = prefix->len + name->len + 6; + + pv_parse_spec(&st, &dbp_fixup->a.u.sval); + } + + *param = prefix; + + return 0; +} static int fixup_db_avp(void** param, int param_no, int allow_scheme) { @@ -329,7 +386,7 @@ static int fixup_db_avp(void** param, int param_no, int allow_scheme) "expected : $pseudo-variable or int/str value\n"); return E_UNSPEC; } - + if(sp->u.sval.type==PVT_RURI || sp->u.sval.type==PVT_FROM || sp->u.sval.type==PVT_TO || sp->u.sval.type==PVT_OURI) { @@ -353,9 +410,13 @@ static int fixup_db_avp(void** param, int param_no, int allow_scheme) LM_ERR("parse failed\n"); return E_UNSPEC; } + + dbp_fixup = dbp; *param=(void*)dbp; } else if (param_no==3) { return fixup_db_url(param); + } else if (param_no==4) { + return fixup_avp_prefix(param); } return 0; @@ -404,7 +465,7 @@ static int fixup_db_query_avp(void** param, int param_no) LM_ERR("wrong format[%s]\n", s.s); return E_UNSPEC; } - + *param = (void*)model; return 0; } else if(param_no==2) { @@ -443,7 +504,7 @@ static int fixup_delete_avp(void** param, int param_no) /* attribute name / alias */ if ( (p=strchr(s,'/'))!=0 ) *(p++)=0; - + if(*s=='$') { /* is variable */ @@ -647,7 +708,7 @@ static int fixup_pushto_avp(void** param, int param_no) break; case PVT_HDR: /* what's the hdr destination ? request or reply? */ - LM_ERR("push to header is obsoleted - use append_hf() " + LM_ERR("push to header is obsolete - use append_hf() " "or append_to_reply() from textops module!\n"); return E_UNSPEC; break; @@ -786,7 +847,7 @@ static int fixup_subst(void** param, int param_no) struct fis_param **av; char *s; char *p; - + if (param_no==1) { s = (char*)*param; ap = 0; @@ -795,7 +856,7 @@ static int fixup_subst(void** param, int param_no) if(av==NULL) { LM_ERR("no more pkg memory\n"); - return E_UNSPEC; + return E_UNSPEC; } memset(av, 0, 2*sizeof(struct fis_param*)); @@ -826,7 +887,7 @@ static int fixup_subst(void** param, int param_no) *param=(void*)av; return 0; } - + /* dst || flags */ s = p; if(*s==PV_MARKER) @@ -841,7 +902,7 @@ static int fixup_subst(void** param, int param_no) LM_ERR("unable to get pseudo-variable in param 2 [%s]\n",s); return E_OUT_OF_MEM; } - + if (ap->u.sval.type!=PVT_AVP) { LM_ERR("bad attribute name <%s>!\n", s); @@ -862,7 +923,7 @@ static int fixup_subst(void** param, int param_no) return 0; } } - + /* flags */ for( ; p&&*p ; p++ ) { @@ -915,7 +976,7 @@ static int fixup_op_avp(void** param, int param_no) if(av==NULL) { LM_ERR("no more pkg memory\n"); - return E_UNSPEC; + return E_UNSPEC; } memset(av, 0, 2*sizeof(struct fis_param*)); /* avp src / avp dst */ @@ -939,7 +1000,7 @@ static int fixup_op_avp(void** param, int param_no) *param=(void*)av; return 0; } - + s = p; ap = avpops_parse_pvar(s); if (ap==0) @@ -979,20 +1040,20 @@ static int fixup_is_avp_set(void** param, int param_no) struct fis_param *ap; char *p; char *s; - + s = (char*)(*param); if (param_no==1) { /* attribute name | alias / flags */ if ( (p=strchr(s,'/'))!=0 ) *(p++)=0; - + ap = avpops_parse_pvar(s); if (ap==0) { LM_ERR("unable to get pseudo-variable in param\n"); return E_OUT_OF_MEM; } - + if (ap->u.sval.type!=PVT_AVP) { LM_ERR("bad attribute name <%s>\n", (char*)*param); @@ -1032,7 +1093,7 @@ static int fixup_is_avp_set(void** param, int param_no) return E_UNSPEC; } } - + *param=(void*)ap; } @@ -1096,16 +1157,16 @@ static int fixup_insert_avp(void** param, int param_no) static int w_dbload_avps(struct sip_msg* msg, char* source, - char* param, char *url) + char* param, char *url, char *prefix) { return ops_dbload_avps ( msg, (struct fis_param*)source, (struct db_param*)param, url?(struct db_url*)url:default_db_url, - use_domain); + use_domain, (str *)prefix); } static int w_dbdelete_avps(struct sip_msg* msg, char* source, - char* param, char *url) + char* param, char *url) { return ops_dbdelete_avps ( msg, (struct fis_param*)source, (struct db_param*)param, diff --git a/modules/avpops/avpops_db.c b/modules/avpops/avpops_db.c index 5aebebb65b4..0dcf9918470 100644 --- a/modules/avpops/avpops_db.c +++ b/modules/avpops/avpops_db.c @@ -419,12 +419,12 @@ int db_query_avp(struct db_url *url, struct sip_msg *msg, char *query, query_str.s = query; query_str.len = strlen(query); - + if(url->dbf.raw_query( url->hdl, &query_str, &db_res)!=0) { const str *t = url->hdl&&url->hdl->table&&url->hdl->table->s ? url->hdl->table : 0; - LM_ERR("raw_query failed: db%d(%.*s) %.40s...\n", + LM_ERR("raw_query failed: db%d(%.*s) %.40s...\n", url->idx, t?t->len:0, t?t->s:"", query); return -1; } @@ -438,11 +438,11 @@ int db_query_avp(struct db_url *url, struct sip_msg *msg, char *query, LM_DBG("rows [%d]\n", RES_ROW_N(db_res)); /* reverse order of rows so that first row get's in front of avp list */ - for(i = RES_ROW_N(db_res)-1; i >= 0; i--) + for(i = RES_ROW_N(db_res)-1; i >= 0; i--) { LM_DBG("row [%d]\n", i); crt = dest; - for(j = 0; j < RES_COL_N(db_res); j++) + for(j = 0; j < RES_COL_N(db_res); j++) { if(RES_ROWS(db_res)[i].values[j].nul) goto next_avp; diff --git a/modules/avpops/avpops_impl.c b/modules/avpops/avpops_impl.c index e2f29d46a1f..af0e586daae 100644 --- a/modules/avpops/avpops_impl.c +++ b/modules/avpops/avpops_impl.c @@ -93,13 +93,15 @@ void init_store_avps(str **db_columns) store_vals[5].nul = 0; } +#define AVPOPS_ATTR_LEN 64 +static char avpops_attr_buf[AVPOPS_ATTR_LEN]; /* value 0 - attr value * value 1 - attr name * value 2 - attr type */ static int dbrow2avp(struct db_row *row, struct db_param *dbp, int attr, - int attr_type, int just_val_flags) + int attr_type, int just_val_flags, str *prefix) { unsigned int uint; int db_flags; @@ -159,6 +161,22 @@ static int dbrow2avp(struct db_row *row, struct db_param *dbp, int attr, } else { atmp = row->values[1].val.str_val; } + + if (prefix) + { + if (atmp.len + prefix->len > AVPOPS_ATTR_LEN) + { + LM_ERR("name too long [%d/%.*s...]\n", + prefix->len + atmp.len, 16, prefix->s); + return -1; + } + + memcpy(avpops_attr_buf, prefix->s, prefix->len); + memcpy(avpops_attr_buf + prefix->len, atmp.s, atmp.len); + atmp.s = avpops_attr_buf; + atmp.len += prefix->len; + } + /* there is always a name here - get the ID */ avp_attr = get_avp_id(&atmp); if (avp_attr < 0) @@ -260,11 +278,9 @@ static int avpops_get_aname(struct sip_msg* msg, struct fis_param *ap, return pv_get_avp_name(msg, &ap->u.sval.pvp, avp_name, name_type); } -#define AVPOPS_ATTR_LEN 64 -static char avpops_attr_buf[AVPOPS_ATTR_LEN]; int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp, - struct db_param *dbp, struct db_url *url, int use_domain) + struct db_param *dbp, struct db_url *url, int use_domain, str *prefix) { struct sip_uri uri; db_res_t *res = NULL; @@ -299,7 +315,7 @@ int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp, uuid.s = sp->u.s.s; uuid.len = sp->u.s.len; } - + if(sp->opd&AVPOPS_FLAG_UUID0) { s0 = &uuid; @@ -356,7 +372,6 @@ int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp, } } } - LM_DBG("attr dbp %s\n", dbp->sa.s); /* do DB query */ res = db_load_avp( url, s0, s1, @@ -371,32 +386,50 @@ int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp, } sh_flg = (dbp->scheme)?dbp->scheme->db_flags:-1; - /* process the results */ - for( n=0,i=0 ; in ; i++) + + /* validate row */ + avp_name = -1; + if(dbp->a.type==AVPOPS_VAL_PVAR) { - /* validate row */ - avp_name = -1; - if(dbp->a.type==AVPOPS_VAL_PVAR) + if(pv_has_dname(&dbp->a.u.sval)) { - if(pv_has_dname(&dbp->a.u.sval)) + if(xvalue.flags&PV_TYPE_INT) { - if(xvalue.flags&PV_TYPE_INT) + avp_name = xvalue.ri; + } else { + + if (prefix) { - avp_name = xvalue.ri; - } else { - avp_name = get_avp_id(&xvalue.rs); - if (avp_name < 0) { - LM_ERR("cannot get avp id\n"); - return -1; + if (xvalue.rs.len + prefix->len > AVPOPS_ATTR_LEN) + { + LM_ERR("name too long [%d/%.*s...]\n", + prefix->len + xvalue.rs.len, 16, prefix->s); + goto error; } + + memcpy(avpops_attr_buf, prefix->s, prefix->len); + memcpy(avpops_attr_buf + prefix->len, xvalue.rs.s, + xvalue.rs.len); + xvalue.rs.s = avpops_attr_buf; + xvalue.rs.len = prefix->len + xvalue.rs.len; + } + + avp_name = get_avp_id(&xvalue.rs); + if (avp_name < 0) { + LM_ERR("cannot get avp id\n"); + return -1; } - } else { - avp_name = dbp->a.u.sval.pvp.pvn.u.isname.name.n; - avp_type = dbp->a.u.sval.pvp.pvn.u.isname.type; } + } else { + avp_name = dbp->a.u.sval.pvp.pvn.u.isname.name.n; + avp_type = dbp->a.u.sval.pvp.pvn.u.isname.type; } - //if ( dbrow2avp( &res->rows[i], dbp->a.opd, avp_name, sh_flg) < 0 ) - if ( dbrow2avp( &res->rows[i], dbp, avp_name, avp_type, sh_flg) < 0 ) + } + + /* process the results */ + for( n=0,i=0 ; in ; i++) + { + if (dbrow2avp(&res->rows[i], dbp, avp_name, avp_type, sh_flg, prefix) < 0) continue; n++; } @@ -412,7 +445,7 @@ int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp, int ops_dbdelete_avps (struct sip_msg* msg, struct fis_param *sp, - struct db_param *dbp, struct db_url *url, int use_domain) + struct db_param *dbp, struct db_url *url, int use_domain) { struct sip_uri uri; int res; @@ -444,7 +477,7 @@ int ops_dbdelete_avps (struct sip_msg* msg, struct fis_param *sp, uuid.s = sp->u.s.s; uuid.len = sp->u.s.len; } - + if(sp->opd&AVPOPS_FLAG_UUID0) { s0 = &uuid; @@ -544,7 +577,7 @@ int ops_dbstore_avps (struct sip_msg* msg, struct fis_param *sp, } keys_nr = 6; /* uuid, avp name, avp val, avp type, user, domain */ - + /* get uuid from avp */ if (sp->opd&AVPOPS_VAL_PVAR) { @@ -563,7 +596,7 @@ int ops_dbstore_avps (struct sip_msg* msg, struct fis_param *sp, uuid.s = sp->u.s.s; uuid.len = sp->u.s.len; } - + if(sp->opd&AVPOPS_FLAG_UUID0) { s0 = &uuid; @@ -645,14 +678,14 @@ int ops_dbstore_avps (struct sip_msg* msg, struct fis_param *sp, avp_name = dbp->a.u.sval.pvp.pvn.u.isname.name.n; } } else { - LM_WARN("TODO: avp is not a dinamic name <%.*s> name is %d\n", dbp->sa.len, dbp->sa.s, avp_name); + LM_WARN("TODO: avp is not a dynamic name <%.*s> name is %d\n", dbp->sa.len, dbp->sa.s, avp_name); avp_name = -1; } /* set the script flags */ if(dbp->a.type==AVPOPS_VAL_PVAR) name_type |= dbp->a.u.sval.pvp.pvn.u.isname.type&0xff00; - + /* set uuid/(username and domain) fields */ n =0 ; @@ -744,7 +777,7 @@ int ops_dbquery_avps(struct sip_msg* msg, pv_elem_t* query, LM_ERR("bad parameters\n"); return -1; } - + printbuf_len = buf_size-1; if(pv_printf(msg, query, printbuf, &printbuf_len)<0 || printbuf_len<=0) { @@ -756,7 +789,7 @@ int ops_dbquery_avps(struct sip_msg* msg, pv_elem_t* query, ret = db_query_avp(url, msg, printbuf, dest); - //Empty return set + //Empty return set if(ret==1) return -2; @@ -996,7 +1029,7 @@ int ops_pushto_avp (struct sip_msg* msg, struct fis_param* dst, LM_CRIT("destination unknown (%d/%d)\n", dst->opd, dst->ops); goto error; } - + if ( act_type ) { /* rewrite part of ruri */ @@ -1340,7 +1373,7 @@ int ops_print_avp(void) } } - + return 1; } @@ -1373,7 +1406,7 @@ int ops_subst(struct sip_msg* msg, struct fis_param** src, if(avp==NULL) return -1; - + if(src[1]!=0) { /* get dst avp name */ @@ -1386,7 +1419,7 @@ int ops_subst(struct sip_msg* msg, struct fis_param** src, name_type2 = name_type1; avp_name2 = avp_name1; } -/* TODO: delete? +/* TODO: delete? if(name_type2&AVP_NAME_STR) { if(avp_name2.s.len>=STR_BUF_SIZE) @@ -1407,7 +1440,7 @@ int ops_subst(struct sip_msg* msg, struct fis_param** src, avp = search_first_avp(name_type1, avp_name1, &avp_val, prev_avp); continue; } - + result=subst_str(avp_val.s.s, msg, se, &nmatches); if(result!=NULL) { @@ -1654,7 +1687,7 @@ int ops_is_avp_set(struct sip_msg* msg, struct fis_param *ap) int_str avp_value; int index; int findex; - + /* get avp name */ if(avpops_get_aname(msg, ap, &avp_name, &name_type)!=0) { @@ -1668,11 +1701,11 @@ int ops_is_avp_set(struct sip_msg* msg, struct fis_param *ap) LM_ERR("failed to get AVP index\n"); return -1; } - + avp=search_first_avp(name_type, avp_name, &avp_value, 0); if(avp==0) return -1; - + do { /* last index [-1] or all [*] go here as well */ if(index<=0) @@ -1701,7 +1734,7 @@ int ops_is_avp_set(struct sip_msg* msg, struct fis_param *ap) } index--; } while ((avp=search_first_avp(name_type, avp_name, &avp_value, avp))!=0); - + return -1; } @@ -1764,7 +1797,7 @@ int w_insert_avp(struct sip_msg* msg, char* name, char* value, /* search the previous avp */ index--; avp = NULL; - while ( (avp=search_first_avp( name_type, avp_name, 0, avp))!=0 ) + while ( (avp=search_first_avp( name_type, avp_name, 0, avp))!=0 ) { if( index == 0 ) { diff --git a/modules/avpops/avpops_impl.h b/modules/avpops/avpops_impl.h index 1d8498f065b..835cb628161 100644 --- a/modules/avpops/avpops_impl.h +++ b/modules/avpops/avpops_impl.h @@ -121,10 +121,10 @@ struct db_param void init_store_avps(str **db_columns); int ops_dbload_avps (struct sip_msg* msg, struct fis_param *sp, - struct db_param *dbp, struct db_url *url, int use_domain); + struct db_param *dbp, struct db_url *url, int use_domain, str *prefix); int ops_dbdelete_avps(struct sip_msg* msg, struct fis_param *sp, - struct db_param *dbp, struct db_url *url, int use_domain); + struct db_param *dbp, struct db_url *url, int use_domain); int ops_dbstore_avps(struct sip_msg* msg, struct fis_param *sp, struct db_param *dbp, struct db_url *url, int use_domain); diff --git a/modules/avpops/avpops_parse.c b/modules/avpops/avpops_parse.c index ded6e1887fc..41a535eb764 100644 --- a/modules/avpops/avpops_parse.c +++ b/modules/avpops/avpops_parse.c @@ -268,7 +268,7 @@ int parse_avp_db(char *s, struct db_param *dbp, int allow_scheme) if (have_scheme) { dbp->scheme = avp_get_db_scheme( &tmp ); - if (dbp->scheme==0) + if (dbp->scheme==0) { LM_ERR("scheme <%s> not found\n", tmp.s); goto error; @@ -335,7 +335,7 @@ struct fis_param* parse_intstr_value(char *p, int len) { if(hexstr2int(val_str.s+2, val_str.len-2, &uint)) { - LM_ERR("value is not hex int as type says <%.*s>\n", + LM_ERR("value is not hex int as type says <%.*s>\n", val_str.len, val_str.s); goto error; } @@ -451,37 +451,37 @@ int parse_avp_db_scheme( char *s, struct db_scheme *scheme) while (*p && isspace((int)*p)) p++; /* identify the attribute */ - if ( foo.len==SCHEME_UUID_COL_LEN && + if ( foo.len==SCHEME_UUID_COL_LEN && !strncasecmp( foo.s, SCHEME_UUID_COL, foo.len) ) { if (scheme->uuid_col.s) goto parse_error; duplicate_str( scheme->uuid_col, bar, error); } else - if ( foo.len==SCHEME_USERNAME_COL_LEN && + if ( foo.len==SCHEME_USERNAME_COL_LEN && !strncasecmp( foo.s, SCHEME_USERNAME_COL, foo.len) ) { if (scheme->username_col.s) goto parse_error; duplicate_str( scheme->username_col, bar, error); } else - if ( foo.len==SCHEME_DOMAIN_COL_LEN && + if ( foo.len==SCHEME_DOMAIN_COL_LEN && !strncasecmp( foo.s, SCHEME_DOMAIN_COL, foo.len) ) { if (scheme->domain_col.s) goto parse_error; duplicate_str( scheme->domain_col, bar, error); } else - if ( foo.len==SCHEME_VALUE_COL_LEN && + if ( foo.len==SCHEME_VALUE_COL_LEN && !strncasecmp( foo.s, SCHEME_VALUE_COL, foo.len) ) { if (scheme->value_col.s) goto parse_error; duplicate_str( scheme->value_col, bar, error); } else - if ( foo.len==SCHEME_TABLE_LEN && + if ( foo.len==SCHEME_TABLE_LEN && !strncasecmp( foo.s, SCHEME_TABLE, foo.len) ) { if (scheme->table.s) goto parse_error; duplicate_str( scheme->table, bar, error); } else - if ( foo.len==SCHEME_VAL_TYPE_LEN && + if ( foo.len==SCHEME_VAL_TYPE_LEN && !strncasecmp( foo.s, SCHEME_VAL_TYPE, foo.len) ) { if ( bar.len==SCHEME_INT_TYPE_LEN && diff --git a/modules/avpops/doc/avpops_admin.xml b/modules/avpops/doc/avpops_admin.xml index 4e0d062d5ac..f7137f37aa5 100644 --- a/modules/avpops/doc/avpops_admin.xml +++ b/modules/avpops/doc/avpops_admin.xml @@ -333,7 +333,7 @@ modparam("avpops", "buf_size", 1024) Exported Functions
- <function moreinfo="none">avp_db_load(source,name[,db_id]) + <function moreinfo="none">avp_db_load(source, name[, db_id[, prefix]]) </function> @@ -341,7 +341,11 @@ modparam("avpops", "buf_size", 1024) source. If given, it sets the script flags for loaded AVPs. It returns true if it loaded some values in AVPs, false otherwise (db error, no avp loaded ...). - + + + AVPs may be preceded by an optional prefix, in + order to avoid some conflicts. + Meaning of the parameters is as follows: @@ -387,6 +391,11 @@ modparam("avpops", "buf_size", 1024) module parameter. + + prefix - static string which will + precede the names of the AVPs populated by this function. + + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, @@ -397,12 +406,18 @@ modparam("avpops", "buf_size", 1024) <function>avp_db_load</function> usage ... -avp_db_load("$fu","$avp(678)"); -avp_db_load("$ru/domain","i/domain_preferences"); -avp_db_load("$avp(uuid)","$avp(404fwd)/fwd_table"); -avp_db_load("$ru","$avp(123)/$some_scheme"); +avp_db_load("$fu", "$avp(678)"); +avp_db_load("$ru/domain", "i/domain_preferences"); +avp_db_load("$avp(uuid)", "$avp(404fwd)/fwd_table"); +avp_db_load("$ru", "$avp(123)/$some_scheme"); + # use DB URL id 3 -avp_db_load("$ru","$avp(1)","3"); +avp_db_load("$ru", "$avp(1)", "3"); + +# precede all loaded AVPs by the "caller_" prefix +avp_db_load("$ru", "$avp(100)", "", "caller_"); +xlog("Loaded: $avp(caller_100)\n"); + ... diff --git a/modules/b2b_entities/README b/modules/b2b_entities/README index 0fd2ee92c2f..79bac4b643c 100644 --- a/modules/b2b_entities/README +++ b/modules/b2b_entities/README @@ -15,8 +15,7 @@ Ovidiu Sas Copyright © 2009 Anca-Maria Vamanu Revision History - Revision $Revision: 8103 $ $Date: 2011-06-30 18:48:57 +0300 - (Thu, 30 Jun 2011) $ + Revision $Revision: 8103 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/b2b_entities/b2b_common.h b/modules/b2b_entities/b2b_common.h index 3fc22a04704..33a824951a7 100644 --- a/modules/b2b_entities/b2b_common.h +++ b/modules/b2b_entities/b2b_common.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_entities/b2b_entities.c b/modules/b2b_entities/b2b_entities.c index f07c9295b65..c333615bb57 100644 --- a/modules/b2b_entities/b2b_entities.c +++ b/modules/b2b_entities/b2b_entities.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -108,11 +108,26 @@ static mi_export_t mi_cmds[] = { { "b2be_list", 0, mi_b2be_list, 0, 0, 0}, { 0, 0, 0, 0, 0, 0} }; + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "uac_auth", DEP_WARN }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_url", get_deps_sqldb_url }, + { NULL, NULL }, + }, +}; + /** Module interface */ struct module_exports exports= { "b2b_entities", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -167,7 +182,7 @@ static int mod_init(void) * if authentication is required */ if(load_uac_auth_api(&uac_auth_api)<0) { - LM_DBG("authentication functionality disabled:" + LM_INFO("authentication functionality disabled:" " load uac_auth first to enable it\n"); uac_auth_loaded = 0; } @@ -176,7 +191,7 @@ static int mod_init(void) uac_auth_loaded = 1; } - /* initialize the hash tables; they will be allocated in shared memory + /* initialize the hash tables; they will be allocated in shared memory * to be accesible by all processes */ if(init_b2b_htables()< 0) { @@ -230,7 +245,7 @@ static int mod_init(void) b2be_dbf.close(b2be_db); b2be_db = NULL; } - else + else b2be_db_mode = 0; if(register_script_cb( b2b_prescript_f, PRE_SCRIPT_CB|REQ_TYPE_CB, 0 ) < 0) @@ -499,7 +514,7 @@ static inline int mi_print_b2be_dlg(struct mi_node *rpl, b2b_table htable, unsig char* p; b2b_dlg_t* dlg; dlg_leg_t* leg; - struct mi_node *node=NULL, *node1=NULL; + struct mi_node *node=NULL, *node1=NULL, *node_l=NULL; struct mi_attr* attr; for(i = 0; i< hsize; i++) @@ -625,29 +640,32 @@ static inline int mi_print_b2be_dlg(struct mi_node *rpl, b2b_table htable, unsig if(attr == NULL) goto error; } - leg=dlg->legs; - while(leg) - { - p = int2str((unsigned long)(leg->id), &len); - node1 = add_mi_node_child(node, MI_DUP_VALUE, "leg", 3, p, len); - if(node1 == NULL) goto error; - attr = add_mi_attr(node1, MI_DUP_VALUE, "tag", 3, - leg->tag.s, leg->tag.len); - if(attr == NULL) goto error; - p = int2str((unsigned long)(leg->cseq), &len); - attr = add_mi_attr(node1, MI_DUP_VALUE, "cseq", 4, p, len); - if(attr == NULL) goto error; - attr = add_mi_attr(node1, MI_DUP_VALUE, "contact", 7, - leg->contact.s, leg->contact.len); - if(attr == NULL) goto error; - if(leg->route_set.len) + if ( (leg=dlg->legs)!=NULL ) { + node_l = add_mi_node_child(node, MI_IS_ARRAY, "LEGS", 4, NULL, 0); + if(node_l == NULL) goto error; + while(leg) { - attr = add_mi_attr(node1, MI_DUP_VALUE, "route_set", 8, - leg->route_set.s, leg->route_set.len); + p = int2str((unsigned long)(leg->id), &len); + node1 = add_mi_node_child(node_l, MI_DUP_VALUE, "leg", 3, p, len); + if(node1 == NULL) goto error; + attr = add_mi_attr(node1, MI_DUP_VALUE, "tag", 3, + leg->tag.s, leg->tag.len); if(attr == NULL) goto error; + p = int2str((unsigned long)(leg->cseq), &len); + attr = add_mi_attr(node1, MI_DUP_VALUE, "cseq", 4, p, len); + if(attr == NULL) goto error; + attr = add_mi_attr(node1, MI_DUP_VALUE, "contact", 7, + leg->contact.s, leg->contact.len); + if(attr == NULL) goto error; + if(leg->route_set.len) + { + attr = add_mi_attr(node1, MI_DUP_VALUE, "route_set", 8, + leg->route_set.s, leg->route_set.len); + if(attr == NULL) goto error; + } + + leg=leg->next; } - - leg=leg->next; } dlg = dlg->next; @@ -669,6 +687,7 @@ static struct mi_root* mi_b2be_list(struct mi_root* cmd, void* param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return NULL; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; if (server_htable) if (mi_print_b2be_dlg(rpl, server_htable, server_hsize)!=0) diff --git a/modules/b2b_entities/b2b_entities.h b/modules/b2b_entities/b2b_entities.h index ce758b5ce21..90c44c830c6 100644 --- a/modules/b2b_entities/b2b_entities.h +++ b/modules/b2b_entities/b2b_entities.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_entities/b2be_db.c b/modules/b2b_entities/b2be_db.c index cf57fea2fd2..64517fb3d52 100644 --- a/modules/b2b_entities/b2be_db.c +++ b/modules/b2b_entities/b2be_db.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -432,7 +432,7 @@ int b2b_entities_restore(void) if (DB_CAPABILITY(b2be_dbf, DB_CAP_FETCH)) { if(b2be_dbf.query(b2be_db,0,0,0,qcols, 0, - DB_COLS_NO, 0, 0) < 0) + DB_COLS_NO, 0, 0) < 0) { LM_ERR("Error while querying (fetch) database\n"); return -1; @@ -479,7 +479,7 @@ int b2b_entities_restore(void) htable = server_htable; if(b2b_parse_key(&dlg.tag[1], &hash_index, &local_index) < 0) { - LM_ERR("Wrong format for b2b key [%.*s]\n", dlg.tag[1].len, dlg.tag[1].s); + LM_ERR("Wrong format for b2b key [%.*s]\n", dlg.tag[1].len, dlg.tag[1].s); goto error; } } @@ -489,7 +489,7 @@ int b2b_entities_restore(void) if(b2b_parse_key(&dlg.callid, &hash_index, &local_index) < 0) { - LM_ERR("Wrong format for b2b key [%.*s]\n", dlg.callid.len, dlg.callid.s); + LM_ERR("Wrong format for b2b key [%.*s]\n", dlg.callid.len, dlg.callid.s); goto error; } } @@ -577,7 +577,7 @@ int b2b_entities_restore(void) /* any more data to be fetched ?*/ if (DB_CAPABILITY(b2be_dbf, DB_CAP_FETCH)) { - if (b2be_dbf.fetch_result( b2be_db, &result, no_rows) < 0) + if (b2be_dbf.fetch_result( b2be_db, &result, no_rows) < 0) { LM_ERR("fetching more rows failed\n"); goto error; diff --git a/modules/b2b_entities/b2be_db.h b/modules/b2b_entities/b2be_db.h index 864747031e6..2599db86d78 100644 --- a/modules/b2b_entities/b2be_db.h +++ b/modules/b2b_entities/b2be_db.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_entities/client.c b/modules/b2b_entities/client.c index a0ed5b91ae9..f2ada74bde6 100644 --- a/modules/b2b_entities/client.c +++ b/modules/b2b_entities/client.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -67,7 +67,7 @@ static void generate_tag(str* tag, str* src, str* callid) LM_DBG("from_tag = %.*s\n", tag->len, tag->s); } -/** +/** * Function to create a new client entity a send send an initial message * method : the method of the message * to_uri : the destination URI @@ -226,8 +226,10 @@ str* client_new(client_info_t* ci,b2b_notify_t b2b_cback, if(ci->dst_uri.len) td.obp = ci->dst_uri; + td.avps = ci->avps; + tmb.setlocalTholder(&dlg->uac_tran); - + /* send request */ result= tmb.t_request_within (&ci->method, /* method*/ diff --git a/modules/b2b_entities/client.h b/modules/b2b_entities/client.h index a67e27e4a3c..ebc5973b283 100644 --- a/modules/b2b_entities/client.h +++ b/modules/b2b_entities/client.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_entities/dlg.c b/modules/b2b_entities/dlg.c index e0ba3c04a98..ce3927d7e0d 100644 --- a/modules/b2b_entities/dlg.c +++ b/modules/b2b_entities/dlg.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -37,6 +37,7 @@ #include "../../parser/parse_content.h" #include "../../parser/parse_authenticate.h" #include "../../locking.h" +#include "../../script_cb.h" #include "../uac_auth/uac_auth.h" #include "../presence/hash.h" #include "../../action.h" @@ -122,7 +123,7 @@ b2b_dlg_t* b2b_search_htable_next_dlg(b2b_dlg_t* start_dlg, b2b_table table, uns dlg, dlg->uas_tran); return dlg; } - + } else { @@ -134,7 +135,7 @@ b2b_dlg_t* b2b_search_htable_next_dlg(b2b_dlg_t* start_dlg, b2b_table table, uns if(dlg->tag[CALLER_LEG].len == to_tag->len && strncmp(dlg->tag[CALLER_LEG].s, to_tag->s, to_tag->len)== 0) { - + leg = dlg->legs; if(dlg->state < B2B_CONFIRMED || dlg->state>=B2B_DESTROYED) { @@ -208,7 +209,7 @@ str* b2b_htable_insert(b2b_table table, b2b_dlg_t* dlg, int hash_index, int src, if(!reload) lock_get(&table[hash_index].lock); - + dlg->prev = dlg->next = NULL; it = table[hash_index].first; @@ -269,7 +270,7 @@ int b2b_parse_key(str* key, unsigned int* hash_index, unsigned int* local_index) if(!key || !key->s) return -1; - if(strncmp(key->s, b2b_key_prefix.s, b2b_key_prefix.len) != 0 || + if(strncmp(key->s, b2b_key_prefix.s, b2b_key_prefix.len) != 0 || key->len<(b2b_key_prefix.len +4) || key->s[b2b_key_prefix.len]!='.') { LM_DBG("Does not have b2b_entities prefix\n"); @@ -462,7 +463,7 @@ b2b_dlg_t* b2bl_search_iteratively(str* callid, str* from_tag, str* ruri, dlg = server_htable[hash_index].first; while(dlg) { - LM_DBG("Found callid= %.*s, tag= %.*s\n", dlg->callid.len, dlg->callid.s, + LM_DBG("Found callid= %.*s, tag= %.*s\n", dlg->callid.len, dlg->callid.s, dlg->tag[CALLER_LEG].len, dlg->tag[CALLER_LEG].s); if(dlg->callid.len == callid->len && strncmp(dlg->callid.s, callid->s, callid->len)== 0 && dlg->tag[CALLER_LEG].len == from_tag->len && @@ -505,7 +506,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) if (parse_headers(msg, HDR_EOH_F, 0) < 0) { LM_ERR("failed to parse message\n"); - return -1; + return SCB_RUN_ALL; } LM_DBG("start - method = %.*s\n", msg->first_line.u.request.method.len, msg->first_line.u.request.method.s); @@ -517,19 +518,19 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) /* we accept Route hdrs only if preloaded route with out IPs */ if (parse_rr(route_hdr) < 0) { LM_ERR("failed to parse Route HF\n"); - return -1; + return SCB_RUN_ALL; } rt = (rr_t*)route_hdr->parsed; /* check if first route is local*/ if ( parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)!=0 ) { LM_ERR("Route uri is not valid <%.*s>\n", rt->nameaddr.uri.len,rt->nameaddr.uri.s); - return -1; + return SCB_RUN_ALL; } if (check_self( &puri.host, puri.port_no?puri.port_no:SIP_PORT, puri.proto?puri.proto:PROTO_UDP)!= 1 ) { LM_DBG("First Route uri is not mine\n"); - return 1; /* not for b2b */ + return SCB_RUN_ALL; /* not for b2b */ } /* check if second route is local*/ rt = rt->next; @@ -538,7 +539,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) route_hdr = msg->route->sibling; if (parse_rr(route_hdr) < 0) { LM_ERR("failed to parse second Route HF\n"); - return -1; + return SCB_RUN_ALL; } rt = (rr_t*)route_hdr->parsed; } @@ -547,17 +548,17 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) if ( parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)!=0 ) { LM_ERR("Second route uri is not valid <%.*s>\n", rt->nameaddr.uri.len,rt->nameaddr.uri.s); - return -1; + return SCB_RUN_ALL; } if (check_self( &puri.host, puri.port_no?puri.port_no:SIP_PORT, puri.proto?puri.proto:PROTO_UDP)!= 1 ) { LM_DBG("Second Route uri is not mine\n"); - return 1; /* not for b2b */ + return SCB_RUN_ALL; /* not for b2b */ } /* check the presence of the third route */ if (rt->next || route_hdr->sibling) { LM_DBG("More than 2 route hdr -> not for me\n"); - return 1; /* not for b2b */ + return SCB_RUN_ALL; /* not for b2b */ } } /* "route" hdr checking is ok, continue */ @@ -572,7 +573,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) if(parse_sip_msg_uri(msg)< 0) { LM_ERR("Failed to parse uri\n"); - return -1; + return SCB_RUN_ALL; } host = msg->parsed_uri.host; port = msg->parsed_uri.port_no; @@ -584,7 +585,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) if (!check_self( &host, port ? port : SIP_PORT, msg->rcv.proto)) { LM_DBG("RURI does not point to me\n"); - return 1; + return SCB_RUN_ALL; } } @@ -609,20 +610,20 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("no callid header found\n"); - return -1; + return SCB_RUN_ALL; } /* examine the from header */ if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); - return -1; + return SCB_RUN_ALL; } if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); - return -1; + return SCB_RUN_ALL; } } @@ -630,30 +631,35 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) from_tag = ((struct to_body*)msg->from->parsed)->tag_value; if (from_tag.len==0 || from_tag.s==NULL) { LM_ERR("From header has no TAG parameter\n"); - return -1; + return SCB_RUN_ALL; } /* if a CANCEL request - search iteratively in the server_htable*/ if(method_value == METHOD_CANCEL) { - str ruri= msg->first_line.u.request.uri; + /*str ruri= msg->first_line.u.request.uri;*/ str reply_text={"canceling", 9}; /* This makes no sense - why not accepting a CANCEL that was generated by other b2b instance ? or ourselves ? - bogdan if(b2b_parse_key(&callid, &hash_index, &local_index) >= 0) { LM_DBG("received a CANCEL message that I sent\n"); - return 1; + return SCB_RUN_ALL; } */ hash_index = core_hash(&callid, &from_tag, server_hsize); - dlg = b2bl_search_iteratively(&callid, &from_tag, &ruri, hash_index); + /* As per RFC3261, the RURI must be used when matching the CANCEL + against the INVITE, but we should not do it here as B2B learns + a RURI that may have been changed in script (before invoking the + B2B module), while the CANCEL has the original RURI (as received) + */ + dlg = b2bl_search_iteratively(&callid, &from_tag, NULL/*&ruri*/, hash_index); if(dlg == NULL) { lock_release(&server_htable[hash_index].lock); LM_DBG("No dialog found for cancel\n"); - return 1; + return SCB_RUN_ALL; } table = server_htable; /* send 200 canceling */ @@ -668,14 +674,14 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) else LM_DBG("Error when creating tm transaction\n"); lock_release(&server_htable[hash_index].lock); - return 0; + return SCB_DROP_MSG; } if(tmb.t_reply(msg, 200, &reply_text) < 0) { LM_ERR("failed to send reply for CANCEL\n"); lock_release(&server_htable[hash_index].lock); - return -1; + return SCB_RUN_ALL; } tmb.unref_cell(tmb.t_gett()); @@ -690,13 +696,13 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) ((struct to_body *)msg->to->parsed)->error != PARSE_OK ) { LM_DBG("'To' header COULD NOT parsed\n"); - return 0; + return SCB_DROP_MSG; } to_tag = get_to(msg)->tag_value; if(to_tag.s == NULL || to_tag.len == 0) { LM_DBG("Not an inside dialog request- not interested.\n"); - return 1; + return SCB_RUN_ALL; } b2b_key = to_tag; @@ -724,7 +730,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) if(method_value != METHOD_UPDATE) { LM_DBG("Not a b2b request\n"); - return 1; + return SCB_RUN_ALL; } else { @@ -736,7 +742,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) { lock_release(&server_htable[hash_index].lock); LM_DBG("No dialog found for cancel\n"); - return 1; + return SCB_RUN_ALL; } } } @@ -753,7 +759,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) if(method_value != METHOD_ACK) { str ok = str_init("OK"); - + if(method_value == METHOD_BYE) tmb.t_reply(msg, 200, &ok); else @@ -762,7 +768,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) msg->first_line.u.request.method.s); } lock_release(&table[hash_index].lock); - return -1; + return SCB_RUN_ALL; } } @@ -772,7 +778,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) { LM_DBG("I can not accept requests if the state is not confimed\n"); lock_release(&table[hash_index].lock); - return 0; + return SCB_DROP_MSG; } } @@ -784,13 +790,13 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) { LM_DBG("It is a ACK retransmission, drop\n"); lock_release(&table[hash_index].lock); - return 0; + return SCB_DROP_MSG; } logic_notify: etype = (table==server_htable?B2B_SERVER:B2B_CLIENT); - if(req_routeid) + if(req_routeid > 0) { lock_release(&table[hash_index].lock); run_top_route(rlist[req_routeid].a, msg); @@ -799,7 +805,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) if (parse_from_header(msg) < 0) { LM_ERR("cannot parse From header\n"); - return 0; + return SCB_DROP_MSG; } callid = msg->callid->body; from_tag = ((struct to_body*)msg->from->parsed)->tag_value; @@ -830,7 +836,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) else LM_DBG("Error when creating tm transaction\n"); lock_release(&table[hash_index].lock); - return 0; + return SCB_DROP_MSG; } tm_tran = tmb.t_gett(); @@ -895,7 +901,7 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) { LM_ERR("No more private memory\n"); lock_release(&table[hash_index].lock); - return -1; + return SCB_RUN_ALL; } memcpy(param.s, dlg->param.s, dlg->param.len); param.len = dlg->param.len; @@ -935,14 +941,14 @@ int b2b_prescript_f(struct sip_msg *msg, void *uparam) { LM_DBG("Record not found anymore\n"); lock_release(&table[hash_index].lock); - return 0; + return SCB_DROP_MSG; } if(b2be_db_update(dlg, etype) < 0) LM_ERR("Failed to update in database\n"); lock_release(&table[hash_index].lock); } - return 0; + return SCB_DROP_MSG; } int init_b2b_htables(void) @@ -1021,7 +1027,7 @@ void destroy_b2b_htables(void) b2b_dlg_t* b2b_new_dlg(struct sip_msg* msg, str* local_contact, b2b_dlg_t* init_dlg, str* param) { - struct to_body *pto, *pfrom = NULL; + struct to_body *pto, *pfrom = NULL; b2b_dlg_t dlg; contact_body_t* b; b2b_dlg_t* shm_dlg = NULL; @@ -1066,7 +1072,7 @@ b2b_dlg_t* b2b_new_dlg(struct sip_msg* msg, str* local_contact, } if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); return 0; @@ -1148,7 +1154,7 @@ b2b_dlg_t* b2b_new_dlg(struct sip_msg* msg, str* local_contact, else dlg.contact[CALLEE_LEG]=*local_contact; - if (!msg->content_length) + if (!msg->content_length) { LM_ERR("no Content-Length header found!\n"); return 0; @@ -1249,7 +1255,7 @@ int b2b_send_reply(b2b_rpl_data_t* rpl_data) } else { - dlg = b2b_search_htable_dlg(table, hash_index, local_index, + dlg = b2b_search_htable_dlg(table, hash_index, local_index, &fromtag, &totag, &dlginfo->callid); } if(dlg== NULL) @@ -1379,7 +1385,7 @@ int b2b_send_reply(b2b_rpl_data_t* rpl_data) } lock_release(&table[hash_index].lock); - + if((extra_headers?extra_headers->len:0) + 14 + local_contact.len + 20 + CRLF_LEN > BUF_LEN) { @@ -1495,7 +1501,7 @@ void b2b_entity_delete(enum b2b_entity_type et, str* b2b_key, if(db_del) b2b_entity_db_delete(et, dlg); - + b2b_delete_record(dlg, table, hash_index); lock_release(&table[hash_index].lock); } @@ -1563,7 +1569,7 @@ int b2b_send_indlg_req(b2b_dlg_t* dlg, enum b2b_entity_type et, dlg->cseq[CALLEE_LEG]--; else dlg->cseq[CALLER_LEG]--; - + if(dlg->ack_sdp.s) { shm_free(dlg->ack_sdp.s); @@ -1691,7 +1697,7 @@ int b2b_send_request(b2b_req_data_t* req_data) } else { - dlg = b2b_search_htable_dlg(table, hash_index, local_index, + dlg = b2b_search_htable_dlg(table, hash_index, local_index, totag.s?&totag:NULL, fromtag.s?&fromtag:NULL, &dlginfo->callid); } if(dlg== NULL) @@ -1982,6 +1988,8 @@ int b2b_send_req(b2b_dlg_t* dlg, enum b2b_entity_type etype, return result; } +static struct sip_msg dummy_msg; + void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) { struct sip_msg * msg; @@ -1998,7 +2006,6 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) str extra_headers = {NULL, 0}; struct hdr_field* hdr; unsigned int method_id = 0; - struct sip_msg dummy_msg; struct cseq_body cb; struct hdr_field cseq; enum b2b_entity_type etype=(htable==server_htable?B2B_SERVER:B2B_CLIENT); @@ -2062,7 +2069,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) LM_ERR("failed to parse cseq header\n"); return; } - + if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("no callid header found\n"); @@ -2076,7 +2083,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) } if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); return; @@ -2133,7 +2140,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) * - this is the cancelled branch of a paralel call fork * and the entity was deleted already. */ - /* FIXME: we may revisit the logic of paralel forking and + /* FIXME: we may revisit the logic of paralel forking and * properly ignore this kind of callbacks. */ if (method_id==METHOD_INVITE && statuscode==487) @@ -2174,7 +2181,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) } else { dlg = previous_dlg; - /* if the transaction is no longer saved or is not the same as + /* if the transaction is no longer saved or is not the same as * the one that the reply belongs to => exit*/ LM_DBG("I don't care anymore about this transaction for dlg [%p]" " last_method=%d method_id=%d t=[%p] dlg->uac_tran=[%p]\n", @@ -2221,7 +2228,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) LM_DBG("Received reply [%d] for dialog [%p], method [%.*s]\n", statuscode, dlg, t->method.len, t->method.s); - + if(statuscode >= 300) { if(dlg->uac_tran == t ) @@ -2306,7 +2313,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) t->uac[0].extra_headers.len); if (extra_headers.s == NULL) { - LM_ERR("No more private memory\n"); + LM_ERR("No more private memory\n"); dlg->state = B2B_TERMINATED; lock_release(&htable[hash_index].lock); goto error; @@ -2318,6 +2325,8 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) extra_headers.len = new_hdr->len + t->uac[0].extra_headers.len; LM_DBG("[%.*s]\n", extra_headers.len, extra_headers.s); + pkg_free(new_hdr->s); + new_hdr->s = NULL; new_hdr->len = 0; b2b_send_indlg_req(dlg, B2B_CLIENT, b2b_key, &t->method, &extra_headers, &t->uac[0].body, 0); @@ -2497,7 +2506,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) if(dlg->next) dlg->next->prev = new_dlg; - + dlg->next= dlg->prev = NULL; b2b_delete_legs(&dlg->legs); shm_free(dlg); @@ -2517,18 +2526,17 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) if(leg) { LM_DBG("Found existing leg - Nothing to update\n"); - goto done; - } - - leg = b2b_add_leg(dlg, msg, &to_tag); - if(leg == NULL) - { - LM_ERR("Failed to add dialog leg\n"); - goto error; + } else { + leg = b2b_add_leg(dlg, msg, &to_tag); + if(leg == NULL) + { + LM_ERR("Failed to add dialog leg\n"); + goto error; + } + UPDATE_DBFLAG(dlg); } - UPDATE_DBFLAG(dlg); /* PRACK handling */ - /* if the provisional reply contains a + /* if the provisional reply contains a * Require: 100rel header -> send PRACK */ hdr = get_header_by_static_name( msg, "Require"); while(hdr) @@ -2565,7 +2573,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) rseq.len, rseq.s, cseq.len, cseq.s); extra_headers.s = buf; extra_headers.len = strlen(buf); - + if(dlg->callid.s==0 || dlg->callid.len==0) dlg->callid = msg->callid->body; if(b2b_send_req(dlg, etype, leg, &method, &extra_headers, 0) < 0) @@ -2623,7 +2631,7 @@ void b2b_tm_cback(struct cell *t, b2b_table htable, struct tmcb_params *ps) dlginfo.callid = dlg->callid; dlginfo.totag = dlg->tag[CALLER_LEG]; dlg->state = B2B_CONFIRMED; - + if(b2be_db_mode == WRITE_THROUGH) { b2be_db_insert(dlg, etype); @@ -2777,7 +2785,7 @@ int b2b_apply_lumps(struct sip_msg* msg) str body; /* faked reply */ - if (msg==NULL || msg == FAKED_REPLY) + if (msg==NULL || msg == FAKED_REPLY || msg==&dummy_msg) return 0; if(!msg->body_lumps && !msg->add_rm) @@ -2785,10 +2793,10 @@ int b2b_apply_lumps(struct sip_msg* msg) if (msg->first_line.type==SIP_REQUEST) obuf.s = build_req_buf_from_sip_req(msg, (unsigned int*)&obuf.len, - NULL, 0, MSG_TRANS_NOVIA_FLAG ); + msg->rcv.bind_address, msg->rcv.proto, MSG_TRANS_NOVIA_FLAG ); else obuf.s = build_res_buf_from_sip_res(msg, (unsigned int*)&obuf.len, - NULL); + msg->rcv.bind_address,0); if (!obuf.s) { LM_ERR("no more shm mem\n"); diff --git a/modules/b2b_entities/dlg.h b/modules/b2b_entities/dlg.h index 75e420e61bc..776158e0d90 100644 --- a/modules/b2b_entities/dlg.h +++ b/modules/b2b_entities/dlg.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -140,6 +140,7 @@ typedef struct client_info str local_contact; unsigned int cseq; struct socket_info* send_sock; + struct usr_avp *avps; }client_info_t; typedef struct b2b_entry @@ -228,7 +229,7 @@ void b2b_entity_delete(enum b2b_entity_type et, str* b2b_key, typedef void (*b2b_entity_delete_t)(enum b2b_entity_type et, str* b2b_key, b2b_dlginfo_t* dlginfo, int db_del); -b2b_dlg_t* b2b_search_htable(b2b_table table, +b2b_dlg_t* b2b_search_htable(b2b_table table, unsigned int hash_index, unsigned int local_index); void b2b_tm_cback(struct cell* t, b2b_table htable, struct tmcb_params *ps); diff --git a/modules/b2b_entities/server.c b/modules/b2b_entities/server.c index b341f8b5dae..0b8ff6746c3 100644 --- a/modules/b2b_entities/server.c +++ b/modules/b2b_entities/server.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -40,10 +40,10 @@ #include "dlg.h" #include "b2b_entities.h" -/** - * Function to create a new server entity +/** + * Function to create a new server entity * msg: SIP message - * b2b_cback: callback function to notify the logic about a change in dialog + * b2b_cback: callback function to notify the logic about a change in dialog * param: the parameter that will be used when calling b2b_cback function * * Return value: the dialog key allocated in private memory @@ -101,7 +101,7 @@ str* server_new(struct sip_msg* msg, str* local_contact, tmb.t_setkr(REQ_FWDED); LM_DBG("new server entity[%p]: callid=[%.*s] tag=[%.*s] param=[%.*s] dlg->uas_tran=[%p]\n", - dlg, dlg->callid.len, dlg->callid.s, + dlg, dlg->callid.len, dlg->callid.s, dlg->tag[CALLER_LEG].len, dlg->tag[CALLER_LEG].s, dlg->param.len, dlg->param.s, dlg->uas_tran); diff --git a/modules/b2b_entities/server.h b/modules/b2b_entities/server.h index 7d6302ad828..34b559b4e51 100644 --- a/modules/b2b_entities/server.h +++ b/modules/b2b_entities/server.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_logic/README b/modules/b2b_logic/README index e5ef48c4ef3..ddeaa45694c 100644 --- a/modules/b2b_logic/README +++ b/modules/b2b_logic/README @@ -17,8 +17,7 @@ Ovidiu Sas Copyright © 2010 VoIP Embedded, Inc. Revision History - Revision $Revision: 8137 $ $Date: 2011-07-07 15:02:20 +0300 - (Thu, 07 Jul 2011) $ + Revision $Revision: 8137 $ $Date$ __________________________________________________________ Table of Contents @@ -37,17 +36,18 @@ Ovidiu Sas 1.3.2. script_scenario (str) 1.3.3. extern_scenario (str) 1.3.4. cleanup_period (int) - 1.3.5. custom_headers (str) - 1.3.6. use_init_sdp (int) - 1.3.7. db_url (str) - 1.3.8. update_period (int) - 1.3.9. max_duration (int) - 1.3.10. b2bl_from_spec_param (string) - 1.3.11. server_address (str) - 1.3.12. init_callid_hdr (str) - 1.3.13. db_mode (int) - 1.3.14. db_table (str) - 1.3.15. b2bl_th_init_timeout (int) + 1.3.5. custom_headers_regexp (str) + 1.3.6. custom_headers (str) + 1.3.7. use_init_sdp (int) + 1.3.8. db_url (str) + 1.3.9. update_period (int) + 1.3.10. max_duration (int) + 1.3.11. b2bl_from_spec_param (string) + 1.3.12. server_address (str) + 1.3.13. init_callid_hdr (str) + 1.3.14. db_mode (int) + 1.3.15. db_table (str) + 1.3.16. b2bl_th_init_timeout (int) 1.4. Exported Functions @@ -79,17 +79,18 @@ Ovidiu Sas 1.4. Set cleanup_period parameter 1.5. Set parameter 1.6. Set parameter - 1.7. Set db_url parameter - 1.8. Set update_period parameter - 1.9. Set max_duration parameter - 1.10. Set b2bl_from_spec_param parameter - 1.11. Set server_address parameter - 1.12. Set init_callid_hdr parameter - 1.13. Set db_mode parameter - 1.14. Set db_table parameter - 1.15. Set b2bl_th_init_timeout parameter - 1.16. b2b_init_request usage - 1.17. b2b_bridge_request usage + 1.7. Set parameter + 1.8. Set db_url parameter + 1.9. Set update_period parameter + 1.10. Set max_duration parameter + 1.11. Set b2bl_from_spec_param parameter + 1.12. Set server_address parameter + 1.13. Set init_callid_hdr parameter + 1.14. Set db_mode parameter + 1.15. Set db_table parameter + 1.16. Set b2bl_th_init_timeout parameter + 1.17. b2b_init_request usage + 1.18. b2b_bridge_request usage 2.1. b2bl_api_t structure Chapter 1. Admin Guide @@ -187,7 +188,38 @@ b_marketing.xml") modparam("b2b_logic", "cleanup_period", 60) ... -1.3.5. custom_headers (str) +1.3.5. custom_headers_regexp (str) + + Regexp to search SIP header by names that should be passed from + the dialog of one side to the other side. There are a number of + headers that are passed by default. They are: + * Content-Type + * Supported + * Allow + * Proxy-Require + * Session-Expires + * Min-SE + * Require + * RSeq + + If you wish some other headers to be passed also you should + define them by setting this parameter. + + It can be in forms like "regexp", "/regexp/" and + "/regexp/flags". + + Meaning of the flags is as follows: + * i - Case insensitive search. + * e - Use extended regexp. + + Default value is “NULL”. + + Example 1.5. Set parameter +... +modparam("b2b_logic", "custom_headers_regexp", "/^x-/i") +... + +1.3.6. custom_headers (str) A list of SIP header names delimited by ';' that should be passed from the dialog of one side to the other side. There are @@ -207,12 +239,12 @@ modparam("b2b_logic", "cleanup_period", 60) Default value is “NULL”. - Example 1.5. Set parameter + Example 1.6. Set parameter ... modparam("b2b_logic", "custom_headers", "User-Agent;Date") ... -1.3.6. use_init_sdp (int) +1.3.7. use_init_sdp (int) This parameter modifies the behaviour of the B2BUA when bridging and a provisional media uri is set. For playing media @@ -228,33 +260,33 @@ modparam("b2b_logic", "custom_headers", "User-Agent;Date") Default value is “0”. - Example 1.6. Set parameter + Example 1.7. Set parameter ... modparam("b2b_logic", "use_init_sdp", 1) ... -1.3.7. db_url (str) +1.3.8. db_url (str) Database URL. - Example 1.7. Set db_url parameter + Example 1.8. Set db_url parameter ... modparam("b2b_logic", "db_url", "mysql://opensips:opensipsrw@127.0.0.1/o pensips") ... -1.3.8. update_period (int) +1.3.9. update_period (int) The time interval at which to update the info in database. Default value is “100”. - Example 1.8. Set update_period parameter + Example 1.9. Set update_period parameter ... modparam("b2b_logic", "update_period", 60) ... -1.3.9. max_duration (int) +1.3.10. max_duration (int) The maximum duration of a call. @@ -262,19 +294,19 @@ modparam("b2b_logic", "update_period", 60) If you set it to 0, there will be no limitation. - Example 1.9. Set max_duration parameter + Example 1.10. Set max_duration parameter ... modparam("b2b_logic", "max_duration", 7200) ... -1.3.10. b2bl_from_spec_param (string) +1.3.11. b2bl_from_spec_param (string) The name of the pseudo variable for storing the new “From” header. The PV must be set before calling “b2b_init_request”. Default value is “NULL” (disabled). - Example 1.10. Set b2bl_from_spec_param parameter + Example 1.11. Set b2bl_from_spec_param parameter ... modparam("b2b_logic", "b2bl_from_spec_param", "$var(b2bl_from)") ... @@ -287,7 +319,7 @@ route{ ... } -1.3.11. server_address (str) +1.3.12. server_address (str) The IP address of the machine that will be used as Contact in the generated messages. This is compulsory only when using @@ -296,24 +328,24 @@ route{ initiating request was received. This socket will be used to send all the requests, replies for that scenario instantiation. - Example 1.11. Set server_address parameter + Example 1.12. Set server_address parameter ... modparam("b2b_logic", "server_address", "sip:sa@10.10.10.10:5060") ... -1.3.12. init_callid_hdr (str) +1.3.13. init_callid_hdr (str) The module offers the possibility to insert the original callid in a header in the generated Invites. If you want this, set this parameter to the name of the header in which to insert the original callid. - Example 1.12. Set init_callid_hdr parameter + Example 1.13. Set init_callid_hdr parameter ... modparam("b2b_logic", "init_callid_hdr", "Init-CallID") ... -1.3.13. db_mode (int) +1.3.14. db_mode (int) The B2B modules have support for the 3 type of database storage @@ -325,29 +357,29 @@ modparam("b2b_logic", "init_callid_hdr", "Init-CallID") Default value is “2” (WRITE BACK). - Example 1.13. Set db_mode parameter + Example 1.14. Set db_mode parameter ... modparam("b2b_logic", "db_mode", 1) ... -1.3.14. db_table (str) +1.3.15. db_table (str) Name of the database table to be used Default value is “b2b_logic” - Example 1.14. Set db_table parameter + Example 1.15. Set db_table parameter ... modparam("b2b_logic", "db_table", "some_table_name") ... -1.3.15. b2bl_th_init_timeout (int) +1.3.16. b2bl_th_init_timeout (int) Call setup timeout for topology hiding scenario. Default value is “60” - Example 1.15. Set b2bl_th_init_timeout parameter + Example 1.16. Set b2bl_th_init_timeout parameter ... modparam("b2b_logic", "b2bl_th_init_timeout", 60) ... @@ -390,7 +422,7 @@ Note correctly routed, but the SIP pacakge may be invalid (as Contact, Via, etc). - Example 1.16. b2b_init_request usage + Example 1.17. b2b_init_request usage ... if(is_method("INVITE") && !has_totag() && prepaid_user()) b2b_init_request("prepaid", "sip:320@opensips.org:5070", @@ -408,7 +440,7 @@ if(is_method("INVITE") && !has_totag() && prepaid_user()) * entity_no - a pseudo-variable that holds the entity of the particapnt to bridge. - Example 1.17. b2b_bridge_request usage + Example 1.18. b2b_bridge_request usage ... modparam("b2b_logic", "b2bl_key_avp", "$avp(99)") ... diff --git a/modules/b2b_logic/b2b_load.h b/modules/b2b_logic/b2b_load.h index 7f946079be5..bbd91c06876 100644 --- a/modules/b2b_logic/b2b_load.h +++ b/modules/b2b_logic/b2b_load.h @@ -42,7 +42,7 @@ typedef int (*b2bl_cback_f)(b2bl_cb_params_t *params, unsigned int b2b_event); * Return: * B2B_ERROR_CB_RET - error * B2B_DROP_MSG_CB_RET - drop the request - * B2B_SEND_MSG_CB_RET - send the request on the other side + * B2B_SEND_MSG_CB_RET - send the request on the other side * B2B_FOLLOW_SCENARIO_CB_RET - do what the scenario tells, * if no rule defined send the request on the other side **/ @@ -52,7 +52,7 @@ typedef str* (*b2bl_init_f)(struct sip_msg* msg, str* name, str* args[5], b2bl_cback_f, void* param, unsigned int cb_mask, str* custom_hdrs); typedef int (*b2bl_bridge_f)(str* key, str* new_uri, str* new_from_dname,int entity_type); -/* key - the string returned by b2bl_init_f +/* key - the string returned by b2bl_init_f * entity_type - 0, the server entity * 1, the client entity */ @@ -79,8 +79,8 @@ typedef int (*b2bl_get_stats_f)(str* key, b2bl_dlg_stat_t* stat); int b2bl_register_cb(str* key, b2bl_cback_f, void* param, unsigned int cb_mask); typedef int (*b2bl_register_cb_f)(str* key, b2bl_cback_f, void* param, unsigned int cb_mask); -int b2bl_restore_upper_info(str* b2bl_key, b2bl_cback_f, void* param); -typedef int (*b2bl_restore_upper_info_f)(str* b2bl_key, b2bl_cback_f, void* param); +int b2bl_restore_upper_info(str* b2bl_key, b2bl_cback_f, void* param, unsigned int cb_mask); +typedef int (*b2bl_restore_upper_info_f)(str* b2bl_key, b2bl_cback_f, void* param, unsigned int cb_mask); typedef struct b2bl_api { diff --git a/modules/b2b_logic/b2b_logic.c b/modules/b2b_logic/b2b_logic.c index aa41bc61b4d..9c9d6eed44d 100644 --- a/modules/b2b_logic/b2b_logic.c +++ b/modules/b2b_logic/b2b_logic.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -170,11 +170,24 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "b2b_entities", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_url", get_deps_sqldb_url }, + { NULL, NULL }, + }, +}; + /** Module interface */ struct module_exports exports= { "b2b_logic", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -608,7 +621,7 @@ static int load_scenario(b2b_scenario_t** scenario_list,char* filename) memset(rule_struct, 0, sizeof(b2b_rule_t)); rule_struct->next = scenario->request_rules[request_id]; scenario->request_rules[request_id] = rule_struct; - + attr.s = (char*)xmlNodeGetAttrContentByName(rule_node, "id"); if(attr.s == NULL) { @@ -694,7 +707,7 @@ static int load_scenario(b2b_scenario_t** scenario_list,char* filename) xmlFree(scenario->id.s); pkg_free(scenario); } - + return -1; } @@ -973,7 +986,7 @@ struct to_body* get_b2bl_from(struct sip_msg* msg) b2bl_from.uri.len, b2bl_from.uri.s); return NULL; } - + /* side effect of parsing - nobody should need them later on, * so free them right now */ free_to_params(&b2bl_from); @@ -1003,13 +1016,13 @@ str* b2bl_bridge_extern(str* scenario_name, str* args[], } hash_index = core_hash(args[0], args[1], b2bl_hsize); - LM_DBG("start: bridge [%.*s] with [%.*s]\n", args[0]->len, args[0]->s, + LM_DBG("start: bridge [%.*s] with [%.*s]\n", args[0]->len, args[0]->s, args[1]->len, args[1]->s); /* find the scenario with the corresponding id */ scenario_struct = extern_scenarios; while(scenario_struct) { - if(scenario_struct->id.len == scenario_name->len && + if(scenario_struct->id.len == scenario_name->len && strncmp(scenario_struct->id.s, scenario_name->s, scenario_name->len) == 0) { break; @@ -1021,7 +1034,7 @@ str* b2bl_bridge_extern(str* scenario_name, str* args[], LM_ERR("No scenario found with the specified id\n"); return 0; } - + /* apply the init part of the scenario */ tuple = b2bl_insert_new(NULL, hash_index, scenario_struct, args, NULL, NULL, -1, &b2bl_key, INSERTDB_FLAG); @@ -1224,7 +1237,7 @@ static struct mi_root* mi_b2b_bridge(struct mi_root* cmd, void* param) node = node->next; if(node == NULL) return 0; - + new_dest = node->value; if(new_dest.s == NULL || new_dest.len == 0) { @@ -1460,12 +1473,13 @@ static struct mi_root* mi_b2b_list(struct mi_root* cmd, void* param) char* p; b2bl_tuple_t* tuple; struct mi_root *rpl_tree; - struct mi_node *node=NULL, *node1=NULL, *rpl=NULL; + struct mi_node *node=NULL, *node1=NULL, *rpl=NULL, *node_a=NULL; struct mi_attr* attr; rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return NULL; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; for(i = 0; i< b2bl_hsize; i++) { @@ -1500,39 +1514,54 @@ static struct mi_root* mi_b2b_list(struct mi_root* cmd, void* param) if(attr == NULL) goto error; } - for (index = 0; index < MAX_B2BL_ENT; index++) + for (node_a=NULL,index=0; index < MAX_B2BL_ENT; index++) { if (tuple->servers[index] != NULL) { + if (node_a==NULL) { + node_a = add_mi_node_child(node, MI_IS_ARRAY, + "SERVERS", 7, NULL, 0); + if (node_a==NULL) goto error; + } p = int2str((unsigned long)(index), &len); - node1 = add_mi_node_child(node, MI_DUP_VALUE, - "servers", 7, p, len); + node1 = add_mi_node_child(node_a, MI_DUP_VALUE, + "server", 6, p, len); if(node1 == NULL) goto error; if (internal_mi_print_b2bl_entity_id(node1, tuple->servers[index])!=0) goto error; } } - for (index = 0; index < MAX_B2BL_ENT; index++) + for (node_a=NULL,index=0; index < MAX_B2BL_ENT; index++) { if (tuple->clients[index] != NULL) { + if (node_a==NULL) { + node_a = add_mi_node_child(node, MI_IS_ARRAY, + "CLIENTS", 7, NULL, 0); + if (node_a==NULL) goto error; + } p = int2str((unsigned long)(index), &len); - node1 = add_mi_node_child(node, MI_DUP_VALUE, - "clients", 7, p, len); + node1 = add_mi_node_child(node_a, MI_DUP_VALUE, + "client", 6, p, len); if(node1 == NULL) goto error; if (internal_mi_print_b2bl_entity_id(node1, tuple->clients[index])!=0) goto error; } } - for (index = 0; index < MAX_BRIDGE_ENT; index++) + for (node_a=NULL,index=0; index < MAX_BRIDGE_ENT; index++) { if (tuple->bridge_entities[index] != NULL) { + if (node_a==NULL) { + node_a = add_mi_node_child(node, MI_IS_ARRAY, + "BRIDGE_ENTITIES", 15, NULL, 0); + if (node_a==NULL) goto error; + } p = int2str((unsigned long)(index), &len); - node1 = add_mi_node_child(node, MI_DUP_VALUE, - "bridge_entities", 15, p, len); + node1 = add_mi_node_child(node_a, MI_DUP_VALUE, + "bridge_entitie", 14, p, len); if(node1 == NULL) goto error; if (internal_mi_print_b2bl_entity_id(node1, tuple->bridge_entities[index])!=0) @@ -1618,7 +1647,8 @@ int b2b_logic_bind(b2bl_api_t* api) } -int b2bl_restore_upper_info(str* b2bl_key, b2bl_cback_f cbf, void* param) +int b2bl_restore_upper_info(str* b2bl_key, b2bl_cback_f cbf, void* param, + unsigned int cb_mask) { b2bl_tuple_t* tuple; unsigned int local_index, hash_index; @@ -1645,6 +1675,7 @@ int b2bl_restore_upper_info(str* b2bl_key, b2bl_cback_f cbf, void* param) return -1; } tuple->cbf = cbf; + tuple->cb_mask = cb_mask; tuple->cb_param = param; lock_release(&b2bl_htable[hash_index].lock); diff --git a/modules/b2b_logic/b2b_logic.h b/modules/b2b_logic/b2b_logic.h index 91b4efdf802..1cb226d4302 100644 --- a/modules/b2b_logic/b2b_logic.h +++ b/modules/b2b_logic/b2b_logic.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -82,6 +82,7 @@ enum { B2B_NOTIFY, B2B_REFER, B2B_CANCEL, + B2B_UPDATE, B2B_METHODS_NO }; @@ -156,6 +157,9 @@ static inline int b2b_get_request_id(str* request) if(request->len==MESSAGE_LEN &&strncasecmp(request->s, MESSAGE, MESSAGE_LEN)==0) return B2B_MESSAGE; + if(request->len==UPDATE_LEN &&strncasecmp(request->s, UPDATE, UPDATE_LEN)==0) + return B2B_UPDATE; + return -1; } diff --git a/modules/b2b_logic/b2bl_db.c b/modules/b2b_logic/b2bl_db.c index bee19dde97d..d75a08f3091 100644 --- a/modules/b2b_logic/b2bl_db.c +++ b/modules/b2b_logic/b2bl_db.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -534,7 +534,7 @@ int b2b_logic_restore(void) /* any more data to be fetched ?*/ if (DB_CAPABILITY(b2bl_dbf, DB_CAP_FETCH)) { if (b2bl_dbf.fetch_result( b2bl_db, &result, - B2BL_FETCH_SIZE ) < 0) + B2BL_FETCH_SIZE ) < 0) { LM_ERR("fetching more rows failed\n"); goto error; diff --git a/modules/b2b_logic/b2bl_db.h b/modules/b2b_logic/b2bl_db.h index c7b810914c9..e872c90b158 100644 --- a/modules/b2b_logic/b2bl_db.h +++ b/modules/b2b_logic/b2bl_db.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_logic/doc/b2b_logic_admin.xml b/modules/b2b_logic/doc/b2b_logic_admin.xml index 9e98797069b..6f2237d0200 100644 --- a/modules/b2b_logic/doc/b2b_logic_admin.xml +++ b/modules/b2b_logic/doc/b2b_logic_admin.xml @@ -156,7 +156,6 @@ modparam("b2b_logic", "cleanup_period", 60) from the dialog of one side to the other side. There are a number of headers that are passed by default. They are: - Max-Forwards (it is decreased by 1) Content-Type Supported Allow diff --git a/modules/b2b_logic/logic.c b/modules/b2b_logic/logic.c index d8308977b4f..bde9fc89bda 100644 --- a/modules/b2b_logic/logic.c +++ b/modules/b2b_logic/logic.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -187,7 +187,7 @@ int msg_add_dlginfo(b2bl_entity_id_t* entity, struct sip_msg* msg, str* totag) if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); return -1; @@ -198,7 +198,7 @@ int msg_add_dlginfo(b2bl_entity_id_t* entity, struct sip_msg* msg, str* totag) dlginfo.totag = *totag; dlginfo.callid = callid; dlginfo.fromtag= fromtag; - + if(entity_add_dlginfo(entity, &dlginfo) < 0) { LM_ERR("Failed to add dialoginfo\n"); @@ -266,7 +266,7 @@ int b2b_msg_get_from(struct sip_msg* msg, str* from_uri, str* from_dname) } if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); return -1; @@ -299,7 +299,7 @@ b2bl_entity_id_t* b2bl_create_new_entity(enum b2b_entity_type type, str* entity_ memset(entity, 0, size); size = sizeof(b2bl_entity_id_t); - + if(entity_id) { entity->key.s= (char*)entity+ size; @@ -547,7 +547,7 @@ int process_bridge_negreply(b2bl_tuple_t* tuple, ret = cbf(&cb_params, B2B_REJECT_CB); LM_DBG("ret = %d\n", ret); - + lock_get(&b2bl_htable[hash_index].lock); /* must search the tuple again * you can't know what might have happened with it */ @@ -584,8 +584,9 @@ b2bl_entity_id_t* b2bl_new_client(str* to_uri, str* from_uri, ci.extra_headers = tuple->extra_headers; ci.body = (tuple->sdp.s?&tuple->sdp:NULL); ci.from_tag = NULL; - ci.send_sock = msg?(msg->force_send_socket?msg->force_send_socket:msg->rcv.bind_address):NULL;; - get_local_contact( ci.send_sock, &ci.local_contact); + ci.send_sock = msg?(msg->force_send_socket?msg->force_send_socket:msg->rcv.bind_address):NULL; + if (ci.send_sock) get_local_contact( ci.send_sock, &ci.local_contact); + else ci.local_contact = server_address; if(msg) { @@ -627,7 +628,7 @@ int process_bridge_200OK(struct sip_msg* msg, str* extra_headers, bentity0 = tuple->bridge_entities[0]; bentity1 = tuple->bridge_entities[1]; - + if(bentity0 == NULL) { LM_ERR("Bridge entities 0 is NULL\n"); @@ -679,7 +680,7 @@ int process_bridge_200OK(struct sip_msg* msg, str* extra_headers, ci.extra_headers = extra_headers; ci.body = body; ci.from_tag = NULL; - ci.send_sock = msg->force_send_socket?msg->force_send_socket:msg->rcv.bind_address;; + ci.send_sock = msg->force_send_socket?msg->force_send_socket:msg->rcv.bind_address; get_local_contact( ci.send_sock, &ci.local_contact); if (str2int( &(get_cseq(msg)->number), &ci.cseq)!=0 ) @@ -738,6 +739,8 @@ int process_bridge_200OK(struct sip_msg* msg, str* extra_headers, /* store this sdp */ if(tuple->b1_sdp.s) shm_free(tuple->b1_sdp.s); + if (tuple->b1_sdp.s==tuple->sdp.s) + tuple->sdp.s = 0; tuple->b1_sdp.s = 0; if(body) { @@ -1037,7 +1040,7 @@ int b2b_logic_notify_reply(int src, struct sip_msg* msg, str* key, str* body, st LM_ERR("No b2b_key match found [%.*s], src=%d\n", key->len, key->s, src); goto error; } - if (entity->no < 0 || entity->no > 1) + if (entity->no > 1) { LM_ERR("unexpected entity->no [%d] for tuple [%p]\n", entity->no, tuple); goto error; @@ -1082,10 +1085,10 @@ int b2b_logic_notify_reply(int src, struct sip_msg* msg, str* key, str* body, st goto done; } - /* if a reply from the client side was received, + /* if a reply from the client side was received, * tell the server side to send a reply also */ - if((scenario && + if((scenario && scenario->reply_rules) || tuple->scenario_state == B2B_BRIDGING_STATE) { if(tuple->scenario_state == B2B_BRIDGING_STATE) /* if in a predefined state */ @@ -1285,7 +1288,7 @@ int b2b_logic_notify_reply(int src, struct sip_msg* msg, str* key, str* body, st if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); return -1; @@ -1295,7 +1298,7 @@ int b2b_logic_notify_reply(int src, struct sip_msg* msg, str* key, str* body, st ((struct to_body*)msg->from->parsed)->tag_value; dlginfo.fromtag = get_to(msg)->tag_value; - + shm_free(entity->dlginfo); entity->dlginfo = NULL; if(entity_add_dlginfo(entity, &dlginfo) < 0) @@ -1378,7 +1381,7 @@ int b2b_logic_notify_request(int src, struct sip_msg* msg, str* key, str* body, LM_ERR("No b2b_key match found [%.*s], src=%d\n", key->len, key->s, src); goto error; } - if (entity->no < 0 || entity->no > 1) + if (entity->no > 1) { LM_ERR("unexpected entity->no [%d] for tuple [%p]\n", entity->no, tuple); goto error; @@ -1534,7 +1537,7 @@ int b2b_logic_notify_request(int src, struct sip_msg* msg, str* key, str* body, LM_ERR("Failed to process BYE received in bridging state\n"); goto error; } - + if(tuple->to_del && entity->peer==NULL) { LM_DBG("Delete this b2bl record after process_bridge_bye\n"); @@ -1608,7 +1611,7 @@ int b2b_logic_notify_request(int src, struct sip_msg* msg, str* key, str* body, LM_ERR("Unexpected return code [%d]\n", ret); goto send_usual_request; } - + } break; } @@ -1617,7 +1620,7 @@ int b2b_logic_notify_request(int src, struct sip_msg* msg, str* key, str* body, { if(request_id == B2B_BYE) { - /* even though I don;t receive a reply, + /* even though I don;t receive a reply, I should delete this record*/ tuple->lifetime = 30 + get_ticks(); } @@ -1705,7 +1708,7 @@ int b2b_logic_notify_request(int src, struct sip_msg* msg, str* key, str* body, strncmp(attr.s, entity->scenario_id.s, attr.len) != 0)) { LM_DBG("Scenary id did not match - do not apply the rule" - " found [%.*s] , required [%s]\n", + " found [%.*s] , required [%s]\n", entity->scenario_id.len, entity->scenario_id.s, attr.s); xmlFree(attr.s); goto send_usual_request; @@ -2210,7 +2213,7 @@ int b2b_logic_notify(int src, struct sip_msg* msg, str* key, int type, void* par /* This function does the following actions: - * - extract the entities description from the scenario document + * - extract the entities description from the scenario document * - send invite or reInvite to one of the parties * - mark in the scenario instantiation which are the bridged entities and * that this scenario is currently taking place @@ -2414,12 +2417,12 @@ int process_bridge_action(struct sip_msg* msg, b2bl_entity_id_t* curr_entity, xmlFree(value_content); goto error; } - + } LM_DBG("New entity, dest = [%.*s]\n", entity_dest.len, entity_dest.s); entity = b2bl_create_new_entity(B2B_CLIENT, 0, &entity_dest, 0, from_dname.s?&from_dname:0, &attr, 0); - + if(fdname_content) xmlFree(fdname_content); fdname_content = 0; @@ -2453,7 +2456,7 @@ int process_bridge_action(struct sip_msg* msg, b2bl_entity_id_t* curr_entity, bridge_entities[0] = old_entity; } - /* I have the two entities -> now do the first step of the bridging scenario + /* I have the two entities -> now do the first step of the bridging scenario * -> send reInvite or Invite to one of the parties */ if(old_entity) { @@ -2498,7 +2501,8 @@ int process_bridge_action(struct sip_msg* msg, b2bl_entity_id_t* curr_entity, ci.body = 0; ci.from_tag = 0; ci.send_sock = msg?(msg->force_send_socket?msg->force_send_socket:msg->rcv.bind_address):0; - get_local_contact( ci.send_sock, &ci.local_contact); + if (ci.send_sock) get_local_contact( ci.send_sock, &ci.local_contact); + else ci.local_contact = server_address; if(msg) { @@ -2706,6 +2710,8 @@ str* create_top_hiding_entities(struct sip_msg* msg, b2bl_cback_f cbf, ci.body = (body.s?&body:NULL); ci.send_sock = msg->force_send_socket?msg->force_send_socket:msg->rcv.bind_address; get_local_contact( ci.send_sock, &ci.local_contact); + /* grab all AVPs from the server side and push them into the client */ + ci.avps = clone_avp_list( *get_avp_list() ); dlginfo = tuple->servers[0]->dlginfo; gen_fromtag(&dlginfo->callid, &dlginfo->fromtag, &ci.req_uri, msg, &from_tag_gen); @@ -2752,6 +2758,7 @@ str* create_top_hiding_entities(struct sip_msg* msg, b2bl_cback_f cbf, gen_fromtag(&dlginfo->callid, &dlginfo->fromtag, &uri, msg, &from_tag_gen); ci.from_tag = &from_tag_gen; ci.req_uri = uri; + ci.avps = clone_avp_list( *get_avp_list() ); client_id = b2b_api.client_new(&ci, b2b_client_notify, b2b_add_dlginfo, b2bl_key); if(client_id == NULL) @@ -2988,7 +2995,7 @@ int udh_to_uri(str user, str host, str port, str* uri) } -str* b2b_process_scenario_init(b2b_scenario_t* scenario_struct, +str* b2b_process_scenario_init(b2b_scenario_t* scenario_struct, struct sip_msg* msg, str* args[], b2bl_cback_f cbf, void* cb_param, unsigned int cb_mask, str* custom_hdrs, struct b2b_params *params) { @@ -3094,7 +3101,7 @@ str* b2b_process_scenario_init(b2b_scenario_t* scenario_struct, LM_ERR("A request for a server entity and no message\n"); goto error; } - /* a server entity can only deal with a message and there can + /* a server entity can only deal with a message and there can * only be one server entity */ /* extract the id */ entity_sid.s = (char*)xmlNodeGetNodeContentByName(server_node, @@ -3203,9 +3210,9 @@ str* b2b_process_scenario_init(b2b_scenario_t* scenario_struct, ci.send_sock = msg->force_send_socket? msg->force_send_socket:msg->rcv.bind_address; get_local_contact( ci.send_sock, &ci.local_contact); - - if (str2int( &(get_cseq(msg)->number), &ci.cseq)!=0 ) - { + /* grab all AVPs from the server side */ + ci.avps = clone_avp_list( *get_avp_list() ); + if (str2int( &(get_cseq(msg)->number), &ci.cseq)!=0 ) { LM_ERR("cannot parse cseq number\n"); goto error; } @@ -3401,6 +3408,8 @@ int b2b_init_request(struct sip_msg* msg, str* arg1, str* arg2, str* arg3, args[3] = arg5; args[4] = arg6; + b2b_api.apply_lumps(msg); + cust_headers = NULL; if (scf->params.flags & B2BL_FLAG_TRANSPARENT_AUTH) { @@ -3418,8 +3427,6 @@ int b2b_init_request(struct sip_msg* msg, str* arg1, str* arg2, str* arg3, } } - b2b_api.apply_lumps(msg); - /* call the scenario init processing function */ key = init_request(msg, scf, args, 0, NULL, 0, cust_headers); if(key) ret = 1; @@ -3490,7 +3497,7 @@ int b2bl_bridge(str* key, str* new_dst, str* new_from_dname, int entity_no) b2bl_print_tuple(tuple, L_ERR); goto error; } - LM_DBG("End peer dialog [%p]\n", old_entity); + LM_DBG("End peer dialog [%p]\n", old_entity); old_entity->peer = NULL; if(old_entity->disconnected && old_entity->state==B2BL_ENT_CONFIRMED) { @@ -3522,7 +3529,7 @@ int b2bl_bridge(str* key, str* new_dst, str* new_from_dname, int entity_no) ci.extra_headers = tuple->extra_headers; ci.body = tuple->b1_sdp.s?&tuple->b1_sdp:0; ci.cseq = 1; - get_local_contact( ci.send_sock, &ci.local_contact); + ci.local_contact = tuple->local_contact; client_id = b2b_api.client_new(&ci, b2b_client_notify, b2b_add_dlginfo, tuple->key); @@ -3645,7 +3652,7 @@ int b2bl_get_stats(str* key, b2bl_dlg_stat_t* stat) lock_release(&b2bl_htable[hash_index].lock); return -1; } - + if(stat && tuple->bridge_entities[0]) { stat->start_time = tuple->bridge_entities[0]->stats.start_time; @@ -3821,7 +3828,7 @@ int b2bl_bridge_2calls(str* key1, str* key2) LM_ERR("No entity found\n"); goto error; } - + e1 = tuple->bridge_entities[0]; if(e1 == NULL || e1->disconnected) { @@ -3857,7 +3864,7 @@ int b2bl_bridge_2calls(str* key1, str* key2) e2->peer = e1; e1->no = 0; e2->no = 1; - + if(b2b_api.update_b2bl_param(e2->type, &e2->key, tuple->key) < 0) { LM_ERR("Failed to update b2bl parameter in b2b_entities\n"); diff --git a/modules/b2b_logic/pidf.c b/modules/b2b_logic/pidf.c index 54944006ac2..92a32d134e3 100644 --- a/modules/b2b_logic/pidf.c +++ b/modules/b2b_logic/pidf.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_logic/pidf.h b/modules/b2b_logic/pidf.h index 59c9be91eae..59393861c3a 100644 --- a/modules/b2b_logic/pidf.h +++ b/modules/b2b_logic/pidf.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_logic/records.c b/modules/b2b_logic/records.c index 305a16b133c..f9bc2499bef 100644 --- a/modules/b2b_logic/records.c +++ b/modules/b2b_logic/records.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -219,7 +219,7 @@ b2bl_tuple_t* b2bl_insert_new(struct sip_msg* msg, lock_get(&b2bl_htable[hash_index].lock); - if(local_index>= 0) /* a local index specified */ + if(local_index>= 0) /* a local index specified */ { tuple->id = local_index; if(b2bl_htable[hash_index].first == NULL) @@ -233,7 +233,7 @@ b2bl_tuple_t* b2bl_insert_new(struct sip_msg* msg, /*insert it in the proper place */ for(it = b2bl_htable[hash_index].first; it && it->idnext) { - prev_it = it; + prev_it = it; } if(!prev_it) { @@ -244,13 +244,13 @@ b2bl_tuple_t* b2bl_insert_new(struct sip_msg* msg, } else { - tuple->prev = prev_it; + tuple->prev = prev_it; prev_it->next = tuple; tuple->next = it; if(it) it->prev = tuple; } - } + } } else { @@ -277,7 +277,7 @@ b2bl_tuple_t* b2bl_insert_new(struct sip_msg* msg, LM_DBG("hash index [%d]:\n", hash_index); for(it = b2bl_htable[hash_index].first; it; it=it->next) { - LM_DBG("id [%d]", it->id); + LM_DBG("id [%d]", it->id); } b2bl_key = b2bl_generate_key(hash_index, tuple->id); @@ -374,6 +374,7 @@ int b2bl_drop_entity(b2bl_entity_id_t* entity, b2bl_tuple_t* tuple) LM_ERR("inconsistent tuple [%p]->[%.*s]\n", tuple, tuple->key->len, tuple->key->s); } + break; default: LM_CRIT("we should never end up here\n"); } @@ -464,7 +465,7 @@ int b2bl_add_client(b2bl_tuple_t* tuple, b2bl_entity_id_t* entity) tuple, tuple->key->len, tuple->key->s); return -1; } - + /* check for inconsistencies */ for (i = pos + 1; i < MAX_B2BL_ENT; i++) @@ -505,7 +506,7 @@ int b2bl_add_server(b2bl_tuple_t* tuple, b2bl_entity_id_t* entity) tuple, tuple->key->len, tuple->key->s); return -1; } - + b2bl_print_tuple(tuple, L_DBG); return 0; } @@ -522,7 +523,11 @@ void b2bl_delete(b2bl_tuple_t* tuple, unsigned int hash_index, LM_DBG("Delete record [%p]->[%.*s], hash_index=[%d], local_index=[%d]\n", tuple, tuple->key->len, tuple->key->s, hash_index, tuple->id); - if(tuple->cbf && tuple->cb_mask&B2B_DESTROY_CB) + /* + * razvanc: if the tuple is not actually deleted, we do not have to call + * the DESTROY callback + */ + if(!not_del_b2be && tuple->cbf && tuple->cb_mask&B2B_DESTROY_CB) { memset(&cb_params, 0, sizeof(b2bl_cb_params_t)); cb_params.param = tuple->cb_param; @@ -622,7 +627,7 @@ int b2bl_parse_key(str* key, unsigned int* hash_index, s.len = hi_len; if(str2int(&s, hash_index)< 0) return -1; - + s.s = p+1; s.len = key->s + key->len - s.s; if(str2int(&s, local_index)< 0) @@ -674,7 +679,7 @@ int init_b2bl_htable(void) b2bl_htable = (b2bl_table_t)shm_malloc(b2bl_hsize* sizeof(b2bl_entry_t)); if(!b2bl_htable) ERR_MEM(SHARE_MEM); - + memset(b2bl_htable, 0, b2bl_hsize* sizeof(b2bl_entry_t)); for(i= 0; i< b2bl_hsize; i++) { @@ -710,8 +715,8 @@ void destroy_b2bl_htable(void) } /* Take headers to pass on the other side: - * Content-Type: - * Allow: + * Content-Type: + * Allow: * Supported: * Require * RSeq @@ -749,7 +754,7 @@ int b2b_extra_headers(struct sip_msg* msg, str* b2bl_key, str* custom_hdrs, hdrs[hdrs_no++] = msg->min_se; if(msg->event) hdrs[hdrs_no++] = msg->event; - + require_hdr = get_header_by_static_name( msg, "Require"); if(require_hdr) diff --git a/modules/b2b_logic/records.h b/modules/b2b_logic/records.h index 5e14ae47c82..9b43289c2b3 100644 --- a/modules/b2b_logic/records.h +++ b/modules/b2b_logic/records.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/b2b_sca/.gitignore b/modules/b2b_sca/.gitignore new file mode 100644 index 00000000000..fd9c310e24f --- /dev/null +++ b/modules/b2b_sca/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +*.d diff --git a/modules/b2b_sca/Makefile b/modules/b2b_sca/Makefile new file mode 100644 index 00000000000..862cd6c0555 --- /dev/null +++ b/modules/b2b_sca/Makefile @@ -0,0 +1,10 @@ +# $Id: Makefile 806 2006-04-14 11:00:10Z bogdan_iancu $ +# +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=b2b_sca.so +LIBS= + +include ../../Makefile.modules diff --git a/modules/b2b_sca/README b/modules/b2b_sca/README new file mode 100644 index 00000000000..9a92177bf0a --- /dev/null +++ b/modules/b2b_sca/README @@ -0,0 +1,455 @@ +b2b_sca Module + +Ovidiu Sas + + + +Edited by + +Ovidiu Sas + + Copyright © 2011-2013 VoIP Embedded, Inc. + Revision History + Revision $Rev: 8688 $ $Date: 2012-01-25 13:52:05 -0500 (Wed, 25 + Jan 2012) $ + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. To-do + 1.3. Dependencies + + 1.3.1. OpenSIPS Modules + + 1.4. Exported Parameters + + 1.4.1. hash_size(integer) + 1.4.2. presence_server(string) + 1.4.3. watchers_avp_spec(string) + 1.4.4. shared_line_spec_param(string) + 1.4.5. appearance_name_addr_spec_param(string) + 1.4.6. db_url(string) + 1.4.7. db_mode(integer) + 1.4.8. table_name(string) + 1.4.9. shared_line_column(string) + 1.4.10. watchers_column(string) + 1.4.11. app[index]_shared_entity_column(string) + 1.4.12. app[index]_call_state_column(string) + 1.4.13. app[index]_call_info_uri_column(string) + 1.4.14. + app[index]_call_info_appearance_uri_column(st + ring) + + 1.4.15. app[index]_b2bl_key_column(string) + + 1.5. Exported Functions + + 1.5.1. sca_init_request(shared_line) + 1.5.2. sca_bridge_request(shared_line_to bridge) + + 1.6. Exported MI Functions + + 1.6.1. sca_list + + List of Examples + + 1.1. Set hash_size parameter + 1.2. Set presence_server parameter + 1.3. Set watchers_avp_spec parameter + 1.4. Set shared_line_spec_param parameter + 1.5. Set appearance_name_addr_spec_param parameter + 1.6. Set db_url parameter + 1.7. Set db_mode parameter + 1.8. Set table_name parameter + 1.9. Set shared_line_column parameter + 1.10. Set watchers_column parameter + 1.11. Set app[index]_shared_entity_column parameter + 1.12. Set app[index]_call_state_column parameter + 1.13. Set app[index]_call_info_uri_column parameter + 1.14. Set app[index]_call_info_appearance_uri_column parameter + 1.15. Set app[index]_b2bl_key_column parameter + 1.16. sca_init_request() usage + +Chapter 1. Admin Guide + +1.1. Overview + + This module provides core SCA (Shared Call Appearance) + functionality for OpenSIPS. It is designed to work in tandem + with the presence_callinfo module. + + The module handles the basic SIP signalling for call controll + while publishing callinfo events to a presence server. It is + built on top of the b2b_logic module and it is using the 'top + hiding' scenario to control SIP signalling. + + A typical usage example is provided below, where Alice makes a + call to Bob. The call leg between Alice and the b2b_sca server + is an "appearance" call of the "shared" call between the + b2b_sca server and Bob. + + caller caller b2b_sca callee presence server +alice1@example alice2@example server bob@example watcher@example + | | | | | + |--INV bob------------------>| | | + | | |--INV bob->| | + | | |--PUBLISH(alerting)--->| + | | |<-----200 OK-----------| + | | | | | + | | |<-180 ring-| | + |<-180 ring------------------| | | + | | | | | + | | | | | + | | |<-200 OK---| | + |<-200 OK--------------------|--ACK----->| | + |--ACK---------------------->|--PUBLISH(active)----->| + | | |<-----200 OK-----------| + | | | | | + |--INV bob (hold)----------->| | | + | | |--INV bob->| | + | | |--PUBLISH(held)------->| + | | |<-----200 OK-----------| + | | |<-200 OK---| | + |<--200 OK-------------------| | | + | | | | | + | |--INV------->| | | + | | |--INV bob->| | + |<-BYE-----------------------|--PUBLISH(active)----->| + |--200 OK------------------->|<-----200 OK-----------| + | | |<-200 OK---| | + | |<-200 OK-----| | + + + * Alice calls Bob from her desk IP phone (alice1). + * Bob answers the call. + * Alice decide to carry the conversation from a meeting room + and she put's BOB on hold. + * Alice arrives to the meeting room and retrieves the call on + the conference room IP phone (alice2). + +1.2. To-do + + Features to be added in the future: + * possibility to handle unlimited number of appearances. + +1.3. Dependencies + +1.3.1. OpenSIPS Modules + + The following modules must be loaded before this module: + * tm module. pua module. b2b_logic module. + +1.4. Exported Parameters + +1.4.1. hash_size(integer) + + The size of the hash table internally used to keep the shared + calls. A larger table means faster acces at the expense of + memory. The hash size is a power of number two. + + The default value is "10". + + Example 1.1. Set hash_size parameter +... +modparam("b2b_sca", "hash_size", "5") +... + +1.4.2. presence_server(string) + + The address of the presence server, where the PUBLISH messages + should be sent (not compulsory). If not set, the PUBLISH + requests will be routed based on watcher's URI. + + The default value is "NULL". + + Example 1.2. Set presence_server parameter +... +modparam("b2b_sca", "presence_server", "sip:opensips.org") +... + +1.4.3. watchers_avp_spec(string) + + AVP that will hold one or more watcher URI(s). If not set, no + PUBLISH requests will be sent out. The watchers_avp_spec MUST + be set before calling sca_init_request(); + + The default value is "NULL". + + Example 1.3. Set watchers_avp_spec parameter +... +modparam("b2b_sca", "watchers_avp_spec", "$avp(watchers_avp_spec)") +... +route { + ... + $avp(watchers_avp_spec) = "sip:first_watcher@opensip.org"; + $avp(watchers_avp_spec) = "sip:second_watcher@opensip.org"; + ... +} + +1.4.4. shared_line_spec_param(string) + + Mandatory parameter. Opaque string identifing the shared + line/call. The shared_line_spec_param MUST be set before + calling sca_init_request(); + + The default value is "NULL". + + Example 1.4. Set shared_line_spec_param parameter +... +modparam("b2b_sca", "shared_line_spec_param", "$var(shared_line)") +... + +1.4.5. appearance_name_addr_spec_param(string) + + Mandatory parameter. It must be a valid SIP URI. It will + populate the appearance-uri SIP parameter inside the Call-Info + SIP header. The appearance_name_addr_spec_param MUST be set + before calling sca_init_request(); + + The default value is "NULL". + + Example 1.5. Set appearance_name_addr_spec_param parameter +... +modparam("b2b_sca", "appearance_name_addr_spec_param", "") +... + +1.4.6. db_url(string) + + This is URL of the database to be used. + + The default value is "NULL". + + Example 1.6. Set db_url parameter +... +modparam("b2b_sca", "db_url", "[dbdriver]://[[username]:[password]]@[dbh +ost]/[dbname]") +... + +1.4.7. db_mode(integer) + + The b2b_sca module can utilize database for persistent call + appearance storage. Using a database ensure that active call + appearances will survive machine restarts or SW crashes. The + following databse accessing modes are available for b2b_sca + module: + + * NO DB STORAGE - set this parameter to 0 + * WRITE THROUGH (synchronous write in database) - set this + parameter to 1 + + The default value is 0 (NO DB STORAGE). + + Example 1.7. Set db_mode parameter +... +modparam("b2b_sca", "db_mode", 1) +... + +1.4.8. table_name(string) + + Identifies the table name from the defined database. + + The default value is "sca". + + Example 1.8. Set table_name parameter +... +modparam("b2b_sca", "table_name", "sla") +... + +1.4.9. shared_line_column(string) + + The column's name in the database storing the shared call/line + id. See "shared_line_spec_param" parameter. + + The default value is "shared_line". + + Example 1.9. Set shared_line_column parameter +... +modparam("b2b_sca", "shared_line_column", "") +... + +1.4.10. watchers_column(string) + + The column's name in the database storing the list of watchers. + See "watchers_avp_spec" parameter. + + The default value is "watchers". + + Example 1.10. Set watchers_column parameter +... +modparam("b2b_sca", "watchers_column", "") +... + +1.4.11. app[index]_shared_entity_column(string) + + The column's name in the database storing the shared entity of + a particular appearance. See "sca_init_request" for more info. + + The default value is "app[index]_shared_entity". Index is an + integer between 1 and 10. + + Example 1.11. Set app[index]_shared_entity_column parameter +... +modparam("b2b_sca", "app1_shared_entity_column", "first_shared_entity") +modparam("b2b_sca", "app2_shared_entity_column", "second_shared_entity") +... + +1.4.12. app[index]_call_state_column(string) + + The column's name in the database storing the call state of a + particular appearance. The following states are stored: + + * 1 - alerting, + * 2 - active, + * 3 - held, + * 4 - held-private. + + The default value is "app[index]_call_state". Index is an + integer between 1 and 10. + + Example 1.12. Set app[index]_call_state_column parameter +... +modparam("b2b_sca", "app1_call_state_column", "first_call_state") +modparam("b2b_sca", "app2_call_state_column", "second_call_state") +... + +1.4.13. app[index]_call_info_uri_column(string) + + The column's name in the database storing the call info URI of + a particular appearance. + + The default value is "app[index]_call_info_uri". Index is an + integer between 1 and 10. + + Example 1.13. Set app[index]_call_info_uri_column parameter +... +modparam("b2b_sca", "app1_call_info_uri_column", "first_call_info_uri") +modparam("b2b_sca", "app2_call_info_uri_column", "second_call_info_uri") +... + +1.4.14. app[index]_call_info_appearance_uri_column(string) + + The column's name in the database storing the call info + appearance URI of a particular appearance. For each appearance, + the value is extracted from the + "appearance_name_addr_spec_param" parameter. + + The default value is "app[index]_call_info_appearance_uri". + Index is an integer between 1 and 10. + + Example 1.14. Set app[index]_call_info_appearance_uri_column + parameter +... +modparam("b2b_sca", "app1_call_info_appearance_uri_column", "first_call_ +info_appearance_uri") +modparam("b2b_sca", "app2_call_info_appearance_uri_column", "second_call +_info_appearance_uri") +... + +1.4.15. app[index]_b2bl_key_column(string) + + The column's name in the database storing the b2b_logic key of + a particular appearance. + + The default value is "app[index]_b2bl_key". Index is an integer + between 1 and 10. + + Example 1.15. Set app[index]_b2bl_key_column parameter +... +modparam("b2b_sca", "app1_b2bl_key_column", "first_b2bl_key") +modparam("b2b_sca", "app2_b2bl_key_column", "second_b2bl_key") +... + +1.5. Exported Functions + +1.5.1. sca_init_request(shared_line) + + This is the function that must be called by the script writer + on an initial INVITE for which an SCA call must be instantiated + (see the call from alice1 in the above diagram). + + Meaning of the parameters: + * shared_line - a PV (pseudo-variable) identifying the call + leg as being an "appearnace" call or a "shared" call: + + 0: "shared" call + + 1: "appearance" call + + Example 1.16. sca_init_request() usage +... +modparam("b2b_sca", + "shared_line_spec_param","$var(shared_line)") +modparam("b2b_sca", + "appearance_name_addr_spec_param","$var(appearance_name_addr)") +modparam("b2b_sca", + "watchers_avp_spec","$avp(watchers_avp_spec)") + +... + + # Setting the shared call identifier + $var(shared_line) = "alice"; + + # Setting the watchers + $avp(watchers_avp_spec) = "sip:alice1@example.com"; + $avp(watchers_avp_spec) = "sip:alice2@example.com"; + + if (INCOMING_SHARED_CALL) { + # The incoming call is a 'shared' call + $var(shared_line_entity) = 0; + # Setting the appearance name address + $var(appearance_name_addr) = $fu; + } + else { + # The incoming call is an 'appearance' call + # - see Alice's initial call leg in the given example + $var(shared_line_entity) = 1; + # Setting the appearance name address + $var(appearance_name_addr) = $tu; + } + + # Initiate the call + if (!sca_init_request("$var(shared_line_entity)")) { + send_reply("403", "Internal Server Error (SLA)"); + exit; + } +... + +1.5.2. sca_bridge_request(shared_line_to bridge) + + This is the function that must be called by the script writer + on an initial "appearance" INVITE for an existing shared call. + It will bridge the current "appearance" call with the existing + "shared" call and the old "appearance" call will be + disconnected (see the call from alice2 in the above diagram). + + Meaning of the parameters: + * shared_line_to_bridge - a PV identifying the shared + line/call that was previously set by sca_init_request(). + +... + if ($rU==NULL && is_method("INVITE") && + $fU==$tU && is_present_hf("Call-Info")) { + # The incoming call is an 'appearance' call + # - see Alice's call from alice2 in the given example + $var(shared_line_to_bridge) = "alice"; + if (!sca_bridge_request("$var(shared_line_to_bridge)")) + send_reply("403", "Internal SLA Error"); + exit; + } + } +... + +1.6. Exported MI Functions + +1.6.1. sca_list + + It lists the appearances belonging to a shared line/call. + + Name: sca_list + + Parameters: none + + MI FIFO Command Format: + :sca_list:_reply_fifo_file_ + _empty_line_ diff --git a/modules/b2b_sca/b2b_sca.c b/modules/b2b_sca/b2b_sca.c new file mode 100644 index 00000000000..d0ddde01300 --- /dev/null +++ b/modules/b2b_sca/b2b_sca.c @@ -0,0 +1,546 @@ +/* + * $Id$ + * + * b2b_sca module + * + * Copyright (C) 2010 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-11-02 initial version (Ovidiu Sas) + */ + +#include +#include +#include + +#include "../../sr_module.h" +#include "../../dprint.h" +#include "../../mod_fix.h" +#include "../../trim.h" +#include "../../db/db.h" +#include "../../parser/parse_from.h" +#include "../tm/tm_load.h" +#include "../pua/pua_bind.h" +#include "../b2b_logic/b2b_load.h" +#include "sca_records.h" +#include "sca_logic.h" +#include "sca_db_handler.h" + +extern str app_state[]; + + +/** Functions declarations */ +static int mod_init(void); +static void mod_destroy(void); +static int child_init(int rank); +int sca_init_request(struct sip_msg* msg); +int sca_bridge_request(struct sip_msg* msg, str* arg1, str* arg2); +static struct mi_root* mi_sca_list(struct mi_root* cmd, void* param); + +/** Global variables */ +struct tm_binds tmb; +pua_api_t pua_api; +b2bl_api_t b2bl_api; + +b2b_sca_table_t b2b_sca_htable; +unsigned int b2b_sca_hsize = 10; + +static str db_url = {NULL, 0}; + +int watchers_avp_name = -1; +unsigned short watchers_avp_type = 0; +static str watchers_avp_spec = {NULL, 0}; +static pv_spec_t watchers_spec; + +static str shared_line_spec_param = {NULL, 0}; +static pv_spec_t shared_line_spec; +static pv_value_t shared_line_tok; + +static str appearance_name_addr_spec_param = {NULL, 0}; +static pv_spec_t appearance_name_addr_spec; +static pv_value_t appearance_name_addr_tok; +static struct to_body appearance_name_addr; + +#define APPEARANCE_NAME_ADDR_BUF_LEN 255 +static char appearance_name_addr_buf[APPEARANCE_NAME_ADDR_BUF_LEN + 1]; + +str presence_server = {NULL, 0}; + + +/** Exported functions */ +static cmd_export_t cmds[]= +{ + {"sca_init_request" ,(cmd_function)sca_init_request ,1,fixup_pvar_pvar,0,REQUEST_ROUTE}, + {"sca_bridge_request",(cmd_function)sca_bridge_request,1,fixup_pvar_pvar,0,REQUEST_ROUTE}, + { 0, 0, 0 , 0 , 0, 0} +}; + +/** Exported parameters */ +static param_export_t params[]= +{ + {"hash_size", INT_PARAM,&b2b_sca_hsize }, + {"presence_server", STR_PARAM,&presence_server.s }, + {"watchers_avp_spec", STR_PARAM,&watchers_avp_spec.s }, + {"shared_line_spec_param", STR_PARAM,&shared_line_spec_param.s }, + {"appearance_name_addr_spec_param", STR_PARAM,&appearance_name_addr_spec_param.s }, + {"db_url", STR_PARAM,&db_url.s }, + {"db_mode", INT_PARAM,&sca_db_mode }, + {"table_name", STR_PARAM,&sca_table_name }, + {"shared_line_column", STR_PARAM,&shared_line_column.s }, + {"watchers_column", STR_PARAM,&watchers_column.s }, + {"app1_shared_entity_column", STR_PARAM,&app_shared_entity_column[0].s }, + {"app1_call_state_column", STR_PARAM,&app_call_state_column[0].s }, + {"app1_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[0].s }, + {"app1_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[0].s}, + {"app1_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[0].s }, + {"app2_shared_entity_column", STR_PARAM,&app_shared_entity_column[1].s }, + {"app2_call_state_column", STR_PARAM,&app_call_state_column[1].s }, + {"app2_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[1].s }, + {"app2_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[1].s}, + {"app2_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[1].s }, + {"app3_shared_entity_column", STR_PARAM,&app_shared_entity_column[2].s }, + {"app3_call_state_column", STR_PARAM,&app_call_state_column[2].s }, + {"app3_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[2].s }, + {"app3_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[2].s}, + {"app3_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[2].s }, + {"app4_shared_entity_column", STR_PARAM,&app_shared_entity_column[3].s }, + {"app4_call_state_column", STR_PARAM,&app_call_state_column[3].s }, + {"app4_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[3].s }, + {"app4_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[3].s}, + {"app4_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[3].s }, + {"app5_shared_entity_column", STR_PARAM,&app_shared_entity_column[4].s }, + {"app5_call_state_column", STR_PARAM,&app_call_state_column[4].s }, + {"app5_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[4].s }, + {"app5_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[4].s}, + {"app5_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[4].s }, + {"app6_shared_entity_column", STR_PARAM,&app_shared_entity_column[5].s }, + {"app6_call_state_column", STR_PARAM,&app_call_state_column[5].s }, + {"app6_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[5].s }, + {"app6_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[5].s}, + {"app6_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[5].s }, + {"app7_shared_entity_column", STR_PARAM,&app_shared_entity_column[6].s }, + {"app7_call_state_column", STR_PARAM,&app_call_state_column[6].s }, + {"app7_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[6].s }, + {"app7_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[6].s}, + {"app7_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[6].s }, + {"app8_shared_entity_column", STR_PARAM,&app_shared_entity_column[7].s }, + {"app8_call_state_column", STR_PARAM,&app_call_state_column[7].s }, + {"app8_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[7].s }, + {"app8_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[7].s}, + {"app8_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[7].s }, + {"app9_shared_entity_column", STR_PARAM,&app_shared_entity_column[8].s }, + {"app9_call_state_column", STR_PARAM,&app_call_state_column[8].s }, + {"app9_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[8].s }, + {"app9_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[8].s}, + {"app9_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[8].s }, + {"app10_shared_entity_column", STR_PARAM,&app_shared_entity_column[9].s }, + {"app10_call_state_column", STR_PARAM,&app_call_state_column[9].s }, + {"app10_call_info_uri_column", STR_PARAM,&app_call_info_uri_column[9].s }, + {"app10_call_info_appearance_uri_column",STR_PARAM,&app_call_info_appearance_uri_column[9].s}, + {"app10_b2bl_key_column", STR_PARAM,&app_b2bl_key_column[9].s }, + {0, 0, 0 } +}; + +/** MI commands */ +static mi_export_t mi_cmds[] = { + { "sca_list", 0, mi_sca_list, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0} +}; + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "pua", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "b2b_logic", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + +/** Module interface */ +struct module_exports exports= { + "b2b_sca", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ + MODULE_VERSION, /* module version */ + DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ + cmds, /* exported functions */ + params, /* exported parameters */ + 0, /* exported statistics */ + mi_cmds, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + (response_function) 0, /* response handling function */ + (destroy_function) mod_destroy, /* destroy function */ + child_init /* per-child init function */ +}; + +/** Module init function */ +static int mod_init(void) +{ + unsigned int i; + + LM_DBG("start\n"); + + init_db_url( db_url , 0 /*cannot be null*/); + + /* load tm api */ + if(load_tm_api(&tmb)==-1) + { + LM_ERR("can't load tm functions\n"); + return -1; + } + + /* load pua api */ + if(load_pua_api(&pua_api) < 0) + { + LM_ERR("Can't bind pua\n"); + return -1; + } + /* add event in pua module */ + if(pua_api.add_event(CALLINFO_EVENT, "call-info", NULL, 0) < 0) { + LM_ERR("failed to add 'call-info' event to pua module\n"); + return -1; + } + + /* load b2b_logic api */ + if(load_b2b_logic_api(&b2bl_api)< 0) + { + LM_ERR("Failed to load b2b_logic api\n"); + return -1; + } + + if(b2b_sca_hsize<1 || b2b_sca_hsize>20) + { + LM_ERR("Wrong hash size. Needs to be greater than 1" + " and smaller than 20. Be aware that you should set the log 2" + " value of the real size\n"); + return -1; + } + b2b_sca_hsize = 1<=0 || rank==PROC_TIMER || rank==PROC_MODULE)) { + if (connect_sca_db(&db_url)) { + LM_ERR("failed to connect to database (rank=%d)\n",rank); + return -1; + } + } + + return 0; +} + + +static void mod_destroy(void) +{ + //if (sca_db_mode != DB_MODE_NONE) { + // sca_update_db(); + //} + destroy_b2b_sca_handlers(); + destroy_b2b_sca_htable(); + + LM_DBG("done\n"); + return; +} + + +int get_hash_index_and_shared_line(struct sip_msg* msg, unsigned int *hash_index, str **shared_line) +{ + if(shared_line_spec_param.s) + { + memset(&shared_line_tok, 0, sizeof(pv_value_t)); + if(pv_get_spec_value(msg, &shared_line_spec, &shared_line_tok) < 0) + { + LM_ERR("Failed to get shared_line value\n"); + return -1; + } + //LM_DBG("got shared_line_spec_param flags [%d]\n", shared_line_tok.flags); + if(!(shared_line_tok.flags&PV_VAL_INT) && (shared_line_tok.flags&PV_VAL_STR)) + { + *shared_line = &shared_line_tok.rs; + *hash_index = core_hash(&shared_line_tok.rs, NULL, b2b_sca_hsize); + //LM_DBG("got hash_index=[%d] for PV_SPEC user [%.*s]\n", *hash_index, + // shared_line_tok.rs.len, shared_line_tok.rs.s); + return 0; + } + else + { + LM_ERR("No shared line PV [%.*s] defined\n", + shared_line_spec_param.len, shared_line_spec_param.s); + return -1; + } + } + else + { + LM_ERR("No shared line PV defined\n"); + return -1; + } + + /* If the shared_line_spec_param is not set, use the username from original RURI */ + /* + parse_orig_ruri(msg); + if (msg->parsed_orig_ruri_ok && + msg->parsed_orig_ruri.user.s && msg->parsed_orig_ruri.user.len) { + *shared_line = &msg->parsed_orig_ruri.user; + *hash_index = core_hash(&msg->parsed_orig_ruri.user, NULL, b2b_sca_hsize); + //LM_DBG("got hash_index=[%d] for RURI user [%.*s]\n", *hash_index, + // msg->parsed_orig_ruri.user.len, msg->parsed_orig_ruri.user.s); + return 0; + } else { + LM_ERR("msg->parsed_orig_ruri_ok is NULL\n"); + } + */ + + return -1; +} + + +struct to_body* get_appearance_name_addr(struct sip_msg* msg) +{ + int len = 0; + + if(appearance_name_addr_spec_param.s) + { + memset(&appearance_name_addr_tok, 0, sizeof(pv_value_t)); + if(pv_get_spec_value(msg, &appearance_name_addr_spec, &appearance_name_addr_tok) < 0) + { + LM_ERR("Failed to get appearance_name_addr value\n"); + return NULL; + } + //LM_DBG("got appearance_name_addr_spec_param flags [%d]\n", appearance_name_addr_tok.flags); + if(!(appearance_name_addr_tok.flags&PV_VAL_INT) && + (appearance_name_addr_tok.flags&PV_VAL_STR)) + { + //LM_DBG("got PV_SPEC appearance_name_addr [%.*s]\n", + // appearance_name_addr_tok.rs.len, appearance_name_addr_tok.rs.s); + if(appearance_name_addr_tok.rs.len+CRLF_LEN > APPEARANCE_NAME_ADDR_BUF_LEN) { + LM_ERR("Buffer overflow"); + return NULL; + } + trim(&appearance_name_addr_tok.rs); + memcpy(appearance_name_addr_buf, appearance_name_addr_tok.rs.s, + appearance_name_addr_tok.rs.len); + len = appearance_name_addr_tok.rs.len; + if(strncmp(appearance_name_addr_tok.rs.s + len - CRLF_LEN, CRLF, CRLF_LEN)) { + memcpy(appearance_name_addr_buf + len, CRLF, CRLF_LEN); + len+= CRLF_LEN; + } + + parse_to(appearance_name_addr_buf, appearance_name_addr_buf+len, + &appearance_name_addr); + if (appearance_name_addr.error != PARSE_OK) { + LM_ERR("Failed to parse PV_SPEC appearance_name_addr [%.*s]\n", + len, appearance_name_addr_buf); + return NULL; + } + if (parse_uri(appearance_name_addr.uri.s, appearance_name_addr.uri.len, + &appearance_name_addr.parsed_uri)<0) { + LM_ERR("failed to parse PV_SPEC appearance_name_addr uri [%.*s]\n", + appearance_name_addr.uri.len, appearance_name_addr.uri.s); + return NULL; + } + return &appearance_name_addr; + } + } + + /* If the appearance_name_addr_spec_param is not set, use the From uri */ + /* + if (msg->from->parsed == NULL) { + if (parse_from_header(msg)<0) { + LM_ERR("cannot parse From header\n"); + return NULL; + } + } + */ + + return msg->from->parsed; +} + + +static struct mi_root* mi_sca_list(struct mi_root* cmd, void* param) +{ + int i, index; + struct mi_root *rpl_tree; + struct mi_node *node=NULL, *node1=NULL, *rpl=NULL; + struct mi_attr* attr; + b2b_sca_record_t *rec; + b2b_sca_call_t *call; + str_lst_t *watcher; + + rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); + if (rpl_tree==NULL) return NULL; + rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; + + for(index = 0; indexshared_line.s, rec->shared_line.len); + if(node == NULL) goto error; + watcher = rec->watchers; + while (watcher) { + attr = add_mi_attr(node, MI_DUP_VALUE, "watcher", 7, + watcher->watcher.s, watcher->watcher.len); + if(attr == NULL) goto error; + watcher = watcher->next; + } + for (i=0; icall[i]) { + call = rec->call[i]; + node1 = add_mi_node_child(node, MI_DUP_VALUE, + "appearance", 10, + call->appearance_index_str.s, + call->appearance_index_str.len); + if(node1 == NULL) goto error; + attr = add_mi_attr(node1, MI_DUP_VALUE, "state", 5, + app_state[call->call_state].s, + app_state[call->call_state].len); + if(attr == NULL) goto error; + attr = add_mi_attr(node1, MI_DUP_VALUE, "b2b_key", 7, + call->b2bl_key.s, call->b2bl_key.len); + if(attr == NULL) goto error; + attr = add_mi_attr(node1, MI_DUP_VALUE, "app_uri", 7, + call->call_info_apperance_uri.s, + call->call_info_apperance_uri.len); + if(attr == NULL) goto error; + } + } + + rec = rec->next; + } + lock_release(&b2b_sca_htable[index].lock); + } + return rpl_tree; +error: + lock_release(&b2b_sca_htable[index].lock); + LM_ERR("Unable to create reply\n"); + free_mi_tree(rpl_tree); + return NULL; +} + diff --git a/modules/b2b_sca/doc/b2b_sca.xml b/modules/b2b_sca/doc/b2b_sca.xml new file mode 100644 index 00000000000..193916c4ac6 --- /dev/null +++ b/modules/b2b_sca/doc/b2b_sca.xml @@ -0,0 +1,50 @@ + + + + + + +%docentities; + +]> + + + + b2b_sca Module + &osipsname; + + + Ovidiu + Sas + osas@voipembedded.com + + + Ovidiu + Sas + + + + 2011-2013 + + VoIP Embedded, Inc. + + + + + $Rev: 8688 $ + $Date: 2012-01-25 13:52:05 -0500 (Wed, 25 Jan 2012) $ + + + + + + &admin; + &faq; + + + + diff --git a/modules/b2b_sca/doc/b2b_sca_admin.xml b/modules/b2b_sca/doc/b2b_sca_admin.xml new file mode 100644 index 00000000000..8bb98b49e6e --- /dev/null +++ b/modules/b2b_sca/doc/b2b_sca_admin.xml @@ -0,0 +1,518 @@ + + + + + &adminguide; + +
Overview + + This module provides core SCA (Shared Call Appearance) functionality + for &osips;. + It is designed to work in tandem with the presence_callinfo module. + + + The module handles the basic SIP signalling for call controll while + publishing callinfo events to a presence server. + It is built on top of the b2b_logic module and it is using the + 'top hiding' scenario to control SIP signalling. + + + A typical usage example is provided below, where Alice makes a + call to Bob. The call leg between Alice and the b2b_sca server + is an "appearance" call of the "shared" call between the b2b_sca server + and Bob. + + +| | | + | | |--INV bob->| | + | | |--PUBLISH(alerting)--->| + | | |<-----200 OK-----------| + | | | | | + | | |<-180 ring-| | + |<-180 ring------------------| | | + | | | | | + | | | | | + | | |<-200 OK---| | + |<-200 OK--------------------|--ACK----->| | + |--ACK---------------------->|--PUBLISH(active)----->| + | | |<-----200 OK-----------| + | | | | | + |--INV bob (hold)----------->| | | + | | |--INV bob->| | + | | |--PUBLISH(held)------->| + | | |<-----200 OK-----------| + | | |<-200 OK---| | + |<--200 OK-------------------| | | + | | | | | + | |--INV------->| | | + | | |--INV bob->| | + |<-BYE-----------------------|--PUBLISH(active)----->| + |--200 OK------------------->|<-----200 OK-----------| + | | |<-200 OK---| | + | |<-200 OK-----| | +]]> + + + + Alice calls Bob from her desk IP phone (alice1). + + + Bob answers the call. + + + Alice decide to carry the conversation from a meeting room + and she put's BOB on hold. + + + Alice arrives to the meeting room and retrieves the call on the + conference room IP phone (alice2). + + +
+ +
+ To-do + + Features to be added in the future: + + + + possibility to handle unlimited number of appearances. + + +
+ +
Dependencies +
+ &osips; Modules + + The following modules must be loaded before this module: + + + + tm module. + pua module. + b2b_logic module. + + + + +
+
+ +
Exported Parameters +
+ <varname>hash_size</varname>(integer) + + The size of the hash table internally used to keep the shared calls. + A larger table means faster acces at the expense of memory. + The hash size is a power of number two. + + + The default value is "10". + + + Set <varname>hash_size</varname> parameter + +... +modparam("b2b_sca", "hash_size", "5") +... + + +
+
+ <varname>presence_server</varname>(string) + + The address of the presence server, where the PUBLISH + messages should be sent (not compulsory). + If not set, the PUBLISH requests will be routed based + on watcher's URI. + + + The default value is "NULL". + + + Set <varname>presence_server</varname> parameter + +... +modparam("b2b_sca", "presence_server", "sip:opensips.org") +... + + +
+
+ <varname>watchers_avp_spec</varname>(string) + + AVP that will hold one or more watcher URI(s). + If not set, no PUBLISH requests will be sent out. + The watchers_avp_spec MUST be set before calling sca_init_request(); + + + The default value is "NULL". + + + Set <varname>watchers_avp_spec</varname> parameter + +... +modparam("b2b_sca", "watchers_avp_spec", "$avp(watchers_avp_spec)") +... +route { + ... + $avp(watchers_avp_spec) = "sip:first_watcher@opensip.org"; + $avp(watchers_avp_spec) = "sip:second_watcher@opensip.org"; + ... +} + + +
+
<varname>shared_line_spec_param</varname>(string) + + Mandatory parameter. + Opaque string identifing the shared line/call. + The shared_line_spec_param MUST be set before calling sca_init_request(); + + + The default value is "NULL". + + + Set <varname>shared_line_spec_param</varname> parameter + +... +modparam("b2b_sca", "shared_line_spec_param", "$var(shared_line)") +... + + +
+
<varname>appearance_name_addr_spec_param</varname>(string) + + Mandatory parameter. + It must be a valid SIP URI. + It will populate the appearance-uri SIP parameter + inside the Call-Info SIP header. + The appearance_name_addr_spec_param MUST be set before calling sca_init_request(); + + + The default value is "NULL". + + + Set <varname>appearance_name_addr_spec_param</varname> parameter + +... +modparam("b2b_sca", "appearance_name_addr_spec_param", "") +... + + +
+
<varname>db_url</varname>(string) + + This is URL of the database to be used. + + + The default value is "NULL". + + + Set <varname>db_url</varname> parameter + +... +modparam("b2b_sca", "db_url", "[dbdriver]://[[username]:[password]]@[dbhost]/[dbname]") +... + + +
+
<varname>db_mode</varname>(integer) + + The b2b_sca module can utilize database for persistent call appearance storage. + Using a database ensure that active call appearances will survive + machine restarts or SW crashes. + The following databse accessing modes are available for b2b_sca module: + + + + NO DB STORAGE - set this parameter to 0 + WRITE THROUGH (synchronous write in database) - set this parameter to 1 + + + + The default value is 0 (NO DB STORAGE). + + + Set <varname>db_mode</varname> parameter + +... +modparam("b2b_sca", "db_mode", 1) +... + + +
+
<varname>table_name</varname>(string) + + Identifies the table name from the defined database. + + + The default value is "sca". + + + Set <varname>table_name</varname> parameter + +... +modparam("b2b_sca", "table_name", "sla") +... + + +
+
<varname>shared_line_column</varname>(string) + + The column's name in the database storing the shared call/line id. + See "shared_line_spec_param" parameter. + + + The default value is "shared_line". + + + Set <varname>shared_line_column</varname> parameter + +... +modparam("b2b_sca", "shared_line_column", "") +... + + +
+
<varname>watchers_column</varname>(string) + + The column's name in the database storing the list of watchers. + See "watchers_avp_spec" parameter. + + + The default value is "watchers". + + + Set <varname>watchers_column</varname> parameter + +... +modparam("b2b_sca", "watchers_column", "") +... + + +
+
<varname>app[index]_shared_entity_column</varname>(string) + + The column's name in the database storing the shared entity of a + particular appearance. + See "sca_init_request" for more info. + + + The default value is "app[index]_shared_entity". + Index is an integer between 1 and 10. + + + Set <varname>app[index]_shared_entity_column</varname> parameter + +... +modparam("b2b_sca", "app1_shared_entity_column", "first_shared_entity") +modparam("b2b_sca", "app2_shared_entity_column", "second_shared_entity") +... + + +
+
<varname>app[index]_call_state_column</varname>(string) + + The column's name in the database storing the call state of a + particular appearance. The following states are stored: + + + + 1 - alerting, + 2 - active, + 3 - held, + 4 - held-private. + + + + The default value is "app[index]_call_state". + Index is an integer between 1 and 10. + + + Set <varname>app[index]_call_state_column</varname> parameter + +... +modparam("b2b_sca", "app1_call_state_column", "first_call_state") +modparam("b2b_sca", "app2_call_state_column", "second_call_state") +... + + +
+
<varname>app[index]_call_info_uri_column</varname>(string) + + The column's name in the database storing the call info URI of a + particular appearance. + + + The default value is "app[index]_call_info_uri". + Index is an integer between 1 and 10. + + + Set <varname>app[index]_call_info_uri_column</varname> parameter + +... +modparam("b2b_sca", "app1_call_info_uri_column", "first_call_info_uri") +modparam("b2b_sca", "app2_call_info_uri_column", "second_call_info_uri") +... + + +
+
<varname>app[index]_call_info_appearance_uri_column</varname>(string) + + The column's name in the database storing the call info appearance URI + of a particular appearance. + For each appearance, the value is extracted from the + "appearance_name_addr_spec_param" parameter. + + + The default value is "app[index]_call_info_appearance_uri". + Index is an integer between 1 and 10. + + + Set <varname>app[index]_call_info_appearance_uri_column</varname> parameter + +... +modparam("b2b_sca", "app1_call_info_appearance_uri_column", "first_call_info_appearance_uri") +modparam("b2b_sca", "app2_call_info_appearance_uri_column", "second_call_info_appearance_uri") +... + + +
+
<varname>app[index]_b2bl_key_column</varname>(string) + + The column's name in the database storing the b2b_logic key of a + particular appearance. + + + The default value is "app[index]_b2bl_key". + Index is an integer between 1 and 10. + + + Set <varname>app[index]_b2bl_key_column</varname> parameter + +... +modparam("b2b_sca", "app1_b2bl_key_column", "first_b2bl_key") +modparam("b2b_sca", "app2_b2bl_key_column", "second_b2bl_key") +... + + +
+
+ +
Exported Functions +
+ + <function moreinfo="none">sca_init_request(shared_line)</function> + + + This is the function that must be called by the script writer + on an initial INVITE for which an SCA call must be instantiated + (see the call from alice1 in the above diagram). + + Meaning of the parameters: + + shared_line - a PV (pseudo-variable) + identifying the call leg as being an "appearnace" call or a "shared" call: + + 0: "shared" call + 1: "appearance" call + + + + + <function>sca_init_request()</function> usage + +... +modparam("b2b_sca", + "shared_line_spec_param","$var(shared_line)") +modparam("b2b_sca", + "appearance_name_addr_spec_param","$var(appearance_name_addr)") +modparam("b2b_sca", + "watchers_avp_spec","$avp(watchers_avp_spec)") + +... + + # Setting the shared call identifier + $var(shared_line) = "alice"; + + # Setting the watchers + $avp(watchers_avp_spec) = "sip:alice1@example.com"; + $avp(watchers_avp_spec) = "sip:alice2@example.com"; + + if (INCOMING_SHARED_CALL) { + # The incoming call is a 'shared' call + $var(shared_line_entity) = 0; + # Setting the appearance name address + $var(appearance_name_addr) = $fu; + } + else { + # The incoming call is an 'appearance' call + # - see Alice's initial call leg in the given example + $var(shared_line_entity) = 1; + # Setting the appearance name address + $var(appearance_name_addr) = $tu; + } + + # Initiate the call + if (!sca_init_request("$var(shared_line_entity)")) { + send_reply("403", "Internal Server Error (SLA)"); + exit; + } +... + + +
+
<function moreinfo="none">sca_bridge_request(shared_line_to bridge)</function> + + This is the function that must be called by the script writer on an initial + "appearance" INVITE for an existing shared call. It will bridge the current + "appearance" call with the existing "shared" call and the old "appearance" + call will be disconnected (see the call from alice2 in the above diagram). + + Meaning of the parameters: + + shared_line_to_bridge - a PV identifying + the shared line/call that was previously set by sca_init_request(). + + + + +... + if ($rU==NULL && is_method("INVITE") && + $fU==$tU && is_present_hf("Call-Info")) { + # The incoming call is an 'appearance' call + # - see Alice's call from alice2 in the given example + $var(shared_line_to_bridge) = "alice"; + if (!sca_bridge_request("$var(shared_line_to_bridge)")) + send_reply("403", "Internal SLA Error"); + exit; + } + } +... + +
+
+ +
Exported MI Functions +
<function moreinfo="none">sca_list</function> + + It lists the appearances belonging to a shared line/call. + + Name: sca_list + Parameters: none + MI FIFO Command Format: + + :sca_list:_reply_fifo_file_ + _empty_line_ + +
+
+
+ diff --git a/modules/b2b_sca/sca_db_handler.c b/modules/b2b_sca/sca_db_handler.c new file mode 100644 index 00000000000..f89c0f22632 --- /dev/null +++ b/modules/b2b_sca/sca_db_handler.c @@ -0,0 +1,620 @@ +/* + * $Id$ + * + * sca_db_handler module + * + * Copyright (C) 2011 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-11-21 initial version (Ovidiu Sas) + */ + +#include +#include + +#include "../../dprint.h" +#include "../../db/db.h" +#include "../../str.h" +#include "sca_db_handler.h" +#include "sca_logic.h" + + +str shared_line_column = str_init(SHARED_LINE_COL); +str watchers_column = str_init(WATCHERS_COL); + +str app_shared_entity_column[MAX_APPEARANCE_INDEX] = { + str_init(SHARED_ENTITY_1_COL), + str_init(SHARED_ENTITY_2_COL), + str_init(SHARED_ENTITY_3_COL), + str_init(SHARED_ENTITY_4_COL), + str_init(SHARED_ENTITY_5_COL), + str_init(SHARED_ENTITY_6_COL), + str_init(SHARED_ENTITY_7_COL), + str_init(SHARED_ENTITY_8_COL), + str_init(SHARED_ENTITY_9_COL), + str_init(SHARED_ENTITY_10_COL), +}; +str app_call_state_column[MAX_APPEARANCE_INDEX] = { + str_init(CALL_STATE_1_COL), + str_init(CALL_STATE_2_COL), + str_init(CALL_STATE_3_COL), + str_init(CALL_STATE_4_COL), + str_init(CALL_STATE_5_COL), + str_init(CALL_STATE_6_COL), + str_init(CALL_STATE_7_COL), + str_init(CALL_STATE_8_COL), + str_init(CALL_STATE_9_COL), + str_init(CALL_STATE_10_COL), +}; +str app_call_info_uri_column[MAX_APPEARANCE_INDEX] = { + str_init(CALL_INFO_URI_1_COL), + str_init(CALL_INFO_URI_2_COL), + str_init(CALL_INFO_URI_3_COL), + str_init(CALL_INFO_URI_4_COL), + str_init(CALL_INFO_URI_5_COL), + str_init(CALL_INFO_URI_6_COL), + str_init(CALL_INFO_URI_7_COL), + str_init(CALL_INFO_URI_8_COL), + str_init(CALL_INFO_URI_9_COL), + str_init(CALL_INFO_URI_10_COL), +}; +str app_call_info_appearance_uri_column[MAX_APPEARANCE_INDEX] = { + str_init(CALL_INFO_APPEARANCE_URI_1_COL), + str_init(CALL_INFO_APPEARANCE_URI_2_COL), + str_init(CALL_INFO_APPEARANCE_URI_3_COL), + str_init(CALL_INFO_APPEARANCE_URI_4_COL), + str_init(CALL_INFO_APPEARANCE_URI_5_COL), + str_init(CALL_INFO_APPEARANCE_URI_6_COL), + str_init(CALL_INFO_APPEARANCE_URI_7_COL), + str_init(CALL_INFO_APPEARANCE_URI_8_COL), + str_init(CALL_INFO_APPEARANCE_URI_9_COL), + str_init(CALL_INFO_APPEARANCE_URI_10_COL), +}; +str app_b2bl_key_column[MAX_APPEARANCE_INDEX] = { + str_init(B2BL_KEY_1_COL), + str_init(B2BL_KEY_2_COL), + str_init(B2BL_KEY_3_COL), + str_init(B2BL_KEY_4_COL), + str_init(B2BL_KEY_5_COL), + str_init(B2BL_KEY_6_COL), + str_init(B2BL_KEY_7_COL), + str_init(B2BL_KEY_8_COL), + str_init(B2BL_KEY_9_COL), + str_init(B2BL_KEY_10_COL), +}; + +str sca_table_name = str_init(SCA_TABLE_NAME); +int sca_db_mode = DB_MODE_NONE; + +static db_con_t *sca_db_handle = NULL; +static db_func_t sca_dbf; + +extern b2bl_api_t b2bl_api; + +int connect_sca_db(const str *db_url) +{ + if (sca_db_handle) { + LM_CRIT("BUG - db connection found already open\n"); + return -1; + } + if ((sca_db_handle = sca_dbf.init(db_url)) == NULL) + return -1; + return 0; +} + + +static int use_sca_table(void) +{ + if(!sca_db_handle){ + LM_ERR("invalid database handle\n"); + return -1; + } + sca_dbf.use_table(sca_db_handle, &sca_table_name); + return 0; +} + + +int delete_sca_info_from_db(b2b_sca_record_t *record) +{ + db_key_t q_cols[1] = {&shared_line_column}; + db_val_t q_vals[1]; + + if(use_sca_table()) return -1; + + memset(q_vals, 0, sizeof(db_val_t)); + + q_vals[0].type = DB_STR; + q_vals[0].val.str_val = record->shared_line; + + /* Delete based on "q_cols" keys with matching "q_vals" values. */ + if(sca_dbf.delete(sca_db_handle, q_cols, 0, q_vals, 1) < 0) { + LM_ERR("failed to delete record\n"); + return -1; + } + return 0; +} + + +int update_sca_info_to_db(b2b_sca_record_t *record, unsigned int appearance_index) +{ + b2b_sca_call_t *call; + unsigned int i; + unsigned int n_q_cols = 0, n_q_vals = 0; + unsigned int shared_line_col, watchers_col; + unsigned int app_shared_entity_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_state_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_info_uri_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_info_appearance_uri_col[MAX_APPEARANCE_INDEX]; + unsigned int app_b2bl_key_col[MAX_APPEARANCE_INDEX]; + db_key_t q_cols[SCA_TABLE_TOTAL_COL_NO]; + db_val_t q_vals[SCA_TABLE_TOTAL_COL_NO]; + + + LM_DBG("\n"); + if(use_sca_table()) return -1; + + memset(q_vals, 0, SCA_TABLE_TOTAL_COL_NO * sizeof(db_val_t)); + + q_cols[shared_line_col = n_q_cols++] = &shared_line_column; + q_vals[shared_line_col].type = DB_STR; + q_cols[watchers_col = n_q_cols++] = &watchers_column; + q_vals[watchers_col].type = DB_STR; + + for (i=0; ishared_line; + + i = appearance_index - 1; + if (i >= MAX_APPEARANCE_INDEX) { + LM_ERR("Non matching call\n"); + return -1; + } + + call = record->call[i]; + if (call) { + LM_DBG("update shared_entity [%d] and call_state [%d] for call[%d][%.*s]\n", + call->shared_entity, call->call_state, i, + call->b2bl_key.len, call->b2bl_key.s); + switch(call->call_state) { + case ALERTING_STATE: + q_vals[app_call_info_uri_col[i]].val.str_val = call->call_info_uri; + q_vals[app_call_info_appearance_uri_col[i]].val.str_val = + call->call_info_apperance_uri; + q_vals[app_b2bl_key_col[i]].val.str_val = call->b2bl_key; + LM_DBG("update [%.*s][%.*s][%.*s]\n", + call->call_info_uri.len, call->call_info_uri.s, + call->call_info_apperance_uri.len, call->call_info_apperance_uri.s, + call->b2bl_key.len, call->b2bl_key.s); + n_q_vals += 3; + default: + q_vals[app_shared_entity_col[i]].val.int_val = call->shared_entity; + q_vals[app_call_state_col[i]].val.int_val = call->call_state; + n_q_vals += 2; + } + } else { + n_q_vals = 5; + } + if(sca_dbf.update(sca_db_handle, q_cols, 0, q_vals, + q_cols + app_shared_entity_col[i], + q_vals + app_shared_entity_col[i], 1, n_q_vals) != 0) { + LM_ERR("failed to update record\n"); + return -1; + } + + return 0; +} + + +int insert_sca_info_into_db(b2b_sca_record_t *record) +{ + b2b_sca_call_t *call = NULL; + unsigned int n_q_cols = 0; + unsigned int i; + unsigned int appearance_index = MAX_APPEARANCE_INDEX; + unsigned int shared_line_col, watchers_col; + unsigned int app_shared_entity_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_state_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_info_uri_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_info_appearance_uri_col[MAX_APPEARANCE_INDEX]; + unsigned int app_b2bl_key_col[MAX_APPEARANCE_INDEX]; + db_key_t q_cols[SCA_TABLE_TOTAL_COL_NO]; + db_val_t q_vals[SCA_TABLE_TOTAL_COL_NO]; + + LM_DBG("\n"); + if(use_sca_table()) return -1; + + memset(q_vals, 0, SCA_TABLE_TOTAL_COL_NO * sizeof(db_val_t)); + + q_cols[shared_line_col = n_q_cols++] = &shared_line_column; + q_vals[shared_line_col].type = DB_STR; + q_cols[watchers_col = n_q_cols++] = &watchers_column; + q_vals[watchers_col].type = DB_STR; + + for (i=0; ishared_line; + /* FIXME: get all the watchers */ + if (record->watchers) { + q_vals[watchers_col].val.str_val = record->watchers->watcher; + } + + for (i=0; icall[i]) { + if (call) { + LM_ERR("This should be an UPDATE not an INSERT\n"); + return -1; + } + call = record->call[i]; + appearance_index = i; + } + } + + if (call) { + q_vals[app_shared_entity_col[appearance_index]].val.int_val = call->shared_entity; + q_vals[app_call_state_col[appearance_index]].val.int_val = call->call_state; + q_vals[app_call_info_uri_col[appearance_index]].val.str_val = call->call_info_uri; + q_vals[app_call_info_appearance_uri_col[appearance_index]].val.str_val = + call->call_info_apperance_uri; + q_vals[app_b2bl_key_col[appearance_index]].val.str_val = call->b2bl_key; + + if((sca_dbf.insert(sca_db_handle, q_cols, q_vals, SCA_TABLE_TOTAL_COL_NO)) != 0) { + LM_ERR("could not add record\n"); + return -1; + } + } else { + LM_ERR("Empty record?\n"); + return -1; + } + + return 0; +} + + +int push_sca_info_to_db(b2b_sca_record_t *record, unsigned int appearance_index, + unsigned int forced_update) +{ + unsigned int i; + unsigned int no_calls = 0; + b2b_sca_call_t *_call = NULL; + + LM_DBG("\n"); + for (i=0; icall[i]) { + no_calls++; + _call = record->call[i]; + } + } + switch (no_calls) { + case 0: + return delete_sca_info_from_db(record); + break; + case 1: + if (_call->call_state==ALERTING_STATE) { + if (forced_update) + return update_sca_info_to_db(record, appearance_index); + else + return insert_sca_info_into_db(record); + } else { + return update_sca_info_to_db(record, appearance_index); + } + break; + default: + return update_sca_info_to_db(record, appearance_index); + } + LM_ERR("logic error\n"); + return -1; + +} + + +static int load_sca_info_from_db(void) +{ + db_res_t * res = NULL; + db_val_t * values; + db_row_t * rows; + int i, j, nr_rows; + unsigned int valid_record; + unsigned int n_result_cols = 0; + unsigned int shared_line_col, watchers_col; + unsigned int app_shared_entity_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_state_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_info_uri_col[MAX_APPEARANCE_INDEX]; + unsigned int app_call_info_appearance_uri_col[MAX_APPEARANCE_INDEX]; + unsigned int app_b2bl_key_col[MAX_APPEARANCE_INDEX]; + db_key_t q_cols[SCA_TABLE_TOTAL_COL_NO]; + + str shared_line, watchers_csv; + //str_lst_t *watchers; + //unsigned int size, watcher_size, watchers_no; + //unsigned int size; + unsigned int hash_index; + //char *p; + b2b_sca_record_t *record; + b2b_sca_call_t *call; + unsigned int shared_entity, appearance_index, call_state; + str call_info_uri, call_info_apperance_uri, b2bl_key; + b2bl_cb_ctx_t *cb_params; + + if(use_sca_table()) return -1; + + q_cols[shared_line_col = n_result_cols++] = &shared_line_column; + q_cols[watchers_col = n_result_cols++] = &watchers_column; + + for (i=0; i skipping\n", + shared_line_column.len, shared_line_column.s, + watchers_column.len, watchers_column.s); + continue; + } + shared_line.s = (char*)values[shared_line_col].val.string_val; + shared_line.len = strlen(shared_line.s); + + watchers_csv.s = (char*)values[watchers_col].val.string_val; + watchers_csv.len = strlen(watchers_csv.s); + + record = restore_record(&shared_line, &watchers_csv); + if (record == NULL) + goto error; + hash_index = core_hash(&shared_line, NULL, b2b_sca_hsize); + + j = 0; + while (j < MAX_APPEARANCE_INDEX) { + if( VAL_NULL(values + app_shared_entity_col[j]) || + VAL_NULL(values + app_call_state_col[j]) || + VAL_NULL(values + app_call_info_uri_col[j]) || + VAL_NULL(values + app_call_info_appearance_uri_col[j]) || + VAL_NULL(values + app_b2bl_key_col[j]) ) { + goto cont; + } + appearance_index = j + 1; + /* 1 - get shared_entity */ + shared_entity = values[app_shared_entity_col[j]].val.int_val; + if (shared_entity!=0 && shared_entity!=1) { + LM_ERR("Unexpected shared_entity [%d] " + "for shared_line [%.*s]\n", + shared_entity, shared_line.len, shared_line.s); + goto cont; + } + /* 2 - get call_state */ + call_state = values[app_call_state_col[j]].val.int_val; + if (call_state == IDLE_STATE) { + LM_DBG("empty call[%d]\n", appearance_index); + goto cont; + } + if (call_state > MAX_INDEX_STATE) { + LM_ERR("Unexpected call_state [%d] for shared_line [%.*s]\n", + call_state, shared_line.len, shared_line.s); + goto cont; + } + /* 3 - get call_info_uri */ + call_info_uri.s = + (char*)values[app_call_info_uri_col[j]].val.string_val; + if (call_info_uri.s) + call_info_uri.len = strlen(call_info_uri.s); + else { + LM_ERR("Missing call_info_uri for shared_line [%.*s][%d]\n", + shared_line.len, shared_line.s, appearance_index); + goto cont; + } + LM_DBG("call_info_uri=[%.*s]\n", + call_info_uri.len, call_info_uri.s); + /* 4 - get call_info_apperance_uri */ + call_info_apperance_uri.s = + (char*) + values[app_call_info_appearance_uri_col[j]].val.string_val; + if (call_info_apperance_uri.s) + call_info_apperance_uri.len = + strlen(call_info_apperance_uri.s); + else { + LM_ERR("Missing call_info_apperance_uri for " + "shared_line [%.*s][%d]\n", + shared_line.len, shared_line.s, appearance_index); + goto cont; + } + LM_DBG("call_info_apperance_uri=[%.*s]\n", + call_info_apperance_uri.len, call_info_apperance_uri.s); + /* 5 - get b2bl_key */ + b2bl_key.s = (char*)values[app_b2bl_key_col[j]].val.string_val; + if (b2bl_key.s) { + b2bl_key.len = strlen(b2bl_key.s); + if (b2bl_key.len > B2BL_MAX_KEY_LEN) { + LM_ERR("buffer overflow on b2bl_key [%.*s]" + " for shared_line [%.*s][%d]\n", + b2bl_key.len, b2bl_key.s, + shared_line.len, shared_line.s, + appearance_index); + goto cont; + } + LM_DBG("b2bl_key=[%.*s]\n", b2bl_key.len, b2bl_key.s); + } else { + LM_ERR("Missing b2bl_key for shared_line [%.*s][1]\n", + shared_line.len, shared_line.s); + goto cont; + } + /* restore the call */ + call = restore_call(record, appearance_index, + shared_entity, call_state, + &call_info_uri, &call_info_apperance_uri); + if (call == NULL) { + goto error; + } + /* update record */ + if (0!=b2b_sca_update_call_record_key(call, &b2bl_key)) { + LM_ERR("Unable to update b2bl_key [%.*s]\n", + b2bl_key.len, b2bl_key.s); + shm_free(call); + call = NULL; + record->call[appearance_index-1] = NULL; + goto cont; + } + /* Prepare b2b_logic callback params. */ + cb_params = build_cb_params(hash_index, + &shared_line, appearance_index); + if (cb_params == NULL) { + LM_ERR("Unable to build cb_params\n"); + goto error; + } + /* re-register callbacks */ + if(b2bl_api.register_cb(&b2bl_key, &sca_logic_notify, cb_params, + B2B_RE_INVITE_CB|B2B_CONFIRMED_CB|B2B_DESTROY_CB) != 0){ + LM_ERR("Unable register b2b cb\n"); + shm_free(call); + call = NULL; + record->call[appearance_index-1] = NULL; + goto cont; + } +cont: + j++; + } + + valid_record = j = 0; + while (j < MAX_APPEARANCE_INDEX) { + if (record->call[j]) { + valid_record = 1; + goto check_valid_record; + } + j++; + } +check_valid_record: + if (valid_record) { + b2b_sca_print_record(record); + insert_record(hash_index, record); + } else { + LM_DBG("removing the record from db!\n"); + delete_sca_info_from_db(record); + } + LM_DBG("Done\n"); + } + + /* any more data to be fetched ?*/ + if (DB_CAPABILITY(sca_dbf, DB_CAP_FETCH)) { + if (sca_dbf.fetch_result(sca_db_handle, &res, SCA_FETCH_SIZE)<0) { + LM_ERR("fetching more rows failed\n"); + goto error; + } + nr_rows = RES_ROW_N(res); + } else { + nr_rows = 0; + } + }while (nr_rows>0); + + sca_dbf.free_result(sca_db_handle, res); + return 0; +error: + sca_dbf.free_result(sca_db_handle, res); + return -1; +} + + +int init_sca_db(const str *db_url, int dlg_hash_size) +{ + /* Find a database module */ + if (db_bind_mod(db_url, &sca_dbf) < 0) { + LM_ERR("Unable to bind to a database driver\n"); + return -1; + } + if (connect_sca_db(db_url)!=0){ + LM_ERR("unable to connect to the database\n"); + return -1; + } + if(db_check_table_version(&sca_dbf, sca_db_handle, &sca_table_name, SCA_TABLE_VERSION) < 0) { + LM_ERR("error during table version check.\n"); + return -1; + } + if(load_sca_info_from_db() !=0){ + LM_ERR("unable to load the sca data\n"); + return -1; + } + + sca_dbf.close(sca_db_handle); + sca_db_handle = NULL; + + return 0; +} + +void destroy_sca_db(void) +{ + /* close the DB connection */ + if (sca_db_handle) { + sca_dbf.close(sca_db_handle); + sca_db_handle = NULL; + } +} + diff --git a/modules/b2b_sca/sca_db_handler.h b/modules/b2b_sca/sca_db_handler.h new file mode 100644 index 00000000000..a51a6c2b86b --- /dev/null +++ b/modules/b2b_sca/sca_db_handler.h @@ -0,0 +1,118 @@ +/* + * $Id$ + * + * sca_db_handler module + * + * Copyright (C) 2011 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-11-21 initial version (Ovidiu Sas) + */ + +#ifndef SCA_DB_HANDLER +#define SCA_DB_HANDLER + +#include +#include + +#include "sca_records.h" + +#define SHARED_LINE_COL "shared_line" +#define WATCHERS_COL "watchers" +#define SHARED_ENTITY_1_COL "app1_shared_entity" +#define CALL_STATE_1_COL "app1_call_state" +#define CALL_INFO_URI_1_COL "app1_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_1_COL "app1_call_info_appearance_uri" +#define B2BL_KEY_1_COL "app1_b2bl_key" +#define SHARED_ENTITY_2_COL "app2_shared_entity" +#define CALL_STATE_2_COL "app2_call_state" +#define CALL_INFO_URI_2_COL "app2_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_2_COL "app2_call_info_appearance_uri" +#define B2BL_KEY_2_COL "app2_b2bl_key" +#define SHARED_ENTITY_3_COL "app3_shared_entity" +#define CALL_STATE_3_COL "app3_call_state" +#define CALL_INFO_URI_3_COL "app3_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_3_COL "app3_call_info_appearance_uri" +#define B2BL_KEY_3_COL "app3_b2bl_key" +#define SHARED_ENTITY_4_COL "app4_shared_entity" +#define CALL_STATE_4_COL "app4_call_state" +#define CALL_INFO_URI_4_COL "app4_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_4_COL "app4_call_info_appearance_uri" +#define B2BL_KEY_4_COL "app4_b2bl_key" +#define SHARED_ENTITY_5_COL "app5_shared_entity" +#define CALL_STATE_5_COL "app5_call_state" +#define CALL_INFO_URI_5_COL "app5_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_5_COL "app5_call_info_appearance_uri" +#define B2BL_KEY_5_COL "app5_b2bl_key" +#define SHARED_ENTITY_6_COL "app6_shared_entity" +#define CALL_STATE_6_COL "app6_call_state" +#define CALL_INFO_URI_6_COL "app6_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_6_COL "app6_call_info_appearance_uri" +#define B2BL_KEY_6_COL "app6_b2bl_key" +#define SHARED_ENTITY_7_COL "app7_shared_entity" +#define CALL_STATE_7_COL "app7_call_state" +#define CALL_INFO_URI_7_COL "app7_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_7_COL "app7_call_info_appearance_uri" +#define B2BL_KEY_7_COL "app7_b2bl_key" +#define SHARED_ENTITY_8_COL "app8_shared_entity" +#define CALL_STATE_8_COL "app8_call_state" +#define CALL_INFO_URI_8_COL "app8_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_8_COL "app8_call_info_appearance_uri" +#define B2BL_KEY_8_COL "app8_b2bl_key" +#define SHARED_ENTITY_9_COL "app9_shared_entity" +#define CALL_STATE_9_COL "app9_call_state" +#define CALL_INFO_URI_9_COL "app9_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_9_COL "app9_call_info_appearance_uri" +#define B2BL_KEY_9_COL "app9_b2bl_key" +#define SHARED_ENTITY_10_COL "app10_shared_entity" +#define CALL_STATE_10_COL "app10_call_state" +#define CALL_INFO_URI_10_COL "app10_call_info_uri" +#define CALL_INFO_APPEARANCE_URI_10_COL "app10_call_info_appearance_uri" +#define B2BL_KEY_10_COL "app10_b2bl_key" + +#define SCA_TABLE_NAME "sca" + +#define SCA_TABLE_VERSION 1 +#define DB_MODE_NONE 0 +#define DB_MODE_REALTIME 1 + +#define SCA_TABLE_TOTAL_COL_NO (2+(MAX_APPEARANCE_INDEX*5)) + +#define SCA_FETCH_SIZE 128 + +extern str shared_line_column; +extern str watchers_column; +extern str app_shared_entity_column[MAX_APPEARANCE_INDEX]; +extern str app_call_state_column[MAX_APPEARANCE_INDEX]; +extern str app_call_info_uri_column[MAX_APPEARANCE_INDEX]; +extern str app_call_info_appearance_uri_column[MAX_APPEARANCE_INDEX]; +extern str app_b2bl_key_column[MAX_APPEARANCE_INDEX]; + +extern str sca_table_name; +extern int sca_db_mode; + +int init_sca_db(const str *db_url, int dlg_hash_size); +int connect_sca_db(const str *db_url); +void destroy_sca_db(void); + +int push_sca_info_to_db(b2b_sca_record_t *record, unsigned int appearance_index, + unsigned int forced_update); + +#endif diff --git a/modules/b2b_sca/sca_logic.c b/modules/b2b_sca/sca_logic.c new file mode 100644 index 00000000000..6589a0bb79c --- /dev/null +++ b/modules/b2b_sca/sca_logic.c @@ -0,0 +1,943 @@ +/* + * $Id$ + * + * sca logic module + * + * Copyright (C) 2010 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-11-21 initial version (Ovidiu Sas) + */ + +#include +#include + +#include "../../ut.h" +#include "../../trim.h" +#include "../../strcommon.c" +#include "../../parser/parse_from.h" +#include "../../parser/sdp/sdp.h" +#include "../../usr_avp.h" +#include "../../parser/parse_call_info.h" +#include "../pua/pua.h" +#include "../pua/pua_bind.h" +#include "../b2b_logic/b2b_load.h" +#include "sca_records.h" +#include "sca_db_handler.h" +#include "sca_logic.h" + +#define APPEARANCE_INDEX_STR "appearance-index" +#define APPEARANCE_INDEX_LEN strlen(APPEARANCE_INDEX_STR) + +#define APPEARANCE_STATE_STR "appearance-state" +#define APPEARANCE_STATE_LEN strlen(APPEARANCE_STATE_STR) + +#define AUDIO_STR "audio" +#define AUDIO_STR_LEN 5 + +extern pua_api_t pua_api; +extern b2bl_api_t b2bl_api; +extern str presence_server; +//extern int watchers_avp_name; +extern unsigned short watchers_avp_type; + +int get_hash_index_and_shared_line(struct sip_msg* msg, unsigned int *hash_index, str **shared_line); +struct to_body* get_appearance_name_addr(struct sip_msg* msg); + +#define CALL_INFO_APPEARANCE_URI_LEN 64 +static char call_info_apperance_uri_buf[CALL_INFO_APPEARANCE_URI_LEN]; + +#define CALL_INFO_URI "sip:" +#define CALL_INFO_URI_LEN 64 +static char call_info_uri_buf[CALL_INFO_URI_LEN] = CALL_INFO_URI; + +#define CALL_INFO_HDR "Call-Info: <" +#define INVITE_CALL_INFO_HDR_LEN 128 +#define PUBLISH_CALL_INFO_HDR_LEN 512 +static char invite_call_info_hdr_buf[INVITE_CALL_INFO_HDR_LEN] = CALL_INFO_HDR; +static char publish_call_info_hdr_buf[PUBLISH_CALL_INFO_HDR_LEN] = CALL_INFO_HDR; + +static const str callinfo_id=str_init("CALLINFO_PUBLISH"); +static const str callinfo_appuri_prefix=str_init(">;appearance-uri=\""); +static const str callinfo_appindex=str_init(";appearance-index="); +static const str callinfo_appstate=str_init(";appearance-state="); +static const str callinfo_hdr_postfix=str_init("*;appearance-state=idle\r\n"); +static const str callinfo_default_uri=str_init("sip:127.0.0.1>"); + +static unsigned int b2b_sca_shutdown_completed = 0; + +#define APP_STATE_IDLE "" +#define APP_STATE_ALERTING "alerting" +#define APP_STATE_ACTIVE "active" +#define APP_STATE_HELD "held" +#define APP_STATE_HELD_PRIVATE "held-private" + +const str app_state[]={ + str_init(APP_STATE_IDLE), + str_init(APP_STATE_ALERTING), + str_init(APP_STATE_ACTIVE), + str_init(APP_STATE_HELD), + str_init(APP_STATE_HELD_PRIVATE), +}; + +static str scenario = str_init("top hiding"); + + +void destroy_b2b_sca_handlers(void) +{ + b2b_sca_shutdown_completed = 1; +} + + +unsigned int get_app_index(struct sip_msg* msg) +{ + unsigned int appearance; + struct hdr_field *call_info; + struct call_info_body *callinfo_b; + struct to_body *call_info_b; + struct to_param *param; + + if (0 == parse_call_info_header(msg)) { + call_info = msg->call_info; + while (call_info) { + //LM_DBG("BODY=[%p]->[%.*s] sibling=[%p]\n", call_info, + // call_info->body.len, call_info->body.s, + // call_info->sibling); + callinfo_b = call_info->parsed; + while (callinfo_b) { + call_info_b = &(callinfo_b->call_info_body); + //LM_DBG(". body=[%.*s] param_lst=[%p] " + // "last_param=[%p]\n", + // call_info_b->body.len, call_info_b->body.s, + // call_info_b->param_lst, + // call_info_b->last_param); + param = call_info_b->param_lst; + while (param) { + //LM_DBG(".. [%p]->[%d] " + // "[%.*s]=[%.*s]->[%p]\n", + // param, param->type, + // param->name.len, param->name.s, + // param->value.len, param->value.s, + // param->next); + if (param->name.len==APPEARANCE_INDEX_LEN && + strncmp(APPEARANCE_INDEX_STR, + param->name.s, + APPEARANCE_INDEX_LEN)==0) { + if (strno2int(¶m->value, + &appearance)<0) { + LM_ERR("bad appearance-index" + " [%.*s]\n", + param->value.len, + param->value.s); + return 0; + } + LM_DBG("*** GOT APP-INDEX [%d]\n", + appearance); + return appearance; + } + param=param->next; + } + callinfo_b = callinfo_b->next; + } + call_info = call_info->sibling; + } + } else { + LM_ERR("Unable to parse Call-Info header\n"); + return 0; + } + + LM_ERR("appearance index not found\n"); + return 0; +} + + +int build_publish_call_info_header(b2b_sca_record_t *rec, str *publish_hdr) +{ + unsigned int i; + unsigned int size = sizeof(CALL_INFO_HDR); + b2b_sca_call_t *call = NULL; + char *p; + + rec->expires = 30; + size += callinfo_default_uri.len + + callinfo_appindex.len + callinfo_hdr_postfix.len; + + if (rec == NULL) { + /* we need to build an idle Call-Info header */ + publish_hdr->s = publish_call_info_hdr_buf; + p = &publish_call_info_hdr_buf[sizeof(CALL_INFO_HDR) - 1]; + goto default_hdr; + } + + for (i=0; icall[i]) { + call = rec->call[i]; + if (call->call_state > ALERTING_STATE) + rec->expires = 36000; + size += call->call_info_uri.len + + callinfo_appuri_prefix.len + + call->call_info_apperance_uri.len + + callinfo_appindex.len + + call->appearance_index_str.len + + callinfo_appstate.len + + app_state[call->call_state].len + 2; + } + } + + if (size > PUBLISH_CALL_INFO_HDR_LEN) { + LM_WARN("buffer overflow for PUBLISH Call-Info" + " header: size [%d]\n", size); + p = (char *)pkg_malloc(size); + if (p == NULL) { + LM_ERR("OOM\n"); + return -1; + } + publish_hdr->s = p; + memcpy(p, publish_call_info_hdr_buf, sizeof(CALL_INFO_HDR) - 1); + p += sizeof(CALL_INFO_HDR) - 1; + } else { + publish_hdr->s = publish_call_info_hdr_buf; + p = &publish_call_info_hdr_buf[sizeof(CALL_INFO_HDR) - 1]; + } + + for (i=0; icall[i]) { + call = rec->call[i]; + + memcpy(p, call->call_info_uri.s, call->call_info_uri.len); + p += call->call_info_uri.len; + + memcpy(p, callinfo_appuri_prefix.s, + callinfo_appuri_prefix.len); + p += callinfo_appuri_prefix.len; + + memcpy(p, call->call_info_apperance_uri.s, + call->call_info_apperance_uri.len); + p += call->call_info_apperance_uri.len; + *p = '\"'; p++; + + memcpy(p, callinfo_appindex.s, callinfo_appindex.len); + p += callinfo_appindex.len; + + memcpy(p, call->appearance_index_str.s, + call->appearance_index_str.len); + p += call->appearance_index_str.len; + + memcpy(p, callinfo_appstate.s, callinfo_appstate.len); + p += callinfo_appstate.len; + + memcpy(p, app_state[call->call_state].s, app_state[call->call_state].len); + p += app_state[call->call_state].len; + + *p = ','; p++; + *p = '<'; p++; + } + } + +default_hdr: + memcpy(p, callinfo_default_uri.s, callinfo_default_uri.len); + p += callinfo_default_uri.len; + + memcpy(p, callinfo_appindex.s, callinfo_appindex.len); + p += callinfo_appindex.len; + + memcpy(p, callinfo_hdr_postfix.s, callinfo_hdr_postfix.len); + p += callinfo_hdr_postfix.len; + + publish_hdr->len = p - publish_hdr->s; + + LM_DBG("publish_hdr [%d:%d] [%.*s]\n", size, publish_hdr->len, + publish_hdr->len, publish_hdr->s); + return 0; +} + +int build_invite_call_info_header(b2b_sca_call_t *call, + str* call_info_uri, str *custom_hdr) +{ + unsigned int size; + char *p; + + size = sizeof(CALL_INFO_HDR) + call_info_uri->len + 1 + + callinfo_appindex.len + call->appearance_index_str.len + CRLF_LEN; + if (size >= INVITE_CALL_INFO_HDR_LEN) { + LM_WARN("buffer overflow on INVITE Call-Info header: size [%d]\n", size); + p = (char *)pkg_malloc(size); + if (p == NULL) { + LM_ERR("OOM\n"); + return -1; + } + custom_hdr->s = p; + memcpy(p, invite_call_info_hdr_buf, sizeof(CALL_INFO_HDR) - 1); + p += sizeof(CALL_INFO_HDR) - 1; + } else { + custom_hdr->s = invite_call_info_hdr_buf; + p = &invite_call_info_hdr_buf[sizeof(CALL_INFO_HDR) - 1]; + } + + memcpy(p, call_info_uri->s, call_info_uri->len); + p += call_info_uri->len; + *p = '>'; p++; + + memcpy(p, callinfo_appindex.s, callinfo_appindex.len); + p += callinfo_appindex.len; + + memcpy(p, call->appearance_index_str.s, call->appearance_index_str.len); + p += call->appearance_index_str.len; + + memcpy(p, CRLF, CRLF_LEN); + p += CRLF_LEN; + + custom_hdr->len = p - custom_hdr->s; + LM_DBG("custom_hdr [%d:%d] [%.*s]\n", size, custom_hdr->len, + custom_hdr->len, custom_hdr->s); + return 0; +} + +int build_appearanceURI(str *display, str *uri, str *call_info_apperance_uri) +{ + unsigned int size; + int escaped_display_size; + char *p; + char escaped_display[256]; + + size = display->len + 5 + uri->len + 2; + if (size > CALL_INFO_APPEARANCE_URI_LEN) { + LM_WARN("buffer overflow on appearance URI param: size [%d]\n", size); + p = (char *)pkg_malloc(size); + if (p == NULL) { + LM_ERR("OOM\n"); + return -1; + } + call_info_apperance_uri->s = p; + } else { + p = call_info_apperance_uri->s = call_info_apperance_uri_buf; + } + if (display->len<80) { + escaped_display_size = escape_common(escaped_display, display->s, display->len); + if (escaped_display_size) { + memcpy(p, escaped_display, escaped_display_size); + p += escaped_display_size; + *p = ' '; p++; + } + } + *p = '<'; p++; + memcpy(p, uri->s, uri->len); + p += uri->len; + *p = '>'; p++; + call_info_apperance_uri->len = p - call_info_apperance_uri->s; + /* + LM_DBG("call_info_apperance_uri [%d:%d][%.*s]\n", + size, call_info_apperance_uri->len, + call_info_apperance_uri->len, call_info_apperance_uri->s); + */ + return 0; +} + +int build_absoluteURI(str *host, str *port, str *call_info_uri) +{ + unsigned int size; + char *p; + + size = sizeof(CALL_INFO_URI) - 1 + host->len + port->len; + if (size > CALL_INFO_URI_LEN) { + LM_WARN("buffer overflow on absoluteURI: size [%d]\n", size); + p = (char *)pkg_malloc(size); + if (p == NULL) { + LM_ERR("OOM\n"); + return -1; + } + call_info_uri->s = p; + memcpy(p, call_info_uri_buf, sizeof(CALL_INFO_URI) - 1); + p += sizeof(CALL_INFO_URI) - 1; + } else { + call_info_uri->s = call_info_uri_buf; + p = &call_info_uri_buf[sizeof(CALL_INFO_URI) - 1]; + } + memcpy(p, host->s, host->len); + p += host->len; + if (port->s && port->len) { + *p = ':'; p++; + memcpy(p, port->s, port->len); + p += port->len; + } + call_info_uri->len = p - call_info_uri->s; + /* + LM_DBG("call_info_uri [%d:%d][%.*s]\n", + size, call_info_uri->len, + call_info_uri->len, call_info_uri->s); + */ + return 0; +} + + +b2bl_cb_ctx_t* build_cb_params(unsigned int hash_index, + str *shared_line, unsigned int appearance_index) +{ + unsigned int size; + char *p; + b2bl_cb_ctx_t *cb_params; + + /* Prepare b2b_logic callback params. */ + size = sizeof(b2bl_cb_ctx_t) + shared_line->len; + cb_params = (b2bl_cb_ctx_t *)shm_malloc(size); + if (cb_params == NULL) { + LM_ERR("OOM\n"); + return NULL; + } + memset(cb_params, 0, size); + cb_params->hash_index = hash_index; + cb_params->appearance = appearance_index; + + p = (char *)(cb_params + 1); + cb_params->shared_line.len = shared_line->len; + cb_params->shared_line.s = p; + memcpy(p, shared_line->s, shared_line->len); + p += shared_line->len; + + return cb_params; +} + + +void sca_publish(b2b_sca_record_t *record, str *extra_hdr) +{ + str_lst_t *new_watcher; + publ_info_t publ; + + /* TESTING */ + //return; + + memset(&publ, 0, sizeof(publ_info_t)); + + publ.id = callinfo_id; + publ.body = NULL; + + publ.expires = record->expires; + + publ.flag|= UPDATE_TYPE; + publ.source_flag|= CALLINFO_PUBLISH; + publ.event|= CALLINFO_EVENT; + + publ.content_type.s = NULL; + publ.content_type.len = 0; + + publ.etag = NULL; + + publ.extra_headers= extra_hdr; + + publ.outbound_proxy = presence_server; + publ.cb_param = NULL; + + new_watcher = record->watchers; + while (new_watcher) { + publ.pres_uri = &new_watcher->watcher; + if(pua_api.send_publish(&publ)< 0) { + LM_ERR("sending publish failed\n"); + } + new_watcher = new_watcher->next; + } + + return; +} + + +int sca_logic_notify(b2bl_cb_params_t *params, unsigned int b2b_event) +{ + int on_hold = 0; + int sdp_session_num = 0, sdp_stream_num; + sdp_session_cell_t* sdp_session; + sdp_stream_cell_t* sdp_stream; + struct sip_msg *msg = params->msg; + b2bl_cb_ctx_t *cb_params = params->param; + str *shared_line; + unsigned int hash_index, appearance; + b2b_sca_record_t *record; + b2b_sca_call_t *call = NULL; + str publish_hdr; + unsigned int call_info_appearance; + unsigned int call_info_appearance_state = 0; + struct hdr_field *call_info; + struct call_info_body *callinfo_b; + struct to_body *call_info_b; + struct to_param *param; + + if (b2b_sca_shutdown_completed) return B2B_FOLLOW_SCENARIO_CB_RET; + if (params == NULL) { + LM_ERR("callback event [%d] without cb params\n", b2b_event); + return B2B_DROP_MSG_CB_RET; + } + + shared_line = &cb_params->shared_line; + hash_index = cb_params->hash_index; + appearance = cb_params->appearance; + + LM_DBG("*** GOT NOTIFICATION TYPE [%d] WITH cb_params [%p]->[%.*s] appearance [%d] on hash index [%d]" + " for b2bl entity [%d]\n", + b2b_event, cb_params, shared_line->len, shared_line->s, + appearance, hash_index, params->entity); + + + if (msg && msg->call_info) { + if (0 == parse_call_info_header(msg)) { + call_info = msg->call_info; + if (call_info) { + LM_DBG("BODY=[%p]->[%.*s] sibling=[%p]\n", call_info, + call_info->body.len, call_info->body.s, call_info->sibling); + callinfo_b = call_info->parsed; + while (callinfo_b) { + call_info_b = &(callinfo_b->call_info_body); + LM_DBG(". body=[%.*s] param_lst=[%p] last_param=[%p]\n", + call_info_b->body.len, call_info_b->body.s, + call_info_b->param_lst, call_info_b->last_param); + param = call_info_b->param_lst; + while (param) { + LM_DBG(".. [%p]->[%d] [%.*s]=[%.*s]->[%p]\n", + param, param->type, param->name.len, param->name.s, + param->value.len, param->value.s, param->next); + if (param->name.len==APPEARANCE_INDEX_LEN && + strncmp(APPEARANCE_INDEX_STR, + param->name.s, APPEARANCE_INDEX_LEN)==0) { + if (strno2int(¶m->value,&call_info_appearance)<0) { + LM_ERR("bad appearance-index [%.*s]\n", + param->value.len, param->value.s); + return -1; + } + if (appearance != call_info_appearance) { + LM_ERR("got appearance[%d] while expecting[%d]\n", + call_info_appearance, appearance); + goto next_callinfo_b; + } else { + LM_DBG("*** GOT APP-INDEX [%d]\n", + call_info_appearance); + } + } else if (param->name.len==APPEARANCE_STATE_LEN && + strncmp(APPEARANCE_STATE_STR, + param->name.s, APPEARANCE_STATE_LEN)==0) { + LM_DBG("*** GOT APP-STATE [%.*s]\n", + param->value.len, param->value.s); + if (param->value.len == strlen(APP_STATE_HELD_PRIVATE) && + strncmp(param->value.s, + app_state[HELD_PRIVATE_STATE].s, + param->value.len)==0) { + call_info_appearance_state = HELD_PRIVATE_STATE; + } + } + param=param->next; + } + goto handle_appearance; +next_callinfo_b: + callinfo_b = callinfo_b->next; + } + call_info = call_info->sibling; + } + } else { + LM_ERR("Unable to parse Call-Info header\n"); + return B2B_DROP_MSG_CB_RET; + } + } + +handle_appearance: + lock_get(&b2b_sca_htable[hash_index].lock); + record = b2b_sca_search_record_safe(hash_index, shared_line); + if (record == NULL) { + lock_release(&b2b_sca_htable[hash_index].lock); + LM_ERR("record not found for shared line [%.*s] on hash index [%d]\n", + shared_line->len, shared_line->s, hash_index); + return B2B_DROP_MSG_CB_RET; + } + + b2b_sca_print_record(record); + + switch(b2b_event){ + case B2B_DESTROY_CB: + /* Destroy the sca index record */ + shm_free(params->param); + b2b_sca_delete_call_record(hash_index, record, appearance); + break; + case B2B_RE_INVITE_CB: + case B2B_CONFIRMED_CB: + call = b2b_sca_search_call_safe(record, appearance); + if (call == NULL) { + LM_ERR("call record not found for shared line [%.*s] with index [%d]\n", + shared_line->len, shared_line->s, appearance); + lock_release(&b2b_sca_htable[hash_index].lock); + return B2B_DROP_MSG_CB_RET; + } + if (0 == parse_sdp(msg)) { + sdp_session = get_sdp_session(msg, sdp_session_num); + if(!sdp_session) break; + sdp_stream_num = 0; + for(;;) { + sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num); + if(!sdp_stream) break; + if(sdp_stream->media.len==AUDIO_STR_LEN && + strncmp(sdp_stream->media.s,AUDIO_STR,AUDIO_STR_LEN)==0 && + sdp_stream->is_on_hold) { + on_hold = 1; + break; + } + sdp_stream_num++; + } + sdp_session_num++; + } + + if (on_hold) { + if (call_info_appearance_state) + call->call_state = HELD_PRIVATE_STATE; + else + call->call_state = HELD_STATE; + } else { + call->call_state = ACTIVE_STATE; + } + break; + default: + LM_ERR("Unexpected event\n"); + } + + /* Prepare PUBLISH Call-Info header. */ + if (build_publish_call_info_header(record, &publish_hdr) != 0) { + lock_release(&b2b_sca_htable[hash_index].lock); + LM_ERR("Unable to build PUBLISH Call-Info header\n"); + return B2B_FOLLOW_SCENARIO_CB_RET; + } + + /* Save the record to db. */ + if (push_sca_info_to_db(record, appearance, 1) != 0) + LM_ERR("DB out of synch\n"); + + /* Notify the watchers. */ + sca_publish(record, &publish_hdr); + + b2b_sca_delete_record_if_empty(record, hash_index); + + lock_release(&b2b_sca_htable[hash_index].lock); + + if (publish_hdr.s != publish_call_info_hdr_buf) + pkg_free(publish_hdr.s); + + return B2B_FOLLOW_SCENARIO_CB_RET; +} + + +int sca_init_request(struct sip_msg* msg, str* p1, str* p2) +{ + int method_value, ret; + //unsigned int size, hash_index, shared_entity; + unsigned int hash_index, shared_entity, app_index; + str *b2bl_key, *host, *port, *display, *uri, *shared_line; + //char *p; + //uri_type scheme; + struct to_body *appearance_name_addr_body; + pv_value_t pv_val; + b2b_sca_record_t *record = NULL; + b2b_sca_call_t *call = NULL; + b2bl_cb_ctx_t *cb_params; + + str publish_hdr = {NULL, 0}; + str custom_hdr = {NULL, 0}; + str call_info_uri = {NULL, 0}; + str call_info_apperance_uri = {NULL, 0}; + + if (parse_headers(msg, HDR_EOH_F, 0) < 0) { + LM_ERR("failed to parse message\n"); + return -1; + } + method_value = msg->first_line.u.request.method_value; + if (method_value != METHOD_INVITE) { + LM_ERR("nonINVITE [%d] cannot initiate a call\n", method_value); + return -1; + } + ret = tmb.t_newtran(msg); + if(ret < 1) { + if(ret == 0) { + LM_DBG("It is a retransmission, drop\n"); + tmb.unref_cell(tmb.t_gett()); + } else { + LM_ERR("Error when creating tm transaction\n"); + } + return 0; + } + + if (p1 && (pv_get_spec_value(msg, (pv_spec_t *)p1, &pv_val) == 0)) { + if (pv_val.flags & PV_VAL_INT) { + shared_entity = pv_val.ri; + LM_DBG("got shared_entity %d\n", shared_entity); + } else if (pv_val.flags & PV_VAL_STR) { + if(str2int(&(pv_val.rs), (unsigned int*)&shared_entity) != 0) { + LM_ERR("Unable to get entity_no from pv '%.*s'\n", + pv_val.rs.len, pv_val.rs.s); + return -1; + } + } else { + LM_ERR("shared entity not a str or int type\n"); + return -1; + } + } else { + LM_ERR("Unable to get shared entity from pv:%p\n", p1); + return -1; + } + + switch (shared_entity) { + case 0: + LM_DBG("Incoming call from shared line\n"); + break; + case 1: + LM_DBG("Outgoing call via a shared line\n"); + break; + default: + LM_ERR("shared line entity should be 0 or 1\n"); + return -1; + } + + /* Get the hash index for the shared line. */ + if (get_hash_index_and_shared_line(msg, &hash_index, &shared_line)<0) + return -1; + LM_DBG("got hash_index=[%d] for shared line [%.*s]\n", + hash_index, shared_line->len, shared_line->s); + + /* Get the appearance name-addr for this call. */ + appearance_name_addr_body = get_appearance_name_addr(msg); + if (appearance_name_addr_body == NULL) { + LM_ERR("unable to get apperance of this call\n"); + return -1; + } + //scheme = appearance_name_addr_body->parsed_uri.type; + host = &appearance_name_addr_body->parsed_uri.host; + port = &appearance_name_addr_body->parsed_uri.port; + display = &appearance_name_addr_body->display; + uri = &appearance_name_addr_body->uri; + LM_DBG("display uri [%.*s][%.*s] from host:port [%.*s]:[%.*s]\n", + display->len, display->s, uri->len, uri->s, + host->len, host->s, port->len, port->s); + + + /* Prepare absoluteURI for Call-Info header. + */ + if (build_absoluteURI(host, port, &call_info_uri) != 0) + goto error1; + + /* Prepare appearanceURI param for Call-Info header. */ + if (build_appearanceURI(display, uri, &call_info_apperance_uri) != 0) + goto error1; + + /* Extract required appearance from the received request */ + app_index = get_app_index(msg); + + /* Adding call to the sca_table. */ + lock_get(&b2b_sca_htable[hash_index].lock); + if (b2b_sca_add_call_record(hash_index, shared_line, shared_entity, app_index, + &call_info_uri, &call_info_apperance_uri, &record, &call) != 0) { + LM_ERR("unable to add record to sca htable\n"); + goto error2; + } + + /* Prepare INVITE Call-Info header. */ + if (build_invite_call_info_header(call, &call_info_uri, &custom_hdr) != 0) + goto error2; + + /* Prepare PUBLISH Call-Info header. */ + if (build_publish_call_info_header(record, &publish_hdr) != 0) { + LM_ERR("Unable to build PUBLISH Call-Info header\n"); + goto error2; + } + + /* Prepare b2b_logic callback params. */ + cb_params = build_cb_params(hash_index, shared_line, call->appearance_index); + if (cb_params == NULL) + goto error2; + + LM_DBG("*** INITIALIZING \"top hiding\" SCENARIO with cb_params [%p]\n", cb_params); + /* release the lock here to avoid deadlock while getting callback notifications */ + lock_release(&b2b_sca_htable[hash_index].lock); + b2bl_key = b2bl_api.init(msg, &scenario, NULL, &sca_logic_notify, (void *)cb_params, + B2B_RE_INVITE_CB|B2B_CONFIRMED_CB|B2B_DESTROY_CB, &custom_hdr); + lock_get(&b2b_sca_htable[hash_index].lock); + + if (!b2bl_key || !b2bl_key->s || !b2bl_key->len) + goto error2; + else if (b2b_sca_update_call_record_key(call, b2bl_key) != 0) + goto error3; + + /* Save the record to db. */ + if (push_sca_info_to_db(record, call->appearance_index, 0) != 0) + goto error3; + + /* Notify the watchers. */ + sca_publish(record, &publish_hdr); + + lock_release(&b2b_sca_htable[hash_index].lock); + + + if (publish_hdr.s != publish_call_info_hdr_buf) + pkg_free(publish_hdr.s); + if (custom_hdr.s != invite_call_info_hdr_buf) + pkg_free(custom_hdr.s); + if (call_info_uri.s != call_info_uri_buf) + pkg_free(call_info_uri.s); + if (call_info_apperance_uri.s != call_info_apperance_uri_buf) + pkg_free(call_info_apperance_uri.s); + + return 1; + +error3: + /* Release the call */ + b2bl_api.terminate_call(b2bl_key); +error2: + lock_release(&b2b_sca_htable[hash_index].lock); +error1: + if (publish_hdr.s != publish_call_info_hdr_buf) + pkg_free(publish_hdr.s); + if (custom_hdr.s != invite_call_info_hdr_buf) + pkg_free(custom_hdr.s); + if (call_info_uri.s != call_info_uri_buf) + pkg_free(call_info_uri.s); + if (call_info_apperance_uri.s != call_info_apperance_uri_buf) + pkg_free(call_info_apperance_uri.s); + + return -1; +} + + +int sca_bridge_request(struct sip_msg* msg, str* p1, str* p2) +{ + pv_value_t pv_val; + str shared_line = {NULL, 0}; + str publish_hdr = {NULL, 0}; + int method_value, ret; + //int entity_no; + unsigned int hash_index; + b2b_sca_record_t *record = NULL; + b2b_sca_call_t *call; + + unsigned int appearance; + + if (p1 && (pv_get_spec_value(msg, (pv_spec_t *)p1, &pv_val) == 0)) { + if (pv_val.flags & PV_VAL_STR) { + LM_DBG("got shared_line:'%.*s'\n", pv_val.rs.len, pv_val.rs.s); + shared_line = pv_val.rs; + } else { + LM_ERR("Unable to get shared_line from PV that is not a string\n"); + return -1; + } + } else { + LM_ERR("Unable to get shared_line from pv:%p\n", p1); + return -1; + } + + /* Get the hash index for the shared line. */ + hash_index = core_hash(&shared_line, NULL, b2b_sca_hsize); + LM_DBG("got hash_index=[%d] for shared line [%.*s]\n", + hash_index, shared_line.len, shared_line.s); + + if (parse_headers(msg, HDR_EOH_F, 0) < 0) { + LM_ERR("failed to parse message\n"); + return -1; + } + method_value = msg->first_line.u.request.method_value; + if (method_value != METHOD_INVITE) { + LM_ERR("nonINVITE [%d] cannot bridge a call\n", method_value); + return -1; + } + ret = tmb.t_newtran(msg); + if(ret < 1) { + if(ret == 0) { + LM_DBG("It is a retransmission, drop\n"); + tmb.unref_cell(tmb.t_gett()); + } else { + LM_ERR("Error when creating tm transaction\n"); + } + return 0; + } + + if (!msg->call_info) { + LM_ERR("No 'Call-Info' header\n"); + return -1; + } + + /* Extract required appearance from the received request */ + appearance = get_app_index(msg); + if (appearance==0) return -1; + + lock_get(&b2b_sca_htable[hash_index].lock); + record = b2b_sca_search_record_safe(hash_index, &shared_line); + if (record == NULL) { + lock_release(&b2b_sca_htable[hash_index].lock); + LM_ERR("record not found for shared line [%.*s] on hash index [%d]\n", + shared_line.len, shared_line.s, hash_index); + // FIXME: + /* Build an empty PUBLISH header */ + //if (build_publish_call_info_header(NULL, &publish_hdr) != 0) { + // LM_ERR("Unable to build PUBLISH Call-Info header\n"); + //} + goto error; + } + + b2b_sca_print_record(record); + + call = b2b_sca_search_call_safe(record, appearance); + if (call == NULL) goto error; + if (call->call_state != HELD_STATE) { + LM_ERR("Improper call state [%d] for bridging\n", call->call_state); + goto error; + } + + /* What will happen if the b2b_logic entity doesn't exist anymore? */ + LM_DBG("*** BRIDGING THE REQUEST to entity [%d] on tuple [%.*s]\n", + call->shared_entity, call->b2bl_key.len, call->b2bl_key.s); + ret = b2bl_api.bridge_msg(msg, &call->b2bl_key, call->shared_entity); + if (ret != 0) { + /* FIXME: + * handle the error here */ + LM_ERR("*** got ret [%d]\n", ret); + goto error; + } + LM_DBG("*** got ret [%d]\n", ret); + + /* Set the state back to active */ + call->call_state = ACTIVE_STATE; + + /* Reset the shared_entity */ + call->shared_entity = 0; + + /* Prepare PUBLISH Call-Info header. */ + if (build_publish_call_info_header(record, &publish_hdr) != 0) { + lock_release(&b2b_sca_htable[hash_index].lock); + LM_ERR("Unable to build PUBLISH Call-Info header\n"); + return B2B_FOLLOW_SCENARIO_CB_RET; + } + + /* Save the record to db. */ + if (push_sca_info_to_db(record, appearance, 1) != 0) + LM_ERR("db out of synch\n"); + + /* Notify the watchers. */ + sca_publish(record, &publish_hdr); + + lock_release(&b2b_sca_htable[hash_index].lock); + + return 1; +error: + lock_release(&b2b_sca_htable[hash_index].lock); + + if (publish_hdr.s && publish_hdr.s != publish_call_info_hdr_buf) + pkg_free(publish_hdr.s); + + return -1; +} + diff --git a/modules/b2b_sca/sca_logic.h b/modules/b2b_sca/sca_logic.h new file mode 100644 index 00000000000..6fffa47b157 --- /dev/null +++ b/modules/b2b_sca/sca_logic.h @@ -0,0 +1,52 @@ +/* + * $Id$ + * + * sca logic module + * + * Copyright (C) 2010 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-11-21 initial version (Ovidiu Sas) + */ + +#ifndef B2B_SLA_LOGIC +#define B2B_SLA_LOGIC + +#include +#include + +#include "../../str.h" + + +typedef struct b2bl_cb_ctx { + unsigned int hash_index; + str shared_line; + unsigned int appearance; +} b2bl_cb_ctx_t; + + +void destroy_b2b_sca_handlers(void); + +b2bl_cb_ctx_t* build_cb_params(unsigned int hash_index, + str *shared_line, unsigned int appearance_index); + +int sca_logic_notify(b2bl_cb_params_t *params, unsigned int b2b_event); + +#endif diff --git a/modules/b2b_sca/sca_records.c b/modules/b2b_sca/sca_records.c new file mode 100644 index 00000000000..208feabdfb7 --- /dev/null +++ b/modules/b2b_sca/sca_records.c @@ -0,0 +1,573 @@ +/* + * $Id$ + * + * shared call appearance module + * + * Copyright (C) 2010 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-11-02 initial version (Ovidiu Sas) + */ + +#include +#include +#include + +#include "../../ut.h" +#include "../../mem/shm_mem.h" +#include "../../usr_avp.h" +#include "../../parser/parse_uri.h" +#include "sca_records.h" + + +extern int watchers_avp_name; +extern unsigned short watchers_avp_type; + +void add_watcher(str_lst_t **watchers, str_lst_t *new_watcher) +{ + new_watcher->next = *watchers; + *watchers = new_watcher; + return; +} + + +void free_watchers(str_lst_t *watchers) +{ + str_lst_t *watcher = watchers, *w; + + while (watcher) { + w = watcher->next; + pkg_free(watcher); + watcher = w; + } + return; +} + + +void memcpy_watchers(str_lst_t *dest, str_lst_t *src, unsigned int size) +{ + str_lst_t *from = src; + str_lst_t *to = dest; + char *p; + unsigned int len, total_len=0; + + p = (char *)to; + while (from) { + len = sizeof(str_lst_t) + from->watcher.len; + total_len += len; + if (len > size) { + LM_CRIT("buffer overflow\n"); + return; + } + memcpy((char *)to, (char *)from, len); + to->watcher.s = (char *)(to + 1); + if (to->watcher.len != from->watcher.len) { + LM_CRIT("error\n"); + return; + } + if (from->next == NULL) { + to->next = NULL; + break; + } + to->next = (str_lst_t *)(p + len); + + from = from->next; + to = to->next; + } + + return; +} + + +void print_watchers(str_lst_t *watchers) +{ + str_lst_t *watcher = watchers; + unsigned int len = 0; + + while (watcher) { + len += watcher->watcher.len; + LM_DBG("watcher [%d] [%d][%.*s]\n", len, watcher->watcher.len, + watcher->watcher.len, watcher->watcher.s); + watcher = watcher->next; + } +} + + +void get_watchers_from_avp(str_lst_t **watchers, unsigned int *watcher_size, + unsigned int *watchers_no) +{ + str_lst_t *new_watcher; + struct usr_avp *avp; + int_str val; + unsigned int size; + struct sip_uri parsed_uri; + char *p; + + *watchers = NULL; + *watcher_size = 0; + *watchers_no = 0; + for(;;) { + avp = search_first_avp(watchers_avp_type, watchers_avp_name, &val, 0); + if (avp == NULL) + break; + if(avp->flags&AVP_VAL_STR) + if (parse_uri(val.s.s, val.s.len, &parsed_uri)<0) + LM_WARN("discarding non URI watcher [%.*s]\n", val.s.len, val.s.s); + else { + LM_DBG("got watcher [%.*s]\n", val.s.len, val.s.s); + size = sizeof(str_lst_t) + val.s.len; + new_watcher = (str_lst_t *)pkg_malloc(size); + if (new_watcher == NULL) { + LM_ERR("OOM\n"); + return; + } + memset(new_watcher, 0, size); + + p = (char*)(new_watcher + 1); + new_watcher->watcher.len = val.s.len; + new_watcher->watcher.s = p; + memcpy(p, val.s.s, val.s.len); + add_watcher(watchers, new_watcher); + *watcher_size += size; + *watchers_no += 1; + } + else + LM_WARN("Ignoring non STR AVP\n"); + destroy_avp(avp); + } + print_watchers(*watchers); + return; +} + + +void get_watchers_from_csv(str *watchers_csv, str_lst_t **watchers, unsigned int *watcher_size, + unsigned int *watcher_no) +{ + str_lst_t *new_watcher; + char *tmp; + char *start = watchers_csv->s; + char *end = watchers_csv->s + watchers_csv->len; + unsigned int size; + char *p; + + *watchers = NULL; + *watcher_size = 0; + for( tmp=watchers_csv->s; tmp<=end; tmp++) { + if (*tmp == ',' || tmp==end) { + LM_DBG("watcher->[%.*s]\n", (int)(tmp-start), start); + + size = sizeof(str_lst_t) + tmp-start; + new_watcher = (str_lst_t *)pkg_malloc(size); + if (new_watcher == NULL) { + LM_ERR("OOM\n"); + return; + } + memset(new_watcher, 0, size); + + p = (char*)(new_watcher + 1); + new_watcher->watcher.len = tmp-start; + new_watcher->watcher.s = p; + memcpy(p, start, tmp-start); + add_watcher(watchers, new_watcher); + *watcher_size += size; + *watcher_no += 1; + + start = tmp + 1; + } + } + print_watchers(*watchers); + return; +} + + + +void b2b_sca_print_call_record(unsigned int i, b2b_sca_call_t *call) +{ + LM_DBG("appearance[%d][%d:%.*s][%p]->[%.*s][%d][%d][%.*s][%.*s]\n", + i, call->appearance_index, + call->appearance_index_str.len, call->appearance_index_str.s, + call, call->b2bl_key.len, call->b2bl_key.s, call->shared_entity, + call->call_state, call->call_info_uri.len, call->call_info_uri.s, + call->call_info_apperance_uri.len, call->call_info_apperance_uri.s); +} + + +void b2b_sca_print_record(b2b_sca_record_t *rec) +{ + unsigned int i; + + LM_DBG("record:[%p]->[%.*s] [%d] [%p:%p]\n", + rec, rec->shared_line.len, rec->shared_line.s, + rec->watchers_no, rec->prev, rec->next); + print_watchers(rec->watchers); + for (i=0; icall[i]) { + b2b_sca_print_call_record(i, rec->call[i]); + } + } +} + + + +b2b_sca_call_t* b2b_sca_search_call_safe(b2b_sca_record_t *record, unsigned int appearance) +{ + if (!appearance || appearance > MAX_APPEARANCE_INDEX) { + LM_ERR("out of bounds index [%d]\n", appearance); + return NULL; + } + if (record->call[appearance - 1] == NULL) { + LM_ERR("non existing call for shared line [%.*s] with index [%d]\n", + record->shared_line.len, record->shared_line.s, appearance); + return NULL; + } + return record->call[appearance - 1]; +} + +b2b_sca_record_t* b2b_sca_search_record_safe(int hash_index, str *shared_line) +{ + b2b_sca_record_t *record; + + record = b2b_sca_htable[hash_index].first; + while(record && (record->shared_line.len != shared_line->len || + strncmp(record->shared_line.s, shared_line->s, shared_line->len) != 0)) { + b2b_sca_print_record(record); + record = record->next; + } + + return record; +} + +b2b_sca_call_t* restore_call(b2b_sca_record_t *record, + unsigned int appearance_index, unsigned int shared_entity, + unsigned int call_state, str *call_info_uri, str *call_info_apperance_uri) +{ + b2b_sca_call_t *call; + unsigned int size; + str appearance_index_str; + char *p; + + appearance_index_str.s = int2str((unsigned long)appearance_index, + &appearance_index_str.len); + size = sizeof(b2b_sca_call_t) + + appearance_index_str.len + + call_info_uri->len + + call_info_apperance_uri->len + + B2BL_MAX_KEY_LEN; + call = (b2b_sca_call_t *)shm_malloc(size); + if (call == NULL) { + LM_ERR("OOM\n"); + return NULL; + } + memset(call, 0, size); + + call->appearance_index = appearance_index; + call->call_state = call_state; + call->shared_entity = shared_entity; + + p = (char*)(call + 1); + + call->appearance_index_str.len = appearance_index_str.len; + call->appearance_index_str.s = p; + memcpy(p, appearance_index_str.s, appearance_index_str.len); + p += appearance_index_str.len; + + call->call_info_uri.len = call_info_uri->len; + call->call_info_uri.s = p; + memcpy(p, call_info_uri->s, call_info_uri->len); + p += call_info_uri->len; + + call->call_info_apperance_uri.len = call_info_apperance_uri->len; + call->call_info_apperance_uri.s = p; + memcpy(p, call_info_apperance_uri->s, call_info_apperance_uri->len); + p += call_info_apperance_uri->len; + + call->b2bl_key.len = 0; + call->b2bl_key.s = p; + p += B2BL_MAX_KEY_LEN; + + record->call[appearance_index-1] = call; + + return call; +} + + +b2b_sca_record_t* restore_record(str *shared_line, str *watchers_csv) +{ + str_lst_t *watchers; + unsigned int size, watcher_size, watchers_no; + char *p; + b2b_sca_record_t *record; + + get_watchers_from_csv(watchers_csv, &watchers, &watcher_size, &watchers_no); + + size = sizeof(b2b_sca_record_t) + shared_line->len + watcher_size; + record = (b2b_sca_record_t *)shm_malloc(size); + if (record == NULL) { + LM_ERR("OOM\n"); + return NULL; + } + memset(record, 0, size); + p = (char*)(record + 1); + record->watchers_no = watchers_no; + record->shared_line.len = shared_line->len; + record->shared_line.s = p; + memcpy(p, shared_line->s, shared_line->len); + p += shared_line->len; + record->watchers = (str_lst_t *)p; + memcpy_watchers(record->watchers, watchers, watcher_size); + if (watchers) + free_watchers(watchers); + return record; +} + + +int b2b_sca_update_call_record_key(b2b_sca_call_t *call, str* b2bl_key) +{ + if (!b2bl_key || !b2bl_key->s || b2bl_key->len > B2BL_MAX_KEY_LEN) + return -1; + memcpy(call->b2bl_key.s, b2bl_key->s, b2bl_key->len); + call->b2bl_key.len = b2bl_key->len; + return 0; +} + + +int b2b_sca_add_call_record(int hash_index, str *shared_line, + unsigned int shared_entity, unsigned int app_index, + str *call_info_uri, str *call_info_apperance_uri, + b2b_sca_record_t **record_ctx, b2b_sca_call_t **call_ctx) +{ + //b2b_sca_record_t *rec, *prev_rec; + b2b_sca_record_t *record; + b2b_sca_call_t *call; + unsigned int i, size, watcher_size, watchers_no; + char *p; + str_lst_t *watchers; + + if (app_index>=MAX_APPEARANCE_INDEX) { + LM_ERR("Required app_index [%d] too big\n", app_index); + return -1; + } + + record = b2b_sca_search_record_safe(hash_index, shared_line); + if (record) { + /* We already have active calls for this shared line */ + if (app_index) { + i = app_index - 1; + if (record->call[i]) { + LM_DBG("Searching for a new slot\n"); + for (i=0; icall[i] == NULL) + break; + } + } + } else { + LM_DBG("no forced app_index\n"); + for (i=0; icall[i] == NULL) + break; + } + } + if (i == MAX_APPEARANCE_INDEX) { + LM_ERR("No available slots for this call\n"); + return -1; + } + call = restore_call(record, i+1, shared_entity, ALERTING_STATE, + call_info_uri, call_info_apperance_uri); + if (call == NULL) { + return -1; + } + } else { + /* First call for this shared line */ + + /* Get the list of watchers */ + get_watchers_from_avp(&watchers, &watcher_size, &watchers_no); + + size = sizeof(b2b_sca_record_t) + shared_line->len + watcher_size; + record = (b2b_sca_record_t *)shm_malloc(size); + if (record == NULL) { + LM_ERR("OOM\n"); + return -1; + } + memset(record, 0, size); + p = (char*)(record + 1); + + record->watchers_no = watchers_no; + record->shared_line.len = shared_line->len; + record->shared_line.s = p; + memcpy(p, shared_line->s, shared_line->len); + p += shared_line->len; + + if (watchers && watcher_size) { + record->watchers = (str_lst_t *)p; + memcpy_watchers(record->watchers, watchers, watcher_size); + if (watchers) + free_watchers(watchers); + } else { + record->watchers = NULL; + LM_WARN("We have no watchers: watchers=[%p] and watcher_size=[%d]\n", + watchers, watcher_size); + } + + /* Let's take care of the call now */ + call = restore_call(record, app_index?app_index:1, shared_entity, ALERTING_STATE, + call_info_uri, call_info_apperance_uri); + if (call == NULL) + goto error; + + /* Insert record into the table */ + insert_record(hash_index, record); + /* + rec = b2b_sca_htable[hash_index].first; + if (rec) { + while(rec) { + prev_rec = rec; + rec = rec->next; + } + prev_rec->next = record; + record->prev = prev_rec; + } else { + b2b_sca_htable[hash_index].first = record; + record->prev = record->next = NULL; + } + */ + } + + *record_ctx = record; + *call_ctx = call; + return 0; +error: + shm_free(record); + return -1; +} + + +void b2b_sca_delete_call_record(int hash_index, b2b_sca_record_t *record, unsigned int appearance) +{ + b2b_sca_call_t *call = b2b_sca_search_call_safe(record, appearance); + if (call) { + shm_free(call); + record->call[appearance - 1] = NULL; + } + return; +} + + + + +void b2b_sca_delete_record(b2b_sca_record_t *record, unsigned int hash_index) +{ + unsigned int i; + + if(b2b_sca_htable[hash_index].first == record) { + b2b_sca_htable[hash_index].first = record->next; + if(record->next) + record->next->prev = NULL; + } else { + if(record->prev) + record->prev->next = record->next; + if(record->next) + record->next->prev = record->prev; + } + + for (i=0; icall[i]) { + b2b_sca_print_call_record(i, record->call[i]); + LM_WARN("delete record with active appearance [%d]\n", i+1); + shm_free(record->call[i]); + } + + shm_free(record); + + return; +} + +void b2b_sca_delete_record_if_empty(b2b_sca_record_t *record, unsigned int hash_index) +{ + unsigned int i; + + for (i=0; icall[i]) + return; + + b2b_sca_delete_record(record, hash_index); + + return; +} + + +void insert_record(unsigned int hash_index, b2b_sca_record_t *record) +{ + b2b_sca_record_t *rec, *prev_rec; + + /* Insert record into the table */ + rec = b2b_sca_htable[hash_index].first; + if (rec) { + while(rec) { + prev_rec = rec; + rec = rec->next; + } + prev_rec->next = record; + record->prev = prev_rec; + } else { + b2b_sca_htable[hash_index].first = record; + record->prev = record->next = NULL; + } +} + + +int init_b2b_sca_htable(void) { + int i; + b2b_sca_htable = (b2b_sca_table_t)shm_malloc(b2b_sca_hsize* sizeof(b2b_sca_entry_t)); + if(!b2b_sca_htable) { + LM_ERR("OOM\n"); + goto error; + } + + for(i= 0; i< b2b_sca_hsize; i++) { + lock_init(&b2b_sca_htable[i].lock); + b2b_sca_htable[i].first = NULL; + } + + return 0; +error: + return -1; +} + +void destroy_b2b_sca_htable(void) { + int i; + b2b_sca_record_t *record; + + if(!b2b_sca_htable) + return; + + for(i= 0; i< b2b_sca_hsize; i++) { + lock_destroy(&b2b_sca_htable[i].lock); + record = b2b_sca_htable[i].first; + + while(record) { + b2b_sca_delete_record(record, i); + record = b2b_sca_htable[i].first; + } + } + + shm_free(b2b_sca_htable); + + return; +} diff --git a/modules/b2b_sca/sca_records.h b/modules/b2b_sca/sca_records.h new file mode 100644 index 00000000000..740d9f1ebaa --- /dev/null +++ b/modules/b2b_sca/sca_records.h @@ -0,0 +1,116 @@ +/* + * $Id$ + * + * sca logic module + * + * Copyright (C) 2010 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-11-21 initial version (Ovidiu Sas) + */ + +#ifndef B2B_SLA_RECORDS +#define B2B_SLA_RECORDS + +#include +#include + +#include "../../usr_avp.h" +#include "../b2b_logic/b2b_load.h" + +#define CALL_INFO_HEADER_MAX_LEN 512 + +#define IDLE_STATE 0 +#define ALERTING_STATE 1 +#define ACTIVE_STATE 2 +#define HELD_STATE 3 +#define HELD_PRIVATE_STATE 4 +#define MAX_INDEX_STATE 4 + +#define MAX_APPEARANCE_INDEX 10 + + +typedef struct str_lst{ + str watcher; + struct str_lst *next; +} str_lst_t; + +typedef struct b2b_sca_call { + unsigned int shared_entity; /* the entity to keep */ + unsigned int appearance_index; /* appearance index */ + str appearance_index_str; /* appearance index stored as str */ + unsigned int call_state; /* state of the call */ + str call_info_uri; /* call info: absoluteURI */ + str call_info_apperance_uri; /* call info: appearance param URI */ + str b2bl_key; /* key for the associated b2b_logic tuple */ +} b2b_sca_call_t; + +typedef struct b2b_sca_record { + str shared_line; /* shared line identifier */ + int expires; + unsigned int watchers_no; + str_lst_t *watchers; /* list of watchers */ + b2b_sca_call_t *call[MAX_APPEARANCE_INDEX]; /* array of appearances */ + struct b2b_sca_record *prev; + struct b2b_sca_record *next; +} b2b_sca_record_t; + +typedef struct b2b_sca_entry { + b2b_sca_record_t *first; + gen_lock_t lock; +} b2b_sca_entry_t; + +typedef b2b_sca_entry_t *b2b_sca_table_t; + +extern b2b_sca_table_t b2b_sca_htable; +extern unsigned int b2b_sca_hsize; + +int init_b2b_sca_htable(void); +void destroy_b2b_sca_htable(void); + +/* +void memcpy_watchers(str_lst_t *dest, str_lst_t *src, unsigned int size); +void get_watchers_from_csv(str *watchers_csv, str_lst_t **watchers, + unsigned int *watcher_size, unsigned int *watcher_no); +*/ + +void add_watcher(str_lst_t **watchers, str_lst_t *new_watcher); +void free_watchers(str_lst_t *watchers); +void print_watchers(str_lst_t *watchers); + +void b2b_sca_print_record(b2b_sca_record_t *rec); +b2b_sca_call_t* b2b_sca_search_call_safe(b2b_sca_record_t *record, unsigned int appearance); +b2b_sca_record_t* b2b_sca_search_record_safe(int hash_index, str *shared_line); +int b2b_sca_update_call_record_key(b2b_sca_call_t *call, str* b2bl_key); +int b2b_sca_add_call_record(int hash_index, str *shared_line, + unsigned int shared_entity, unsigned int app_index, + str *call_info_uri, str *call_info_apperance_uri, + b2b_sca_record_t **record, b2b_sca_call_t **call); +void b2b_sca_delete_call_record(int hash_index, b2b_sca_record_t *record, unsigned int appearance); +void b2b_sca_delete_record_if_empty(b2b_sca_record_t *record, unsigned int hash_index); + +b2b_sca_call_t* restore_call(b2b_sca_record_t *record, + unsigned int appearance_index, unsigned int shared_entity, + unsigned int call_state, str *call_info_uri, str *call_info_apperance_uri); +b2b_sca_record_t* restore_record(str *shared_line, str *watchers_csv); + +void insert_record(unsigned int hash_index, b2b_sca_record_t *record); + +#endif diff --git a/modules/benchmark/README b/modules/benchmark/README index 1b4e47b7041..dcc164728da 100644 --- a/modules/benchmark/README +++ b/modules/benchmark/README @@ -19,8 +19,7 @@ Bastian Friedrich Copyright © 2007 Voice System SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/benchmark/benchmark.c b/modules/benchmark/benchmark.c index 794e010e7a3..85262981550 100644 --- a/modules/benchmark/benchmark.c +++ b/modules/benchmark/benchmark.c @@ -142,7 +142,7 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; -static int bm_get_time_diff(struct sip_msg *msg, pv_param_t *param, +static int bm_get_time_diff(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); static pv_export_t mod_items[] = { @@ -155,9 +155,11 @@ static pv_export_t mod_items[] = { * Module interface */ struct module_exports exports = { - "benchmark", + "benchmark", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -212,7 +214,7 @@ static void destroy(void) benchmark_timer_t *bmt = 0; benchmark_timer_t *bmp = 0; - if(bm_mycfg!=NULL) + if(bm_mycfg!=NULL) { /* free timers list */ bmt = bm_mycfg->timers; @@ -233,7 +235,7 @@ static void soft_reset_timer(benchmark_timer_t *timer) { timer->calls = 0; timer->last_sum = 0; timer->last_max = 0; - timer->last_min = STARTING_MIN_VALUE; + timer->last_min = STARTING_MIN_VALUE; } static void reset_timer(int i) @@ -242,7 +244,7 @@ static void reset_timer(int i) if(bm_mycfg==NULL || (timer = bm_mycfg->tindex[i])==NULL) return; - + lock_get(timer->lock); timer->calls = 0; @@ -253,7 +255,7 @@ static void reset_timer(int i) timer->global_calls = 0; timer->global_max = 0; timer->global_min = STARTING_MIN_VALUE; - + lock_release(timer->lock); } @@ -317,7 +319,7 @@ static int _bm_log_timer(unsigned int id) LM_ERR("error getting current time\n"); return -1; } - + timer = bm_mycfg->tindex[id]; tdiff = bm_diff_time(timer->start, &now); _bm_last_time_diff = (int)tdiff; @@ -333,7 +335,7 @@ static int _bm_log_timer(unsigned int id) timer->last_sum += tdiff; timer->calls++; timer->global_calls++; - + if (tdiff < timer->last_min) timer->last_min = tdiff; @@ -368,11 +370,11 @@ static int _bm_log_timer(unsigned int id) soft_reset_timer(timer); } - + lock_release(timer->lock); return 1; -} +} static int bm_log_timer(struct sip_msg* _msg, char* timer, char* mystr) { @@ -425,7 +427,7 @@ static int _bm_register_timer(char *tname, int mode, unsigned int *id) } /* private memory, otherwise we have races */ - bmt->start = (bm_timeval_t*)pkg_malloc(sizeof(bm_timeval_t)); + bmt->start = (bm_timeval_t*)pkg_malloc(sizeof(bm_timeval_t)); if(bmt->start == NULL) { lock_dealloc(bmt->lock); @@ -433,7 +435,7 @@ static int _bm_register_timer(char *tname, int mode, unsigned int *id) LM_ERR("no more pkg\n"); return -1; } - memset(bmt->start, 0, sizeof(bm_timeval_t)); + memset(bmt->start, 0, sizeof(bm_timeval_t)); strcpy(bmt->name, tname); if(bm_mycfg->timers==0) @@ -567,7 +569,7 @@ static struct mi_root* mi_bm_enable_timer(struct mi_root *cmd, void *param) //p2 = strndup(node->next->value.s, node->next->value.len); p2 = pkg_strndup(node->next->value.s, node->next->value.len); v2 = strtol(p2, &e2, 0); - + pkg_free(p1); pkg_free(p2); @@ -630,7 +632,7 @@ static struct mi_root* mi_bm_loglevel(struct mi_root *cmd, void *param) p1 = pkg_strndup(node->value.s, node->value.len); v1 = strtol(p1, &e1, 0); - + pkg_free(p1); if ((*e1 != '\0') || (*p1 == '\0')) @@ -668,7 +670,7 @@ static struct mi_root* mi_bm_poll_results(struct mi_root *cmd, void *param) { struct mi_root *rpl_tree; benchmark_timer_t *bmt; - + if (bm_mycfg->granularity!=0) return init_mi_tree( 400, MI_CALL_INVALID_S, MI_CALL_INVALID_LEN); @@ -677,13 +679,14 @@ static struct mi_root* mi_bm_poll_results(struct mi_root *cmd, void *param) LM_ERR("Could not allocate the reply mi tree"); return NULL; } + rpl_tree->node.flags |= MI_IS_ARRAY; for(bmt = bm_mycfg->timers; bmt!=NULL; bmt=bmt->next) { lock_get(bmt->lock); add_results_node(&rpl_tree->node, bmt); soft_reset_timer(bmt); - + lock_release(bmt->lock); } diff --git a/modules/benchmark/benchmark.h b/modules/benchmark/benchmark.h index 10246f81a1a..97fc3f66d56 100644 --- a/modules/benchmark/benchmark.h +++ b/modules/benchmark/benchmark.h @@ -82,7 +82,7 @@ inline unsigned long long bm_diff_time(bm_timeval_t *t1, bm_timeval_t *t2) unsigned long long tdiff; tdiff = t2->tv_sec - t1->tv_sec; - + #ifdef BM_CLOCK_REALTIME tdiff = tdiff*1000000000 + t2->tv_nsec - t1->tv_nsec; #else diff --git a/modules/benchmark/benchmark_api.h b/modules/benchmark/benchmark_api.h index a4bb3c3553d..b29146b8374 100644 --- a/modules/benchmark/benchmark_api.h +++ b/modules/benchmark/benchmark_api.h @@ -60,7 +60,7 @@ static inline int load_bm_api( struct bm_binds *bmb ) LM_ERR("load_bm failed\n"); return -1; } - + return 0; } diff --git a/modules/cachedb_cassandra/Makefile b/modules/cachedb_cassandra/Makefile index dc812346df0..f0c212929ff 100644 --- a/modules/cachedb_cassandra/Makefile +++ b/modules/cachedb_cassandra/Makefile @@ -5,7 +5,7 @@ NAME=cachedb_cassandra.so CXX=g++ LD=g++ LIBS=cachedb_cassandra_dbase.o cassandra_constants.o cassandra_types.o Cassandra.o -L/usr/local/lib -lthrift -CXXFLAGS=$(CFLAGS:-Wno-deprecated option=) +CXXFLAGS=$(CFLAGS:-Wno-deprecated option=) -DHAVE_NETINET_IN_H # suppress a TON of warnings CXXFLAGS+= -Wno-write-strings -Wno-deprecated -Wno-unused-function -Wno-sign-compare -Wno-strict-aliasing @@ -13,18 +13,18 @@ include ../../Makefile.modules cassandra_constants.o: cassandra_constants.cpp cassandra_constants.h @echo "Compiling $<" - $(Q)$(CXX) $(CXXFLAGS) -I/usr/local/include/thrift -c $< -o $@ + $(Q)$(CXX) $(CXXFLAGS) -I/usr/include/thrift -I/usr/local/include/thrift -c $< -o $@ cassandra_types.o: cassandra_types.cpp cassandra_types.h @echo "Compiling $<" - $(Q)$(CXX) $(CXXFLAGS) -I/usr/local/include/thrift -c $< -o $@ + $(Q)$(CXX) $(CXXFLAGS) -I/usr/include/thrift -I/usr/local/include/thrift -c $< -o $@ Cassandra.o: Cassandra.cpp Cassandra.h @echo "Compiling $<" - $(Q)$(CXX) $(CXXFLAGS) -I/usr/local/include/thrift -c $< -o $@ + $(Q)$(CXX) $(CXXFLAGS) -I/usr/include/thrift -I/usr/local/include/thrift -c $< -o $@ cachedb_cassandra_dbase.o: cachedb_cassandra_dbase.cpp cachedb_cassandra_lib.h cachedb_cassandra_dbase.h @echo "Compiling $<" - $(Q)$(CXX) $(CXXFLAGS) $(DEFS) -I/usr/local/include/thrift -c $< -o $@ + $(Q)$(CXX) $(CXXFLAGS) $(DEFS) -I/usr/include/thrift -I/usr/local/include/thrift -c $< -o $@ cachedb_cassandra.so: cachedb_cassandra_dbase.o cassandra_constants.o cassandra_types.o Cassandra.o diff --git a/modules/cachedb_cassandra/README b/modules/cachedb_cassandra/README index 9a2e1283884..f32c9296fae 100644 --- a/modules/cachedb_cassandra/README +++ b/modules/cachedb_cassandra/README @@ -31,6 +31,7 @@ Vladut-Stefan Paiu 1.5.4. receive_timeout (int) 1.5.5. wr_consistency_level (int) 1.5.6. rd_consistency_level (int) + 1.5.7. exec_threshold (int) 1.6. Exported Functions 1.7. Known issues @@ -44,6 +45,7 @@ Vladut-Stefan Paiu 1.5. Set receive_timeout parameter 1.6. Set wr_consistency_level parameter 1.7. Set rd_consistency_level parameter + 1.8. Set exec_threshold parameter Chapter 1. Admin Guide @@ -185,6 +187,19 @@ modparam("cachedb_cassandra", "wr_consistency_level",7); modparam("cachedb_cassandra", "rd_consistency_level",7); ... +1.5.7. exec_threshold (int) + + The maximum number of microseconds that a cassandra cache query + can last. Anything above the threshold will trigger a warning + message to the log + + Default value is “0 ( unlimited - no warnings )”. + + Example 1.8. Set exec_threshold parameter +... +modparam("cachedb_cassandra", "exec_threshold", 100000) +... + 1.6. Exported Functions The module does not export functions to be used in diff --git a/modules/cachedb_cassandra/cachedb_cassandra.c b/modules/cachedb_cassandra/cachedb_cassandra.c index f7e2cc4e46d..7a0242473c2 100644 --- a/modules/cachedb_cassandra/cachedb_cassandra.c +++ b/modules/cachedb_cassandra/cachedb_cassandra.c @@ -45,6 +45,8 @@ int send_timeout=2000; /* ms */ int recv_timeout=2000; /* ms */ int rd_consistency_level=1; int wr_consistency_level=1; +/* TODO - implement */ +int cassandra_exec_threshold = 0; static int mod_init(void); static int child_init(int); @@ -65,16 +67,19 @@ static param_export_t params[]={ { "receive_timeout", INT_PARAM, &recv_timeout}, { "rd_consistency_level", INT_PARAM, &rd_consistency_level}, { "wr_consistency_level", INT_PARAM, &wr_consistency_level}, + { "exec_threshold", INT_PARAM, &cassandra_exec_threshold}, {0,0,0} }; /** module exports */ struct module_exports exports= { "cachedb_cassandra", + MOD_TYPE_CACHEDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, + NULL, /* OpenSIPS module dependencies */ 0, - params, + params, 0, 0, 0, diff --git a/modules/cachedb_cassandra/cachedb_cassandra.h b/modules/cachedb_cassandra/cachedb_cassandra.h index fc8893cd23c..a88d36de30d 100644 --- a/modules/cachedb_cassandra/cachedb_cassandra.h +++ b/modules/cachedb_cassandra/cachedb_cassandra.h @@ -31,5 +31,6 @@ extern int send_timeout; extern int recv_timeout; extern int rd_consistency_level; extern int wr_consistency_level; +extern int cassandra_exec_threshold; #endif diff --git a/modules/cachedb_cassandra/cachedb_cassandra_dbase.cpp b/modules/cachedb_cassandra/cachedb_cassandra_dbase.cpp index 6ba20177969..3a6bc0bf458 100644 --- a/modules/cachedb_cassandra/cachedb_cassandra_dbase.cpp +++ b/modules/cachedb_cassandra/cachedb_cassandra_dbase.cpp @@ -60,17 +60,17 @@ void* cassandra_init_connection(struct cachedb_id *id) str counter_family; int db_len; char *p; - + if (id == NULL) { LM_ERR("null cachedb_id\n"); return 0; } - + if (id->flags & CACHEDB_ID_MULTIPLE_HOSTS) { LM_ERR("multiple hosts are not supported for cassandra\n"); return 0; } - + if (id->database == NULL) { LM_ERR("no database supplied for cassandra\n"); return 0; @@ -104,7 +104,7 @@ void* cassandra_init_connection(struct cachedb_id *id) LM_INFO("Keyspace = [%.*s]. ColumnFamily = [%.*s]. CounterFamily = [%.*s]\n", keyspace.len,keyspace.s,column_family.len,column_family.s, counter_family.len,counter_family.s); - + con = (cassandra_con *)pkg_malloc(sizeof(cassandra_con)); if (con == NULL) { LM_ERR("no more pkg \n"); @@ -228,7 +228,7 @@ int cassandra_set(cachedb_con *connection,str *attr,str *val,int expires) con = (cassandra_con *)connection->data; c_con = (CassandraConnection *)con->cass_con; - + ret = c_con->cassandra_simple_insert(col_name,col_val,expires); if (ret<0) { LM_ERR("Failed to insert Cassandra key\n"); @@ -253,7 +253,7 @@ int cassandra_remove(cachedb_con *connection,str *attr) con = (cassandra_con *)connection->data; c_con = (CassandraConnection *)con->cass_con; - + ret = c_con->cassandra_simple_remove(col_name); if (ret<0) { LM_ERR("Failed to remove Cassandra key\n"); diff --git a/modules/cachedb_cassandra/cachedb_cassandra_lib.h b/modules/cachedb_cassandra/cachedb_cassandra_lib.h index 95f50b993e1..00ebb604da6 100644 --- a/modules/cachedb_cassandra/cachedb_cassandra_lib.h +++ b/modules/cachedb_cassandra/cachedb_cassandra_lib.h @@ -70,7 +70,7 @@ CassandraClient* client; protected: /* generate a timestamp in ms. Thrift stuff :| */ -long int make_cassandra_timestamp() const +long int make_cassandra_timestamp() const { struct timeval tv; long microseconds; @@ -82,24 +82,24 @@ long int make_cassandra_timestamp() const public: -CassandraConnection(const string& keyspace, const string& column_family,const string& counter_family) : +CassandraConnection(const string& keyspace, const string& column_family,const string& counter_family) : keyspace(keyspace), column_family(column_family), counter_family(counter_family), host(""), -port(0), -client(NULL) +port(0), +client(NULL) { } -virtual ~CassandraConnection() +virtual ~CassandraConnection() { cassandra_close(); } int cassandra_open(const string& host, int port, int connection_timeout,int receive_timeout,int send_timeout, - int read_cs_level,int write_cs_level) + int read_cs_level,int write_cs_level) { /* save host & port */ @@ -140,7 +140,7 @@ int cassandra_open(const string& host, int port, client->set_keyspace(keyspace); client->describe_version(version); LM_DBG("Opened connection for KeySpace [%s]." - " Cassandra version = [%s]\n", + " Cassandra version = [%s]\n", keyspace.c_str(), version.c_str()); return 0; @@ -157,7 +157,7 @@ int cassandra_open(const string& host, int port, return -1; } -void cassandra_close() +void cassandra_close() { if (client) { try { @@ -173,7 +173,7 @@ void cassandra_close() } } -int cassandra_reopen() +int cassandra_reopen() { cassandra_close(); return cassandra_open(host, port,conn_to,snd_to,rcv_to,rd_level,wr_level); @@ -215,7 +215,7 @@ char* cassandra_simple_get(const string& attr) LM_ERR("ERROR3: %s\n", e.what()); } } while (retry-- && cassandra_reopen() == 0); - + LM_ERR("giving up on query\n"); return NULL; } @@ -250,7 +250,7 @@ int cassandra_simple_get_counter(const string& attr,int *value) catch (NotFoundException &nfx) { /* if counter not found as set, return a 0 value */ if (value) - *value=0; + *value=0; return 0; } catch (TException &tx) { @@ -260,7 +260,7 @@ int cassandra_simple_get_counter(const string& attr,int *value) LM_ERR("ERROR3: %s\n", e.what()); } } while (retry-- && cassandra_reopen() == 0); - + LM_ERR("giving up on query\n"); return -1; } @@ -304,7 +304,7 @@ int cassandra_simple_insert(const string& name,const string& val, int expires) LM_ERR("ERROR: %s\n", e.what()); } } while (retry-- && cassandra_reopen() == 0); - + LM_ERR("giving up on query\n"); return -1; } @@ -344,7 +344,7 @@ int cassandra_simple_remove(const string& name) LM_ERR("ERROR: %s\n", e.what()); } } while (retry-- && cassandra_reopen() == 0); - + LM_ERR("giving up on query\n"); return -1; } @@ -368,7 +368,7 @@ int cassandra_simple_add(const string& name,int val) CounterColumn cc; cc.name = key; - cc.value = val; + cc.value = val; client->add(name, cp,cc,wr_level); return 0; @@ -382,7 +382,7 @@ int cassandra_simple_add(const string& name,int val) LM_ERR("ERROR3: %s\n", e.what()); } } while (retry-- && cassandra_reopen() == 0); - + LM_ERR("giving up on query\n"); return -1; } @@ -406,7 +406,7 @@ int cassandra_simple_sub(const string& name,int val) CounterColumn cc; cc.name = key; - cc.value = -val; + cc.value = -val; client->add(name, cp,cc,wr_level); return 0; @@ -420,7 +420,7 @@ int cassandra_simple_sub(const string& name,int val) LM_ERR("ERROR3: %s\n", e.what()); } } while (retry-- && cassandra_reopen() == 0); - + LM_ERR("giving up on query\n"); return -1; } diff --git a/modules/cachedb_cassandra/doc/cachedb_cassandra_admin.xml b/modules/cachedb_cassandra/doc/cachedb_cassandra_admin.xml index 85ecd852e0d..db2b6247972 100644 --- a/modules/cachedb_cassandra/doc/cachedb_cassandra_admin.xml +++ b/modules/cachedb_cassandra/doc/cachedb_cassandra_admin.xml @@ -271,6 +271,25 @@ modparam("cachedb_cassandra", "rd_consistency_level",7);
+
+ <varname>exec_threshold</varname> (int) + + The maximum number of microseconds that a cassandra cache query can last. + Anything above the threshold will trigger a warning message to the log + + + Default value is 0 ( unlimited - no warnings ). + + + + Set <varname>exec_threshold</varname> parameter + +... +modparam("cachedb_cassandra", "exec_threshold", 100000) +... + + +
diff --git a/modules/cachedb_couchbase/README b/modules/cachedb_couchbase/README index 051932b22f1..dc3758f6988 100644 --- a/modules/cachedb_couchbase/README +++ b/modules/cachedb_couchbase/README @@ -27,13 +27,17 @@ Vladut-Stefan Paiu 1.5.1. cachedb_url (string) 1.5.2. timeout (int) - 1.5.3. Exported Functions + 1.5.3. exec_threshold (int) + 1.5.4. lazy_connect (int) + 1.5.5. Exported Functions List of Examples 1.1. Set cachedb_url parameter 1.2. Set timeout parameter - 1.3. Use CouchBase servers + 1.3. Set exec_threshold parameter + 1.4. Set lazy_connect parameter + 1.5. Use CouchBase servers Chapter 1. Admin Guide @@ -84,14 +88,19 @@ Chapter 1. Admin Guide order to use the from script cache_store,cache_fetch, etc operations. It can be set more than one time. The prefix part of the URL will be the identifier that will be used from the - script. + script. The format of the URL is + couchbase[:identifier]://[username:password@]IP:Port/bucket_nam + e Example 1.1. Set cachedb_url parameter ... modparam("cachedb_couchbase", "cachedb_url","couchbase:group1://localhos -t:6379/"); +t:6379/default"); modparam("cachedb_couchbase", "cachedb_url","couchbase:cluster1://random -_url:8888/"); +_url:8888/my_bucket"); +#Multiple hosts +modparam("cachedb_couchbase", "cachedb_url","couchbase:cluster1://random +_url1:8888;random_url2:8888;random_url3:8888/my_bucket"); ... 1.5.2. timeout (int) @@ -104,14 +113,43 @@ _url:8888/"); modparam("cachedb_couchbase", "timeout",5000000); ... - Example 1.3. Use CouchBase servers +1.5.3. exec_threshold (int) + + The maximum number of microseconds that a couchbase query can + last. Anything above the threshold will trigger a warning + message to the log + + Default value is “0 ( unlimited - no warnings )”. + + Example 1.3. Set exec_threshold parameter +... +modparam("cachedb_couchbase", "exec_threshold", 100000) +... + +1.5.4. lazy_connect (int) + + Delay connecting to a bucket until the first time it is used. + Connecting to many buckets at startup can be time consuming. + This option allows for faster startup by delaying connections + until they are needed. This option can be dangerous for + untested bucket configurations/settings. Always test first + without lazy_connect. This option will show errors in the log + during the first access made to a bucket. Default is 0 ( + Connect to all buckets on startup ) + + Example 1.4. Set lazy_connect parameter +... +modparam("cachedb_couchbase", "lazy_connect", 1); +... + + Example 1.5. Use CouchBase servers ... cache_store("couchbase:group1","key","$ru value"); cache_fetch("couchbase:cluster1","key",$avp(10)); cache_remove("couchbase:cluster1","key"); ... -1.5.3. Exported Functions +1.5.5. Exported Functions The module does not export functions to be used in configuration script. diff --git a/modules/cachedb_couchbase/cachedb_couchbase.c b/modules/cachedb_couchbase/cachedb_couchbase.c index fb1837c45e0..5ca77e215da 100644 --- a/modules/cachedb_couchbase/cachedb_couchbase.c +++ b/modules/cachedb_couchbase/cachedb_couchbase.c @@ -48,6 +48,8 @@ static str cache_mod_name = str_init("couchbase"); struct cachedb_url *couchbase_script_urls = NULL; int couch_timeout_usec=3000000; /* defaults to 3 seconds */ +int couch_lazy_connect=0;/*Don't be lazy, connect on start*/ +int couch_exec_threshold=0; int set_connection(unsigned int type, void *val) { @@ -57,6 +59,8 @@ int set_connection(unsigned int type, void *val) static param_export_t params[]={ { "cachedb_url", STR_PARAM|USE_FUNC_PARAM, (void *)&set_connection}, { "timeout", INT_PARAM, &couch_timeout_usec }, + { "lazy_connect", INT_PARAM, &couch_lazy_connect }, + { "exec_threshold", INT_PARAM, &couch_exec_threshold }, {0,0,0} }; @@ -64,8 +68,10 @@ static param_export_t params[]={ /** module exports */ struct module_exports exports= { "cachedb_couchbase", /* module name */ + MOD_TYPE_CACHEDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ diff --git a/modules/cachedb_couchbase/cachedb_couchbase_dbase.c b/modules/cachedb_couchbase/cachedb_couchbase_dbase.c index 722121bef5e..ab4de4ccf13 100644 --- a/modules/cachedb_couchbase/cachedb_couchbase_dbase.c +++ b/modules/cachedb_couchbase/cachedb_couchbase_dbase.c @@ -33,8 +33,9 @@ #include extern int couch_timeout_usec; +extern int couch_lazy_connect; +extern int couch_exec_threshold; -volatile int last_error = 0; volatile str get_res = {0,0}; volatile int arithmetic_res = 0; @@ -45,22 +46,23 @@ static void couchbase_error_cb(lcb_t instance, LM_ERR("Error %d occured. Extra info : [%s]\n",error, errinfo?errinfo:""); - last_error = error; } + static void couchbase_get_cb(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *item) { if (error != LCB_SUCCESS) { - LM_ERR("Failure to get %.*s\n",(int)item->v.v0.nkey,(char*)item->v.v0.key); - last_error = error; + if (error != LCB_KEY_ENOENT) { + LM_ERR("Failure to get %.*s - %s\n",(int)item->v.v0.nkey,(char*)item->v.v0.key,lcb_strerror(instance, error)); + } + return; } get_res.s = pkg_malloc((int)item->v.v0.nbytes); if (!get_res.s) { LM_ERR("No more pkg mem\n"); - last_error = -1; return; } @@ -74,8 +76,7 @@ static void couchbase_store_cb(lcb_t instance, const void *cookie, const lcb_store_resp_t *item) { if (err != LCB_SUCCESS) { - LM_ERR("Failure to store %.*s\n",(int)item->v.v0.nkey,(char*)item->v.v0.key); - last_error = err; + LM_ERR("Failure to store %.*s - %s\n",(int)item->v.v0.nkey,(char*)item->v.v0.key,lcb_strerror(instance, err)); } } @@ -85,8 +86,9 @@ static void couchbase_remove_cb(lcb_t instance, const lcb_remove_resp_t *item) { if (err != LCB_SUCCESS) { - LM_ERR("Failure to remove %.*s\n",(int)item->v.v0.nkey,(char*)item->v.v0.key); - last_error = err; + if (err != LCB_KEY_ENOENT) { + LM_ERR("Failure to remove %.*s - %s\n",(int)item->v.v0.nkey,(char*)item->v.v0.key,lcb_strerror(instance, err)); + } } } @@ -96,23 +98,20 @@ static void couchbase_arithmetic_cb(lcb_t instance, const lcb_arithmetic_resp_t *item) { if (error != LCB_SUCCESS) { - LM_ERR("Failure to remove %.*s\n",(int)item->v.v0.nkey,(char*)item->v.v0.key); - last_error = error; + LM_ERR("Failure to perform arithmetic %.*s - %s\n",(int)item->v.v0.nkey,(char*)item->v.v0.key,lcb_strerror(instance, error)); return; } arithmetic_res = item->v.v0.value; } -couchbase_con* couchbase_new_connection(struct cachedb_id* id) +couchbase_con* couchbase_connect(struct cachedb_id* id, int is_reconnect) { couchbase_con *con; struct lcb_create_st options; lcb_t instance; lcb_error_t rc; - last_error = 0; - if (id == NULL) { LM_ERR("null cachedb_id\n"); return 0; @@ -154,22 +153,38 @@ couchbase_con* couchbase_new_connection(struct cachedb_id* id) (void)lcb_set_arithmetic_callback(instance,couchbase_arithmetic_cb); (void)lcb_set_timeout(instance,couch_timeout_usec); - rc=lcb_connect(instance); - if (rc != LCB_SUCCESS || last_error != 0) { - LM_ERR("Failed to connect to the Couchbase node: 0x%02x, %s\n", - rc, lcb_strerror(instance, rc)); - lcb_destroy(instance); - return 0; + //Set to synchronous mode + lcb_behavior_set_syncmode(instance, LCB_SYNCHRONOUS); + + if (couch_lazy_connect == 0 || is_reconnect == 1) { + rc=lcb_connect(instance); + + /*Check connection*/ + if (rc != LCB_SUCCESS) { + /*Consider these connect failurs as fatal*/ + if(rc == LCB_AUTH_ERROR || rc == LCB_INVALID_HOST_FORMAT || rc == LCB_INVALID_CHAR) { + LM_ERR("Fatal connection error to Couchbase. Host: %s Bucket: %s Error: %s", + id->host, id->database, lcb_strerror(instance, rc)); + lcb_destroy(instance); + return 0; + } else { + /* Non-fatal errors, we may be able to connect later */ + LM_ERR("Non-Fatal connection error to Couchbase. Host: %s Bucket: %s Error: %s", + id->host, id->database, lcb_strerror(instance, rc)); + } + } else { + LM_DBG("Succesfully connected to Couchbase Server. Host: %s Bucket: %s\n", id->host, id->database); + } } - /* Wait for the connect to complete */ - lcb_wait(instance); - - LM_DBG("Succesfully connected to Couchbase Server\n"); con->couchcon = instance; return con; } +couchbase_con* couchbase_new_connection(struct cachedb_id* id) +{ + return couchbase_connect(id, 0); +} cachedb_con *couchbase_init(str *url) { return cachedb_do_init(url,(void *)couchbase_new_connection); @@ -192,7 +207,45 @@ void couchbase_destroy(cachedb_con *con) cachedb_do_close(con,couchbase_free_connection); } -/* TODO - handle reconnection ? */ +/*Conditionally reconnect based on the error code*/ +int couchbase_conditional_reconnect(cachedb_con *con, lcb_error_t err) { + cachedb_pool_con *tmp; + void *newcon; + + if (!con) return -1; + + switch (err) { + /* Error codes to attempt reconnects on */ + case LCB_EINTERNAL: + case LCB_CLIENT_ETMPFAIL: + case LCB_EBADHANDLE: + case LCB_NETWORK_ERROR: + case LCB_ETIMEDOUT: + break; + default: + /*nothing to do*/ + return 0; + break; + } + + tmp = (cachedb_pool_con*)(con->data); + LM_ERR("Attempting reconnect to Couchbase. Host: %s Bucket: %s On Error: %s", + tmp->id->host, tmp->id->database, lcb_strerror(COUCHBASE_CON(con), err)); + + newcon = couchbase_connect(tmp->id, 1); + + /*Successful reconnect, get rid of the old handle*/ + if (newcon != NULL) { + LM_ERR("Successfully reconnected to Couchbase. Host: %s Bucket: %s", tmp->id->host, tmp->id->database); + tmp->id = NULL; + couchbase_free_connection(tmp); + con->data = newcon; + return 1; + } + + LM_ERR("Failed to reconnect to Couchbase. Host: %s Bucket: %s", tmp->id->host, tmp->id->database); + return -2; +} int couchbase_set(cachedb_con *connection,str *attr, str *val,int expires) @@ -201,9 +254,9 @@ int couchbase_set(cachedb_con *connection,str *attr, lcb_error_t oprc; lcb_store_cmd_t cmd; const lcb_store_cmd_t *commands[1]; + struct timeval start; - last_error = 0; - + start_expire_timer(start,couch_exec_threshold); instance = COUCHBASE_CON(connection); commands[0] = &cmd; @@ -214,22 +267,33 @@ int couchbase_set(cachedb_con *connection,str *attr, cmd.v.v0.bytes = val->s; cmd.v.v0.nbytes = val->len; cmd.v.v0.exptime = expires; + oprc = lcb_store(instance, NULL, 1, commands); if (oprc != LCB_SUCCESS) { - LM_ERR("Failed to send the insert query\n"); - return -1; - } - - lcb_wait(instance); - - oprc = lcb_get_last_error(instance); - if (oprc != LCB_SUCCESS || last_error != 0) { - LM_ERR("Failed to store the key\n"); - return -1; + LM_ERR("Set request failed - %s\n", lcb_strerror(instance, oprc)); + //Attempt reconnect + if(couchbase_conditional_reconnect(connection, oprc) != 1) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase set",attr->s,attr->len,0); + return -2; + } + + //Try again + instance = COUCHBASE_CON(connection); + oprc = lcb_store(instance, NULL, 1, commands); + + if (oprc != LCB_SUCCESS) { + LM_ERR("Set command retry failed - %s\n", lcb_strerror(instance, oprc)); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase set",attr->s,attr->len,0); + return -2; + } + LM_ERR("Set command successfully retried\n"); } - LM_DBG("Succesfully stored\n"); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase set",attr->s,attr->len,0); return 1; } @@ -239,9 +303,9 @@ int couchbase_remove(cachedb_con *connection,str *attr) lcb_error_t oprc; lcb_remove_cmd_t cmd; const lcb_remove_cmd_t *commands[1]; + struct timeval start; - last_error = 0; - + start_expire_timer(start,couch_exec_threshold); instance = COUCHBASE_CON(connection); commands[0] = &cmd; memset(&cmd, 0, sizeof(cmd)); @@ -250,19 +314,40 @@ int couchbase_remove(cachedb_con *connection,str *attr) oprc = lcb_remove(instance, NULL, 1, commands); if (oprc != LCB_SUCCESS) { - LM_ERR("Failed to send the insert query\n"); - return -1; - } - - lcb_wait(instance); - - oprc = lcb_get_last_error(instance); - if (oprc != LCB_SUCCESS || last_error != 0) { - LM_ERR("Failed to store the key\n"); - return -1; + if (oprc == LCB_KEY_ENOENT) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase remove",attr->s,attr->len,0); + return -1; + } + + LM_ERR("Failed to send the remove query - %s\n", lcb_strerror(instance, oprc)); + if (couchbase_conditional_reconnect(connection, oprc) != 1) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase remove",attr->s,attr->len,0); + return -2; + }; + + instance = COUCHBASE_CON(connection); + oprc = lcb_remove(instance, NULL, 1, commands); + + if (oprc != LCB_SUCCESS) { + if (oprc == LCB_KEY_ENOENT) { + LM_ERR("Remove command successfully retried\n"); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase remove",attr->s,attr->len,0); + return -1; + } + LM_ERR("Remove command retry failed - %s\n", lcb_strerror(instance, oprc)); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase remove",attr->s,attr->len,0); + return -2; + } + LM_ERR("Remove command successfully retried\n"); } - LM_DBG("Succesfully stored\n"); + LM_DBG("Succesfully removed\n"); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase remove",attr->s,attr->len,0); return 1; } @@ -272,8 +357,9 @@ int couchbase_get(cachedb_con *connection,str *attr,str *val) lcb_error_t oprc; lcb_get_cmd_t cmd; const lcb_get_cmd_t *commands[1]; + struct timeval start; - last_error = 0; + start_expire_timer(start,couch_exec_threshold); instance = COUCHBASE_CON(connection); commands[0] = &cmd; @@ -283,18 +369,47 @@ int couchbase_get(cachedb_con *connection,str *attr,str *val) oprc = lcb_get(instance, NULL, 1, commands); if (oprc != LCB_SUCCESS) { - LM_ERR("Failed to send the insert query\n"); - return -1; + /* Key not present, record does not exist */ + if (oprc == LCB_KEY_ENOENT) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get",attr->s,attr->len,0); + return -1; + } + + //Attempt reconnect + if (couchbase_conditional_reconnect(connection, oprc) != 1) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get",attr->s,attr->len,0); + return -2; + } + + //Try Again + instance = COUCHBASE_CON(connection); + oprc = lcb_get(instance, NULL, 1, commands); + if (oprc != LCB_SUCCESS) { + if (oprc == LCB_KEY_ENOENT) { + LM_ERR("Get command successfully retried\n"); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get",attr->s,attr->len,0); + return -1; + } + LM_ERR("Get command retry failed - %s\n", lcb_strerror(instance, oprc)); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get",attr->s,attr->len,0); + return -2; + } + LM_ERR("Get command successfully retried\n"); } - lcb_wait(instance); - - oprc = lcb_get_last_error(instance); - if (oprc != LCB_SUCCESS || last_error != 0) { - LM_ERR("Failed to store the key\n"); - return -1; + //Incase of malloc failure + if (!get_res.s) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get",attr->s,attr->len,0); + return -2; } + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get",attr->s,attr->len,0); *val = get_res; return 1; } @@ -305,8 +420,9 @@ int couchbase_add(cachedb_con *connection,str *attr,int val,int expires,int *new lcb_error_t oprc; lcb_arithmetic_cmd_t cmd; const lcb_arithmetic_cmd_t *commands[1]; + struct timeval start; - last_error = 0; + start_expire_timer(start,couch_exec_threshold); instance = COUCHBASE_CON(connection); commands[0] = &cmd; @@ -320,21 +436,44 @@ int couchbase_add(cachedb_con *connection,str *attr,int val,int expires,int *new oprc = lcb_arithmetic(instance, NULL, 1, commands); if (oprc != LCB_SUCCESS) { - LM_ERR("Failed to send the insert query\n"); - return -1; - } - - lcb_wait(instance); - - oprc = lcb_get_last_error(instance); - if (oprc != LCB_SUCCESS || last_error != 0) { - LM_ERR("Failed to store the key\n"); - return -1; + if (oprc == LCB_KEY_ENOENT) { + return -1; + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase add",attr->s,attr->len,0); + } + + LM_ERR("Failed to send the arithmetic query - %s\n", lcb_strerror(instance, oprc)); + //Attempt reconnect + if (couchbase_conditional_reconnect(connection, oprc) != 1) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase add",attr->s,attr->len,0); + return -2; + } + + //Try again + instance = COUCHBASE_CON(connection); + oprc = lcb_arithmetic(instance, NULL, 1, commands); + + if (oprc != LCB_SUCCESS) { + if (oprc == LCB_KEY_ENOENT) { + LM_ERR("Arithmetic command successfully retried\n"); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase add",attr->s,attr->len,0); + return -1; + } + LM_ERR("Arithmetic command retry failed - %s\n", lcb_strerror(instance, oprc)); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase add",attr->s,attr->len,0); + return -2; + } + LM_ERR("Arithmetic command successfully retried\n"); } if (new_val) *new_val = arithmetic_res; + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase add",attr->s,attr->len,0); return 1; } @@ -345,5 +484,72 @@ int couchbase_sub(cachedb_con *connection,str *attr,int val,int expires,int *new int couchbase_get_counter(cachedb_con *connection,str *attr,int *val) { - return couchbase_add(connection,attr,0,0,val); + lcb_t instance; + lcb_error_t oprc; + lcb_get_cmd_t cmd; + const lcb_get_cmd_t *commands[1]; + struct timeval start; + + start_expire_timer(start,couch_exec_threshold); + instance = COUCHBASE_CON(connection); + + commands[0] = &cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.v.v0.key = attr->s; + cmd.v.v0.nkey = attr->len; + oprc = lcb_get(instance, NULL, 1, commands); + + if (oprc != LCB_SUCCESS) { + /* Key not present, record does not exist */ + if (oprc == LCB_KEY_ENOENT) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get counter",attr->s,attr->len,0); + return -1; + } + + //Attempt reconnect + if (couchbase_conditional_reconnect(connection, oprc) != 1) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get counter ",attr->s,attr->len,0); + return -2; + } + + //Try Again + instance = COUCHBASE_CON(connection); + oprc = lcb_get(instance, NULL, 1, commands); + if (oprc != LCB_SUCCESS) { + if (oprc == LCB_KEY_ENOENT) { + LM_ERR("Get counter command successfully retried\n"); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get counter",attr->s,attr->len,0); + return -1; + } + LM_ERR("Get counter command retry failed - %s\n", lcb_strerror(instance, oprc)); + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get counter",attr->s,attr->len,0); + return -2; + } + LM_ERR("Get command successfully retried\n"); + } + + //Incase of malloc failure + if (!get_res.s) { + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get counter",attr->s,attr->len,0); + return -2; + } + + stop_expire_timer(start,couch_exec_threshold, + "cachedb_couchbase get counter",attr->s,attr->len,0); + + if (str2sint((str *)&get_res,val)) { + LM_ERR("Failued to convert counter [%.*s] to int\n",get_res.len,get_res.s); + pkg_free(get_res.s); + get_res.s = NULL; + return -1; + } + + pkg_free(get_res.s); + get_res.s = NULL; + return 1; } diff --git a/modules/cachedb_couchbase/doc/cachedb_couchbase_admin.xml b/modules/cachedb_couchbase/doc/cachedb_couchbase_admin.xml index e9a8d551652..18566bec7c0 100644 --- a/modules/cachedb_couchbase/doc/cachedb_couchbase_admin.xml +++ b/modules/cachedb_couchbase/doc/cachedb_couchbase_admin.xml @@ -122,14 +122,18 @@ It can be set more than one time. The prefix part of the URL will be the identifier that will be used from the script. + The format of the URL is + couchbase[:identifier]://[username:password@]IP:Port/bucket_name Set <varname>cachedb_url</varname> parameter ... -modparam("cachedb_couchbase", "cachedb_url","couchbase:group1://localhost:6379/"); -modparam("cachedb_couchbase", "cachedb_url","couchbase:cluster1://random_url:8888/"); +modparam("cachedb_couchbase", "cachedb_url","couchbase:group1://localhost:6379/default"); +modparam("cachedb_couchbase", "cachedb_url","couchbase:cluster1://random_url:8888/my_bucket"); +#Multiple hosts +modparam("cachedb_couchbase", "cachedb_url","couchbase:cluster1://random_url1:8888;random_url2:8888;random_url3:8888/my_bucket"); ... @@ -147,6 +151,47 @@ modparam("cachedb_couchbase", "cachedb_url","couchbase:cluster1://random_url:888 ... modparam("cachedb_couchbase", "timeout",5000000); +... + + +
+
+ <varname>exec_threshold</varname> (int) + + The maximum number of microseconds that a couchbase query can last. + Anything above the threshold will trigger a warning message to the log + + + Default value is 0 ( unlimited - no warnings ). + + + + Set <varname>exec_threshold</varname> parameter + +... +modparam("cachedb_couchbase", "exec_threshold", 100000) +... + + +
+ +
+ <varname>lazy_connect</varname> (int) + + Delay connecting to a bucket until the first time it is used. + Connecting to many buckets at startup can be time consuming. This option allows for + faster startup by delaying connections until they are needed. + This option can be dangerous for untested bucket configurations/settings. Always test + first without lazy_connect. + This option will show errors in the log during the first access made to a bucket. + Default is 0 ( Connect to all buckets on startup ) + + + + Set <varname>lazy_connect</varname> parameter + +... +modparam("cachedb_couchbase", "lazy_connect", 1); ... diff --git a/modules/cachedb_local/README b/modules/cachedb_local/README index 34df14261f2..35a9263cfa2 100644 --- a/modules/cachedb_local/README +++ b/modules/cachedb_local/README @@ -15,8 +15,7 @@ Vladut-Stefan Paiu Copyright © 2009 Anca-Maria Vamanu Revision History - Revision $Revision: 5901 $ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -32,13 +31,17 @@ Vladut-Stefan Paiu 1.3. Exported Parameters 1.3.1. cache_table_size (int) - 1.3.2. cache_clean_period (int) - 1.3.3. Exported Functions + 1.3.2. exec_threshold (int) + 1.3.3. cache_clean_period (int) + 1.3.4. Exported Functions + 1.3.5. Exported MI Functions List of Examples 1.1. Set cache_table_size parameter - 1.2. Set cache_clean_period parameter + 1.2. Set exec_threshold parameter + 1.3. Set cache_clean_period parameter + 1.4. cache_remove_chunk usage Chapter 1. Admin Guide @@ -74,19 +77,55 @@ Chapter 1. Admin Guide modparam("cachedb_local", "cache_table_size", 10) ... -1.3.2. cache_clean_period (int) +1.3.2. exec_threshold (int) + + The maximum number of microseconds that a local cache query can + last. Anything above the threshold will trigger a warning + message to the log + + Default value is “0 ( unlimited - no warnings )”. + + Example 1.2. Set exec_threshold parameter +... +modparam("cachedb_local", "exec_threshold", 100000) +... + +1.3.3. cache_clean_period (int) The time interval in seconds at which to go through all the records and delete the expired ones. Default value is “600 (10 minutes)”. - Example 1.2. Set cache_clean_period parameter + Example 1.3. Set cache_clean_period parameter ... modparam("cachedb_local", "cache_clean_period", 1200) ... -1.3.3. Exported Functions +1.3.4. Exported Functions + +1.3.4.1. cache_remove_chunk(glob) + + Remove all keys from local cache that match the glob pattern + + This function can be used from all routes + + Example 1.4. cache_remove_chunk usage + ... + cache_remove_chunk("myinfo_*"); + ... + +1.3.5. Exported MI Functions + +1.3.5.1. cache_remove_chunk + + Removes all local cache entries that match the provided glob + param. + + Parameters : + * glob - keys that match glob will be removed - The module does not export functions to be used in - configuration script. + MI FIFO Command Format: + :cache_remove_chunk:_reply_fifo_file_ + keyprefix* + _empty_line_ diff --git a/modules/cachedb_local/cachedb_local.c b/modules/cachedb_local/cachedb_local.c index 5204c3167b0..eb3927fa49d 100644 --- a/modules/cachedb_local/cachedb_local.c +++ b/modules/cachedb_local/cachedb_local.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -37,10 +37,14 @@ #include "../../ut.h" #include "../../mem/mem.h" #include "../../mem/shm_mem.h" +#include "../../mod_fix.h" +#include "../../mi/tree.h" #include "cachedb_local.h" #include "hash.h" +#include + str cache_mod_name = str_init("local"); static int mod_init(void); static int child_init(int rank); @@ -49,24 +53,43 @@ static void destroy(void); lcache_t* cache_htable = NULL; int cache_htable_size = 9; int cache_clean_period = 600; +int local_exec_threshold = 0; + +static int remove_chunk_f(struct sip_msg* msg, char* glob); +struct mi_root * mi_cache_remove_chunk(struct mi_root *cmd_tree,void *param); void localcache_clean(unsigned int ticks,void *param); static param_export_t params[]={ { "cache_table_size", INT_PARAM, &cache_htable_size }, - { "cache_clean_period", INT_PARAM, &cache_clean_period}, + { "cache_clean_period", INT_PARAM, &cache_clean_period }, + { "exec_threshold", INT_PARAM, &local_exec_threshold }, {0,0,0} }; +static cmd_export_t cmds[]= { + {"cache_remove_chunk", (cmd_function)remove_chunk_f, 1, + fixup_str_null, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE}, + {0,0,0,0,0,0} +}; + +static mi_export_t mi_cmds[] = { + { "cache_remove_chunk", 0, mi_cache_remove_chunk, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0} +}; + /** module exports */ struct module_exports exports= { "cachedb_local", /* module name */ + MOD_TYPE_CACHEDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ - 0, /* exported functions */ + NULL, /* OpenSIPS module dependencies */ + cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ - 0, /* exported MI functions */ + mi_cmds, /* exported MI functions */ 0, /* exported pseudo-variables */ 0, /* extra processes */ mod_init, /* module initialization function */ @@ -75,10 +98,113 @@ struct module_exports exports= { child_init /* per-child init function */ }; +static char *key_buff = NULL; +static int key_buff_size = 0; +static char *pat_buff = NULL; +static int pat_buff_size = 0; +static int remove_chunk_f(struct sip_msg* msg, char* glob) +{ + int i; + str *pat = (str *)glob; + lcache_entry_t* me1, *me2; + struct timeval start; + + if (pat->len+1 > pat_buff_size) { + pat_buff = pkg_realloc(pat_buff,pat->len+1); + if (pat_buff == NULL) { + LM_ERR("No more pkg mem\n"); + pat_buff_size = 0; + return -1; + } + + pat_buff_size = pat->len +1; + } + + memcpy(pat_buff,pat->s,pat->len); + pat_buff[pat->len] = 0; + + LM_DBG("trying to remove chunk with pattern [%s]\n",pat_buff); + start_expire_timer(start,local_exec_threshold); + + for(i = 0; i< cache_htable_size; i++) { + lock_get(&cache_htable[i].lock); + me1 = cache_htable[i].entries; + me2 = NULL; + + while(me1) { + if (me1->attr.len + 1 > key_buff_size) { + key_buff = pkg_realloc(key_buff,me1->attr.len+1); + if (key_buff == NULL) { + LM_ERR("No more pkg mem\n"); + key_buff_size = 0; + lock_release(&cache_htable[i].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local remove_chunk",pat->s,pat->len,0); + return -1; + } + + key_buff_size = me1->attr.len + 1; + } + + memcpy(key_buff,me1->attr.s,me1->attr.len); + key_buff[me1->attr.len] = 0; + + if(fnmatch(pat_buff,key_buff,0) == 0) { + LM_DBG("[%.*s] matches glob [%.*s] - removing from bucket %d\n", + me1->attr.len, me1->attr.s,pat_buff_size,pat_buff,i); + + if(me2) { + me2->next = me1->next; + shm_free(me1); + me1 = me2->next; + } else{ + cache_htable[i].entries = me1->next; + shm_free(me1); + me1 = cache_htable[i].entries; + } + } else { + me2 = me1; + me1 = me1->next; + } + } + lock_release(&cache_htable[i].lock); + } + + stop_expire_timer(start,local_exec_threshold, + "cachedb_local remove_chunk",pat->s,pat->len,0); + return 1; +} + +struct mi_root * mi_cache_remove_chunk(struct mi_root *cmd_tree,void *param) +{ + struct mi_node* node; + int status, msg_len; + char *msg; + + node = cmd_tree->node.kids; + if (node == NULL) + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + + if (!node->value.s || !node->value.len) + return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + + if (remove_chunk_f(NULL,(char *)(&node->value)) < 1) { + status = 500; + msg = MI_INTERNAL_ERR_S; + msg_len = MI_INTERNAL_ERR_LEN; + } else { + status = 200; + msg = MI_OK_S; + msg_len = MI_OK_LEN; + } + + return init_mi_tree(status,msg,msg_len); +} + lcache_con* lcache_new_connection(struct cachedb_id* id) { lcache_con *con; - + if (id->flags != CACHEDB_ID_NO_URL) { LM_ERR("bogus url for local cachedb\n"); return 0; @@ -98,7 +224,7 @@ lcache_con* lcache_new_connection(struct cachedb_id* id) memset(con,0,sizeof(lcache_con)); con->id = id; con->ref = 1; - + return con; } @@ -112,7 +238,7 @@ void lcache_free_connection(cachedb_pool_con *con) pkg_free(con); } -void lcache_destroy(cachedb_con *con) +void lcache_destroy(cachedb_con *con) { cachedb_do_close(con,lcache_free_connection); } @@ -127,7 +253,7 @@ static int mod_init(void) cachedb_con *con; str url=str_init("local://"); str name=str_init("local"); - + if(cache_htable_size< 1) cache_htable_size= 512; else @@ -150,7 +276,7 @@ static int mod_init(void) cde.cdb_func.remove = lcache_htable_remove; cde.cdb_func.add = lcache_htable_add; cde.cdb_func.sub = lcache_htable_sub; - + cde.cdb_func.capability = CACHEDB_CAP_BINARY_VALUE; if(cache_clean_period <= 0 ) @@ -216,7 +342,7 @@ void localcache_clean(unsigned int ticks,void *param) { if((me1->expires > 0) && (me1->expires < get_ticks())) { - LM_DBG("deleted entry attr= [%.*s]\n", + LM_DBG("deleted entry attr= [%.*s]\n", me1->attr.len, me1->attr.s); if(me2) diff --git a/modules/cachedb_local/cachedb_local.h b/modules/cachedb_local/cachedb_local.h index fbf97760e2d..16bf2fd4970 100644 --- a/modules/cachedb_local/cachedb_local.h +++ b/modules/cachedb_local/cachedb_local.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -35,6 +35,7 @@ extern lcache_t* cache_htable; extern int cache_htable_size; +extern int local_exec_threshold; typedef struct { struct cachedb_id *id; diff --git a/modules/cachedb_local/doc/cachedb_local_admin.xml b/modules/cachedb_local/doc/cachedb_local_admin.xml index d751a7f9a90..4ff717ca505 100644 --- a/modules/cachedb_local/doc/cachedb_local_admin.xml +++ b/modules/cachedb_local/doc/cachedb_local_admin.xml @@ -56,6 +56,25 @@ ... modparam("cachedb_local", "cache_table_size", 10) +... + + +
+
+ <varname>exec_threshold</varname> (int) + + The maximum number of microseconds that a local cache query can last. + Anything above the threshold will trigger a warning message to the log + + + Default value is 0 ( unlimited - no warnings ). + + + + Set <varname>exec_threshold</varname> parameter + +... +modparam("cachedb_local", "exec_threshold", 100000) ... @@ -82,10 +101,55 @@ modparam("cachedb_local", "cache_clean_period", 1200)
Exported Functions - The module does not export functions to be used - in configuration script. + +
+ + <function moreinfo="none">cache_remove_chunk(glob)</function> + + + Remove all keys from local cache that match the glob pattern + + + This function can be used from all routes + + + <function>cache_remove_chunk</function> usage + + ... + cache_remove_chunk("myinfo_*"); + ... + + +
+
+
+ Exported MI Functions + +
+ <varname>cache_remove_chunk</varname> + + Removes all local cache entries that match the provided glob param. + + + Parameters : + + + glob - keys that match glob will be removed + + + + + MI FIFO Command Format: + + + :cache_remove_chunk:_reply_fifo_file_ + keyprefix* + _empty_line_ + +
+
diff --git a/modules/cachedb_local/hash.c b/modules/cachedb_local/hash.c index f4748933483..0ba03cf8f2f 100644 --- a/modules/cachedb_local/hash.c +++ b/modules/cachedb_local/hash.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -100,6 +100,7 @@ int lcache_htable_insert(cachedb_con *con,str* attr, str* value, int expires) lcache_entry_t* me, *it; int hash_code; int size; + struct timeval start; size= sizeof(lcache_entry_t) + attr->len + value->len; @@ -111,6 +112,8 @@ int lcache_htable_insert(cachedb_con *con,str* attr, str* value, int expires) } memset(me, 0, size); + start_expire_timer(start,local_exec_threshold); + me->attr.s = (char*)me + (sizeof(lcache_entry_t)); memcpy(me->attr.s, attr->s, attr->len); me->attr.len = attr->len; @@ -134,6 +137,8 @@ int lcache_htable_insert(cachedb_con *con,str* attr, str* value, int expires) lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local insert",attr->s,attr->len,0); return 1; } @@ -143,10 +148,10 @@ void lcache_htable_remove_safe(str attr, lcache_entry_t** it_p) while(it) { - if(it->attr.len == attr.len && + if(it->attr.len == attr.len && (strncmp(it->attr.s, attr.s, attr.len) == 0)) { - + if(me) me->next = it->next; else @@ -165,6 +170,9 @@ void lcache_htable_remove_safe(str attr, lcache_entry_t** it_p) int lcache_htable_remove(cachedb_con *con,str* attr) { int hash_code; + struct timeval start; + + start_expire_timer(start,local_exec_threshold); hash_code= core_hash( attr, 0, cache_htable_size); lock_get(&cache_htable[hash_code].lock); @@ -173,10 +181,13 @@ int lcache_htable_remove(cachedb_con *con,str* attr) lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local remove",attr->s,attr->len,0); + return 0; } -int lcache_htable_add(cachedb_con *con,str *attr,int val,int expires,int *new_val) +int lcache_htable_add(cachedb_con *con,str *attr,int val,int expires,int *new_val) { int hash_code; lcache_entry_t *it=NULL,*it_prev=NULL; @@ -184,13 +195,16 @@ int lcache_htable_add(cachedb_con *con,str *attr,int val,int expires,int *new_va char *new_value; int new_len; str ins_val; + struct timeval start; + + start_expire_timer(start,local_exec_threshold); hash_code = core_hash(attr,0,cache_htable_size); lock_get(&cache_htable[hash_code].lock); it = cache_htable[hash_code].entries; while (it) { - if (it->attr.len == attr->len && + if (it->attr.len == attr->len && memcmp(it->attr.s,attr->s,attr->len) == 0) { if (it->expires !=0 && it->expires < get_ticks()) { /* found an expired entry -> delete it */ @@ -198,18 +212,23 @@ int lcache_htable_add(cachedb_con *con,str *attr,int val,int expires,int *new_va it_prev->next = it->next; else cache_htable[hash_code].entries = it->next; - + shm_free(it); lock_release(&cache_htable[hash_code].lock); ins_val.s = sint2str(val,&ins_val.len); if (lcache_htable_insert(con,attr,&ins_val,expires) < 0) { LM_ERR("failed to insert value\n"); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local add",attr->s,attr->len,0); return -1; } if (new_val) *new_val = val; + + stop_expire_timer(start,local_exec_threshold, + "cachedb_local add",attr->s,attr->len,0); return 0; } @@ -217,15 +236,20 @@ int lcache_htable_add(cachedb_con *con,str *attr,int val,int expires,int *new_va if (str2sint(&it->value,&old_value) < 0) { LM_ERR("not an integer\n"); lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local add",attr->s,attr->len,0); return -1; } old_value+=val; + expires = it->expires; new_value = sint2str(old_value,&new_len); it = shm_realloc(it,sizeof(lcache_entry_t) + attr->len +new_len); if (it == NULL) { LM_ERR("failed to realloc struct\n"); lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local add",attr->s,attr->len,0); return -1; } @@ -233,19 +257,18 @@ int lcache_htable_add(cachedb_con *con,str *attr,int val,int expires,int *new_va it_prev->next = it; else cache_htable[hash_code].entries = it; - + it->attr.s = (char*)(it + 1); it->value.s =(char *)(it + 1) + attr->len; - + it->expires = expires; + memcpy(it->value.s,new_value,new_len); it->value.len = new_len; - if( expires != 0) { - LM_DBG("key %.*s will expire in %d s\n",attr->len,attr->s,expires); - it->expires = get_ticks() + expires; - } lock_release(&cache_htable[hash_code].lock); if (new_val) *new_val = old_value; + stop_expire_timer(start,local_exec_threshold, + "cachedb_local add",attr->s,attr->len,0); return 0; } @@ -254,20 +277,24 @@ int lcache_htable_add(cachedb_con *con,str *attr,int val,int expires,int *new_va } lock_release(&cache_htable[hash_code].lock); - + /* not found */ ins_val.s = sint2str(val,&ins_val.len); if (lcache_htable_insert(con,attr,&ins_val,expires) < 0) { LM_ERR("failed to insert value\n"); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local add",attr->s,attr->len,0); return -1; } if (new_val) *new_val = val; + stop_expire_timer(start,local_exec_threshold, + "cachedb_local add",attr->s,attr->len,0); return 0; } -int lcache_htable_sub(cachedb_con *con,str *attr,int val,int expires,int *new_val) +int lcache_htable_sub(cachedb_con *con,str *attr,int val,int expires,int *new_val) { return lcache_htable_add(con,attr,-val,expires,new_val); } @@ -283,6 +310,9 @@ int lcache_htable_fetch(cachedb_con *con,str* attr, str* res) int hash_code; lcache_entry_t* it = NULL, *it_aux = NULL; char* value; + struct timeval start; + + start_expire_timer(start,local_exec_threshold); hash_code= core_hash( attr, 0, cache_htable_size); lock_get(&cache_htable[hash_code].lock); @@ -291,7 +321,7 @@ int lcache_htable_fetch(cachedb_con *con,str* attr, str* res) while(it) { - if(it->attr.len == attr->len && + if(it->attr.len == attr->len && (strncmp(it->attr.s, attr->s, attr->len) == 0)) { if( it->expires != 0 && it->expires < get_ticks()) @@ -301,10 +331,12 @@ int lcache_htable_fetch(cachedb_con *con,str* attr, str* res) it_aux->next = it->next; else cache_htable[hash_code].entries = it->next; - + shm_free(it); lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local fetch",attr->s,attr->len,0); return -2; } value = (char*)pkg_malloc(it->value.len); @@ -312,20 +344,26 @@ int lcache_htable_fetch(cachedb_con *con,str* attr, str* res) { LM_ERR("no more memory\n"); lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local fetch",attr->s,attr->len,0); return -1; } memcpy(value, it->value.s, it->value.len); res->len = it->value.len; res->s = value; lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local fetch",attr->s,attr->len,0); return 1; } it_aux = it; it = it->next; } - + lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local fetch",attr->s,attr->len,0); return -2; } @@ -334,6 +372,9 @@ int lcache_htable_fetch_counter(cachedb_con* con,str* attr,int *val) int hash_code; lcache_entry_t* it = NULL, *it_aux = NULL; int ret; + struct timeval start; + + start_expire_timer(start,local_exec_threshold); hash_code= core_hash( attr, 0, cache_htable_size); lock_get(&cache_htable[hash_code].lock); @@ -342,7 +383,7 @@ int lcache_htable_fetch_counter(cachedb_con* con,str* attr,int *val) while(it) { - if(it->attr.len == attr->len && + if(it->attr.len == attr->len && (strncmp(it->attr.s, attr->s, attr->len) == 0)) { if( it->expires != 0 && it->expires < get_ticks()) @@ -352,27 +393,35 @@ int lcache_htable_fetch_counter(cachedb_con* con,str* attr,int *val) it_aux->next = it->next; else cache_htable[hash_code].entries = it->next; - + shm_free(it); lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local fetch_counter",attr->s,attr->len,0); return -2; } if (str2sint(&it->value,&ret) != 0) { LM_ERR("Not a counter key\n"); lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local fetch_counter",attr->s,attr->len,0); return -3; } if (val) *val = ret; lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local fetch_counter",attr->s,attr->len,0); return 1; } it_aux = it; it = it->next; } - + lock_release(&cache_htable[hash_code].lock); + stop_expire_timer(start,local_exec_threshold, + "cachedb_local fetch_counter",attr->s,attr->len,0); return -2; } diff --git a/modules/cachedb_local/hash.h b/modules/cachedb_local/hash.h index 3ab81e2fc91..78ad4523f0c 100644 --- a/modules/cachedb_local/hash.h +++ b/modules/cachedb_local/hash.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/cachedb_memcached/README b/modules/cachedb_memcached/README index 3d37fa3b487..0fd8f0f5601 100644 --- a/modules/cachedb_memcached/README +++ b/modules/cachedb_memcached/README @@ -16,8 +16,7 @@ Vladut-Stefan Paiu Copyright © 2009 Andrei Dragus Revision History - Revision $Revision: 5901 $ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -35,12 +34,14 @@ Vladut-Stefan Paiu 1.5. Exported Parameters 1.5.1. cachedb_url (string) - 1.5.2. Exported Functions + 1.5.2. exec_threshold (int) + 1.5.3. Exported Functions List of Examples 1.1. Set cachedb_url parameter 1.2. Use memcached servers + 1.3. Set exec_threshold parameter Chapter 1. Admin Guide @@ -118,7 +119,20 @@ cache_fetch("memcached:y","key",$avp(10)); cache_remove("memcached:group1","key"); ... -1.5.2. Exported Functions +1.5.2. exec_threshold (int) + + The maximum number of microseconds that a local cache query can + last. Anything above the threshold will trigger a warning + message to the log + + Default value is “0 ( unlimited - no warnings )”. + + Example 1.3. Set exec_threshold parameter +... +modparam("cachedb_memcached", "exec_threshold", 100000) +... + +1.5.3. Exported Functions The module does not export functions to be used in configuration script. diff --git a/modules/cachedb_memcached/cachedb_memcached.c b/modules/cachedb_memcached/cachedb_memcached.c index b0ecfb21beb..4b8551b2ff3 100644 --- a/modules/cachedb_memcached/cachedb_memcached.c +++ b/modules/cachedb_memcached/cachedb_memcached.c @@ -44,6 +44,7 @@ static str cache_mod_name = str_init("memcached"); struct cachedb_url *memcached_script_urls = NULL; +static int memcache_exec_threshold=0; int mc_set_connection(unsigned int type, void *val) { @@ -71,14 +72,17 @@ mem_server * servers; /** module parameters */ static param_export_t params[]={ {"cachedb_url", STR_PARAM|USE_FUNC_PARAM, (void*)&mc_set_connection }, + {"exec_threshold", INT_PARAM, &memcache_exec_threshold }, {0,0,0} }; /** module exports */ struct module_exports exports= { "cachedb_memcached", /* module name */ + MOD_TYPE_CACHEDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -96,12 +100,17 @@ int wrap_memcached_insert(cachedb_con *con,str* attr, str* value,int expires) { memcached_return rc; memcached_con *connection; + struct timeval start; + start_expire_timer(start,memcache_exec_threshold); connection = (memcached_con *)con->data; rc = memcached_set(connection->memc,attr->s, attr->len , value->s, value->len, (time_t)expires, (uint32_t)0); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached insert",attr->s,attr->len,0); + if( rc != MEMCACHED_SUCCESS) { LM_ERR("Failed to insert: %s\n",memcached_strerror(connection->memc,rc)); @@ -115,11 +124,16 @@ int wrap_memcached_remove(cachedb_con *connection,str* attr) { memcached_return rc; memcached_con *con; + struct timeval start; + start_expire_timer(start,memcache_exec_threshold); con = (memcached_con *)connection->data; rc = memcached_delete(con->memc,attr->s,attr->len,0); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached remove",attr->s,attr->len,0); + if( rc != MEMCACHED_SUCCESS && rc != MEMCACHED_NOTFOUND) { LM_ERR("Failed to remove: %s\n",memcached_strerror(con->memc,rc)); @@ -138,9 +152,11 @@ int wrap_memcached_get(cachedb_con *connection,str* attr, str* res) char * err; char * value; memcached_con *con; - + struct timeval start; + + start_expire_timer(start,memcache_exec_threshold); con = (memcached_con *)connection->data; - + ret = memcached_get(con->memc,attr->s, attr->len, &ret_len,&fl,&rc); @@ -150,12 +166,16 @@ int wrap_memcached_get(cachedb_con *connection,str* attr, str* res) { res->s = NULL; res->len = 0; + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached get",attr->s,attr->len,0); return -2; } else { err = (char*)memcached_strerror(con->memc,rc); LM_ERR("Failed to get: %s\n",err ); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached get",attr->s,attr->len,0); return -1; } } @@ -164,6 +184,8 @@ int wrap_memcached_get(cachedb_con *connection,str* attr, str* res) if( value == NULL) { LM_ERR("Memory allocation"); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached get",attr->s,attr->len,0); return -1; } @@ -173,52 +195,8 @@ int wrap_memcached_get(cachedb_con *connection,str* attr, str* res) free(ret); - return 0; -} - -int wrap_memcached_get_counter(cachedb_con *connection,str* attr, int* res) -{ - memcached_return rc; - char * ret; - size_t ret_len; - uint32_t fl; - char * err; - memcached_con *con; - str counter; - int int_counter; - - con = (memcached_con *)connection->data; - - ret = memcached_get(con->memc,attr->s, attr->len, - &ret_len,&fl,&rc); - - if(ret == NULL) - { - if(rc == MEMCACHED_NOTFOUND) - { - return -2; - } - else - { - err = (char*)memcached_strerror(con->memc,rc); - LM_ERR("Failed to get: %s\n",err ); - return -1; - } - } - - counter.s = ret; - counter.len = ret_len; - - if (str2sint(&counter,&int_counter) < 0) { - LM_ERR("Not a counter\n"); - free(ret); - return -3; - } - - if (res) - *res = int_counter; - - free(ret); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached get",attr->s,attr->len,0); return 0; } @@ -230,7 +208,9 @@ int wrap_memcached_add(cachedb_con *connection,str* attr,int val, memcached_con *con; uint64_t res; str ins_val; + struct timeval start; + start_expire_timer(start,memcache_exec_threshold); con = (memcached_con *)connection->data; rc = memcached_increment(con->memc,attr->s,attr->len,val,&res); @@ -240,14 +220,20 @@ int wrap_memcached_add(cachedb_con *connection,str* attr,int val, ins_val.s = sint2str(val,&ins_val.len); if (wrap_memcached_insert(connection,attr,&ins_val,expires) < 0) { LM_ERR("failed to insert value\n"); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached add",attr->s,attr->len,0); return -1; } if (new_val) *new_val = val; + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached add",attr->s,attr->len,0); return 0; } else { LM_ERR("Failed to add: %s\n",memcached_strerror(con->memc,rc)); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached add",attr->s,attr->len,0); return -1; } } @@ -255,6 +241,8 @@ int wrap_memcached_add(cachedb_con *connection,str* attr,int val, if (new_val) *new_val = (int)res; + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached add",attr->s,attr->len,0); return 0; } @@ -266,7 +254,9 @@ int wrap_memcached_sub(cachedb_con *connection,str* attr,int val, memcached_con *con; uint64_t res; str ins_val; + struct timeval start; + start_expire_timer(start,memcache_exec_threshold); con = (memcached_con *)connection->data; rc = memcached_decrement(con->memc,attr->s,attr->len,val,&res); @@ -276,14 +266,20 @@ int wrap_memcached_sub(cachedb_con *connection,str* attr,int val, ins_val.s = sint2str(val,&ins_val.len); if (wrap_memcached_insert(connection,attr,&ins_val,expires) < 0) { LM_ERR("failed to insert value\n"); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached sub",attr->s,attr->len,0); return -1; } if (new_val) *new_val = val; + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached sub",attr->s,attr->len,0); return 0; } else { LM_ERR("Failed to sub: %s\n",memcached_strerror(con->memc,rc)); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached sub",attr->s,attr->len,0); return -1; } } @@ -291,6 +287,62 @@ int wrap_memcached_sub(cachedb_con *connection,str* attr,int val, if (new_val) *new_val = (int)res; + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached sub",attr->s,attr->len,0); + + return 0; +} + +int wrap_memcached_get_counter(cachedb_con *connection,str* attr, int* res) +{ + memcached_return rc; + char * ret; + size_t ret_len; + uint32_t fl; + char * err; + memcached_con *con; + struct timeval start; + str rpl; + + start_expire_timer(start,memcache_exec_threshold); + con = (memcached_con *)connection->data; + + ret = memcached_get(con->memc,attr->s, attr->len, + &ret_len,&fl,&rc); + + if(ret == NULL) + { + if(rc == MEMCACHED_NOTFOUND) + { + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached counter fetch",attr->s,attr->len,0); + return -2; + } + else + { + err = (char*)memcached_strerror(con->memc,rc); + LM_ERR("Failed to get: %s\n",err ); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached counter fetch",attr->s,attr->len,0); + return -1; + } + } + + rpl.len = (int)ret_len; + rpl.s = ret; + + if (str2sint(&rpl,res) < 0) { + LM_ERR("Failed to convert %.*s to int\n",(int)ret_len,ret); + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached counter fetch",attr->s,attr->len,0); + free(ret); + return -1; + + } + + stop_expire_timer(start,memcache_exec_threshold, + "cachedb_memcached counter fetch",attr->s,attr->len,0); + free(ret); return 0; } @@ -371,7 +423,7 @@ void memcached_free_connection(cachedb_pool_con *con) if (!con) return; c = (memcached_con *)con; - + memcached_free(c->memc); } @@ -402,7 +454,7 @@ static int mod_init(void) cde.cdb_func.sub = wrap_memcached_sub; cde.cdb_func.capability = CACHEDB_CAP_BINARY_VALUE; - + if (register_cachedb(&cde) < 0) { LM_ERR("failed to initialize cachedb_memcached\n"); return -1; diff --git a/modules/cachedb_memcached/doc/cachedb_memcached_admin.xml b/modules/cachedb_memcached/doc/cachedb_memcached_admin.xml index 5295ce69517..fde87ea2e2f 100644 --- a/modules/cachedb_memcached/doc/cachedb_memcached_admin.xml +++ b/modules/cachedb_memcached/doc/cachedb_memcached_admin.xml @@ -159,6 +159,25 @@ cache_remove("memcached:group1","key");
+
+ <varname>exec_threshold</varname> (int) + + The maximum number of microseconds that a local cache query can last. + Anything above the threshold will trigger a warning message to the log + + + Default value is 0 ( unlimited - no warnings ). + + + + Set <varname>exec_threshold</varname> parameter + +... +modparam("cachedb_memcached", "exec_threshold", 100000) +... + + +
Exported Functions diff --git a/modules/cachedb_mongodb/Makefile b/modules/cachedb_mongodb/Makefile index ea75693f022..99c4903d54b 100644 --- a/modules/cachedb_mongodb/Makefile +++ b/modules/cachedb_mongodb/Makefile @@ -9,7 +9,22 @@ include ../../Makefile.defs auto_gen= NAME=cachedb_mongodb.so -DEFS+=-I$(LOCALBASE)/include -LIBS=-L$(LOCALBASE)/lib -lmongoc -ljson +ifeq ($(CROSS_COMPILE),) +JSON_BUILDER = $(shell \ + if pkg-config --exists json; then \ + echo 'pkg-config json'; \ + fi) +endif + +ifeq ($(JSON_BUILDER),) + DEFS += -I$(LOCALBASE)/include + LIBS += -L$(LOCALBASE)/lib -ljson +else + DEFS += $(shell $(JSON_BUILDER) --cflags) + LIBS += $(shell $(JSON_BUILDER) --libs) +endif + +DEFS += -I$(LOCALBASE)/include +LIBS += -L$(LOCALBASE)/lib -lmongoc include ../../Makefile.modules diff --git a/modules/cachedb_mongodb/README b/modules/cachedb_mongodb/README index 0b917f0b7f9..b209f704520 100644 --- a/modules/cachedb_mongodb/README +++ b/modules/cachedb_mongodb/README @@ -29,6 +29,7 @@ Vladut-Stefan Paiu 1.5.2. op_timeout (int) 1.5.3. slave_ok (int) 1.5.4. write_concern (string) + 1.5.5. exec_threshold (int) 1.6. Exported Functions 1.7. Raw Query Syntax @@ -40,8 +41,9 @@ Vladut-Stefan Paiu 1.3. Set op_timeout parameter 1.4. Set slave_ok parameter 1.5. Set write_concern parameter - 1.6. Mongo Raw Query Syntax - 1.7. Mongo Raw Query Examples + 1.6. Set exec_threshold parameter + 1.7. Mongo Raw Query Syntax + 1.8. Mongo Raw Query Examples Chapter 1. Admin Guide @@ -87,7 +89,8 @@ Chapter 1. Admin Guide http://oss.metaparadigm.com/json-c/ * mongo-c-driver The mongo C driver can be downloaded from - https://github.com/mongodb/mongo-c-driver + https://github.com/mongodb/mongo-c-driver Note : Please use + the 0.6 version of the driver 1.5. Exported Parameters @@ -148,6 +151,19 @@ modparam("cachedb_mongodb","write_concern","{ \"getLastError\": 1, "j" : "true" }") ... +1.5.5. exec_threshold (int) + + The maximum number of microseconds that a mongodb query can + last. Anything above the threshold will trigger a warning + message to the log + + Default value is “0 ( unlimited - no warnings )”. + + Example 1.6. Set exec_threshold parameter +... +modparam("cachedb_mongodb", "exec_threshold", 100000) +... + 1.6. Exported Functions The module does not export functions to be used in @@ -164,7 +180,7 @@ modparam("cachedb_mongodb","write_concern","{ \"getLastError\": 1, "j" : The syntax looks like the following : - Example 1.6. Mongo Raw Query Syntax + Example 1.7. Mongo Raw Query Syntax ... cache_raw_query("mongodb","{ \"op\" : \"desiredOP\", \"ns\" : \"db.colle ction\", \"query\": {\"_id\" : $rU} }","$avp(mongo_result)"); @@ -200,7 +216,7 @@ ction\", \"query\": {\"_id\" : $rU} }","$avp(mongo_result)"); Here are a couple examples of running some mongoDB queries : - Example 1.7. Mongo Raw Query Examples + Example 1.8. Mongo Raw Query Examples ... /* find documents where my_key has the value 345, and return just the en try1 and entry2 values from the matching documents */ diff --git a/modules/cachedb_mongodb/cachedb_mongodb.c b/modules/cachedb_mongodb/cachedb_mongodb.c index e30e563c9c4..e2c56b31347 100644 --- a/modules/cachedb_mongodb/cachedb_mongodb.c +++ b/modules/cachedb_mongodb/cachedb_mongodb.c @@ -53,6 +53,7 @@ int mongo_slave_ok=0; /* not ok to send read requests to secondaries */ str mongo_write_concern_str = {0,0}; bson mongo_write_concern_b; mongo_write_concern mwc; +int mongo_exec_threshold=0; int set_connection(unsigned int type, void *val) { @@ -64,6 +65,7 @@ static param_export_t params[]={ { "op_timeout", INT_PARAM, &mongo_op_timeout}, { "slave_ok", INT_PARAM, &mongo_slave_ok}, { "write_concern", STR_PARAM, &mongo_write_concern_str }, + { "exec_treshold", INT_PARAM, &mongo_exec_threshold }, {0,0,0} }; @@ -71,8 +73,10 @@ static param_export_t params[]={ /** module exports */ struct module_exports exports= { "cachedb_mongodb", /* module name */ + MOD_TYPE_CACHEDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -94,6 +98,7 @@ static int mod_init(void) cachedb_engine cde; LM_NOTICE("initializing module cachedb_mongodb ...\n"); + memset(&cde,0,sizeof(cachedb_engine)); cde.name = cache_mod_name; @@ -106,8 +111,13 @@ static int mod_init(void) cde.cdb_func.add = mongo_con_add; cde.cdb_func.sub = mongo_con_sub; cde.cdb_func.raw_query = mongo_con_raw_query; + cde.cdb_func.db_query_trans = mongo_db_query_trans; + cde.cdb_func.db_free_trans = mongo_db_free_result_trans; + cde.cdb_func.db_insert_trans = mongo_db_insert_trans; + cde.cdb_func.db_delete_trans = mongo_db_delete_trans; + cde.cdb_func.db_update_trans = mongo_db_update_trans; - cde.cdb_func.capability = 0; + cde.cdb_func.capability = 0; if (mongo_write_concern_str.s != NULL) { /* TODO - try manually building the getlasterror bson */ diff --git a/modules/cachedb_mongodb/cachedb_mongodb_dbase.c b/modules/cachedb_mongodb/cachedb_mongodb_dbase.c index 3b4c343e642..40139aa6b02 100644 --- a/modules/cachedb_mongodb/cachedb_mongodb_dbase.c +++ b/modules/cachedb_mongodb/cachedb_mongodb_dbase.c @@ -36,6 +36,10 @@ extern mongo_write_concern mwc; extern str mongo_write_concern_str; extern str mongo_write_concern_b; extern int mongo_slave_ok; +extern int mongo_exec_threshold; + +#define HEX_OID_SIZE 25 +char *hex_oid_id = NULL; mongo_con* mongo_new_connection(struct cachedb_id* id) { @@ -52,7 +56,7 @@ mongo_con* mongo_new_connection(struct cachedb_id* id) LM_ERR("null cachedb_id\n"); return 0; } - + if (id->flags & CACHEDB_ID_MULTIPLE_HOSTS) { /* we are connecting to a replica set */ replset_name.s = id->database; @@ -70,14 +74,14 @@ mongo_con* mongo_new_connection(struct cachedb_id* id) if (!p) { LM_ERR("Malformed mongo database\n"); return 0; - } + } database.len = p-database.s; collection.s = p+1; collection.len = id->database+strlen(id->database) - collection.s; - con = pkg_malloc(sizeof(mongo_con)+database.len+collection.len+ + con = pkg_malloc(sizeof(mongo_con)+database.len+collection.len+ replset_name.len+3); if (con == NULL) { LM_ERR("no more pkg \n"); @@ -177,7 +181,7 @@ mongo_con* mongo_new_connection(struct cachedb_id* id) memcpy(con->database,database.s,database.len); con->collection = con->database + database.len + 1; memcpy(con->collection,collection.s,collection.len); - + if (mongo_set_op_timeout(&MONGO_CON(con),mongo_op_timeout) != MONGO_OK) LM_WARN("Failed to set timeout of %d millis\n",mongo_op_timeout); else @@ -224,7 +228,7 @@ void mongo_free_connection(cachedb_pool_con *con) { } -void mongo_con_destroy(cachedb_con *con) +void mongo_con_destroy(cachedb_con *con) { LM_DBG("in mongo_destroy\n"); cachedb_do_close(con,mongo_free_connection); @@ -238,15 +242,17 @@ int mongo_con_get(cachedb_con *connection,str *attr,str *val) const char *rez; int rez_len,i; mongo *conn = &MONGO_CDB_CON(connection); - char hex_oid[25]; + char hex_oid[HEX_OID_SIZE]; + struct timeval start; LM_DBG("Get operation on namespace %s\n",MONGO_NAMESPACE(connection)); + start_expire_timer(start,mongo_exec_threshold); bson_init(&new_b); if (bson_append_string_n(&new_b,"_id",attr->s,attr->len) != BSON_OK) { LM_ERR("Failed to append _id \n"); bson_destroy(&new_b); - return -1; + goto error; } bson_finish(&new_b); @@ -254,7 +260,7 @@ int mongo_con_get(cachedb_con *connection,str *attr,str *val) m_cursor = mongo_find(conn,MONGO_NAMESPACE(connection), &new_b,0,0,0,mongo_slave_ok); if (m_cursor == NULL) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -264,7 +270,7 @@ int mongo_con_get(cachedb_con *connection,str *attr,str *val) mongo_cmd_get_last_error(conn,MONGO_DATABASE(connection),&err_b); bson_iterator_init(&it,&err_b); while( bson_iterator_next(&it)) { - LM_DBG("Fetched key %s\n",bson_iterator_key(&it)); + LM_DBG("Fetched key %s\n",bson_iterator_key(&it)); switch( bson_iterator_type( &it ) ) { case BSON_DOUBLE: LM_DBG("(double) %e\n",bson_iterator_double(&it)); @@ -282,12 +288,12 @@ int mongo_con_get(cachedb_con *connection,str *attr,str *val) default: LM_DBG("(unknown type %d)\n",bson_iterator_type(&it)); break; - + } bson_destroy(&new_b); } - return -1; + goto error; } break; } @@ -305,18 +311,20 @@ int mongo_con_get(cachedb_con *connection,str *attr,str *val) LM_ERR("Failed to convert %d to str\n", bson_iterator_int(&it)); mongo_cursor_destroy(m_cursor); - return -1; + goto error; } - + val->s = pkg_malloc(rez_len); if (val->s == NULL) { LM_ERR("No more pkg malloc\n"); mongo_cursor_destroy(m_cursor); - return -1; - } + goto error; + } memcpy(val->s,rez,rez_len); val->len = rez_len; mongo_cursor_destroy(m_cursor); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo get",attr->s,attr->len,0); return 0; break; @@ -325,7 +333,7 @@ int mongo_con_get(cachedb_con *connection,str *attr,str *val) if (rez == NULL) { LM_ERR("Got null str for mongo\n"); mongo_cursor_destroy(m_cursor); - return -1; + goto error; } rez_len=strlen(rez); val->s = pkg_malloc(rez_len); @@ -333,13 +341,15 @@ int mongo_con_get(cachedb_con *connection,str *attr,str *val) if (val->s == NULL) { LM_ERR("No more pkg malloc\n"); mongo_cursor_destroy(m_cursor); - return -1; - } + goto error; + } memcpy(val->s,rez,rez_len); val->len = rez_len; mongo_cursor_destroy(m_cursor); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo get",attr->s,attr->len,0); return 0; - + break; default: LM_DBG("(unknown type %d)\n",bson_iterator_type(&it)); @@ -349,36 +359,44 @@ int mongo_con_get(cachedb_con *connection,str *attr,str *val) LM_DBG("No suitable response found\n"); mongo_cursor_destroy(m_cursor); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo get",attr->s,attr->len,0); return -2; +error: + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo get",attr->s,attr->len,0); + return -1; } int mongo_con_set(cachedb_con *connection,str *attr,str *val,int expires) { bson new_b; int i; + struct timeval start; mongo *conn = &MONGO_CDB_CON(connection); LM_DBG("Set operation on namespace %s\n",MONGO_NAMESPACE(connection)); - + start_expire_timer(start,mongo_exec_threshold); + bson_init(&new_b); if (bson_append_string_n(&new_b,"_id",attr->s,attr->len) != BSON_OK) { LM_ERR("Failed to append _id \n"); bson_destroy(&new_b); - return -1; + goto error; } if (bson_append_string_n(&new_b,"opensips",val->s,val->len) != BSON_OK) { LM_ERR("Failed to append _id \n"); bson_destroy(&new_b); - return -1; + goto error; } bson_finish(&new_b); - + for (i=0;i<2;i++) { if (mongo_insert(conn,MONGO_NAMESPACE(connection), &new_b,NULL) != BSON_OK) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -387,35 +405,43 @@ int mongo_con_set(cachedb_con *connection,str *attr,str *val,int expires) LM_ERR("Failed to do insert. Con err = %d\n", conn->err); bson_destroy(&new_b); - return -1; + goto error; } - } + } + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo set",attr->s,attr->len,0); bson_destroy(&new_b); return 0; +error: + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo set",attr->s,attr->len,0); + return -1; } int mongo_con_remove(cachedb_con *connection,str *attr) { bson new_b; int i; + struct timeval start; mongo *conn = &MONGO_CDB_CON(connection); LM_DBG("Remove operation on namespace %s\n",MONGO_NAMESPACE(connection)); - + start_expire_timer(start,mongo_exec_threshold); + bson_init(&new_b); if (bson_append_string_n(&new_b,"_id",attr->s,attr->len) != BSON_OK) { LM_ERR("Failed to append _id \n"); bson_destroy(&new_b); - return -1; + goto error; } bson_finish(&new_b); - + for (i=0;i<2;i++) { if (mongo_remove(conn,MONGO_NAMESPACE(connection), &new_b,NULL) != BSON_OK) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -424,21 +450,27 @@ int mongo_con_remove(cachedb_con *connection,str *attr) LM_ERR("Failed to do insert. Con err = %d\n", conn->err); bson_destroy(&new_b); - return -1; - } + goto error; + } } + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo remove",attr->s,attr->len,0); bson_destroy(&new_b); return 0; +error: + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo remove",attr->s,attr->len,0); + return -1; } -void dbg_bson_print_raw( const char *data , int depth ) +void dbg_bson_print_raw( const char *data , int depth ) { bson_iterator i; const char *key; int temp; bson_timestamp_t ts; - char oidhex[25]; + char oidhex[HEX_OID_SIZE]; bson scope; bson_iterator_from_buffer( &i, data ); @@ -577,14 +609,18 @@ int mongo_raw_find(cachedb_con *connection,bson *raw_query,cdb_raw_entry ***repl m_cursor = mongo_find(conn,ns?ns:MONGO_NAMESPACE(connection), &op_b,have_fields?&fields_b:0,0,0,mongo_slave_ok); if (m_cursor == NULL) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); continue; } LM_ERR("Failed to run query. Err = %d, %d , %d \n",conn->err,conn->errcode,conn->lasterrcode); - mongo_cmd_get_last_error(conn,MONGO_DATABASE(connection),&err_b); + ret = mongo_cmd_get_last_error(conn,MONGO_DATABASE(connection),&err_b); + if (ret == MONGO_OK) { + LM_ERR("We had error - can't tell what it was - we're really bogus - probably mongos down\n"); + return -1; + } bson_iterator_init(&i,&err_b); while( bson_iterator_next(&i)) { LM_ERR("Fetched ERR key [%s]. Val = ",bson_iterator_key(&i)); @@ -678,7 +714,7 @@ int mongo_raw_count(cachedb_con *connection,bson *raw_query,cdb_raw_entry ***rep result = (int)mongo_count(conn,ns?db:MONGO_DATABASE(connection), ns?coll:MONGO_COLLECTION(connection),&op_b); if (result == MONGO_ERROR) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -784,7 +820,7 @@ int mongo_raw_update(cachedb_con *connection,bson *raw_query) ret = mongo_update(conn,ns?ns:MONGO_NAMESPACE(connection), have_match?&match_b:0,&op_b,0,0); if (ret == MONGO_ERROR) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -866,7 +902,7 @@ int mongo_raw_insert(cachedb_con *connection,bson *raw_query) ret = mongo_insert(conn,ns?ns:MONGO_NAMESPACE(connection), &op_b,0); if (ret == MONGO_ERROR) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -950,7 +986,7 @@ int mongo_raw_remove(cachedb_con *connection,bson *raw_query) ret = mongo_remove(conn,ns?ns:MONGO_NAMESPACE(connection), &op_b,0); if (ret == MONGO_ERROR) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -993,15 +1029,17 @@ int mongo_con_raw_query(cachedb_con *connection,str *attr,cdb_raw_entry ***reply bson new_b; int ret; bson_iterator i; + struct timeval start; const char *op=NULL; LM_DBG("Get operation on namespace %s\n",MONGO_NAMESPACE(connection)); + start_expire_timer(start,mongo_exec_threshold); if (attr->len > raw_query_buf_len) { raw_query_buf = pkg_realloc(raw_query_buf,attr->len+1); if (!raw_query_buf) { LM_ERR("No more pkg\n"); - return -1; + goto error; } memcpy(raw_query_buf,attr->s,attr->len); @@ -1017,19 +1055,19 @@ int mongo_con_raw_query(cachedb_con *connection,str *attr,cdb_raw_entry ***reply if (ret < 0) { LM_ERR("Failed to convert [%.*s] to BSON\n",attr->len,attr->s); - return -1; + goto error; } if (bson_find(&i,&new_b,"op") == BSON_EOO) { LM_ERR("No \"op\" specified \n"); bson_destroy(&new_b); - return -1; + goto error; } if (bson_iterator_type( &i ) != BSON_STRING) { LM_ERR("The op must be a string \n"); bson_destroy(&new_b); - return -1; + goto error; } op = bson_iterator_string( &i ); @@ -1047,11 +1085,17 @@ int mongo_con_raw_query(cachedb_con *connection,str *attr,cdb_raw_entry ***reply } else { LM_ERR("Unsupported op type [%s] \n",op); bson_destroy(&new_b); - return -1; + goto error; } + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo raw",attr->s,attr->len,0); bson_destroy(&new_b); return ret; +error: + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo raw",attr->s,attr->len,0); + return -1; } static char counter_q_buf[256]; @@ -1059,10 +1103,13 @@ int mongo_con_add(cachedb_con *connection,str *attr,int val,int expires,int *new { bson cmd,err_b,out; int j,ret; + struct timeval start; mongo *conn = &MONGO_CDB_CON(connection); bson_iterator it,it2; const char *curr_key,*inner_key; + start_expire_timer(start,mongo_exec_threshold); + bson_init( &cmd ); bson_append_string(&cmd,"findAndModify",MONGO_COLLECTION(connection)); @@ -1084,7 +1131,7 @@ int mongo_con_add(cachedb_con *connection,str *attr,int val,int expires,int *new ret = mongo_run_command(conn,MONGO_DATABASE(connection), &cmd,&out); if (ret != MONGO_OK) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -1112,6 +1159,8 @@ int mongo_con_add(cachedb_con *connection,str *attr,int val,int expires,int *new } } bson_destroy(&cmd); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo add",attr->s,attr->len,0); return -1; } break; @@ -1120,6 +1169,8 @@ int mongo_con_add(cachedb_con *connection,str *attr,int val,int expires,int *new if (!new_val) { bson_destroy(&out); bson_destroy(&cmd); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo add",attr->s,attr->len,0); return 0; } @@ -1140,6 +1191,8 @@ int mongo_con_add(cachedb_con *connection,str *attr,int val,int expires,int *new *new_val = bson_iterator_int(&it2) + val; bson_destroy(&out); bson_destroy(&cmd); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo add",attr->s,attr->len,0); return 0; } } @@ -1149,6 +1202,8 @@ int mongo_con_add(cachedb_con *connection,str *attr,int val,int expires,int *new err: bson_destroy(&out); bson_destroy(&cmd); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo add",attr->s,attr->len,0); return -1; } @@ -1164,15 +1219,19 @@ int mongo_con_get_counter(cachedb_con *connection,str *attr,int *val) mongo_cursor *m_cursor; bson_iterator it; int i; + struct timeval start; mongo *conn = &MONGO_CDB_CON(connection); - char hex_oid[25]; + char hex_oid[HEX_OID_SIZE]; LM_DBG("Get counter operation on namespace %s\n",MONGO_NAMESPACE(connection)); + start_expire_timer(start,mongo_exec_threshold); bson_init(&new_b); if (bson_append_string_n(&new_b,"_id",attr->s,attr->len) != BSON_OK) { LM_ERR("Failed to append _id \n"); bson_destroy(&new_b); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo get_counter",attr->s,attr->len,0); return -1; } bson_finish(&new_b); @@ -1181,7 +1240,7 @@ int mongo_con_get_counter(cachedb_con *connection,str *attr,int *val) m_cursor = mongo_find(conn,MONGO_NAMESPACE(connection), &new_b,0,0,0,mongo_slave_ok); if (m_cursor == NULL) { - if (mongo_check_connection(conn) == MONGO_ERROR && + if (mongo_check_connection(conn) == MONGO_ERROR && mongo_reconnect(conn) == MONGO_OK && mongo_check_connection(conn) == MONGO_OK) { LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); @@ -1191,7 +1250,7 @@ int mongo_con_get_counter(cachedb_con *connection,str *attr,int *val) mongo_cmd_get_last_error(conn,MONGO_DATABASE(connection),&err_b); bson_iterator_init(&it,&err_b); while( bson_iterator_next(&it)) { - LM_DBG("Fetched key %s\n",bson_iterator_key(&it)); + LM_DBG("Fetched key %s\n",bson_iterator_key(&it)); switch( bson_iterator_type( &it ) ) { case BSON_DOUBLE: LM_DBG("(double) %e\n",bson_iterator_double(&it)); @@ -1209,11 +1268,12 @@ int mongo_con_get_counter(cachedb_con *connection,str *attr,int *val) default: LM_DBG("(unknown type %d)\n",bson_iterator_type(&it)); break; - - } - bson_destroy(&new_b); + } } + bson_destroy(&new_b); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo get_counter",attr->s,attr->len,0); return -1; } break; @@ -1231,6 +1291,8 @@ int mongo_con_get_counter(cachedb_con *connection,str *attr,int *val) *val = bson_iterator_int(&it); mongo_cursor_destroy(m_cursor); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo get_counter",attr->s,attr->len,0); return 0; break; @@ -1242,5 +1304,587 @@ int mongo_con_get_counter(cachedb_con *connection,str *attr,int *val) LM_DBG("No suitable response found\n"); mongo_cursor_destroy(m_cursor); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo get_counter",attr->s,attr->len,0); return -2; } + +#define MONGO_DB_KEY_TRANS(key,val,index,op,query)\ + do { \ + if (VAL_NULL(val+index) == 0) { \ + memcpy(key_buff,key[index]->s,key[index]->len); \ + key_buff[key[index]->len]=0; \ + if (op != NULL && strcmp(op[index],OP_EQ)) { \ + bson_append_start_object(&query,key_buff);\ + if (strcmp(op[index],OP_LT) == 0) \ + memcpy(key_buff,"$lt",4); \ + else if (strcmp(op[index],OP_GT) == 0) \ + memcpy(key_buff,"$gt",4); \ + else if (strcmp(op[index],OP_LEQ) == 0) \ + memcpy(key_buff,"$lte",5); \ + else if (strcmp(op[index],OP_GEQ) == 0) \ + memcpy(key_buff,"$gte",5); \ + else if (strcmp(op[index],OP_NEQ) == 0) \ + memcpy(key_buff,"$ne",4); \ + } \ + switch VAL_TYPE(val+index) { \ + case DB_INT: \ + bson_append_int(&query,key_buff,VAL_INT(val+index)); \ + break; \ + case DB_STRING: \ + if (appendOID && key[index]->len == 3 && strncmp("_id", key[index]->s,key[index]->len) == 0) { \ + LM_DBG("we got it [%.*s]\n", key[index]->len, key[index]->s); \ + bson_oid_from_string(&_id, VAL_STRING(val+index)); \ + bson_append_oid(&query,key_buff,&_id); \ + appendOID = 0; \ + } else { \ + bson_append_string(&query,key_buff,VAL_STRING(val+index)); \ + } \ + break; \ + case DB_STR: \ + if (appendOID && key[index]->len == 3 && strncmp("_id", key[index]->s,key[index]->len) == 0) { \ + p = VAL_STR(val+index).s + VAL_STR(val+index).len; \ + _old_char = *p; \ + *p = '\0'; \ + bson_oid_from_string(&_id, VAL_STR(val+index).s); \ + *p = _old_char; \ + bson_append_oid(&query,key_buff,&_id); \ + appendOID = 0; \ + } else { \ + bson_append_string_n(&query,key_buff,VAL_STR(val+index).s, \ + VAL_STR(val+index).len); \ + } \ + break; \ + case DB_BLOB: \ + bson_append_string_n(&query,key_buff,VAL_BLOB(val+index).s, \ + VAL_BLOB(val+index).len); \ + break; \ + case DB_DOUBLE: \ + bson_append_double(&query,key_buff,VAL_DOUBLE(val+index)); \ + break; \ + case DB_BIGINT: \ + bson_append_long(&query,key_buff,VAL_BIGINT(val+index)); \ + break; \ + case DB_DATETIME: \ + bson_append_time_t(&query,key_buff,VAL_TIME(val+index)); \ + break; \ + case DB_BITMAP: \ + bson_append_int(&query,key_buff,VAL_BITMAP(val+index)); \ + break; \ + } \ + if (op != NULL && strcmp(op[index],OP_EQ)) { \ + bson_append_finish_object(&query); \ + } \ + } \ + } while (0) + +int mongo_db_query_trans(cachedb_con *con,const str *table,const db_key_t* _k, const db_op_t* _op,const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,const db_key_t _o, db_res_t** _r) +{ + char key_buff[32],namespace_buff[64],*p; + bson query; + bson fields; + bson err_b; + int i,j,row_no; + mongo *conn = &MONGO_CDB_CON(con); + mongo_cursor *m_cursor; + bson_iterator it; + char hex_oid[HEX_OID_SIZE]; + db_row_t *current; + db_val_t *cur_val; + static str dummy_string = {"", 0}; + struct timeval start; + char _old_char; + bson_oid_t _id; + int appendOID = 1; + + start_expire_timer(start,mongo_exec_threshold); + + if (!_c) { + LM_ERR("The module does not support 'select *' SQL queries \n"); + return -1; + } + + bson_init(&query); + if (_n) { + bson_append_start_object(&query, "$query"); + for (i=0;i<_n;i++) { + MONGO_DB_KEY_TRANS(_k,_v,i,_op,query); + } + bson_append_finish_object(&query); + } + + if (_o) { + if (!_n) { + bson_append_start_object(&query, "$query"); + bson_append_finish_object(&query); + } + memcpy(key_buff,_o->s,_o->len); + key_buff[_o->len]=0; + bson_append_start_object(&query, "$orderby"); + bson_append_int(&query,key_buff,1); + bson_append_finish_object(&query); + } + + bson_finish(&query); + + bson_init(&fields); + for (i=0;i<_nc;i++) { + memcpy(key_buff,_c[i]->s,_c[i]->len); + key_buff[_c[i]->len]=0; + bson_append_bool(&fields,key_buff,1); + } + + bson_finish(&fields); + + p=namespace_buff; + i = strlen(MONGO_DATABASE(con)); + memcpy(p,MONGO_DATABASE(con),i); + p +=i; + *p++ = '.'; + memcpy(p,table->s,table->len); + p+= table->len; + *p = 0; + + LM_DBG("Running raw mongo query on table %s\n",namespace_buff); + + for (i=0;i<2;i++) { + m_cursor = mongo_find(conn,namespace_buff, + &query,&fields,0,0,mongo_slave_ok); + if (m_cursor == NULL) { + if (mongo_check_connection(conn) == MONGO_ERROR && + mongo_reconnect(conn) == MONGO_OK && + mongo_check_connection(conn) == MONGO_OK) { + LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); + continue; + } + LM_ERR("Failed to run query. Err = %d, %d , %d \n",conn->err,conn->errcode,conn->lasterrcode); + mongo_cmd_get_last_error(conn,MONGO_DATABASE(con),&err_b); + bson_iterator_init(&it,&err_b); + while( bson_iterator_next(&it)) { + LM_DBG("Fetched key %s\n",bson_iterator_key(&it)); + switch( bson_iterator_type( &it ) ) { + case BSON_DOUBLE: + LM_DBG("(double) %e\n",bson_iterator_double(&it)); + break; + case BSON_INT: + LM_DBG("(int) %d\n",bson_iterator_int(&it)); + break; + case BSON_STRING: + LM_DBG("(string) \"%s\"\n",bson_iterator_string(&it)); + break; + case BSON_OID: + bson_oid_to_string(bson_iterator_oid(&it),hex_oid); + LM_DBG("(oid) \"%s\"\n",hex_oid); + break; + default: + LM_DBG("(unknown type %d)\n",bson_iterator_type(&it)); + break; + + } + } + goto error; + } + break; + } + + MONGO_CDB_CURSOR(con) = m_cursor; + + *_r = db_new_result(); + if (*_r == NULL) { + LM_ERR("Failed to init new result \n"); + goto error; + } + + RES_COL_N(*_r) = _nc; + + row_no = m_cursor->reply->fields.num; + LM_DBG("We have %d rows\n",row_no); + if (row_no == 0) { + LM_DBG("No rows returned from Mongo \n"); + bson_destroy(&fields); + bson_destroy(&query); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_select",table->s,table->len,0); + return 0; + } + + /* on first iteration we allocate the result + * we always assume the query returns exactly the number + * of 'columns' as were requested */ + if (db_allocate_columns(*_r,_nc) != 0) { + LM_ERR("Failed to allocate columns \n"); + goto error2; + } + + /* and we initialize the names as if all are there */ + for (j=0;j<_nc;j++) { + /* since we don't have schema, the types will be allocated + * when we fetch the actual rows */ + RES_NAMES(*_r)[j]->s = _c[j]->s; + RES_NAMES(*_r)[j]->len = _c[j]->len; + } + + if (db_allocate_rows(*_r,row_no) != 0) { + LM_ERR("No more private memory for rows \n"); + goto error2; + } + + RES_ROW_N(*_r) = row_no; + + hex_oid_id = pkg_malloc(sizeof(char) * row_no * HEX_OID_SIZE); + if (hex_oid_id==NULL) { + LM_ERR("oom\n"); + goto error2; + } + i=0; + while( mongo_cursor_next(m_cursor) == MONGO_OK ) { + bson_iterator_init(&it,mongo_cursor_bson(m_cursor)); + current = &(RES_ROWS(*_r)[i]); + ROW_N(current) = RES_COL_N(*_r); + for (j=0;j<_nc;j++) { + memcpy(key_buff,_c[j]->s,_c[j]->len); + key_buff[_c[j]->len]=0; + cur_val = &ROW_VALUES(current)[j]; + if (bson_find(&it,mongo_cursor_bson(m_cursor),key_buff) == BSON_EOO) { + memset(cur_val,0,sizeof(db_val_t)); + VAL_STRING(cur_val) = dummy_string.s; + VAL_STR(cur_val) = dummy_string; + VAL_BLOB(cur_val) = dummy_string; + /* we treat null values as DB string */ + VAL_TYPE(cur_val) = DB_STRING; + VAL_NULL(cur_val) = 1; + LM_DBG("Found empty [%.*s]\n", _c[j]->len, _c[j]->s); + } else { + switch( bson_iterator_type( &it ) ) { + case BSON_INT: + VAL_TYPE(cur_val) = DB_INT; + VAL_INT(cur_val) = bson_iterator_int(&it); + LM_DBG("Found int [%.*s]=[%d]\n", + _c[j]->len, _c[j]->s, VAL_INT(cur_val)); + break; + case BSON_DOUBLE: + VAL_TYPE(cur_val) = DB_DOUBLE; + VAL_DOUBLE(cur_val) = bson_iterator_double(&it); + LM_DBG("Found double [%.*s]=[%f]\n", + _c[j]->len, _c[j]->s, VAL_DOUBLE(cur_val)); + break; + case BSON_STRING: + VAL_TYPE(cur_val) = DB_STRING; + VAL_STRING(cur_val) = bson_iterator_string(&it); + LM_DBG("Found string [%.*s]=[%s]\n", + _c[j]->len, _c[j]->s, VAL_STRING(cur_val)); + break; + case BSON_LONG: + VAL_TYPE(cur_val) = DB_BIGINT; + VAL_BIGINT(cur_val) = bson_iterator_long(&it); + LM_DBG("Found long [%.*s]=[%lld]\n", + _c[j]->len, _c[j]->s, VAL_BIGINT(cur_val)); + break; + case BSON_DATE: + VAL_TYPE(cur_val) = DB_DATETIME; + VAL_TIME(cur_val) = bson_iterator_time_t(&it); + LM_DBG("Found time [%.*s]=[%d]\n", + _c[j]->len, _c[j]->s, (int)VAL_TIME(cur_val)); + break; + case BSON_OID: + bson_oid_to_string(bson_iterator_oid(&it), hex_oid); + p = &hex_oid_id[i*HEX_OID_SIZE]; + memcpy(p, hex_oid, HEX_OID_SIZE); + VAL_TYPE(cur_val) = DB_STRING; + VAL_STRING(cur_val) = p; + LM_DBG("Found oid [%.*s]=[%s]\n", + _c[j]->len, _c[j]->s, VAL_STRING(cur_val)); + break; + default: + LM_WARN("Unsupported type [%d] for [%.*s] - treating as NULL\n", + bson_iterator_type(&it), _c[j]->len, _c[j]->s); + memset(cur_val,0,sizeof(db_val_t)); + VAL_STRING(cur_val) = dummy_string.s; + VAL_STR(cur_val) = dummy_string; + VAL_BLOB(cur_val) = dummy_string; + /* we treat null values as DB string */ + VAL_TYPE(cur_val) = DB_STRING; + VAL_NULL(cur_val) = 1; + break; + } + } + } + i++; + } + + LM_DBG("Succesfully ran query\n"); + bson_destroy(&query); + bson_destroy(&fields); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_select",table->s,table->len,0); + return 0; + +error2: + db_free_result(*_r); + mongo_cursor_destroy(m_cursor); + *_r = NULL; + MONGO_CDB_CURSOR(con) = NULL; +error: + bson_destroy(&query); + bson_destroy(&fields); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_select",table->s,table->len,0); + return -1; +} + +int mongo_db_free_result_trans(cachedb_con* con, db_res_t* _r) +{ + if ((!con) || (!_r)) { + LM_ERR("invalid parameter value\n"); + return -1; + } + + LM_DBG("freeing mongo query result \n"); + + if (hex_oid_id) { + pkg_free(hex_oid_id); hex_oid_id = NULL; + } + + if (db_free_result(_r) < 0) { + LM_ERR("unable to free result structure\n"); + return -1; + } + + mongo_cursor_destroy(MONGO_CDB_CURSOR(con)); + MONGO_CDB_CURSOR(con) = NULL; + return 0; +} + +int mongo_db_insert_trans(cachedb_con *con,const str *table,const db_key_t* _k, const db_val_t* _v,const int _n) +{ + int i,j,ret; + bson query; + bson err_b; + char key_buff[32],namespace_buff[64],*p; + mongo *conn = &MONGO_CDB_CON(con); + bson_iterator it; + struct timeval start; + char _old_char; + bson_oid_t _id; + int appendOID = 1; + + start_expire_timer(start,mongo_exec_threshold); + + bson_init(&query); + for (i=0;i<_n;i++) { + if (VAL_NULL(_v+i) == 0) { + MONGO_DB_KEY_TRANS(_k,_v,i,((db_op_t*)0),query); + } + } + bson_finish(&query); + + p=namespace_buff; + i = strlen(MONGO_DATABASE(con)); + memcpy(p,MONGO_DATABASE(con),i); + p +=i; + *p++ = '.'; + memcpy(p,table->s,table->len); + p+= table->len; + *p = 0; + + LM_DBG("Running raw mongo insert on table %s\n",namespace_buff); + + for (j=0;j<2;j++) { + ret = mongo_insert(conn,namespace_buff,&query,0); + if (ret == MONGO_ERROR) { + if (mongo_check_connection(conn) == MONGO_ERROR && + mongo_reconnect(conn) == MONGO_OK && + mongo_check_connection(conn) == MONGO_OK) { + LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); + continue; + } + LM_ERR("Failed to run query. Err = %d, %d , %d \n",conn->err,conn->errcode,conn->lasterrcode); + mongo_cmd_get_last_error(conn,MONGO_DATABASE(con),&err_b); + bson_iterator_init(&it,&err_b); + while( bson_iterator_next(&it)) { + LM_ERR("Fetched ERR key [%s]. Val = ",bson_iterator_key(&it)); + switch( bson_iterator_type( &it ) ) { + case BSON_DOUBLE: + LM_DBG("(double) %e\n",bson_iterator_double(&it)); + break; + case BSON_INT: + LM_DBG("(int) %d\n",bson_iterator_int(&it)); + break; + case BSON_STRING: + LM_DBG("(string) \"%s\"\n",bson_iterator_string(&it)); + break; + default: + LM_DBG("(unknown type %d)\n",bson_iterator_type(&it)); + break; + } + } + + LM_ERR("Failed to run query. Err = %d, %d , %d \n",conn->err,conn->errcode,conn->lasterrcode); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_insert",table->s,table->len,0); + return -1; + } + break; + } + + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_insert",table->s,table->len,0); + return 0; +} + +int mongo_db_delete_trans(cachedb_con *con,const str *table,const db_key_t* _k,const db_op_t *_o, const db_val_t* _v,const int _n) +{ + int i,j,ret; + bson query; + bson err_b; + char key_buff[32],namespace_buff[64],*p; + mongo *conn = &MONGO_CDB_CON(con); + bson_iterator it; + struct timeval start; + char _old_char; + bson_oid_t _id; + int appendOID = 1; + + start_expire_timer(start,mongo_exec_threshold); + + bson_init(&query); + for (i=0;i<_n;i++) { + MONGO_DB_KEY_TRANS(_k,_v,i,_o,query); + } + bson_finish(&query); + + p=namespace_buff; + i = strlen(MONGO_DATABASE(con)); + memcpy(p,MONGO_DATABASE(con),i); + p +=i; + *p++ = '.'; + memcpy(p,table->s,table->len); + p+= table->len; + *p = 0; + + LM_DBG("Running raw mongo delete on table %s\n",namespace_buff); + + for (j=0;j<2;j++) { + ret = mongo_remove(conn,namespace_buff,&query,0); + if (ret == MONGO_ERROR) { + if (mongo_check_connection(conn) == MONGO_ERROR && + mongo_reconnect(conn) == MONGO_OK && + mongo_check_connection(conn) == MONGO_OK) { + LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); + continue; + } + LM_ERR("Failed to run query. Err = %d, %d , %d \n",conn->err,conn->errcode,conn->lasterrcode); + mongo_cmd_get_last_error(conn,MONGO_DATABASE(con),&err_b); + bson_iterator_init(&it,&err_b); + while( bson_iterator_next(&it)) { + LM_ERR("Fetched ERR key [%s]. Val = ",bson_iterator_key(&it)); + switch( bson_iterator_type( &it ) ) { + case BSON_DOUBLE: + LM_DBG("(double) %e\n",bson_iterator_double(&it)); + break; + case BSON_INT: + LM_DBG("(int) %d\n",bson_iterator_int(&it)); + break; + case BSON_STRING: + LM_DBG("(string) \"%s\"\n",bson_iterator_string(&it)); + break; + default: + LM_DBG("(unknown type %d)\n",bson_iterator_type(&it)); + break; + } + } + + LM_ERR("Failed to run query. Err = %d, %d , %d \n",conn->err,conn->errcode,conn->lasterrcode); + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_delete",table->s,table->len,0); + return -1; + } + break; + } + + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_delete",table->s,table->len,0); + return 0; +} + +int mongo_db_update_trans(cachedb_con *con,const str *table,const db_key_t* _k,const db_op_t *_o, const db_val_t* _v,const db_key_t* _uk, const db_val_t* _uv, const int _n,const int _un) +{ + int i,j,ret; + bson query,op_query; + bson err_b; + char key_buff[32],namespace_buff[64],*p; + mongo *conn = &MONGO_CDB_CON(con); + bson_iterator it; + struct timeval start; + char _old_char; + bson_oid_t _id; + int appendOID = 1; + + start_expire_timer(start,mongo_exec_threshold); + + bson_init(&query); + for (i=0;i<_n;i++) { + MONGO_DB_KEY_TRANS(_k,_v,i,_o,query); + } + bson_finish(&query); + + bson_init(&op_query); + bson_append_start_object(&op_query, "$set"); + for (i=0;i<_un;i++) { + MONGO_DB_KEY_TRANS(_uk,_uv,i,((db_op_t*)NULL),op_query); + } + bson_append_finish_object(&op_query); + bson_finish(&op_query); + + p=namespace_buff; + i = strlen(MONGO_DATABASE(con)); + memcpy(p,MONGO_DATABASE(con),i); + p +=i; + *p++ = '.'; + memcpy(p,table->s,table->len); + p+= table->len; + *p = '\0'; + + LM_DBG("Running raw mongo update on table %s\n",namespace_buff); + + for (j=0;j<2;j++) { + ret = mongo_update(conn,namespace_buff, + &query,&op_query,MONGO_UPDATE_UPSERT|MONGO_UPDATE_MULTI,0); + if (ret == MONGO_ERROR) { + if (mongo_check_connection(conn) == MONGO_ERROR && + mongo_reconnect(conn) == MONGO_OK && + mongo_check_connection(conn) == MONGO_OK) { + LM_INFO("Lost connection to Mongo but reconnected. Re-Trying\n"); + continue; + } + LM_ERR("Failed to run query. Err = %d, %d , %d \n",conn->err,conn->errcode,conn->lasterrcode); + mongo_cmd_get_last_error(conn,MONGO_DATABASE(con),&err_b); + bson_iterator_init(&it,&err_b); + while( bson_iterator_next(&it)) { + LM_ERR("Fetched ERR key [%s]. Val = ",bson_iterator_key(&it)); + switch( bson_iterator_type( &it ) ) { + case BSON_DOUBLE: + LM_DBG("(double) %e\n",bson_iterator_double(&it)); + break; + case BSON_INT: + LM_DBG("(int) %d\n",bson_iterator_int(&it)); + break; + case BSON_STRING: + LM_DBG("(string) \"%s\"\n",bson_iterator_string(&it)); + break; + default: + LM_DBG("(unknown type %d)\n",bson_iterator_type(&it)); + break; + } + } + return -1; + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_update",table->s,table->len,0); + } + break; + } + + stop_expire_timer(start,mongo_exec_threshold, + "cachedb_mongo sql_update",table->s,table->len,0); + return 0; +} diff --git a/modules/cachedb_mongodb/cachedb_mongodb_dbase.h b/modules/cachedb_mongodb/cachedb_mongodb_dbase.h index 9a4809c358a..712f3a2f79a 100644 --- a/modules/cachedb_mongodb/cachedb_mongodb_dbase.h +++ b/modules/cachedb_mongodb/cachedb_mongodb_dbase.h @@ -27,6 +27,7 @@ #define CACHEDBMONGO_DBASE_H #include "../../cachedb/cachedb.h" +#include "../../db/db.h" #define MONGO_HAVE_STDINT 1 @@ -52,10 +53,13 @@ typedef struct { /* actual connection to mongo */ mongo connection; + /* cursor result for the query */ + mongo_cursor *cursor; } mongo_con; #define MONGO_CON(mon_con) ((mon_con)->connection) #define MONGO_CDB_CON(cdb_con) (((mongo_con *)((cdb_con)->data))->connection) +#define MONGO_CDB_CURSOR(cdb_con) (((mongo_con *)((cdb_con)->data))->cursor) #define MONGO_NAMESPACE(cdb_con) (((mongo_con *)((cdb_con)->data))->id->database) #define MONGO_DATABASE(cdb_con) (((mongo_con *)((cdb_con)->data))->database) #define MONGO_COLLECTION(cdb_con) (((mongo_con *)((cdb_con)->data))->collection) @@ -69,6 +73,10 @@ int mongo_con_raw_query(cachedb_con *connection,str *attr,cdb_raw_entry ***val,i int mongo_con_add(cachedb_con *connection,str *attr,int val,int expires,int *new_val); int mongo_con_sub(cachedb_con *connection,str *attr,int val,int expires,int *new_val); int mongo_con_get_counter(cachedb_con *connection,str *attr,int *val); - +int mongo_db_query_trans(cachedb_con *con,const str *table,const db_key_t* _k, const db_op_t* _op,const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,const db_key_t _o, db_res_t** _r); +int mongo_db_free_result_trans(cachedb_con* con, db_res_t* _r); +int mongo_db_insert_trans(cachedb_con *con,const str *table,const db_key_t* _k, const db_val_t* _v,const int _n); +int mongo_db_delete_trans(cachedb_con *con,const str *table,const db_key_t* _k,const db_op_t *_o, const db_val_t* _v,const int _n); +int mongo_db_update_trans(cachedb_con *con,const str *table,const db_key_t* _k,const db_op_t *_o, const db_val_t* _v,const db_key_t* _uk, const db_val_t* _uv, const int _n,const int _un); #endif /* CACHEDBMONGO_DBASE_H */ diff --git a/modules/cachedb_mongodb/cachedb_mongodb_json.c b/modules/cachedb_mongodb/cachedb_mongodb_json.c index 397aa9def46..63a981d7cbd 100644 --- a/modules/cachedb_mongodb/cachedb_mongodb_json.c +++ b/modules/cachedb_mongodb/cachedb_mongodb_json.c @@ -30,7 +30,7 @@ int json_to_bson_append_element( bson *bb , const char *k , struct json_object *v ); -int json_to_bson_append_array( bson *bb , struct json_object *a ) +int json_to_bson_append_array( bson *bb , struct json_object *a ) { int i,al_len; char *al; @@ -78,7 +78,7 @@ int json_to_bson_append(bson *bb,struct json_object *o) return 0; } -int json_to_bson_append_element( bson *bb , const char *k , struct json_object *v ) +int json_to_bson_append_element( bson *bb , const char *k , struct json_object *v ) { if (v==NULL) { bson_append_null(bb,k); @@ -136,7 +136,7 @@ int json_to_bson_append_element( bson *bb , const char *k , struct json_object * LM_ERR("Failed to append start array\n"); return -1; } - + if (json_to_bson_append_array(bb,v) < 0) { LM_ERR("Failed to append array to bson\n"); return -1; @@ -157,7 +157,7 @@ int json_to_bson_append_element( bson *bb , const char *k , struct json_object * int json_to_bson(char *json,bson *bb) { - struct json_object *obj; + struct json_object *obj; LM_DBG("Trying to convert [%s]\n",json); @@ -191,12 +191,86 @@ int json_to_bson(char *json,bson *bb) return -1; } +void bson_to_json_generic(struct json_object *obj,bson_iterator *it,int type) +{ + const char *curr_key; + char *s; + int len; + struct json_object *obj2=NULL; + bson_iterator it2; + + while (bson_iterator_next(it)) { + curr_key=bson_iterator_key(it); + + switch( bson_iterator_type(it) ) { + case BSON_INT: + LM_DBG("Found key %s with type int\n",curr_key); + if (type == BSON_OBJECT) + json_object_object_add(obj,curr_key, + json_object_new_int(bson_iterator_int(it))); + else if (type == BSON_ARRAY) + json_object_array_add(obj,json_object_new_int(bson_iterator_int(it))); + break; + case BSON_LONG: + LM_DBG("Found key %s with type long\n",curr_key); + /* no intrinsic support in OpenSIPS for 64bit integers - + * converting to string */ + s = int2str(bson_iterator_long(it),&len); + s[len]=0; + if (type == BSON_OBJECT) + json_object_object_add(obj,curr_key,json_object_new_string(s)); + else if (type == BSON_ARRAY) + json_object_array_add(obj,json_object_new_string(s)); + break; + case BSON_DOUBLE: + /* no intrinsic support in OpenSIPS for floating point numbers + * converting to int */ + LM_DBG("Found key %s with type double\n",curr_key); + if (type == BSON_OBJECT) + json_object_object_add(obj,curr_key, + json_object_new_int((int)bson_iterator_double(it))); + else if (type == BSON_ARRAY) + json_object_array_add(obj,json_object_new_int((int)bson_iterator_double(it))); + break; + case BSON_STRING: + LM_DBG("Found key %s with type string\n",curr_key); + if (type == BSON_OBJECT) + json_object_object_add(obj,curr_key, + json_object_new_string(bson_iterator_string(it))); + else if (type == BSON_ARRAY) + json_object_array_add(obj,json_object_new_string(bson_iterator_string(it))); + break; + case BSON_BOOL: + LM_DBG("Found key %s with type bool\n",curr_key); + if (type == BSON_OBJECT) + json_object_object_add(obj,curr_key, + json_object_new_int((int)bson_iterator_bool(it))); + else if (type == BSON_ARRAY) + json_object_array_add(obj,json_object_new_int((int)bson_iterator_bool(it))); + break; + case BSON_ARRAY: + LM_DBG("Found key %s with type array\n",curr_key); + obj2 = json_object_new_array(); + bson_iterator_subiterator(it, &it2 ); + bson_to_json_generic(obj2,&it2,BSON_ARRAY); + json_object_object_add(obj,curr_key,obj2); + //json_object_put(obj2); + break; + default: + /* TODO - support embedded documents */ + LM_DBG("Unsupported type %d for key %s - skipping\n", + bson_iterator_type(it),curr_key); + break; + } + } +} + int mongo_cursor_to_json(mongo_cursor *m_cursor, cdb_raw_entry ***reply,int expected_kv_no,int *reply_no) { struct json_object *obj=NULL; bson_iterator it; - const char *curr_key,*p; + const char *p; int current_size=0,len; /* start with a single returned document */ @@ -229,30 +303,8 @@ int mongo_cursor_to_json(mongo_cursor *m_cursor, } obj = json_object_new_object(); - bson_iterator_init(&it,mongo_cursor_bson(m_cursor)); - while (bson_iterator_next(&it)) { - curr_key=bson_iterator_key(&it); - - switch( bson_iterator_type( &it ) ) { - case BSON_INT: - json_object_object_add(obj,curr_key, - json_object_new_int(bson_iterator_int(&it))); - break; - case BSON_DOUBLE: - json_object_object_add(obj,curr_key, - json_object_new_int((int)bson_iterator_double(&it))); - break; - case BSON_STRING: - json_object_object_add(obj,curr_key, - json_object_new_string(bson_iterator_string(&it))); - break; - default: - /* TODO - support embedded documents */ - LM_WARN("Unsupported type %d - skipping\n",bson_iterator_type(&it)); - break; - } - } + bson_to_json_generic(obj,&it,BSON_OBJECT); p = json_object_to_json_string(obj); if (!p) { @@ -279,7 +331,10 @@ int mongo_cursor_to_json(mongo_cursor *m_cursor, *reply_no = current_size; LM_DBG("Fetched %d results\n",current_size); - return 0; + if (current_size == 0) + return -2; + + return 1; error_cleanup: if (obj) diff --git a/modules/cachedb_mongodb/doc/cachedb_mongodb_admin.xml b/modules/cachedb_mongodb/doc/cachedb_mongodb_admin.xml index a3d597cf453..28af7271b78 100644 --- a/modules/cachedb_mongodb/doc/cachedb_mongodb_admin.xml +++ b/modules/cachedb_mongodb/doc/cachedb_mongodb_admin.xml @@ -124,6 +124,7 @@ The mongo C driver can be downloaded from https://github.com/mongodb/mongo-c-driver + Note : Please use the 0.6 version of the driver @@ -222,6 +223,25 @@ modparam("cachedb_mongodb","write_concern","{ \"getLastError\": 1, "j" : "true"
+
+ <varname>exec_threshold</varname> (int) + + The maximum number of microseconds that a mongodb query can last. + Anything above the threshold will trigger a warning message to the log + + + Default value is 0 ( unlimited - no warnings ). + + + + Set <varname>exec_threshold</varname> parameter + +... +modparam("cachedb_mongodb", "exec_threshold", 100000) +... + + +
diff --git a/modules/cachedb_redis/README b/modules/cachedb_redis/README index f67a7702606..1bf31bfb313 100644 --- a/modules/cachedb_redis/README +++ b/modules/cachedb_redis/README @@ -27,11 +27,13 @@ Vladut-Stefan Paiu 1.5.1. cachedb_url (string) 1.5.2. Exported Functions + 1.5.3. Raw Query Syntax List of Examples 1.1. Set cachedb_url parameter 1.2. Use Redis servers + 1.3. Redis Raw Query Examples Chapter 1. Admin Guide @@ -72,7 +74,10 @@ Chapter 1. Admin Guide The following libraries or applications must be installed before running OpenSIPS with this module loaded: * hiredis: - hiredis can be downloaded from: + On the latest Debian based distributions, hiredis can be + installed by running 'apt-get install libhiredis-dev' + Alternatively, if hiredis is not available on your OS + repos, hiredis can be downloaded from: https://github.com/antirez/hiredis . Download the archive, extract sources, run make,sudo make install. @@ -105,3 +110,41 @@ cache_remove("redis:cluster1","key"); The module does not export functions to be used in configuration script. + +1.5.3. Raw Query Syntax + + The cachedb_redis module allows to run RAW queries, thus taking + full advantage of the capabilities of the back-end. The query + syntax is the typical REDIS one. + + Here are a couple examples of running some Redis queries : + + Example 1.3. Redis Raw Query Examples +... + $var(my_hash) = "my_hash_name"; + $var(my_key) = "my_key_name"; + $var(my_value) = "my_key_value"; + cache_raw_query("redis","HSET $var(my_hash) $var(my_key) $var(my +_value)"); + cache_raw_query("redis","HGET $var(my_hash) $var(my_key)","$avp( +result)"); + xlog("We have fetched $avp(result) \n"); +... + $var(my_hash) = "my_hash_name"; + $var(my_key1) = "my_key1_name"; + $var(my_key2) = "my_key2_name"; + $var(my_value1) = "my_key1_value"; + $var(my_value2) = "my_key2_value"; + cache_raw_query("redis","HSET $var(my_hash) $var(my_key1) $var(m +y_value1)"); + cache_raw_query("redis","HSET $var(my_hash) $var(my_key2) $var(m +y_value2)"); + cache_raw_query("redis","HGETALL $var(my_hash)","$avp(result)"); + + $var(it) = 0; + while ($(avp(result_final)[$var(it)]) != NULL) { + xlog("Multiple key reply: - we have fetched $(avp(result +_final)[$var(it)]) \n"); + $var(it) = $var(it) + 1; + } +... diff --git a/modules/cachedb_redis/cachedb_redis.c b/modules/cachedb_redis/cachedb_redis.c index 173143b360d..a9fbd6a67ac 100644 --- a/modules/cachedb_redis/cachedb_redis.c +++ b/modules/cachedb_redis/cachedb_redis.c @@ -61,8 +61,10 @@ static param_export_t params[]={ /** module exports */ struct module_exports exports= { "cachedb_redis", /* module name */ + MOD_TYPE_CACHEDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -84,6 +86,7 @@ static int mod_init(void) cachedb_engine cde; LM_NOTICE("initializing module cachedb_redis ...\n"); + memset(&cde,0,sizeof(cachedb_engine)); cde.name = cache_mod_name; @@ -95,8 +98,9 @@ static int mod_init(void) cde.cdb_func.remove = redis_remove; cde.cdb_func.add = redis_add; cde.cdb_func.sub = redis_sub; + cde.cdb_func.raw_query = redis_raw_query; - cde.cdb_func.capability = 0; + cde.cdb_func.capability = 0; if (register_cachedb(&cde) < 0) { LM_ERR("failed to initialize cachedb_redis\n"); diff --git a/modules/cachedb_redis/cachedb_redis_dbase.c b/modules/cachedb_redis/cachedb_redis_dbase.c index d389d0c9883..bb89430189f 100644 --- a/modules/cachedb_redis/cachedb_redis_dbase.c +++ b/modules/cachedb_redis/cachedb_redis_dbase.c @@ -111,7 +111,7 @@ int redis_connect(redis_con *con) LM_DBG("AUTH [password] - %.*s\n",rpl->len,rpl->str); freeReplyObject(rpl); } - + rpl = redisCommand(ctx,"CLUSTER NODES"); if (rpl == NULL || rpl->type == REDIS_REPLY_ERROR) { /* single instace mode */ @@ -134,6 +134,7 @@ int redis_connect(redis_con *con) } else { /* cluster instance mode */ con->type |= REDIS_CLUSTER_INSTANCE; + con->slots_assigned = 0; LM_DBG("cluster instance mode\n"); if (build_cluster_nodes(con,rpl->str,rpl->len) < 0) { LM_ERR("failed to parse Redis cluster info\n"); @@ -143,11 +144,16 @@ int redis_connect(redis_con *con) freeReplyObject(rpl); redisFree(ctx); - for (it=con->nodes;it;it=it->next) + for (it=con->nodes;it;it=it->next) { + + if (it->end_slot > con->slots_assigned ) + con->slots_assigned = it->end_slot; + if (redis_connect_node(con,it) < 0) { LM_ERR("failed to init connection \n"); return -1; } + } return 0; } @@ -155,12 +161,12 @@ int redis_connect(redis_con *con) redis_con* redis_new_connection(struct cachedb_id* id) { redis_con *con; - + if (id == NULL) { LM_ERR("null cachedb_id\n"); return 0; } - + if (id->flags & CACHEDB_ID_MULTIPLE_HOSTS) { LM_ERR("multiple hosts are not supported for redis\n"); return 0; @@ -218,8 +224,8 @@ void redis_destroy(cachedb_con *con) { for (i=2;i;i--) { \ reply = redisCommand(node->context,fmt,##args); \ if (reply == NULL || reply->type == REDIS_REPLY_ERROR) { \ - LM_ERR("Redis operation failure - %.*s\n",\ - reply?reply->len:7,reply?reply->str:"FAILURE"); \ + LM_ERR("Redis operation failure - %p %.*s\n",\ + reply,reply?reply->len:7,reply?reply->str:"FAILURE"); \ if (reply) \ freeReplyObject(reply); \ if (node->context->err == REDIS_OK || redis_reconnect_node(con,node) < 0) { \ @@ -427,3 +433,224 @@ int redis_get_counter(cachedb_con *connection,str *attr,int *val) freeReplyObject(reply); return 0; } + +int redis_raw_query_handle_reply(redisReply *reply,cdb_raw_entry ***ret, + int expected_kv_no,int *reply_no) +{ + int current_size=0,len,i; + + /* start with a single returned document */ + *ret = pkg_malloc(1 * sizeof(cdb_raw_entry *)); + if (*ret == NULL) { + LM_ERR("No more PKG mem\n"); + goto error; + } + + **ret = pkg_malloc(expected_kv_no * sizeof(cdb_raw_entry)); + if (**ret == NULL) { + LM_ERR("No more pkg mem\n"); + goto error; + } + + switch (reply->type) { + case REDIS_REPLY_STRING: + (*ret)[current_size][0].val.s.s = pkg_malloc(reply->len); + if (! (*ret)[current_size][0].val.s.s ) { + LM_ERR("No more pkg \n"); + goto error; + } + + memcpy((*ret)[current_size][0].val.s.s,reply->str,reply->len); + (*ret)[current_size][0].val.s.len = reply->len; + (*ret)[current_size][0].type = CDB_STR; + + current_size++; + break; + case REDIS_REPLY_INTEGER: + (*ret)[current_size][0].val.n = reply->integer; + (*ret)[current_size][0].type = CDB_INT; + current_size++; + break; + case REDIS_REPLY_ARRAY: + for (i=0;ielements;i++) { + switch (reply->element[i]->type) { + case REDIS_REPLY_STRING: + case REDIS_REPLY_INTEGER: + if (current_size > 0) { + *ret = pkg_realloc(*ret,(current_size + 1) * sizeof(cdb_raw_entry *)); + if (*ret == NULL) { + LM_ERR("No more pkg\n"); + goto error; + } + (*ret)[current_size] = pkg_malloc(expected_kv_no * sizeof(cdb_raw_entry)); + if ((*ret)[current_size] == NULL) { + LM_ERR("No more pkg\n"); + goto error; + } + } + + + if (reply->element[i]->type == REDIS_REPLY_INTEGER) { + (*ret)[current_size][0].val.n = reply->element[i]->integer; + (*ret)[current_size][0].type = CDB_INT; + } else { + (*ret)[current_size][0].val.s.s = pkg_malloc(reply->element[i]->len); + if (! (*ret)[current_size][0].val.s.s ) { + LM_ERR("No more pkg \n"); + goto error; + } + + memcpy((*ret)[current_size][0].val.s.s,reply->element[i]->str,reply->element[i]->len); + (*ret)[current_size][0].val.s.len = reply->element[i]->len; + (*ret)[current_size][0].type = CDB_STR; + } + + current_size++; + break; + default: + LM_DBG("Unexpected data type %d found in array - skipping \n",reply->element[i]->type); + } + } + break; + } + + *reply_no = current_size; + freeReplyObject(reply); + return 1; + +error: + if (*ret) { + pkg_free(*ret); + for (len = 0;lens == NULL || query_key == NULL) + return -1; + + trim_len(len,p,*attr); + q = memchr(p,' ',len); + if (q == NULL) { + LM_ERR("Malformed Redis RAW query \n"); + return -1; + } + + query_key->s = q+1; + r = memchr(query_key->s,' ',len - (query_key->s - p)); + if (r == NULL) { + query_key->len = (p+len) - query_key->s; + } else { + query_key->len = r-query_key->s; + } + + return 0; +} + +int redis_raw_query_send(cachedb_con *connection,redisReply **reply,cdb_raw_entry ***rpl,int expected_kv_no,int *reply_no,str *attr, ...) +{ + redis_con *con; + cluster_node *node; + int i,end; + va_list ap; + str query_key; + + con = (redis_con *)connection->data; + if (redis_raw_query_extract_key(attr,&query_key) < 0) { + LM_ERR("Failed to extra Redis raw query key \n"); + return -1; + } + + node = get_redis_connection(con,&query_key); + if (node == NULL) { + LM_ERR("Bad cluster configuration\n"); + return -10; + } + + va_start(ap,attr); + end = attr->s[attr->len]; + attr->s[attr->len] = 0; + + for (i=2;i;i--) { + *reply = redisvCommand(node->context,attr->s,ap); + if (*reply == NULL || (*reply)->type == REDIS_REPLY_ERROR) { + LM_ERR("Redis operation failure - %.*s\n", + *reply?(*reply)->len:7,*reply?(*reply)->str:"FAILURE"); + if (*reply) + freeReplyObject(*reply); + if (node->context->err == REDIS_OK || redis_reconnect_node(con,node) < 0) { + i = 0; break; + } + } else break; + } + + va_end(ap); + attr->s[attr->len]=end; + + if (i==0) { + LM_ERR("giving up on query\n"); + return -1; + } + + return 0; +} + +int redis_raw_query(cachedb_con *connection,str *attr,cdb_raw_entry ***rpl,int expected_kv_no,int *reply_no) +{ + redisReply *reply; + + if (!attr || !connection) { + LM_ERR("null parameter\n"); + return -1; + } + + + if (redis_raw_query_send(connection,&reply,rpl,expected_kv_no,reply_no,attr) < 0) { + LM_ERR("Failed to send query to server \n"); + return -1; + } + + switch (reply->type) { + case REDIS_REPLY_ERROR: + LM_ERR("Error encountered when running Redis raw query [%.*s]\n", + attr->len,attr->s); + return -1; + case REDIS_REPLY_NIL: + LM_DBG("Redis raw query [%.*s] failed - no such key\n",attr->len,attr->s); + freeReplyObject(reply); + return -2; + case REDIS_REPLY_STATUS: + LM_DBG("Received a status of %.*s from Redis \n",reply->len,reply->str); + if (reply_no) + *reply_no = 0; + freeReplyObject(reply); + return 1; + default: + /* some data arrived - yay */ + + if (rpl == NULL) { + LM_DBG("Received reply type %d but script writer not interested in it \n",reply->type); + freeReplyObject(reply); + return 1; + } + return redis_raw_query_handle_reply(reply,rpl,expected_kv_no,reply_no); + } + + return 1; +} diff --git a/modules/cachedb_redis/cachedb_redis_dbase.h b/modules/cachedb_redis/cachedb_redis_dbase.h index 60dc37fad21..ea86ec727eb 100644 --- a/modules/cachedb_redis/cachedb_redis_dbase.h +++ b/modules/cachedb_redis/cachedb_redis_dbase.h @@ -47,6 +47,7 @@ typedef struct { struct cachedb_pool_con_t *next; int type; /* single node or cluster node */ + unsigned short slots_assigned; /* total slots for cluster */ cluster_node *nodes; /* one or more Redis nodes */ } redis_con; @@ -58,6 +59,7 @@ int redis_remove(cachedb_con *con,str *attr); int redis_add(cachedb_con *con,str *attr,int val,int expires,int *new_val); int redis_sub(cachedb_con *con,str *attr,int val,int expires,int *new_val); int redis_get_counter(cachedb_con *connection,str *attr,int *val); +int redis_raw_query(cachedb_con *connection,str *attr,cdb_raw_entry ***reply,int expected_kv_no,int *reply_no); #endif /* CACHEDBREDIS_DBASE_H */ diff --git a/modules/cachedb_redis/cachedb_redis_utils.c b/modules/cachedb_redis/cachedb_redis_utils.c index 6f965b1755d..500a3a46d54 100644 --- a/modules/cachedb_redis/cachedb_redis_utils.c +++ b/modules/cachedb_redis/cachedb_redis_utils.c @@ -29,6 +29,7 @@ #include "../../ut.h" #include "../../cachedb/cachedb.h" +#include #include #include #define is_valid(p,end) ((p) && (p)<(end)) @@ -68,7 +69,7 @@ static const uint16_t crc16tab[256]= { 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 }; -uint16_t crc16(const char *buf, int len) +uint16_t crc16(const char *buf, int len) { int counter; uint16_t crc = 0; @@ -77,9 +78,9 @@ uint16_t crc16(const char *buf, int len) return crc; } -unsigned int redisHash(str* key) +unsigned int redisHash(redis_con *con, str* key) { - return crc16(key->s,key->len) & 0x0FFF; + return crc16(key->s,key->len) & con->slots_assigned; } inline cluster_node *get_redis_connection(redis_con *con,str *key) @@ -90,7 +91,7 @@ inline cluster_node *get_redis_connection(redis_con *con,str *key) if (con->type & REDIS_SINGLE_INSTANCE) return con->nodes; else { - hash_slot = redisHash(key); + hash_slot = redisHash(con, key); for (it=con->nodes;it;it=it->next) { if (it->start_slot <= hash_slot && it->end_slot >= hash_slot) return it; @@ -99,7 +100,7 @@ inline cluster_node *get_redis_connection(redis_con *con,str *key) } } -void destroy_cluster_nodes(redis_con *con) +void destroy_cluster_nodes(redis_con *con) { cluster_node *new,*foo; @@ -114,110 +115,192 @@ void destroy_cluster_nodes(redis_con *con) } } +struct datavalues { + int count; + char **redisdata; +}; + +int chkmalloc1 (char *handle) { + if ( handle == NULL || handle == 0) { + LM_ERR("Error1 while parsing cluster redisdata \n"); + return -1; + } + return 1; +} +int chkmalloc2 (struct datavalues *handle) { + if ( handle == NULL || handle == 0) { + LM_ERR("Error2 while parsing cluster redisdata \n"); + return -1; + } + return 1; +} + +int chkmalloc3 (struct datavalues **handle) { + if ( handle == NULL || handle == 0) { + LM_ERR("Error3 while parsing cluster redisdata \n"); + return -1; + } + return 1; +} + +int chkmalloc4 (char **handle) { + if ( handle == NULL || handle == 0) { + LM_ERR("Error4 while parsing cluster redisdata \n"); + return -1; + } + return 1; +} + +int explode(char *line, const char *delimeters, struct datavalues **newret) { + + int counter = 0; + char *result = NULL; + char *data = NULL; + + data = pkg_malloc((strlen(line) * sizeof(char)) +1); + if (!chkmalloc1(data)) return 0; + strcpy(data,line); + + result = strtok(data, delimeters); + while (result != NULL ) { + newret[0]->redisdata[counter] = pkg_malloc((strlen(result) * sizeof(char) ) +1 ); + if (chkmalloc1(newret[0]->redisdata[counter])) { + strcpy(newret[0]->redisdata[counter],result); + counter++; + result = strtok(NULL, delimeters); + } else { return 0; } + } + newret[0]->count = counter-1; + + pkg_free(data); + + return 1; + +} + int build_cluster_nodes(redis_con *con,char *info,int size) { - char *p,*end,*aux,*aux2; - char *ip; - unsigned short port,start_slot,end_slot; - int err; + cluster_node *new; - - LM_DBG("info = [%.*s]\n",size,info); - - end = info+size; - p = info; - - while (is_valid(p,end)) - { - start_slot = end_slot = port = 0; - ip = NULL; - - /* skip ID */ - aux = memchr(p,' ',size); - if (!is_valid(aux,end)) - goto error; - - while (is_valid(aux,end) && (*aux) == ' ') aux++; - - size -= (aux-p); - p = aux; - - if (*aux == ':') { - /* no IP - my IP in CACHEDB_ID */ - ip = con->id->host; - port = con->id->port; - while (is_valid(aux,end) && (*aux) != ' ') aux++; - } else { - /* other node in cluster */ - p = memchr(aux,':',size); - if (!is_valid(p,end)) - goto error; - - *p = 0; - ip = aux; - size -= (p-aux); + const char *delimeters = "\n"; + int i = 0, j = 0; + int masters = 1, count = 0; + char *ip, *block = NULL; + unsigned short port,start_slot,end_slot; + + // Define **pointers for new structures + struct datavalues **newret1 = pkg_malloc(sizeof(struct datavalues *)); + if (!chkmalloc3(newret1)) goto error; + struct datavalues **newret2 = pkg_malloc(sizeof(struct datavalues *)); + if (!chkmalloc3(newret2)) goto error; + struct datavalues **newret3 = pkg_malloc(sizeof(struct datavalues *)); + if (!chkmalloc3(newret3)) goto error; + + // Allocate space for the structures + newret1[0] = pkg_malloc(sizeof(struct datavalues)); + if (!chkmalloc2(newret1[0])) goto error; + newret2[0] = pkg_malloc(sizeof(struct datavalues)); + if (!chkmalloc2(newret2[0])) goto error; + newret3[0] = pkg_malloc(sizeof(struct datavalues)); + if (!chkmalloc2(newret3[0])) goto error; + + // Allocate space for data item "redisdata" within the structures + newret1[0]->redisdata = pkg_malloc((strlen(info) * sizeof(char)) +1); + if (!chkmalloc4(newret1[0]->redisdata)) goto error; + newret2[0]->redisdata = pkg_malloc((strlen(info) * sizeof(char)) +1); + if (!chkmalloc4(newret2[0]->redisdata)) goto error; + newret3[0]->redisdata = pkg_malloc((strlen(info) * sizeof(char)) +1); + if (!chkmalloc4(newret3[0]->redisdata)) goto error; + + // Initialise the counter + newret1[0]->count = 0; + newret2[0]->count = 0; + newret3[0]->count = 0; + + + // Redis really only requires two connections ("myself,master" && one other master) || (at least two masters) + // but this will supply info for upto 1000 masters due to current Opensips design (hopefully representing the total hash slots) + // will always connect to myself,master + strstr(info,"myself,master")?(count = 999):(count = 1000); - aux = memchr(p+1,' ',size); - if (!is_valid(aux,end)) - goto error; + // Cluster data into Array + if (explode(info,delimeters,newret1)) { + for (i=0;i<=newret1[0]->count;i++) { + + if ((strstr(newret1[0]->redisdata[i],"master") && (masters <= count)) || strstr(newret1[0]->redisdata[i],"myself,master")) { + + start_slot = end_slot = port = 0; + ip = NULL; + masters++; + + // Break up the row + if (explode(newret1[0]->redisdata[i]," ",newret2)) { + for (j=0 ; j <= newret2[0]->count ; j++ ) { + + if (strstr(newret1[0]->redisdata[i],"myself") && strstr(newret2[0]->redisdata[j],"myself")) { + //myself no ip + ip = con->id->host; + port = con->id->port; + if (i==0) masters--; - port = str2s(p+1,aux-p-1,&err); - if (err) - goto error; - } + } else { + //Get the ip and port of other master + if (strstr(newret2[0]->redisdata[j],":") && (strlen(newret2[0]->redisdata[j]) > 5)) { - size -= (aux-p); - p=aux; - - p = memchr(p,'\n',size); - if (!is_valid(p,end)) - goto error; - - p++; - size -= (p-aux); - aux = p-2; - - while (*aux == ' ') aux--; - aux2 = aux; - while (*aux != '-') aux--; - end_slot = str2s(aux+1,aux2-aux,&err); - if (err) - goto error; - - aux2=aux; - while (*aux2 != ' ') aux2--; - start_slot=str2s(aux2+1,aux-aux2-1,&err); - if (err) - goto error; - - LM_DBG("ip port start end %s %hu %hu %hu\n",ip,port,start_slot,end_slot); - new = pkg_malloc(sizeof(cluster_node)); - if (!new) { - LM_ERR("no more pkg\n"); - goto error; - } - - memset(new,0,sizeof(cluster_node)); - - strcpy(new->ip,ip); - new->port = port; - new->start_slot = start_slot; - new->end_slot = end_slot; - - if (con->nodes == NULL) - con->nodes = new; - else { - new->next = con->nodes; - con->nodes = new; + if (explode(newret2[0]->redisdata[j],":",newret3)) { + ip = (char *)newret3[0]->redisdata[0]; + port = atoi(newret3[0]->redisdata[1]); + } else { block = ":parsing ip/port"; goto error;} + } + } + //Get slots + if (strstr(newret2[0]->redisdata[j],"-") && (strlen(newret2[0]->redisdata[j]) > 2)) { + if (explode(newret2[0]->redisdata[j],"-",newret3)) { + start_slot = atoi(newret3[0]->redisdata[0]); + end_slot = atoi(newret3[0]->redisdata[1]); + } else {block = ":parsing slots"; goto error;} + + } + } + + } else { block = "row to array"; goto error;} + + LM_DBG("ip port start end %s %hu %hu %hu\n",ip,port,start_slot,end_slot); + + if ( ip == NULL || !(port > 0) || (start_slot > end_slot) || !(end_slot > 0) ) {block = ":processing row"; goto error;} + + new = pkg_malloc(sizeof(cluster_node)); + if (!new) { + LM_ERR("no more pkg\n"); + goto error; + } + + memset(new,0,sizeof(cluster_node)); + + strcpy(new->ip,ip); + new->port = port; + new->start_slot = start_slot; + new->end_slot = end_slot; + + if (con->nodes == NULL) + con->nodes = new; + else { + new->next = con->nodes; + con->nodes = new; + } + } } - - } + + } else { block = ":initial"; goto error;} + + pkg_free(newret1); + pkg_free(newret2); + pkg_free(newret3); return 0; error: - LM_ERR("Error while parsing cluster nodes\n"); + LM_ERR("Error while parsing cluster nodes in %s\n",block); destroy_cluster_nodes(con); return -1; } - diff --git a/modules/cachedb_redis/doc/cachedb_redis_admin.xml b/modules/cachedb_redis/doc/cachedb_redis_admin.xml index 0fe9b41b378..9ff67bd342d 100644 --- a/modules/cachedb_redis/doc/cachedb_redis_admin.xml +++ b/modules/cachedb_redis/doc/cachedb_redis_admin.xml @@ -104,6 +104,10 @@ + On the latest Debian based distributions, hiredis can be installed + by running 'apt-get install libhiredis-dev' + + Alternatively, if hiredis is not available on your OS repos, hiredis can be downloaded from: https://github.com/antirez/hiredis . Download the archive, extract sources, run make,sudo make install. @@ -154,7 +158,47 @@ cache_remove("redis:cluster1","key"); in configuration script. +
+ Raw Query Syntax + + The cachedb_redis module allows to run RAW queries, thus taking full advantage of the capabilities of the back-end. + + The query syntax is the typical REDIS one. + + + + Here are a couple examples of running some Redis queries : + + Redis Raw Query Examples + +... + $var(my_hash) = "my_hash_name"; + $var(my_key) = "my_key_name"; + $var(my_value) = "my_key_value"; + cache_raw_query("redis","HSET $var(my_hash) $var(my_key) $var(my_value)"); + cache_raw_query("redis","HGET $var(my_hash) $var(my_key)","$avp(result)"); + xlog("We have fetched $avp(result) \n"); +... + $var(my_hash) = "my_hash_name"; + $var(my_key1) = "my_key1_name"; + $var(my_key2) = "my_key2_name"; + $var(my_value1) = "my_key1_value"; + $var(my_value2) = "my_key2_value"; + cache_raw_query("redis","HSET $var(my_hash) $var(my_key1) $var(my_value1)"); + cache_raw_query("redis","HSET $var(my_hash) $var(my_key2) $var(my_value2)"); + cache_raw_query("redis","HGETALL $var(my_hash)","$avp(result)"); + + $var(it) = 0; + while ($(avp(result_final)[$var(it)]) != NULL) { + xlog("Multiple key reply: - we have fetched $(avp(result_final)[$var(it)]) \n"); + $var(it) = $var(it) + 1; + } +... + + + +
diff --git a/modules/cachedb_sql/README b/modules/cachedb_sql/README index 71a4c96f1e7..155215fcb9c 100644 --- a/modules/cachedb_sql/README +++ b/modules/cachedb_sql/README @@ -25,7 +25,7 @@ Vladut-Stefan Paiu 1.5. Exported Parameters - 1.5.1. db_url (string) + 1.5.1. cachedb_url (string) 1.5.2. db_table (string) 1.5.3. key_column (string) 1.5.4. value_column (string) @@ -34,6 +34,8 @@ Vladut-Stefan Paiu 1.5.7. cache_clean_period (int) 1.5.8. Exported Functions + 2. Frequently Asked Questions + List of Examples 1.1. Set db_url parameter @@ -82,20 +84,32 @@ Chapter 1. Admin Guide 1.5. Exported Parameters -1.5.1. db_url (string) +1.5.1. cachedb_url (string) The url of the Database that OpenSIPS will connect to in order to use the from script cache_store,cache_fetch, etc operations. + The format to follow is : sql:[conn_id]-dburl + + The parameter can be set multiple times to create multiple + connections accessible from the OpenSIPS script. + Example 1.1. Set db_url parameter ... -modparam("cachedb_sql", "db_url","mysql://localhost/my_database"); +modparam("cachedb_sql", "cachedb_url", "sql:1st-mysql://root:vlad@localh +ost/opensips_sql") ... Example 1.2. Usage example ... -cache_store("sql","key","$ru value"); -cache_add("sql","counter",10); +modparam("cachedb_sql", "cachedb_url", "sql:1st-mysql://root:vlad@localh +ost/opensips_sql") +modparam("cachedb_sql", "cachedb_url", "sql:2nd-postgres://root:vlad@loc +alhost/opensips_pg") +... +... +cache_store("sql:1st-mysql","key","$ru value"); +cache_store("sql:2nd-postgres","counter","10"); ... 1.5.2. db_table (string) @@ -159,3 +173,12 @@ modparam("cachedb_sql", "cache_clean_period",10); The module does not export functions to be used in configuration script. + +Chapter 2. Frequently Asked Questions + + 2.1. + + What happend with the old “db_url” module parameter? + + It was replaced with the “cachedb_url” parameter. See the + documentation for the usage of the “cachedb_url” parameter. diff --git a/modules/cachedb_sql/cachedb_sql.c b/modules/cachedb_sql/cachedb_sql.c index afb76efc6c3..38ba3f31558 100644 --- a/modules/cachedb_sql/cachedb_sql.c +++ b/modules/cachedb_sql/cachedb_sql.c @@ -1,5 +1,7 @@ /* - * Copyright (C) 2011 OpenSIPS Solutions + * Copyright (C) 2013 Steve Frécinaux + * Be IP s.a. http://www.beip.be + * Copyright (C) 2013 OpenSIPS Solutions * * This file is part of opensips, a free SIP server. * @@ -20,7 +22,9 @@ * * history: * --------- - * 2013-01-xx created (vlad-paiu) + * 2013-01-xx created (Steve Frécinaux) + * 2013-01-xx improved implementation of cachedb (vlad-paiu) + * 2014-05-xx full rework of the connection management (vlad-paiu) */ @@ -35,8 +39,18 @@ #include "../../mem/mem.h" #include "../../mem/shm_mem.h" +typedef struct { + struct cachedb_id *id; + unsigned int ref; + struct cachedb_pool_con_t *next; + + db_con_t* cdb_db_handle; + db_func_t cdb_dbf; +} cachedbsql_con; + #define MAX_RAW_QUERY_SIZE 512 static str cache_mod_name = str_init("sql"); +struct cachedb_url *sql_script_urls = NULL; static char query_buf[MAX_RAW_QUERY_SIZE]; static str query_str; @@ -53,9 +67,8 @@ static void destroy(void); #define EXPIRES_COL "expires" #define EXPIRES_COL_LEN (sizeof(EXPIRES_COL) - 1) -#define CACHEDB_SQL_TABLE_VERSION 1 +#define CACHEDB_SQL_TABLE_VERSION 2 -static str db_url = {NULL, 0}; static str db_table = str_init("cachedb"); static str key_column = {KEY_COL, KEY_COL_LEN}; static str value_column = {VALUE_COL, VALUE_COL_LEN}; @@ -63,13 +76,13 @@ static str counter_column = {COUNTER_VALUE_COL, COUNTER_VALUE_COL_LEN}; static str expires_column = {EXPIRES_COL, EXPIRES_COL_LEN}; static int cache_clean_period = 60; -static db_con_t* cdb_db_handle = 0; -static db_func_t cdb_dbf; - - +int set_connection(unsigned int type, void *val) +{ + return cachedb_store_url(&sql_script_urls,(char *)val); +} static param_export_t params[] = { - {"db_url", STR_PARAM, &db_url.s }, + {"cachedb_url", STR_PARAM|USE_FUNC_PARAM, (void *)&set_connection }, {"db_table", STR_PARAM, &db_table.s }, {"key_column", STR_PARAM, &key_column.s }, {"value_column", STR_PARAM, &value_column.s }, @@ -82,8 +95,10 @@ static param_export_t params[] = { /** module exports */ struct module_exports exports = { "cachedb_sql", /* module name */ + MOD_TYPE_CACHEDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -96,29 +111,72 @@ struct module_exports exports = { child_init /* per-child init function */ }; -cachedb_pool_con* dbcache_new_connection(struct cachedb_id* id) +#define CACHEDBSQL_DB_DELIMITER '-' +cachedbsql_con* dbcache_new_connection(struct cachedb_id* id) { - cachedb_pool_con *con; + cachedbsql_con *con; + str db_url; + char *p,*end; + int group_name_len,scheme_len; if(id == NULL) { LM_ERR("null db_id\n"); return 0; } - if(id->flags != CACHEDB_ID_NO_URL) { + if((id->flags & (CACHEDB_ID_NO_URL | CACHEDB_ID_MULTIPLE_HOSTS)) != 0) { LM_ERR("bogus url for local cachedb\n"); return 0; } - con = pkg_malloc(sizeof(cachedb_pool_con)); + if (id->group_name == NULL) { + LM_ERR("No sql back-end info provided \n"); + return 0; + } + + group_name_len = strlen(id->group_name); + scheme_len = strlen(id->scheme); + db_url.s = id->initial_url + scheme_len + 1; + db_url.len = strlen(id->initial_url) - scheme_len - 1; + + for (p=id->group_name,end=p+group_name_len;pgroup_name) + 1; + db_url.len -= (p-id->group_name) + 1; + break; + } + } + + con = pkg_malloc(sizeof(cachedbsql_con)); if(con == NULL) { LM_ERR("no more pkg\n"); return 0; } + memset(con,0,sizeof(cachedbsql_con)); con->id = id; con->ref = 1; - con->next = NULL; + + if (db_bind_mod(&db_url, &con->cdb_dbf) < 0){ + LM_ERR("unable to bind to a database driver\n"); + pkg_free(con); + return 0; + } + + con->cdb_db_handle = con->cdb_dbf.init(&db_url); + if (con->cdb_db_handle == 0) { + LM_ERR("Failed to connect to the DB \n"); + pkg_free(con); + return 0; + } + + if(db_check_table_version(&con->cdb_dbf, con->cdb_db_handle, + &db_table, CACHEDB_SQL_TABLE_VERSION) < 0) { + LM_ERR("error during table version check.\n"); + con->cdb_dbf.close(con->cdb_db_handle); + pkg_free(con); + return 0; + } return con; } @@ -130,7 +188,13 @@ static cachedb_con* dbcache_init(str *url) void dbcache_free_connection(cachedb_pool_con *con) { - pkg_free(con); + cachedbsql_con *c; + if (!con) + return; + + c = (cachedbsql_con*)con; + c->cdb_dbf.close(c->cdb_db_handle); + pkg_free(c); } static void dbcache_destroy(cachedb_con *con) @@ -138,6 +202,9 @@ static void dbcache_destroy(cachedb_con *con) cachedb_do_close(con, dbcache_free_connection); } +#define CACHEDBSQL_CON(c) (((cachedbsql_con*)((c)->data))->cdb_db_handle) +#define CACHEDBSQL_FUNC(c) (((cachedbsql_con*)((c)->data))->cdb_dbf) + static int dbcache_set(cachedb_con *con, str* attr, str* value, int expires) { db_key_t keys[3]; @@ -164,12 +231,12 @@ static int dbcache_set(cachedb_con *con, str* attr, str* value, int expires) else vals[2].val.int_val = 0; - if (cdb_dbf.use_table(cdb_db_handle, &db_table) < 0) { + if (CACHEDBSQL_FUNC(con).use_table(CACHEDBSQL_CON(con), &db_table) < 0) { LM_ERR("sql use_table failed\n"); return -1; } - if (cdb_dbf.insert_update(cdb_db_handle, keys, vals, 3) < 0) { + if (CACHEDBSQL_FUNC(con).insert_update(CACHEDBSQL_CON(con), keys, vals, 3) < 0) { LM_ERR("inserting cache entry in db failed\n"); return -1; } @@ -193,19 +260,20 @@ static int dbcache_get(cachedb_con *con, str* attr, str* res) col = &value_column; - if (cdb_dbf.use_table(cdb_db_handle, &db_table) < 0) { + if (CACHEDBSQL_FUNC(con).use_table(CACHEDBSQL_CON(con), &db_table) < 0) { LM_ERR("sql use_table failed\n"); return -1; } - if(cdb_dbf.query(cdb_db_handle, &key, NULL, &val, &col, 1, 1, NULL, &db_res) < 0) { + if(CACHEDBSQL_FUNC(con).query(CACHEDBSQL_CON(con), &key, NULL, &val, + &col, 1, 1, NULL, &db_res) < 0) { LM_ERR("failed to query database\n"); return -1; } if (RES_ROW_N(db_res) <= 0 || RES_ROWS(db_res)[0].values[0].nul != 0) { LM_DBG("no value found for keyI\n"); - if (db_res != NULL && cdb_dbf.free_result(cdb_db_handle, db_res) < 0) + if (db_res != NULL && CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con),db_res) < 0) LM_DBG("failed to free result of query\n"); return -2; } @@ -217,7 +285,7 @@ static int dbcache_get(cachedb_con *con, str* attr, str* res) if (res->s == NULL) { LM_ERR("no more pkg\n"); - if (cdb_dbf.free_result(cdb_db_handle, db_res) < 0) + if (CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con), db_res) < 0) LM_ERR("failed to free result of query\n"); return -1; } @@ -230,7 +298,7 @@ static int dbcache_get(cachedb_con *con, str* attr, str* res) if (res->s == NULL) { LM_ERR("no more pkg\n"); - if (cdb_dbf.free_result(cdb_db_handle, db_res) < 0) + if (CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con), db_res) < 0) LM_DBG("failed to free result of query\n"); return -1; } @@ -242,7 +310,7 @@ static int dbcache_get(cachedb_con *con, str* attr, str* res) res->s = pkg_malloc(res->len + 1); if (res->s == NULL) { LM_ERR("no more pkg\n"); - if (cdb_dbf.free_result(cdb_db_handle, db_res) < 0) + if (CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con), db_res) < 0) LM_DBG("failed to free result of query\n"); return -1; } @@ -250,7 +318,7 @@ static int dbcache_get(cachedb_con *con, str* attr, str* res) break; default: LM_ERR("unknown type of DB user column\n"); - if (db_res != NULL && cdb_dbf.free_result(cdb_db_handle, db_res) < 0) + if (db_res != NULL && CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con), db_res) < 0) LM_DBG("failed to freeing result of query\n"); return -1; } @@ -270,12 +338,12 @@ static int dbcache_remove(cachedb_con *con, str* attr) val.val.str_val.s = attr->s; val.val.str_val.len = attr->len; - if (cdb_dbf.use_table(cdb_db_handle, &db_table) < 0) { + if (CACHEDBSQL_FUNC(con).use_table(CACHEDBSQL_CON(con), &db_table) < 0) { LM_ERR("sql use_table failed\n"); return -1; } - if (cdb_dbf.delete(cdb_db_handle, &key, 0, &val, 1) < 0) { + if (CACHEDBSQL_FUNC(con).delete(CACHEDBSQL_CON(con), &key, 0, &val, 1) < 0) { LM_ERR("deleting from database failed\n"); return -1; } @@ -293,7 +361,9 @@ static int dbcache_add(cachedb_con *con, str *attr, int val, int expires, int *n else expires = 0; - i = snprintf(query_buf, sizeof(query_buf), "insert into %.*s (%.*s, %.*s, %.*s) values ('%.*s', %d, %d) on duplicate key update %.*s=%.*s %c %d, %.*s=%d", + i = snprintf(query_buf, sizeof(query_buf), + "insert into %.*s (%.*s, %.*s, %.*s) values ('%.*s', %d, %d)" + "on duplicate key update %.*s=%.*s %c %d, %.*s=%d", db_table.len, db_table.s, key_column.len, key_column.s, counter_column.len, counter_column.s, @@ -314,13 +384,13 @@ static int dbcache_add(cachedb_con *con, str *attr, int val, int expires, int *n query_str.s = query_buf; query_str.len = i; - if(cdb_dbf.raw_query(cdb_db_handle, &query_str, &res) < 0) { + if(CACHEDBSQL_FUNC(con).raw_query(CACHEDBSQL_CON(con), &query_str, &res) < 0) { LM_ERR("raw_query failed\n"); return -1; } if(res != NULL) - cdb_dbf.free_result(cdb_db_handle, res); + CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con), res); /* Beware of the race conditions! */ if(new_val) { @@ -357,19 +427,19 @@ static int dbcache_fetch_counter(cachedb_con *con,str *attr,int *ret_val) col = &counter_column; - if (cdb_dbf.use_table(cdb_db_handle, &db_table) < 0) { + if (CACHEDBSQL_FUNC(con).use_table(CACHEDBSQL_CON(con), &db_table) < 0) { LM_ERR("sql use_table failed\n"); return -1; } - if(cdb_dbf.query(cdb_db_handle, &key, NULL, &val, &col, 1, 1, NULL, &db_res) < 0) { + if(CACHEDBSQL_FUNC(con).query(CACHEDBSQL_CON(con), &key, NULL, &val, &col, 1, 1, NULL, &db_res) < 0) { LM_ERR("failed to query database\n"); return -1; } if (RES_ROW_N(db_res) <= 0 || RES_ROWS(db_res)[0].values[0].nul != 0) { LM_DBG("no value found for keyI\n"); - if (db_res != NULL && cdb_dbf.free_result(cdb_db_handle, db_res) < 0) + if (db_res != NULL && CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con), db_res) < 0) LM_DBG("failed to free result of query\n"); return -2; } @@ -378,12 +448,12 @@ static int dbcache_fetch_counter(cachedb_con *con,str *attr,int *ret_val) case DB_INT: if (ret_val) *ret_val = RES_ROWS(db_res)[0].values[0].val.int_val; - if (cdb_dbf.free_result(cdb_db_handle, db_res) < 0) + if (CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con), db_res) < 0) LM_ERR("failed to freeing result of query\n"); break; default: LM_ERR("unknown type of DB user column\n"); - if (db_res != NULL && cdb_dbf.free_result(cdb_db_handle, db_res) < 0) + if (db_res != NULL && CACHEDBSQL_FUNC(con).free_result(CACHEDBSQL_CON(con), db_res) < 0) LM_ERR("failed to freeing result of query\n"); return -1; } @@ -393,6 +463,10 @@ static int dbcache_fetch_counter(cachedb_con *con,str *attr,int *ret_val) static void dbcache_clean(unsigned int ticks, void* param) { + cachedb_pool_con **lst; + cachedbsql_con *c; + int size=0,i; + db_key_t keys[2]; db_op_t ops[2]; db_val_t vals[2]; @@ -411,15 +485,23 @@ static void dbcache_clean(unsigned int ticks, void* param) vals[1].nul = 0; vals[1].val.int_val = (int)time(NULL); - if (cdb_dbf.use_table(cdb_db_handle, &db_table) < 0) { - LM_ERR("sql use_table failed\n"); - return; - } + lst = filter_pool_by_scheme(&cache_mod_name,&size); + for (i=0;icdb_dbf.use_table(c->cdb_db_handle, &db_table) < 0) { + LM_ERR("sql use_table failed\n"); + return; + } - if (cdb_dbf.delete(cdb_db_handle, keys, ops, vals, 2) < 0) { - LM_ERR("deleting from database failed\n"); - return; + if (c->cdb_dbf.delete(c->cdb_db_handle, keys, ops, vals, 2) < 0) { + LM_ERR("deleting from database failed\n"); + return; + } } + + if (lst) + pkg_free(lst); } /** @@ -428,27 +510,18 @@ static void dbcache_clean(unsigned int ticks, void* param) static int mod_init(void) { cachedb_engine cde; - cachedb_con *con; - str url = str_init("sql://"); - str name = str_init("sql"); - LM_INFO("initializing...\n"); + LM_INFO("initializing module cachedb_sql...\n"); - init_db_url(db_url , 0 /*cannot be null*/); db_table.len = strlen(db_table.s); key_column.len = strlen(key_column.s); value_column.len = strlen(value_column.s); counter_column.len = strlen(counter_column.s); expires_column.len = strlen(expires_column.s); - /* Find a database module */ - if (db_bind_mod(&db_url, &cdb_dbf) < 0){ - LM_ERR("unable to bind to a database driver\n"); - return -1; - } - /* register the cache system */ cde.name = cache_mod_name; + cde.cdb_func.init = dbcache_init; cde.cdb_func.destroy = dbcache_destroy; cde.cdb_func.get = dbcache_get; @@ -459,21 +532,6 @@ static int mod_init(void) cde.cdb_func.get_counter = dbcache_fetch_counter; cde.cdb_func.capability = 0; - cdb_db_handle = cdb_dbf.init(&db_url); - if (cdb_db_handle == 0) { - LM_ERR("Failed to connect to the DB \n"); - return -1; - } - - if(db_check_table_version(&cdb_dbf, cdb_db_handle, - &db_table, CACHEDB_SQL_TABLE_VERSION) < 0) { - LM_ERR("error during table version check.\n"); - return -1; - } - - cdb_dbf.close(cdb_db_handle); - cdb_db_handle = 0; - if(cache_clean_period <= 0) { LM_ERR("wrong parameter cache_clean_period - need a postive value\n"); return -1; @@ -484,17 +542,6 @@ static int mod_init(void) return -1; } - con = dbcache_init(&url); - if(con == NULL) { - LM_ERR("failed to init connection for script\n"); - return -1; - } - - if(cachedb_put_connection(&name, con) < 0) { - LM_ERR("failed to insert connection for script\n"); - return -1; - } - /* register timer to delete the expired entries */ register_timer("cachedb_sql",dbcache_clean, 0, cache_clean_period); @@ -506,12 +553,24 @@ static int mod_init(void) */ static int child_init(int rank) { - cdb_db_handle = cdb_dbf.init(&db_url); - if (cdb_db_handle == 0) { - LM_ERR("unable to connect to the database\n"); + struct cachedb_url *it; + cachedb_con *con; + + for (it = sql_script_urls;it;it=it->next) { + LM_DBG("iterating through conns - [%.*s]\n",it->url.len,it->url.s); + con = dbcache_init(&it->url); + if (con == NULL) { + LM_ERR("failed to open connection\n"); + return -1; + } + if (cachedb_put_connection(&cache_mod_name,con) < 0) { + LM_ERR("failed to insert connection\n"); return -1; + } } + cachedb_free_url(sql_script_urls); + return 0; } @@ -520,8 +579,5 @@ static int child_init(int rank) */ static void destroy(void) { - if (cdb_db_handle) { - cdb_dbf.close(cdb_db_handle); - cdb_db_handle = 0; - } + cachedb_end_connections(&cache_mod_name); } diff --git a/modules/cachedb_sql/doc/cachedb_sql.xml b/modules/cachedb_sql/doc/cachedb_sql.xml index 15fdaa1694e..1345b66a75b 100644 --- a/modules/cachedb_sql/doc/cachedb_sql.xml +++ b/modules/cachedb_sql/doc/cachedb_sql.xml @@ -4,6 +4,7 @@ + @@ -43,6 +44,8 @@ &admin; +&faq; + diff --git a/modules/cachedb_sql/doc/cachedb_sql_admin.xml b/modules/cachedb_sql/doc/cachedb_sql_admin.xml index 56aeebda79e..1cdffb1a484 100644 --- a/modules/cachedb_sql/doc/cachedb_sql_admin.xml +++ b/modules/cachedb_sql/doc/cachedb_sql_admin.xml @@ -96,17 +96,25 @@
Exported Parameters
- <varname>db_url</varname> (string) + <varname>cachedb_url</varname> (string) The url of the Database that OpenSIPS will connect to in order to use the from script cache_store,cache_fetch, etc operations. + + + The format to follow is : sql:[conn_id]-dburl + + + + The parameter can be set multiple times to create multiple connections accessible from the OpenSIPS script. + Set <varname>db_url</varname> parameter ... -modparam("cachedb_sql", "db_url","mysql://localhost/my_database"); +modparam("cachedb_sql", "cachedb_url", "sql:1st-mysql://root:vlad@localhost/opensips_sql") ... @@ -115,8 +123,12 @@ modparam("cachedb_sql", "db_url","mysql://localhost/my_database"); Usage example ... -cache_store("sql","key","$ru value"); -cache_add("sql","counter",10); +modparam("cachedb_sql", "cachedb_url", "sql:1st-mysql://root:vlad@localhost/opensips_sql") +modparam("cachedb_sql", "cachedb_url", "sql:2nd-postgres://root:vlad@localhost/opensips_pg") +... +... +cache_store("sql:1st-mysql","key","$ru value"); +cache_store("sql:2nd-postgres","counter","10"); ... diff --git a/modules/cachedb_sql/doc/cachedb_sql_faq.xml b/modules/cachedb_sql/doc/cachedb_sql_faq.xml new file mode 100644 index 00000000000..e909a71ab61 --- /dev/null +++ b/modules/cachedb_sql/doc/cachedb_sql_faq.xml @@ -0,0 +1,24 @@ + + + + + &faqguide; + + + + + + What happend with the old db_url module parameter? + + + + It was replaced with the cachedb_url parameter. + See the documentation for the usage of the cachedb_url parameter. + + + + + + + + diff --git a/modules/call_center/Makefile b/modules/call_center/Makefile new file mode 100755 index 00000000000..60db6fdc366 --- /dev/null +++ b/modules/call_center/Makefile @@ -0,0 +1,9 @@ +# +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=call_center.so +LIBS= + +include ../../Makefile.modules diff --git a/modules/call_center/README b/modules/call_center/README new file mode 100644 index 00000000000..fac3d2af2ef --- /dev/null +++ b/modules/call_center/README @@ -0,0 +1,514 @@ +Call-Center Module + +Bogdan-Andrei Iancu + +Edited by + +Bogdan-Andrei Iancu + + Copyright © 2014 www.opensips-solutions.com + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. How it works + + 1.2.1. DB tables + 1.2.2. Call Flows + 1.2.3. Agents + + 1.3. Dependencies + + 1.3.1. OpenSIPS Modules + 1.3.2. External Libraries or Applications + + 1.4. Exported Parameters + + 1.4.1. db_url (string) + 1.4.2. acc_db_url (string) + 1.4.3. b2b_scenario (string) + 1.4.4. wrapup_time (integer) + + 1.5. Exported Functions + + 1.5.1. cc_handle_call(flowID) + 1.5.2. cc_agent_login(agentID, state) + + 1.6. Exported Statistics + + 1.6.1. Global statistics + 1.6.2. Per-flow statistics (one set for each flow) + 1.6.3. Per-agent statistics (one set for each agent) + + 1.7. Exported MI Functions + + 1.7.1. cc_reload + 1.7.2. cc_agent_login + 1.7.3. cc_list_queue + 1.7.4. cc_list_flows + 1.7.5. cc_list_agents + 1.7.6. cc_list_calls + 1.7.7. cc_reset_stats + + 1.8. Exported pseudo-variables + + 2. Developer Guide + + 2.1. Available Functions + + 3. Frequently Asked Questions + + List of Examples + + 1.1. Set db_url parameter + 1.2. Set acc_db_url parameter + 1.3. Set b2b_scenario parameter + 1.4. Set wrapup_time parameter + 1.5. cc_handle_call usage + 1.6. cc_agent_login usage + +Chapter 1. Admin Guide + +1.1. Overview + + The Call Center module implements an inbound call center system + with call flows (for queuing the received calls) and agents + (for answering the calls). + + The module implements the queuing system, the call distribution + to agents, agents managements, CDRs for the calls, statistics + on call distribution and agent's activity - basically + everything except the media playback (for the queue). This part + must be provided via a third party media server (FreeSwitch, + Asterisk or others). + +1.2. How it works + + The main entities in the modules are the flows (queues) and + agents. + +1.2.1. DB tables + + Each entity has a corresponding table in the database, for + provisioning purposes - the cc_flows and cc_agents tables, see + DB schema. Data is loaded at startup and cached into memory ; + runtime reload is possible via the MI commands (see the + cc_reload command in Section 1.7, “Exported MI Functions”). + + Additionally there is a table cc_cdrs for writing the CDRs - + this operation is done in realtime, after the call in + completed, covering all possible cases: call was dropped while + in queue, call was rejected by agent, call was accepted by + agent, call terminated with error - NOTE that a call may + generate more than one CDR (like call rejected by agent A, and + redistributed and accepted by agent B). + + The cc_calls table is used to store ongoing calls, regardless + it's state (in queue, to the agent, ended). It is populated at + runtime by the module and queried at startup. This table should + not be manually provisioned. + +1.2.2. Call Flows + + A flow is defined by a unique alphanumerical ID - the main + attribute of a flow is the skill - the skill is a capability + required by the flow for an agent to be able to answer the call + ; the concept of skills is the link between the flows and the + agents - telling what agents are serving what flows - the flows + require a skill, while the agents provide a set of skills. + Agents matching the required skill of a flow will automatically + receive calls from that flow. + + Additional, the flow has a priority - as agents may server + multiple flows in the same time (based on skills), you can + define priorities between the flows - if the flows has a higher + priority, its calls will be pushed (in deliver to agents and + queuing) in front of the calls from flows with a lower + priority. + + Optionally, the flow may define a prependcid - a prefix to be + added to the CLI (Caller ID) when the call is delivered to the + agents - as an agent may receive call from multiple flows, it + is important for the user to see which was the queue a call was + received. + + In terms of media announcements, the flow defines the + message_welcome (optional, to be played in the call, before + doing anything with the call) and message_queue (mandatory, the + looping message providing infinite on hold media IMPORTANT - + this message must cycle and media server must never hung up on + it. Both announcements are provided as SIP URIs (where the call + has to be sent in order to get the playback). + +1.2.3. Agents + + An agent is defined by a unique alphanumerical ID - the main + attribute of an agent is its the set of skills and its SIP + location. The set of skills will tell what calls to be received + (from which flows, based on the skill matching); the location + is a SIP URI where to call must be sent in order to be answered + by the agent. + + Additionally, the agent has a initial logstate - if he is + logged in or not (being logged in is a must in order to receive + calls). The log state may be changed at runtime via a dedicated + MI command cc_agent_login, see Section 1.7, “Exported MI + Functions”. + + There is a wrapup_time defined, saying the time interval for an + agent before getting a new call from the system (after he + finished a call). + +1.3. Dependencies + +1.3.1. OpenSIPS Modules + + The following modules must be loaded before this module: + * b2b_logic - B2bUA module + * database - one of the SQL DB modules + +1.3.2. External Libraries or Applications + + The following libraries or applications must be installed + before running OpenSIPS with this module loaded: + * None. + +1.4. Exported Parameters + +1.4.1. db_url (string) + + SQL address to the DB server -- database specific. This must be + the Database holding the provisioning tables (cc_flows, + cc_agents and cc_calls tables). + If not explicitly set, the global OpenSIPS DB URL will be used. + + Example 1.1. Set db_url parameter +... +modparam("call_center", "db_url", + "mysql://opensips:opensipsrw@localhost/opensips") +... + +1.4.2. acc_db_url (string) + + SQL address to the DB server -- database specific. This must be + the Database where the CDRs table (cc_cdrs) is located. + If not explicitly set, the global OpenSIPS DB URL will be used. + + Example 1.2. Set acc_db_url parameter +... +modparam("call_center", "acc_db_url", + "mysql://opensips:opensipsrw@localhost/opensips_cdrs") +... + +1.4.3. b2b_scenario (string) + + The name of the B2B scenario that is used by the module for + handling the calls in the queue. This is an advanced options + and you should not change it unless you really understand what + you are doing. + + The module provides an B2B scenario file + scenario_callcenter.xml located in the module directory. The + name of this scenario from this file (which must be loaded via + the b2b_logic module) must match the b2b_scenario parameter. + + Default value is “call center”. + + Example 1.3. Set b2b_scenario parameter +... +modparam("b2b_logic", "script_scenario", "/etc/opensips/scenario_callcen +ter.xml") +modparam("call_center", "b2b_scenario", "call center") +... + +1.4.4. wrapup_time (integer) + + Time for an agent between finishing a call and receiving the + next call from the system. Even if there are queued calls, the + module will not deliver call to agent during this wrapup + interval. + + Default value is “30 seconds”. + + Example 1.4. Set wrapup_time parameter +... +modparam("call_center", "wrapup_time", 45) +... + +1.5. Exported Functions + +1.5.1. cc_handle_call(flowID) + + This must be used only for initial INVITE requests - the + function pushes the call to be handled by the call center + module (via a certain flow/queue). + + This function can be used from REQUEST_ROUTE. + + The flowID mandatory parameter is the ID of the flow to handle + this call (push the call to that flow). This can be a variable + or a static string. + + The function returns TRUE back to the script if the call was + successfully pushed and handled by the Call Center engine. + IMPORTANT: you must not do any signaling on the call (reply, + relay) after this point. + + In case of error, FALSE is returned to the script with the + following return codes: + * -1 - unable to get the flow ID from the parameter; + * -2 - unable to parse the FROM URI; + * -3 - flow with FlowID not found; + * -4 - no agents logged in the flow; + * -5 - internal error; + + Example 1.5. cc_handle_call usage +... +if (is_method("INVITE") and !has_totag()) { + if (!cc_handle_call("tech_support")) { + send_reply("403","Cannot handle call"); + exit; + } +} +... + +1.5.2. cc_agent_login(agentID, state) + + This function sets the login (on or off) state for an agent. + + This function can be used from REQUEST_ROUTE. + + The agentID mandatory parameter is the ID of the agent and the + state is an integer value giving the new state - 0 means logged + off, anything else means logged in. + + Example 1.6. cc_agent_login usage +... +# log off the 'agentX' agent +cc_agent_login("agentX","0"); +... + +1.6. Exported Statistics + +1.6.1. Global statistics + +1.6.1.1. ccg_incalls + + Total number of received calls. (counter type) + +1.6.1.2. ccg_awt + + Global avg. waiting time for calls. (realtime type) + +1.6.1.3. ccg_load + + Global load (across all flows). (realtime type) + +1.6.1.4. ccg_distributed_incalls + + Total number of distributed calls. (counter type) + +1.6.1.5. ccg_answered_incalls + + Total number of calls answered by agents. (counter type) + +1.6.1.6. ccg_abandonned_incalls + + Total number of calls terminated by caller before being + answered by agents. (counter type) + +1.6.1.7. ccg_onhold_calls + + Total number of calls in the queues (onhold). (realtime type) + +1.6.1.8. ccg_free_agents + + Total number of free agents (across all flows). (realtime type) + +1.6.2. Per-flow statistics (one set for each flow) + +1.6.2.1. ccf_incalls_flowID + + Number of received calls for the flow. (counter type) + +1.6.2.2. ccf_dist_incalls_flowID + + Number of distributed calls in this flow. (counter type) + +1.6.2.3. ccf_answ_incalls_flowID + + Nnumber of calls from the flow answered by agents. (counter + type) + +1.6.2.4. ccf_aban_incalls_flowID + + Number of calls (from the flow) terminated by caller before + being answered by agents. (counter type) + +1.6.2.5. ccf_onhold_incalls_flowID + + Number of calls (from the flow) which were put onhold. (counter + type) + +1.6.2.6. ccf_queued_calls_flowID + + Number of calls which are queued for this flow. (realtime type) + +1.6.2.7. ccf_free_agents_flowID + + Number of free agents serving this flow. (realtime type) + +1.6.2.8. ccf_etw_flowID + + Estimated Time to Wait for this flow. (realtime type) + +1.6.2.9. ccf_awt_flowID + + Avg. Wating Time for this flow. (realtime type) + +1.6.2.10. ccg_load_flowID + + The load on the flow (number of queued calls versus number of + logged agents). (realtime type) + +1.6.3. Per-agent statistics (one set for each agent) + +1.6.3.1. cca_dist_incalls_agnetID + + Number of distributed calls to this agent. (counter type) + +1.6.3.2. cca_answ_incalls_agentID + + Nnumber of calls answered by the agent. (counter type) + +1.6.3.3. cca_aban_incalls_agentID + + Number of calls (sent to this agent) terminated by caller + before being answered by agents. (counter type) + +1.6.3.4. cca_att_agentID + + Avg. Talk Time for this agent (realtime type) + +1.7. Exported MI Functions + +1.7.1. cc_reload + + Command to reload flows and agents definition from database. + + It takes no parameter. + + MI FIFO Command usage: +opensipsctl fifo cc_reload + +1.7.2. cc_agent_login + + Command to login an agent into the Call Center engine. + + It takes two mandatory parameters, the ID of the agent and the + new login state (0 - log off, 1 - log in) + + MI FIFO Command usage: +opensipsctl fifo cc_agent_login agentX 0 + +1.7.3. cc_list_queue + + Command to list all the calls in queuing - for each call, the + following attributes will be printed: the flow of the call, for + how long the call is in the queue, the ETW for the call, call + priority and the call skill (inherited from the flow). + + It takes no parameter. + + MI FIFO Command usage: +opensipsctl fifo cc_list_queue + +1.7.4. cc_list_flows + + Command to list all the flows - for each flow, the following + attributes will be printed: the flow ID, the avg. call + duration, how many calls were processed, how many agents are + logged, and how many onging calls are. + + It takes no parameter. + + MI FIFO Command usage: +opensipsctl fifo cc_list_flows + +1.7.5. cc_list_agents + + Command to list all the agents - for each agent, the following + attributes will be printed: agent ID, agent login state and + agent state (free, wrapup, incall). + + It takes no parameter. + + MI FIFO Command usage: +opensipsctl fifo cc_list_agents + +1.7.6. cc_list_calls + + Command to list all the ongoing calls - for each call, the + following attributes will be printed: call ID, call state + (welcome, queued, toagent, ended), call duration, flow it + belongs to, agent serving the call (if any). + + It takes no parameter. + + MI FIFO Command usage: +opensipsctl fifo cc_list_agents + +1.7.7. cc_reset_stats + + Command to reset all counter-like statistics. + + It takes no parameter. + + MI FIFO Command usage: +opensipsctl fifo cc_reset_stats + +1.8. Exported pseudo-variables + + NONE + +Chapter 2. Developer Guide + +2.1. Available Functions + + NONE + +Chapter 3. Frequently Asked Questions + + 3.1. + + Where can I find more about OpenSIPS? + + Take a look at http://www.opensips.org/. + + 3.2. + + Where can I post a question about this module? + + First at all check if your question was already answered on one + of our mailing lists: + * User Mailing List - + http://lists.opensips.org/cgi-bin/mailman/listinfo/users + * Developer Mailing List - + http://lists.opensips.org/cgi-bin/mailman/listinfo/devel + + E-mails regarding any stable OpenSIPS release should be sent to + and e-mails regarding development + versions should be sent to . + + If you want to keep the mail private, send it to + . + + 3.3. + + How can I report a bug? + + Please follow the guidelines provided at: + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/call_center/call_center.c b/modules/call_center/call_center.c new file mode 100755 index 00000000000..aa176ef2a0c --- /dev/null +++ b/modules/call_center/call_center.c @@ -0,0 +1,1465 @@ +/* + * call center module - call queuing and distribution + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-03-17 initial version (bogdan) + */ + +#include "../../sr_module.h" +#include "../../db/db.h" +#include "../../dprint.h" +#include "../../error.h" +#include "../../timer.h" +#include "../../ut.h" +#include "../../mod_fix.h" +#include "../../locking.h" +#include "../../flags.h" +#include "../../parser/parse_from.h" +#include "../b2b_logic/b2b_load.h" +#include "cc_data.h" +#include "cc_queue.h" +#include "cc_db.h" + + + +/* db stuff */ +static str db_url = {NULL, 0}; +static str acc_db_url = {NULL, 0};; + +/* internal data (agents, flows) */ +static struct cc_data *data=NULL; +static str b2b_scenario = {"call center", 0}; + +/* b2b logic API */ +b2bl_api_t b2b_api; + + +static int mod_init(void); +static void mod_destroy(void); +static int child_init( int rank ); +static int mi_child_init(); + +static struct mi_root* mi_cc_reload(struct mi_root *cmd_tree, void *param); +static struct mi_root* mi_cc_list_flows(struct mi_root *cmd_tree, void *param); +static struct mi_root* mi_cc_list_queue(struct mi_root *cmd_tree, void *param); +static struct mi_root* mi_agent_login(struct mi_root *cmd_tree, void *param); +static struct mi_root* mi_cc_list_agents(struct mi_root *cmd_tree, void *param); +static struct mi_root* mi_cc_list_calls(struct mi_root *cmd_tree, void *param); +static struct mi_root* mi_reset_stats(struct mi_root *cmd_tree, void *param); + +static int w_handle_call(struct sip_msg *req, char *id); +static int w_agent_login(struct sip_msg *req, char *agent, char *state); + +static void cc_timer_agents(unsigned int ticks, void* param); +static void cc_timer_cleanup(unsigned int ticks, void* param); + +unsigned long stg_awt(unsigned short foo); +unsigned long stg_load(unsigned short foo); +unsigned long stg_free_agents(unsigned short foo); + +stat_var *stg_incalls = 0; +stat_var *stg_dist_incalls = 0; +stat_var *stg_answ_incalls = 0; +stat_var *stg_aban_incalls = 0; +stat_var *stg_onhold_calls = 0; + +/* a default of 30 secs wrapup time for agents */ +unsigned int wrapup_time = 30; + + + +static cmd_export_t cmds[]={ + {"cc_handle_call", (cmd_function)w_handle_call, 1, + fixup_sgp_null, 0, REQUEST_ROUTE}, + {"cc_agent_login", (cmd_function)w_agent_login, 2, + fixup_sgp_sgp, 0, REQUEST_ROUTE}, + {0,0,0,0,0,0} + }; + + +static param_export_t mod_params[]={ + { "db_url", STR_PARAM, &db_url.s }, + { "acc_db_url", STR_PARAM, &acc_db_url.s }, + { "b2b_scenario", STR_PARAM, &b2b_scenario.s }, + { "wrapup_time", INT_PARAM, &wrapup_time }, + { 0,0,0 } +}; + + +static mi_export_t mi_cmds[] = { + { "cc_reload", "", mi_cc_reload, MI_NO_INPUT_FLAG, 0, mi_child_init}, + { "cc_agent_login", "", mi_agent_login, 0, 0, 0}, + { "cc_list_queue", "", mi_cc_list_queue, MI_NO_INPUT_FLAG, 0, 0}, + { "cc_list_flows", "", mi_cc_list_flows, MI_NO_INPUT_FLAG, 0, 0}, + { "cc_list_agents", "", mi_cc_list_agents,MI_NO_INPUT_FLAG, 0, 0}, + { "cc_list_calls", "", mi_cc_list_calls, MI_NO_INPUT_FLAG, 0, 0}, + { "cc_reset_stats", "", mi_reset_stats, MI_NO_INPUT_FLAG, 0, 0}, + { 0, 0, 0, 0, 0, 0} +}; + + +static stat_export_t mod_stats[] = { + {"ccg_incalls", 0, &stg_incalls }, + {"ccg_awt", STAT_IS_FUNC, (stat_var**)stg_awt }, + {"ccg_load", STAT_IS_FUNC, (stat_var**)stg_load }, + {"ccg_distributed_incalls", 0, &stg_dist_incalls }, + {"ccg_answered_incalls" , 0, &stg_answ_incalls }, + {"ccg_abandonned_incalls" , 0, &stg_aban_incalls }, + {"ccg_onhold_calls", STAT_NO_RESET, &stg_onhold_calls }, + {"ccg_free_agents", STAT_IS_FUNC, (stat_var**)stg_free_agents }, + {0,0,0} +}; + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "b2b_logic", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + +struct module_exports exports= { + "call_center", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ + MODULE_VERSION, + DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ + cmds, /* exported functions */ + mod_params, /* param exports */ + mod_stats, /* exported statistics */ + mi_cmds, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + 0, /* reply processing function */ + mod_destroy, + child_init /* per-child init function */ +}; + + + +unsigned long stg_awt(unsigned short foo) +{ + return data->avt_waittime; +} + + +unsigned long stg_load(unsigned short foo) +{ + unsigned int free_ag; + unsigned int load; + struct cc_agent *agent; + + lock_get( data->lock ); + + if (data->logedin_agents==0) { + lock_release( data->lock ); + return 0; + } + + free_ag = 0; + for (agent = data->agents[CC_AG_ONLINE] ; agent ; agent=agent->next) { + if (agent->state==CC_AGENT_FREE) free_ag++; + } + + load = 100*( get_stat_val(stg_onhold_calls) + data->logedin_agents - free_ag ) / data->logedin_agents; + + lock_release( data->lock ); + + return load; +} + + +unsigned long stg_free_agents(unsigned short foo) +{ + struct cc_agent *agent; + unsigned int free = 0; + + lock_get( data->lock ); + + for (agent = data->agents[CC_AG_ONLINE] ; agent ; agent=agent->next) { + if (agent->state==CC_AGENT_FREE) free++; + } + + lock_release( data->lock ); + + return free; +} + +unsigned long cc_flow_free_agents( void *flow) +{ + struct cc_agent *agent; + unsigned int free = 0; + unsigned int i; + + lock_get( data->lock ); + + for (agent = data->agents[CC_AG_ONLINE] ; agent ; agent=agent->next) { + if (agent->state==CC_AGENT_FREE) { + /* iterate all skills of the agent */ + for( i=0 ; ino_skills ; i++) { + if (agent->skills[i]==((struct cc_flow*)flow)->skill) + free++; + } + } + } + + lock_release( data->lock ); + + return free; +} + + +static int mod_init(void) +{ + LM_INFO("Call Center module - initializing\n"); + + init_db_url( db_url , 0 /*cannot be null*/); + init_db_url( acc_db_url , 0 /*cannot be null*/); + b2b_scenario.len = strlen(b2b_scenario.s); + + /* Load B2BUA API */ + if (load_b2b_logic_api( &b2b_api) != 0) { + LM_ERR("Can't load B2B-UA hooks, missing 'b2b_logic' module ?\n"); + return -1; + } + + if (register_timer( "cc_agents", cc_timer_agents, NULL, 1)<0) { + LM_ERR("failed to register agents timer function\n"); + return -1; + } + + if (register_timer( "cc_cleanup", cc_timer_cleanup, NULL, 5)<0) { + LM_ERR("failed to register cleaup timer function\n"); + return -1; + } + + /* main CC data */ + data = init_cc_data(); + if (data==0) { + LM_CRIT("failed to get shm mem for data\n"); + return -1; + } + + /* init and open DB connection */ + if (init_cc_db( &db_url )!=0) { + LM_ERR("failed to initialize the DB support\n"); + return -1; + } + if (init_cc_acc_db( &acc_db_url )!=0) { + LM_ERR("failed to initialize the acc DB support\n"); + return -1; + } + + /* load data */ + if ( cc_load_db_data( data )!=0 ) { + LM_CRIT("failed to load callcenter data\n"); + return -1; + } + clean_cc_old_data(data); + + /* restore calls */ + if ( cc_db_restore_calls( data )!=0 ) { + LM_CRIT("failed to load callcenter data\n"); + return -1; + } + + /* close DB connection */ + cc_close_db(); + + return 0; +} + + +static int child_init( int rank ) +{ + /* init DB connection */ + if ( rankavt_waittime_no ++; + data->avt_waittime = + ( ((float)duration + (data->avt_waittime * (float)(data->avt_waittime_no-1))) ) / + (float)data->avt_waittime_no; +} + + +static void terminate_call(struct cc_call *call, b2bl_dlg_stat_t* stat, + call_state prev_state) +{ + str un, fid, aid; + int type; + + if(prev_state == CC_CALL_ENDED) { + LM_CRIT("BUG - terminate state \n"); + return; + } + + LM_DBG("terminating call %p (stat=%p)\n",call,stat); + + lock_get( data->lock ); + + prepare_cdr( call, &un, &fid , &aid); + + if (prev_state==CC_CALL_TOAGENT) { + /* free the agent */ + if (stat && stat->call_time && prev_state==CC_CALL_TOAGENT) { + call->agent->state = CC_AGENT_WRAPUP; + call->agent->last_call_end = get_ticks(); + call->flow->processed_calls ++; + call->flow->avg_call_duration = + ( ((float)stat->call_time + + ((float)call->flow->avg_call_duration * + (call->flow->processed_calls-1)) ) ) / + call->flow->processed_calls ; + /* update awt for established calls */ + update_awt( stat->start_time - call->recv_time ); + update_cc_flow_awt(call->flow, stat->start_time - call->recv_time); + update_cc_agent_att(call->agent, stat->call_time); + } else { + call->agent->state = CC_AGENT_FREE; + /* update awt for failed calls */ + update_awt( get_ticks() - call->recv_time ); + update_cc_flow_awt( call->flow, get_ticks() - call->recv_time ); + } + /* update last_call_end for agent */ + cc_db_update_agent_end_call(call->agent); + call->agent->ref_cnt--; + call->agent = NULL; + } else { + /* update awt for failed calls */ + update_awt( get_ticks() - call->recv_time ); + update_cc_flow_awt( call->flow, get_ticks() - call->recv_time ); + } + + /* remove the call from queue (if there) */ + if ( is_call_in_queue(data, call) ) { + cc_queue_rmv_call( data, call); + call->ref_cnt--; + } + + call->flow->ongoing_calls--; + + lock_release( data->lock ); + + if (call->setup_time==-1 && stat) + call->setup_time = stat->setup_time; + + /* generate CDR */ + type = (stat==NULL) ? -1 : ((prev_state==CC_CALL_TOAGENT && stat->call_time)? 0 : 1); + cc_write_cdr( &un, &fid, &aid, type, call->recv_time, + ((type==0)? stat->start_time : get_ticks()) - call->recv_time , + (type==0)?stat->call_time:0 , call->setup_time, call->no_rejections, call->fst_flags, + call->id); + + cc_db_delete_call(call); +} + + +int set_call_leg( struct sip_msg *msg, struct cc_call *call, str *new_leg); + +#define MAX_OUT_BUF_LEN 1024 +static char out_buf[MAX_OUT_BUF_LEN]; +#define OUT_BUF_LEN(_a) (_aagent->st_aban_incalls, 1); + call->no_rejections++; + + /* put call back into queue */ + call->state = CC_CALL_QUEUED; + call->setup_time = -1; + + lock_get( data->lock ); + + /* prepare CDR */ + prepare_cdr( call, &un, &fid , &aid); + + call->agent->state = CC_AGENT_WRAPUP; + call->agent->last_call_end = get_ticks(); + /* update last call_end for agent */ + cc_db_update_agent_end_call(call->agent); + call->agent->ref_cnt--; + call->agent = NULL; + + cc_queue_push_call( data, call, 1/*top*/); + + if(from_customer || call->prev_state != CC_CALL_QUEUED) { + out.len = OUT_BUF_LEN(call->flow->recordings[AUDIO_QUEUE].len); + out.s = out_buf; + memcpy( out.s, call->flow->recordings[AUDIO_QUEUE].s, out.len); + } + + lock_release( data->lock ); + + if(from_customer || call->prev_state != CC_CALL_QUEUED) { + /* send call to queue */ + if (set_call_leg( NULL, call, &out)< 0 ) { + LM_ERR("failed to set new destination for call\n"); + } + LM_DBG("onhold++: agent rejected [%p]\n", call); + if(from_customer) + { + update_stat( stg_onhold_calls, 1); + update_stat( call->flow->st_onhold_calls, 1); + } + } + /* write CDR */ + cc_write_cdr( &un, &fid, &aid, -2, call->recv_time, + get_ticks() - call->recv_time, 0 , pickup_time, call->no_rejections-1, + call->fst_flags, call->id); + cc_db_update_call(call); +} + + +int b2bl_callback_customer(b2bl_cb_params_t *params, unsigned int event) +{ + struct cc_call *call = (struct cc_call*)params->param; + str leg = {NULL,0}; + call_state cs; + int cnt; + b2bl_dlg_stat_t* stat = params->stat; + + LM_DBG(" call (%p) has BYE for %d, \n", call, event); + + lock_get( call->lock ); + cs = call->state; + + if (event==B2B_DESTROY_CB) { + LM_DBG("A delete in b2blogic, call->state=%d, %p\n", call->state, call); + call->state = CC_CALL_ENDED; + lock_release( call->lock ); + if( cs != CC_CALL_ENDED) { + /* call terminated due to some error -> cleanup here */ + terminate_call( call, NULL, cs); + if (cs < CC_CALL_TOAGENT) { + LM_DBG("** onhold-- Destroy [%p]\n", call); + update_stat( stg_onhold_calls, -1); + update_stat( call->flow->st_onhold_calls, -1); + } + if (cs == CC_CALL_TOAGENT) { + /* call no longer on wait */ + //update_stat( stg_aban_incalls, 1); /*abandon from agent */ + //update_stat( call->agent->st_aban_incalls, 1); + } + } + lock_get( call->lock ); + cnt = --call->ref_cnt; + lock_release( call->lock ); + if (cnt==0) + free_cc_call( data, call); + else + LM_DBG("!!! Call ref not 0 - do not delete %p\n", call); + return 0; + } + + if(call->ign_cback) { + lock_release( call->lock ); + return 2; + } + + if ( event==B2B_BYE_CB ) { + if (cs==CC_CALL_TOAGENT && stat->call_time) { + /* an established call was terminated */ + update_stat( stg_answ_incalls, 1); + update_stat( call->flow->st_answ_incalls, 1); + call->fst_flags |= FSTAT_ANSW; + update_stat( call->agent->st_answ_incalls, 1); + } + } + + if (event==B2B_BYE_CB && params->entity==1) { + LM_DBG("BYE from the customer\n"); + /* external caller terminated the call */ + call->state = CC_CALL_ENDED; + lock_release( call->lock ); + if (csflow->st_onhold_calls, -1); + } + /* Abandon: client was not sent to agent yet, or call still ringing + * on agent side + */ + if (cscall_time==0) { + /*abandon from customer */ + update_stat( stg_aban_incalls, 1); + update_stat( call->flow->st_aban_incalls, 1); + call->fst_flags |= FSTAT_ABAN; + } + terminate_call(call, stat, cs); + + /* route the BYE according to scenario */ + return 2; + } + /* if reInvite to the customer failed - end the call */ + if(event == B2B_REJECT_CB && params->entity==1) { + lock_release( call->lock ); + return 1; + } + + if(event == B2B_REJECT_CB && params->entity>1) { + if(call->state == CC_CALL_TOAGENT) { + handle_agent_reject(call, 1, stat->setup_time); + lock_release( call->lock ); + return 0; + } + lock_release( call->lock ); + return 1; + } + + if (stat->call_time==0 && call->state == CC_CALL_TOAGENT) { + LM_INFO("*** AGENT answered and closed immediately %.*s\n", + call->agent->location.len, call->agent->location.s); + handle_agent_reject(call, 1, stat->setup_time); + lock_release( call->lock ); + return 0; + } + + /* right-side leg of call sent BYE -> get next state */ + lock_get( data->lock ); + + if (cc_call_state_machine( data, call, &leg )!=0) { + LM_ERR("failed to get next call destination \n"); + lock_release( data->lock ); + lock_release( call->lock ); + /* force BYE to be sent in both parts */ + return -1; + } + + lock_release( data->lock ); + + LM_DBG("new destination for call(%p) is %.*s (state=%d)\n", + call, leg.len, leg.s, call->state); + + if (call->state == CC_CALL_ENDED) { + lock_release( call->lock ); + terminate_call( call, stat, cs); + return 2; + } else if (call->state == CC_CALL_TOAGENT) { + /* call no longer on wait */ + LM_DBG("** onhold-- Direct to agent [%p]\n", call); + update_stat( stg_onhold_calls, -1); + update_stat( call->flow->st_onhold_calls, -1); + } + + /* send call to selected destination */ + if (set_call_leg( NULL, call, &leg)< 0) { + LM_ERR("failed to set new destination for call\n"); + lock_release( call->lock ); + pkg_free(leg.s); + return -1; + } + lock_release( call->lock ); + + if(cc_db_update_call(call) < 0) + { + LM_ERR("Failed to update call in database\n"); + } + + pkg_free(leg.s); + return 0; +} + + +int set_call_leg( struct sip_msg *msg, struct cc_call *call, str *new_leg) +{ + str* id; + + LM_DBG("call %p moving to %.*s , state %d\n", call, + new_leg->len, new_leg->s, call->state); + + if (call->b2bua_id.len==0) { + /* b2b instance not initialized yet => + * create new b2bua instance */ + call->ref_cnt++; + id = b2b_api.init( msg, &b2b_scenario, &new_leg, b2bl_callback_customer, + (void*)call, B2B_DESTROY_CB|B2B_REJECT_CB|B2B_BYE_CB, NULL /* custom_hdrs */ ); + if (id==NULL || id->len==0 || id->s==NULL) { + LM_ERR("failed to init new b2bua call (empty ID received)\n"); + return -2; + } + + call->b2bua_id.s = (char*)shm_malloc(id->len); + if (call->b2bua_id.s==NULL) { + LM_ERR("failed to allocate b2bua ID\n"); + return -1; + } + memcpy( call->b2bua_id.s, id->s, id->len); + /* this must be the last, as we use it as marker for checking + * if b2b entity is initialized */ + call->b2bua_id.len = id->len; + } else { + /* call already ongoing */ + if(b2b_api.bridge( &call->b2bua_id, new_leg, &call->caller_dn, 0) < 0) { + LM_ERR("bridging failed\n"); + b2b_api.terminate_call(&call->b2bua_id); + return -1; + } + } + /* remember last time when the call started */ + call->last_start = get_ticks(); + //b2b_api.set_state(&call->b2bua_id, call->state); + return 0; +} + + +static inline str* build_displayname(str *prefix, struct to_body *fh) +{ + static char buf[65]; + static str dn; + unsigned int l=64; + unsigned int n; + char *p; + str *s; + + dn.s = p = buf; + + *(p++) = '"'; + l --; + + n = prefix->len; + if (n>l) n = l; + + memcpy( p, prefix->s , n); + p += n; + l -= n; + + if (l<=0) + goto done; + + *(p++) = ' '; + l --; + + if (l<=0) + goto done; + + if (fh->display.len) { + s = &fh->display; + if(s->s[0]=='"') { + s->s++; + s->len-=2; + } + } + else + s = &fh->parsed_uri.user; + + n = s->len; + if (n>l) n = l; + memcpy( p, s->s , n); + p += n; + l -= n; + +done: + *(p++) = '"'; + dn.len = p-buf; + return &dn; +} + + +static int w_handle_call(struct sip_msg *msg, char *flow_var) +{ + struct cc_flow *flow; + struct cc_call *call; + str leg = {NULL,0}; + str *dn; + str val; + int dec; + int ret = -1; + + call = NULL; + dec = 0; + + /* get the flow name */ + if (fixup_get_svalue(msg, (gparam_p)flow_var, &val)!=0) { + LM_ERR("failed to avaluate the flow name variable\n"); + return -1; + } + + /* parse FROM URI */ + if (parse_from_uri(msg)==NULL) { + LM_ERR("failed to parse from hdr\n"); + return -2; + } + + lock_get( data->lock ); + + /* get the flow ID */ + flow = get_flow_by_name(data, &val); + if (flow==NULL) { + LM_ERR("flow <%.*s> does not exists\n", val.len, val.s); + ret = -3; + goto error; + } + LM_DBG("using call flow %p\n", flow); + + if (flow->logged_agents==0 /* no logged agents */ ) { + LM_NOTICE("flow <%.*s> closed\n",flow->id.len,flow->id.s); + ret = -4; + goto error; + } + + update_stat(stg_incalls, 1); + update_stat(flow->st_incalls, 1); + + if (flow->cid.len) { + dn = build_displayname(&flow->cid, get_from(msg)); + } else if (get_from(msg)->display.len) { + dn = &get_from(msg)->display; + } else { + dn = &get_from(msg)->parsed_uri.user; + } + LM_DBG("cid=<%.*s>\n",dn->len,dn->s); + + call = new_cc_call(data, flow, dn, &get_from(msg)->parsed_uri.user); + if (call==NULL) { + LM_ERR("failed to create new call\n"); + ret = -5; + goto error; + } + call->fst_flags |= FSTAT_INCALL; + + /* get estimated wait time */ + call->eta = (unsigned int) (( flow->avg_call_duration * + (float)get_stat_val(flow->st_queued_calls) ) / + (float)flow->logged_agents); + + LM_DBG("avg_call_duration=%.2f queued_calls=%lu logedin_agents=%u\n", + flow->avg_call_duration, get_stat_val(flow->st_queued_calls), + flow->logged_agents); + + LM_DBG("ETA for new call(%p) is %d\n", call, call->eta); + + /* one more call to process */ + flow->ongoing_calls++; + + /* there is no need to lock the call here as it is not + * yet sharead at all - just we have a ref to it */ + + /* get the first state */ + if (cc_call_state_machine( data, call, &leg )!=0) { + LM_ERR("failed to get first call destination \n"); + ret = -5; + goto error; + } + + lock_release( data->lock ); + LM_DBG("new destination for call(%p) is %.*s (state=%d)\n", + call, leg.len, leg.s, call->state); + + /* call still waits for agent ? */ + if (call->state!=CC_CALL_TOAGENT) { + LM_DBG("** onhold++ Not to agent [%p]\n", call); + update_stat( stg_onhold_calls, +1); + update_stat( flow->st_onhold_calls, +1); + dec = 1; + } + + /* send call to selected destination */ + if (set_call_leg( msg, call, &leg)< 0 ) { + LM_ERR("failed to set new destination for call\n"); + if (dec) { + LM_DBG("** onhold-- Error [%p]\n", call); + update_stat( stg_onhold_calls, -1); + update_stat( flow->st_onhold_calls, -1); + } + pkg_free(leg.s); + goto error1; + } + + pkg_free(leg.s); + + if(cc_db_insert_call(call) < 0) { + LM_ERR("Failed to insert call record in db\n"); + } + + return 1; +error: + lock_release( data->lock ); +error1: + if (call) { free_cc_call( data, call); flow->ongoing_calls--; } + return ret; +} + + +static int w_agent_login(struct sip_msg *req, char *agent_v, char *state_v) +{ + struct cc_agent *agent, *prev_agent; + str agent_s; + int state; + unsigned int flags; + + + /* get state */ + if (fixup_get_isvalue( req, (gparam_p)state_v, &state, &agent_s, + &flags)!=0 || ((flags|GPARAM_INT_VALUE_FLAG)==0) ) { + LM_ERR("unable to evaluate state spec \n"); + return -1; + } + /* get agent */ + if (fixup_get_svalue( req, (gparam_p)agent_v, &agent_s)!=0) { + LM_ERR("unable to evaluate agent spec \n"); + return -2; + } + + /* block access to data */ + lock_get( data->lock ); + + /* name of the agent */ + agent = get_agent_by_name( data, &agent_s, &prev_agent); + if (agent==NULL) { + lock_release( data->lock ); + LM_DBG("agent <%.*s> not found\n",agent_s.len,agent_s.s); + return -3; + } + + if (agent->loged_in != state) { + + if(state && (agent->state==CC_AGENT_WRAPUP) && + (get_ticks() - agent->last_call_end > wrapup_time)) + agent->state = CC_AGENT_FREE; + + if(state && data->agents[CC_AG_ONLINE] == NULL) + data->last_online_agent = agent; + + agent_switch_login(data, agent, prev_agent); + + if(state) { + data->logedin_agents++; + log_agent_to_flows( data, agent, 1); + } else { + data->logedin_agents--; + log_agent_to_flows(data, agent, 0); + } + } + + /* release access to data */ + lock_release( data->lock ); + + return 1; +} + + +static void cc_timer_agents(unsigned int ticks, void* param) +{ + struct cc_agent *agent, *prev_agent, *tmp_ag; + struct cc_call *call; + str out; + str dest; + + if (data==NULL || data->agents[CC_AG_ONLINE]==NULL) + return; + + do { + + lock_get( data->lock ); + + prev_agent = data->agents[CC_AG_ONLINE]; + agent = data->agents[CC_AG_ONLINE]; + call = NULL; + + /* iterate all agents*/ + do { + + //LM_DBG("%.*s , state=%d, last_call_end=%u, ticks=%u, wrapup=%u\n", + // agent->id.len, agent->id.s, agent->state, agent->last_call_end, ticks, wrapup_time); + /* for agents in WRAPUP time, check if expired */ + if ( (agent->state==CC_AGENT_WRAPUP) && + (ticks - agent->last_call_end > wrapup_time)) { + agent->state = CC_AGENT_FREE; + /* move it to the end of the list*/ + if(data->last_online_agent != agent) { + remove_cc_agent(data, agent, prev_agent); + if(!data->last_online_agent) { + LM_CRIT("last_online_agent NULL\n"); + if(data->agents[CC_AG_ONLINE] == NULL) + data->agents[CC_AG_ONLINE] = agent; + else { + for (tmp_ag = data->agents[CC_AG_ONLINE]; tmp_ag; tmp_ag= tmp_ag->next) + { + prev_agent = tmp_ag; + } + prev_agent->next = agent; + agent->next = NULL; + data->last_online_agent = agent; + } + } + else { + data->last_online_agent->next = agent; + agent->next = NULL; + data->last_online_agent = agent; + } + goto next_ag; + } + } + + /* for free agents -> check for calls */ + if ( (data->queue.calls_no!=0) && (agent->state==CC_AGENT_FREE) ) { + call = cc_queue_pop_call_for_agent( data, agent); + if (call) { + /* found a call for the agent */ + break; + } + } +next_ag: + /* next agent */ + prev_agent = agent; + agent = agent->next; + + }while(agent); + + lock_release( data->lock ); + + /* no locking here */ + + if (call) { + + lock_get( call->lock ); + call->ref_cnt--; + + /* is the call state still valid? (as queued) */ + if(call->state != CC_CALL_QUEUED) { + if (call->state==CC_CALL_ENDED && call->ref_cnt==0) { + lock_release( call->lock ); + free_cc_call( data, call); + } else { + lock_release( call->lock ); + } + continue; + } + LM_DBG("Call %p ref= %d, state= %d\n", call, + call->ref_cnt, call->state); + + lock_get( data->lock ); + + dest = agent->location; + + /* make a copy for destination to agent */ + out.len = OUT_BUF_LEN(dest.len); + out.s = out_buf; + memcpy( out.s, dest.s, out.len); + + call->prev_state = call->state; + call->state = CC_CALL_TOAGENT; + /* call no longer on wait */ + LM_DBG("** onhold-- Took out of the queue [%p]\n", call); + update_stat( stg_onhold_calls, -1); + update_stat( call->flow->st_onhold_calls, -1); + + /* mark agent as used */ + agent->state = CC_AGENT_INCALL; + call->agent = agent; + call->agent->ref_cnt++; + update_stat( stg_dist_incalls, 1); + update_stat( call->flow->st_dist_incalls, 1); + call->fst_flags |= FSTAT_DIST; + update_stat( call->agent->st_dist_incalls, +1); + + /* unlock data */ + lock_release( data->lock ); + + /* send call to selected agent */ + if (set_call_leg( NULL, call, &out)< 0 ) { + LM_ERR("failed to set new destination for call\n"); + } + lock_release( call->lock ); + + if(cc_db_update_call(call) < 0) + { + LM_ERR("Failed to update call in database\n"); + } + } + + } while (call); +} + + +static void cc_timer_cleanup(unsigned int ticks, void* param) +{ + if (data->old_flows==NULL && data->old_agents==NULL) + return; + + /* block access to data */ + lock_get( data->lock ); + + clean_cc_unref_data(data); + + /* done with data */ + lock_release( data->lock ); +} + + +/******************** MI commands ***********************/ + +static struct mi_root* mi_cc_reload(struct mi_root *cmd_tree, void *param) +{ + int ret; + + LM_INFO("\"cc_reload\" MI command received!\n"); + + /* block access to data */ + lock_get( data->lock ); + + /* do the update */ + ret = cc_load_db_data( data ); + if (ret<0) { + LM_CRIT("failed to load CC data\n"); + } + + clean_cc_old_data(data); + + /* release the readers */ + lock_release( data->lock ); + + if (ret==0) + return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); + else + return init_mi_tree( 500, "Failed to reload",16); +} + + +static struct mi_root* mi_cc_list_flows(struct mi_root *cmd, void *param) +{ + struct cc_flow *flow; + struct mi_root *rpl_tree; + struct mi_node *node; + struct mi_node *rpl; + struct mi_attr *attr; + int len; + char *p; + + rpl_tree = init_mi_tree( 200, MI_SSTR("OK") ); + if ( rpl_tree==NULL) + return NULL; + rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; + + /* block access to data */ + lock_get( data->lock ); + + for( flow=data->flows; flow ; flow=flow->next ) { + + node = add_mi_node_child( rpl, MI_DUP_VALUE, MI_SSTR("Flow"), + flow->id.s, flow->id.len ); + if (node==NULL) + goto error; + + p = int2str( (unsigned long)(flow->avg_call_duration), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Avg Call Duration"), p, len); + if (attr==NULL) + goto error; + + p = int2str( (unsigned long)(flow->processed_calls), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Processed Calls"), p, len); + if (attr==NULL) + goto error; + + p = int2str( (unsigned long)(flow->logged_agents), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Logged Agents"), p, len); + if (attr==NULL) + goto error; + + p = int2str( (unsigned long)(flow->ongoing_calls), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Ongoing Calls"), p, len); + if (attr==NULL) + goto error; + + p = int2str( (unsigned long)(flow->ref_cnt), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Ref"), p, len); + if (attr==NULL) + goto error; + + } + + lock_release( data->lock ); + + return rpl_tree; + +error: + lock_release( data->lock ); + return 0; +} + + +static struct mi_root* mi_cc_list_agents(struct mi_root *cmd_tree, void *param) +{ + struct cc_agent *agent; + struct mi_root *rpl_tree; + struct mi_node *node; + struct mi_node *rpl; + struct mi_attr *attr; + str state; + static str s_free={"free", 4}; + static str s_wrapup={"wrapup", 6}; + static str s_incall={"incall", 6}; + char *p; + int len; + int i; + + rpl_tree = init_mi_tree( 200, MI_SSTR("OK") ); + if ( rpl_tree==NULL) + return NULL; + rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; + + /* block access to data */ + lock_get( data->lock ); + + for(i=0; i< 2; i++) { + for( agent=data->agents[i] ; agent ; agent=agent->next ) { + node = add_mi_node_child( rpl, MI_DUP_VALUE, "Agent", 5, + agent->id.s, agent->id.len ); + if (node==NULL) + goto error; + + p = int2str( (unsigned long)(agent->ref_cnt), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Ref"), p, len); + if (attr==NULL) + goto error; + + if(!agent->loged_in) + attr = add_mi_attr( node, MI_DUP_VALUE, "Loged in", 8, "NO", 2); + else { + attr = add_mi_attr( node, MI_DUP_VALUE, "Loged in", 8, "YES", 3); + if (attr==NULL) + goto error; + + switch ( agent->state ) { + case CC_AGENT_FREE: state = s_free; break; + case CC_AGENT_WRAPUP: state = s_wrapup; break; + case CC_AGENT_INCALL: state = s_incall; break; + default: state.s =0; state.len = 0; + } + attr = add_mi_attr( node, MI_DUP_VALUE, "State", 5, + state.s, state.len ); + + } + if (attr==NULL) + goto error; + } + } + lock_release( data->lock ); + + return rpl_tree; + +error: + lock_release( data->lock ); + return 0; +} + + +static struct mi_root* mi_cc_list_calls(struct mi_root *cmd_tree, void *param) +{ + struct cc_call *call; + struct cc_agent *agent; + struct mi_root *rpl_tree; + struct mi_node *node; + struct mi_node *rpl; + struct mi_attr *attr; + char *p; + int len; + static str call_state[12]= {{"none", 4}, + {"welcome", 7}, + {"queued", 6}, + {"toagent", 7}, + {"ended", 5}}; + + rpl_tree = init_mi_tree( 200, MI_SSTR("OK") ); + if ( rpl_tree==NULL) + return NULL; + rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; + + /* block access to data */ + lock_get( data->lock ); + + for( call=data->list.first ; call ; call=call->next_list ) { + + node = add_mi_node_child( rpl, MI_DUP_VALUE, "Call", 4, + call->b2bua_id.s, call->b2bua_id.len); + if (node==NULL) + goto error; + + p = int2str( (unsigned long)(call->ref_cnt), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Ref"), p, len); + if (attr==NULL) + goto error; + if(call->ign_cback) + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("State"), MI_SSTR("ignored")); + else + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("State"), call_state[call->state].s, call_state[call->state].len); + if (attr==NULL) + goto error; + + LM_DBG("call->recv_time= %d, ticks= %d\n", call->recv_time, get_ticks()); + if(call->state != CC_CALL_ENDED) + { + p = int2str( (unsigned long)(call->recv_time?(get_ticks() - call->recv_time):0), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Call Time"), p, len); + if (attr==NULL) + goto error; + + if(call->flow) { + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Flow"), call->flow->id.s, call->flow->id.len); + if (attr==NULL) + goto error; + } + } + if(call->agent) { + agent = call->agent; + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Agent"), agent->id.s, agent->id.len); + if (attr==NULL) + goto error; + } + + } + + lock_release( data->lock ); + + return rpl_tree; + +error: + lock_release( data->lock ); + return 0; +} + + +/* FORMAT : agent_id log_state */ +static struct mi_root* mi_agent_login(struct mi_root *cmd_tree, void *param) +{ + struct mi_node *node; + struct cc_agent *agent; + unsigned int loged_in; + struct cc_agent* prev_agent= 0; + + node = cmd_tree->node.kids; + + if (node==NULL || node->next==NULL || node->next->next!=NULL) + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + + /* block access to data */ + lock_get( data->lock ); + + /* name of the agent */ + agent = get_agent_by_name( data, &node->value, &prev_agent); + if (agent==NULL) { + lock_release( data->lock ); + return init_mi_tree( 404, MI_SSTR("Agent not found") ); + } + + /* login state */ + node = node->next; + if (str2int( &node->value , &loged_in)!=0 ) { + lock_release( data->lock ); + return init_mi_tree( 400, MI_SSTR("Bad loged_in state") ); + } + + if (agent->loged_in != loged_in) { + + if(loged_in && (agent->state==CC_AGENT_WRAPUP) && + (get_ticks() - agent->last_call_end > wrapup_time)) + agent->state = CC_AGENT_FREE; + + if(loged_in && data->agents[CC_AG_ONLINE] == NULL) + data->last_online_agent = agent; + + agent_switch_login(data, agent, prev_agent); + + if(loged_in) { + data->logedin_agents++; + log_agent_to_flows( data, agent, 1); + } else { + data->logedin_agents--; + log_agent_to_flows(data, agent, 0); + } + } + + /* release the readers */ + lock_release( data->lock ); + + return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); +} + + +static struct mi_root* mi_reset_stats(struct mi_root *cmd_tree, void *param) +{ + struct cc_flow *flow; + struct cc_agent *agent; + int i; + + /* reset global stats */ + reset_stat( stg_incalls) ; + data->avt_waittime_no = 0; + data->avt_waittime = 0; + reset_stat( stg_dist_incalls ); + reset_stat( stg_answ_incalls ); + reset_stat( stg_aban_incalls ); + + /* block access to data */ + lock_get( data->lock ); + + /* reset flow stats */ + for ( flow = data->flows ; flow ; flow = flow->next ) { + reset_stat( flow->st_incalls ); + reset_stat( flow->st_dist_incalls ); + reset_stat( flow->st_answ_incalls ); + reset_stat( flow->st_aban_incalls ); + reset_stat( flow->st_onhold_calls ); + flow->avg_call_duration = 0; + flow->processed_calls = 0; + flow->avg_waittime = 0; + flow->avg_waittime_no = 0; + } + + /* reset agent stats */ + for(i = 0; i< 2; i++) { + for ( agent = data->agents[i] ; agent ; agent = agent->next ) { + reset_stat( agent->st_dist_incalls ); + reset_stat( agent->st_answ_incalls ); + reset_stat( agent->st_aban_incalls ); + agent->avg_talktime = 0; + agent->avg_talktime_no = 0; + } + } + + /* release the readers */ + lock_release( data->lock ); + + return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); +} + + +static struct mi_root* mi_cc_list_queue(struct mi_root *cmd_tree, void *param) +{ + struct mi_root *rpl_tree; + struct mi_node *node; + struct mi_attr *attr; + struct mi_node *rpl; + struct cc_call *call; + unsigned int n, now; + char *p; + int len; + str *s; + + rpl_tree = init_mi_tree( 200, MI_SSTR("OK") ); + if ( rpl_tree==NULL) + return NULL; + rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; + + n = 0; + now = get_ticks(); + + /* block access to data */ + lock_get( data->lock ); + + for ( call=data->queue.first ; call ; call=call->lower_in_queue, n++) { + + p = int2str( (unsigned long)n, &len); + node = add_mi_node_child( rpl, MI_DUP_VALUE, "Call", 4, p, len); + if (node==NULL) + goto error; + + p = int2str( (unsigned long)(now-call->last_start), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, "Waiting for", 11, p, len); + if (attr==NULL) + goto error; + + p = int2str( (unsigned long)(call->eta), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, "ETW", 3, p, len); + if (attr==NULL) + goto error; + + /* flow data */ + node = add_mi_node_child( node, MI_DUP_VALUE, "Flow", 4, + call->flow->id.s, call->flow->id.len); + if (node==NULL) + goto error; + + p = int2str( (unsigned long)(call->flow->priority), &len); + attr = add_mi_attr( node, MI_DUP_VALUE, "Priority", 8, p, len); + if (attr==NULL) + goto error; + + s = get_skill_by_id(data,call->flow->skill); + if (s) { + attr = add_mi_attr( node, MI_DUP_VALUE, "Skill", 5, s->s, s->len); + if (attr==NULL) + goto error; + } + } + + /* release the readers */ + lock_release( data->lock ); + + return rpl_tree; +error: + lock_release( data->lock ); + free_mi_tree(rpl_tree); + return NULL; +} + + diff --git a/modules/call_center/cc_data.c b/modules/call_center/cc_data.c new file mode 100755 index 00000000000..4ca376e125e --- /dev/null +++ b/modules/call_center/cc_data.c @@ -0,0 +1,1032 @@ +/* + * call center module - call queuing and distributio + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-03-17 initial version (bogdan) + */ + + + +#include + +#include "../../mem/shm_mem.h" +#include "../../parser/parse_uri.h" +#include "../../locking.h" +#include "../../ut.h" +#include "../../trim.h" +#include "../b2b_logic/b2b_load.h" +#include "cc_data.h" + + +/* b2b logic API */ +extern b2bl_api_t b2b_api; + +extern unsigned int wrapup_time; + + +static void free_cc_flow( struct cc_flow *flow); +static void free_cc_agent( struct cc_agent *agent); +unsigned long cc_flow_free_agents( void *flow); + + +unsigned int get_skill_id(struct cc_data *data, str *name) +{ + struct cc_skill *skill; + + /* search to see if exists */ + for ( skill=data->skills_map ; skill ; skill=skill->next ) { + if ( (skill->name.len==name->len) && + (memcmp(skill->name.s,name->s,name->len)==0) ) + return skill->id; + } + + /* none found, allocate a new one */ + skill = (struct cc_skill*)shm_malloc( sizeof(struct cc_skill)+name->len ); + if (skill==NULL) { + LM_ERR("no enough shm mem for a new skill map\n"); + return 0; + } + + skill->is_new = 1; + skill->name.s = (char*)(skill+1); + skill->name.len = name->len; + memcpy( skill->name.s , name->s, name->len); + + skill->id = ++(data->last_skill_id); + + /* link it */ + skill->next = data->skills_map; + data->skills_map = skill; + + return skill->id; +} + + +str* get_skill_by_id(struct cc_data *data, unsigned int id) +{ + struct cc_skill *skill; + + /* search to see if exists */ + for ( skill=data->skills_map ; skill ; skill=skill->next ) { + if (skill->id==id) + return &skill->name; + } + + return NULL; +} + + +void free_cc_skill(struct cc_skill *skill) +{ + shm_free(skill); +} + + +struct cc_data* init_cc_data(void) +{ + struct cc_data *data; + + data = (struct cc_data*) shm_malloc( sizeof(struct cc_data) ); + if (data==NULL) { + LM_ERR("failed to allocate shm mem\n"); + return NULL; + } + memset( data, 0, sizeof(struct cc_data)); + + /* create & init lock */ + if ( (data->lock=lock_alloc())==0) { + LM_CRIT("failed to alloc lock\n"); + goto error; + } + if (lock_init(data->lock)==0 ) { + LM_CRIT("failed to init lock\n"); + goto error; + } + + /* set of locks for calls */ + if ( (data->call_locks=lock_set_alloc(512))==0) { + LM_CRIT("failed to alloc set of call locks\n"); + goto error; + } + if (lock_set_init(data->call_locks)==0 ) { + LM_CRIT("failed to init set of call locks\n"); + goto error; + } + + return data; +error: + free_cc_data(data); + return NULL; +} + + +void free_cc_data(struct cc_data *data) +{ + struct cc_flow *flow, *f_flow; + struct cc_agent *agent,*f_agent; + int i; + + if (data) { + /* lock */ + if (data->lock) { + lock_destroy( data->lock ); + lock_dealloc( data->lock ); + } + if (data->call_locks) { + lock_set_destroy( data->call_locks ); + lock_set_dealloc( data->call_locks ); + } + /* flows */ + for( flow=data->flows ; flow ; ) { + f_flow = flow; + flow = flow->next; + free_cc_flow( f_flow ); + } + /* agents */ + for(i = 0; i< 2; i++) { + for( agent=data->agents[i] ; agent ; ) { + f_agent = agent; + agent = agent->next; + free_cc_agent( f_agent ); + } + } + shm_free(data); + } +} + + +struct cc_flow *get_flow_by_name(struct cc_data *data, str *name) +{ + struct cc_flow *flow; + + for( flow=data->flows ; flow ; flow=flow->next ) { + if (name->len==flow->id.len && + memcmp( name->s, flow->id.s, name->len)==0) + return flow; + } + + return NULL; +} + + +struct cc_agent* get_agent_by_name(struct cc_data *data, str *name, struct cc_agent **prev_agent) +{ + struct cc_agent *agent; + int i; + + for(i = 0; i< 2; i++) { + *prev_agent = data->agents[i]; + for( agent=data->agents[i] ; agent ; agent=agent->next ) { + if (name->len==agent->id.len && + memcmp( name->s, agent->id.s, name->len)==0) + return agent; + *prev_agent = agent; + } + } + return NULL; +} + + +void update_cc_flow_awt(struct cc_flow *flow, unsigned long duration) +{ + flow->avg_waittime_no ++; + flow->avg_waittime = + ( ((float)duration + (flow->avg_waittime * (float)(flow->avg_waittime_no-1))) ) / + (float)flow->avg_waittime_no; +} + +#ifdef STATISTICS +static unsigned long cc_flow_get_etw( void *flow_p) +{ + struct cc_flow *flow = (struct cc_flow*)flow_p; + + return flow->logged_agents? (unsigned long)(( flow->avg_call_duration * get_stat_val(flow->st_queued_calls) ) / + (float)flow->logged_agents):0; +} + + +static unsigned long cc_flow_get_awt( void *flow_p) +{ + return (unsigned long)((struct cc_flow*)flow_p)->avg_waittime; +} + + +static unsigned long cc_flow_get_load( void *flow_p) +{ + struct cc_flow *flow = (struct cc_flow*)flow_p; + + return (flow->logged_agents==0) ? 0 : + (100*(get_stat_val(flow->st_onhold_calls)+flow->logged_agents-cc_flow_free_agents(flow))/flow->logged_agents); +} +#endif + +int add_cc_flow( struct cc_data *data, str *id, int priority, str *skill, + str *cid, str *recordings ) +{ + struct cc_flow *flow, *prev_flow; + unsigned int i; + unsigned int skill_id; +#ifdef STATISTICS + char *name; + str s; +#endif + + /* is the flow a new one? - search by ID */ + flow = get_flow_by_name( data, id); + + if (flow==NULL) { + /* new flow -> create and populate one */ + flow = (struct cc_flow*)shm_malloc(sizeof(struct cc_flow)+id->len); + if (flow==NULL) { + LM_ERR("not enough shmem for a new flow\n"); + goto error; + } + memset( flow, 0, sizeof(struct cc_flow) ); + /* id */ + flow->id.s = (char*)(flow+1); + memcpy( flow->id.s, id->s, id->len); + flow->id.len = id->len; + /* priority */ + flow->priority = priority; + /* skill */ + flow->skill = get_skill_id( data, skill ); + if (flow->skill==0) { + LM_ERR("cannot get skill id\n"); + goto error; + } + /* cid */ + if (cid && cid->s && cid->len) { + flow->cid.s = (char*)shm_malloc(cid->len); + if (flow->cid.s==NULL) { + LM_ERR("not enough shmem for the cid of the flow\n"); + goto error; + } + memcpy( flow->cid.s, cid->s, cid->len); + flow->cid.len = cid->len; + } + /* audio messages */ + for( i=0 ; irecordings[i].s = (char*)shm_malloc(recordings[i].len); + if (flow->recordings[i].s==NULL) { + LM_ERR("not enough shmem for the message %d of the flow\n", + i); + goto error; + } + memcpy( flow->recordings[i].s, recordings[i].s, + recordings[i].len); + flow->recordings[i].len = recordings[i].len; + } + } +#ifdef STATISTICS + /* statistics */ + s.s = "ccf_incalls";s.len = 11 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &flow->st_incalls, STAT_SHM_NAME)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_dist_incalls";s.len = 15 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &flow->st_dist_incalls, STAT_SHM_NAME)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_answ_incalls";s.len = 15 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &flow->st_answ_incalls, STAT_SHM_NAME)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_aban_incalls";s.len = 15 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &flow->st_aban_incalls, STAT_SHM_NAME)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_onhold_calls";s.len = 15 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &flow->st_onhold_calls, STAT_SHM_NAME)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_queued_calls";s.len = 16 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &flow->st_queued_calls, STAT_SHM_NAME|STAT_NO_RESET)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_etw";s.len = 7 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat2("call_center", + name, (stat_var **)cc_flow_get_etw, STAT_SHM_NAME|STAT_IS_FUNC, + (void*)flow, 0)!=0) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_awt";s.len = 7 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat2("call_center", + name, (stat_var **)cc_flow_get_awt, STAT_SHM_NAME|STAT_IS_FUNC, + (void*)flow, 0)!=0) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_load";s.len = 8 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat2("call_center", + name, (stat_var **)cc_flow_get_load, STAT_SHM_NAME|STAT_IS_FUNC, + (void*)flow, 0)!=0) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "ccf_free_agents";s.len = 15 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat2("call_center", + name, (stat_var **)cc_flow_free_agents, STAT_SHM_NAME|STAT_IS_FUNC, + (void*)flow, 0)!=0) { + LM_ERR("failed to add stat variable\n"); + goto error; + } +#endif + + flow->is_new = 1; + /* insert the new flow in the list */ + flow->next = data->flows; + data->flows = flow; + } else { + /* flow already exists -> update */ + /* priority */ + flow->priority = priority; + /* skill - needs to be changed ? */ + skill_id = get_skill_id(data,skill); + if (skill_id==0) { + LM_ERR("cannot get skill id\n"); + goto error1; + } + flow->skill = skill_id; + /* cid - needs to be changed ? */ + if ( flow->cid.len && ( cid->len==0 || + cid->len>flow->cid.len || memcmp(flow->cid.s,cid->s,cid->len)!=0) ) { + shm_free(flow->cid.s); flow->cid.s = NULL; flow->cid.len = 0 ; + } + if (flow->cid.s==NULL && cid->len!=0) { + flow->cid.s = (char*)shm_malloc(cid->len); + if (flow->cid.s==NULL) { + LM_ERR("not enough shmem for the cid of the flow\n"); + goto error1; + } + } + if (flow->cid.s) { + memcpy( flow->cid.s, cid->s, cid->len); + flow->cid.len = cid->len; + } + /* audio messages */ + for( i=0 ; irecordings[i].len && ( recordings[i].len==0 || + recordings[i].len>flow->recordings[i].len || + memcmp(flow->recordings[i].s,recordings[i].s,recordings[i].len) + ) ) { + shm_free(flow->recordings[i].s); flow->recordings[i].s = NULL; + flow->recordings[i].len = 0 ; + } + if (flow->recordings[i].s==NULL && recordings[i].len!=0) { + flow->recordings[i].s = (char*)shm_malloc(recordings[i].len); + if (flow->recordings[i].s==NULL) { + LM_ERR("not enough shmem for the message of the flow\n"); + goto error1; + } + } + if (flow->recordings[i].s) { + memcpy( flow->recordings[i].s, recordings[i].s, + recordings[i].len); + flow->recordings[i].len = recordings[i].len; + } + } + flow->is_new = 1; + + } + + return 0; + +error1: + if(data->flows == flow) + data->flows = flow->next; + else + for(prev_flow=data->flows; prev_flow; prev_flow=prev_flow->next) + if(prev_flow->next == flow) { + prev_flow->next = flow->next; + break; + } +error: + if (flow) + free_cc_flow(flow); + return -1; +} + + +static void free_cc_flow( struct cc_flow *flow) +{ + int i; + + if (flow->cid.s) + shm_free(flow->cid.s); + for( i=0 ; irecordings[i].s) + shm_free(flow->recordings[i].s); + } + shm_free(flow); +} + + +void update_cc_agent_att(struct cc_agent *agent, unsigned long duration) +{ + agent->avg_talktime_no ++; + agent->avg_talktime = + ( ((float)duration + (agent->avg_talktime * (float)(agent->avg_talktime_no-1))) ) / + (float)agent->avg_talktime_no; +} + + +#ifdef STATISTICS +static unsigned long cc_agent_get_att( void *agent_p) +{ + return (unsigned long)((struct cc_agent*)agent_p)->avg_talktime; +} +#endif + +int add_cc_agent( struct cc_data *data, str *id, str *location, + str *skills, unsigned int logstate, unsigned int last_call_end) +{ + struct cc_agent *agent, *prev_agent= 0; + struct sip_uri uri; + str skill; + char *p; + unsigned int n,skill_id; +#ifdef STATISTICS + char *name; + str s; +#endif + + /* is the agent a new one? - search by ID */ + agent = get_agent_by_name( data, id, &prev_agent); + + if (agent==NULL) { + /* new agent -> create and populate one */ + agent = (struct cc_agent*)shm_malloc(sizeof(struct cc_agent)+id->len); + if (agent==NULL) { + LM_ERR("not enough shmem for a new agent\n"); + goto error; + } + memset( agent, 0, sizeof(struct cc_agent) ); + /* id */ + agent->id.s = (char*)(agent+1); + memcpy( agent->id.s, id->s, id->len); + agent->id.len = id->len; + /* location */ + agent->location.s = (char*)shm_malloc(location->len); + if (agent->location.s==NULL) { + LM_ERR("not enough shmem for the location of the agent\n"); + goto error; + } + memcpy( agent->location.s, location->s, location->len); + agent->location.len = location->len; + if (parse_uri( agent->location.s, agent->location.len, &uri)<0) { + LM_ERR("location of the agent is not a SIP URI\n"); + goto error; + } + agent->did = uri.user; + /* LOG STATE */ + agent->loged_in = logstate; + /* set of skills */ + if (skills && skills->len) { + p = skills->s; + while (p) { + skill.s = p; + p = q_memchr(skill.s, ',', skills->s+skills->len-skill.s); + skill.len = p?(p-skill.s):(skills->s+skills->len-skill.s); + trim(&skill); + if (skill.len) { + skill_id = get_skill_id(data,&skill); + if (skill_id==0) { + LM_ERR("cannot get skill id\n"); + goto error; + } + n = agent->no_skills++; + agent->skills[n] = skill_id; + } + if(p) + p++; + } + } + /* statistics */ +#ifdef STATISTICS + s.s = "cca_dist_incalls";s.len = 16 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &agent->st_dist_incalls, STAT_SHM_NAME)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "cca_answ_incalls";s.len = 16 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &agent->st_answ_incalls, STAT_SHM_NAME)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "cca_aban_incalls";s.len = 16 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", + name, &agent->st_aban_incalls, STAT_SHM_NAME)!=0 ) { + LM_ERR("failed to add stat variable\n"); + goto error; + } + s.s = "cca_att";s.len = 7 ; + if ( (name=build_stat_name( &s, id->s))==0 || register_stat2("call_center", + name, (stat_var **)cc_agent_get_att, STAT_SHM_NAME|STAT_IS_FUNC, + (void*)agent, 0)!=0) { + LM_ERR("failed to add stat variable\n"); + goto error; + } +#endif + if(last_call_end && (last_call_end + wrapup_time < (int)time(NULL))) { + agent->state = CC_AGENT_WRAPUP; + agent->last_call_end = last_call_end - startup_time; /* it will be a negative value */ + } + agent->is_new = 1; + /* link the agent */ + add_cc_agent_top(data, agent); + data->totalnr_agents++; + } else { + /* agent already exists -> update only */ + /* location - needs to be changed ? */ + if ( agent->location.len!=location->len || + memcmp(agent->location.s,location->s,location->len)!=0 ) { + /* set new location */ + if (agent->location.len < location->len ){ + shm_free(agent->location.s); + agent->location.s = (char*)shm_malloc(location->len); + if (agent->location.s==NULL) { + LM_ERR("not enough shmem for the location of the agent\n"); + goto error1; + } + } + memcpy( agent->location.s, location->s, location->len); + agent->location.len = location->len; + if (parse_uri( agent->location.s, agent->location.len, &uri)<0) { + LM_ERR("location of the agent is not a SIP URI\n"); + goto error1; + } + agent->did = uri.user; + } + /* if logstate changed - move between the lists TODO */ + if(logstate != agent->loged_in) { + agent_switch_login(data, agent, prev_agent); + } + /* skills - needs to be changed ? */ + agent->no_skills = 0; + if (skills && skills->len) { + p = skills->s; + while (p) { + skill.s = p; + p = q_memchr(skill.s, ',', skills->s+skills->len-skill.s); + skill.len = p?(p-skill.s):(skills->s+skills->len-skill.s); + trim(&skill); + if (skill.len) { + skill_id = get_skill_id(data,&skill); + if (skill_id==0) { + LM_ERR("cannot get skill id\n"); + goto error1; + } + n = agent->no_skills++; + agent->skills[n] = skill_id; + } + if(p) + p++; + } + } + agent->is_new = 1; + } + + return 0; +error1: + remove_cc_agent(data, agent, prev_agent); +error: + if (agent) + free_cc_agent(agent); + return 0; +} + + +static void free_cc_agent( struct cc_agent *agent) +{ + if (agent->location.s) + shm_free(agent->location.s); + shm_free(agent); +} + + +void print_call_list(struct cc_data *data) +{ + struct cc_call *call; + + for( call=data->list.first ; call ; call=call->next_list ) + LM_DBG("[%.*s] - %p\n", call->b2bua_id.len, call->b2bua_id.s, call); +} + +void cc_list_insert_call(struct cc_data *data, struct cc_call *call) +{ + if(data->list.first) + data->list.first->prev_list = call; + call->next_list= data->list.first; + data->list.first = call; + call->prev_list = NULL; + data->list.calls_no++; + call->id = data->list.lid++; + print_call_list(data); +} + +void cc_list_remove_call(struct cc_data *data, struct cc_call *call) +{ + if(call->prev_list) + call->prev_list->next_list = call->next_list; + else + data->list.first = call->next_list; + + if(call->next_list) + call->next_list->prev_list = call->prev_list; + + data->list.calls_no--; + print_call_list(data); +} + +struct cc_call* new_cc_call(struct cc_data *data, struct cc_flow *flow, str *dn, str *un) +{ + struct cc_call *call; + char *p; + + /* new call structure */ + call = (struct cc_call*)shm_malloc( sizeof(struct cc_call) + + (dn?dn->len:0) + (un?un->len:0) ); + if (call==NULL) { + LM_ERR("no more shm mem for a new call\n"); + return NULL; + } + memset( call, 0, sizeof(struct cc_call) ); + p = (char*)(call+1); + + /*copy DisplayName and UserName */ + if (dn) { + call->caller_dn.s = p; + call->caller_dn.len = dn->len; + memcpy( p, dn->s, dn->len ); + p += dn->len; + } + if (un) { + call->caller_un.s = p; + call->caller_un.len = un->len; + memcpy( p, un->s, un->len ); + p += un->len; + } + + call->recv_time = get_ticks(); + + call->setup_time = -1; + + /* attache to flow */ + call->flow = flow; + flow->ref_cnt++; + LM_DBG("created call %p\n", call); + + /* attache a lock */ + call->lock = &(data->call_locks->locks[data->next_lock_to_use++]); + if (data->next_lock_to_use==512) + data->next_lock_to_use = 0; + + cc_list_insert_call( data, call ); + + return call; +} + + +void free_cc_call(struct cc_data * data, struct cc_call *call) +{ + lock_get( data->lock ); + + cc_list_remove_call( data, call ); + + lock_release( data->lock ); + + LM_DBG("free call %p, [%.*s]\n", call, call->b2bua_id.len, call->b2bua_id.s); + if (call->flow) + call->flow->ref_cnt--; + + if(call->b2bua_id.s) + shm_free(call->b2bua_id.s); + + shm_free(call); +} + + +struct cc_agent* get_free_agent_by_skill(struct cc_data *data, + unsigned int skill) +{ + struct cc_agent *agent; + unsigned int n; + + agent = data->agents[CC_AG_ONLINE]; + if (agent==NULL) return NULL; + + /* iterate all agents*/ + do { + if(agent->state==CC_AGENT_FREE) { + /* iterate all skills of the agent */ + for( n=0 ; nno_skills ; n++) { + if (agent->skills[n]==skill) + return agent; + } + } + /* next agent */ + agent = agent->next; + }while(agent); + + return NULL; +} + + +void log_agent_to_flows(struct cc_data *data, struct cc_agent *agent, int login) +{ + unsigned int i; + struct cc_flow *flow; + + LM_DBG("login %d agent %.*s\n", login, agent->id.len, agent->id.s); + /* iterate all skills of the agent */ + for( i=0 ; ino_skills ; i++) { + //LM_DBG(" agent skill is %d (%d)\n", agent->skills[i],i); + /* iterate all flows */ + for( flow=data->flows ; flow ; flow=flow->next ) { + //LM_DBG("chekcing flow %.*s with skill %d\n", flow->id.len, flow->id.s, flow->skill); + if (agent->skills[i]==flow->skill) + flow->logged_agents = flow->logged_agents + (login?1:-1); + } + } +} + + +void clean_cc_old_data(struct cc_data *data) +{ + struct cc_skill *skill, **prv_skill; + struct cc_agent *agent, **prv_agent; + struct cc_flow *flow, **prv_flow; + int i; + + /* clean old skills */ + skill = data->skills_map; + prv_skill = &(data->skills_map); + while(skill) { + if (skill->is_new) { + skill->is_new = 0; + prv_skill = &(skill->next); + skill = skill->next; + } else { + *prv_skill = skill->next; + free_cc_skill(skill); + skill = (*prv_skill); + } + } + + /* clean old agents */ + for(i= 0; i< 2; i++) { + agent = data->agents[i]; + prv_agent = &data->agents[i]; + while(agent) { + if (agent->is_new) { + agent->is_new = 0; + prv_agent = &(agent->next); + agent = agent->next; + } else { + *prv_agent = agent->next; + if (agent->ref_cnt==0) { + free_cc_agent(agent); + } else { + agent->next = data->old_agents; + data->old_agents = agent; + } + agent = (*prv_agent); + data->totalnr_agents--; + } + } + } + + /* clean old flows */ + flow = data->flows; + prv_flow = &(data->flows); + while(flow) { + flow->logged_agents = 0; + if (flow->is_new) { + flow->is_new = 0; + prv_flow = &(flow->next); + flow = flow->next; + } else { + *prv_flow = flow->next; + if (flow->ref_cnt==0) { + free_cc_flow(flow); + } else { + /* put in a cleanup list */ + flow->next = data->old_flows; + data->old_flows = flow; + } + flow = (*prv_flow); + } + } + + /* sync flows and agents (how many agents per flow are logged) */ + /* iterate all logged agents */ + data->logedin_agents = 0; + for( agent=data->agents[CC_AG_ONLINE] ; agent ; agent=agent->next ) { + /* update last agent */ + data->last_online_agent = agent; + + /* log_agent_to_flows() must now the call center of the + * agent to count it as logged in */ + log_agent_to_flows( data, agent, agent->loged_in); + data->logedin_agents++; + } +} + + +void clean_cc_unref_data(struct cc_data *data) +{ + struct cc_agent *agent, **prv_agent; + struct cc_flow *flow, **prv_flow; + + /* clean unref flows */ + flow = data->old_flows; + prv_flow = &(data->old_flows); + while(flow) { + if (flow->ref_cnt!=0) { + prv_flow = &(flow->next); + flow = flow->next; + } else { + *prv_flow = flow->next; + free_cc_flow(flow); + flow = (*prv_flow); + } + } + + /* clean unref agents */ + agent = data->old_agents; + prv_agent = &(data->old_agents); + while(agent) { + if (agent->ref_cnt!=0) { + prv_agent = &(agent->next); + agent = agent->next; + } else { + *prv_agent = agent->next; + free_cc_agent(agent); + agent = (*prv_agent); + } + } + + return; +} + + +void print_queue(struct cc_data *data) +{ + struct cc_call *call_it; + LM_DBG("QUEUE:\n"); + for(call_it=data->queue.first ; call_it ; call_it=call_it->lower_in_queue) + LM_DBG("[%p] ->\n", call_it); + LM_DBG("0\n"); +} + + +void cc_queue_push_call(struct cc_data *data, struct cc_call *call, int top) +{ + struct cc_call *call_it; + int n = 0; + + LM_DBG(" QUEUE - adding call %p \n",call); + if ( is_call_in_queue(data, call) ) { + LM_CRIT(" QUEUE - call already in queue \n"); + abort(); + } + + if (top) { + /* add the call in the very top of the queue */ + call_it = NULL; + } else { + /* search (priority based) the place in queue */ + for(call_it=data->queue.last ; call_it ; call_it=call_it->higher_in_queue){ + if (call_it->flow->priority <= call->flow->priority) + break; + n++; + } + } + + + if (call_it) { + /* add before it */ + if (call_it->lower_in_queue) { + call_it->lower_in_queue->higher_in_queue = call; + } else { + data->queue.last = call; + } + call->lower_in_queue = call_it->lower_in_queue; + call->higher_in_queue = call_it; + call_it->lower_in_queue = call; + } else { + /* add in top of the queue */ + call->lower_in_queue = data->queue.first; + if (data->queue.first) { + data->queue.first->higher_in_queue = call; + } + else { + data->queue.last = call; + } + call->higher_in_queue = NULL; + data->queue.first = call; + } + data->queue.calls_no++; + update_stat( call->flow->st_queued_calls, +1 ); + + LM_DBG("adding call on pos %d (already %d calls), l=%p h=%p\n", + n, data->queue.calls_no, + call->lower_in_queue, call->higher_in_queue); + call->ref_cnt++; + + if (call->queue_start==0) + call->queue_start = get_ticks(); +} + + + +void cc_queue_rmv_call( struct cc_data *data, struct cc_call *call) +{ + LM_DBG(" QUEUE - removing call %p \n",call); + if ( !is_call_in_queue(data, call) ) { + LM_CRIT(" QUEUE - call not in queue l=%p, h=%p\n", + call->lower_in_queue, call->higher_in_queue); + abort(); + } + + if (call->lower_in_queue) { + call->lower_in_queue->higher_in_queue = + call->higher_in_queue; + } else { + data->queue.last = call->higher_in_queue; + } + if (call->higher_in_queue) { + call->higher_in_queue->lower_in_queue = + call->lower_in_queue; + } else { + data->queue.first = call->lower_in_queue; + } + call->lower_in_queue = call->higher_in_queue = NULL; + data->queue.calls_no--; + update_stat( call->flow->st_queued_calls, -1 ); +} + + + +struct cc_call *cc_queue_pop_call_for_agent(struct cc_data *data, + struct cc_agent *agent) +{ + struct cc_call *call_it; + unsigned int i; + + /* interate all the queued calls and see * + * if they mathe the agent (as skills)*/ + for(call_it=data->queue.first ; call_it ; call_it=call_it->lower_in_queue){ + /* check the call skill against the agent skills */ + for(i=0 ; ino_skills ; i++) { + /* before taking a call out, be sure that call is fully initialized + * from b2bua point of view (to avoid races) -> check the b2bua id */ + if (call_it->b2bua_id.len!=0 && call_it->flow->skill==agent->skills[i]) { + LM_DBG("found call %p for agent %p(%.*s) with skill %d \n", + call_it, agent, agent->id.len, agent->id.s, + call_it->flow->skill); + /* remove the call from queue */ + cc_queue_rmv_call( data, call_it); + return call_it; + } + } + } + + return NULL; +} + diff --git a/modules/call_center/cc_data.h b/modules/call_center/cc_data.h new file mode 100755 index 00000000000..0fe7a97b6cc --- /dev/null +++ b/modules/call_center/cc_data.h @@ -0,0 +1,282 @@ +/* + * call center module - call queuing and distributio + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + */ + + + +#ifndef CC_CC_DATA_H_ +#define CC_CC_DATA_H_ + +#include "../../str.h" +#include "../../locking.h" +#include "../../hash_func.h" +#include "../../parser/msg_parser.h" + + +typedef enum { + AUDIO_WELCOME, + AUDIO_QUEUE, + MAX_AUDIO +} audio_files; + + +struct cc_flow { + str id; + unsigned int is_new; + /* configuration data */ + unsigned int priority; + unsigned int skill; + str recordings[MAX_AUDIO]; + str cid; + /* runtime data */ + int ref_cnt; + float avg_call_duration; + unsigned long processed_calls; + unsigned int logged_agents; + unsigned int ongoing_calls; + /* statistics */ + stat_var *st_incalls; + stat_var *st_dist_incalls; + stat_var *st_answ_incalls; + stat_var *st_aban_incalls; + stat_var *st_onhold_calls; + stat_var *st_queued_calls; + float avg_waittime; + unsigned long avg_waittime_no; + + struct cc_flow *next; +}; + + +#define MAX_SKILLS_PER_AGENT 32 + +typedef enum { + CC_AGENT_FREE, + CC_AGENT_WRAPUP, + CC_AGENT_INCALL +}agent_state; + + +struct cc_agent { + str id; + unsigned int is_new; + /* configuration data */ + str location; /* sip address*/ + str did; /* shorcut for username in sips address */ + unsigned int no_skills; + unsigned int skills[MAX_SKILLS_PER_AGENT]; + /* runtime data */ + int ref_cnt; + agent_state state; + unsigned int loged_in; + int last_call_end; + /* statistics */ + stat_var *st_dist_incalls; + stat_var *st_answ_incalls; + stat_var *st_aban_incalls; + float avg_talktime; + unsigned long avg_talktime_no; + + struct cc_agent *next; +}; + + +struct cc_list { + unsigned int lid; + unsigned int calls_no; + struct cc_call *first; + struct cc_call *last; +}; + + +struct cc_skill { + str name; + unsigned int id; + unsigned int is_new; + struct cc_skill *next; +}; + + +#define CC_AG_OFFLINE 0 +#define CC_AG_ONLINE 1 + +struct cc_data { + gen_lock_t *lock; + /* sub-structures */ + struct cc_flow *flows; + struct cc_agent *agents[2]; + struct cc_agent *last_online_agent; + struct cc_skill *skills_map; + struct cc_list queue; + struct cc_list list; + /* old data */ + struct cc_flow *old_flows; + struct cc_agent *old_agents; + /* call related data */ + gen_lock_set_t *call_locks; + unsigned int next_lock_to_use; + struct cc_call *calls; + /* skills related data */ + unsigned int last_skill_id; + /* tracking data */ + unsigned int logedin_agents; + float avt_waittime; + unsigned long avt_waittime_no; + unsigned long totalnr_agents; +}; + + +typedef enum { + CC_CALL_NONE, + CC_CALL_WELCOME, + CC_CALL_QUEUED, + CC_CALL_TOAGENT, + CC_CALL_ENDED +} call_state; + +#define FSTAT_INCALL (1<<0) +#define FSTAT_DIST (1<<1) +#define FSTAT_ANSW (1<<2) +#define FSTAT_ABAN (1<<3) + +struct cc_call { + unsigned int id; + gen_lock_t *lock; + char ign_cback; /* ignore callbacks because agent_free was called */ + int fst_flags; /* flow stats flags */ + call_state state; /* call state */ + call_state prev_state; + short ref_cnt; + short no_rejections; + short setup_time; + unsigned int eta; + unsigned int last_start; + unsigned int queue_start; + unsigned int recv_time; + str caller_dn; + str caller_un; + /* b2b id */ + str b2bua_id; + /* flow the call belong to */ + struct cc_flow *flow; + /* agent taking this call */ + struct cc_agent *agent; + /* queue-ing link */ + struct cc_call *higher_in_queue; + struct cc_call *lower_in_queue; + struct cc_call *next_list; + struct cc_call *prev_list; +}; + +#define is_call_in_queue(_data, _call) ((_call)->lower_in_queue || (_call)->higher_in_queue || \ + (_data->queue.first==_call && _data->queue.last==_call)) + +struct cc_data* init_cc_data(void); + +void free_cc_data(struct cc_data *data); + +str* get_skill_by_id(struct cc_data *data, unsigned int id); + +int add_cc_flow( struct cc_data *data, str *id, int priority, str *skill, + str *cid, str *recordings ); + +void update_cc_agent_att(struct cc_agent *agent, unsigned long duration); + +int add_cc_agent( struct cc_data *data, str *id, str *location, + str *skills, unsigned int logstate, unsigned int last_call_end); + +void update_cc_flow_awt(struct cc_flow *flow, unsigned long duration); + +struct cc_agent* get_agent_by_name(struct cc_data *data, str *name, struct cc_agent **prev_agent); + +struct cc_flow *get_flow_by_name(struct cc_data *data, str *name); + +struct cc_call* new_cc_call(struct cc_data *data, struct cc_flow *flow, + str *dn, str *un); + +void free_cc_call(struct cc_data *data, struct cc_call *call); + +struct cc_agent* get_free_agent_by_skill(struct cc_data *data, + unsigned int skill); + +void log_agent_to_flows(struct cc_data *data, struct cc_agent *agent, + int login); + +void clean_cc_old_data(struct cc_data *data); + +void clean_cc_unref_data(struct cc_data *data); + +void cc_queue_push_call(struct cc_data *data, struct cc_call *call, int top); + +struct cc_call *cc_queue_pop_call_for_agent(struct cc_data *data, + struct cc_agent *agent); + +void cc_queue_rmv_call( struct cc_data *data, struct cc_call *call); + + +static inline void remove_cc_agent(struct cc_data* data, + struct cc_agent* agent, struct cc_agent* prev_agent) +{ + struct cc_agent* tmp_agent; + if(prev_agent == agent) /* if on top of the list*/ + data->agents[agent->loged_in] = agent->next; + else + prev_agent->next = agent->next; + + if(agent->loged_in && data->last_online_agent == agent) {/* if agent was the last in the list */ + if(data->agents[CC_AG_ONLINE] == NULL) + data->last_online_agent = NULL; + else { + if(prev_agent == agent) { + LM_CRIT("last_online_agent pointer not correct" + "- pointing to the first record in list but next not NULL\n"); + /* search for the real last */ + for(tmp_agent= data->agents[CC_AG_ONLINE]; tmp_agent; tmp_agent= tmp_agent->next) + data->last_online_agent = tmp_agent; + } + else + data->last_online_agent = prev_agent; + } + } +} + + +static inline void add_cc_agent_top( struct cc_data *data, struct cc_agent *agent) +{ + agent->next = data->agents[agent->loged_in]; + data->agents[agent->loged_in] = agent; +} + + +static inline void agent_switch_login(struct cc_data* data, + struct cc_agent* agent, struct cc_agent* prev_agent) +{ + /* take out of the current list */ + remove_cc_agent(data, agent, prev_agent); + agent->loged_in ^= 1; + /* add on top of the new one */ + add_cc_agent_top(data, agent); +} + +#endif diff --git a/modules/call_center/cc_db.c b/modules/call_center/cc_db.c new file mode 100755 index 00000000000..ade75b1bf9e --- /dev/null +++ b/modules/call_center/cc_db.c @@ -0,0 +1,803 @@ +/* + * call center module - call queuing and distribution + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + */ + + + + +#include "../../globals.h" +#include "../../db/db.h" +#include "../b2b_logic/b2b_load.h" +#include "cc_db.h" + +#define CC_FETCH_ROWS 100 + +str cc_flow_table_name = str_init(CC_FLOW_TABLE_NAME); +str ccf_flowid_column = str_init(CCF_FLOWID_COL); +str ccf_priority_column = str_init(CCF_PRIORITY_ID_COL); +str ccf_skill_column = str_init(CCF_SKILL_COL); +str ccf_cid_column = str_init(CCF_CID_COL); +str ccf_m_welcome_column = str_init(CCF_WELCOME_COL); +str ccf_m_queue_column = str_init(CCF_M_QUEUE_COL); + +str cc_agent_table_name = str_init(CC_AGENT_TABLE_NAME); +str cca_agentid_column = str_init(CCA_AGENTID_COL); +str cca_location_column = str_init(CCA_LOCATION_ID_COL); +str cca_skills_column = str_init(CCA_SKILLS_COL); +str cca_logstate_column = str_init(CCA_LOGSTATE_COL); +str cca_lastcallend_column = str_init(CCA_LASTCALLEND_COL); + +str cc_globals_table_name = str_init(CC_GLOBALS_TABLE_NAME); +str ccg_name_column = str_init(CCG_NAME_COL); +str ccg_value_column = str_init(CCG_VALUE_COL); + +str cc_cdrs_table_name = str_init(CC_CDRS_TABLE_NAME); +str ccc_caller_column = str_init(CCC_CALLER_COL); +str ccc_recv_time_column = str_init(CCC_RECV_TIME_COL); +str ccc_wait_time_column = str_init(CCC_WAIT_TIME_COL); +str ccc_talk_time_column = str_init(CCC_TALK_TIME_COL); +str ccc_pickup_time_column = str_init(CCC_PICKUP_TIME_COL); +str ccc_flow_id_column = str_init(CCC_FLOW_ID_COL); +str ccc_agent_id_column = str_init(CCC_AGENT_ID_COL); +str ccc_cc_id_column = str_init(CCC_CC_ID_COL); +str ccc_type_column = str_init(CCC_TYPE_COL); +str ccc_rejected_column = str_init(CCC_REJECTED_COL); +str ccc_fstats_column = str_init(CCC_FSTATS_COL); +str ccc_cid_column = str_init(CCC_CID_COL); + +str cc_calls_table_name = str_init(CC_CALLS_TABLE_NAME); +str ccq_state_column = str_init(CCQ_STATE_COL); +str ccq_ig_cback_column = str_init(CCQ_IGCBACK_COL); +str ccq_no_rej_column = str_init(CCQ_NOREJ_COL); +str ccq_setup_time_column = str_init(CCQ_SETUP_TIME_COL); +str ccq_eta_column = str_init(CCQ_ETA_COL); +str ccq_last_start_column = str_init(CCQ_LAST_START_COL); +str ccq_recv_time_column = str_init(CCQ_RECV_TIME_COL); +str ccq_caller_dn_column = str_init(CCQ_CALLER_DN_COL); +str ccq_caller_un_column = str_init(CCQ_CALLER_UN_COL); +str ccq_b2buaid_column = str_init(CCQ_B2BUAID_COL); +str ccq_flow_column = str_init(CCQ_FLOW_COL); +str ccq_agent_column = str_init(CCQ_AGENT_COL); +#define CCQ_COLS_NO 12 + +static db_con_t* cc_db_handle = 0; /* database connection handle */ +static db_con_t* cc_acc_db_handle = 0; /* database connection handle */ +static db_func_t cc_dbf; +static db_func_t cc_acc_dbf; +extern b2bl_api_t b2b_api; + + +#define check_val( _val, _type, _not_null, _is_empty_str, _c) \ + do{\ + if ((_val)->type!=_type) { \ + LM_ERR("bad column type: %s [%d/%d]\n", _c, (_val)->type, _type);\ + goto error;\ + } \ + if (_not_null && (_val)->nul) { \ + LM_ERR("nul column: %s\n", _c);\ + goto error;\ + } \ + if (_is_empty_str && VAL_STRING(_val)==0) { \ + LM_ERR("empty str column: %s\n", _c);\ + goto error;\ + } \ + }while(0) + + +int cc_connect_db(const str *db_url) +{ + if (cc_db_handle) { + LM_CRIT("BUG - db connection found already open\n"); + return -1; + } + if ((cc_db_handle = cc_dbf.init(db_url)) == 0) + return -1; + + return 0; +} + +int cc_connect_acc_db(const str *acc_db_url) +{ + if (cc_acc_db_handle) { + LM_CRIT("BUG - db connection found already open\n"); + return -1; + } + if ((cc_acc_db_handle = cc_acc_dbf.init(acc_db_url)) == 0) + return -1; + + return 0; +} + +void cc_close_db(void) +{ + if (cc_db_handle==NULL) + return; + + cc_dbf.close(cc_db_handle); + cc_db_handle = NULL; +} + + +int init_cc_db(const str *db_url) +{ + /* Find a database module */ + if (db_bind_mod(db_url, &cc_dbf) < 0){ + LM_ERR("Unable to bind to a database driver\n"); + return -1; + } + + if (cc_connect_db(db_url)!=0){ + LM_ERR("unable to connect to the database\n"); + return -1; + } + + if(db_check_table_version(&cc_dbf, cc_db_handle, + &cc_flow_table_name, CC_FLOW_TABLE_VERSION) < 0) { + LM_ERR("error during FLOW table version check.\n"); + return -1; + } + + if(db_check_table_version(&cc_dbf, cc_db_handle, + &cc_agent_table_name, CC_AGENT_TABLE_VERSION) < 0) { + LM_ERR("error during AGENT table version check.\n"); + return -1; + } + + return 0; +} + + +int init_cc_acc_db(const str *acc_db_url) +{ + /* Find a database module */ + if (db_bind_mod(acc_db_url, &cc_acc_dbf) < 0){ + LM_ERR("Unable to bind to a database driver\n"); + return -1; + } + return 0; +} + + +int cc_db_delete_call(struct cc_call *call) +{ + db_key_t qcols[1]; + db_val_t qvals[1]; + + if(cc_dbf.use_table( cc_db_handle, &cc_calls_table_name) < 0) + { + LM_ERR("SQL use table for %.*s table failed\n", + cc_calls_table_name.len, cc_calls_table_name.s); + return -1; + } + + qcols[0] = &ccq_b2buaid_column; + qvals[0].type = DB_STR; + qvals[0].nul = 0; + qvals[0].val.str_val = call->b2bua_id; + + if(cc_dbf.delete(cc_db_handle, qcols, 0, qvals, 1) < 0) { + LM_ERR("unsuccessful sql delete operation"); + return -1; + } + LM_DBG("Deleted call %.*s\n", call->b2bua_id.len, call->b2bua_id.s); + return 0; +} + +int cc_db_update_call(struct cc_call *call) +{ + db_key_t qcols[1]; + db_key_t ucols[5]; + db_val_t qvals[1]; + db_val_t uvals[5]; + + if(cc_dbf.use_table( cc_db_handle, &cc_calls_table_name) < 0) { + LM_ERR("SQL use table for %.*s table failed\n", + cc_calls_table_name.len, cc_calls_table_name.s); + return -1; + } + + memset(&uvals, 0, 5*sizeof(db_val_t)); + + qcols[0] = &ccq_b2buaid_column; + qvals[0].type = DB_STR; + qvals[0].val.str_val = call->b2bua_id; + + ucols[0] = &ccq_state_column; + uvals[0].type = DB_INT; + uvals[0].val.int_val = call->state; + ucols[1] = &ccq_ig_cback_column; + uvals[1].type = DB_INT; + uvals[1].val.int_val = call->ign_cback; + ucols[2] = &ccq_no_rej_column; + uvals[2].type = DB_INT; + uvals[2].val.int_val = call->no_rejections; + ucols[3] = &ccq_last_start_column; + uvals[3].type = DB_INT; + uvals[3].val.int_val = call->last_start; + ucols[4] = &ccq_agent_column; + uvals[4].type = DB_STR; + if(call->agent) + uvals[4].val.str_val = call->agent->id; + + if( cc_dbf.update(cc_db_handle, qcols, 0, qvals, + ucols, uvals, 1, 5)<0) + { + LM_ERR("updating call record in database\n"); + return -1; + } + LM_DBG("updated call in db\n"); + return 0; +} + + +int cc_db_insert_call(struct cc_call *call) +{ + db_key_t columns[CCQ_COLS_NO]; + db_val_t vals[CCQ_COLS_NO]; + + if(cc_dbf.use_table( cc_db_handle, &cc_calls_table_name) < 0) + { + LM_ERR("SQL use table for %.*s table failed\n", + cc_calls_table_name.len, cc_calls_table_name.s); + return -1; + } + + memset(&vals, 0, CCQ_COLS_NO*sizeof(db_val_t)); + + columns[0] = &ccq_state_column; + vals[0].type = DB_INT; + vals[0].val.int_val = call->state; + columns[1] = &ccq_ig_cback_column; + vals[1].type = DB_INT; + vals[1].val.int_val = call->ign_cback; + columns[2] = &ccq_no_rej_column; + vals[2].type = DB_INT; + vals[2].val.int_val = call->no_rejections; + columns[3] = &ccq_setup_time_column; + vals[3].type = DB_INT; + vals[3].val.int_val = call->setup_time; + columns[4] = &ccq_eta_column; + vals[4].type = DB_INT; + vals[4].val.int_val = call->eta; + columns[5] = &ccq_last_start_column; + vals[5].type = DB_INT; + vals[5].val.int_val = call->last_start; + columns[6] = &ccq_recv_time_column; + vals[6].type = DB_INT; + vals[6].val.int_val = call->recv_time; + columns[7] = &ccq_caller_dn_column; + vals[7].type = DB_STR; + vals[7].val.str_val = call->caller_dn; + columns[8] = &ccq_caller_un_column; + vals[8].type = DB_STR; + vals[8].val.str_val = call->caller_un; + columns[9] = &ccq_b2buaid_column; + vals[9].type = DB_STR; + vals[9].val.str_val = call->b2bua_id; + columns[10] = &ccq_flow_column; + vals[10].type = DB_STR; + vals[10].val.str_val = call->flow->id; + columns[11] = &ccq_agent_column; + vals[11].type = DB_STR; + if(call->agent) + vals[11].val.str_val = call->agent->id; + + if (cc_dbf.insert(cc_db_handle, columns, vals, CCQ_COLS_NO) < 0) { + LM_ERR("inserting new record in database\n"); + return -1; + } + LM_DBG("inserted call in db\n"); + return 0; +} + +int cc_db_restore_calls( struct cc_data *data) +{ + db_key_t columns[CCQ_COLS_NO]; + db_res_t* res; + db_row_t* row; + str s; + struct cc_flow *flow; + struct cc_call *call; + int i; + struct cc_agent *agent = NULL; + struct cc_agent *prev; + str dn, un; + str id; + + cc_dbf.use_table( cc_db_handle, &cc_calls_table_name); + + columns[0] = &ccq_state_column; + columns[1] = &ccq_ig_cback_column; + columns[2] = &ccq_no_rej_column; + columns[3] = &ccq_setup_time_column; + columns[4] = &ccq_eta_column; + columns[5] = &ccq_last_start_column; + columns[6] = &ccq_recv_time_column; + columns[7] = &ccq_caller_dn_column; + columns[8] = &ccq_caller_un_column; + columns[9] = &ccq_b2buaid_column; + columns[10] = &ccq_flow_column; + columns[11] = &ccq_agent_column; + + if ( cc_dbf.query( cc_db_handle, 0, 0, 0, columns, 0, + CCQ_COLS_NO, 0, &res)<0) { + LM_ERR("DB query failed\n"); + return -1; + } + + + if (RES_ROW_N(res) == 0) { + LM_DBG("No calls restored\n"); + return 0; + } + + LM_DBG("%d records found in %.*s\n", + RES_ROW_N(res), cc_calls_table_name.len,cc_calls_table_name.s ); + + for(i= RES_ROW_N(res)-1; i>= 0; i--) { + row = RES_ROWS(res) + i; + + /* FLOW_COL */ + check_val( ROW_VALUES(row)+10, DB_STRING, 1, 1, "flow"); + s.s = (char*)VAL_STRING(ROW_VALUES(row)+10); + s.len = strlen(s.s); + flow = get_flow_by_name(data, &s); + if (flow==NULL) { + LM_ERR("flow <%.*s> does not exists\n", s.len, s.s); + continue; + } + LM_DBG("using call flow %p\n", flow); + + /* CALLER_DN_COL */ + check_val( ROW_VALUES(row)+7, DB_STRING, 1, 0, "caller_dn"); + dn.s = (char*)VAL_STRING(ROW_VALUES(row)+7); + if(dn.s) + dn.len = strlen(dn.s); + /* CALLER_UN_COL */ + check_val( ROW_VALUES(row)+8, DB_STRING, 1, 0, "caller_un"); + un.s = (char*)VAL_STRING(ROW_VALUES(row)+8); + if(un.s) + un.len = strlen(un.s); + + call = new_cc_call(data, flow, &dn, &un); + if (call==NULL) { + LM_ERR("failed to create new call\n"); + goto error; + } + + /* AGENT_COL */ + check_val( ROW_VALUES(row)+11, DB_STRING, 0, 0, "agent"); + s.s = (char*)VAL_STRING(ROW_VALUES(row)+11); + if(s.s && strlen(s.s)) { + s.len = strlen(s.s); + /* name of the agent */ + agent = get_agent_by_name(data, &s, &prev); + if (agent==NULL) { + LM_ERR("Agent <%.*s> does not exists\n", s.len, s.s); + continue; + } + call->agent = agent; + agent->state = CC_AGENT_INCALL; + agent->ref_cnt++; + } + + /* STATE_COL */ + check_val( ROW_VALUES(row), DB_INT, 1, 0, "state"); + call->state = VAL_INT(ROW_VALUES(row)); + /* IGCBACK_COL */ + check_val( ROW_VALUES(row)+1, DB_INT, 1, 0, "ig_cback"); + call->ign_cback = VAL_INT(ROW_VALUES(row)+1); + /* NOREJ_COL */ + check_val( ROW_VALUES(row)+2, DB_INT, 1, 0, "no_rej"); + call->no_rejections = VAL_INT(ROW_VALUES(row)+2); + /* SETUP_TIME_COL */ + check_val( ROW_VALUES(row)+3, DB_INT, 1, 0, "setup_time"); + call->setup_time = VAL_INT(ROW_VALUES(row)+3); + /* ETA_COL */ + check_val( ROW_VALUES(row)+4, DB_INT, 1, 0, "eta"); + call->eta = VAL_INT(ROW_VALUES(row)+4); + /* LAST_START_COL */ + check_val( ROW_VALUES(row)+5, DB_INT, 1, 0, "last_start"); + call->last_start = VAL_INT(ROW_VALUES(row)+5); + /* RECV_TIME_COL */ + check_val( ROW_VALUES(row)+6, DB_INT, 1, 0, "recv_time"); + call->recv_time = VAL_INT(ROW_VALUES(row)+6); + /* B2BUAID_COL */ + check_val( ROW_VALUES(row)+9, DB_STRING, 1, 1, "b2buaid"); + id.s = (char*)VAL_STRING(ROW_VALUES(row)+9); + if(id.s) { + id.len = strlen(id.s); + call->b2bua_id.len = id.len; + call->b2bua_id.s = (char*)shm_malloc(id.len); + if(call->b2bua_id.s == NULL) { + LM_ERR("No more memory\n"); + goto error; + } + memcpy(call->b2bua_id.s, id.s, id.len); + call->ref_cnt++; + + /* restore logic info */ + if(b2b_api.restore_upper_info(&call->b2bua_id, b2bl_callback_customer, call, + B2B_DESTROY_CB|B2B_REJECT_CB|B2B_BYE_CB)< 0) + { + /* delete the call*/ + LM_ERR("Upper info not found for [%.*s]\n", id.len, id.s); + free_cc_call( data, call); + continue; + } + } + + if(call->state == CC_CALL_QUEUED) { + cc_queue_push_call( data, call, 0); + call->ref_cnt++; + } + } + LM_DBG("Restored calls\n"); + return 0; + +error: + return -1; +} + + +int cc_load_db_data( struct cc_data *data) +{ + db_key_t columns[6]; + db_res_t* res; + db_row_t* row; + int i, j, n; + str id,skill,cid; + str location; + unsigned int priority, logstate, last_call_end; + str messages[MAX_AUDIO]; + + cc_dbf.use_table( cc_db_handle, &cc_flow_table_name); + + columns[0] = &ccf_flowid_column; + columns[1] = &ccf_priority_column; + columns[2] = &ccf_skill_column; + columns[3] = &ccf_cid_column; + columns[4] = &ccf_m_welcome_column; + columns[5] = &ccf_m_queue_column; + + if (0/*DB_CAPABILITY(cc_dbf, DB_CAP_FETCH))*/) { + if ( cc_dbf.query( cc_db_handle, 0, 0, 0, columns, 0, 6, 0, 0 ) < 0) { + LM_ERR("DB query failed\n"); + return -1; + } + if(cc_dbf.fetch_result( cc_db_handle, &res, CC_FETCH_ROWS)<0) { + LM_ERR("Error fetching rows\n"); + return -1; + } + } else { + if ( cc_dbf.query( cc_db_handle, 0, 0, 0, columns, 0, 6, 0, &res)<0) { + LM_ERR("DB query failed\n"); + return -1; + } + } + + if (RES_ROW_N(res) == 0) { + LM_WARN("table \"%.*s\" empty\n", cc_flow_table_name.len, + cc_flow_table_name.s ); + return -1; + } + + LM_DBG("%d records found in %.*s\n", + RES_ROW_N(res), cc_flow_table_name.len,cc_flow_table_name.s ); + n = 0; + + do { + for(i=0; i < RES_ROW_N(res); i++) { + row = RES_ROWS(res) + i; + /* flowID column */ + check_val( ROW_VALUES(row), DB_STRING, 1, 1, "flowid"); + id.s = (char*)VAL_STRING(ROW_VALUES(row)); + id.len = strlen(id.s); + /* PRIORITY column */ + check_val( ROW_VALUES(row)+1, DB_INT, 1, 0, "priority"); + priority = VAL_INT(ROW_VALUES(row)+1); + /* SKILL column */ + check_val( ROW_VALUES(row)+2, DB_STRING, 1, 1, "skill"); + skill.s = (char*)VAL_STRING(ROW_VALUES(row)+2); + skill.len = strlen(skill.s); + /* CID column */ + check_val( ROW_VALUES(row)+3, DB_STRING, 0, 0, "prependcid"); + if (VAL_NULL(ROW_VALUES(row)+3)) { + cid.s = NULL; cid.len = 0; + } else { + cid.s = (char*)VAL_STRING(ROW_VALUES(row)+3); + if (cid.s==NULL || (cid.len=strlen(cid.s))==0 ) { + cid.s = NULL; cid.len = 0; + } + } + for( j=0 ; j skipping\n", + id.len,id.s); + continue; + } + n++; + } + if (DB_CAPABILITY( cc_dbf, DB_CAP_FETCH)) { + if(cc_dbf.fetch_result(cc_db_handle, &res, CC_FETCH_ROWS)<0) { + LM_ERR( "fetching rows (1)\n"); + return -1; + } + } else { + break; + } + } while(RES_ROW_N(res)>0); + + cc_dbf.free_result(cc_db_handle, res); + res = 0; + + + cc_dbf.use_table( cc_db_handle, &cc_agent_table_name); + + columns[0] = &cca_agentid_column; + columns[1] = &cca_location_column; + columns[2] = &cca_skills_column; + columns[3] = &cca_logstate_column; + columns[4] = &cca_lastcallend_column; + + if (0/*DB_CAPABILITY(cc_dbf, DB_CAP_FETCH))*/) { + if ( cc_dbf.query( cc_db_handle, 0, 0, 0, columns, 0, 5, 0, 0 ) < 0) { + LM_ERR("DB query failed\n"); + return -1; + } + if(cc_dbf.fetch_result( cc_db_handle, &res, CC_FETCH_ROWS)<0) { + LM_ERR("Error fetching rows\n"); + return -1; + } + } else { + if ( cc_dbf.query( cc_db_handle, 0, 0, 0, columns, 0, 5, 0, &res)<0) { + LM_ERR("DB query failed\n"); + return -1; + } + } + + if (RES_ROW_N(res) == 0) { + LM_WARN("table \"%.*s\" empty\n", cc_agent_table_name.len, + cc_agent_table_name.s ); + return -1; + } + + LM_DBG("%d records found in %.*s\n", + RES_ROW_N(res), cc_agent_table_name.len,cc_agent_table_name.s ); + n = 0; + + do { + for(i=0; i < RES_ROW_N(res); i++) { + row = RES_ROWS(res) + i; + /* agentID column */ + check_val( ROW_VALUES(row), DB_STRING, 1, 1, "agentid"); + id.s = (char*)VAL_STRING(ROW_VALUES(row)); + id.len = strlen(id.s); + /* LOCATION column */ + check_val( ROW_VALUES(row)+1, DB_STRING, 1, 1, "location"); + location.s = (char*)VAL_STRING(ROW_VALUES(row)+1); + location.len = strlen(location.s); + /* SKILLS column */ + check_val( ROW_VALUES(row)+2, DB_STRING, 1, 1, "skills"); + skill.s = (char*)VAL_STRING(ROW_VALUES(row)+2); + skill.len = strlen(skill.s); + /* LOGSTATE column */ + check_val( ROW_VALUES(row)+3, DB_INT, 1, 0, "logstate"); + logstate = VAL_INT(ROW_VALUES(row)+3); + /* LAST_CALL_END column */ + last_call_end = VAL_INT(ROW_VALUES(row)+4); + + /* add agent */ + if (add_cc_agent(data,&id,&location,&skill,logstate,last_call_end)<0){ + LM_ERR("failed to add agent %.*s -> skipping\n", + id.len,id.s); + continue; + } + n++; + } + if (DB_CAPABILITY( cc_dbf, DB_CAP_FETCH)) { + if(cc_dbf.fetch_result(cc_db_handle, &res, CC_FETCH_ROWS)<0) { + LM_ERR( "fetching rows (1)\n"); + return -1; + } + } else { + break; + } + } while(RES_ROW_N(res)>0); + + cc_dbf.free_result(cc_db_handle, res); + res = 0; + + return 0; +error: + if (res) + cc_dbf.free_result(cc_db_handle, res); + return -1; +} + + +int prepare_cdr(struct cc_call *call, str *un, str *fid , str *aid) +{ + #define CDR_BUF_LEN 2048 + #define CDR_ITEM_LEN(_a) ( (p+_a>buf+CDR_BUF_LEN) ? buf+CDR_BUF_LEN-p : _a ) + static char buf[CDR_BUF_LEN+1]; + char *p = buf; + + un->len = CDR_ITEM_LEN(call->caller_un.len); + un->s = p; + if (un->len) { + memcpy( p, call->caller_un.s, un->len ); + p += un->len; + } + + fid->len = CDR_ITEM_LEN(call->flow->id.len); + fid->s = p; + if (fid->len) { + memcpy( p, call->flow->id.s, fid->len ); + p += fid->len; + } + + if (call->agent) { + aid->len = CDR_ITEM_LEN(call->agent->id.len); + aid->s = p; + if (aid->len) { + memcpy( p, call->agent->id.s, aid->len ); + p += aid->len; + } + } else { + aid->s = NULL; + aid->len = 0; + } + + return 0; +} + + +int cc_write_cdr( str *un, str *fid, str *aid, int type, int rt, int wt, int tt, int pt, int rej, int fst, int cid) +{ + db_key_t columns[11]; + db_val_t vals[11]; + static db_ps_t my_ps = NULL; + + cc_acc_dbf.use_table( cc_acc_db_handle, &cc_cdrs_table_name); + + columns[0] = &ccc_caller_column; + columns[1] = &ccc_recv_time_column; + columns[2] = &ccc_wait_time_column; + columns[3] = &ccc_talk_time_column; + columns[4] = &ccc_pickup_time_column; + columns[5] = &ccc_flow_id_column; + columns[6] = &ccc_agent_id_column; + columns[7] = &ccc_type_column; + columns[8] = &ccc_rejected_column; + columns[9]= &ccc_fstats_column; + columns[10]= &ccc_cid_column; + + /* caller */ + vals[0].nul = 0; + vals[0].type = DB_STR; + vals[0].val.str_val = *un; + + /* received timestamp */ + vals[1].nul = 0; + vals[1].type = DB_DATETIME; + vals[1].val.time_val = startup_time + rt; + + /* wait time */ + vals[2].nul = 0; + vals[2].type = DB_INT; + vals[2].val.int_val = wt; + + /* talk time */ + vals[3].nul = 0; + vals[3].type = DB_INT; + vals[3].val.int_val = tt; + + /* pickup time */ + vals[4].nul = 0; + vals[4].type = DB_INT; + vals[4].val.int_val = pt; + + /* flow ID */ + vals[5].nul = 0; + vals[5].type = DB_STR; + vals[5].val.str_val = *fid; + + /* agent ID */ + vals[6].type = DB_STR; + if (aid->len==0) { + vals[6].nul = 1; + } else { + vals[6].nul = 0; + vals[6].val.str_val = *aid; + } + + /* type */ + vals[7].nul = 0; + vals[7].type = DB_INT; + vals[7].val.int_val = type; + + /* rej */ + vals[8].nul = 0; + vals[8].type = DB_INT; + vals[8].val.int_val = rej; + + /* fstat */ + vals[9].nul = 0; + vals[9].type = DB_INT; + vals[9].val.int_val = fst; + + /* cid */ + vals[10].nul = 0; + vals[10].type = DB_INT; + vals[10].val.int_val = cid; + + CON_PS_REFERENCE(cc_acc_db_handle) = &my_ps; + + if (cc_acc_dbf.insert( cc_acc_db_handle, columns, vals, 11) < 0) { + LM_ERR("CDR insert failed\n"); + return -1; + } + + return 0; +} + + +void cc_db_update_agent_end_call(struct cc_agent* agent) +{ + db_key_t columns[2]; + db_val_t vals[2]; + + columns[0] = &cca_agentid_column; + columns[1] = &cca_lastcallend_column; + + vals[0].nul = 0; + vals[0].type = DB_STR; + vals[0].val.str_val = agent->id; + + vals[1].nul = 0; + vals[1].type = DB_INT; + vals[1].val.int_val = (int)time(NULL); + + cc_dbf.use_table( cc_db_handle, &cc_agent_table_name); + + if (cc_dbf.update( cc_db_handle, columns, 0, vals, columns+1, vals+1, 1, 1) < 0) { + LM_ERR("Agent update failed\n"); + } +} + diff --git a/modules/call_center/cc_db.h b/modules/call_center/cc_db.h new file mode 100755 index 00000000000..ff0e07c721e --- /dev/null +++ b/modules/call_center/cc_db.h @@ -0,0 +1,109 @@ +/* + * call center module - call queuing and distribution + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + */ + + + +#ifndef CC_CC_DB_H_ +#define CC_CC_DB_H_ + +#include "../../str.h" +#include "cc_data.h" + + +#define CC_FLOW_TABLE_NAME "cc_flows" +#define CC_FLOW_TABLE_VERSION 1 +#define CCF_FLOWID_COL "flowid" +#define CCF_PRIORITY_ID_COL "priority" +#define CCF_SKILL_COL "skill" +#define CCF_CID_COL "prependcid" +#define CCF_WELCOME_COL "message_welcome" +#define CCF_M_QUEUE_COL "message_queue" + +#define CC_AGENT_TABLE_NAME "cc_agents" +#define CC_AGENT_TABLE_VERSION 1 +#define CCA_AGENTID_COL "agentid" +#define CCA_LOCATION_ID_COL "location" +#define CCA_SKILLS_COL "skills" +#define CCA_LOGSTATE_COL "logstate" +#define CCA_LASTCALLEND_COL "last_call_end" + +#define CC_GLOBALS_TABLE_NAME "cc_globals" +#define CC_GLOBALS_TABLE_VERSION 1 +#define CCG_NAME_COL "name" +#define CCG_VALUE_COL "value" + +#define CC_CDRS_TABLE_NAME "cc_cdrs" +#define CCC_CALLER_COL "caller" +#define CCC_RECV_TIME_COL "received_timestamp" +#define CCC_WAIT_TIME_COL "wait_time" +#define CCC_TALK_TIME_COL "talk_time" +#define CCC_PICKUP_TIME_COL "pickup_time" +#define CCC_FLOW_ID_COL "flow_id" +#define CCC_AGENT_ID_COL "agent_id" +#define CCC_CC_ID_COL "callcenter_id" +#define CCC_TYPE_COL "call_type" +#define CCC_REJECTED_COL "rejected" +#define CCC_FSTATS_COL "fstats" +#define CCC_CID_COL "cid" + +#define CC_CALLS_TABLE_NAME "cc_calls" +#define CCQ_STATE_COL "state" +#define CCQ_IGCBACK_COL "ig_cback" +#define CCQ_NOREJ_COL "no_rej" +#define CCQ_SETUP_TIME_COL "setup_time" +#define CCQ_ETA_COL "eta" +#define CCQ_LAST_START_COL "last_start" +#define CCQ_RECV_TIME_COL "recv_time" +#define CCQ_CALLER_DN_COL "caller_dn" +#define CCQ_CALLER_UN_COL "caller_un" +#define CCQ_B2BUAID_COL "b2buaid" +#define CCQ_FLOW_COL "flow" +#define CCQ_AGENT_COL "agent" +#define CCQ_QID_COL "qid" + +int init_cc_db(const str *db_url); +int init_cc_acc_db(const str *acc_db_url); + +int cc_connect_db(const str *db_url); +int cc_connect_acc_db(const str *acc_db_url); + +void cc_close_db(void); + +int cc_load_db_data( struct cc_data *data); + +int cc_write_cdr( str *un, str *fid, str *aid, int type, + int rt, int wt, int tt , int pt, int rej, int fst, int cid); + +int prepare_cdr(struct cc_call *call, str *un, str *fid , str *aid); + +int cc_db_insert_call(struct cc_call *call); +int cc_db_update_call(struct cc_call *call); +int cc_db_delete_call(struct cc_call *call); +int cc_db_restore_calls( struct cc_data *data); +void cc_db_update_agent_end_call(struct cc_agent* agent); +int b2bl_callback_customer(b2bl_cb_params_t *params, unsigned int event); +int b2bl_callback_agent(b2bl_cb_params_t *params, unsigned int event); + +#endif diff --git a/modules/call_center/cc_queue.c b/modules/call_center/cc_queue.c new file mode 100644 index 00000000000..f6240269d63 --- /dev/null +++ b/modules/call_center/cc_queue.c @@ -0,0 +1,113 @@ +/* + * call center module - call queuing and distribution + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-03-17 initial version (bogdan) + */ + +#include "cc_queue.h" + +extern stat_var *stg_terminated_calls; +extern stat_var *stg_dist_incalls; + + +/* this function must be call under + * 1) general data lock as it accesses diverent data to calculate the next state + * 2) call lock as it is changing the call state + */ +int cc_call_state_machine(struct cc_data *data, struct cc_call *call, + str *leg) +{ + struct cc_agent *agent; + str *out = NULL; + int state =0; + + switch (call->state) { + case CC_CALL_NONE: + /* next should be welcome msg if any */ + if ( call->flow->recordings[ AUDIO_WELCOME ].len ) { + LM_DBG("selecting WELCOME\n"); + out = &(call->flow->recordings[ AUDIO_WELCOME ]); + state = CC_CALL_WELCOME; + break; + } + /* no Welcome message -> got for queue/agent */ + case CC_CALL_WELCOME: + case CC_CALL_QUEUED: + /* search for an available agent */ + agent = get_free_agent_by_skill( data, call->flow->skill); + if (agent) { + /* send it to agent */ + LM_DBG("selecting AGENT %p (%.*s)\n",agent, + agent->id.len, agent->id.s); + state = CC_CALL_TOAGENT; + out = &agent->location; + LM_DBG("moved to TOAGENT from %d, out=%p\n", call->state, out); + /* mark agent as used */ + agent->state = CC_AGENT_INCALL; + call->agent = agent; + call->agent->ref_cnt++; + update_stat( stg_dist_incalls, 1); + update_stat( call->flow->st_dist_incalls, 1); + call->fst_flags |= FSTAT_DIST; + update_stat( call->agent->st_dist_incalls, +1); + break; + } else { + /* put it into queue */ + LM_DBG("selecting QUEUE\n"); + out = &(call->flow->recordings[AUDIO_QUEUE]); + state = CC_CALL_QUEUED; + if(call->state == CC_CALL_QUEUED) { + LM_DBG("State is already queued %p\n", call); + break; + } + /* add it to queue */ + cc_queue_push_call( data, call, 0); + } + break; + case CC_CALL_TOAGENT: + case CC_CALL_ENDED: + LM_DBG("selecting END\n"); + call->state = CC_CALL_ENDED; + return 0; + default: + LM_CRIT("Bogus state [%p] [%d]\n", call, call->state); + } + + if (out) { + leg->s = (char*)pkg_malloc( out->len ); + if (leg->s) { + leg->len = out->len; + memcpy(leg->s,out->s,out->len); + call->prev_state = call->state; + call->state = state; + return 0; + } + } + + leg->s = NULL; + leg->len = 0; + + return -1; +} + + diff --git a/modules/call_center/cc_queue.h b/modules/call_center/cc_queue.h new file mode 100644 index 00000000000..7cd550aff55 --- /dev/null +++ b/modules/call_center/cc_queue.h @@ -0,0 +1,37 @@ +/* + * call center module - call queuing and distribution + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-03-17 initial version (bogdan) + */ + +#ifndef _CALL_CENTER_CC_QUEUE +#define _CALL_CENTER_CC_QUEUE + +#include "cc_data.h" + +int cc_call_state_machine(struct cc_data *data, struct cc_call *call, + str *leg); + + +#endif + diff --git a/modules/call_center/doc/call_center.xml b/modules/call_center/doc/call_center.xml new file mode 100644 index 00000000000..3dd44a2cbb8 --- /dev/null +++ b/modules/call_center/doc/call_center.xml @@ -0,0 +1,47 @@ + + + + + + + +%docentities; + +]> + + + + Call-Center Module + &osipsname; + + + Bogdan-Andrei + Iancu +
+ bogdan@opensips.org +
+
+ + Bogdan-Andrei + Iancu +
+ bogdan@opensips.org +
+
+
+ + 2014 + &osipssol; + +
+ + + &admin; + &devel; + &faq; + +
diff --git a/modules/call_center/doc/call_center_admin.xml b/modules/call_center/doc/call_center_admin.xml new file mode 100644 index 00000000000..8ce4f73d7f1 --- /dev/null +++ b/modules/call_center/doc/call_center_admin.xml @@ -0,0 +1,676 @@ + + + + + &adminguide; + +
+ Overview + + The Call Center module implements an inbound call center system with call + flows (for queuing the received calls) and agents (for answering the + calls). + + + The module implements the queuing system, the call distribution + to agents, agents managements, CDRs for the calls, statistics on + call distribution and agent's activity - basically everything + except the media playback (for the queue). This part must be provided via + a third party media server (FreeSwitch, Asterisk or others). + +
+ +
+ How it works + + The main entities in the modules are the flows (queues) and agents. + +
+ DB tables + + Each entity has a corresponding table in the database, for + provisioning purposes - the cc_flows and + cc_agents tables, see + DB schema. + Data is loaded at startup and cached into memory ; runtime reload is + possible via the MI commands (see the cc_reload + command in ). + + + Additionally there is a table cc_cdrs for writing + the CDRs - this operation is done in realtime, after the call in + completed, covering all possible cases: call was dropped while in + queue, call was rejected by agent, call was accepted by agent, call + terminated with error - NOTE that a call may generate more than one + CDR (like call rejected by agent A, and redistributed and accepted by + agent B). + + + The cc_calls table is used to store ongoing calls, + regardless it's state (in queue, to the agent, ended). It is populated + at runtime by the module and queried at startup. This table should not + be manually provisioned. + +
+ +
+ Call Flows + + A flow is defined by a unique alphanumerical ID - the main attribute + of a flow is the skill - the skill is a + capability required by the flow for an agent to be able to answer the + call ; the concept of skills is the link between + the flows and the agents - telling what agents are serving what flows + - the flows require a skill, while the agents provide a set of skills. + Agents matching the required skill of a flow will automatically + receive calls from that flow. + + + Additional, the flow has a priority - as agents + may server multiple flows in the same time (based on skills), you can + define priorities between the flows - if the flows has a higher + priority, its calls will be pushed (in deliver to agents and queuing) in + front of the calls from flows with a lower priority. + + + Optionally, the flow may define a prependcid - a + prefix to be added to the CLI (Caller ID) when the call is delivered to + the agents - as an agent may receive call from multiple flows, it is + important for the user to see which was the queue a call was received. + + + In terms of media announcements, the flow defines the + message_welcome (optional, to be played in the + call, before doing anything with the call) and + message_queue (mandatory, the looping message + providing infinite on hold media IMPORTANT - this message must cycle + and media server must never hung up on it. Both announcements are + provided as SIP URIs (where the call has to be sent in order to get + the playback). + +
+ +
+ Agents + + An agent is defined by a unique alphanumerical ID - the main attribute + of an agent is its the set of skills and its SIP + location. The set of skills will tell what calls + to be received (from which flows, based on the skill matching); the + location is a SIP URI where to call must be sent in order to be + answered by the agent. + + + Additionally, the agent has a initial logstate - + if he is logged in or not (being logged in is a must in order to + receive calls). The log state may be changed at runtime via a + dedicated MI command cc_agent_login, see + . + + + There is a wrapup_time defined, saying the + time interval for an agent before getting a new call from the system + (after he finished a call). + +
+ +
+ + +
+ Dependencies +
+ &osips; Modules + + The following modules must be loaded before this module: + + + + b2b_logic - B2bUA module + + + + + database - one of the SQL DB modules + + + + +
+ + +
+ External Libraries or Applications + + The following libraries or applications must be installed before + running &osips; with this module loaded: + + + + None. + + + + +
+
+ + +
+ Exported Parameters + +
+ <varname>db_url</varname> (string) + + SQL address to the DB server -- database specific. This must be + the Database holding the provisioning tables (cc_flows, cc_agents + and cc_calls tables). + + If not explicitly set, the global OpenSIPS DB URL will be used. + + + + Set <varname>db_url</varname> parameter + +... +modparam("call_center", "db_url", + "mysql://opensips:opensipsrw@localhost/opensips") +... + + +
+ +
+ <varname>acc_db_url</varname> (string) + + SQL address to the DB server -- database specific. This must be + the Database where the CDRs table (cc_cdrs) is located. + + If not explicitly set, the global OpenSIPS DB URL will be used. + + + + Set <varname>acc_db_url</varname> parameter + +... +modparam("call_center", "acc_db_url", + "mysql://opensips:opensipsrw@localhost/opensips_cdrs") +... + + +
+ +
+ <varname>b2b_scenario</varname> (string) + + The name of the B2B scenario that is used by the module for handling + the calls in the queue. This is an advanced options and you should + not change it unless you really understand what you are doing. + + + The module provides an B2B scenario file + scenario_callcenter.xml located in the module + directory. The name of this scenario from this file (which must be + loaded via the b2b_logic module) must match the + b2b_scenario parameter. + + + Default value is call center. + + + + Set <varname>b2b_scenario</varname> parameter + +... +modparam("b2b_logic", "script_scenario", "/etc/opensips/scenario_callcenter.xml") +modparam("call_center", "b2b_scenario", "call center") +... + + +
+ +
+ <varname>wrapup_time</varname> (integer) + + Time for an agent between finishing a call and receiving the next + call from the system. Even if there are queued calls, the module + will not deliver call to agent during this wrapup interval. + + + Default value is 30 seconds. + + + + Set <varname>wrapup_time</varname> parameter + +... +modparam("call_center", "wrapup_time", 45) +... + + +
+ +
+ + +
+ Exported Functions +
+ + <function>cc_handle_call(flowID)</function> + + + This must be used only for initial INVITE requests - the function + pushes the call to be handled by the call center module (via a certain + flow/queue). + + + This function can be used from REQUEST_ROUTE. + + + The flowID mandatory parameter is + the ID of the flow to handle this call (push the call to that flow). + This can be a variable or a static string. + + + The function returns TRUE back to the script if the call was + successfully pushed and handled by the Call Center engine. IMPORTANT: + you must not do any signaling on the call (reply, relay) after this + point. + + + In case of error, FALSE is returned to the script with the following + return codes: + + + + -1 - unable to get the flow ID + from the parameter; + + + -2 - unable to parse the FROM URI; + + + -3 - flow with FlowID not found; + + + -4 - no agents logged in the flow; + + + -5 - internal error; + + + + <function>cc_handle_call</function> usage + +... +if (is_method("INVITE") and !has_totag()) { + if (!cc_handle_call("tech_support")) { + send_reply("403","Cannot handle call"); + exit; + } +} +... + + +
+ +
+ + <function>cc_agent_login(agentID, state)</function> + + + This function sets the login (on or off) state for an agent. + + + This function can be used from REQUEST_ROUTE. + + + The agentID mandatory parameter is + the ID of the agent and the state + is an integer value giving the new state - 0 means logged off, + anything else means logged in. + + + <function>cc_agent_login</function> usage + +... +# log off the 'agentX' agent +cc_agent_login("agentX","0"); +... + + +
+ +
+ + +
+ Exported Statistics + +
+ Global statistics +
+ ccg_incalls + + Total number of received calls. (counter type) + +
+ +
+ ccg_awt + + Global avg. waiting time for calls. (realtime type) + +
+ +
+ ccg_load + + Global load (across all flows). (realtime type) + +
+ +
+ ccg_distributed_incalls + + Total number of distributed calls. (counter type) + +
+ +
+ ccg_answered_incalls + + Total number of calls answered by agents. (counter type) + +
+ +
+ ccg_abandonned_incalls + + Total number of calls terminated by caller before being + answered by agents. (counter type) + +
+ +
+ ccg_onhold_calls + + Total number of calls in the queues (onhold). (realtime type) + +
+ +
+ ccg_free_agents + + Total number of free agents (across all flows). (realtime type) + +
+
+ +
+ Per-flow statistics (one set for each flow) +
+ ccf_incalls_flowID + + Number of received calls for the flow. (counter type) + +
+ +
+ ccf_dist_incalls_flowID + + Number of distributed calls in this flow. (counter type) + +
+ +
+ ccf_answ_incalls_flowID + + Nnumber of calls from the flow answered by agents. (counter type) + +
+ +
+ ccf_aban_incalls_flowID + + Number of calls (from the flow) terminated by caller before being + answered by agents. (counter type) + +
+ +
+ ccf_onhold_incalls_flowID + + Number of calls (from the flow) which were put onhold. + (counter type) + +
+ +
+ ccf_queued_calls_flowID + + Number of calls which are queued for this flow. (realtime type) + +
+ +
+ ccf_free_agents_flowID + + Number of free agents serving this flow. (realtime type) + +
+ +
+ ccf_etw_flowID + + Estimated Time to Wait for this flow. (realtime type) + +
+ +
+ ccf_awt_flowID + + Avg. Wating Time for this flow. (realtime type) + +
+ +
+ ccg_load_flowID + + The load on the flow (number of queued calls versus number of + logged agents). (realtime type) + +
+
+ +
+ Per-agent statistics (one set for each agent) +
+ cca_dist_incalls_agnetID + + Number of distributed calls to this agent. (counter type) + +
+ +
+ cca_answ_incalls_agentID + + Nnumber of calls answered by the agent. (counter type) + +
+ +
+ cca_aban_incalls_agentID + + Number of calls (sent to this agent) terminated by caller before + being answered by agents. (counter type) + +
+ +
+ cca_att_agentID + + Avg. Talk Time for this agent (realtime type) + +
+
+ +
+ + +
+ Exported MI Functions + +
+ + <function moreinfo="none">cc_reload</function> + + + Command to reload flows and agents definition from database. + + + It takes no parameter. + + + MI FIFO Command usage: + + +opensipsctl fifo cc_reload + +
+ +
+ + <function moreinfo="none">cc_agent_login</function> + + + Command to login an agent into the Call Center engine. + + + It takes two mandatory parameters, the ID of the agent and the + new login state (0 - log off, 1 - log in) + + + MI FIFO Command usage: + + +opensipsctl fifo cc_agent_login agentX 0 + +
+ +
+ + <function moreinfo="none">cc_list_queue</function> + + + Command to list all the calls in queuing - for each call, the + following attributes will be printed: the flow of the call, for how + long the call is in the queue, the ETW for the call, call priority + and the call skill (inherited from the flow). + + + It takes no parameter. + + + MI FIFO Command usage: + + +opensipsctl fifo cc_list_queue + +
+ +
+ + <function moreinfo="none">cc_list_flows</function> + + + Command to list all the flows - for each flow, the + following attributes will be printed: the flow ID, the avg. call + duration, how many calls were processed, how many agents are logged, + and how many onging calls are. + + + It takes no parameter. + + + MI FIFO Command usage: + + +opensipsctl fifo cc_list_flows + +
+ +
+ + <function moreinfo="none">cc_list_agents</function> + + + Command to list all the agents - for each agent, the + following attributes will be printed: agent ID, agent login state and + agent state (free, wrapup, incall). + + + It takes no parameter. + + + MI FIFO Command usage: + + +opensipsctl fifo cc_list_agents + +
+ +
+ + <function moreinfo="none">cc_list_calls</function> + + + Command to list all the ongoing calls - for each call, the + following attributes will be printed: call ID, call state + (welcome, queued, toagent, ended), call duration, flow it belongs to, + agent serving the call (if any). + + + It takes no parameter. + + + MI FIFO Command usage: + + +opensipsctl fifo cc_list_agents + +
+ +
+ + <function moreinfo="none">cc_reset_stats</function> + + + Command to reset all counter-like statistics. + + + It takes no parameter. + + + MI FIFO Command usage: + + +opensipsctl fifo cc_reset_stats + +
+ +
+ + +
+ Exported pseudo-variables + + NONE + +
+ + + +
+ diff --git a/modules/call_center/doc/call_center_devel.xml b/modules/call_center/doc/call_center_devel.xml new file mode 100644 index 00000000000..b96223d7dd6 --- /dev/null +++ b/modules/call_center/doc/call_center_devel.xml @@ -0,0 +1,14 @@ + + + + + &develguide; +
+ Available Functions + + NONE + +
+ +
+ diff --git a/modules/call_center/doc/call_center_faq.xml b/modules/call_center/doc/call_center_faq.xml new file mode 100644 index 00000000000..4b1c4df9306 --- /dev/null +++ b/modules/call_center/doc/call_center_faq.xml @@ -0,0 +1,58 @@ + + + + + &faqguide; + + + + Where can I find more about OpenSIPS? + + + + Take a look at &osipshomelink;. + + + + + + Where can I post a question about this module? + + + + First at all check if your question was already answered on one of + our mailing lists: + + + + User Mailing List - &osipsuserslink; + + + Developer Mailing List - &osipsdevlink; + + + + E-mails regarding any stable &osips; release should be sent to + &osipsusersmail; and e-mails regarding development versions + should be sent to &osipsdevmail;. + + + If you want to keep the mail private, send it to + &osipshelpmail;. + + + + + + How can I report a bug? + + + + Please follow the guidelines provided at: + &osipsbugslink;. + + + + + + diff --git a/modules/call_center/scenario_callcenter.xml b/modules/call_center/scenario_callcenter.xml new file mode 100644 index 00000000000..1366e466115 --- /dev/null +++ b/modules/call_center/scenario_callcenter.xml @@ -0,0 +1,18 @@ + + + + + + server1 + + + client1 + message + + 1 + + + + 1 + + diff --git a/modules/call_control/README b/modules/call_control/README index be8fcb25245..bfa84d8f6a4 100644 --- a/modules/call_control/README +++ b/modules/call_control/README @@ -18,8 +18,7 @@ Irina-Maria Stanescu Copyright © 2005-2008 Dan Pascu Revision History - Revision $Revision$ $Date: 2009-09-17 15:45:11 +0300 - (Thu, 17 Sep 2009) $ + Revision $Revision: 6149 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/call_control/call_control.c b/modules/call_control/call_control.c index 242a22ff641..2002044d1cb 100644 --- a/modules/call_control/call_control.c +++ b/modules/call_control/call_control.c @@ -180,10 +180,22 @@ static param_export_t parameters[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "dialog", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports = { "call_control", // module name + MOD_TYPE_DEFAULT,// class of this module MODULE_VERSION, // module version DEFAULT_DLFLAGS, // dlopen flags + &deps, // OpenSIPS module dependencies commands, // exported functions parameters, // exported parameters NULL, // exported statistics @@ -1184,7 +1196,7 @@ mod_init(void) LM_CRIT("cannot register callback for dialogs loaded from the database\n"); } - fix_flag_name(&prepaid_account_str, prepaid_account_flag); + fix_flag_name(prepaid_account_str, prepaid_account_flag); prepaid_account_flag = get_flag_id_by_name(FLAG_TYPE_MSG, prepaid_account_str); diff --git a/modules/carrierroute/Makefile b/modules/carrierroute/Makefile index bbe2d9978bc..c96e59cfbde 100644 --- a/modules/carrierroute/Makefile +++ b/modules/carrierroute/Makefile @@ -10,10 +10,10 @@ NAME=carrierroute.so ifeq ($(CROSS_COMPILE),) CONFUSE_BUILDER = $(shell \ - if which confuse-config >/dev/null;then \ + if which confuse-config >/dev/null 2>/dev/null;then \ echo 'confuse-config'; \ elif pkg-config --exists libconfuse; then \ - echo 'pkg-config libconfuse'; \ + echo 'pkg-config libconfuse'; \ fi) endif diff --git a/modules/carrierroute/README b/modules/carrierroute/README index 0a1ebd5ae29..5c965da4b7c 100644 --- a/modules/carrierroute/README +++ b/modules/carrierroute/README @@ -14,8 +14,7 @@ Henning Westerholt Copyright © 2007 1&1 Internet AG Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/carrierroute/carrier_tree.c b/modules/carrierroute/carrier_tree.c index da8ed8b2a29..9e037eb7a95 100644 --- a/modules/carrierroute/carrier_tree.c +++ b/modules/carrierroute/carrier_tree.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -210,10 +210,10 @@ int find_tree(str tree){ * @param rewrite_local_suffix the rewrite suffix * @param status the status of the rule * @param hash_index the hash index of the rule - * @param backup indicates if the route is backed up by another. only + * @param backup indicates if the route is backed up by another. only useful if status==0, if set, it is the hash value of another rule - * @param backed_up an -1-termintated array of hash indices of the route + * @param backed_up an -1-termintated array of hash indices of the route for which this route is backup * @param comment a comment for the route rule * @@ -254,7 +254,7 @@ int add_route(struct rewrite_data * rd, int carrier_id, * @param domain the routing domain of the new route * @param scan_prefix the number prefix * @param host the hostname last tried - * @param reply_code the reply code + * @param reply_code the reply code * @param flags user defined flags * @param mask for user defined flags * @param next_domain continue routing with this domain @@ -269,17 +269,17 @@ int add_failure_route(struct rewrite_data * rd, int carrier_id, const str * doma struct carrier_tree * ct = NULL; struct route_tree * rt = NULL; LM_INFO("adding prefix %.*s, reply code %.*s\n", scan_prefix->len, scan_prefix->s, reply_code->len, reply_code->s); - + if (reply_code->len!=3) { LM_ERR("invalid reply_code '%.*s'!\n", reply_code->len, reply_code->s); return -1; } - + if ((ct = get_carrier_tree(carrier_id, rd)) == NULL) { LM_ERR("could not retrieve carrier tree\n"); return -1; } - + if ((rt = get_route_tree(domain, ct)) == NULL) { LM_ERR("could not retrieve route tree\n"); return -1; @@ -289,7 +289,7 @@ int add_failure_route(struct rewrite_data * rd, int carrier_id, const str * doma LM_ERR("add_domain failed\n"); return -1; } - + LM_INFO("found failure route, now adding\n"); return add_failure_route_to_tree(rt->failure_tree, scan_prefix, scan_prefix, host, reply_code, flags, mask, next_domain_id, comment); @@ -335,8 +335,8 @@ struct carrier_tree * add_carrier_tree(const str * carrier, int carrier_id, stru return NULL; } rd->carriers[id]->index = id; - LM_INFO("created carrier tree: %.*s, with id %i and %ld trees\n", - rd->carriers[id]->name.len, rd->carriers[id]->name.s, rd->carriers[id]->id, + LM_INFO("created carrier tree: %.*s, with id %i and %ld trees\n", + rd->carriers[id]->name.len, rd->carriers[id]->name.s, rd->carriers[id]->id, (long)rd->carriers[id]->tree_num); return rd->carriers[id]; } diff --git a/modules/carrierroute/carrier_tree.h b/modules/carrierroute/carrier_tree.h index 4eede36a5af..81b2dab19fa 100644 --- a/modules/carrierroute/carrier_tree.h +++ b/modules/carrierroute/carrier_tree.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -131,7 +131,7 @@ int add_route(struct rewrite_data * rd, int carrier_id, * @param domain the routing domain of the new route * @param scan_prefix the number prefix * @param host the hostname last tried - * @param reply_code the reply code + * @param reply_code the reply code * @param flags user defined flags * @param mask mask for user defined flags * @param next_domain continue routing with this domain diff --git a/modules/carrierroute/carrierroute.c b/modules/carrierroute/carrierroute.c index 8df3d913c3f..8ba981ec9d0 100644 --- a/modules/carrierroute/carrierroute.c +++ b/modules/carrierroute/carrierroute.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -206,10 +206,22 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports = { "carrierroute", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version*/ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Export parameters */ 0, /* exported statistics */ @@ -352,14 +364,14 @@ static int carrier_fixup(void ** param) { return -1; } memset(mp, 0, sizeof(struct multiparam_t)); - + s.s = (char *)(*param); s.len = strlen(s.s); if (s.s[0]!='$') { /* This is a name string */ mp->type=MP_INT; - + /* get carrier id */ if ((mp->u.n = find_tree(s)) < 0) { LM_ERR("could not find carrier tree '%s'\n", (char *)(*param)); @@ -367,7 +379,7 @@ static int carrier_fixup(void ** param) { return -1; } LM_INFO("carrier tree %s has id %i\n", (char *)*param, mp->u.n); - + pkg_free(*param); *param = (void *)mp; } @@ -420,14 +432,14 @@ static int domain_fixup(void ** param) { return -1; } memset(mp, 0, sizeof(struct multiparam_t)); - + s.s = (char *)(*param); s.len = strlen(s.s); - + if (s.s[0]!='$') { /* This is a name string */ mp->type=MP_INT; - + /* get domain id */ if ((mp->u.n = add_domain(&s)) < 0) { LM_ERR("could not add domain\n"); @@ -459,7 +471,7 @@ static int domain_fixup(void ** param) { pkg_free(mp); return -1; } - } + } } *param = (void*)mp; @@ -486,14 +498,14 @@ static int avp_name_fixup(void ** param) { LM_ERR("Malformed or non AVP definition <%s>\n", (char *)(*param)); return -1; } - + mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t)); if (mp == NULL) { LM_ERR("no more memory\n"); return -1; } memset(mp, 0, sizeof(struct multiparam_t)); - + mp->type=MP_AVP; if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) { LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param)); @@ -502,7 +514,7 @@ static int avp_name_fixup(void ** param) { } *param = (void*)mp; - + return 0; } diff --git a/modules/carrierroute/carrierroute.h b/modules/carrierroute/carrierroute.h index 6a36165d4e9..f9d7d41b552 100644 --- a/modules/carrierroute/carrierroute.h +++ b/modules/carrierroute/carrierroute.h @@ -16,10 +16,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * */ /** diff --git a/modules/carrierroute/load_data.c b/modules/carrierroute/load_data.c index 314e7fab9eb..6ea8cd5641d 100644 --- a/modules/carrierroute/load_data.c +++ b/modules/carrierroute/load_data.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -39,7 +39,7 @@ * Binds the loader function pointer api to the matching loader * function depending on source * - * @param source the configuration data source, at the moment + * @param source the configuration data source, at the moment * it can be db or file * @param api pointer to the api where the loader function is * bound to @@ -66,7 +66,7 @@ int bind_data_loader(const char * source, route_data_load_func_t * api){ return -1; } if(fs.st_mode & S_IWOTH){ - LM_WARN("insecure file permissions, routing data is world writeable"); + LM_WARN("insecure file permissions, routing data is world writable"); } if( !( fs.st_mode & S_IWOTH) && !((fs.st_mode & S_IWGRP) && (fs.st_gid == getegid())) && diff --git a/modules/carrierroute/load_data.h b/modules/carrierroute/load_data.h index 55340874c84..97b224fbfca 100644 --- a/modules/carrierroute/load_data.h +++ b/modules/carrierroute/load_data.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -38,7 +38,7 @@ typedef int (*route_data_load_func_t)(struct rewrite_data * rd); * Binds the loader function pointer api to the matching loader * functionm depending on source * - * @param source the configuration data source, at the moment + * @param source the configuration data source, at the moment * it can be db or file * @param api pointer to the api where the loader function is * bound to diff --git a/modules/carrierroute/route.h b/modules/carrierroute/route.h index a011602081b..fe3afd9209b 100644 --- a/modules/carrierroute/route.h +++ b/modules/carrierroute/route.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/carrierroute/route_config.c b/modules/carrierroute/route_config.c index ff28971e56f..c3c87be730d 100644 --- a/modules/carrierroute/route_config.c +++ b/modules/carrierroute/route_config.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/carrierroute/route_config.h b/modules/carrierroute/route_config.h index bbcfd76e19f..f23bf4d26cc 100644 --- a/modules/carrierroute/route_config.h +++ b/modules/carrierroute/route_config.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/carrierroute/route_db.c b/modules/carrierroute/route_db.c index 39346f8ee95..4b3ac3b0c94 100644 --- a/modules/carrierroute/route_db.c +++ b/modules/carrierroute/route_db.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -242,7 +242,7 @@ int load_route_data(struct rewrite_data * rd) { LM_ERR("Failed to query database to prepare fetchrow.\n"); return -1; } - no_rows = estimate_available_rows( 4+64+64+64+4+4+4+64+4+64+64+128, + no_rows = estimate_available_rows( 4+64+64+64+4+4+4+64+4+64+64+128, COLUMN_NUM); if (no_rows==0) no_rows = 10; if(dbf.fetch_result(dbh, &res, no_rows) < 0) { @@ -311,7 +311,7 @@ int load_route_data(struct rewrite_data * rd) { dbf.free_result(dbh, res); res = NULL; - + if (dbf.use_table(dbh, &db_failure_table) < 0) { LM_ERR("cannot set database table '%.*s'.\n", db_failure_table.len, db_failure_table.s); @@ -414,7 +414,7 @@ if(res){ static void destroy_carriers(struct carrier * start){ struct carrier * tmp, * tmp2; tmp = start; - + while(tmp){ tmp2 = tmp; tmp = tmp->next; diff --git a/modules/carrierroute/route_db.h b/modules/carrierroute/route_db.h index a3f6de19b8f..e8615548d3a 100644 --- a/modules/carrierroute/route_db.h +++ b/modules/carrierroute/route_db.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -34,7 +34,7 @@ #include "carrier_tree.h" /** - * Initialises the db API + * Initialises the db API * * @return 0 means ok, -1 means an error occured. */ diff --git a/modules/carrierroute/route_fifo.c b/modules/carrierroute/route_fifo.c index 2db623940f8..2e965b41be1 100644 --- a/modules/carrierroute/route_fifo.c +++ b/modules/carrierroute/route_fifo.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -68,12 +68,12 @@ static struct mi_root* print_fifo_err(void); static int str_toklen(str * str, const char * delims) { int len; - + if ((str==NULL) || (str->s==NULL)) { /* No more tokens */ return -1; } - + len=0; while (lenlen) { if (strchr(delims,str->s[len])!=NULL) { @@ -81,7 +81,7 @@ static int str_toklen(str * str, const char * delims) } len++; } - + return len; } @@ -126,12 +126,13 @@ struct mi_root* dump_fifo (struct mi_root* cmd_tree, void *param) { LM_ERR("error during retrieve data\n"); return init_mi_tree(500, "error during command processing", 31); } - + struct mi_root* rpl_tree; struct mi_node* node = NULL; rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if(rpl_tree == NULL) return 0; + rpl_tree->node.flags |= MI_IS_ARRAY; node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "Printing routing information:"); if(node == NULL) goto error; @@ -184,12 +185,12 @@ struct mi_root* replace_host (struct mi_root* cmd_tree, void *param) { if(mode != SP_ROUTE_MODE_FILE) { return init_mi_tree(400, "Not running in config file mode, cannot modify route from command line", 70); } - + node = cmd_tree->node.kids; if (node==NULL || node->next!=NULL) return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); - + /* look for command */ if (node->value.s==NULL) return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); @@ -232,7 +233,7 @@ struct mi_root* deactivate_host (struct mi_root* cmd_tree, void *param) { if (node==NULL || node->next!=NULL) return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); - + /* look for command */ if (node->value.s==NULL) return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); @@ -275,7 +276,7 @@ struct mi_root* activate_host (struct mi_root* cmd_tree, void *param) { if (node==NULL || node->next!=NULL) return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); - + /* look for command */ if (node->value.s==NULL) return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); @@ -357,7 +358,7 @@ struct mi_root* delete_host (struct mi_root* cmd_tree, void * param) { if (node==NULL || node->next!=NULL) return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); - + /* look for command */ if (node->value.s==NULL) return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); @@ -911,9 +912,9 @@ static struct mi_root* print_replace_help(void) { */ struct mi_root* print_fifo_err(void) { struct mi_root* rpl_tree; - + switch (fifo_err) { - case E_MISC: + case E_MISC: rpl_tree = init_mi_tree( 400, "An error occured", 17); if(rpl_tree == NULL) return 0; diff --git a/modules/carrierroute/route_fifo.h b/modules/carrierroute/route_fifo.h index 6075629cf5a..24d3693e30e 100644 --- a/modules/carrierroute/route_fifo.h +++ b/modules/carrierroute/route_fifo.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/carrierroute/route_func.c b/modules/carrierroute/route_func.c index f22628f0998..6b6d6c2e73d 100644 --- a/modules/carrierroute/route_func.c +++ b/modules/carrierroute/route_func.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -61,7 +61,7 @@ int cr_load_user_carrier(struct sip_msg * _msg, pv_elem_t *_user, pv_elem_t *_do str user; str domain; int_str avp_val; - + if (pv_printf_s(_msg, _user, &user)<0) { LM_ERR("cannot print the user\n"); return -1; @@ -71,7 +71,7 @@ int cr_load_user_carrier(struct sip_msg * _msg, pv_elem_t *_user, pv_elem_t *_do LM_ERR("cannot print the domain\n"); return -1; } - + /* get carrier id */ if ((avp_val.n = load_user_carrier(&user, &domain)) < 0) { LM_ERR("error in load user carrier"); @@ -210,15 +210,15 @@ int mp2domain_id(struct sip_msg * _msg, struct multiparam_t *mp) { */ static inline int reply_code_matcher(const str *rcw, const str *rc) { int i; - + if (rcw->len==0) return 0; - + if (rcw->len != rc->len) return -1; - + for (i=0; ilen; i++) { if (rcw->s[i]!='.' && rcw->s[i]!=rc->s[i]) return -1; } - + return 0; } @@ -239,9 +239,9 @@ static int set_next_domain_on_rule(const struct failure_route_tree_item *failure const struct multiparam_t *dstavp) { struct failure_route_rule * rr; int_str avp_val; - + assert(failure_tree != NULL); - + LM_DBG("searching for matching routing rules"); for (rr = failure_tree->rule_list; rr != NULL; rr = rr->next) { /* @@ -259,12 +259,12 @@ static int set_next_domain_on_rule(const struct failure_route_tree_item *failure LM_ERR("set AVP failed\n"); return -1; } - + LM_INFO("next_domain is %d.\n", rr->next_domain); return 0; } } - + return -1; } @@ -289,7 +289,7 @@ static int set_next_domain_recursor(const struct failure_route_tree_item *failur int ret; struct failure_route_tree_item *re_tree; str re_uri = *uri; - + /* Skip over non-digits. */ while (re_uri.len > 0 && !isdigit(*re_uri.s)) { ++re_uri.s; @@ -458,7 +458,7 @@ static int rewrite_on_rule(const struct route_tree_item * route_tree, flag_t fla assert(route_tree != NULL); assert(route_tree->flag_list != NULL); - + LM_DBG("searching for matching routing rules"); for (rf = route_tree->flag_list; rf != NULL; rf = rf->next) { /* LM_DBG("actual flags %i, searched flags %i, mask %i and match %i", rf->flags, flags, rf->mask, flags&rf->mask); */ @@ -640,7 +640,7 @@ int cr_do_route(struct sip_msg * _msg, struct multiparam_t *_carrier, do { rd = get_data(); } while (rd == NULL); - + ct=NULL; if (carrier_id < 0) { if (fallback_default) { @@ -801,7 +801,7 @@ int cr_load_next_domain(struct sip_msg * _msg, struct multiparam_t *_carrier, do { rd = get_data(); } while (rd == NULL); - + ct=NULL; if (carrier_id < 0) { if (fallback_default) { @@ -836,9 +836,9 @@ int cr_load_next_domain(struct sip_msg * _msg, struct multiparam_t *_carrier, prefix_matching.s, carrier_id, domain_id); goto unlock_and_out; } - + ret = 1; - + unlock_and_out: release_data(rd); return ret; diff --git a/modules/carrierroute/route_func.h b/modules/carrierroute/route_func.h index 8c60dc344f9..713451ef602 100644 --- a/modules/carrierroute/route_func.h +++ b/modules/carrierroute/route_func.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/carrierroute/route_rule.c b/modules/carrierroute/route_rule.c index d1352c6dba9..80917168df5 100644 --- a/modules/carrierroute/route_rule.c +++ b/modules/carrierroute/route_rule.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -66,7 +66,7 @@ static int fixup_rule_backup(struct route_flags * rf, struct route_rule * rr); int add_route_rule(struct route_flags *rf, const str * prefix, int max_targets, double prob, const str * rewrite_hostpart, int strip, const str * rewrite_local_prefix, const str * rewrite_local_suffix, - int status, int hash_index, int backup, int * backed_up, + int status, int hash_index, int backup, int * backed_up, const str * comment) { struct route_rule * shm_rr, * prev = NULL, * tmp = NULL; struct route_rule_p_list * t_rl; @@ -177,7 +177,7 @@ int add_route_rule(struct route_flags *rf, const str * prefix, */ int rule_prio_cmp(struct failure_route_rule *rr1, struct failure_route_rule *rr2) { int n1, n2, i; - + /* host has highest priority */ if ((rr1->host.len == 0) && (rr2->host.len > 0)) { /* host1 is wildcard -> rr1 has lower priority */ @@ -215,7 +215,7 @@ int rule_prio_cmp(struct failure_route_rule *rr1, struct failure_route_rule *rr2 } } } - + return 0; } @@ -227,7 +227,7 @@ int rule_prio_cmp(struct failure_route_rule *rr1, struct failure_route_rule *rr2 * @param failure_tree the current route tree node * @param prefix the whole scan prefix * @param host the hostname last tried - * @param reply_code the reply code + * @param reply_code the reply code * @param flags user defined flags * @param mask mask for user defined flags * @param next_domain continue routing with this domain @@ -243,29 +243,29 @@ int add_failure_route_rule(struct failure_route_tree_item * failure_tree, const struct failure_route_rule * shm_rr; struct failure_route_rule * rr; struct failure_route_rule * prev; - + if ((shm_rr = shm_malloc(sizeof(struct failure_route_rule))) == NULL) { LM_ERR("out of shared memory\n"); return -1; } memset(shm_rr, 0, sizeof(struct failure_route_rule)); - + if (shm_str_dup(&shm_rr->host, host) != 0) { goto mem_error; } - + if (shm_str_dup(&shm_rr->reply_code, reply_code) != 0) { goto mem_error; } - + shm_rr->flags = flags; shm_rr->mask = mask; shm_rr->next_domain = next_domain; - + if (shm_str_dup(&shm_rr->comment, comment) != 0) { goto mem_error; } - + /* before inserting into list, check priorities! */ rr=failure_tree->rule_list; prev=NULL; @@ -280,7 +280,7 @@ int add_failure_route_rule(struct failure_route_tree_item * failure_tree, const shm_rr->next = failure_tree->rule_list; failure_tree->rule_list = shm_rr; } - + return 0; mem_error: @@ -350,7 +350,7 @@ static int rule_fixup_recursor(struct route_tree_item * rt) { p_dice = rr->dice_to; rr = rr->next; } - + if (rf->rule_num != rf->max_targets) { LM_ERR("number of rules(%i) differs from max_targets(%i), maybe your config is wrong?\n", rf->rule_num, rf->max_targets); return -1; @@ -380,7 +380,7 @@ static int rule_fixup_recursor(struct route_tree_item * rt) { LM_INFO("rule with host %.*s hash has hashindex %i.\n", rr->host.len, rr->host.s, rr->hash_index); } } - + rr = rf->rule_list; i=0; while (rr && i < rf->rule_num) { diff --git a/modules/carrierroute/route_rule.h b/modules/carrierroute/route_rule.h index e36580898de..2708ce28e3a 100644 --- a/modules/carrierroute/route_rule.h +++ b/modules/carrierroute/route_rule.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -68,7 +68,7 @@ int add_route_rule(struct route_flags *rf, const str * prefix, * @param failure_tree the current route tree node * @param prefix the whole scan prefix * @param host the hostname last tried - * @param reply_code the reply code + * @param reply_code the reply code * @param flags user defined flags * @param mask mask for user defined flags * @param next_domain continue routing with this domain id diff --git a/modules/carrierroute/route_tree.c b/modules/carrierroute/route_tree.c index 39ca851a20b..dfed3953a9b 100644 --- a/modules/carrierroute/route_tree.c +++ b/modules/carrierroute/route_tree.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -161,7 +161,7 @@ static struct route_tree_item * create_route_tree_item(void) { */ static struct failure_route_tree_item * create_failure_route_tree_item(void) { struct failure_route_tree_item *ret; - + ret = (struct failure_route_tree_item *) shm_malloc(sizeof(struct failure_route_tree_item)); if (ret == NULL) { @@ -235,7 +235,7 @@ struct route_flags * add_route_flags(struct route_tree_item * route_tree, const shm_rf->flags=flags; shm_rf->mask=mask; shm_rf->next=tmp_rf; - + if (prev_rf) prev_rf->next = shm_rf; else route_tree->flag_list = shm_rf; @@ -266,10 +266,10 @@ struct route_flags * add_route_flags(struct route_tree_item * route_tree, const * @param rewrite_local_suffix the rewrite suffix * @param status the status of the rule * @param hash_index the hash index of the rule - * @param backup indicates if the route is backed up by another. only + * @param backup indicates if the route is backed up by another. only useful if status==0, if set, it is the hash value of another rule - * @param backed_up an -1-termintated array of hash indices of the route + * @param backed_up an -1-termintated array of hash indices of the route for which this route is backup * @param comment a comment for the route rule * @@ -280,7 +280,7 @@ struct route_flags * add_route_flags(struct route_tree_item * route_tree, const int add_route_to_tree(struct route_tree_item * route_tree, const str * scan_prefix, flag_t flags, flag_t mask, const str * full_prefix, int max_targets, double prob, const str * rewrite_hostpart, int strip, const str * rewrite_local_prefix, - const str * rewrite_local_suffix, int status, int hash_index, + const str * rewrite_local_suffix, int status, int hash_index, int backup, int * backed_up, const str * comment) { str next_prefix; struct route_flags *rf; @@ -326,7 +326,7 @@ int add_route_to_tree(struct route_tree_item * route_tree, const str * scan_pref * @param scan_prefix the prefix at the current position * @param full_prefix the whole scan prefix * @param host the hostname last tried - * @param reply_code the reply code + * @param reply_code the reply code * @param flags user defined flags * @param mask mask for user defined flags * @param next_domain continue routing with this domain id @@ -449,11 +449,11 @@ static void destroy_failure_route_tree_item(struct failure_route_tree_item *rout int i; struct failure_route_rule *rs; struct failure_route_rule *rs_tmp; - + if (!route_tree_item) { LM_ERR("NULL pointer in parameter\n"); } - + for (i = 0; i < 10; ++i) { if (route_tree_item->nodes[i] != NULL) { destroy_failure_route_tree_item(route_tree_item->nodes[i]); diff --git a/modules/carrierroute/route_tree.h b/modules/carrierroute/route_tree.h index 1ea1332c8cf..1dfeba1b00b 100644 --- a/modules/carrierroute/route_tree.h +++ b/modules/carrierroute/route_tree.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -55,10 +55,10 @@ * @param rewrite_local_suffix the rewrite suffix * @param status the status of the rule * @param hash_index the hash index of the rule - * @param backup indicates if the route is backed up by another. only + * @param backup indicates if the route is backed up by another. only useful if status==0, if set, it is the hash value of another rule - * @param backed_up an -1-termintated array of hash indices of the route + * @param backed_up an -1-termintated array of hash indices of the route for which this route is backup * @param comment a comment for the route rule * @@ -85,7 +85,7 @@ int add_route_to_tree(struct route_tree_item * route_tree, const str * scan_pref * @param scan_prefix the prefix at the current position * @param full_prefix the whole scan prefix * @param host the hostname last tried - * @param reply_code the reply code + * @param reply_code the reply code * @param flags user defined flags * @param mask mask for user defined flags * @param next_domain continue routing with this domain id diff --git a/modules/cfgutils/README b/modules/cfgutils/README index 1af1f4d4729..f38c7f0a514 100644 --- a/modules/cfgutils/README +++ b/modules/cfgutils/README @@ -21,8 +21,7 @@ Sergio Gutierrez Copyright © 2007, 2008 1und1 Internet AG, BASIS AudioNet GmbH, Elena-Ramona Modroiu Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -425,9 +424,12 @@ ts_usec_delta("$avp(10)", "$avp(20)", "10", "300", "$avp(result)"); 1.4.13. check_time_rec(time_string) The function returns a positive value if the specified time - reccurence string matches the current time, or a negative value + recurrence string matches the current time, or a negative value otherwise. + The syntax of each field is identical to the corresponding + field from RFC 2445. + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE, EVENT_ROUTE. diff --git a/modules/cfgutils/cfgutils.c b/modules/cfgutils/cfgutils.c index b16202512dc..8159f8b3f11 100644 --- a/modules/cfgutils/cfgutils.c +++ b/modules/cfgutils/cfgutils.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -38,7 +38,7 @@ * or command line tools. * Furthermore it provides some functions to let the server wait a * specific time interval. - * + * */ @@ -172,7 +172,7 @@ static cmd_export_t cmds[]={ {0, 0, 0, 0, 0, 0} }; -static param_export_t params[]={ +static param_export_t params[]={ {"initial_probability", INT_PARAM, &initial}, {"hash_file", STR_PARAM, &hash_file }, {"shvset", STR_PARAM|USE_FUNC_PARAM, (void*)param_set_shvar }, @@ -207,8 +207,10 @@ static pv_export_t mod_items[] = { struct module_exports exports = { "cfgutils", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -303,7 +305,7 @@ static struct mi_root* mi_get_prob(struct mi_root* cmd, void* param ) node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "actual probability: %u percent\n",(*probability)); if(node == NULL) goto error; - + return rpl_tree; error: @@ -349,7 +351,7 @@ static struct mi_root* mi_check_hash(struct mi_root* cmd, void* param ) LM_ERR("could not hash the config file"); rpl_tree = init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN ); } - + if (strncmp(config_hash, tmp, MD5_LEN) == 0) { rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN ); if(rpl_tree == NULL) @@ -364,7 +366,7 @@ static struct mi_root* mi_check_hash(struct mi_root* cmd, void* param ) if(node == NULL) goto error; } - + return rpl_tree; error: @@ -372,12 +374,12 @@ static struct mi_root* mi_check_hash(struct mi_root* cmd, void* param ) return 0; } -static int set_prob(struct sip_msg *bar, char *percent_par, char *foo) +static int set_prob(struct sip_msg *bar, char *percent_par, char *foo) { *probability=(int)(long)percent_par; return 1; } - + static int reset_prob(struct sip_msg *bar, char *percent_par, char *foo) { *probability=initial; @@ -633,7 +635,7 @@ static int pv_set_count(struct sip_msg* msg, char* pv_name, char* pv_result) pv_val.flags = PV_TYPE_INT; pv_val.ri = pv_elem->spec.pvp.pvi.u.ival-1; - + if (pv_set_value( msg, &pv_res->spec, 0, &pv_val) != 0) { LM_ERR("SET output value failed.\n"); diff --git a/modules/cfgutils/doc/cfgutils_admin.xml b/modules/cfgutils/doc/cfgutils_admin.xml index ba52d5fcff0..0326bb8a200 100644 --- a/modules/cfgutils/doc/cfgutils_admin.xml +++ b/modules/cfgutils/doc/cfgutils_admin.xml @@ -470,9 +470,13 @@ ts_usec_delta("$avp(10)", "$avp(20)", "10", "300", "$avp(result)"); check_time_rec(time_string) - The function returns a positive value if the specified time reccurence string + The function returns a positive value if the specified time recurrence string matches the current time, or a negative value otherwise. + + The syntax of each field is identical to the corresponding field from + RFC 2445. + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE, diff --git a/modules/cfgutils/env_var.c b/modules/cfgutils/env_var.c index 5a5d34ca33c..372e61961d4 100644 --- a/modules/cfgutils/env_var.c +++ b/modules/cfgutils/env_var.c @@ -24,7 +24,7 @@ int pv_parse_env_name(pv_spec_p sp, str *in) return -1; } memset(it, 0, sizeof(env_var_t)); - + it->name.s = (char*)pkg_malloc(in->len + 1); if (!it->name.s) { LM_ERR("no more pkg mem\n"); @@ -58,7 +58,7 @@ int pv_get_env(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) return pv_get_null(msg, param, res); env_v = (env_var_p)param->pvn.u.dname; - + env_val = getenv(env_v->name.s); if (!env_val) { LM_DBG("env variable <%s> could not be found\n", env_v->name.s); diff --git a/modules/cfgutils/script_locks.c b/modules/cfgutils/script_locks.c index 91d4e121e00..55d11aa58a4 100644 --- a/modules/cfgutils/script_locks.c +++ b/modules/cfgutils/script_locks.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -162,7 +162,7 @@ int strings_share_lock(struct sip_msg *msg, char *s1, char *s2) if (core_hash(&ret1, NULL, lock_pool_size) == core_hash(&ret2, NULL, lock_pool_size)) { - + return 1; } @@ -179,11 +179,13 @@ void destroy_script_locks(void) lock_entry = static_locks; static_locks = static_locks->next; - lock_dealloc(lock_entry->lock); + if (lock_entry->lock) + lock_dealloc(lock_entry->lock); shm_free(lock_entry); } /* Free all dynamic locks */ - lock_set_dealloc(dynamic_locks); + if (dynamic_locks) + lock_set_dealloc(dynamic_locks); } diff --git a/modules/cfgutils/script_locks.h b/modules/cfgutils/script_locks.h index 7f23a6790d7..f2c58e4cdf3 100644 --- a/modules/cfgutils/script_locks.h +++ b/modules/cfgutils/script_locks.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History diff --git a/modules/cfgutils/shvar.c b/modules/cfgutils/shvar.c index 9ccfc1fdf54..f9e9312ef1b 100644 --- a/modules/cfgutils/shvar.c +++ b/modules/cfgutils/shvar.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -432,10 +432,10 @@ void destroy_shvars(void) int pv_parse_shvar_name(pv_spec_p sp, str *in) { pv_spec_list_t *pvi = 0; - + if(in==NULL || in->s==NULL || sp==NULL) return -1; - + sp->pvp.pvn.type = PV_NAME_PVAR; if(shvar_initialized) sp->pvp.pvn.u.dname = (void*)add_shvar(in); @@ -470,13 +470,13 @@ int pv_get_shvar(struct sip_msg *msg, pv_param_t *param, int len = 0; char *sval = NULL; sh_var_t *shv=NULL; - + if(msg==NULL || res==NULL) return -1; if(param==NULL || param->pvn.u.dname==0) return pv_get_null(msg, param, res); - + shv= (sh_var_t*)param->pvn.u.dname; lock_shvar(shv); @@ -496,16 +496,16 @@ int pv_get_shvar(struct sip_msg *msg, pv_param_t *param, } strncpy(param->pvv.s, shv->v.value.s.s, shv->v.value.s.len); param->pvv.len = shv->v.value.s.len; - + unlock_shvar(shv); - + res->rs = param->pvv; res->flags = PV_VAL_STR; } else { res->ri = shv->v.value.n; - + unlock_shvar(shv); - + sval = sint2str(res->ri, &len); res->rs.s = sval; res->rs.len = len; @@ -649,7 +649,7 @@ struct mi_root* mi_shvar_get(struct mi_root* cmd_tree, void* param) shv = get_shvar_by_name(&name); if(shv==NULL) return init_mi_tree(404, MI_SSTR("Not found")); - + rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return NULL; @@ -762,7 +762,7 @@ int param_set_xvar( modparam_t type, void* val, int mode) if(*p!='=') goto error; - + s.len = p - s.s; if(s.len == 0) goto error; @@ -792,7 +792,7 @@ int param_set_xvar( modparam_t type, void* val, int mode) goto error; if(set_var_value(sv, &isv, flags)==NULL) goto error; - + return 0; error: LM_ERR("unable to set shv parame [%s]\n", s.s); @@ -819,7 +819,7 @@ int pv_parse_time_name(pv_spec_p sp, str *in) switch(in->len) { - case 3: + case 3: if(strncmp(in->s, "sec", 3)==0) sp->pvp.pvn.u.isname.name.n = 0; else if(strncmp(in->s, "min", 3)==0) @@ -828,7 +828,7 @@ int pv_parse_time_name(pv_spec_p sp, str *in) sp->pvp.pvn.u.isname.name.n = 4; else goto error; break; - case 4: + case 4: if(strncmp(in->s, "hour", 4)==0) sp->pvp.pvn.u.isname.name.n = 2; else if(strncmp(in->s, "mday", 4)==0) @@ -841,7 +841,7 @@ int pv_parse_time_name(pv_spec_p sp, str *in) sp->pvp.pvn.u.isname.name.n = 7; else goto error; break; - case 5: + case 5: if(strncmp(in->s, "isdst", 5)==0) sp->pvp.pvn.u.isname.name.n = 8; else goto error; @@ -878,7 +878,7 @@ int pv_get_time(struct sip_msg *msg, pv_param_t *param, return -1; } } - + switch(param->pvn.u.isname.name.n) { case 1: @@ -888,16 +888,16 @@ int pv_get_time(struct sip_msg *msg, pv_param_t *param, case 3: return pv_get_uintval(msg, param, res, (unsigned int)stored_ts.tm_mday); case 4: - return pv_get_uintval(msg, param, res, + return pv_get_uintval(msg, param, res, (unsigned int)(stored_ts.tm_mon+1)); case 5: return pv_get_uintval(msg, param, res, (unsigned int)(stored_ts.tm_year+1900)); case 6: - return pv_get_uintval(msg, param, res, + return pv_get_uintval(msg, param, res, (unsigned int)(stored_ts.tm_wday+1)); case 7: - return pv_get_uintval(msg, param, res, + return pv_get_uintval(msg, param, res, (unsigned int)(stored_ts.tm_yday+1)); case 8: return pv_get_sintval(msg, param, res, stored_ts.tm_isdst); diff --git a/modules/cfgutils/shvar.h b/modules/cfgutils/shvar.h index 5650457e5a9..89de08d431a 100644 --- a/modules/cfgutils/shvar.h +++ b/modules/cfgutils/shvar.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/closeddial/README b/modules/closeddial/README index 4237049361d..1494d7be97f 100644 --- a/modules/closeddial/README +++ b/modules/closeddial/README @@ -8,7 +8,7 @@ Sergio Gutierrez Copyright © 2009 Revision History - Revision $Revision$ $Date: 2009-02-07 18:00:00 -0500$ + Revision $Revision: 5901 $ $Date: 2009-02-07 18:00:00 -0500$ __________________________________________________________ Table of Contents diff --git a/modules/closeddial/cdlookup.c b/modules/closeddial/cdlookup.c index a695a7c121b..1bfe9d71b9b 100644 --- a/modules/closeddial/cdlookup.c +++ b/modules/closeddial/cdlookup.c @@ -66,7 +66,7 @@ int cd_lookup(struct sip_msg* _msg, char* _table, char* _group) int key_count=0; /* Query to execute: select new_uri from closeddial - * where cd_username='username' and group='group' + * where cd_username='username' and group='group' * [ and domain='domain' ] */ @@ -113,7 +113,7 @@ int cd_lookup(struct sip_msg* _msg, char* _table, char* _group) /* ... where cd_username ... */ colsToCompare[0]=&cd_user_column; - /* ... and group_id ... */ + /* ... and group_id ... */ colsToCompare[1]=&group_id_column; if(parse_sip_msg_uri(_msg) < 0){ @@ -144,10 +144,10 @@ int cd_lookup(struct sip_msg* _msg, char* _table, char* _group) valsToMatch[key_count].val.str_val.s=from_uri->host.s; valsToMatch[key_count].val.str_val.len=from_uri->host.len; key_count++; - } + } colsToReturn[0]=&new_uri_column; - + if(db_functions.use_table(db_connection, &table_s) < 0) { LM_ERR("Error trying to use table %s\n", table_s.s); return -1; @@ -178,21 +178,21 @@ int cd_lookup(struct sip_msg* _msg, char* _table, char* _group) user_s.s = useruri_buf+4; switch(RES_ROWS(result)[0].values[0].type) - { + { case DB_STRING: - strcpy(user_s.s, + strcpy(user_s.s, (char*)RES_ROWS(result)[0].values[0].val.string_val); user_s.len = strlen(user_s.s); break; case DB_STR: - strncpy(user_s.s, + strncpy(user_s.s, (char*)RES_ROWS(result)[0].values[0].val.str_val.s, RES_ROWS(result)[0].values[0].val.str_val.len); user_s.len = RES_ROWS(result)[0].values[0].val.str_val.len; user_s.s[user_s.len] = '\0'; break; case DB_BLOB: - strncpy(user_s.s, + strncpy(user_s.s, (char*)RES_ROWS(result)[0].values[0].val.blob_val.s, RES_ROWS(result)[0].values[0].val.blob_val.len); user_s.len = RES_ROWS(result)[0].values[0].val.blob_val.len; @@ -205,7 +205,7 @@ int cd_lookup(struct sip_msg* _msg, char* _table, char* _group) } return -1; } - + /* check 'sip:' */ if(user_s.len<4 || strncasecmp(user_s.s, "sip:", 4)) { @@ -243,7 +243,7 @@ str _get_group(struct sip_uri *from_uri) db_res_t *result = NULL; static db_ps_t my_ps = NULL; - /* Query to exec is: + /* Query to exec is: * select group_id from closeddial where username='value' */ @@ -282,16 +282,16 @@ str _get_group(struct sip_uri *from_uri) } if(RES_ROW_N(result) == 0) { - LM_DBG("No group_id for username %s\n", from_uri->user.s); + LM_DBG("No group_id for username %s\n", from_uri->user.s); } else { - switch(RES_ROWS(result)[0].values[0].type) { + switch(RES_ROWS(result)[0].values[0].type) { case DB_STRING: returnValue.s = (char*)RES_ROWS(result)[0].values[0].val.string_val; returnValue.len = strlen(returnValue.s); break; - + case DB_STR: returnValue.s=(char*)RES_ROWS(result)[0].values[0].val.str_val.s; returnValue.len=strlen(returnValue.s); diff --git a/modules/closeddial/closeddial.c b/modules/closeddial/closeddial.c index aabdeca905e..e3c49e49a2a 100644 --- a/modules/closeddial/closeddial.c +++ b/modules/closeddial/closeddial.c @@ -19,7 +19,7 @@ * * History: * --------- - * 2009-02-07 Initial version of closeddial module (saguti) + * 2009-02-07 Initial version of closeddial module (saguti) */ @@ -83,12 +83,23 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* Module interface */ struct module_exports exports = { - "closeddial", + "closeddial", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ diff --git a/modules/closeddial/closeddial.h b/modules/closeddial/closeddial.h index 22b22e174e7..1bb2a4d983b 100644 --- a/modules/closeddial/closeddial.h +++ b/modules/closeddial/closeddial.h @@ -18,7 +18,7 @@ * * History: * --------- - * 2009-02-07 Initial version of closeddial module (saguti) + * 2009-02-07 Initial version of closeddial module (saguti) */ diff --git a/modules/cpl-c/README b/modules/cpl-c/README index 7d9b0868a5b..b6dab744b75 100644 --- a/modules/cpl-c/README +++ b/modules/cpl-c/README @@ -8,8 +8,7 @@ Bogdan-Andrei Iancu Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/cpl-c/cpl.c b/modules/cpl-c/cpl.c index 20ba432b792..5224cab0daa 100644 --- a/modules/cpl-c/cpl.c +++ b/modules/cpl-c/cpl.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -28,7 +28,7 @@ * 2004-06-14: all global variables merged into cpl_env and cpl_fct; * case_sensitive and realm_prefix added for building AORs - see * build_userhost (bogdan) - * 2004-10-09: added process_register_norpl to allow register processing + * 2004-10-09: added process_register_norpl to allow register processing * without sending the reply(bogdan) - based on a patch sent by * Christopher Crawford */ @@ -166,13 +166,34 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static module_dependency_t *get_deps_lookup_domain(param_export_t *param) +{ + char *domain = *(char **)param->param_pointer; + if (!domain || strlen(domain) == 0) + return NULL; + return alloc_module_dep(MOD_TYPE_DEFAULT, "usrloc", DEP_ABORT); +} +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "lookup_domain", get_deps_lookup_domain }, + { NULL, NULL }, + }, +}; struct module_exports exports = { "cpl-c", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -518,7 +539,7 @@ static inline int get_orig_user(struct sip_msg *msg, str *username, str *domain) { struct to_body *from; struct sip_uri uri; - + /* if it's outgoing -> get the user_name from From */ /* parsing from header */ LM_DBG("trying to get user from From\n"); @@ -539,9 +560,9 @@ static inline int get_orig_user(struct sip_msg *msg, str *username, str *domain) -/* Params: - * str1 - as unsigned int - can be CPL_RUN_INCOMING or CPL_RUN_OUTGOING - * str2 - as unsigned int - flags regarding state(less)|(ful) +/* Params: + * str1 - as unsigned int - can be CPL_RUN_INCOMING or CPL_RUN_OUTGOING + * str2 - as unsigned int - flags regarding state(less)|(ful) */ static int cpl_invoke_script(struct sip_msg* msg, char* str1, char* str2) { diff --git a/modules/cpl-c/cpl_db.c b/modules/cpl-c/cpl_db.c index a1a094132c1..2fa12187fcb 100644 --- a/modules/cpl-c/cpl_db.c +++ b/modules/cpl-c/cpl_db.c @@ -49,7 +49,7 @@ int cpl_db_bind(const str* db_url, const str *db_table) "Did you forget to load a database module ?\n"); return -1; } - + /* CPL module uses all database functions */ if (!DB_CAPABILITY(cpl_dbf, DB_CAP_ALL)) { LM_CRIT("Database modules does not " @@ -80,12 +80,12 @@ int cpl_db_init(const str* db_url, const str* db_table) } db_hdl=cpl_dbf.init(db_url); - + if (db_hdl==0){ LM_CRIT("cannot initialize database connection\n"); return -1; } - + if (cpl_dbf.use_table(db_hdl, db_table)<0) { LM_CRIT("cannot select table \"%.*s\"\n",db_table->len, db_table->s); cpl_db_close(); diff --git a/modules/cpl-c/cpl_nonsig.c b/modules/cpl-c/cpl_nonsig.c index 7dd05cbfa20..60078e3d660 100644 --- a/modules/cpl-c/cpl_nonsig.c +++ b/modules/cpl-c/cpl_nonsig.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/cpl-c/cpl_nonsig.h b/modules/cpl-c/cpl_nonsig.h index 0e3bd12364d..3cbaba97e04 100644 --- a/modules/cpl-c/cpl_nonsig.h +++ b/modules/cpl-c/cpl_nonsig.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/cpl-c/cpl_proxy.h b/modules/cpl-c/cpl_proxy.h index f79f9ad15d3..cb68de6a62a 100644 --- a/modules/cpl-c/cpl_proxy.h +++ b/modules/cpl-c/cpl_proxy.h @@ -22,7 +22,7 @@ * History: * ------- * 2003-07-29: file created (bogdan) - * 2004-06-14: flag CPL_IS_STATEFUL is set now immediately after the + * 2004-06-14: flag CPL_IS_STATEFUL is set now immediately after the * transaction is created (bogdan) */ @@ -253,7 +253,7 @@ static void reply_callback( struct cell* t, int type, struct tmcb_params* ps) rez = cpl_run_script(intr); switch ( rez ) { case SCRIPT_END: - /* we don't need to free the interpreter here since it will + /* we don't need to free the interpreter here since it will * be freed in the final_reply callback */ case SCRIPT_TO_BE_CONTINUED: return; diff --git a/modules/cpl-c/cpl_run.c b/modules/cpl-c/cpl_run.c index 13fa2149a62..37d98d1850c 100644 --- a/modules/cpl-c/cpl_run.c +++ b/modules/cpl-c/cpl_run.c @@ -25,7 +25,7 @@ * 2003-09-11 : build_lump_rpl() merged into add_lump_rpl() (bogdan) * 2004-06-14 : all global variables merged into cpl_env and cpl_fct; * append_branches param added to lookup node (bogdan) - * 2004-06-14 : flag CPL_IS_STATEFUL is set now immediately after the + * 2004-06-14 : flag CPL_IS_STATEFUL is set now immediately after the * transaction is created (bogdan) */ @@ -295,7 +295,7 @@ static inline char *run_lookup( struct cpl_interpreter *intr ) LM_DBG("adding <%.*s>q=%d\n", contact->c.len,contact->c.s, (int)((contact->q==Q_UNSPECIFIED)?10:10*contact->q)); - if (add_location( &(intr->loc_set), &contact->c, + if (add_location( &(intr->loc_set), &contact->c, &contact->received, (int)((contact->q==Q_UNSPECIFIED)?10:10*contact->q), CPL_LOC_DUPL| @@ -927,7 +927,7 @@ static inline int run_default( struct cpl_interpreter *intr ) return SCRIPT_DEFAULT; } else { /* case 2 : no location modifications or signaling operations - * performed, location set non-empty: (This can only happen + * performed, location set non-empty: (This can only happen * for outgoing calls.) -> * Proxy the call to the address in the location set. * With other words, let ser to continue processing the @@ -935,7 +935,7 @@ static inline int run_default( struct cpl_interpreter *intr ) return SCRIPT_DEFAULT; } } else { - /* case 3 : location modifications performed, no signaling + /* case 3 : location modifications performed, no signaling * operations -> * Proxy the call to the addresses in the location set */ if (!cpl_proxy_to_loc_set(intr->msg,&(intr->loc_set),intr->flags)) @@ -943,7 +943,7 @@ static inline int run_default( struct cpl_interpreter *intr ) return SCRIPT_RUN_ERROR; } } else { - /* case 4 : proxy operation previously taken -> return whatever the + /* case 4 : proxy operation previously taken -> return whatever the * "best" response is of all accumulated responses to the call to this * point, according to the rules of the underlying signaling * protocol. */ diff --git a/modules/cpl-c/cpl_sig.c b/modules/cpl-c/cpl_sig.c index 4f706d980b1..8fa5078d645 100644 --- a/modules/cpl-c/cpl_sig.c +++ b/modules/cpl-c/cpl_sig.c @@ -30,8 +30,8 @@ /* forwards the msg to the given location set; if flags has set the - * CPL_PROXY_DONE, all locations will be added as branches, otherwise, the - * first one will set as RURI (this is ha case when this is the first proxy + * CPL_PROXY_DONE, all locations will be added as branches, otherwise, the + * first one will set as RURI (this is ha case when this is the first proxy * of the message) * The given list of location will be freed, returning 0 instead. * Returns: 0 - OK diff --git a/modules/cpl-c/cpl_switches.h b/modules/cpl-c/cpl_switches.h index 6fc7f30aec8..80b679043c1 100644 --- a/modules/cpl-c/cpl_switches.h +++ b/modules/cpl-c/cpl_switches.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -1012,7 +1012,7 @@ static inline char *run_language_switch( struct cpl_interpreter *intr ) goto script_error; } } - + /* get the value from the SIP message -> if not yet, do it now * and remember it for the next times */ if (!msg_val.s) { @@ -1038,7 +1038,7 @@ static inline char *run_language_switch( struct cpl_interpreter *intr ) trim_len( msg_val.len,msg_val.s, *(intr->subject)); LM_DBG("extracted msg string is " "<%.*s>\n",msg_val.len, msg_val.s); - + /* does the value from script match the one from message? */ if (msg_val.len && msg_val.s) { j = is_lang_tag_matching(&msg_val,&lang_tag,&lang_subtag); diff --git a/modules/cpl-c/loc_set.h b/modules/cpl-c/loc_set.h index fdc9a47a4bc..7427c3d67c5 100644 --- a/modules/cpl-c/loc_set.h +++ b/modules/cpl-c/loc_set.h @@ -69,7 +69,7 @@ static inline int add_location(struct location **loc_set, str *uri, if(received && received->s && received->len) loc = (struct location*)shm_malloc(sizeof(struct location)+ ((flags&CPL_LOC_DUPL)?uri->len+1+received->len+1:0) ); - else + else loc = (struct location*)shm_malloc( sizeof(struct location)+((flags&CPL_LOC_DUPL)?uri->len+1:0) ); if (!loc) { diff --git a/modules/db_berkeley/README b/modules/db_berkeley/README index 89c719b86d5..361fa471ecc 100644 --- a/modules/db_berkeley/README +++ b/modules/db_berkeley/README @@ -10,8 +10,7 @@ Will Quan Copyright © 2007 Cisco Systems Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/db_berkeley/bdb_lib.c b/modules/db_berkeley/bdb_lib.c index a2e1e6d9b18..b01e16e0618 100644 --- a/modules/db_berkeley/bdb_lib.c +++ b/modules/db_berkeley/bdb_lib.c @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) @@ -46,25 +46,25 @@ static db_parms_p _db_parms = NULL; /** * */ -int bdblib_init(db_parms_p _p) +int bdblib_init(db_parms_p _p) { if (!_cachedb) { _cachedb = pkg_malloc( sizeof(database_p) ); - if (!_cachedb) + if (!_cachedb) { LM_CRIT("not enough private memory\n"); return -1; } - + *_cachedb = NULL; - + /*create default parms*/ db_parms_p dp = (db_parms_p) pkg_malloc( sizeof(db_parms_t) ); - if (!dp) + if (!dp) { LM_CRIT("not enough private memory\n"); return -1; } - + if(_p) { dp->cache_size = _p->cache_size; @@ -79,7 +79,7 @@ int bdblib_init(db_parms_p _p) dp->log_enable = 0; dp->journal_roll_interval = 3600; } - + _db_parms = dp; } return 0; @@ -109,22 +109,22 @@ int bdblib_close(char* _n) DB* _db = NULL; DB_ENV* _env = NULL; database_p _db_p = *_cachedb; - + if (!_cachedb || !_n) return -1; - + rc = 0; s.s = (char*)_n; s.len = strlen(_n); - + if (_db_p) - { + { _env = _db_p->dbenv; _tbc = _db_p->tables; LM_DBG("ENV %.*s \n" , _db_p->name.len , _db_p->name.s); - if(s.len == _db_p->name.len && + if(s.len == _db_p->name.len && !strncasecmp(s.s, _db_p->name.s, _db_p->name.len)) { //close the whole dbenv @@ -140,7 +140,7 @@ LM_DBG("ENV %.*s \n" if(rc != 0) LM_CRIT("error closing %s\n", _tbc->dtp->name.s); _tbc->dtp->db = NULL; - + lock_release(&_tbc->dtp->sem); } _tbc = _tbc->next; @@ -149,7 +149,7 @@ LM_DBG("ENV %.*s \n" _db_p->dbenv = NULL; return 0; } - + //close a particular db while(_tbc) { @@ -158,8 +158,8 @@ LM_DBG("ENV %.*s \n" LM_DBG("checking DB %.*s \n" , _tbc->dtp->name.len , _tbc->dtp->name.s); - - if(_tbc->dtp->name.len == s.len && + + if(_tbc->dtp->name.len == s.len && !strncasecmp(_tbc->dtp->name.s, s.s, s.len )) { LM_DBG("DB %.*s \n", s.len, s.s); @@ -195,19 +195,19 @@ int bdblib_reopen(char* _n) database_p _db_p = *_cachedb; rc = flags = 0; _tbc = NULL; - + if (!_cachedb || !_n) return -1; s.s = (char*)_n; s.len = strlen(_n); - + if (_db_p) { _env = _db_p->dbenv; _tbc = _db_p->tables; - - if(s.len ==_db_p->name.len && + + if(s.len ==_db_p->name.len && !strncasecmp(s.s, _db_p->name.s,_db_p->name.len)) { //open the whole dbenv @@ -216,7 +216,7 @@ int bdblib_reopen(char* _n) { rc = bdblib_create_dbenv(&_env, _n); _db_p->dbenv = _env; } - + if(rc!=0) return rc; _env = _db_p->dbenv; _tbc = _db_p->tables; @@ -234,13 +234,13 @@ int bdblib_reopen(char* _n) bdblib_recover(_tbc->dtp, rc); } } - + if ((rc = _db->open(_db, NULL, _n, NULL, DB_HASH, DB_CREATE, 0664)) != 0) { _db->dbenv->err(_env, rc, "DB->open: %s", _n); LM_CRIT("error in db_open: %s.\n",db_strerror(rc)); bdblib_recover(_tbc->dtp, rc); } - + _tbc->dtp->db = _db; lock_release(&_tbc->dtp->sem); } @@ -249,7 +249,7 @@ int bdblib_reopen(char* _n) _env->close(_env, 0); return rc; } - + //open a particular db while(_tbc) { @@ -258,13 +258,13 @@ int bdblib_reopen(char* _n) LM_DBG("checking DB %.*s \n" , _tbc->dtp->name.len , _tbc->dtp->name.s); - - if(_tbc->dtp->name.len == s.len && + + if(_tbc->dtp->name.len == s.len && !strncasecmp(_tbc->dtp->name.s, s.s, s.len )) { LM_DBG("DB %.*s \n", s.len, s.s); lock_get(&_tbc->dtp->sem); - if(!_tbc->dtp->db) + if(!_tbc->dtp->db) { if ((rc = db_create(&_db, _env, 0)) != 0) { _env->err(_env, rc, "db_create"); @@ -272,7 +272,7 @@ int bdblib_reopen(char* _n) bdblib_recover(_tbc->dtp, rc); } } - + if ((rc = _db->open(_db, NULL, _n, NULL, DB_HASH, DB_CREATE, 0664)) != 0) { _db->dbenv->err(_env, rc, "DB->open: %s", _n); LM_CRIT("bdb open: %s.\n",db_strerror(rc)); @@ -285,7 +285,7 @@ int bdblib_reopen(char* _n) } _tbc = _tbc->next; } - + } LM_DBG("DB not found %.*s \n", s.len, s.s); return 1; /*table not found*/ @@ -300,24 +300,24 @@ int bdblib_create_dbenv(DB_ENV **_dbenv, char* _home) DB_ENV *env; char *progname; int rc, flags; - + progname = "opensips"; - - /* Create an environment and initialize it for additional error * reporting. */ - if ((rc = db_env_create(&env, 0)) != 0) + + /* Create an environment and initialize it for additional error * reporting. */ + if ((rc = db_env_create(&env, 0)) != 0) { - LM_ERR("db_env_create failed! bdb error: %s.\n", db_strerror(rc)); + LM_ERR("db_env_create failed! bdb error: %s.\n", db_strerror(rc)); return (rc); } - + env->set_errpfx(env, progname); - /* Specify the shared memory buffer pool cachesize */ - if ((rc = env->set_cachesize(env, 0, _db_parms->cache_size, 0)) != 0) + /* Specify the shared memory buffer pool cachesize */ + if ((rc = env->set_cachesize(env, 0, _db_parms->cache_size, 0)) != 0) { LM_ERR("dbenv set_cachsize failed! bdb error: %s.\n", db_strerror(rc)); - env->err(env, rc, "set_cachesize"); - goto err; + env->err(env, rc, "set_cachesize"); + goto err; } /* Concurrent Data Store flags */ @@ -325,26 +325,26 @@ int bdblib_create_dbenv(DB_ENV **_dbenv, char* _home) DB_INIT_CDB | DB_INIT_MPOOL | DB_THREAD; - + /* Transaction Data Store flags ; not supported yet */ /* flags = DB_CREATE | DB_RECOVER | - DB_INIT_LOG | + DB_INIT_LOG | DB_INIT_LOCK | DB_INIT_MPOOL | DB_THREAD | DB_INIT_TXN; */ - - /* Open the environment */ - if ((rc = env->open(env, _home, flags, 0)) != 0) - { + + /* Open the environment */ + if ((rc = env->open(env, _home, flags, 0)) != 0) + { LM_ERR("dbenv is not initialized! bdb error: %s.\n",db_strerror(rc)); - env->err(env, rc, "environment open: %s", _home); - goto err; + env->err(env, rc, "environment open: %s", _home); + goto err; } - + *_dbenv = env; return (0); @@ -379,7 +379,7 @@ database_p bdblib_get_db(str *_s) } if(!bdb_is_database(_s)) - { + { LM_ERR("database [%.*s] does not exists!\n" ,_s->len , _s->s); return NULL; } @@ -437,7 +437,7 @@ tbl_cache_p bdblib_get_table(database_p _db, str *_s) if(_tbc->dtp) { - if(_tbc->dtp->name.len == _s->len + if(_tbc->dtp->name.len == _s->len && !strncasecmp(_tbc->dtp->name.s, _s->s, _s->len )) { return _tbc; @@ -474,7 +474,7 @@ tbl_cache_p bdblib_get_table(database_p _db, str *_s) if(_db->tables) (_db->tables)->prev = _tbc; - + _tbc->next = _db->tables; _db->tables = _tbc; lock_release(&_tbc->sem); @@ -488,13 +488,13 @@ void bdblib_log(int op, table_p _tp, char* _msg, int len) if(!_tp || !len) return; if(! _db_parms->log_enable) return; if (_tp->logflags == JLOG_NONE) return; - + if ((_tp->logflags & op) == op) { int op_len=7; char buf[MAX_ROW_SIZE + op_len]; char *c; time_t now = time(NULL); - + if( _db_parms->journal_roll_interval) { if((_tp->t) && (now - _tp->t) > _db_parms->journal_roll_interval) @@ -506,7 +506,7 @@ void bdblib_log(int op, table_p _tp, char* _msg, int len) } } } - + c = buf; switch (op) { @@ -520,21 +520,21 @@ void bdblib_log(int op, table_p _tp, char* _msg, int len) strncpy(c, "DELETE|", op_len); break; } - + c += op_len; strncpy(c, _msg, len); c +=len; *c = '\n'; c++; *c = '\0'; - + if ((_tp->logflags & JLOG_STDOUT) == JLOG_STDOUT) puts(buf); - + if ((_tp->logflags & JLOG_SYSLOG) == JLOG_SYSLOG) syslog(LOG_LOCAL6, "%s", buf); - - if(_tp->fp) + + if(_tp->fp) { if(!fputs(buf, _tp->fp) ) fflush(_tp->fp); @@ -544,16 +544,16 @@ void bdblib_log(int op, table_p _tp, char* _msg, int len) /** * The function is called to create a handle to a db table. - * + * * On startup, we do not create any of the db handles. - * Instead it is done on first-use (lazy-initialized) to only create handles to + * Instead it is done on first-use (lazy-initialized) to only create handles to * files (db) that we require. - * + * * There is one db file per opensips table (eg. acc), and they should exist * in your DB_PATH (refer to opensipsctlrc) directory. * * This function does _not_ create the underlying binary db tables. - * Creating the tables MUST be manually performed before + * Creating the tables MUST be manually performed before * opensips startup by 'opensipsdbctl create' * * Function returns NULL on error, which will cause opensips to exit. @@ -565,7 +565,7 @@ table_p bdblib_create_table(database_p _db, str *_s) int rc,i,flags; DB *bdb = NULL; table_p tp = NULL; - char tblname[MAX_TABLENAME_SIZE]; + char tblname[MAX_TABLENAME_SIZE]; if(!_db || !_db->dbenv) { @@ -581,7 +581,7 @@ table_p bdblib_create_table(database_p _db, str *_s) } if ((rc = db_create(&bdb, _db->dbenv, 0)) != 0) - { + { _db->dbenv->err(_db->dbenv, rc, "database create"); LM_ERR("error in db_create, bdb error: %s.\n",db_strerror(rc)); pkg_free(tp); @@ -598,7 +598,7 @@ table_p bdblib_create_table(database_p _db, str *_s) flags = DB_THREAD; if ((rc = bdb->open(bdb, NULL, tblname, NULL, DB_HASH, flags, 0664)) != 0) - { + { _db->dbenv->err(_db->dbenv, rc, "DB->open: %s", tblname); LM_ERR("bdb open failed: %s.\n",db_strerror(rc)); pkg_free(tp); @@ -609,7 +609,7 @@ table_p bdblib_create_table(database_p _db, str *_s) { goto error; } - + tp->name.s = (char*)pkg_malloc(_s->len*sizeof(char)); memcpy(tp->name.s, _s->s, _s->len); tp->name.len = _s->len; @@ -621,12 +621,12 @@ table_p bdblib_create_table(database_p _db, str *_s) tp->logflags=0; /*bitmap; 4=Delete, 2=Update, 1=Insert, 0=None*/ tp->fp=0; tp->t=0; - + for(i=0;icolp[i] = NULL; /*load metadata; seeded\db_loaded when database are created*/ - + /*initialize columns with metadata*/ rc = load_metadata_columns(tp); if(rc!=0) @@ -634,7 +634,7 @@ table_p bdblib_create_table(database_p _db, str *_s) LM_ERR("FAILED to load METADATA COLS in table: %s.\n", tblname); goto error; } - + /*initialize columns default values from metadata*/ rc = load_metadata_defaults(tp); if(rc!=0) @@ -642,7 +642,7 @@ table_p bdblib_create_table(database_p _db, str *_s) LM_ERR("FAILED to load METADATA DEFAULTS in table: %s.\n", tblname); goto error; } - + rc = load_metadata_keys(tp); if(rc!=0) { @@ -660,52 +660,52 @@ table_p bdblib_create_table(database_p _db, str *_s) } if(tp->ro) - { + { /*schema defines this table RO readonly*/ #ifdef BDB_EXTRA_DEBUG LM_DBG("TABLE %.*s is changing to READONLY mode\n" , tp->name.len, tp->name.s); #endif - + if ((rc = bdb->close(bdb,0)) != 0) - { + { _db->dbenv->err(_db->dbenv, rc, "DB->close: %s", tblname); LM_ERR("bdb close: %s.\n",db_strerror(rc)); goto error; } - + bdb = NULL; if ((rc = db_create(&bdb, _db->dbenv, 0)) != 0) - { + { _db->dbenv->err(_db->dbenv, rc, "database create"); LM_ERR("error in db_create.\n"); goto error; } - + flags = DB_THREAD | DB_RDONLY; if ((rc = bdb->open(bdb, NULL, tblname, NULL, DB_HASH, flags, 0664)) != 0) - { + { _db->dbenv->err(_db->dbenv, rc, "DB->open: %s", tblname); LM_ERR("bdb open: %s.\n",db_strerror(rc)); goto error; } tp->db=bdb; } - + /* set the journaling flags; flags indicate which operations need to be journalled. (e.g possible to only journal INSERT.) */ rc = load_metadata_logflags(tp); if(rc!=0) LM_INFO("No METADATA_LOGFLAGS in table: %s.\n", tblname); - + if ((tp->logflags & JLOG_FILE) == JLOG_FILE) bdblib_create_journal(tp); - + return tp; - + error: - if(tp) + if(tp) { pkg_free(tp->name.s); pkg_free(tp); @@ -723,26 +723,26 @@ int bdblib_create_journal(table_p _tp) int bl; database_p _db_p = *_cachedb; time_t tim = time(NULL); - + if(! _db_p || ! _tp) return -1; if(! _db_parms->log_enable) return 0; /* journal filename ; e.g. '/var/opensips/db/location-YYYYMMDDhhmmss.jnl' */ s=fn; strncpy(s, _db_p->name.s, _db_p->name.len); s+=_db_p->name.len; - + *s = '/'; s++; - + strncpy(s, _tp->name.s, _tp->name.len); s+=_tp->name.len; - + t = localtime( &tim ); bl=strftime(d,128,"-%Y%m%d%H%M%S.jnl",t); strncpy(s, d, bl); s+= bl; *s = 0; - + if(_tp->fp) { /* must be rolling. */ if( fclose(_tp->fp) ) @@ -751,7 +751,7 @@ int bdblib_create_journal(table_p _tp) return -1; } } - + if( (fp = fopen(fn, "w")) != NULL ) { _tp->fp = fp; @@ -761,7 +761,7 @@ int bdblib_create_journal(table_p _tp) LM_ERR("Failed to Open Log in table: %.*s .\n",_tp->name.len, _tp->name.s); return -1; } - + _tp->t = tim; return 0; @@ -778,13 +778,13 @@ int load_metadata_columns(table_p _tp) DBT key, data; column_p col; ret = n = len = 0; - + if(!_tp || !_tp->db) return -1; - + if(_tp->ncols!=0) return 0; - + db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); @@ -797,39 +797,39 @@ int load_metadata_columns(table_p _tp) data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; - - if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) + + if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) { db->err(db, ret, "load_metadata_columns DB->get failed"); LM_ERR("FAILED to find METADATA_COLUMNS in DB \n"); return -1; } - + /* eg: dbuf = "table_name(str) table_version(int)" */ LM_DBG("Found: [%s]\n",dbuf); tmp = dbuf; s = strsep(&tmp, " "); - while(s!=NULL && nname.s = (char*)pkg_malloc(len * sizeof(char)); memcpy(col->name.s, cn, len ); col->name.len = len; - + /*set column type*/ if(strncmp(ct, "str", 3)==0) { col->type = DB_STRING; @@ -849,7 +849,7 @@ int load_metadata_columns(table_p _tp) else { col->type = DB_STRING; } - + col->flag = 0; _tp->colp[n] = col; n++; @@ -869,10 +869,10 @@ int load_metadata_keys(table_p _tp) DB *db = NULL; DBT key, data; ret = n = ci = 0; - + if(!_tp || !_tp->db) return -1; - + db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); @@ -882,8 +882,8 @@ int load_metadata_keys(table_p _tp) data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; - - if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) + + if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) { db->err(db, ret, "load_metadata_keys DB->get failed"); LM_ERR("FAILED to find METADATA in table \n"); @@ -897,7 +897,7 @@ int load_metadata_keys(table_p _tp) while(s!=NULL && strlen(s) && n< _tp->ncols) { ret = sscanf(s,"%i", &ci); if(ret != 1) return -1; - if( _tp->colp[ci] ) + if( _tp->colp[ci] ) { _tp->colp[ci]->flag = 1; _tp->nkeys++; } @@ -917,10 +917,10 @@ int load_metadata_readonly(table_p _tp) DB *db = NULL; DBT key, data; i = 0; - + if(!_tp || !_tp->db) return -1; - + db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); @@ -930,14 +930,14 @@ int load_metadata_readonly(table_p _tp) data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; - - if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) + + if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) { return ret; } - + if( 1 == sscanf(dbuf,"%i", &i) ) _tp->ro=(i>0)?1:0; - + return 0; } @@ -949,10 +949,10 @@ int load_metadata_logflags(table_p _tp) DB *db = NULL; DBT key, data; i = 0; - + if(!_tp || !_tp->db) return -1; - + db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); @@ -962,14 +962,14 @@ int load_metadata_logflags(table_p _tp) data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; - - if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) + + if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) { return ret; } - + if( 1 == sscanf(dbuf,"%i", &i) ) _tp->logflags=i; - + return 0; } @@ -984,10 +984,10 @@ int load_metadata_defaults(table_p _tp) DBT key, data; column_p col; ret = n = len = 0; - + if(!_tp || !_tp->db) return -1; - + db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); @@ -1000,8 +1000,8 @@ int load_metadata_defaults(table_p _tp) data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; - - if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) + + if ((ret = db->get(db, NULL, &key, &data, 0)) != 0) { #ifdef BDB_EXTRA_DEBUG LM_DBG("NO DEFAULTS ; SETTING ALL columns to NULL! \n" ); @@ -1011,7 +1011,7 @@ int load_metadata_defaults(table_p _tp) for(n=0; n<_tp->ncols; n++) { col = _tp->colp[n]; - if( col ) + if( col ) { /*set all columns default value to 'NULL' */ len = strlen("NULL"); col->dv.s = (char*)pkg_malloc(len * sizeof(char)); @@ -1021,18 +1021,18 @@ int load_metadata_defaults(table_p _tp) } return 0; } - + /* use the defaults provided*/ LM_DBG("Found: [%s]\n",dbuf); tmp = dbuf; s = strsep(&tmp, DELIM); - while(s!=NULL && n< _tp->ncols) + while(s!=NULL && n< _tp->ncols) { strcpy(cv,s); col = _tp->colp[n]; - if( col ) + if( col ) { /*set column default*/ len = strlen(s); col->dv.s = (char*)pkg_malloc(len * sizeof(char)); @@ -1049,7 +1049,7 @@ int load_metadata_defaults(table_p _tp) n++; s = strsep( &tmp, DELIM); } - + return 0; } @@ -1061,7 +1061,7 @@ int load_metadata_defaults(table_p _tp) */ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v, int _n, int _ko) { - char *p; + char *p; char sk[MAX_ROW_SIZE]; // subkey(sk) val char* delim = DELIM; char* cNULL = "NULL"; @@ -1070,18 +1070,18 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v p = _k; len = sum = total = 0; i = j = k = 0; - + if(!_tp) return -1; if(!_v || (_n<1) ) return -1; if(!_k || !_klen ) return -1; if( *_klen < 1) return -1; - + memset(sk, 0, MAX_ROW_SIZE); total = *_klen; *_klen = 0; //sum - + if(! _lres) - { + { #ifdef BDB_EXTRA_DEBUG LM_DBG("schema has NOT specified any keys! \n"); #endif @@ -1091,7 +1091,7 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v */ for(i=0;i<_n;i++) { len = total - sum; - if ( bdb_val2str(&_v[i], sk, &len) != 0 ) + if ( bdb_val2str(&_v[i], sk, &len) != 0 ) { LM_ERR("error building composite key \n"); return -2; } @@ -1100,7 +1100,7 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v if(sum > total) { LM_ERR("Destination buffer too short for subval %s\n",sk); return -2; - } + } /* write sk */ strncpy(p, sk, len); @@ -1112,7 +1112,7 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v { LM_ERR("Destination buffer too short for delim \n"); return -3; } - + /* write delim */ strncpy(p, delim, DELIM_LEN); p += DELIM_LEN; @@ -1131,12 +1131,12 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v { /* i indexes columns in schema order */ if( _ko) { /* keymode; skip over non-key columns */ - if( ! _tp->colp[i]->flag) - continue; + if( ! _tp->colp[i]->flag) + continue; } - + for(j=0; j<_n; j++) - { + { /* j indexes the columns provided in _k which may be less than the total required by @@ -1144,7 +1144,7 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v of the columns in our schema! */ k = (_lres) ? _lres[j] : j; - + /* * k index will remap back to our schema order; like i */ @@ -1152,14 +1152,14 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v { /* KEY was provided; append to buffer; - _k[j] contains a key, but its a key that + _k[j] contains a key, but its a key that corresponds to column k of our schema. now we know its a match, and we dont need index k for anything else */ #ifdef BDB_EXTRA_DEBUG - LM_DBG("KEY PROVIDED[%i]: %.*s.%.*s \n", i - , _tp->name.len , ZSW(_tp->name.s) + LM_DBG("KEY PROVIDED[%i]: %.*s.%.*s \n", i + , _tp->name.len , ZSW(_tp->name.s) , _tp->colp[i]->name.len, ZSW(_tp->colp[i]->name.s) ); #endif @@ -1169,7 +1169,7 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v { LM_ERR("Error while converting to str %s\n",sk); return -4; } - + sum += len; if(sum > total) { LM_ERR("Destination buffer too short for subval %s\n",sk); @@ -1184,21 +1184,21 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v if(sum > total) { LM_ERR("Destination buffer too short for delim \n"); return -5; - } - + } + /* append delim */ strncpy(p, delim, DELIM_LEN); p += DELIM_LEN; *_klen = sum; - - + + /* take us out of inner for loop and at the end of the outer loop to look for our next schema key */ goto next; } - + } /* @@ -1207,7 +1207,7 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v */ #ifdef BDB_EXTRA_DEBUG LM_DBG("Missing KEY[%i]: %.*s.%.*s using default [%.*s] \n", i - , _tp->name.len , ZSW(_tp->name.s) + , _tp->name.len , ZSW(_tp->name.s) , _tp->colp[i]->name.len, ZSW(_tp->colp[i]->name.s) , _tp->colp[i]->dv.len , ZSW(_tp->colp[i]->dv.s) ); @@ -1218,17 +1218,17 @@ int bdblib_valtochar(table_p _tp, int* _lres, char* _k, int* _klen, db_val_t* _v { LM_ERR("Destination buffer too short for subval %s\n",cNULL); return -5; } - + strncpy(p, _tp->colp[i]->dv.s, len); p += len; *_klen = sum; - + sum += DELIM_LEN; if(sum > total) { LM_ERR("Destination buffer too short for delim \n"); return -5; - } - + } + strncpy(p, delim, DELIM_LEN); p += DELIM_LEN; *_klen = sum; @@ -1259,13 +1259,13 @@ int db_free(database_p _dbp) tbl_cache_free(_tbc); _tbc = _tbc0; } - + if(_dbp->dbenv) _dbp->dbenv->close(_dbp->dbenv, 0); - + if(_dbp->name.s) pkg_free(_dbp->name.s); - + pkg_free(_dbp); return 0; @@ -1279,12 +1279,12 @@ int tbl_cache_free(tbl_cache_p _tbc) { if(!_tbc) return -1; - + lock_get(&_tbc->sem); - + if(_tbc->dtp) tbl_free(_tbc->dtp); - + lock_destroy(&_tbc->sem); pkg_free(_tbc); @@ -1302,13 +1302,13 @@ int tbl_free(table_p _tp) if(_tp->db) _tp->db->close(_tp->db, 0); - + if(_tp->fp) fclose(_tp->fp); if(_tp->name.s) pkg_free(_tp->name.s); - + for(i=0;i<_tp->ncols;i++) { if(_tp->colp[i]) { pkg_free(_tp->colp[i]->name.s); @@ -1327,13 +1327,13 @@ int bdblib_recover(table_p _tp, int _rc) { case DB_LOCK_DEADLOCK: LM_ERR("DB_LOCK_DEADLOCK detected !!\n"); - + case DB_RUNRECOVERY: LM_ERR("DB_RUNRECOVERY detected !! \n"); bdblib_destroy(); exit(1); break; } - + return 0; } diff --git a/modules/db_berkeley/bdb_lib.h b/modules/db_berkeley/bdb_lib.h index ec2d1753b77..c9675fc0499 100644 --- a/modules/db_berkeley/bdb_lib.h +++ b/modules/db_berkeley/bdb_lib.h @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) diff --git a/modules/db_berkeley/bdb_mi.c b/modules/db_berkeley/bdb_mi.c index b92dd828f78..bdf39b8fbc3 100644 --- a/modules/db_berkeley/bdb_mi.c +++ b/modules/db_berkeley/bdb_mi.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -41,21 +41,21 @@ struct mi_root* mi_bdb_reload(struct mi_root *cmd, void *param) { struct mi_node *node; str *db_path; - + node = cmd->node.kids; if (node && node->next) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); - + db_path = &node->value; - + if (!db_path || db_path->len == 0) return init_mi_tree( 400, "bdb_reload missing db arg", 21); - if (bdb_reload(db_path->s) == 0) + if (bdb_reload(db_path->s) == 0) { return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); - } - else + } + else { return init_mi_tree( 500, "db_berkeley Reload Failed", 26); } diff --git a/modules/db_berkeley/bdb_mi.h b/modules/db_berkeley/bdb_mi.h index 9c9344bd27e..01aff4d27a5 100644 --- a/modules/db_berkeley/bdb_mi.h +++ b/modules/db_berkeley/bdb_mi.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_berkeley/bdb_res.c b/modules/db_berkeley/bdb_res.c index 49ae3d5eb13..f20f3437277 100644 --- a/modules/db_berkeley/bdb_res.c +++ b/modules/db_berkeley/bdb_res.c @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) @@ -100,13 +100,13 @@ int bdb_convert_row(db_res_t* _res, char *bdb_result, int* _lres) /* Save the number of rows in the current fetch */ RES_ROW_N(_res) = 1; row = RES_ROWS(_res); - + /* Save the number of columns in the ROW structure */ ROW_N(row) = RES_COL_N(_res); /* * Allocate an array of pointers one per column. - * It that will be used to hold the address of the string + * It that will be used to hold the address of the string * representation of each column. */ len = sizeof(char *) * RES_COL_N(_res); @@ -142,7 +142,7 @@ int bdb_convert_row(db_res_t* _res, char *bdb_result, int* _lres) memset(row_buf[i], 0, len+1); strncpy(row_buf[i], s, len); } - + } } else { @@ -184,10 +184,10 @@ int bdb_convert_row(db_res_t* _res, char *bdb_result, int* _lres) row->values[col].type == DB_DATETIME ) pkg_free(row_buf[col]); - + } - + LM_DBG("freeing row buffer at %p\n", row_buf); if( row_buf[col]) pkg_free(row_buf); @@ -213,14 +213,14 @@ int bdb_append_row(db_res_t* _res, char *bdb_result, int* _lres, int _rx) char **row_buf, *s; db_row_t* row = NULL; col = len = i = j = 0; - + if (!_res) { LM_ERR("invalid parameter"); return -1; } - + row = &(RES_ROWS(_res)[_rx]); - + /* Save the number of columns in the ROW structure */ ROW_N(row) = RES_COL_N(_res); @@ -236,14 +236,14 @@ int bdb_append_row(db_res_t* _res, char *bdb_result, int* _lres, int _rx) } LM_DBG("allocate for %d columns %d bytes in row buffer at %p\n", RES_COL_N(_res), len, row_buf); memset(row_buf, 0, len); - + /*populate the row_buf with bdb_result*/ /*bdb_result is memory from our callers stack so we copy here*/ LM_DBG("Found: [%s]\n",bdb_result); - + s = strsep(&bdb_result, DELIM); while( s!=NULL) { @@ -285,7 +285,7 @@ int bdb_append_row(db_res_t* _res, char *bdb_result, int* _lres, int _rx) s = strsep(&bdb_result, DELIM); col++; } - + /*do the type conversion per col*/ for(col = 0; col < ROW_N(row); col++) { #ifdef BDB_EXTRA_DEBUG @@ -315,7 +315,7 @@ int bdb_append_row(db_res_t* _res, char *bdb_result, int* _lres, int _rx) pkg_free(row_buf[col]); } - + if( row_buf ) pkg_free(row_buf); row_buf = NULL; @@ -335,14 +335,14 @@ int bdb_append_row(db_res_t* _res, char *bdb_result, int* _lres, int _rx) int* bdb_get_colmap(table_p _dtp, db_key_t* _k, int _n) { int i, j, *_lref=NULL; - + if(!_dtp || !_k || _n < 0) return NULL; - + _lref = (int*)pkg_malloc(_n*sizeof(int)); if(!_lref) return NULL; - + for(i=0; i < _n; i++) { for(j=0; j<_dtp->ncols; j++) { @@ -366,11 +366,14 @@ int* bdb_get_colmap(table_p _dtp, db_key_t* _k, int _n) int bdb_is_neq_type(db_type_t _t0, db_type_t _t1) { if(_t0 == _t1) return 0; - + switch(_t1) { case DB_INT: - if(_t0==DB_DATETIME || _t0==DB_BITMAP) + if(_t0==DB_BIGINT || _t0==DB_DATETIME || _t0==DB_BITMAP) + return 0; + case DB_BIGINT: + if(_t0==DB_INT || _t0==DB_DATETIME || _t0==DB_BITMAP) return 0; case DB_DATETIME: if(_t0==DB_INT) @@ -402,12 +405,12 @@ int bdb_row_match(db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n, db_res_t* _r { int i, res; db_row_t* row = NULL; - + if(!_r || !_lkey) return 1; - + row = RES_ROWS(_r); - + for(i=0; i<_n; i++) { res = bdb_cmp_val(&(ROW_VALUES(row)[_lkey[i]]), &_v[i]); @@ -434,7 +437,7 @@ int bdb_row_match(db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n, db_res_t* _r return res; }}}}} } - + return 1; } @@ -443,7 +446,7 @@ int bdb_row_match(db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n, db_res_t* _r int bdb_cmp_val(db_val_t* _vp, db_val_t* _v) { int _l, _n; - + if(!_vp && !_v) return 0; if(!_v) @@ -456,7 +459,7 @@ int bdb_cmp_val(db_val_t* _vp, db_val_t* _v) return 1; if(_vp->nul) return -1; - + switch(VAL_TYPE(_v)) { case DB_INT: diff --git a/modules/db_berkeley/bdb_res.h b/modules/db_berkeley/bdb_res.h index 27a56de453f..ecd28dba9b0 100644 --- a/modules/db_berkeley/bdb_res.h +++ b/modules/db_berkeley/bdb_res.h @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) diff --git a/modules/db_berkeley/bdb_util.c b/modules/db_berkeley/bdb_util.c index 091693cafab..cc7a03dc421 100644 --- a/modules/db_berkeley/bdb_util.c +++ b/modules/db_berkeley/bdb_util.c @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) @@ -40,7 +40,7 @@ int bdb_is_database(str *_s) { DIR *dirp = NULL; char buf[512]; - + if(!_s || !_s->s || _s->len <= 0 || _s->len > 510) return 0; strncpy(buf, _s->s, _s->len); diff --git a/modules/db_berkeley/bdb_util.h b/modules/db_berkeley/bdb_util.h index d2e5786bf55..1afc0560a16 100644 --- a/modules/db_berkeley/bdb_util.h +++ b/modules/db_berkeley/bdb_util.h @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) diff --git a/modules/db_berkeley/bdb_val.c b/modules/db_berkeley/bdb_val.c index 1d1e8cefeb2..184ed65b2eb 100644 --- a/modules/db_berkeley/bdb_val.c +++ b/modules/db_berkeley/bdb_val.c @@ -18,15 +18,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) */ - + #include "../../db/db_val.h" #include "../../db/db_ut.h" @@ -152,8 +152,8 @@ int bdb_str2val(db_type_t _t, db_val_t* _v, char* _s, int _l) VAL_TYPE(_v) = DB_STRING; VAL_FREE(_v) = 1; } - - + + return 0; case DB_STR: @@ -168,7 +168,7 @@ int bdb_str2val(db_type_t _t, db_val_t* _v, char* _s, int _l) VAL_TYPE(_v) = DB_STR; VAL_FREE(_v) = 1; } - + return 0; @@ -204,12 +204,12 @@ int bdb_val2str(db_val_t* _v, char* _s, int* _len) { int l; - if (VAL_NULL(_v)) + if (VAL_NULL(_v)) { *_len = snprintf(_s, *_len, "NULL"); return 0; } - + switch(VAL_TYPE(_v)) { case DB_INT: if (db_int2str(VAL_INT(_v), _s, _len) < 0) { @@ -243,7 +243,7 @@ int bdb_val2str(db_val_t* _v, char* _s, int* _len) case DB_DOUBLE: if (db_double2str(VAL_DOUBLE(_v), _s, _len) < 0) { - LM_ERR("Error while converting double to string\n"); + LM_ERR("Error while converting double to string\n"); return -3; } else { LM_DBG("Converted double to string\n"); @@ -253,11 +253,11 @@ int bdb_val2str(db_val_t* _v, char* _s, int* _len) case DB_STRING: l = strlen(VAL_STRING(_v)); - if (*_len < l ) + if (*_len < l ) { LM_ERR("Destination buffer too short for string\n"); return -4; - } - else + } + else { LM_DBG("Converted string to string\n"); strncpy(_s, VAL_STRING(_v) , l); _s[l] = 0; @@ -272,8 +272,8 @@ int bdb_val2str(db_val_t* _v, char* _s, int* _len) { LM_ERR("Destination buffer too short for str\n"); return -5; - } - else + } + else { LM_DBG("Converted str to string\n"); strncpy(_s, VAL_STR(_v).s , l); @@ -294,12 +294,12 @@ int bdb_val2str(db_val_t* _v, char* _s, int* _len) case DB_BLOB: l = VAL_BLOB(_v).len; - if (*_len < l) + if (*_len < l) { LM_ERR("Destination buffer too short for blob\n"); return -7; - } - else + } + else { strncpy(_s, VAL_BLOB(_v).s , l); LM_DBG("Converting BLOB [%.*s]\n", l,_s); diff --git a/modules/db_berkeley/bdb_val.h b/modules/db_berkeley/bdb_val.h index 412ca69c95d..ce0a399fe35 100644 --- a/modules/db_berkeley/bdb_val.h +++ b/modules/db_berkeley/bdb_val.h @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) diff --git a/modules/db_berkeley/db_berkeley.c b/modules/db_berkeley/db_berkeley.c index 212085678b3..f1f13684506 100644 --- a/modules/db_berkeley/db_berkeley.c +++ b/modules/db_berkeley/db_berkeley.c @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) @@ -92,10 +92,12 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; -struct module_exports exports = { +struct module_exports exports = { "db_berkeley", + MOD_TYPE_SQLDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -112,12 +114,12 @@ struct module_exports exports = { static int mod_init(void) { db_parms_t p; - + p.auto_reload = auto_reload; p.log_enable = log_enable; p.cache_size = (4 * 1024 * 1024); //4Mb p.journal_roll_interval = journal_roll_interval; - + if(bdblib_init(&p)) return -1; @@ -142,7 +144,7 @@ int bdb_bind_api(const str* mod, db_func_t *dbb) dbb->query = (db_query_f)bdb_query; dbb->free_result = bdb_free_query; dbb->insert = (db_insert_f)bdb_insert; - dbb->delete = (db_delete_f)bdb_delete; + dbb->delete = (db_delete_f)bdb_delete; dbb->update = (db_update_f)bdb_update; return 0; @@ -161,12 +163,12 @@ db_con_t* bdb_init(const str* _sqlurl) db_con_t* _res; str _s; char bdb_path[BDB_PATH_LEN]; - + if (!_sqlurl || !_sqlurl->s) { LM_ERR("invalid parameter value\n"); return 0; } - + _s.s = _sqlurl->s; _s.len = _sqlurl->len; if(_s.len <= BDB_ID_LEN || strncmp(_s.s, BDB_ID, BDB_ID_LEN)!=0) @@ -177,7 +179,7 @@ db_con_t* bdb_init(const str* _sqlurl) } _s.s += BDB_ID_LEN; _s.len -= BDB_ID_LEN; - + if(_s.s[0]!='/') { if(sizeof(CFG_DIR)+_s.len+2 > BDB_PATH_LEN) @@ -191,7 +193,7 @@ db_con_t* bdb_init(const str* _sqlurl) _s.len += sizeof(CFG_DIR); _s.s = bdb_path; } - + _res = pkg_malloc(sizeof(db_con_t)+sizeof(bdb_con_t)); if (!_res) { @@ -223,7 +225,7 @@ void bdb_close(db_con_t* _h) pkg_free(_h); } -/* +/* * n can be the dbenv path or a table name */ int bdb_reload(char* _n) @@ -233,12 +235,12 @@ int bdb_reload(char* _n) LM_DBG("[bdb_reload] Initiate RELOAD in %s\n", _n); #endif - if ((rc = bdblib_close(_n)) != 0) + if ((rc = bdblib_close(_n)) != 0) { LM_ERR("[bdb_reload] Error while closing db_berkeley DB.\n"); return rc; } - if ((rc = bdblib_reopen(_n)) != 0) + if ((rc = bdblib_reopen(_n)) != 0) { LM_ERR("[bdb_reload] Error while reopening db_berkeley DB.\n"); return rc; } @@ -264,40 +266,40 @@ void bdb_check_reload(db_con_t* _con) char t[MAX_TABLENAME_SIZE]; table_p tp = NULL; tbl_cache_p tbc = NULL; - + p=n; rc = len = 0; - + /*get dbenv name*/ db = BDB_CON_CONNECTION(_con); if(!db->dbenv) return; s.s = db->name.s; s.len = db->name.len; len+=s.len; - + if(len > MAX_ROW_SIZE) { LM_ERR("dbenv name too long \n"); return; } - + strncpy(p, s.s, s.len); p+=s.len; - + len++; if(len > MAX_ROW_SIZE) { LM_ERR("dbenv name too long \n"); return; } - + /*append slash */ *p = '/'; p++; - + /*get table name*/ s.s = CON_TABLE(_con)->s; s.len = CON_TABLE(_con)->len; len+=s.len; - + if((len>MAX_ROW_SIZE) || (s.len > MAX_TABLENAME_SIZE) ) { LM_ERR("table name too long \n"); return; @@ -305,23 +307,23 @@ void bdb_check_reload(db_con_t* _con) strncpy(t, s.s, s.len); t[s.len] = 0; - + strncpy(p, s.s, s.len); p+=s.len; *p=0; - + if( (tbc = bdblib_get_table(db, &s)) == NULL) return; - + if( (tp = tbc->dtp) == NULL) return; - + LM_DBG("stat file [%.*s]\n", len, n); rc = stat(n, &st); if(!rc) { if((tp->ino!=0) && (st.st_ino != tp->ino)) bdb_reload(t); /*file changed on disk*/ - + tp->ino = st.st_ino; } @@ -352,14 +354,14 @@ int bdb_free_query(db_con_t* _h, db_res_t* _r) * _nc: number of columns to return * _o: order by the specified column */ -int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, +int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _c, int _n, int _nc, db_key_t _o, db_res_t** _r) { tbl_cache_p _tbc = NULL; table_p _tp = NULL; char kbuf[MAX_ROW_SIZE]; char dbuf[MAX_ROW_SIZE]; - u_int32_t i, ret; + u_int32_t i, ret; int klen=MAX_ROW_SIZE; int *lkey=NULL, *lres=NULL; DBT key, data; @@ -374,7 +376,7 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, return -1; } *_r = NULL; - + /*check if underlying DB file has changed inode */ if(auto_reload) bdb_check_reload(_con); @@ -397,20 +399,20 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, if (_o) LM_DBG("DONT-CARE : _o: order by the specified column \n"); if (_op) LM_DBG("DONT-CARE : _op: operators for refining query \n"); #endif - + db = _tp->db; if(!db) return -1; - + memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, MAX_ROW_SIZE); memset(&data, 0, sizeof(DBT)); memset(dbuf, 0, MAX_ROW_SIZE); - + data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; - /* if _c is NULL and _nc is zero, you will get all table + /* if _c is NULL and _nc is zero, you will get all table columns in the result */ if (_c) @@ -420,10 +422,10 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, goto error; } } - + if(_k) { lkey = bdb_get_colmap(_tbc->dtp, _k, _n); - if(!lkey) + if(!lkey) { ret = -1; goto error; } @@ -439,32 +441,32 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, #endif /* Acquire a cursor for the database. */ - if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) + if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) { LM_ERR("Error creating cursor\n"); goto error; } - + /*count the number of records*/ while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) - { if(!strncasecmp((char*)key.data,"METADATA",8)) + { if(!strncasecmp((char*)key.data,"METADATA",8)) continue; i++; } - + dbcp->c_close(dbcp); ret=0; - + #ifdef BDB_EXTRA_DEBUG LM_DBG("%i = SELECT COUNT(*) FROM %.*s\n", i, _tp->name.len, _tp->name.s); #endif *_r = db_new_result(); - if (!*_r) + if (!*_r) { LM_ERR("no memory left for result \n"); ret = -2; goto error; } - + if(i == 0) { /*return empty table*/ @@ -475,7 +477,7 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, RES_ROW_N(*_r) = i; /*fill in the column part of db_res_t (metadata) */ - if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) + if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) { LM_ERR("Error while getting column names\n"); goto error; } @@ -487,7 +489,7 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, } /* Acquire a cursor for the database. */ - if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) + if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) { LM_ERR("Error creating cursor\n"); goto error; } @@ -496,9 +498,9 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, i =0 ; while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { - if(!strncasecmp((char*)key.data,"METADATA",8)) + if(!strncasecmp((char*)key.data,"METADATA",8)) continue; - + #ifdef BDB_EXTRA_DEBUG LM_DBG("KEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size @@ -508,19 +510,19 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, #endif /*fill in the row part of db_res_t */ - if ((ret=bdb_append_row( *_r, dbuf, lres, i)) < 0) + if ((ret=bdb_append_row( *_r, dbuf, lres, i)) < 0) { LM_ERR("Error while converting row\n"); goto error; } i++; } - + dbcp->c_close(dbcp); BDB_CON_RESULT(_con) = *_r; - return 0; + return 0; } - if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) + if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) { LM_ERR("error in query key \n"); goto error; } @@ -536,7 +538,7 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, /*create an empty db_res_t which gets returned even if no result*/ *_r = db_new_result(); - if (!*_r) + if (!*_r) { LM_ERR("no memory left for result \n"); ret = -2; goto error; @@ -551,7 +553,7 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, #endif /*query Berkely DB*/ - if ((ret = db->get(db, NULL, &key, &data, 0)) == 0) + if ((ret = db->get(db, NULL, &key, &data, 0)) == 0) { #ifdef BDB_EXTRA_DEBUG LM_DBG("RESULT\nKEY: [%.*s]\nDATA: [%.*s]\n" @@ -562,7 +564,7 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, #endif /*fill in the col part of db_res_t */ - if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) + if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) { LM_ERR("Error while getting column names\n"); goto error; } @@ -572,31 +574,31 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, goto error; } /*fill in the row part of db_res_t */ - if ((ret=bdb_convert_row( *_r, dbuf, lres)) < 0) + if ((ret=bdb_convert_row( *_r, dbuf, lres)) < 0) { LM_ERR("Error while converting row\n"); goto error; } - + } else - { + { /*Berkeley DB error handler*/ switch(ret) { - + case DB_NOTFOUND: - + #ifdef BDB_EXTRA_DEBUG LM_DBG("NO RESULT for QUERY \n"); #endif - + ret=0; break; /*The following are all critical/fatal */ - case DB_LOCK_DEADLOCK: - // The operation was selected to resolve a deadlock. + case DB_LOCK_DEADLOCK: + // The operation was selected to resolve a deadlock. case DB_SECONDARY_BAD: - // A secondary index references a nonexistent primary key. + // A secondary index references a nonexistent primary key. case DB_RUNRECOVERY: default: LM_CRIT("DB->get error: %s.\n", db_strerror(ret)); @@ -604,23 +606,23 @@ int bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, goto error; } } - + if(lkey) pkg_free(lkey); if(lres) pkg_free(lres); - + return ret; - + error: if(lkey) pkg_free(lkey); if(lres) pkg_free(lres); - if(*_r) + if(*_r) db_free_result(*_r); *_r = NULL; - + return ret; } @@ -680,12 +682,12 @@ int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) #ifdef BDB_EXTRA_DEBUG LM_DBG("INSERT in %.*s\n", _tp->name.len, _tp->name.s ); #endif - + db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, klen); - - if(_tp->ncols<_n) + + if(_tp->ncols<_n) { LM_WARN("more values than columns!!\n"); return -5; } @@ -703,14 +705,14 @@ int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) goto error; } } - + /* make the key */ - if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) - { LM_ERR("Error in bdblib_valtochar \n"); + if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) + { LM_ERR("Error in bdblib_valtochar\n"); ret = -9; goto error; } - + key.data = kbuf; key.ulen = MAX_ROW_SIZE; key.flags = DB_DBT_USERMEM; @@ -720,8 +722,8 @@ int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) memset(&data, 0, sizeof(DBT)); memset(dbuf, 0, MAX_ROW_SIZE); - if ( (ret = bdblib_valtochar(_tp, lkey, dbuf, &dlen, _v, _n, BDB_VALUE)) != 0 ) - { LM_ERR("Error in bdblib_valtochar \n"); + if ( (ret = bdblib_valtochar(_tp, lkey, dbuf, &dlen, _v, _n, BDB_VALUE)) != 0 ) + { LM_ERR("Error in bdblib_valtochar\n"); ret = -9; goto error; } @@ -731,7 +733,7 @@ int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) data.flags = DB_DBT_USERMEM; data.size = dlen; - if ((ret = db->put(db, NULL, &key, &data, 0)) == 0) + if ((ret = db->put(db, NULL, &key, &data, 0)) == 0) { bdblib_log(JLOG_INSERT, _tp, dbuf, dlen); @@ -748,9 +750,9 @@ int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) switch(ret) { /*The following are all critical/fatal */ - case DB_LOCK_DEADLOCK: - /* The operation was selected to resolve a deadlock. */ - + case DB_LOCK_DEADLOCK: + /* The operation was selected to resolve a deadlock. */ + case DB_RUNRECOVERY: default: LM_CRIT("DB->put error: %s.\n", db_strerror(ret)); @@ -758,11 +760,11 @@ int bdb_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) goto error; } } - + error: if(lkey) pkg_free(lkey); - + return ret; } @@ -779,13 +781,13 @@ int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) tbl_cache_p _tbc = NULL; table_p _tp = NULL; char kbuf[MAX_ROW_SIZE]; - int i, j, ret, klen; + int ret, klen; int *lkey=NULL; DBT key,data; DB *db; DBC *dbcp; - i = j = ret = 0; + ret = 0; klen=MAX_ROW_SIZE; if (_op) @@ -818,14 +820,14 @@ int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) if(!_k || !_v || _n<=0) { /* Acquire a cursor for the database. */ - if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR) ) != 0) + if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR) ) != 0) { LM_ERR("Error creating cursor\n"); goto error; } - + while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { - if(!strncasecmp((char*)key.data,"METADATA",8)) + if(!strncasecmp((char*)key.data,"METADATA",8)) continue; #ifdef BDB_EXTRA_DEBUG LM_DBG("KEY: [%.*s]\n" @@ -834,7 +836,7 @@ int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) #endif ret = dbcp->c_del(dbcp, 0); } - + dbcp->c_close(dbcp); return 0; } @@ -843,7 +845,7 @@ int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) if(!lkey) return -5; /* make the key */ - if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) + if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) { LM_ERR("Error in bdblib_makekey\n"); ret = -6; goto error; @@ -865,14 +867,14 @@ int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) else { /*Berkeley DB error handler*/ switch(ret){ - + case DB_NOTFOUND: ret = 0; break; - + /*The following are all critical/fatal */ - case DB_LOCK_DEADLOCK: - /* The operation was selected to resolve a deadlock. */ + case DB_LOCK_DEADLOCK: + /* The operation was selected to resolve a deadlock. */ case DB_SECONDARY_BAD: /* A secondary index references a nonexistent primary key. */ case DB_RUNRECOVERY: @@ -885,20 +887,20 @@ int bdb_delete(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) } ret = 0; - + error: if(lkey) pkg_free(lkey); - + return ret; } /* -_bdb_delete_cursor -- called from bdb_delete when the query involves operators +_bdb_delete_cursor -- called from bdb_delete when the query involves operators other than equal '='. Adds support for queries like this: DELETE from SomeTable WHERE _k[0] < _v[0] - In this case, the keys _k are not the actually schema keys, so we need to + In this case, the keys _k are not the actually schema keys, so we need to iterate via cursor to perform this operation. */ int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) @@ -908,14 +910,14 @@ int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, i db_res_t* _r = NULL; char kbuf[MAX_ROW_SIZE]; char dbuf[MAX_ROW_SIZE]; - int i, ret, klen=MAX_ROW_SIZE; + int ret, klen=MAX_ROW_SIZE; DBT key, data; DB *db; DBC *dbcp; int *lkey=NULL; - - i = ret = 0; - + + ret = 0; + if ((!_h) || !CON_TABLE(_h)) return -1; @@ -930,45 +932,45 @@ int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, i { LM_WARN("table not loaded!\n"); return -4; } - + #ifdef BDB_EXTRA_DEBUG LM_DBG("DELETE by cursor in %.*s\n", _tp->name.len, _tp->name.s ); #endif if(_k) { lkey = bdb_get_colmap(_tp, _k, _n); - if(!lkey) + if(!lkey) { ret = -1; goto error; } } - + /* create an empty db_res_t which gets returned even if no result */ _r = db_new_result(); - if (!_r) + if (!_r) { LM_ERR("no memory for result \n"); } - + RES_ROW_N(_r) = 0; - + /* fill in the col part of db_res_t */ - if ((ret = bdb_get_columns(_tp, _r, 0, 0)) != 0) + if ((ret = bdb_get_columns(_tp, _r, 0, 0)) != 0) { LM_ERR("Error while getting column names\n"); goto error; } - + db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, klen); memset(&data, 0, sizeof(DBT)); memset(dbuf, 0, MAX_ROW_SIZE); - + data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; - + /* Acquire a cursor for the database. */ - if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR)) != 0) + if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR)) != 0) { LM_ERR("Error creating cursor\n"); } @@ -985,39 +987,39 @@ int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, i RES_ROW_N(_r) = 1; - + if(!strncasecmp((char*)key.data,"METADATA",8)) continue; - + /*fill in the row part of db_res_t */ - - if ((ret=bdb_convert_row( _r, dbuf, 0)) < 0) + + if ((ret=bdb_convert_row( _r, dbuf, 0)) < 0) { LM_ERR("Error while converting row\n"); goto error; } - + if(bdb_row_match(_k, _op, _v, _n, _r, lkey )) { #ifdef BDB_EXTRA_DEBUG - LM_DBG("DELETE ROW by KEY: [%.*s]\n", (int) key.size, + LM_DBG("DELETE ROW by KEY: [%.*s]\n", (int) key.size, (char *)key.data); #endif if((ret = dbcp->c_del(dbcp, 0)) != 0) - { + { /* Berkeley DB error handler */ LM_CRIT("DB->get error: %s.\n", db_strerror(ret)); bdblib_recover(_tp,ret); } - + } - + memset(dbuf, 0, MAX_ROW_SIZE); db_free_rows( _r); } ret = 0; - + error: if(dbcp) dbcp->c_close(dbcp); @@ -1025,7 +1027,7 @@ int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, i db_free_result(_r); if(lkey) pkg_free(lkey); - + return ret; } @@ -1037,7 +1039,7 @@ int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, i * _k: key names * _op: operators * _v: values of the keys that must match - * _uk: update keys; cols that need to be updated + * _uk: update keys; cols that need to be updated * _uv: update values; col values that need to be commited * _un: number of rows to update */ @@ -1055,9 +1057,9 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, char * tmp; DBT key, qdata, udata; DB *db; - + sum = ret = i = qcol = len = 0; - + if (!_con || !CON_TABLE(_con) || !_uk || !_uv || _un <= 0) return -1; @@ -1072,27 +1074,27 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, { LM_ERR("table not loaded\n"); return -1; } - + db = _tp->db; if(!db) { LM_ERR("DB null ptr\n"); return -1; } - + #ifdef BDB_EXTRA_DEBUG LM_DBG("UPDATE in %.*s\n", _tp->name.len, _tp->name.s); if (_op) LM_DBG("DONT-CARE : _op: operators for refining query \n"); #endif - + memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, MAX_ROW_SIZE); memset(&qdata, 0, sizeof(DBT)); memset(qbuf, 0, MAX_ROW_SIZE); - + qdata.data = qbuf; qdata.ulen = MAX_ROW_SIZE; qdata.flags = DB_DBT_USERMEM; - + if(_k) { lkey = bdb_get_colmap(_tbc->dtp, _k, _n); if(!lkey) return -4; @@ -1102,23 +1104,23 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, LM_ERR("Null keys in update _k=0 \n"); return -1; } - + len = MAX_ROW_SIZE; - - if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &len, _v, _n, BDB_KEY)) != 0 ) + + if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &len, _v, _n, BDB_KEY)) != 0 ) { LM_ERR("Error in query key \n"); goto cleanup; } - + if(lkey) pkg_free(lkey); - + key.data = kbuf; key.ulen = MAX_ROW_SIZE; key.flags = DB_DBT_USERMEM; key.size = len; - + /*stage 1: QUERY Berkely DB*/ - if ((ret = db->get(db, NULL, &key, &qdata, 0)) == 0) + if ((ret = db->get(db, NULL, &key, &qdata, 0)) == 0) { #ifdef BDB_EXTRA_DEBUG @@ -1133,17 +1135,17 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, else { goto db_error; } - + /* stage 2: UPDATE row with new values */ - - /* map the provided keys to those in our schema */ + + /* map the provided keys to those in our schema */ lkey = bdb_get_colmap(_tbc->dtp, _uk, _un); if(!lkey) return -4; - + /* build a new row for update data (udata) */ memset(&udata, 0, sizeof(DBT)); memset(ubuf, 0, MAX_ROW_SIZE); - + /* loop over each column of the qbuf and copy it to our new ubuf unless its a field that needs to update */ @@ -1157,16 +1159,16 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, while( c!=NULL) { char* delim = DELIM; int k; - + len = strlen(c); sum+=len; - + if(sum > MAX_ROW_SIZE) { LM_ERR("value too long for string \n"); ret = -3; goto cleanup; } - + for(i=0;i<_un;i++) { k = lkey[i]; @@ -1181,15 +1183,15 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, goto next; } - + } - + /* copy original column to the new column */ strncpy(t, c, len); next: t+=len; - + /* append DELIM */ sum += DELIM_LEN; if(sum > MAX_ROW_SIZE) @@ -1197,14 +1199,14 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, ret = -3; goto cleanup; } - + strncpy(t, delim, DELIM_LEN); t += DELIM_LEN; - + c = strsep(&tmp, DELIM); qcol++; } - + ubuf[sum] = '0'; udata.data = ubuf; udata.ulen = MAX_ROW_SIZE; @@ -1228,9 +1230,9 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, else { goto db_error; } - + /* stage 4: INSERT new row with key*/ - if ((ret = db->put(db, NULL, &key, &udata, 0)) == 0) + if ((ret = db->put(db, NULL, &key, &udata, 0)) == 0) { bdblib_log(JLOG_UPDATE, _tp, ubuf, sum); #ifdef BDB_EXTRA_DEBUG @@ -1253,7 +1255,7 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, cleanup: if(lkey) pkg_free(lkey); - + return ret; @@ -1262,27 +1264,27 @@ int bdb_update(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, /*Berkeley DB error handler*/ switch(ret) { - + case DB_NOTFOUND: - + #ifdef BDB_EXTRA_DEBUG LM_DBG("NO RESULT \n"); #endif return -1; - + /* The following are all critical/fatal */ - case DB_LOCK_DEADLOCK: + case DB_LOCK_DEADLOCK: /* The operation was selected to resolve a deadlock. */ case DB_SECONDARY_BAD: - /* A secondary index references a nonexistent primary key.*/ + /* A secondary index references a nonexistent primary key.*/ case DB_RUNRECOVERY: default: LM_CRIT("DB->get error: %s.\n", db_strerror(ret)); bdblib_recover(_tp,ret); } - + if(lkey) pkg_free(lkey); - + return ret; } diff --git a/modules/db_berkeley/db_berkeley.h b/modules/db_berkeley/db_berkeley.h index f32022c15c5..e017fbfbb72 100644 --- a/modules/db_berkeley/db_berkeley.h +++ b/modules/db_berkeley/db_berkeley.h @@ -18,10 +18,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) @@ -64,7 +64,7 @@ int bdb_free_query(db_con_t* _h, db_res_t* _r); /* * Do a query */ -int bdb_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, +int bdb_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _c, int _n, int _nc, db_key_t _o, db_res_t** _r); diff --git a/modules/db_cachedb/Makefile b/modules/db_cachedb/Makefile new file mode 100644 index 00000000000..daa9a3e189c --- /dev/null +++ b/modules/db_cachedb/Makefile @@ -0,0 +1,8 @@ +include ../../Makefile.defs + +auto_gen= +NAME=db_cachedb.so +LIBS= +DEFS+= + +include ../../Makefile.modules diff --git a/modules/db_cachedb/README b/modules/db_cachedb/README new file mode 100644 index 00000000000..4b024c8b091 --- /dev/null +++ b/modules/db_cachedb/README @@ -0,0 +1,146 @@ +db_cachedb Module + +Vladut-Stefan Paiu + + OpenSIPS Solutions + +Edited by + +Vladut-Stefan Paiu + + Copyright © 2013 www.opensips-solutions.com + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + + 1.1.1. The idea + 1.1.2. OpenSIPS Modules + 1.1.3. External Libraries or Applications + + 1.2. Exported Parameters + + 1.2.1. cachedb_url (str) + + 1.3. Examples of Usage + + 1.3.1. Distributed Subscriber Base + + 1.4. Current Limitations + + 1.4.1. CacheDB modules integration + 1.4.2. Extensive Testing Needed + 1.4.3. CacheDB Specific 'schema' and other + incompatibilities + + List of Examples + + 1.1. Set cachedb_url parameter + 1.2. OpenSIPS CFG Snippet for using DB_CACHEDB + +Chapter 1. Admin Guide + +1.1. Overview + +1.1. Overview + +1.1.1. The idea + + The db_cachedb module will expose the same front db api, + however it will run on top of a NoSQL back-end, emulating the + SQL calls to the back-end specific queries. Thus, any OpenSIPS + module that would regularily need a regular SQL-based database, + will now be able to run over a NoSQL back-end, allowing for a + much easier distribution and integration of the currently + existing OpenSIPS modules in a distributed environment. + +1.1.2. OpenSIPS Modules + + The following modules must be loaded before this module: + * At least one NoSQL cachedb_* module. + +1.1.3. External Libraries or Applications + + The following libraries or applications must be installed + before running OpenSIPS with this module loaded: + * None. + +1.2. Exported Parameters + +1.2.1. cachedb_url (str) + + The URL for the CacheDB back-end to be used. It can be set more + than one time. + + Example 1.1. Set cachedb_url parameter +... +modparam("db_cachedb","cachedb_url","mongodb:mycluster://127.0.0.1:27017 +/db.col") +... + +1.3. Examples of Usage + +1.3.1. Distributed Subscriber Base + + In order to achieve such a setup, one would have to set the + db_url parameter of the auth_db module to point to the + DB_CACHEDB URL. + + Example 1.2. OpenSIPS CFG Snippet for using DB_CACHEDB +loadmodule "auth_db.so" +modparam("auth_db", "load_credentials", "$avp(user_rpid)=rpid") + +loadmodule "db_cachedb.so" +loadmodule "cachedb_mongodb.so" +... +modparam("db_cachedb","cachedb_url","mongodb:mycluster://127.0.0.1:27017 +/my_db.col") +modparam("auth_db","db_url","cachedb://mongodb:mycluster") +... + + With such a setup, the auth_db module will load the subscribers + from the MongoDB cluster, in the 'my_db' database, in the + 'subscriber' collection. + + The same mechanism/setup can be used to run other modules ( + like usrloc, dialog, permissions, drouting, etc ) on top of a + cachedb cluster. + +1.4. Current Limitations + +1.4.1. CacheDB modules integration + + Currently the only cachedb_* module that implements this + functionality is the cachedb_mongodb module, so currently you + can only emulate SQL queries to a MongoDB instance/cluster. + There are plans to also extend this functionality to other + cachedb_* backends, like Cassandra and CouchBase. + +1.4.2. Extensive Testing Needed + + Since there are many OpenSIPS modules that currently use the DB + interface, it wasn't feasible to test all scenarios with all + modules, and there still might be some incompatibilities. The + module was tested with some regularily used modules ( like + usrloc, dialog, permissions, drouting ), but more testing is + very much welcome, and feedback is appreciated. + +1.4.3. CacheDB Specific 'schema' and other incompatibilities + + Since the NoSQL backends do not usually have a strict schema + involved, we do not provide scripts for creating such schemas, + since the insertion ops will trigger the dynamically creation + of the schema and info. Still, a specific data collection needs + to be present, and that is the equivalent of the 'version' + table from the SQL. Since most modules check the version table + at the module setup, it's the user's responsability to setup + such a 'version' collection in the respective NoSQL back-end. + For example, for the MongoDB cluster, 'version' is a reserved + keyword, so one would have to change the default version table + that OpenSIPS uses ( via the 'db_version_table' global + parameter ) and then manually insert the version number with + something like db.my_version_table.insert({table_version : + NumberInt(5), table_name : "address"}) diff --git a/modules/db_cachedb/db_cachedb.c b/modules/db_cachedb/db_cachedb.c new file mode 100644 index 00000000000..b13d072bed9 --- /dev/null +++ b/modules/db_cachedb/db_cachedb.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * history: + * --------- + * 2013-02-xx created (vlad-paiu) + */ + +#include "../../sr_module.h" +#include "../../db/db.h" +#include "dbase.h" +#include "../../mi/mi.h" +#include "../../pt.h" +#include +#include "../../mem/shm_mem.h" + +#include + +static int mod_init(void); +static void destroy(void); +int db_cachedb_bind_api(const str* mod, db_func_t *dbb); + +struct cachedb_url *db_cachedb_script_urls = NULL; + +int set_connection(unsigned int type, void *val) +{ + return cachedb_store_url(&db_cachedb_script_urls,(char *)val); +} + +/* + * Virtual database module interface + */ +static cmd_export_t cmds[] = { + {"db_bind_api", (cmd_function)db_cachedb_bind_api, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +/* + * Exported parameters + */ +static param_export_t params[] = { + {"cachedb_url", STR_PARAM|USE_FUNC_PARAM,(void*)&set_connection}, + {0, 0, 0} +}; + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_CACHEDB, NULL, DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + +struct module_exports exports = { + "db_cachedb", + MOD_TYPE_SQLDB, /* class of this module */ + MODULE_VERSION, + DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ + cmds, + params, /* module parameters */ + 0, /* exported statistics */ + 0, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + 0, /* response function*/ + destroy, /* destroy function */ + 0 /* per-child init function */ +}; + + +int db_cachedb_bind_api(const str* mod, db_func_t *dbb) +{ + LM_DBG("BINDING API for : %.*s\n", mod->len, mod->s); + + if(dbb==NULL) + return -1; + + memset(dbb, 0, sizeof(db_func_t)); + + dbb->use_table = db_cachedb_use_table; + dbb->init = db_cachedb_init; + dbb->close = db_cachedb_close; + dbb->query = db_cachedb_query; + dbb->free_result = db_cachedb_free_result; + dbb->insert = db_cachedb_insert; + dbb->delete = db_cachedb_delete; + dbb->update = db_cachedb_update; + dbb->raw_query = db_cachedb_raw_query; + + return 0; +} + +/** + * init module function + */ +static int mod_init(void) +{ + LM_NOTICE("initializing module db_cachedb ...\n"); + return 0; +} + +/* + * destroy function + */ +static void destroy(void) +{ + LM_NOTICE("destroy module db_cachedb ...\n"); + return; +} diff --git a/modules/db_cachedb/dbase.c b/modules/db_cachedb/dbase.c new file mode 100644 index 00000000000..9f388dfe299 --- /dev/null +++ b/modules/db_cachedb/dbase.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * history: + * --------- + * 2013-02-xx created (vlad-paiu) + */ + +#include "../../mem/mem.h" +#include "../../dprint.h" +#include "../../db/db_query.h" +#include "../../db/db_ut.h" +#include "../../db/db_id.h" +#include "../../timer.h" +#include "../../cachedb/cachedb.h" + +#include "dbase.h" + +extern struct cachedb_url *db_cachedb_script_urls; + +db_con_t* db_cachedb_init(const str* _url) +{ + char *p; + int len; + struct cachedb_url *it; + cachedb_funcs cdbf; + cachedb_con *cdbc = NULL; + struct db_cachedb_con* ptr; + db_con_t *res; + + if (!_url) { + LM_ERR("invalid parameter value\n"); + return 0; + } + + res = pkg_malloc(sizeof(db_con_t)); + if (!res) { + LM_ERR("No more pkg mem\n"); + return NULL; + } + + memset(res,0,sizeof(db_con_t)); + + p=_url->s+sizeof("cachedb:/"); + len=_url->len-sizeof("cachedb:/"); + + for (it=db_cachedb_script_urls;it;it=it->next) { + if (memcmp(it->url.s,p,len) == 0) { + LM_DBG("Found matching URL : [%.*s]\n",it->url.len,it->url.s); + + if (cachedb_bind_mod(&it->url,&cdbf) < 0) { + LM_ERR("Cannot bind cachedb functions for URL [%.*s]\n", + it->url.len,it->url.s); + return NULL; + } + + cdbc = cdbf.init(&it->url); + if (cdbc == NULL) { + LM_ERR("Failed to connect to the cachedb back-end\n"); + return NULL; + } + + ptr = pkg_malloc(sizeof(struct db_cachedb_con)); + if (!ptr) { + LM_ERR("no private memory left\n"); + pkg_free(res); + return 0; + } + + memset(ptr, 0, sizeof(struct db_cachedb_con)); + ptr->ref = 1; + + ptr->cdbc = cdbc; + ptr->cdbf = cdbf; + + res->tail = (unsigned long)ptr; + LM_DBG("Succesfully initiated connection to [%.*s] \n",len,p); + + return res; + } + } + + LM_ERR("No match for url [%.*s]\n",_url->len,_url->s); + return NULL; +} + +void db_cachedb_close(db_con_t* _h) +{ + struct db_cachedb_con* ptr = (struct db_cachedb_con *)_h->tail; + + LM_DBG("closing db_cachedb con \n"); + ptr->cdbf.destroy(ptr->cdbc); + pkg_free(_h); +} + + +int db_cachedb_free_result(db_con_t* _h, db_res_t* _r) +{ + struct db_cachedb_con* ptr = (struct db_cachedb_con *)_h->tail; + + if (ptr->cdbf.db_free_trans == NULL) { + LM_ERR("The selected NoSQL driver cannot convert free result queries\n"); + return -1; + } + + return ptr->cdbf.db_free_trans(ptr->cdbc,_r); +} + +int db_cachedb_query(const db_con_t* _h, const db_key_t* _k, const db_op_t* _op, + const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc, + const db_key_t _o, db_res_t** _r) +{ + struct db_cachedb_con* ptr = (struct db_cachedb_con *)_h->tail; + + if (ptr->cdbf.db_query_trans == NULL) { + LM_ERR("The selected NoSQL driver cannot convert select queries\n"); + return -1; + } + + return ptr->cdbf.db_query_trans(ptr->cdbc,_h->table,_k,_op,_v,_c,_n,_nc,_o,_r); +} + +int db_cachedb_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n) +{ + struct db_cachedb_con* ptr = (struct db_cachedb_con *)_h->tail; + + if (ptr->cdbf.db_insert_trans == NULL) { + LM_ERR("The selected NoSQL driver cannot convert insert queries\n"); + return -1; + } + + return ptr->cdbf.db_insert_trans(ptr->cdbc,_h->table,_k,_v,_n); +} + +int db_cachedb_delete(const db_con_t* _h, const db_key_t* _k, const + db_op_t* _o, const db_val_t* _v, const int _n) +{ + struct db_cachedb_con* ptr = (struct db_cachedb_con *)_h->tail; + + if (ptr->cdbf.db_delete_trans == NULL) { + LM_ERR("The selected NoSQL driver cannot convert delete queries\n"); + return -1; + } + + return ptr->cdbf.db_delete_trans(ptr->cdbc,_h->table,_k,_o,_v,_n); +} + +int db_cachedb_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o, + const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv, const int _n, + const int _un) +{ + struct db_cachedb_con* ptr = (struct db_cachedb_con *)_h->tail; + + if (ptr->cdbf.db_update_trans == NULL) { + LM_ERR("The selected NoSQL driver cannot convert update queries\n"); + return -1; + } + + return ptr->cdbf.db_update_trans(ptr->cdbc,_h->table,_k,_o,_v,_uk,_uv,_n,_un); +} + +int db_cachedb_use_table(db_con_t* _h, const str* _t) +{ + if (!_h || !_t || !_t->s) { + LM_ERR("invalid parameter value %p, %p\n", _h, _t); + return -1; + } + + CON_TABLE(_h) = _t; + return 0; +} + +int db_cachedb_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r) +{ + /* This will most likely never be supported :( */ + LM_ERR("RAW query not support by db_cachedb \n"); + return -1; +} diff --git a/modules/db_cachedb/dbase.h b/modules/db_cachedb/dbase.h new file mode 100644 index 00000000000..929d2542c18 --- /dev/null +++ b/modules/db_cachedb/dbase.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * history: + * --------- + * 2013-02-xx created (vlad-paiu) + */ + +#ifndef DB_CACHEDB_DBASE_H +#define DB_CACHEDB_DBASE_H + + +#include "../../db/db_val.h" +#include "../../cachedb/cachedb.h" +#include "../../str.h" + +struct db_cachedb_con { + struct db_id* id; /* Connection identifier */ + unsigned int ref; /* Reference count */ + struct pool_con* next; /* Next connection in the pool */ + + cachedb_funcs cdbf; /* pointers to the NoSQL specific functions */ + cachedb_con *cdbc; /* connection to actual NoSQL back-end */ +}; + +/* + * Initialize database connection + */ +db_con_t* db_cachedb_init(const str* _sqlurl); + + +/* + * Close a database connection + */ +void db_cachedb_close(db_con_t* _h); + + +/* + * Free all memory allocated by get_result + */ +int db_cachedb_free_result(db_con_t* _h, db_res_t* _r); + + +/* + * Do a query + */ +int db_cachedb_query(const db_con_t* _h, const db_key_t* _k, const db_op_t* _op, + const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc, + const db_key_t _o, db_res_t** _r); + + +/* + * Insert a row into table + */ +int db_cachedb_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n); + + +/* + * Delete a row from table + */ +int db_cachedb_delete(const db_con_t* _h, const db_key_t* _k, const + db_op_t* _o, const db_val_t* _v, const int _n); + + +/* + * Update a row in table + */ +int db_cachedb_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o, + const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv, const int _n, + const int _un); + +/* + * Store name of table that will be used by + * subsequent database functions + */ +int db_cachedb_use_table(db_con_t* _h, const str* _t); + +/* + * Raw SQL query + */ +int db_cachedb_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r); + +#endif /* DB_CACHEDB_DBASE_H */ diff --git a/modules/db_cachedb/doc/db_cachedb.xml b/modules/db_cachedb/doc/db_cachedb.xml new file mode 100644 index 00000000000..ffb94a09bc4 --- /dev/null +++ b/modules/db_cachedb/doc/db_cachedb.xml @@ -0,0 +1,49 @@ + + + + + + +%docentities; + +]> + + + +db_cachedb Module +&osipsname; + + +Vladut-Stefan +Paiu +OpenSIPS Solutions +
+vladpaiu@opensips.org + +http://www.opensips.org + +
+
+ +Vladut-Stefan +Paiu +
+vladpaiu@opensips.org +
+
+
+ +2013 +&osipssol; + +
+ + +&admin; + +
+ diff --git a/modules/db_cachedb/doc/db_cachedb_admin.xml b/modules/db_cachedb/doc/db_cachedb_admin.xml new file mode 100644 index 00000000000..5621ece789e --- /dev/null +++ b/modules/db_cachedb/doc/db_cachedb_admin.xml @@ -0,0 +1,149 @@ + + + + + &adminguide; + +
+ Overview + +
+ The idea + + The db_cachedb module will expose the same front db api, however it will run on top + of a NoSQL back-end, emulating the SQL calls to the back-end specific queries. + + Thus, any OpenSIPS module that would regularily need a regular SQL-based database, + will now be able to run over a NoSQL back-end, allowing for a much easier distribution + and integration of the currently existing OpenSIPS modules in a distributed environment. + +
+ + Dependencies +
+ &osips; Modules + + The following modules must be loaded before this module: + + + + + At least one NoSQL cachedb_* module. + + + + +
+
+ External Libraries or Applications + + The following libraries or applications must be installed before running + &osips; with this module loaded: + + + + + None. + + + + +
+
+
+ Exported Parameters +
+ + <varname>cachedb_url</varname> (str) + + + The URL for the CacheDB back-end to be used. It can be set more than one time. + + + Set + <varname>cachedb_url</varname> parameter + + +... +modparam("db_cachedb","cachedb_url","mongodb:mycluster://127.0.0.1:27017/db.col") +... + + + +
+
+ +
+ Examples of Usage +
+ + <varname>Distributed Subscriber Base</varname> + + + In order to achieve such a setup, one would have to set the db_url parameter of the auth_db module to point to the DB_CACHEDB URL. + + + OpenSIPS CFG Snippet for using DB_CACHEDB + + +loadmodule "auth_db.so" +modparam("auth_db", "load_credentials", "$avp(user_rpid)=rpid") + +loadmodule "db_cachedb.so" +loadmodule "cachedb_mongodb.so" +... +modparam("db_cachedb","cachedb_url","mongodb:mycluster://127.0.0.1:27017/my_db.col") +modparam("auth_db","db_url","cachedb://mongodb:mycluster") +... + + + + + With such a setup, the auth_db module will load the subscribers from the MongoDB cluster, in the 'my_db' database, in the 'subscriber' collection. + + + The same mechanism/setup can be used to run other modules ( like usrloc, dialog, permissions, drouting, etc ) on top of a cachedb cluster. + +
+
+ +
+ Current Limitations +
+ + <varname>CacheDB modules integration</varname> + + + Currently the only cachedb_* module that implements this functionality is the cachedb_mongodb module, so currently you can only emulate SQL queries to a MongoDB instance/cluster. + + There are plans to also extend this functionality to other cachedb_* backends, like Cassandra and CouchBase. + +
+ +
+ + <varname>Extensive Testing Needed</varname> + + + Since there are many OpenSIPS modules that currently use the DB interface, it wasn't feasible to test all scenarios with all modules, and there still might be some incompatibilities. + + The module was tested with some regularily used modules ( like usrloc, dialog, permissions, drouting ), but more testing is very much welcome, and feedback is appreciated. + +
+ +
+ + <varname>CacheDB Specific 'schema' and other incompatibilities</varname> + + + Since the NoSQL backends do not usually have a strict schema involved, + we do not provide scripts for creating such schemas, since the insertion ops will trigger the dynamically creation of the schema and info. + + Still, a specific data collection needs to be present, and that is the equivalent of the 'version' table from the SQL. Since most modules check the version table at the module setup, it's the user's responsability to setup such a 'version' collection in the respective NoSQL back-end. + + For example, for the MongoDB cluster, 'version' is a reserved keyword, so one would have to change the default version table that OpenSIPS uses ( via the 'db_version_table' global parameter ) and then manually insert the version number with something like db.my_version_table.insert({table_version : NumberInt(5), table_name : "address"}) + +
+
+
+ diff --git a/modules/db_flatstore/README b/modules/db_flatstore/README index 2a3b466d30e..148b8469f16 100644 --- a/modules/db_flatstore/README +++ b/modules/db_flatstore/README @@ -10,8 +10,7 @@ Jan Janak Copyright © 2004, 2005 FhG FOKUS Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/db_flatstore/flat_con.c b/modules/db_flatstore/flat_con.c index 76ceb5813bb..613b9f0bd27 100644 --- a/modules/db_flatstore/flat_con.c +++ b/modules/db_flatstore/flat_con.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Flastore module connection structure @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -82,7 +82,7 @@ static char* get_name(struct flat_id* id) total_len, buf_len); return 0; } - + buf=pkg_malloc(buf_len); if (buf==0){ LM_ERR("pkg memory allocation failure\n"); @@ -142,7 +142,7 @@ struct flat_con* flat_new_connection(struct flat_id* id) memset(res, 0, sizeof(struct flat_con)); res->ref = 1; - + res->id = id; fn = get_name(id); @@ -158,7 +158,7 @@ struct flat_con* flat_new_connection(struct flat_id* id) pkg_free(res); return 0; } - + return res; } diff --git a/modules/db_flatstore/flat_con.h b/modules/db_flatstore/flat_con.h index 3838922d94b..7267327de61 100644 --- a/modules/db_flatstore/flat_con.h +++ b/modules/db_flatstore/flat_con.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Flatstore module connection structure @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_flatstore/flat_id.c b/modules/db_flatstore/flat_id.c index 630ecd304ad..3a150991ae9 100644 --- a/modules/db_flatstore/flat_id.c +++ b/modules/db_flatstore/flat_id.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Flatstore module connection identifier @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_flatstore/flat_id.h b/modules/db_flatstore/flat_id.h index 7a226b5c474..072f3128211 100644 --- a/modules/db_flatstore/flat_id.h +++ b/modules/db_flatstore/flat_id.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Flatstore connection identifier @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -29,7 +29,7 @@ struct flat_id { - str dir; /* Database directory */ + str dir; /* Database directory */ str table; /* Name of table */ }; diff --git a/modules/db_flatstore/flat_mi.c b/modules/db_flatstore/flat_mi.c index ce430dd6f0a..80325770a5a 100644 --- a/modules/db_flatstore/flat_mi.c +++ b/modules/db_flatstore/flat_mi.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Flatstore module MI interface * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_flatstore/flat_mi.h b/modules/db_flatstore/flat_mi.h index cefbb8df038..a6c944e9a5a 100644 --- a/modules/db_flatstore/flat_mi.h +++ b/modules/db_flatstore/flat_mi.h @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id$ * * Flatstore module MI interface * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_flatstore/flat_pool.c b/modules/db_flatstore/flat_pool.c index 1e55dc67e65..3ed465fb268 100644 --- a/modules/db_flatstore/flat_pool.c +++ b/modules/db_flatstore/flat_pool.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Flatstore module connection pool @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_flatstore/flat_pool.h b/modules/db_flatstore/flat_pool.h index 6943fa60d1c..c8a2e82fd53 100644 --- a/modules/db_flatstore/flat_pool.h +++ b/modules/db_flatstore/flat_pool.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Flatstore module connection pool @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_flatstore/flatstore.c b/modules/db_flatstore/flatstore.c index 7562b3e55e1..60d707a1d5e 100644 --- a/modules/db_flatstore/flatstore.c +++ b/modules/db_flatstore/flatstore.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Flatstore module interface * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -44,7 +44,7 @@ static int parse_flat_url(const str* url, str* path) { struct stat st_buf; - + if (!url || !url->s || !path) { LM_ERR("invalid parameter value\n"); return -1; @@ -81,11 +81,11 @@ db_con_t* flat_db_init(const str* url) } /* We do not know the name of the table (and the name of the corresponding - * file) at this point, we will simply store the path taken from the url - * parameter in the table variable, flat_use_table will then pick that + * file) at this point, we will simply store the path taken from the url + * parameter in the table variable, flat_use_table will then pick that * value and open the file */ - /* as the table (path) is a substring of the received str, we need to + /* as the table (path) is a substring of the received str, we need to * allocate a separate str struct for it -bogdan */ res = pkg_malloc(sizeof(db_con_t)+sizeof(struct flat_con*)+sizeof(str)); @@ -136,7 +136,7 @@ int flat_use_table(db_con_t* h, const str* t) return -1; } } - + return 0; } @@ -217,7 +217,7 @@ static int flat_prepare_iovec(const int n) flat_iov[flat_iov_len - 1].iov_base = "\n"; flat_iov[flat_iov_len - 1].iov_len = 1; LM_DBG("Successfully allocated %d fields", flat_iov_len); - + return 0; } @@ -264,6 +264,41 @@ static int flat_prepare_iovec(const int n) FLAT_INC(aux.len); \ } while(0) +#define FLAT_COPY(_i, _s, _l) \ + do { \ + str aux; \ + int len = 0; \ + int l = _l; \ + const char *s = _s; \ + const char *p = _s; \ + while (l--) { \ + if ( !(isprint((int)*s) && *s != '\\' && *s != flat_delimiter[0])) { \ + aux.len = snprintf(FLAT_BUF, FLAT_LEN,"%.*s\\x%02X", \ + (int)(s-p),p,(*s & 0xff)); \ + p = s+1; \ + if (aux.len < 0) { \ + LM_ERR("error while writing blob %d\n", i); \ + aux.len = 0; \ + } \ + len += aux.len; \ + FLAT_INC(aux.len); \ + } \ + ++s; \ + } \ + if (p!=s) { \ + aux.len = snprintf(FLAT_BUF, FLAT_LEN,"%.*s", (int)(s-p), p); \ + if (aux.len < 0) { \ + LM_ERR("error while writing blob %d\n", i); \ + aux.len = 0; \ + } \ + len += aux.len; \ + FLAT_INC(aux.len); \ + } \ + FLAT_SET_LEN(i, len); \ + } while (0) + + + /* * Insert a row into specified table @@ -277,9 +312,8 @@ int flat_db_insert(const db_con_t* h, const db_key_t* k, const db_val_t* v, { FILE* f; int i; - int l, len; + int auxl; str aux; - char *s, *p; char * begin = flat_iov_buf.s; if (local_timestamp < *flat_rotate) { @@ -326,13 +360,14 @@ int flat_db_insert(const db_con_t* h, const db_key_t* k, const db_val_t* v, break; case DB_STRING: - FLAT_SET_STR(i, (char *)VAL_STRING(v + i)); - FLAT_SET_LEN(i, strlen(VAL_STRING(v + i))); + auxl = strlen(VAL_STRING(v + i)); + FLAT_ALLOC(auxl * 4); + FLAT_COPY(i, VAL_STRING(v + i), auxl); break; case DB_STR: - FLAT_SET_STR(i, VAL_STR(v + i).s); - FLAT_SET_LEN(i, VAL_STR(v + i).len); + FLAT_ALLOC(VAL_STR(v + i).len * 4); + FLAT_COPY(i, VAL_STR(v + i).s, VAL_STR(v + i).len); break; case DB_DATETIME: @@ -342,35 +377,10 @@ int flat_db_insert(const db_con_t* h, const db_key_t* k, const db_val_t* v, break; case DB_BLOB: - l = VAL_BLOB(v+i).len; - s = p = VAL_BLOB(v+i).s; + auxl = VAL_BLOB(v+i).len; /* the maximum size is 4l - if all chars were not printable */ - FLAT_ALLOC(4 * l); - len = 0; - while (l--) { - if ( !(isprint((int)*s) && *s != '\\' && *s != '|')) { - aux.len = snprintf(FLAT_BUF, FLAT_LEN,"%.*s\\x%02X", - (int)(s-p),p,(*s & 0xff)); - p = s+1; - if (aux.len < 0) { - LM_ERR("error while writing blob %d\n", i); - aux.len = 0; - } - len += aux.len; - FLAT_INC(aux.len); - } - ++s; - } - if (p!=s) { - aux.len = snprintf(FLAT_BUF, FLAT_LEN,"%.*s", (int)(s-p), p); - if (aux.len < 0) { - LM_ERR("error while writing blob %d\n", i); - aux.len = 0; - } - len += aux.len; - FLAT_INC(aux.len); - } - FLAT_SET_LEN(i, len); + FLAT_ALLOC(4 * auxl); + FLAT_COPY(i, VAL_BLOB(v+i).s, auxl); break; case DB_BITMAP: @@ -384,8 +394,7 @@ int flat_db_insert(const db_con_t* h, const db_key_t* k, const db_val_t* v, if (flat_iov_buf.s != begin && flat_iov_buf.len) { FLAT_RESET(); for (i = 0; i < n; i++) { - if (!VAL_NULL(v + i) && VAL_TYPE(v + i) != DB_STRING && - VAL_TYPE(v + i) != DB_STR) { + if (!VAL_NULL(v + i)) { FLAT_SET_STR(i, FLAT_BUF); FLAT_INC(FLAT_GET_LEN(i)); } @@ -393,10 +402,10 @@ int flat_db_insert(const db_con_t* h, const db_key_t* k, const db_val_t* v, } do { - l = writev(fileno(f), flat_iov, 2 * n); - } while (l < 0 && errno == EINTR); + auxl = writev(fileno(f), flat_iov, 2 * n); + } while (auxl < 0 && errno == EINTR); - if (l < 0) { + if (auxl < 0) { LM_ERR("unable to write to file: %s - %d\n", strerror(errno), errno); return -1; } diff --git a/modules/db_flatstore/flatstore.h b/modules/db_flatstore/flatstore.h index aec68478619..a758d5e7d27 100644 --- a/modules/db_flatstore/flatstore.h +++ b/modules/db_flatstore/flatstore.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Flatstore module interface * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* diff --git a/modules/db_flatstore/flatstore_mod.c b/modules/db_flatstore/flatstore_mod.c index b863d5ef603..53de15ba1ca 100644 --- a/modules/db_flatstore/flatstore_mod.c +++ b/modules/db_flatstore/flatstore_mod.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Flatstore module interface * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -115,8 +115,10 @@ static mi_export_t mi_cmds[] = { struct module_exports exports = { "db_flatstore", + MOD_TYPE_SQLDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, params, /* module parameters */ 0, /* exported statistics */ diff --git a/modules/db_flatstore/flatstore_mod.h b/modules/db_flatstore/flatstore_mod.h index 5d59d2bf4a2..1cb4c3e0533 100644 --- a/modules/db_flatstore/flatstore_mod.h +++ b/modules/db_flatstore/flatstore_mod.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Flatstore module interface * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/db_http/README b/modules/db_http/README index 88c5288e056..76b462a286f 100644 --- a/modules/db_http/README +++ b/modules/db_http/README @@ -2,16 +2,15 @@ DB_HTTP Module Andrei Dragus - voice-system.ro + OpenSIPS Solutions Edited by Andrei Dragus - Copyright © 2009 voice-system.ro + Copyright © 2009 Voice Sistem SRL Revision History - Revision $Revision: 6072 $ $Date: 2009-09-03 12:37:19 +0300 - (Thu, 03 Sep 2009) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -34,6 +33,8 @@ Andrei Dragus 1.3.6. field_delimiter (str) 1.3.7. row_delimiter (str) 1.3.8. quote_delimiter (str) + 1.3.9. value_delimiter (str) + 1.3.10. timeout (int) 1.4. Exported Functions 1.5. Server specifications @@ -58,12 +59,14 @@ Andrei Dragus 1.7. Set field_delimiter parameter 1.8. Set row_delimiter parameter 1.9. Set quote_delimiter parameter - 1.10. Example query. - 1.11. Example query with variables. - 1.12. More query examples. - 1.13. NULL query example. - 1.14. Example Reply. - 1.15. Quoting Example. + 1.10. Set value_delimiter parameter + 1.11. Set timeout parameter + 1.12. Example query. + 1.13. Example query with variables. + 1.14. More query examples. + 1.15. NULL query example. + 1.16. Example Reply. + 1.17. Quoting Example. Chapter 1. Admin Guide @@ -205,6 +208,31 @@ modparam("db_http", "row_delimiter","\n") modparam("db_http", "quote_delimiter","|") ... +1.3.9. value_delimiter (str) + + The delimiter used to separate multiple fields of a single + variable (see Section 1.5.2, “Variables”). Only one char may be + set. + + Default value is “,” + + Example 1.10. Set value_delimiter parameter +... +modparam("db_http", "value_delimiter",";") +... + +1.3.10. timeout (int) + + The maximum number of milliseconds that the HTTP ops are + allowed to last + + Default value is “30000 ( 30 seconds )” + + Example 1.11. Set timeout parameter +... +modparam("db_http", "timeout",5000) +... + 1.4. Exported Functions This module does not export any functions. @@ -223,7 +251,7 @@ modparam("db_http", "quote_delimiter","|") apart by the query_type variable. Each type of query uses specific variables simillar to those in the opensips db_api. - Example 1.10. Example query. + Example 1.12. Example query. ... GET /presentity/?c=username,domain,event,expires HTTP/1.1 ... @@ -268,7 +296,7 @@ GET /presentity/?c=username,domain,event,expires HTTP/1.1 value. Will be present in all queries except the "SELECT" (normal query). - Example 1.11. Example query with variables. + Example 1.13. Example query with variables. ... GET /presentity/?c=username,domain,event,expires HTTP/1.1 GET /version/?k=table_name&v=xcap&c=table_version HTTP/1.1 @@ -309,7 +337,7 @@ k=id&v=100&query_type=insert Uses the q variable. This is an optional type of query. If the module is not configured to use it it will not. - Example 1.12. More query examples. + Example 1.14. More query examples. ... POST /active_watchers HTTP/1.1 @@ -329,7 +357,7 @@ k=id&op=%3D&v=100&uk=id&uv=101&query_type=update NULL values in queries are represented as a string of length 1 containing a single character with value '\0'. - Example 1.13. NULL query example. + Example 1.15. NULL query example. ... POST /active_watchers HTTP/1.1 @@ -364,7 +392,7 @@ k=id&op=%3D&v=%00&query_type=delete If the query produced an error the server must reply with a HTTP 500 reply, or with a corresponding error code (404, 401). - Example 1.14. Example Reply. + Example 1.16. Example Reply. ... int;string;blob 6;something=something;1000 @@ -384,7 +412,7 @@ int;string;blob be placed under quotes. A quote delimiter inside a value must be preceeded by another quote delimiter. - Example 1.15. Quoting Example. + Example 1.17. Quoting Example. ... int;string;blob 6;|ana;maria|;1000 diff --git a/modules/db_http/db_http.c b/modules/db_http/db_http.c index 32e5a7b4cbe..0b16ff94285 100644 --- a/modules/db_http/db_http.c +++ b/modules/db_http/db_http.c @@ -49,7 +49,7 @@ int cap_replace = 0; int cap_insert_update = 0; int use_ssl = 0 ; - +unsigned int db_http_timeout = 30000; /* Default is 30 seconds */ /* @@ -73,21 +73,25 @@ static param_export_t params[] = { {"field_delimiter", STR_PARAM | USE_FUNC_PARAM ,set_col_delim}, {"row_delimiter", STR_PARAM | USE_FUNC_PARAM ,set_line_delim}, {"quote_delimiter", STR_PARAM | USE_FUNC_PARAM ,set_quote_delim}, + {"value_delimiter", STR_PARAM | USE_FUNC_PARAM ,set_value_delim}, + {"timeout", INT_PARAM,&db_http_timeout}, {0, 0, 0} }; struct module_exports exports = { "db_http", + MOD_TYPE_SQLDB, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, params, /* module parameters */ 0, /* exported statistics */ 0, /* exported MI functions */ 0, /* exported pseudo-variables */ 0, /* extra processes */ - http_mod_init, /* module initialization function */ + http_mod_init, /* module initialization function */ 0, /* response function*/ 0, /* destroy function */ 0 /* per-child init function */ @@ -145,7 +149,7 @@ int db_http_bind_api( const str* mod, db_func_t *dbb) dbb->insert = db_http_insert; dbb->delete = db_http_delete; dbb->update = db_http_update; - + return 0; } diff --git a/modules/db_http/db_http.h b/modules/db_http/db_http.h new file mode 100644 index 00000000000..8f8fddd8d3d --- /dev/null +++ b/modules/db_http/db_http.h @@ -0,0 +1,33 @@ +/* + * $Id$ + * + * Copyright (C) 2012 Guillaume Bour (Orange-Vallee) + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * History: + * --------- + * 2012-02-25 first version (gbour) + */ + +#ifndef DB_HTTP_H +#define DB_HTTP_H + +extern unsigned int db_http_timeout; + +#endif /* DB_HTTP_H */ diff --git a/modules/db_http/doc/db_http_admin.xml b/modules/db_http/doc/db_http_admin.xml index 7612de70edb..94222c733dd 100644 --- a/modules/db_http/doc/db_http_admin.xml +++ b/modules/db_http/doc/db_http_admin.xml @@ -221,6 +221,46 @@ modparam("db_http", "quote_delimiter","|")
+
+ <varname>value_delimiter</varname> (str) + + The delimiter used to separate multiple fields of a single + variable (see ). + Only one char may be set. + + + Default value is , + + + + Set <varname>value_delimiter</varname> parameter + +... +modparam("db_http", "value_delimiter",";") +... + + +
+ +
+ <varname>timeout</varname> (int) + + The maximum number of milliseconds that the HTTP ops are allowed to last + + + Default value is 30000 ( 30 seconds ) + + + + Set <varname>timeout</varname> parameter + +... +modparam("db_http", "timeout",5000) +... + + +
+
@@ -261,7 +301,7 @@ GET /presentity/?c=username,domain,event,expires HTTP/1.1 -
+
Variables A description of all the variables. Each variable can have diff --git a/modules/db_http/http_dbase.c b/modules/db_http/http_dbase.c index d55ed4f2c2e..16ec5263476 100644 --- a/modules/db_http/http_dbase.c +++ b/modules/db_http/http_dbase.c @@ -28,6 +28,7 @@ #include "http_dbase.h" +#include "db_http.h" #include "../../db/db_id.h" #include "../../db/db_ut.h" #include "../../db/db_row.h" @@ -73,6 +74,7 @@ int next_state[3][256]; char line_delim = '\n'; char col_delim = ';'; +char *val_delim_s = ","; char quote_delim = '|'; extern int use_ssl; @@ -84,7 +86,7 @@ char error_buffer[CURL_ERROR_SIZE]; { \ if( (val) != (expected) ) \ goto err_tag; \ -} +} @@ -132,6 +134,18 @@ int set_quote_delim( unsigned int type, void *val) } +int set_value_delim( unsigned int type, void *val) +{ + if( strlen(val) != 1) + { + LM_ERR("Only one values delimiter may be set\n"); + return -1; + } + val_delim_s = val; + + return 0; +} + str value_to_string(const db_val_t * v); @@ -185,13 +199,13 @@ static int append_keys (var_str * q,const char * name, const db_key_t* k, CHECK(append_const(q,(char*)name),0,error); CHECK(append_const(q,"="),0,error); - + for(i=0;ires_rows = rows; res->last_row = rows; - + for( i=0;irows[i].n = cols; @@ -361,7 +375,7 @@ int put_type_in_result( char * start, int len , db_res_t * res , int cur_col ) res->col.types[cur_col] = DB_STRING; ok = 1; } - + if( len == 3 && !strncmp (start,"str",len)) { res->col.types[cur_col] = DB_STR; @@ -381,9 +395,9 @@ int put_type_in_result( char * start, int len , db_res_t * res , int cur_col ) if( !ok ) LM_ERR("Unknown datatype\n"); - + return 1 - ok; - + } int put_value_in_result( char * start, int len , db_res_t * res , @@ -398,7 +412,7 @@ int put_value_in_result( char * start, int len , db_res_t * res , row = res->rows[cur_line].values; row[cur_col].type = res->col.types[cur_col]; - + if( len == 0 && (res->col.types[cur_col] != DB_BLOB ) && (res->col.types[cur_col] != DB_STRING ) && (res->col.types[cur_col] != DB_STR ) @@ -407,7 +421,7 @@ int put_value_in_result( char * start, int len , db_res_t * res , row[cur_col].nul = 1; return 0; } - + switch(res->col.types[cur_col]) { case( DB_INT): @@ -453,9 +467,9 @@ int form_result(var_str buff, db_res_t** r) db_res_t * res; char * cur, * dest, * start, * end; int col_count, cur_col, line_count, cur_line, delim_count, len; - int state, next, first_line, consume; + int state, next, consume; + - LM_DBG("Called with : %.*s\n",buff.len,buff.s); @@ -526,7 +540,7 @@ int form_result(var_str buff, db_res_t** r) line_count = cur_line; - + if( col_count == 0 || line_count == 0 ) goto error_before; @@ -538,7 +552,7 @@ int form_result(var_str buff, db_res_t** r) goto error_before; - + /* allocate all necessary info */ @@ -547,7 +561,7 @@ int form_result(var_str buff, db_res_t** r) if( res == NULL ) return -1; - + state = OUT; @@ -556,12 +570,11 @@ int form_result(var_str buff, db_res_t** r) cur_col = 0; cur_line = -1; - first_line = 1; start = dest; while( cur < end ) { - + next = next_state[ state ][ (int)((unsigned char)*cur) ]; consume = 1; @@ -576,7 +589,7 @@ int form_result(var_str buff, db_res_t** r) if( cur_line == -1 ) CHECK( put_type_in_result(start,len, res,cur_col), 0, error) - + else CHECK( put_value_in_result(start,len, res,cur_col,cur_line),0,error) @@ -585,7 +598,7 @@ int form_result(var_str buff, db_res_t** r) start = dest; cur_col++; - + } else if( *cur == line_delim ) @@ -604,7 +617,7 @@ int form_result(var_str buff, db_res_t** r) cur_line++; cur_col = 0; - + } else if( *cur != quote_delim ) @@ -622,7 +635,7 @@ int form_result(var_str buff, db_res_t** r) consume = 0; else *dest++ = *cur; - + } if( state == IN ) @@ -641,7 +654,7 @@ int form_result(var_str buff, db_res_t** r) - + LM_DBG("Finished query\n"); @@ -657,7 +670,7 @@ int form_result(var_str buff, db_res_t** r) LM_ERR("Error parsing HTTP reply\n"); return -1; - + } int do_http_op ( const db_con_t* h, const db_key_t* k, const db_op_t* op, @@ -778,17 +791,17 @@ int do_http_op ( const db_con_t* h, const db_key_t* k, const db_op_t* op, } - + q.s[q.len] = 0 ; - + LM_DBG("Sent:%s \n",q.s); curl_easy_setopt(conn->handle, CURLOPT_HTTPGET, 1); curl_easy_setopt(conn->handle, CURLOPT_URL, q.s); - + curl_easy_setopt(conn->handle, CURLOPT_WRITEFUNCTION, receive); curl_easy_setopt(conn->handle, CURLOPT_WRITEDATA, &buff); @@ -823,7 +836,7 @@ int do_http_op ( const db_con_t* h, const db_key_t* k, const db_op_t* op, sscanf(buff.s,"%d",&conn->last_id); } - + return 0; @@ -848,7 +861,7 @@ str value_to_string(const db_val_t * v) rez.len = 1; return rez; } - + switch ( v->type) @@ -895,7 +908,7 @@ str value_to_string(const db_val_t * v) rez.s = ""; rez.len = 0; } - + return rez; } @@ -914,7 +927,7 @@ char to_hex(char code) str url_encode(str s) { - + static char *buf = NULL; static int size = 0; @@ -929,10 +942,10 @@ str url_encode(str s) buf = pkg_realloc(buf, s.len * 3 + 1); size = s.len * 3 + 1; } - + pbuf = buf; i = 0; - + while ( i < s.len ) { if (isalnum(*pstr) || *pstr == '-' || @@ -945,7 +958,7 @@ str url_encode(str s) *pbuf++ = to_hex(*pstr >> 4); *pbuf++ = to_hex(*pstr & 15); } - + pstr++; i++; } @@ -963,7 +976,7 @@ str url_encode(str s) db_con_t* db_http_init(const str* url) { - + char* path; char port [20]; char user_pass[1024]; @@ -995,8 +1008,8 @@ db_con_t* db_http_init(const str* url) } memset(path,0,1024); - - + + id = new_db_id( &tmp ); if( id == NULL) @@ -1004,7 +1017,7 @@ db_con_t* db_http_init(const str* url) LM_ERR("Incorrect db_url\n"); return NULL; } - + if( id->username && id->password) @@ -1014,7 +1027,7 @@ db_con_t* db_http_init(const str* url) strcat(user_pass,id->password); } - + curl = (http_conn_t * ) pkg_malloc(sizeof(http_conn_t)); @@ -1032,13 +1045,16 @@ db_con_t* db_http_init(const str* url) curl_easy_setopt(curl->handle,CURLOPT_HTTPAUTH,CURLAUTH_ANY); curl_easy_setopt(curl->handle,CURLOPT_ERRORBUFFER,error_buffer); - +#if LIBCURL_VERSION_NUM >= 0x071002 + LM_DBG("timeout set to %d", db_http_timeout); + curl_easy_setopt(curl->handle,CURLOPT_TIMEOUT_MS,db_http_timeout); +#endif strcat(path,"http"); if ( use_ssl ) strcat(path,"s"); strcat(path,"://"); - + strcat(path,id->host); if( id->port ) @@ -1085,7 +1101,7 @@ db_con_t* db_http_init(const str* url) next_state[ ESC ][ (int) quote_delim ] = IN; return ans; - + } @@ -1175,7 +1191,7 @@ int db_http_insert(const db_con_t* _h, const db_key_t* _k, NULL, HTTPDB_INSERT ); - + } @@ -1196,7 +1212,7 @@ int db_http_delete(const db_con_t* _h, const db_key_t* _k, const NULL, HTTPDB_DELETE ); - + } @@ -1217,7 +1233,7 @@ int db_http_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o, NULL, HTTPDB_UPDATE ); - + } @@ -1248,7 +1264,7 @@ int db_last_inserted_id(const db_con_t* _h) return conn->last_id; - + } /* @@ -1268,7 +1284,7 @@ int db_insert_update(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, HTTPDB_INSERT_UPDATE ); - + } diff --git a/modules/db_http/http_dbase.h b/modules/db_http/http_dbase.h index da8cae24564..3a711e623fd 100644 --- a/modules/db_http/http_dbase.h +++ b/modules/db_http/http_dbase.h @@ -43,6 +43,7 @@ int set_col_delim( unsigned int type, void *val); int set_line_delim( unsigned int type, void *val); int set_quote_delim( unsigned int type, void *val); +int set_value_delim( unsigned int type, void *val); diff --git a/modules/db_mysql/README b/modules/db_mysql/README index 2eadeea0dd5..b29665adad6 100644 --- a/modules/db_mysql/README +++ b/modules/db_mysql/README @@ -10,10 +10,9 @@ Daniel-Constantin Mierla - Copyright 2006 Voice Sistem SRL + Copyright © 2006 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -99,8 +98,8 @@ modparam("db_mysql", "exec_query_threshold", 60000) retries are done from the driver before it gives up. The read timeout parameter is ignored on driver versions prior - to "5.1.12", "5.0.25" and "4.1.22". The write timeout parameter - is ignored on version prior to "5.1.12" and "5.0.25", the "4.1" + to “5.1.12”, “5.0.25” and “4.1.22”. The write timeout parameter + is ignored on version prior to “5.1.12” and “5.0.25”, the “4.1” release don't support it at all. Default value is 2 (6 sec). diff --git a/modules/db_mysql/db_mysql.c b/modules/db_mysql/db_mysql.c index b6c22a70746..de043949d32 100644 --- a/modules/db_mysql/db_mysql.c +++ b/modules/db_mysql/db_mysql.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * MySQL module interface * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* @@ -68,10 +68,12 @@ static param_export_t params[] = { }; -struct module_exports exports = { +struct module_exports exports = { "db_mysql", + MOD_TYPE_SQLDB, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, params, /* module parameters */ 0, /* exported statistics */ @@ -111,7 +113,7 @@ int db_mysql_bind_api(const str* mod, db_func_t *dbb) dbb->raw_query = db_mysql_raw_query; dbb->free_result = db_mysql_free_result; dbb->insert = db_mysql_insert; - dbb->delete = db_mysql_delete; + dbb->delete = db_mysql_delete; dbb->update = db_mysql_update; dbb->replace = db_mysql_replace; dbb->last_inserted_id = db_last_inserted_id; diff --git a/modules/db_mysql/db_mysql.h b/modules/db_mysql/db_mysql.h index 0c03cbeb751..cfdef162f68 100644 --- a/modules/db_mysql/db_mysql.h +++ b/modules/db_mysql/db_mysql.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * MySQL module interface * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/db_mysql/dbase.c b/modules/db_mysql/dbase.c index 2c358eb54ee..e011564a0a3 100644 --- a/modules/db_mysql/dbase.c +++ b/modules/db_mysql/dbase.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * MySQL module core functions * @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -74,7 +74,7 @@ static inline void mysql_raise_event(const db_con_t *conn) { evi_params_p list = NULL; if (mysql_evi_id == EVI_ERROR) { - LM_ERR("event not registered %d\n", mysql_evi_id); + LM_DBG("event not registered %d\n", mysql_evi_id); return; } @@ -217,7 +217,7 @@ static inline void reset_all_statements(const db_con_t* conn) struct prep_stmt *pq_ptr; struct my_stmt_ctx *ctx; - LM_INFO("reseting all statements on connection: (%p) %p\n", + LM_INFO("reseting all statements on connection: (%p) %p\n", conn,(void*)conn->tail); for( pq_ptr=CON_PS_LIST(conn); pq_ptr ; pq_ptr=pq_ptr->next ) { for (ctx = pq_ptr->stmts ; ctx ; ctx=ctx->next ) { @@ -368,14 +368,14 @@ static int re_init_statement(const db_con_t* conn, struct prep_stmt *pq_ptr, LM_DBG(" query is <%.*s>, ptr=%p\n", ctx->query.len, ctx->query.s, ctx->stmt); - + for( i=0 ; i<2 ; i++ ) { /* re-init the statement */ if ( !(ctx->stmt=mysql_stmt_init(CON_CONNECTION(conn))) ) { LM_ERR("failed while mysql_stmt_init()\n"); goto error; } - + code = wrapper_single_mysql_stmt_prepare(conn, ctx); if (code < 0) { /* got disconnected during call */ @@ -446,7 +446,7 @@ static struct my_stmt_ctx * get_new_stmt_ctx(const db_con_t* conn, LM_ERR("no more pkg mem for statement context\n"); return NULL; } - memset( ctx, 0, + memset( ctx, 0, sizeof(struct my_stmt_ctx) + CON_TABLE(conn)->len + query->len); ctx->table.s = (char*)(ctx+1); ctx->table.len = CON_TABLE(conn)->len; @@ -515,7 +515,7 @@ static struct prep_stmt* alloc_new_prepared_stmt(const db_con_t *conn,const db_v pq_ptr->bind_in[i].is_null = &pq_ptr->in_bufs[i].null; if (VAL_TYPE(v+i%n)==DB_DATETIME) pq_ptr->bind_in[i].buffer = &mt[--time_no]; - } + } } else { for( i=0 ; ibind_in[i].length = &pq_ptr->in_bufs[i].len; @@ -560,7 +560,7 @@ static int db_mysql_do_prepared_query(const db_con_t* conn, const str *query, db_val_t **buffered_rows = NULL; LM_DBG("conn=%p (tail=%ld) MC=%p\n",conn, conn->tail,CON_CONNECTION(conn)); - + if ( CON_MYSQL_PS(conn) == NULL ) { /* First time when this query is run, so we need to init it -> ** allocate new structure for prepared statemet and its values @@ -588,7 +588,7 @@ static int db_mysql_do_prepared_query(const db_con_t* conn, const str *query, /* link it to the connection */ pq_ptr->next = CON_PS_LIST(conn); CON_PS_LIST(conn) = pq_ptr; - LM_DBG("new statement(%p) on connection: (%p) %p\n", + LM_DBG("new statement(%p) on connection: (%p) %p\n", pq_ptr, conn, (void*)conn->tail); /* also return it for direct future usage */ CON_CURR_PS(conn) = pq_ptr; @@ -616,7 +616,7 @@ static int db_mysql_do_prepared_query(const db_con_t* conn, const str *query, } } - + if (query_buffer_size > 1 && CON_HAS_INSLIST(conn)) { if (ql_row_add(conn->ins_list,v,&buffered_rows) < 0) { LM_ERR("failed to insert row to buffered list\n"); @@ -634,13 +634,13 @@ static int db_mysql_do_prepared_query(const db_con_t* conn, const str *query, LM_DBG("set values for the statement run\n"); if (query_buffer_size > 1 && CON_HAS_INSLIST(conn)) { - /* got here, we need to push data to DB + /* got here, we need to push data to DB * first bind data */ for (j=0;j= (SQL_BUF_LEN - off)) goto error; off += ret; - + ret = db_print_set(_h, sql_buf + off, SQL_BUF_LEN - off, _k, _v, _n, db_mysql_val2str); if (ret < 0) return -1; off += ret; - + sql_str.s = sql_buf; sql_str.len = off; - + if (db_mysql_submit_query(_h, &sql_str) < 0) { LM_ERR("error while submitting query\n"); return -2; diff --git a/modules/db_mysql/dbase.h b/modules/db_mysql/dbase.h index 7cba5ad5c1e..fe627e0dc5c 100644 --- a/modules/db_mysql/dbase.h +++ b/modules/db_mysql/dbase.h @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -83,7 +83,7 @@ int db_mysql_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, /* * Delete a row from table */ -int db_mysql_delete(const db_con_t* _h, const db_key_t* _k, const +int db_mysql_delete(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o, const db_val_t* _v, const int _n); diff --git a/modules/db_mysql/my_con.c b/modules/db_mysql/my_con.c index 4bd91a6287d..80307991999 100644 --- a/modules/db_mysql/my_con.c +++ b/modules/db_mysql/my_con.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2004 iptel.org @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -47,7 +47,7 @@ int db_mysql_connect(struct my_con* ptr) ZSW(ptr->id->host), ZSW(ptr->id->database)); } - if (!mysql_real_connect(ptr->con, ptr->id->host, + if (!mysql_real_connect(ptr->con, ptr->id->host, ptr->id->username, ptr->id->password, ptr->id->database, ptr->id->port, 0, #if (MYSQL_VERSION_ID >= 40100) @@ -94,7 +94,7 @@ struct my_con* db_mysql_new_connection(const struct db_id* id) memset(ptr, 0, sizeof(struct my_con)); ptr->ref = 1; - + ptr->con = (MYSQL*)pkg_malloc(sizeof(MYSQL)); if (!ptr->con) { LM_ERR("no private memory left\n"); diff --git a/modules/db_mysql/my_con.h b/modules/db_mysql/my_con.h index 43f4fbb4fc1..0268f6428ce 100644 --- a/modules/db_mysql/my_con.h +++ b/modules/db_mysql/my_con.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_mysql/res.c b/modules/db_mysql/res.c index 1e37f7a0154..09a570b3731 100644 --- a/modules/db_mysql/res.c +++ b/modules/db_mysql/res.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * MySQL module result related functions * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -58,7 +58,7 @@ int db_mysql_get_columns(const db_con_t* _h, db_res_t* _r) } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } - + if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; diff --git a/modules/db_mysql/res.h b/modules/db_mysql/res.h index 104621f3d10..cc4b74803f8 100644 --- a/modules/db_mysql/res.h +++ b/modules/db_mysql/res.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * MySQL module result related functions * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_mysql/row.c b/modules/db_mysql/row.c index 80565cd8bbf..795c292ed6b 100644 --- a/modules/db_mysql/row.c +++ b/modules/db_mysql/row.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * MySQL module row related functions * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_mysql/row.h b/modules/db_mysql/row.h index ffb5d8aabd7..ce6d4be96e5 100644 --- a/modules/db_mysql/row.h +++ b/modules/db_mysql/row.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * MySQL module row related functions * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_mysql/val.c b/modules/db_mysql/val.c index 70c010283df..6f650816669 100644 --- a/modules/db_mysql/val.c +++ b/modules/db_mysql/val.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -37,7 +37,7 @@ int db_mysql_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const int _l) { static str dummy_string = {"", 0}; - + if (!_v) { LM_ERR("invalid parameter value\n"); return -1; @@ -91,7 +91,7 @@ int db_mysql_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const int return 0; } break; - + case DB_DOUBLE: LM_DBG("converting DOUBLE [%s]\n", _s); if (db_str2double(_s, &VAL_DOUBLE(_v)) < 0) { @@ -159,7 +159,7 @@ int db_mysql_val2str(const db_con_t* _c, const db_val_t* _v, char* _s, int* _len *_len = snprintf(_s, *_len, "NULL"); return 0; } - + switch(VAL_TYPE(_v)) { case DB_INT: if (db_int2str(VAL_INT(_v), _s, _len) < 0) { @@ -251,7 +251,7 @@ int db_mysql_val2str(const db_con_t* _c, const db_val_t* _v, char* _s, int* _len *_s = '\0'; *_len = _s - old_s; return 0; - } + } break; default: diff --git a/modules/db_mysql/val.h b/modules/db_mysql/val.h index 9b1aa66f507..d75d1ad6d91 100644 --- a/modules/db_mysql/val.h +++ b/modules/db_mysql/val.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2008 1&1 Internet AG @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_oracle/Makefile b/modules/db_oracle/Makefile index 6b7e68549eb..3dfd1b7f668 100644 --- a/modules/db_oracle/Makefile +++ b/modules/db_oracle/Makefile @@ -38,13 +38,29 @@ ifeq ($(ORAPATH),) echo $(SYSBASE)/lib64/oracle$(ORAVERDIR) ) endif ifeq ($(ORAPATH),) - ORAPATH=$(shell [ -f $(SYSBASE)/lib/oracle$(ORAVERDIR)/libocci.so ] && \ - echo $(SYSBASE)/lib/oracle$(ORAVERDIR) ) + ORAPATH=$(shell [ -f $(LOCALBASE)/lib64/oracle$(ORAVERDIR)/lib/libocci.so ] && \ + echo $(LOCALBASE)/lib64/oracle$(ORAVERDIR)/lib ) +endif +ifeq ($(ORAPATH),) + ORAPATH=$(shell [ -f $(SYSBASE)/lib64/oracle$(ORAVERDIR)/lib/libocci.so ] && \ + echo $(SYSBASE)/lib64/oracle$(ORAVERDIR)/lib ) +endif +ifeq ($(ORAPATH),) + ORAPATH=$(shell [ -f $(LOCALBASE)/lib/oracle$(ORAVERDIR)/libocci.so ] && \ + echo $(LOCALBASE)/lib/oracle$(ORAVERDIR) ) endif ifeq ($(ORAPATH),) ORAPATH=$(shell [ -f $(SYSBASE)/lib/oracle$(ORAVERDIR)/libocci.so ] && \ echo $(SYSBASE)/lib/oracle$(ORAVERDIR) ) endif +ifeq ($(ORAPATH),) + ORAPATH=$(shell [ -f $(LOCALBASE)/lib/oracle$(ORAVERDIR)/lib/libocci.so ] && \ + echo $(LOCALBASE)/lib/oracle$(ORAVERDIR)/lib ) +endif +ifeq ($(ORAPATH),) + ORAPATH=$(shell [ -f $(SYSBASE)/lib/oracle$(ORAVERDIR)/lib/libocci.so ] && \ + echo $(SYSBASE)/lib/oracle$(ORAVERDIR)/lib ) +endif ifneq ($(ORAPATH),) LIBS +=-L$(ORAPATH) diff --git a/modules/db_oracle/README b/modules/db_oracle/README index f72786da255..212bbe22d78 100644 --- a/modules/db_oracle/README +++ b/modules/db_oracle/README @@ -20,8 +20,7 @@ Iouri Kharon Copyright © 2007,2008 TRUNK MOBILE, INC. Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/db_oracle/db_oracle.c b/modules/db_oracle/db_oracle.c index 70cfe4012ab..ad67f928033 100644 --- a/modules/db_oracle/db_oracle.c +++ b/modules/db_oracle/db_oracle.c @@ -61,8 +61,10 @@ static param_export_t params[] = { struct module_exports exports = { "db_oracle", + MOD_TYPE_SQLDB, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, params, /* module parameters */ 0, /* exported statistics */ @@ -108,7 +110,7 @@ static int db_oracle_bind_api(const str* mod, db_func_t *dbb) dbb->raw_query = db_oracle_raw_query; dbb->free_result = db_oracle_free_result; dbb->insert = db_oracle_insert; - dbb->delete = db_oracle_delete; + dbb->delete = db_oracle_delete; dbb->update = db_oracle_update; return 0; diff --git a/modules/db_oracle/dbase.c b/modules/db_oracle/dbase.c index d129e11a707..32459c618d1 100644 --- a/modules/db_oracle/dbase.c +++ b/modules/db_oracle/dbase.c @@ -223,7 +223,7 @@ static int db_oracle_submit_query(const db_con_t* _h, const str* _s) (unsigned)hc); return -1; } - + if (!pqd->_rs) { /* * This method is at ~25% faster as set OCI_COMMIT_ON_SUCCESS @@ -498,7 +498,7 @@ int db_oracle_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o, { query_data_t cb; int rc; - + if (!_h || !CON_TABLE(_h)) { LM_ERR("invalid parameter value\n"); return -1; diff --git a/modules/db_oracle/ora_con.h b/modules/db_oracle/ora_con.h index 5835ffe772e..6635ea0a926 100644 --- a/modules/db_oracle/ora_con.h +++ b/modules/db_oracle/ora_con.h @@ -50,7 +50,7 @@ struct ora_con { int connected; /* Authorized session started */ int bindpos; /* Last Bind handle position */ - + query_data_t* pqdata; /* Temporary: cb data for submit_query/store_result */ int uri_len; diff --git a/modules/db_oracle/res.c b/modules/db_oracle/res.c index e9e62335bab..d03aff8f1ee 100644 --- a/modules/db_oracle/res.c +++ b/modules/db_oracle/res.c @@ -446,15 +446,15 @@ int db_oracle_store_result(const db_con_t* _h, db_res_t** _r) con = CON_ORA(_h); { query_data_t *pcb = con->pqdata; - + if (!pcb || !pcb->_rs) goto badparam; - + hs = *pcb->_rs; pcb->_rs = NULL; /* paranoid for next call */ - } - + } + rc = -1; if (_r) *_r = NULL; /* unification for all errors */ diff --git a/modules/db_perlvdb/README b/modules/db_perlvdb/README index 097a8179a07..eaa9b421895 100644 --- a/modules/db_perlvdb/README +++ b/modules/db_perlvdb/README @@ -10,8 +10,7 @@ Bastian Friedrich Copyright © 2007 Collax GmbH Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 9599 $ $Date$ __________________________________________________________ Table of Contents @@ -62,13 +61,13 @@ Chapter 1. Admin Guide need database access. Relaying of insert, update, query and delete operations is supported. - Modules can be configured to use the perlvdb module as database - backend using the db_url_parameter: + Modules can be configured to use the db_perlvdb module as + database backend using the db_url_parameter: modparam("acc", "db_url", "perlvdb:OpenSIPS::VDB::Adapter::AccountingSIP trace") This configuration options tells acc module that it should use - the perlvdb module which will in turn use the Perl class + the db_perlvdb module which will in turn use the Perl class OpenSIPS::VDB::Adapter::AccountingSIPtrace to relay the database requests. @@ -110,10 +109,10 @@ Chapter 2. Developer Guide 2.2. Base class OpenSIPS::VDB - A client module has to be configured to use the perlvdb module - in conjunction with a Perl class to provide the functions. The - configured class needs to inherit from the base class - OpenSIPS::VDB. + A client module has to be configured to use the db_perlvdb + module in conjunction with a Perl class to provide the + functions. The configured class needs to inherit from the base + class OpenSIPS::VDB. Derived classes have to implement the necessary functions "query", "insert", "update" and/or "delete". The client module diff --git a/modules/db_perlvdb/perlvdb.c b/modules/db_perlvdb/perlvdb.c index c7781241383..39235ebec1f 100644 --- a/modules/db_perlvdb/perlvdb.c +++ b/modules/db_perlvdb/perlvdb.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Perl virtual database module @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -60,12 +60,22 @@ static param_export_t params[] = { {0, 0, 0} }; - +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "perl", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; struct module_exports exports = { "db_perlvdb", + MOD_TYPE_SQLDB,/* class of this module */ MODULE_VERSION, RTLD_NOW | RTLD_GLOBAL, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, params, /* module parameters */ 0, /* exported statistics */ diff --git a/modules/db_perlvdb/perlvdb.h b/modules/db_perlvdb/perlvdb.h index ae1717c7652..0a7ea4ea49d 100644 --- a/modules/db_perlvdb/perlvdb.h +++ b/modules/db_perlvdb/perlvdb.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Perl virtual database module interface @@ -18,14 +18,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _PERLVDB_H -#define _PERLVDB_H +#define _PERLVDB_H #include "../../db/db.h" diff --git a/modules/db_perlvdb/perlvdb_conv.c b/modules/db_perlvdb/perlvdb_conv.c index 511e07631b1..66fb5e32871 100644 --- a/modules/db_perlvdb/perlvdb_conv.c +++ b/modules/db_perlvdb/perlvdb_conv.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Perl virtual database module interface @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -72,7 +72,7 @@ AV *conds2perlarray(db_key_t* keys, db_op_t* ops, db_val_t* vals, int n) { element = cond2perlcond(*(keys + i), "=", vals + i); #endif } - + av_push(array, element); } return array; @@ -87,7 +87,7 @@ AV *keys2perlarray(db_key_t* keys, int n) { SV *element; int i; for (i = 0; i < n; i++) { - element = newSVpv((keys[i])->s, (keys[i])->len); + element = newSVpv((keys[i])->s, (keys[i])->len); av_push(array, element); } @@ -154,7 +154,7 @@ SV *val2perlval(db_val_t* val) { p_data = valdata(val); p_type = newSViv(val->type); - + retval = perlvdb_perlmethod(class, PERL_CONSTRUCTOR_NAME, p_type, p_data, NULL, NULL); @@ -175,37 +175,37 @@ SV *pair2perlpair(db_key_t key, db_val_t* val) { p_key = newSVpv(key->s, key->len); p_type = newSViv(val->type); p_data = valdata(val); - + retval = perlvdb_perlmethod(class, PERL_CONSTRUCTOR_NAME, p_key, p_type, p_data, NULL); SvREFCNT_dec(class); return retval; - + } SV *cond2perlcond(db_key_t key, db_op_t op, db_val_t* val) { SV* retval; SV *class; - + SV *p_key; SV *p_op; SV *p_type; SV *p_data; - + ENTER; SAVETMPS; class = newSVpv(PERL_CLASS_REQCOND, 0); - + p_key = newSVpv(key->s, key->len); p_op = newSVpv(op, strlen(op)); p_type = newSViv(val->type); p_data = valdata(val); - + retval = perlvdb_perlmethod(sv_2mortal(class), PERL_CONSTRUCTOR_NAME, sv_2mortal(p_key), sv_2mortal(p_op), sv_2mortal(p_type), sv_2mortal(p_data)); - + FREETMPS; LEAVE; return retval; @@ -214,7 +214,7 @@ SV *cond2perlcond(db_key_t key, db_op_t op, db_val_t* val) { int perlresult2dbres(SV *perlres, db_res_t **r) { - + HV * result = NULL; SV *colarrayref = NULL; AV *colarray = NULL; @@ -239,7 +239,7 @@ int perlresult2dbres(SV *perlres, db_res_t **r) { char *currentstring; int i, j; - + int retval = 0; STRLEN len; @@ -252,9 +252,9 @@ int perlresult2dbres(SV *perlres, db_res_t **r) { (sv_derived_from(perlres, "OpenSIPS::VDB::Result")))) { goto error; } - + result = (HV*)SvRV(perlres); - + /* Memory allocation for C side result structure */ *r = db_new_result(); /* Fetch column definitions */ @@ -263,7 +263,7 @@ int perlresult2dbres(SV *perlres, db_res_t **r) { NULL, NULL, NULL, NULL); */ if (!(SvROK(colarrayref))) goto error; colarray = (AV *)SvRV(colarrayref); - + /* SvREFCNT_dec(colarray); */ if (!(SvTYPE(colarray) == SVt_PVAV)) goto error; @@ -281,7 +281,7 @@ int perlresult2dbres(SV *perlres, db_res_t **r) { (*r)->col.types[i] = SvIV(d1); SvREFCNT_dec(d1); - + d1 = perlvdb_perlmethod(acol, PERL_VDB_NAMEMETHOD, NULL, NULL, NULL, NULL); if (!SvPOK(d1)) goto error; @@ -294,7 +294,7 @@ int perlresult2dbres(SV *perlres, db_res_t **r) { (*r)->col.names[i]->s = charbuf; (*r)->col.names[i]->len = strlen(charbuf); SvREFCNT_dec(d1); - + } if(hv_exists(result, "rows", 4)){ @@ -329,14 +329,14 @@ int perlresult2dbres(SV *perlres, db_res_t **r) { (*r)->n = rowcount; (*r)->res_rows = rowcount; (*r)->last_row = rowcount; - + db_allocate_rows(*r, rowcount); /* (rows * (sizeof(db_row_t) + sizeof(db_val_t) * RES_COL_N(_res)) */ /* LM_DBG("We got %d rows each row requres %d bytes because the row struct is %d and" - "the values in that row take up %d. That is %d values each size is %d\n", - rowcount, sizeof(db_row_t) + sizeof(db_val_t) * RES_COL_N(*r), sizeof(db_row_t), sizeof(db_val_t) * RES_COL_N(*r), RES_COL_N(*r), sizeof(db_val_t)); - */ - + "the values in that row take up %d. That is %d values each size is %d\n", + rowcount, sizeof(db_row_t) + sizeof(db_val_t) * RES_COL_N(*r), sizeof(db_row_t), sizeof(db_val_t) * RES_COL_N(*r), RES_COL_N(*r), sizeof(db_val_t)); + */ + for (i = 0; i < rowcount; i++) { arowref = *av_fetch(rowarray, i, 0); if (!SvROK(arowref)) goto error; @@ -349,7 +349,7 @@ int perlresult2dbres(SV *perlres, db_res_t **r) { #define cur_val (((*r)->rows)[i].values)[j] /*cur_val = (((*r)->rows)[i].values)[j];*/ /* cur_val is just an "abbreviation" */ - if (!(sv_isobject(aelement) && + if (!(sv_isobject(aelement) && sv_derived_from(aelement, PERL_CLASS_VALUE))) { cur_val.nul = 1; continue; @@ -370,12 +370,12 @@ int perlresult2dbres(SV *perlres, db_res_t **r) { } else { switch (atype) { case DB_INT: - cur_val.val.int_val = + cur_val.val.int_val = SvIV(aval); cur_val.nul = 0; break; case DB_DOUBLE: - cur_val.val.double_val = + cur_val.val.double_val = SvNV(aval); cur_val.nul = 0; break; diff --git a/modules/db_perlvdb/perlvdb_conv.h b/modules/db_perlvdb/perlvdb_conv.h index 65f8c6f5cd7..6af2d4d5861 100644 --- a/modules/db_perlvdb/perlvdb_conv.h +++ b/modules/db_perlvdb/perlvdb_conv.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Perl virtual database module interface @@ -18,14 +18,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _PERLVDB_CONV_H -#define _PERLVDB_CONV_H +#define _PERLVDB_CONV_H #include "../../db/db_op.h" #include "../../db/db_val.h" diff --git a/modules/db_perlvdb/perlvdb_oohelpers.c b/modules/db_perlvdb/perlvdb_oohelpers.c index 61e5cab8121..3ab63856f66 100644 --- a/modules/db_perlvdb/perlvdb_oohelpers.c +++ b/modules/db_perlvdb/perlvdb_oohelpers.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Perl virtual database module interface @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -34,15 +34,15 @@ SV *perlvdb_perlmethod(SV *class, SV *param2, SV *param3, SV *param4) { - + I32 res; SV *retval = NULL; - + dSP; - + ENTER; SAVETMPS; - + PUSHMARK(SP); /* passed stack: diff --git a/modules/db_perlvdb/perlvdb_oohelpers.h b/modules/db_perlvdb/perlvdb_oohelpers.h index 80b539bf465..9dacf143721 100644 --- a/modules/db_perlvdb/perlvdb_oohelpers.h +++ b/modules/db_perlvdb/perlvdb_oohelpers.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Perl virtual database module interface @@ -18,14 +18,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _PERLVDB_OOHELPERS_H -#define _PERLVDB_OOHELPERS_H +#define _PERLVDB_OOHELPERS_H #include "perlvdb.h" diff --git a/modules/db_perlvdb/perlvdbfunc.c b/modules/db_perlvdb/perlvdbfunc.c index 7d0fdcb2c18..e861ba5b632 100644 --- a/modules/db_perlvdb/perlvdbfunc.c +++ b/modules/db_perlvdb/perlvdbfunc.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Perl virtual database module interface @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -131,7 +131,7 @@ db_con_t* perlvdb_db_init(const str* url) { PERL_VDB_BASECLASS); return NULL; } - + res = pkg_malloc(consize); if (!res) { LM_ERR("no pkg memory left\n"); @@ -261,7 +261,7 @@ int perlvdb_db_update(db_con_t* h, db_key_t* k, db_op_t* o, db_val_t* v, condarrref = newRV_noinc((SV*)condarr); updatearrref = newRV_noinc((SV*)updatearr); - + ret = perlvdb_perlmethod(getobj(h), PERL_VDB_UPDATEMETHOD, condarrref, updatearrref, NULL, NULL); @@ -302,22 +302,22 @@ int perlvdb_db_query(db_con_t* h, db_key_t* k, db_op_t* op, db_val_t* v, condarr = conds2perlarray(k, op, v, n); retkeysarr = keys2perlarray(c, nc); - + if (o) order = newSVpv(o->s, o->len); else order = &PL_sv_undef; - + condarrref = newRV_noinc((SV*)condarr); retkeysref = newRV_noinc((SV*)retkeysarr); /* Call perl method */ resultset = perlvdb_perlmethod(getobj(h), PERL_VDB_QUERYMETHOD, condarrref, retkeysref, order, NULL); - + SvREFCNT_dec(condarrref); SvREFCNT_dec(retkeysref); if(SvOK(order)) SvREFCNT_dec(order); - + /* Transform perl result set to OpenSIPS result set */ if (!resultset) { /* No results. */ @@ -326,8 +326,8 @@ int perlvdb_db_query(db_con_t* h, db_key_t* k, db_op_t* op, db_val_t* v, if (sv_isa(resultset, "OpenSIPS::VDB::Result")) { retval = perlresult2dbres(resultset, r); /* Nested refs are decreased/deleted inside the routine */ - SvREFCNT_dec(resultset); - } else { + SvREFCNT_dec(resultset); + } else { LM_ERR("invalid result set retrieved from perl call.\n"); retval = -1; } @@ -342,7 +342,7 @@ int perlvdb_db_query(db_con_t* h, db_key_t* k, db_op_t* op, db_val_t* v, int perlvdb_db_free_result(db_con_t* _h, db_res_t* _r) { int i,j; SV* temp; - /* free result set + /* free result set * use the order of allocation * first free values */ @@ -364,7 +364,7 @@ int perlvdb_db_free_result(db_con_t* _h, db_res_t* _r) { case DB_DOUBLE: case DB_BITMAP: case DB_DATETIME: - break; + break; } } /* for each column in row i*/ } /* for each row */ @@ -372,7 +372,7 @@ int perlvdb_db_free_result(db_con_t* _h, db_res_t* _r) { for(i=0; i< RES_COL_N(_r); i++){ pkg_free(RES_NAMES(_r)[i]->s); } - db_free_result(_r); + db_free_result(_r); } return 0; } diff --git a/modules/db_perlvdb/perlvdbfunc.h b/modules/db_perlvdb/perlvdbfunc.h index 61ba8d3a9c1..32c2a826b22 100644 --- a/modules/db_perlvdb/perlvdbfunc.h +++ b/modules/db_perlvdb/perlvdbfunc.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Perl virtual database module interface @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/db_postgres/README b/modules/db_postgres/README index 47057a921dd..c0bd98db40b 100644 --- a/modules/db_postgres/README +++ b/modules/db_postgres/README @@ -10,8 +10,7 @@ Greg Fausak Copyright © 2003 Greg Fausak Revision History - Revision $Revision$ $Date: 2009-07-20 19:41:39 +0300 - (Mon, 20 Jul 2009) $ + Revision $Revision: 5898 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/db_postgres/db_postgres.c b/modules/db_postgres/db_postgres.c index e1414b63290..0842dbd93d7 100644 --- a/modules/db_postgres/db_postgres.c +++ b/modules/db_postgres/db_postgres.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Postgres module interface * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -59,10 +59,12 @@ static param_export_t params[] = { {0, 0, 0} }; -struct module_exports exports = { +struct module_exports exports = { "db_postgres", + MOD_TYPE_SQLDB, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* module parameters */ params, /* module parameters */ 0, /* exported statistics */ @@ -97,7 +99,7 @@ int db_postgres_bind_api(const str* mod, db_func_t *dbb) dbb->raw_query = db_postgres_raw_query; dbb->free_result = db_postgres_free_result; dbb->insert = db_postgres_insert; - dbb->delete = db_postgres_delete; + dbb->delete = db_postgres_delete; dbb->update = db_postgres_update; dbb->cap |= DB_CAP_MULTIPLE_INSERT; diff --git a/modules/db_postgres/dbase.c b/modules/db_postgres/dbase.c index a4367fed3ed..f862a1120b4 100644 --- a/modules/db_postgres/dbase.c +++ b/modules/db_postgres/dbase.c @@ -20,8 +20,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * --- @@ -29,37 +29,37 @@ * History * ------- * 2003-04-06 initial code written (Greg Fausak/Andy Fullford) - * 2006-07-28 within pg_get_result(): added check to immediatly return of no - * result set was returned added check to only execute - * convert_result() if PGRES_TUPLES_OK added safety check to avoid + * 2006-07-28 within pg_get_result(): added check to immediatly return of no + * result set was returned added check to only execute + * convert_result() if PGRES_TUPLES_OK added safety check to avoid * double pg_free_result() (norm) * 2006-08-07 Rewrote pg_get_result(). * Additional debugging lines have been placed through out the code. - * Added Asynchronous Command Processing (PQsendQuery/PQgetResult) - * instead of PQexec. this was done in preparation of adding FETCH - * support. Note that PQexec returns a result pointer while - * PQsendQuery does not. The result set pointer is obtained from + * Added Asynchronous Command Processing (PQsendQuery/PQgetResult) + * instead of PQexec. this was done in preparation of adding FETCH + * support. Note that PQexec returns a result pointer while + * PQsendQuery does not. The result set pointer is obtained from * a call (or multiple calls) to PQgetResult. - * Removed transaction processing calls (BEGIN/COMMIT/ROLLBACK) as - * they added uneeded overhead. Klaus' testing showed in excess of - * 1ms gain by removing each command. In addition, OpenSIPS only + * Removed transaction processing calls (BEGIN/COMMIT/ROLLBACK) as + * they added uneeded overhead. Klaus' testing showed in excess of + * 1ms gain by removing each command. In addition, OpenSIPS only * issues single queries and is not, at this time transaction aware. - * The transaction processing routines have been left in place + * The transaction processing routines have been left in place * should this support be needed in the future. - * Updated logic in pg_query / pg_raw_query to accept a (0) result + * Updated logic in pg_query / pg_raw_query to accept a (0) result * set (_r) parameter. In this case, control is returned - * immediately after submitting the query and no call to - * pg_get_results() is performed. This is a requirement for + * immediately after submitting the query and no call to + * pg_get_results() is performed. This is a requirement for * FETCH support. (norm) * 2006-10-27 Added fetch support (norm) * Removed dependency on aug_* memory routines (norm) * Added connection pooling support (norm) * Standardized API routines to pg_* names (norm) - * 2006-11-01 Updated pg_insert(), pg_delete(), pg_update() and - * pg_get_result() to handle failed queries. Detailed warnings - * along with the text of the failed query is now displayed in the - * log. Callers of these routines can now assume that a non-zero - * rc indicates the query failed and that remedial action may need + * 2006-11-01 Updated pg_insert(), pg_delete(), pg_update() and + * pg_get_result() to handle failed queries. Detailed warnings + * along with the text of the failed query is now displayed in the + * log. Callers of these routines can now assume that a non-zero + * rc indicates the query failed and that remedial action may need * to be taken. (norm) */ @@ -153,7 +153,7 @@ static int db_postgres_submit_query(const db_con_t* _con, const str* _s) /* this bit of nonsense in case our connection get screwed up */ switch(PQstatus(CON_CONNECTION(_con))) { - case CONNECTION_OK: + case CONNECTION_OK: break; case CONNECTION_BAD: LM_DBG("connection reset\n"); @@ -253,12 +253,12 @@ int db_postgres_fetch_result(const db_con_t* _con, db_res_t** _res, const int nr switch(pqresult) { case PGRES_COMMAND_OK: - /* Successful completion of a command returning no data + /* Successful completion of a command returning no data * (such as INSERT or UPDATE). */ return 0; case PGRES_TUPLES_OK: - /* Successful completion of a command returning data + /* Successful completion of a command returning data * (such as a SELECT or SHOW). */ if (db_postgres_get_columns(_con, *_res) < 0) { LM_ERR("failed to get column names\n"); @@ -312,7 +312,7 @@ int db_postgres_fetch_result(const db_con_t* _con, db_res_t** _res, const int nr return 0; /* if the fetch count is less than the remaining rows to process */ - /* set the number of rows to process (during this call) equal to + /* set the number of rows to process (during this call) equal to * the fetch count */ if (nrows < rows) rows = nrows; @@ -449,7 +449,7 @@ int db_postgres_store_result(const db_con_t* _con, db_res_t** _r) } pqresult = PQresultStatus(CON_RESULT(_con)); - + LM_DBG("%p PQresultStatus(%s) PQgetResult(%p)\n", _con, PQresStatus(pqresult), CON_RESULT(_con)); @@ -512,7 +512,7 @@ int db_postgres_store_result(const db_con_t* _con, db_res_t** _r) * _v: values of the keys * _n: number of key=value pairs */ -int db_postgres_insert(const db_con_t* _h, const db_key_t* _k, +int db_postgres_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n) { db_res_t* _r = NULL; @@ -523,7 +523,7 @@ int db_postgres_insert(const db_con_t* _h, const db_key_t* _k, if (submit_func_called) { - /* finish the async query, + /* finish the async query, * otherwise the next query will not complete */ /* only call this if the DB API has effectively called @@ -537,7 +537,7 @@ int db_postgres_insert(const db_con_t* _h, const db_key_t* _k, submit_func_called = 0; } - + if (_r) db_free_result(_r); @@ -567,7 +567,7 @@ int db_postgres_delete(const db_con_t* _h, const db_key_t* _k, if (db_postgres_store_result(_h, &_r) != 0) LM_WARN("unexpected result returned"); - + if (_r) db_free_result(_r); @@ -587,7 +587,7 @@ int db_postgres_delete(const db_con_t* _h, const db_key_t* _k, * _un: number of columns to update */ int db_postgres_update(const db_con_t* _h, const db_key_t* _k, - const db_op_t* _o, const db_val_t* _v, const db_key_t* _uk, + const db_op_t* _o, const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv, const int _n, const int _un) { db_res_t* _r = NULL; diff --git a/modules/db_postgres/dbase.h b/modules/db_postgres/dbase.h index f6b8adb5e5f..b1d715b981b 100644 --- a/modules/db_postgres/dbase.h +++ b/modules/db_postgres/dbase.h @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * --- diff --git a/modules/db_postgres/pg_con.c b/modules/db_postgres/pg_con.c index b7c119de392..9c584b6abce 100644 --- a/modules/db_postgres/pg_con.c +++ b/modules/db_postgres/pg_con.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2004 iptel.org @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -39,7 +39,7 @@ struct pg_con* db_postgres_new_connection(struct db_id* id) char *ports; LM_DBG("db_id = %p\n", id); - + if (!id) { LM_ERR("invalid db_id parameter value\n"); return 0; diff --git a/modules/db_postgres/pg_con.h b/modules/db_postgres/pg_con.h index c53a8446c7e..36bcf7b1287 100644 --- a/modules/db_postgres/pg_con.h +++ b/modules/db_postgres/pg_con.h @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * --- diff --git a/modules/db_postgres/pg_type.h b/modules/db_postgres/pg_type.h index 698ba402c43..e033a7e3358 100644 --- a/modules/db_postgres/pg_type.h +++ b/modules/db_postgres/pg_type.h @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History diff --git a/modules/db_postgres/res.c b/modules/db_postgres/res.c index fd954b78371..b0389b49963 100644 --- a/modules/db_postgres/res.c +++ b/modules/db_postgres/res.c @@ -20,8 +20,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * --- @@ -107,7 +107,7 @@ int db_postgres_get_columns(const db_con_t* _h, db_res_t* _r) return -3; } - /* For each column both the name and the OID number of the + /* For each column both the name and the OID number of the * data type are saved. */ for(col = 0; col < RES_COL_N(_r); col++) { @@ -165,7 +165,7 @@ int db_postgres_get_columns(const db_con_t* _h, db_res_t* _r) LM_DBG("use DB_BITMAP result type\n"); RES_TYPES(_r)[col] = DB_BITMAP; break; - + default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use DB_STRING as default\n", RES_NAMES(_r)[col]->len, @@ -195,7 +195,7 @@ int db_postgres_convert_rows(const db_con_t* _h, db_res_t* _r) RES_ROWS(_r) = 0; return 0; } - /* Allocate an array of pointers per column to holds the string + /* Allocate an array of pointers per column to holds the string * representation */ len = sizeof(char *) * RES_COL_N(_r); row_buf = (char**)pkg_malloc(len); @@ -215,18 +215,18 @@ int db_postgres_convert_rows(const db_con_t* _h, db_res_t* _r) for(row=RES_LAST_ROW(_r); row<(RES_LAST_ROW(_r)+RES_ROW_N(_r)) ; row++) { for(col = 0; col < RES_COL_N(_r); col++) { /* - * The row data pointer returned by PQgetvalue points to - * storage that is part of the PGresult structure. One should - * not modify the data it points to, and one must explicitly - * copy the data into other storage if it is to be used past + * The row data pointer returned by PQgetvalue points to + * storage that is part of the PGresult structure. One should + * not modify the data it points to, and one must explicitly + * copy the data into other storage if it is to be used past * the lifetime of the PGresult structure itself. */ - + /* * There's a weird bug (or just weird behavior) in the postgres - * API - if the result is a BLOB (like 'text') and is with - * zero length, we get a pointer to nowhere, which is not - * null-terminated. The fix for this is to check what does the + * API - if the result is a BLOB (like 'text') and is with + * zero length, we get a pointer to nowhere, which is not + * null-terminated. The fix for this is to check what does the * DB think about the length and use that as a correction. */ if (PQgetisnull(CON_RESULT(_h), row, col) == 0) { @@ -238,7 +238,7 @@ int db_postgres_convert_rows(const db_con_t* _h, db_res_t* _r) s = PQgetvalue(CON_RESULT(_h), row, col); LM_DBG("PQgetvalue(%p,%d,%d)=[%.*s]\n", _h, row,col,len,s); } - + row_buf[col] = pkg_malloc(len+1); if (!row_buf[col]) { LM_ERR("no private memory left\n"); @@ -301,7 +301,7 @@ int db_postgres_convert_rows(const db_con_t* _h, db_res_t* _r) * Note that DB_STRING fields have not been pkg_free(). NULLing DB_STRING * fields would normally not be good to do because a memory leak would * occur. However, the pg_convert_row() routine has saved the DB_STRING - * pointer in the db_val_t structure. The db_val_t structure will + * pointer in the db_val_t structure. The db_val_t structure will * eventually be used to pkg_free() the DB_STRING storage. */ row_buf[col] = (char *)NULL; diff --git a/modules/db_postgres/res.h b/modules/db_postgres/res.h index 33d243fc49a..8c45c367b6e 100644 --- a/modules/db_postgres/res.h +++ b/modules/db_postgres/res.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/db_postgres/val.c b/modules/db_postgres/val.c index 142ce39a8c8..f561b78df92 100644 --- a/modules/db_postgres/val.c +++ b/modules/db_postgres/val.c @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * --- @@ -108,7 +108,7 @@ int db_postgres_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const return 0; } break; - + case DB_DOUBLE: LM_DBG("converting DOUBLE [%s]\n", _s); if (db_str2double(_s, &VAL_DOUBLE(_v)) < 0) { @@ -198,7 +198,7 @@ int db_postgres_val2str(const db_con_t* _con, const db_val_t* _v, *_len = l; return 0; } - + switch(VAL_TYPE(_v)) { case DB_INT: if (db_int2str(VAL_INT(_v), _s, _len) < 0) { diff --git a/modules/db_postgres/val.h b/modules/db_postgres/val.h index 093ffe1181e..74786d46eea 100644 --- a/modules/db_postgres/val.h +++ b/modules/db_postgres/val.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/db_text/README b/modules/db_text/README index 0db73e61a93..dfcd59d5ae2 100644 --- a/modules/db_text/README +++ b/modules/db_text/README @@ -18,8 +18,7 @@ Daniel-Constantin Mierla Copyright © 2003, 2004 FhG FOKUS Revision History - Revision $Revision$ $Date: 2012-12-15 09:11:44 +0400 - (Sat, 15 Dec 2012) $ + Revision $Revision: 9528 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/db_text/dbt_api.c b/modules/db_text/dbt_api.c index 8d9016c4970..461de6874fa 100644 --- a/modules/db_text/dbt_api.c +++ b/modules/db_text/dbt_api.c @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-02-05 created by Daniel - * + * */ #include @@ -47,12 +47,12 @@ int dbt_use_table(db_con_t* _h, const str* _t) static int dbt_get_columns(db_con_t* _h, db_res_t* _r) { int col; - + if (!_h || !_r) { LM_ERR("invalid parameter\n"); return -1; } - + RES_COL_N(_r) = DBT_CON_RESULT(_h)->nrcols; if (!RES_COL_N(_r)) { LM_ERR("no columns\n"); @@ -108,25 +108,25 @@ static int dbt_convert_row(db_con_t* _h, db_res_t* _res, db_row_t* _r) switch(RES_TYPES(_res)[i]) { case DB_INT: - VAL_INT(&(ROW_VALUES(_r)[i])) = + VAL_INT(&(ROW_VALUES(_r)[i])) = DBT_CON_ROW(_h)->fields[i].val.int_val; VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB_INT; break; case DB_BIGINT: - VAL_BIGINT(&(ROW_VALUES(_r)[i])) = + VAL_BIGINT(&(ROW_VALUES(_r)[i])) = DBT_CON_ROW(_h)->fields[i].val.bigint_val; VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB_BIGINT; break; case DB_DOUBLE: - VAL_DOUBLE(&(ROW_VALUES(_r)[i])) = + VAL_DOUBLE(&(ROW_VALUES(_r)[i])) = DBT_CON_ROW(_h)->fields[i].val.double_val; VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB_DOUBLE; break; case DB_STRING: - VAL_STR(&(ROW_VALUES(_r)[i])).s = + VAL_STR(&(ROW_VALUES(_r)[i])).s = DBT_CON_ROW(_h)->fields[i].val.str_val.s; VAL_STR(&(ROW_VALUES(_r)[i])).len = DBT_CON_ROW(_h)->fields[i].val.str_val.len; @@ -135,7 +135,7 @@ static int dbt_convert_row(db_con_t* _h, db_res_t* _res, db_row_t* _r) break; case DB_STR: - VAL_STR(&(ROW_VALUES(_r)[i])).s = + VAL_STR(&(ROW_VALUES(_r)[i])).s = DBT_CON_ROW(_h)->fields[i].val.str_val.s; VAL_STR(&(ROW_VALUES(_r)[i])).len = DBT_CON_ROW(_h)->fields[i].val.str_val.len; @@ -144,7 +144,7 @@ static int dbt_convert_row(db_con_t* _h, db_res_t* _res, db_row_t* _r) break; case DB_DATETIME: - VAL_INT(&(ROW_VALUES(_r)[i])) = + VAL_INT(&(ROW_VALUES(_r)[i])) = DBT_CON_ROW(_h)->fields[i].val.int_val; VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB_DATETIME; break; @@ -253,18 +253,18 @@ int dbt_get_result(db_con_t* _h, db_res_t** _r) } *_r = db_new_result(); - if (*_r == 0) + if (*_r == 0) { LM_ERR("no private memory left\n"); return -2; } - if (dbt_convert_result(_h, *_r) < 0) + if (dbt_convert_result(_h, *_r) < 0) { LM_ERR("failed to convert result\n"); pkg_free(*_r); return -4; } - + return 0; } diff --git a/modules/db_text/dbt_api.h b/modules/db_text/dbt_api.h index 993db1f483d..8d6c6c3f5cd 100644 --- a/modules/db_text/dbt_api.h +++ b/modules/db_text/dbt_api.h @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-02-05 created by Daniel - * + * */ diff --git a/modules/db_text/dbt_base.c b/modules/db_text/dbt_base.c index d12371607b5..a425d0ed257 100644 --- a/modules/db_text/dbt_base.c +++ b/modules/db_text/dbt_base.c @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-01-30 created by Daniel - * + * */ #include @@ -32,7 +32,7 @@ #include "../../str.h" #include "../../mem/mem.h" #include "../../mem/shm_mem.h" - + #include "dbtext.h" #include "dbt_res.h" #include "dbt_api.h" @@ -52,7 +52,7 @@ db_con_t* dbt_init(const str* _sqlurl) db_con_t* _res; str _s; char dbt_path[DBT_PATH_LEN]; - + if (!_sqlurl || !_sqlurl->s) { LM_ERR("invalid parameter value\n"); @@ -85,7 +85,7 @@ db_con_t* dbt_init(const str* _sqlurl) _s.len += sizeof(CFG_DIR); _s.s = dbt_path; } - + _res = pkg_malloc(sizeof(db_con_t)+sizeof(dbt_con_t)); if (!_res) { @@ -95,7 +95,7 @@ db_con_t* dbt_init(const str* _sqlurl) memset(_res, 0, sizeof(db_con_t) + sizeof(dbt_con_t)); _res->tail = (unsigned long)((char*)_res+sizeof(db_con_t)); - LM_INFO("using database at: %.*s", _s.len, _s.s); + LM_INFO("using database at: %.*s\n", _s.len, _s.s); DBT_CON_CONNECTION(_res) = dbt_cache_get_db(&_s); if (!DBT_CON_CONNECTION(_res)) { @@ -112,15 +112,15 @@ db_con_t* dbt_init(const str* _sqlurl) */ void dbt_close(db_con_t* _h) { - if (!_h) + if (!_h) { LM_ERR("invalid parameter value\n"); return; } - - if (DBT_CON_RESULT(_h)) + + if (DBT_CON_RESULT(_h)) dbt_result_free(DBT_CON_RESULT(_h)); - + pkg_free(_h); return; } @@ -137,14 +137,14 @@ int dbt_free_result(db_con_t* _h, db_res_t* _r) return -1; } - if(db_free_result(_r) < 0) + if(db_free_result(_r) < 0) { LM_ERR("unable to free result structure\n"); return -1; } - - if(dbt_result_free(DBT_CON_RESULT(_h)) < 0) + + if(dbt_result_free(DBT_CON_RESULT(_h)) < 0) { LM_ERR("unable to free internal structure\n"); return -1; @@ -166,22 +166,22 @@ int dbt_free_result(db_con_t* _h, db_res_t* _r) * _o: order by the specified column */ -int dbt_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, +int dbt_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _c, int _n, int _nc, db_key_t _o, db_res_t** _r) { dbt_table_p _tbc = NULL; dbt_row_p _drp = NULL; dbt_result_p _dres = NULL; - + int *lkey=NULL, *lres=NULL; - + if ((!_h) || (!_r) || !CON_TABLE(_h)) { LM_ERR("invalid parameters\n"); return -1; } *_r = NULL; - + /* lock database */ _tbc = dbt_db_get_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); @@ -212,10 +212,10 @@ int dbt_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, LM_DBG("new res with %d cols\n", _nc); _dres = dbt_result_new(_tbc, lres, _nc); - + if(!_dres) goto error; - + _drp = _tbc->rows; while(_drp) { @@ -231,15 +231,15 @@ int dbt_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, } dbt_table_update_flags(_tbc, DBT_TBFL_ZERO, DBT_FL_IGN, 1); - + /* unlock database */ dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); /* dbt_result_print(_dres); */ - + DBT_CON_RESULT(_h) = _dres; - + if(lkey) pkg_free(lkey); if(lres) @@ -287,9 +287,9 @@ int dbt_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) { dbt_table_p _tbc = NULL; dbt_row_p _drp = NULL; - + int *lkey=NULL, i, j; - + if (!_h || !CON_TABLE(_h)) { LM_ERR("invalid parameter\n"); @@ -300,7 +300,7 @@ int dbt_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) LM_ERR("no key-value to insert\n"); return -1; } - + /* lock database */ _tbc = dbt_db_get_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); if(!_tbc) @@ -314,7 +314,7 @@ int dbt_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) LM_ERR("more values than columns!!\n"); goto error; } - + if(_k) { lkey = dbt_get_refs(_tbc, _k, _n); @@ -327,7 +327,7 @@ int dbt_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) LM_ERR("no shm memory for a new row!!\n"); goto error; } - + for(i=0; i<_n; i++) { j = (lkey)?lkey[i]:i; @@ -343,7 +343,7 @@ int dbt_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) LM_ERR("cannot set v[%d] in c[%d]!\n", i, j); goto clean; } - + } if(dbt_table_add_row(_tbc, _drp)) @@ -353,7 +353,7 @@ int dbt_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) } /* dbt_print_table(_tbc, NULL); */ - + /* unlock databse */ dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); @@ -361,7 +361,7 @@ int dbt_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) pkg_free(lkey); return 0; - + error: /* unlock database */ dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); @@ -369,16 +369,16 @@ int dbt_insert(db_con_t* _h, db_key_t* _k, db_val_t* _v, int _n) pkg_free(lkey); LM_ERR("failed to insert row in table!\n"); return -1; - + clean: if(lkey) pkg_free(lkey); - + if(_drp) // free row dbt_row_free(_tbc, _drp); /* unlock database */ dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); - + return -1; } @@ -419,7 +419,7 @@ int dbt_delete(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, int _n) lkey = dbt_get_refs(_tbc, _k, _n); if(!lkey) goto error; - + _drp = _tbc->rows; while(_drp) { @@ -441,17 +441,17 @@ int dbt_delete(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, int _n) } dbt_table_update_flags(_tbc, DBT_TBFL_MODI, DBT_FL_SET, 1); - + /* dbt_print_table(_tbc, NULL); */ - + /* unlock database */ dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); if(lkey) pkg_free(lkey); - + return 0; - + error: /* unlock database */ dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); @@ -476,7 +476,7 @@ int dbt_update(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, LM_ERR("invalid parameters\n"); return -1; } - + /* lock database */ _tbc = dbt_db_get_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); if(!_tbc) @@ -506,7 +506,7 @@ int dbt_update(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, LM_ERR("incompatible types!\n"); goto error; } - + if(dbt_row_update_val(_drp, &(_uv[i]), _tbc->colv[lres[i]]->type, lres[i])) { @@ -520,9 +520,9 @@ int dbt_update(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, } dbt_table_update_flags(_tbc, DBT_TBFL_MODI, DBT_FL_SET, 1); - + /* dbt_print_table(_tbc, NULL); */ - + /* unlock database */ dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h)); @@ -541,7 +541,7 @@ int dbt_update(db_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, pkg_free(lkey); if(lres) pkg_free(lres); - + LM_ERR("failed to update the table!\n"); return -1; diff --git a/modules/db_text/dbt_file.c b/modules/db_text/dbt_file.c index 0c571f470c2..222030f592d 100644 --- a/modules/db_text/dbt_file.c +++ b/modules/db_text/dbt_file.c @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-02-03 created by Daniel - * + * */ #include @@ -96,11 +96,11 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) dbt_table_p dtp = NULL; dbt_column_p colp, colp0 = NULL; dbt_row_p rowp, rowp0 = NULL; - + enum {DBT_FLINE_ST, DBT_NLINE_ST, DBT_DATA_ST} state; - + LM_DBG("request for table [%.*s]\n", tbn->len, tbn->s); - + if(!tbn || !tbn->s || tbn->len<=0 || tbn->len>=255) return NULL; path[0] = 0; @@ -120,16 +120,16 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) strncpy(path, tbn->s, tbn->len); path[tbn->len] = 0; } - + LM_DBG("loading file [%s]\n", path); fin = fopen(path, "rt"); if(!fin) - return NULL; - + return NULL; + dtp = dbt_table_new(tbn, dbn, path); if(!dtp) goto done; - + state = DBT_FLINE_ST; crow = ccol = -1; colp = colp0 = NULL; @@ -182,7 +182,7 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) c = fgetc(fin); while(c==DBT_DELIM_C) c = fgetc(fin); - + switch(c) { case 's': @@ -265,6 +265,14 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) colp0 = colp; dtp->nrcols++; c = fgetc(fin); + + /* at least 1 column was found. eat all trailing spaces */ + while (c == DBT_DELIM_C) + c = fgetc(fin); + + /* properly load files which do not end in a newline */ + if (c == EOF) + c = DBT_DELIM_R; } else goto clean; @@ -298,9 +306,9 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) if(!rowp) goto clean; state = DBT_DATA_ST; - + break; - + case DBT_DATA_ST: //LM_DBG("state DATA!\n"); //while(c==DBT_DELIM) @@ -312,17 +320,17 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) } if(ccol>= dtp->nrcols) goto clean; - + switch(dtp->colv[ccol]->type) { case DB_INT: case DB_BIGINT: case DB_DATETIME: - //LM_DBG("INT value!\n"); - dtval.val.int_val = 0; + //LM_DBG("INT/BIGINT/DATETIME value!\n"); + dtval.val.bigint_val = 0; dtval.type = dtp->colv[ccol]->type; - if(c==DBT_DELIM || + if(c==DBT_DELIM || (ccol==dtp->nrcols-1 && (c==DBT_DELIM_R || c==EOF))) dtval.nul = 1; @@ -339,12 +347,12 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) goto clean; while(c>='0' && c<='9') { - dtval.val.int_val=dtval.val.int_val*10+c-'0'; + dtval.val.bigint_val=dtval.val.bigint_val*10+c-'0'; c = fgetc(fin); } - dtval.val.int_val *= sign; + dtval.val.bigint_val *= sign; //LM_DBG("data[%d,%d]=%d\n", crow, - // ccol, dtval.val.int_val); + // ccol, dtval.val.bigint_val); } if(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF) goto clean; @@ -352,16 +360,18 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) ccol)) goto clean; if(ccol == dtp->auto_col) - max_auto = (max_autonrcols-1 && (c==DBT_DELIM_R || c==EOF))) dtval.nul = 1; @@ -402,18 +412,18 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) if(dbt_row_set_val(rowp,&dtval,DB_DOUBLE,ccol)) goto clean; break; - + case DB_STR: case DB_STRING: case DB_BLOB: //LM_DBG("STR value!\n"); - + dtval.val.str_val.s = NULL; dtval.val.str_val.len = 0; dtval.type = dtp->colv[ccol]->type; - + bp = 0; - if(c==DBT_DELIM || + if(c==DBT_DELIM || (ccol == dtp->nrcols-1 && (c == DBT_DELIM_R || c==EOF))) dtval.nul = 1; @@ -428,7 +438,7 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) switch(c) { case 'n': - c = '\n'; + c = '\n'; break; case 'r': c = '\r'; @@ -466,6 +476,11 @@ dbt_table_p dbt_load_file(const str *tbn, const str *dbn) default: goto clean; } + + /* do not skip last row if it does not end with a newline */ + if (c == EOF) + c = DBT_DELIM_R; + if(c==DBT_DELIM) c = fgetc(fin); ccol++; @@ -500,7 +515,7 @@ int dbt_print_table(dbt_table_p _dtp, str *_dbn) FILE *fout = NULL; int ccol; char *p, path[512]; - + if(!_dtp || !_dtp->name.s || _dtp->name.len <= 0) return -1; @@ -521,9 +536,9 @@ int dbt_print_table(dbt_table_p _dtp, str *_dbn) path[_dbn->len+_dtp->name.len+1] = 0; fout = fopen(path, "wt"); if(!fout) - return -1; + return -1; } - + colp = _dtp->cols; while(colp) { @@ -533,7 +548,7 @@ int dbt_print_table(dbt_table_p _dtp, str *_dbn) fprintf(fout, "%.*s(int", colp->name.len, colp->name.s); break; case DB_BIGINT: - fprintf(fout, "%.*s(bigint", colp->name.len, colp->name.s); + fprintf(fout, "%.*s(long", colp->name.len, colp->name.s); break; case DB_DOUBLE: fprintf(fout, "%.*s(double", colp->name.len, colp->name.s); @@ -555,13 +570,13 @@ int dbt_print_table(dbt_table_p _dtp, str *_dbn) fclose(fout); return -1; } - + if(colp->flag & DBT_FLAG_NULL) fprintf(fout,",null"); else if(colp->type==DB_INT && colp->flag & DBT_FLAG_AUTO) fprintf(fout,",auto"); fprintf(fout,")"); - + colp = colp->next; if(colp) fprintf(fout,"%c", DBT_DELIM_C); @@ -637,10 +652,10 @@ int dbt_print_table(dbt_table_p _dtp, str *_dbn) fprintf(fout, "%c", DBT_DELIM_R); rowp = rowp->next; } - + if(fout!=stdout) fclose(fout); - + return 0; } diff --git a/modules/db_text/dbt_lib.c b/modules/db_text/dbt_lib.c index 946144d2c51..a794dbfe4a7 100644 --- a/modules/db_text/dbt_lib.c +++ b/modules/db_text/dbt_lib.c @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-01-30 created by Daniel - * + * */ #include @@ -81,7 +81,7 @@ int dbt_init_cache(void) } /* init tables' hash table */ if (!_dbt_cachetbl) { - _dbt_cachetbl + _dbt_cachetbl = (dbt_tbl_cachel_p)shm_malloc(DBT_CACHETBL_SIZE* sizeof(dbt_tbl_cachel_t)); if(_dbt_cachetbl==NULL) @@ -106,7 +106,7 @@ int dbt_init_cache(void) } } - + return 0; } @@ -128,17 +128,17 @@ dbt_cache_p dbt_cache_get_db(str *_s) LM_DBG("looking for db %.*s!\n",_s->len,_s->s); lock_get(_dbt_cachesem); - + _dcache = *_dbt_cachedb; while(_dcache) { - if(_dcache->name.len==_s->len + if(_dcache->name.len==_s->len && !strncasecmp(_dcache->name.s, _s->s, _s->len)) { LM_DBG("db already cached!\n"); goto done; } - + _dcache = _dcache->next; } if(!dbt_is_database(_s)) @@ -147,7 +147,7 @@ dbt_cache_p dbt_cache_get_db(str *_s) goto done; } LM_DBG("new db!\n"); - + _dcache = (dbt_cache_p)shm_malloc(sizeof(dbt_cache_t)); if(!_dcache) { @@ -155,7 +155,7 @@ dbt_cache_p dbt_cache_get_db(str *_s) goto done; } memset(_dcache, 0, sizeof(dbt_cache_t)); - + _dcache->name.s = (char*)shm_malloc((_s->len+1)*sizeof(char)); if(!_dcache->name.s) { @@ -164,11 +164,11 @@ dbt_cache_p dbt_cache_get_db(str *_s) _dcache = NULL; goto done; } - + memcpy(_dcache->name.s, _s->s, _s->len); _dcache->name.s[_s->len] = '\0'; _dcache->name.len = _s->len; - + if(*_dbt_cachedb) _dcache->next = *_dbt_cachedb; @@ -188,9 +188,9 @@ int dbt_cache_check_db(str *_s) if(!_dbt_cachesem || !(*_dbt_cachedb) || !_s || !_s->s || _s->len<=0) return -1; - + lock_get(_dbt_cachesem); - + _dcache = *_dbt_cachedb; while(_dcache) { @@ -202,7 +202,7 @@ int dbt_cache_check_db(str *_s) } _dcache = _dcache->next; } - + lock_release(_dbt_cachesem); return -1; } @@ -220,7 +220,7 @@ int dbt_db_del_table(dbt_cache_p _dc, const str *_s, int sync) hash = core_hash(&_dc->name, _s, DBT_CACHETBL_SIZE); hashidx = hash % DBT_CACHETBL_SIZE; - + if(sync) lock_get(&_dbt_cachetbl[hashidx].sem); @@ -237,7 +237,7 @@ int dbt_db_del_table(dbt_cache_p _dc, const str *_s, int sync) (_tbc->prev)->next = _tbc->next; else _dbt_cachetbl[hashidx].dtp = _tbc->next; - + if(_tbc->next) (_tbc->next)->prev = _tbc->prev; break; @@ -249,7 +249,7 @@ int dbt_db_del_table(dbt_cache_p _dc, const str *_s, int sync) lock_release(&_dbt_cachetbl[hashidx].sem); dbt_table_free(_tbc); - + return 0; } @@ -267,7 +267,7 @@ dbt_table_p dbt_db_get_table(dbt_cache_p _dc, const str *_s) hash = core_hash(&_dc->name, _s, DBT_CACHETBL_SIZE); hashidx = hash % DBT_CACHETBL_SIZE; - + lock_get(&_dbt_cachetbl[hashidx].sem); _tbc = _dbt_cachetbl[hashidx].dtp; @@ -290,7 +290,7 @@ dbt_table_p dbt_db_get_table(dbt_cache_p _dc, const str *_s) } _tbc = _tbc->next; } - + /* new table */ if(_tbc) /* free old one */ { @@ -309,7 +309,7 @@ dbt_table_p dbt_db_get_table(dbt_cache_p _dc, const str *_s) _tbc->next = _dbt_cachetbl[hashidx].dtp; if(_dbt_cachetbl[hashidx].dtp) _dbt_cachetbl[hashidx].dtp->prev = _tbc; - + _dbt_cachetbl[hashidx].dtp = _tbc; /* table is locked */ @@ -326,7 +326,7 @@ int dbt_release_table(dbt_cache_p _dc, const str *_s) hash = core_hash(&_dc->name, _s, DBT_CACHETBL_SIZE); hashidx = hash % DBT_CACHETBL_SIZE; - + lock_release(&_dbt_cachetbl[hashidx].sem); return 0; @@ -341,10 +341,10 @@ int dbt_cache_destroy(void) dbt_cache_p _dc=NULL, _dc0=NULL; dbt_table_p _tbc = NULL; dbt_table_p _tbc0 = NULL; - + if(!_dbt_cachesem) return -1; - + lock_get(_dbt_cachesem); if( _dbt_cachedb!=NULL ) { @@ -389,7 +389,7 @@ int dbt_cache_print(int _f) if(!_dbt_cachetbl) return -1; - + for(i=0; i< DBT_CACHETBL_SIZE; i++) { lock_get(&_dbt_cachetbl[i].sem); @@ -418,7 +418,7 @@ int dbt_cache_print(int _f) } lock_release(&_dbt_cachetbl[i].sem); } - + return 0; } diff --git a/modules/db_text/dbt_lib.h b/modules/db_text/dbt_lib.h index f3ef1509b8a..609eb84ffcf 100644 --- a/modules/db_text/dbt_lib.h +++ b/modules/db_text/dbt_lib.h @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-01-30 created by Daniel - * + * */ @@ -62,7 +62,7 @@ typedef struct _dbt_row dbt_val_p fields; struct _dbt_row *prev; struct _dbt_row *next; - + } dbt_row_t, *dbt_row_p; typedef struct _dbt_column @@ -72,7 +72,7 @@ typedef struct _dbt_column int flag; struct _dbt_column *prev; struct _dbt_column *next; - + } dbt_column_t, *dbt_column_p; @@ -101,7 +101,7 @@ typedef struct _dbt_tbl_cachel dbt_table_p dtp; } dbt_tbl_cachel_t, *dbt_tbl_cachel_p; -typedef struct _dbt_cache +typedef struct _dbt_cache { str name; int flags; diff --git a/modules/db_text/dbt_res.c b/modules/db_text/dbt_res.c index 496638ecf0b..d646bad3a8a 100644 --- a/modules/db_text/dbt_res.c +++ b/modules/db_text/dbt_res.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -27,7 +27,7 @@ * the second one, the result of 'dbt_row_match' was always true, * thanks to Gabriel, (Daniel) * 2003-02-04 created by Daniel - * + * */ #include @@ -43,13 +43,13 @@ dbt_result_p dbt_result_new(dbt_table_p _dtp, int *_lres, int _sz) dbt_result_p _dres = NULL; int i, n; char *p; - + if(!_dtp || _sz < 0) return NULL; if(!_lres) _sz = _dtp->nrcols; - + _dres = (dbt_result_p)pkg_malloc(sizeof(dbt_result_t)); if(!_dres) return NULL; @@ -78,7 +78,7 @@ dbt_result_p dbt_result_new(dbt_table_p _dtp, int *_lres, int _sz) _dres->colv[i].type = (_lres)?_dtp->colv[_lres[i]]->type:_dtp->colv[i]->type; } - + _dres->nrcols = _sz; _dres->nrrows = 0; _dres->rows = NULL; @@ -93,7 +93,7 @@ dbt_result_p dbt_result_new(dbt_table_p _dtp, int *_lres, int _sz) } pkg_free(_dres->colv); pkg_free(_dres); - + return NULL; } @@ -112,7 +112,7 @@ int dbt_result_free(dbt_result_p _dres) { for(i=0; i<_dres->nrcols; i++) { - if((_dres->colv[i].type==DB_STR + if((_dres->colv[i].type==DB_STR || _dres->colv[i].type==DB_STRING) && _rp0->fields[i].val.str_val.s) pkg_free(_rp0->fields[i].val.str_val.s); @@ -142,7 +142,7 @@ int dbt_result_add_row(dbt_result_p _dres, dbt_row_p _drp) if(!_dres || !_drp) return -1; _dres->nrrows++; - + if(_dres->rows) (_dres->rows)->prev = _drp; _drp->next = _dres->rows; @@ -154,7 +154,7 @@ int dbt_result_add_row(dbt_result_p _dres, dbt_row_p _drp) int* dbt_get_refs(dbt_table_p _dtp, db_key_t* _k, int _n) { int i, j, *_lref=NULL; - + if(!_dtp || !_k || _n < 0) return NULL; @@ -182,7 +182,7 @@ int* dbt_get_refs(dbt_table_p _dtp, db_key_t* _k, int _n) } } return _lref; -} +} int dbt_row_match(dbt_table_p _dtp, dbt_row_p _drp, int* _lkey, @@ -222,7 +222,7 @@ int dbt_row_match(dbt_table_p _dtp, dbt_row_p _drp, int* _lkey, return 0; }else{ return 0; - }}}}} + }}}}} } return 1; } @@ -232,10 +232,10 @@ int dbt_result_extract_fields(dbt_table_p _dtp, dbt_row_p _drp, { dbt_row_p _rp=NULL; int i, n; - - if(!_dtp || !_drp || !_dres || _dres->nrcols<=0) + + if(!_dtp || !_drp || !_dres || _dres->nrcols<=0) return -1; - + _rp = dbt_result_new_row(_dres); if(!_rp) return -1; @@ -254,7 +254,7 @@ int dbt_result_extract_fields(dbt_table_p _dtp, dbt_row_p _drp, memset(&(_rp->fields[i].val), 0, sizeof(_rp->fields[i].val)); continue; } - + switch(_dres->colv[i].type) { case DB_INT: @@ -309,7 +309,7 @@ int dbt_result_extract_fields(dbt_table_p _dtp, dbt_row_p _drp, && !_rp->fields[i].nul && _rp->fields[i].val.str_val.s) pkg_free(_rp->fields[i].val.str_val.s); - + i--; } pkg_free(_rp->fields); @@ -330,7 +330,7 @@ int dbt_result_print(dbt_result_p _dres) return -1; fprintf(fout, "\nContent of result\n"); - + for(i=0; i<_dres->nrcols; i++) { switch(_dres->colv[i].type) @@ -445,7 +445,7 @@ int dbt_cmp_val(dbt_val_p _vp, db_val_t* _v) return 1; if(_vp->nul) return -1; - + switch(VAL_TYPE(_v)) { case DB_INT: @@ -505,7 +505,7 @@ dbt_row_p dbt_result_new_row(dbt_result_p _dres) dbt_row_p _drp = NULL; if(!_dres || _dres->nrcols<=0) return NULL; - + _drp = (dbt_row_p)pkg_malloc(sizeof(dbt_row_t)); if(!_drp) return NULL; diff --git a/modules/db_text/dbt_res.h b/modules/db_text/dbt_res.h index ac9b6459f6d..d8c940d0b21 100644 --- a/modules/db_text/dbt_res.h +++ b/modules/db_text/dbt_res.h @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-02-04 created by Daniel - * + * */ diff --git a/modules/db_text/dbt_tb.c b/modules/db_text/dbt_tb.c index a1bd74da05f..28ca5a04825 100644 --- a/modules/db_text/dbt_tb.c +++ b/modules/db_text/dbt_tb.c @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-02-03 created by Daniel - * + * */ #include @@ -75,13 +75,13 @@ dbt_column_p dbt_column_new(char *_s, int _l) */ int dbt_column_free(dbt_column_p dcp) { - + if(!dcp) return -1; if(dcp->name.s) shm_free(dcp->name.s); shm_free(dcp); - + return 0; } @@ -96,7 +96,7 @@ dbt_row_p dbt_row_new(int _nf) _drp = (dbt_row_p)shm_malloc(sizeof(dbt_row_t)); if(!_drp) return NULL; - + _drp->fields = (dbt_val_p)shm_malloc(_nf*sizeof(dbt_val_t)); if(!_drp->fields) { @@ -118,10 +118,10 @@ dbt_row_p dbt_row_new(int _nf) int dbt_row_free(dbt_table_p _dtp, dbt_row_p _drp) { int i; - + if(!_dtp || !_drp) return -1; - + if(_drp->fields) { for(i=0; i<_dtp->nrcols; i++) @@ -145,10 +145,12 @@ dbt_table_p dbt_table_new(const str *_tbname, const str *_dbname, const char *pa dbt_table_p dtp = NULL; if(!_tbname || !_dbname || !path) return NULL; - + dtp = (dbt_table_p)shm_malloc(sizeof(dbt_table_t)); if(!dtp) goto done; + memset(dtp, 0, sizeof *dtp); + dtp->name.s = (char*)shm_malloc((_tbname->len+1)*sizeof(char)); if(!dtp->name.s) { @@ -159,7 +161,7 @@ dbt_table_p dbt_table_new(const str *_tbname, const str *_dbname, const char *pa memcpy(dtp->name.s, _tbname->s, _tbname->len); dtp->name.s[_tbname->len] = '\0'; dtp->name.len = _tbname->len; - + dtp->dbname.s = (char*)shm_malloc((_dbname->len+1)*sizeof(char)); if(!dtp->dbname.s) { @@ -172,20 +174,15 @@ dbt_table_p dbt_table_new(const str *_tbname, const str *_dbname, const char *pa dtp->dbname.s[_dbname->len] = '\0'; dtp->dbname.len = _dbname->len; - dtp->rows = NULL; - dtp->cols = NULL; - dtp->colv = NULL; dtp->mark = (int)time(NULL); dtp->flag = DBT_TBFL_ZERO; - dtp->nrrows = dtp->nrcols = dtp->auto_val = 0; dtp->auto_col = -1; - dtp->mt = 0; if(stat(path, &s) == 0) { dtp->mt = s.st_mtime; LM_DBG("mtime is %d\n", (int)s.st_mtime); } - + done: return dtp; } @@ -196,7 +193,7 @@ dbt_table_p dbt_table_new(const str *_tbname, const str *_dbname, const char *pa int dbt_table_free_rows(dbt_table_p _dtp) { dbt_row_p _rp=NULL, _rp0=NULL; - + if(!_dtp || !_dtp->rows || !_dtp->colv) return -1; _rp = _dtp->rows; @@ -206,9 +203,9 @@ int dbt_table_free_rows(dbt_table_p _dtp) _rp=_rp->next; dbt_row_free(_dtp, _rp0); } - + dbt_table_update_flags(_dtp, DBT_TBFL_MODI, DBT_FL_SET, 1); - + _dtp->rows = NULL; _dtp->nrrows = 0; @@ -222,12 +219,12 @@ int dbt_table_add_row(dbt_table_p _dtp, dbt_row_p _drp) { if(!_dtp || !_drp) return -1; - + if(dbt_table_check_row(_dtp, _drp)) return -1; - + dbt_table_update_flags(_dtp, DBT_TBFL_MODI, DBT_FL_SET, 1); - + if(_dtp->rows) (_dtp->rows)->prev = _drp; _drp->next = _dtp->rows; @@ -243,7 +240,7 @@ int dbt_table_add_row(dbt_table_p _dtp, dbt_row_p _drp) int dbt_table_free(dbt_table_p _dtp) { dbt_column_p _cp=NULL, _cp0=NULL; - + if(!_dtp) return -1; @@ -251,10 +248,10 @@ int dbt_table_free(dbt_table_p _dtp) shm_free(_dtp->name.s); if(_dtp->dbname.s) shm_free(_dtp->dbname.s); - + if(_dtp->rows && _dtp->nrrows>0) dbt_table_free_rows(_dtp); - + _cp = _dtp->cols; while(_cp) { @@ -277,7 +274,7 @@ int dbt_row_set_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) { if(!_drp || !_vp || _idx<0) return -1; - + _drp->fields[_idx].nul = _vp->nul; _drp->fields[_idx].type = _t; @@ -288,7 +285,7 @@ int dbt_row_set_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) case DB_STR: case DB_BLOB: _drp->fields[_idx].type = _t; - _drp->fields[_idx].val.str_val.s = + _drp->fields[_idx].val.str_val.s = (char*)shm_malloc((_vp->val.str_val.len+1)*sizeof(char)); if(!_drp->fields[_idx].val.str_val.s) { @@ -300,12 +297,12 @@ int dbt_row_set_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) _drp->fields[_idx].val.str_val.s[_vp->val.str_val.len] = '\0'; _drp->fields[_idx].val.str_val.len = _vp->val.str_val.len; break; - + case DB_STRING: _drp->fields[_idx].type = _t; _drp->fields[_idx].val.str_val.len=_vp->val.str_val.len; - - _drp->fields[_idx].val.str_val.s = + + _drp->fields[_idx].val.str_val.s = (char*)shm_malloc((_drp->fields[_idx].val.str_val.len+1) *sizeof(char)); if(!_drp->fields[_idx].val.str_val.s) @@ -317,38 +314,38 @@ int dbt_row_set_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) _drp->fields[_idx].val.str_val.len); _drp->fields[_idx].val.str_val.s[_drp->fields[_idx].val.str_val.len] = '\0'; break; - + case DB_DOUBLE: _drp->fields[_idx].type = DB_DOUBLE; _drp->fields[_idx].val.double_val = _vp->val.double_val; break; - + case DB_INT: _drp->fields[_idx].type = DB_INT; _drp->fields[_idx].val.int_val = _vp->val.int_val; break; - + case DB_BIGINT: _drp->fields[_idx].type = DB_BIGINT; _drp->fields[_idx].val.bigint_val = _vp->val.bigint_val; break; - + case DB_DATETIME: _drp->fields[_idx].type = _t; _drp->fields[_idx].val.int_val = (int)_vp->val.time_val; break; - + case DB_BITMAP: _drp->fields[_idx].type = DB_INT; _drp->fields[_idx].val.int_val = (int)_vp->val.bitmap_val; break; - + default: _drp->fields[_idx].nul = 1; return -1; } } - + return 0; } @@ -359,10 +356,10 @@ int dbt_row_update_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) { if(!_drp || !_vp || _idx<0) return -1; - + _drp->fields[_idx].nul = _vp->nul; _drp->fields[_idx].type = _t; - + if(!_vp->nul) { switch(_t) @@ -373,8 +370,8 @@ int dbt_row_update_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) // free if already exists if(_drp->fields[_idx].val.str_val.s) shm_free(_drp->fields[_idx].val.str_val.s); - - _drp->fields[_idx].val.str_val.s = + + _drp->fields[_idx].val.str_val.s = (char*)shm_malloc((_vp->val.str_val.len+1)*sizeof(char)); if(!_drp->fields[_idx].val.str_val.s) { @@ -386,7 +383,7 @@ int dbt_row_update_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) _drp->fields[_idx].val.str_val.s[_vp->val.str_val.len] = '\0'; _drp->fields[_idx].val.str_val.len = _vp->val.str_val.len; break; - + case DB_STRING: /* free if already exists */ if(_drp->fields[_idx].val.str_val.s) @@ -398,8 +395,8 @@ int dbt_row_update_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) else _drp->fields[_idx].val.str_val.len =strlen(_vp->val.string_val); - - _drp->fields[_idx].val.str_val.s = + + _drp->fields[_idx].val.str_val.s = (char*)shm_malloc((_drp->fields[_idx].val.str_val.len+1) *sizeof(char)); if(!_drp->fields[_idx].val.str_val.s) @@ -411,39 +408,39 @@ int dbt_row_update_val(dbt_row_p _drp, dbt_val_p _vp, int _t, int _idx) _drp->fields[_idx].val.str_val.len); _drp->fields[_idx].val.str_val.s[_vp->val.str_val.len] = '\0'; break; - + case DB_DOUBLE: _drp->fields[_idx].type = _t; _drp->fields[_idx].val.double_val = _vp->val.double_val; break; - + case DB_INT: _drp->fields[_idx].type = _t; _drp->fields[_idx].val.int_val = _vp->val.int_val; break; - + case DB_BIGINT: _drp->fields[_idx].type = _t; _drp->fields[_idx].val.bigint_val = _vp->val.bigint_val; break; - + case DB_DATETIME: _drp->fields[_idx].type = _t; _drp->fields[_idx].val.int_val = (int)_vp->val.time_val; break; - + case DB_BITMAP: _drp->fields[_idx].type = _t; _drp->fields[_idx].val.int_val = (int)_vp->val.bitmap_val; break; - + default: LM_ERR("unsupported type %d in update\n",_t); _drp->fields[_idx].nul = 1; return -1; } } - + return 0; } @@ -455,10 +452,10 @@ int dbt_table_check_row(dbt_table_p _dtp, dbt_row_p _drp) int i; if(!_dtp || _dtp->nrcols <= 0 || !_drp) return -1; - + for(i=0; i<_dtp->nrcols; i++) { - if(!_drp->fields[i].nul + if(!_drp->fields[i].nul && dbt_is_neq_type(_dtp->colv[i]->type, _drp->fields[i].type)) { LM_ERR("incompatible types - field %d [%d/%d]\n",i, @@ -467,7 +464,7 @@ int dbt_table_check_row(dbt_table_p _dtp, dbt_row_p _drp) } if(_dtp->colv[i]->flag & DBT_FLAG_NULL) continue; - + if(!_drp->fields[i].nul) continue; @@ -483,7 +480,7 @@ int dbt_table_check_row(dbt_table_p _dtp, dbt_row_p _drp) LM_ERR("null value not allowed - field %d\n",i); return -1; } - + return 0; } @@ -494,15 +491,15 @@ int dbt_table_update_flags(dbt_table_p _dtp, int _f, int _o, int _m) { if(!_dtp) return -1; - + if(_o == DBT_FL_SET) _dtp->flag |= _f; else if(_o == DBT_FL_UNSET) _dtp->flag &= ~_f; - + if(_m) _dtp->mark = (int)time(NULL); - + return 0; } diff --git a/modules/db_text/dbt_util.c b/modules/db_text/dbt_util.c index b31d4445c43..0ce9c03cec0 100644 --- a/modules/db_text/dbt_util.c +++ b/modules/db_text/dbt_util.c @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * ------- * 2003-01-30 created by Daniel - * + * */ #include @@ -40,7 +40,7 @@ int dbt_is_database(str *_s) { DIR *dirp = NULL; char buf[512]; - + if(!_s || !_s->s || _s->len <= 0 || _s->len > 510) return 0; strncpy(buf, _s->s, _s->len); diff --git a/modules/db_text/dbt_util.h b/modules/db_text/dbt_util.h index 2c03bbe8ede..19e33620315 100644 --- a/modules/db_text/dbt_util.h +++ b/modules/db_text/dbt_util.h @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-01-30 created by Daniel - * + * */ diff --git a/modules/db_text/dbtext.c b/modules/db_text/dbtext.c index 20f43a9def0..2d59c8d361e 100644 --- a/modules/db_text/dbtext.c +++ b/modules/db_text/dbtext.c @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-01-30 created by Daniel * 2003-03-11 New module interface (janakj) * 2003-03-16 flags export parameter added (janakj) - * + * */ #include @@ -76,10 +76,12 @@ static mi_export_t mi_cmds[] = { {0, 0, 0, 0, 0, 0} }; -struct module_exports exports = { +struct module_exports exports = { "db_text", + MOD_TYPE_SQLDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ NULL, /* exported statistics */ @@ -98,7 +100,7 @@ static int mod_init(void) if(dbt_init_cache()) return -1; /* return make_demo(); */ - + return 0; } @@ -124,7 +126,7 @@ int dbt_bind_api(const str* mod, db_func_t *dbb) dbb->query = (db_query_f)dbt_query; dbb->free_result = dbt_free_result; dbb->insert = (db_insert_f)dbt_insert; - dbb->delete = (db_delete_f)dbt_delete; + dbb->delete = (db_delete_f)dbt_delete; dbb->update = (db_update_f)dbt_update; return 0; diff --git a/modules/db_text/dbtext.h b/modules/db_text/dbtext.h index 34a36000489..f3197caf14c 100644 --- a/modules/db_text/dbtext.h +++ b/modules/db_text/dbtext.h @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-01-30 created by Daniel - * + * */ @@ -59,7 +59,7 @@ int dbt_free_result(db_con_t* _h, db_res_t* _r); /* * Do a query */ -int dbt_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, +int dbt_query(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _c, int _n, int _nc, db_key_t _o, db_res_t** _r); diff --git a/modules/db_unixodbc/README b/modules/db_unixodbc/README index 5944f71f4b8..3594948d7d7 100644 --- a/modules/db_unixodbc/README +++ b/modules/db_unixodbc/README @@ -10,8 +10,7 @@ Marco Lorrai Copyright © 2005, 2006 Marco Lorrai Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/db_unixodbc/con.c b/modules/db_unixodbc/con.c index 3f835f34412..1d8428a3ca3 100644 --- a/modules/db_unixodbc/con.c +++ b/modules/db_unixodbc/con.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * UNIXODBC module @@ -26,7 +26,7 @@ * History: * -------- * 2005-12-01 initial commit (chgen) - * 2006-01-10 UID (username) and PWD (password) attributes added to + * 2006-01-10 UID (username) and PWD (password) attributes added to * connection string (bogdan) * 2006-05-05 extract_error passes back last error state on return (sgupta) */ @@ -216,7 +216,7 @@ void db_unixodbc_extract_error(const char *fn, const SQLHANDLE handle, const SQL ret = SQLGetDiagRec(type, handle, ++i, state, &native, text, sizeof(text), &len ); if (SQL_SUCCEEDED(ret)) { - LM_ERR("unixodbc:%s=%s:%ld:%ld:%s\n", fn, state, (long)i, + LM_ERR("unixodbc:%s=%s:%ld:%ld:%s\n", fn, state, (long)i, (long)native, text); if(stret) strcpy( stret, (char*)state ); } diff --git a/modules/db_unixodbc/con.h b/modules/db_unixodbc/con.h index fea974209fc..6291dab183a 100644 --- a/modules/db_unixodbc/con.h +++ b/modules/db_unixodbc/con.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * UNIXODBC module @@ -60,6 +60,7 @@ struct my_con SQLHSTMT stmt_handle; /* Actual result */ SQLHDBC dbc; /* Connection representation */ char** row; /* Actual row in the result */ + void *data; time_t timestamp; /* Timestamp of last query */ }; @@ -72,6 +73,7 @@ struct my_con #define CON_TIMESTAMP(db_con) (((struct my_con*)((db_con)->tail))->timestamp) #define CON_ID(db_con) (((struct my_con*)((db_con)->tail))->id) #define CON_ENV(db_con) (((struct my_con*)((db_con)->tail))->env) +#define CON_DATA(db_con) (((struct my_con*)((db_con)->tail))->data) #define MAX_CONN_STR_LEN 2048 diff --git a/modules/db_unixodbc/db_unixodbc.c b/modules/db_unixodbc/db_unixodbc.c index 9990c56ad89..7b1f7fe6edb 100644 --- a/modules/db_unixodbc/db_unixodbc.c +++ b/modules/db_unixodbc/db_unixodbc.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * UNIXODBC module interface * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -61,10 +61,12 @@ static param_export_t params[] = { }; -struct module_exports exports = { +struct module_exports exports = { "db_unixodbc", + MOD_TYPE_SQLDB,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, params, /* module parameters */ 0, /* exported statistics */ @@ -91,7 +93,7 @@ int db_unixodbc_bind_api(const str* mod, db_func_t *dbb) dbb->raw_query = db_unixodbc_raw_query; dbb->free_result = db_unixodbc_free_result; dbb->insert = db_unixodbc_insert; - dbb->delete = db_unixodbc_delete; + dbb->delete = db_unixodbc_delete; dbb->update = db_unixodbc_update; dbb->replace = db_unixodbc_replace; diff --git a/modules/db_unixodbc/db_unixodbc.h b/modules/db_unixodbc/db_unixodbc.h index 2d621b7981b..09e6fd59929 100644 --- a/modules/db_unixodbc/db_unixodbc.h +++ b/modules/db_unixodbc/db_unixodbc.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * UNIXODBC module interface * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * diff --git a/modules/db_unixodbc/dbase.c b/modules/db_unixodbc/dbase.c index 507949e0c0e..b9fe0952f7b 100644 --- a/modules/db_unixodbc/dbase.c +++ b/modules/db_unixodbc/dbase.c @@ -29,7 +29,7 @@ * 2006-04-03 fixed invalid handle to extract error (sgupta) * 2006-04-04 removed deprecated ODBC functions, closed cursors on error * (sgupta) - * 2006-05-05 Fixed reconnect code to actually work on connection loss + * 2006-05-05 Fixed reconnect code to actually work on connection loss * (sgupta) */ @@ -38,6 +38,7 @@ #include "../../dprint.h" #include "../../db/db_query.h" #include "val.h" +#include "list.h" #include "con.h" #include "res.h" #include "db_unixodbc.h" @@ -113,7 +114,7 @@ static int db_unixodbc_submit_query(const db_con_t* _h, const str* _s) (int)(long)CON_CONNECTION(_h)); db_unixodbc_extract_error("SQLAllocStmt", CON_CONNECTION(_h), SQL_HANDLE_DBC, (char*)sqlstate); - + /* Connection broken */ if( !strncmp((char*)sqlstate,"08003",5) || !strncmp((char*)sqlstate,"08S01",5) ) { @@ -134,7 +135,7 @@ static int db_unixodbc_submit_query(const db_con_t* _h, const str* _s) /* Connection broken */ if( !strncmp((char*)sqlstate,"08003",5) || - !strncmp((char*)sqlstate,"08S01",5) + !strncmp((char*)sqlstate,"08S01",5) ) { ret = reconnect(_h); @@ -153,7 +154,7 @@ static int db_unixodbc_submit_query(const db_con_t* _h, const str* _s) } else { - /* Close the cursor */ + /* Close the cursor */ SQLCloseCursor(CON_RESULT(_h)); SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h)); } @@ -245,6 +246,11 @@ int db_unixodbc_free_result(db_con_t* _h, db_res_t* _r) LM_ERR("failed to free result structure\n"); return -1; } + + /* free the duplicated list of results */ + if (CON_DATA(_h)) + db_unixodbc_list_destroy((list *)CON_DATA(_h)); + SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h)); CON_RESULT(_h) = 0; return 0; @@ -334,7 +340,7 @@ int db_unixodbc_update(const db_con_t* _h, const db_key_t* _k, /* * Just like insert, but replace the row if it exists */ -int db_unixodbc_replace(const db_con_t* _h, const db_key_t* _k, +int db_unixodbc_replace(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n) { CON_RESET_CURR_PS(_h); /* no prepared statements support */ diff --git a/modules/db_unixodbc/list.c b/modules/db_unixodbc/list.c index b94461c04df..d45173a4ad4 100644 --- a/modules/db_unixodbc/list.c +++ b/modules/db_unixodbc/list.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * UNIXODBC module * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -78,7 +78,7 @@ int db_unixodbc_list_insert(list** start, list** link, int n, strn* value) } strncpy((*link)->data[i], value[i].s, (*link)->lengths[i]); } - + *start = *link; return 0; } diff --git a/modules/db_unixodbc/list.h b/modules/db_unixodbc/list.h index dea1dcc0302..1765cfcb65e 100644 --- a/modules/db_unixodbc/list.h +++ b/modules/db_unixodbc/list.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * UNIXODBC module * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * diff --git a/modules/db_unixodbc/res.c b/modules/db_unixodbc/res.c index d8cb24e77c2..727a5126a38 100644 --- a/modules/db_unixodbc/res.c +++ b/modules/db_unixodbc/res.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * UNIXODBC module result related functions @@ -236,7 +236,8 @@ static inline int db_unixodbc_convert_rows(const db_con_t* _h, db_res_t* _r) i++; rows = rows->next; } - db_unixodbc_list_destroy(rowstart); + + CON_DATA(_h) = rowstart ? rowstart : NULL; return 0; } diff --git a/modules/db_unixodbc/res.h b/modules/db_unixodbc/res.h index 64abb0d8a9c..ea5d93739dc 100644 --- a/modules/db_unixodbc/res.h +++ b/modules/db_unixodbc/res.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * UNIXODBC module result related functions * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * diff --git a/modules/db_unixodbc/row.c b/modules/db_unixodbc/row.c index 20101434ef7..a96373bf3c3 100644 --- a/modules/db_unixodbc/row.c +++ b/modules/db_unixodbc/row.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * UNIXODBC module row related functions @@ -40,7 +40,7 @@ /* * Convert a row from result into db API representation */ -int db_unixodbc_convert_row(const db_con_t* _h, const db_res_t* _res, +int db_unixodbc_convert_row(const db_con_t* _h, const db_res_t* _res, db_row_t* _r, const unsigned long* lengths) { int i; diff --git a/modules/db_unixodbc/row.h b/modules/db_unixodbc/row.h index f5e1348ff99..1b88ff33225 100644 --- a/modules/db_unixodbc/row.h +++ b/modules/db_unixodbc/row.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * UNIXODBC module row related functions * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * diff --git a/modules/db_unixodbc/val.c b/modules/db_unixodbc/val.c index 48bb2a36d8b..5fb9d48c7bc 100644 --- a/modules/db_unixodbc/val.c +++ b/modules/db_unixodbc/val.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * UNIXODBC module * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * diff --git a/modules/db_unixodbc/val.h b/modules/db_unixodbc/val.h index 6cef8a921a0..6f086f0454c 100644 --- a/modules/db_unixodbc/val.h +++ b/modules/db_unixodbc/val.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * UNIXODBC module * @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * diff --git a/modules/db_virtual/README b/modules/db_virtual/README index 06c4d054945..096afbccf93 100644 --- a/modules/db_virtual/README +++ b/modules/db_virtual/README @@ -12,8 +12,7 @@ Razvan Pistolea Copyright © 2009 Voice Sistem SRL Revision History - Revision $Revision: 5917 $ $Date: 2009-07-29 19:12:14 +0300 - (Wed, 29 Jul 2009) $ + Revision $Revision: 5917 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/db_virtual/db_virtual.c b/modules/db_virtual/db_virtual.c index c6b9c63d281..ac25911ec7e 100644 --- a/modules/db_virtual/db_virtual.c +++ b/modules/db_virtual/db_virtual.c @@ -45,10 +45,10 @@ int db_probe_time = 10; /* max consecutive retries before give up */ -int db_max_consec_retrys = 10; +int db_max_consec_retrys = 10; /* for debug.. try_reconect with or without a timer process(probe) */ -int db_reconnect_with_timer = 1; +int db_reconnect_with_timer = 1; /* exactly once condition keeper */ /*char is_initialized = 0;*/ @@ -107,20 +107,32 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; -struct module_exports exports = { +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + +struct module_exports exports = { "db_virtual", + MOD_TYPE_SQLDB, /* class of this module */ MODULE_VERSION, - DEFAULT_DLFLAGS, /* dlopen flags */ + DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, - params, /* module parameters */ - 0, /* exported statistics */ - mi_cmds, /* exported MI functions */ - 0, /* exported pseudo-variables */ - 0, /* extra processes */ - virtual_mod_init, /* module initialization function */ - 0, /* response function*/ - (destroy_function) destroy, /* destroy function */ - 0 /* per-child init function */ + params, /* module parameters */ + 0, /* exported statistics */ + mi_cmds, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + virtual_mod_init, /* module initialization function */ + 0, /* response function*/ + destroy, /* destroy function */ + 0 /* per-child init function */ }; @@ -129,59 +141,37 @@ int add_url(int index, char * name){ LM_DBG("add url (%i . %s)\n", index, name); int i; - if(global->set_list[index].size){ - LM_DBG("add another url %p\n", global->set_list[index].db_list); - - /* realoc */ - i = global->set_list[index].size; - - /* db_list realloc */ - global->set_list[index].db_list = - (info_db_t *) shm_realloc(global->set_list[index].db_list, - (i+1)* sizeof(info_db_t)); - global->set_list[index].size +=1; - - /* db_url */ - global->set_list[index].db_list[i].db_url.s = - (char *) shm_malloc(strlen(name) * sizeof(char)); - global->set_list[index].db_list[i].db_url.len = strlen(name); - memcpy(global->set_list[index].db_list[i].db_url.s, - name, strlen(name)); - - }else{ + LM_DBG("add another url %p\n", global->set_list[index].db_list); - LM_DBG("add first set url\n"); + /* realoc */ + i = global->set_list[index].size; - i=0; - /* alloc set_list index */ - global->set_list[index].db_list = - (info_db_t *) shm_malloc(1 * sizeof(info_db_t)); - if(!global->set_list[index].db_list) - MEM_ERR(MEM_SHM); + /* db_list realloc */ + global->set_list[index].db_list = + (info_db_t *) shm_realloc(global->set_list[index].db_list, + (i+1)* sizeof(info_db_t)); - memset(global->set_list[index].db_list, 0, sizeof(info_db_t)); + if(!global->set_list[index].db_list) + MEM_ERR(MEM_SHM); - global->set_list[index].size = 1; + global->set_list[index].size++; - /* alloc url name */ - global->set_list[index].db_list[0].db_url.s = - (char *) shm_malloc(strlen(name)*sizeof(char)); - global->set_list[index].db_list[0].db_url.len = strlen(name); - - memcpy(global->set_list[index].db_list[0].db_url.s, - name, strlen(name)); - } + /* db_url */ + global->set_list[index].db_list[i].db_url.s = + (char *) shm_malloc(strlen(name) * sizeof(char)); + global->set_list[index].db_list[i].db_url.len = strlen(name); + memcpy(global->set_list[index].db_list[i].db_url.s, + name, strlen(name)); global->set_list[index].db_list[i].flags = CAN_USE | MAY_USE; return 0; - error: +error: return 1; } int add_set(char * name, char * mode){ - int nmode = 0; @@ -194,75 +184,44 @@ int add_set(char * name, char * mode){ LM_DBG("add set=%s mode=%i\n", name, nmode); - if(global){ - LM_DBG("realloc\n"); - /* realoc set_list */ - int i = global->size; - global->set_list = (info_set_t *)shm_realloc(global->set_list, - (i+1)*sizeof(info_set_t)); - if(!global->set_list) - MEM_ERR(MEM_SHM); - - global->size +=1; - - global->set_list[i].set_name.s = - (char *) shm_malloc(strlen(name)*sizeof(char)); - global->set_list[i].set_name.len = strlen(name); - memcpy(global->set_list[i].set_name.s, name, strlen(name)); + if (!global) { + global = shm_malloc(sizeof *global); - /* set mode */ - global->set_list[i].set_mode = nmode; + if (!global) + MEM_ERR(MEM_SHM); - global->set_list[i].size = 0 ; + memset(global, 0, sizeof *global); + } + /* realloc set_list */ + int i = global->size; + global->set_list = (info_set_t *)shm_realloc(global->set_list, + (i+1)*sizeof(info_set_t)); + if(!global->set_list) + MEM_ERR(MEM_SHM); + memset(&global->set_list[i], 0, sizeof *global->set_list); - }else{ - LM_DBG("alloc %p %i\n", global, (int)sizeof(info_global_t)); - /* alloc global */ - LM_DBG("alloc %p\n", global); - global = (info_global_t *) shm_malloc (1 * sizeof(info_global_t)); - LM_DBG("alloc %p\n", global); - - if(!global) - MEM_ERR(MEM_SHM); + global->size++; - memset(global, 0, 1 * sizeof(info_global_t)); - LM_DBG("alloc done\n"); + global->set_list[i].set_name.s = + (char *) shm_malloc(strlen(name)*sizeof(char)); + global->set_list[i].set_name.len = strlen(name); + memcpy(global->set_list[i].set_name.s, name, strlen(name)); - /* alloc set array */ - global->set_list = (info_set_t *) shm_malloc (1 * sizeof(info_set_t)); - if(!global->set_list) - MEM_ERR(MEM_SHM); + /* set mode */ + global->set_list[i].set_mode = nmode; - memset(global->set_list, 0, 1 * sizeof(info_set_t)); - - /* set array size */ - global->size = 1; - - - /* alloc set name */ - global->set_list[0].set_name.s = - (char *) shm_malloc(strlen(name)*sizeof(char)); - global->set_list[0].set_name.len = strlen(name); - - memcpy(global->set_list[0].set_name.s, name, strlen(name)); - - /* set mode */ - global->set_list[0].set_mode = nmode; - - /* set size */ - global->set_list[0].size=0; - } + global->set_list[i].size = 0; return 0; - error: +error: return 1; } static int store_urls( modparam_t type, void* val){ - + db_urls_list[db_urls_count] = val; db_urls_count++; @@ -273,7 +232,7 @@ static int store_urls( modparam_t type, void* val){ int init_global(void){//str *info_set_mapping){ - + int i, j; char *s, *p; int count = -1; @@ -302,7 +261,7 @@ int init_global(void){//str *info_set_mapping){ add_url(count, s); } } - + } for(i = 0; i< global->size; i++) for(j=0; jset_list[i].size; j++){ @@ -338,7 +297,7 @@ int init_private_handles(void){ MEM_ERR(MEM_PKG); memset(private, 0, sizeof(handle_private_t)); - + private->size = global->size; private->hset_list = (handle_set_t*)pkg_malloc(private->size * sizeof(handle_set_t)); @@ -348,7 +307,7 @@ int init_private_handles(void){ memset(private->hset_list, 0, private->size * sizeof(handle_set_t)); return 0; - + error: return -1; } @@ -359,7 +318,7 @@ static void reconnect_timer(unsigned int ticks, void *data) int i,j; db_con_t * con; - + for(i=0; i < global-> size; i++){ for(j=0; j < global->set_list[i].size; j++){ /* if CAN DOWN */ @@ -425,10 +384,10 @@ int virtual_mod_init(void){ static void destroy(void){ - LM_NOTICE("destroy module bla bla...\n"); + LM_NOTICE("destroying module...\n"); int i, j; - + if(global){ if(global->set_list){ for(i=0; i< global->size; i++){ @@ -458,7 +417,7 @@ int db_virtual_bind_api(const str* mod, db_func_t *dbb) if(!global) if(virtual_mod_init()) return 1; - + if(dbb==NULL) return -1; @@ -471,7 +430,7 @@ int db_virtual_bind_api(const str* mod, db_func_t *dbb) s.s = strchr(mod->s, '/'); s.s +=2; - + for(i=0; i< global->size; i++){ if(strncmp(s.s, global->set_list[i].set_name.s, global->set_list[i].set_name.len) == 0) @@ -493,8 +452,8 @@ int db_virtual_bind_api(const str* mod, db_func_t *dbb) }else if(global->set_list[i].set_mode == ROUND){ dbb->cap &= DB_CAP_ROUND; } - - + + dbb->use_table = db_virtual_use_table; dbb->init = db_virtual_init; dbb->close = db_virtual_close; @@ -528,14 +487,15 @@ struct mi_root *db_get_info(struct mi_root *cmd, void *param){ char buf[MAX_BUF]; rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK)); - + if (rpl_tree==0) return 0; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; for(i=0; i < global->size; i++ ){ - node = add_mi_node_child(rpl, 0, MI_SSTR("SET"), 0, 0 ); + node = add_mi_node_child(rpl, MI_IS_ARRAY, MI_SSTR("SET"), 0, 0 ); if (node==0) goto error; @@ -565,7 +525,7 @@ struct mi_root *db_get_info(struct mi_root *cmd, void *param){ buf,strlen(buf)); if (attr==0) goto error; - + for(j=0; j< global->set_list[i].size; j++){ node2 = add_mi_node_child(node, 0, MI_SSTR("DB"), 0, 0); @@ -577,7 +537,7 @@ struct mi_root *db_get_info(struct mi_root *cmd, void *param){ if (attr==0) goto error; - attr = add_mi_attr(node2, 0, MI_SSTR("name"), + attr = add_mi_attr(node2, 0, MI_SSTR("name"), global->set_list[i].db_list[j].db_url.s, global->set_list[i].db_list[j].db_url.len); if (attr==0) @@ -608,7 +568,7 @@ struct mi_root *db_get_info(struct mi_root *cmd, void *param){ } return rpl_tree; - + error: LM_ERR("failed to add node\n"); free_mi_tree(rpl_tree); @@ -617,7 +577,7 @@ struct mi_root *db_get_info(struct mi_root *cmd, void *param){ struct mi_root* db_set_info(struct mi_root* cmd, void* param){ - + struct mi_node* node= NULL; @@ -632,7 +592,7 @@ struct mi_root* db_set_info(struct mi_root* cmd, void* param){ unsigned int nrecon = 0; int flags; - + // get index node = cmd->node.kids; @@ -728,11 +688,11 @@ struct mi_root* db_set_info(struct mi_root* cmd, void* param){ else flags &=NOT_MAY_USE; - - + + global->set_list[nindex1].db_list[nindex2].flags = flags; /* dont worry about race conditions */ - + return init_mi_tree( 200, MI_SSTR(MI_OK)); } diff --git a/modules/db_virtual/db_virtual.h b/modules/db_virtual/db_virtual.h index def1bc95edf..53fc66b8825 100644 --- a/modules/db_virtual/db_virtual.h +++ b/modules/db_virtual/db_virtual.h @@ -97,7 +97,7 @@ typedef struct info_db{ typedef struct info_set{ - + str set_name; /* name of the set; ex: set1, set2...*/ char set_mode; /* mode of the set: PARALLEL, FAILOVER, ... */ diff --git a/modules/db_virtual/dbase.c b/modules/db_virtual/dbase.c index f033025faab..8513201a1d1 100644 --- a/modules/db_virtual/dbase.c +++ b/modules/db_virtual/dbase.c @@ -51,7 +51,7 @@ dbb->last_inserted_id 0 0 dbb->insert_update 1 1 * - * Explanation: + * Explanation: * it makes sense to insert in multiple dbs * but not to query and fetch from multiple dbs. * @@ -101,7 +101,7 @@ void try_reconnect(handle_set_t * p){ int i; //handle_set_t * p = (handle_set_t*)_h->tail;//private_handles; - + for(i=0; i< global->set_list[p->set_index].size; i++){ if(!(p->con_list[i].flags & CAN_USE) && global->set_list[p->set_index].db_list[i].flags & CAN_USE){ @@ -272,9 +272,9 @@ do{ db_con_t* db_virtual_init(const str* _set_url) { /* - find set_url in globla state + find set_url in global state get index - alocate + allocate populate with db_init */ LM_DBG("INIT set_name, %.*s\n", _set_url->len, _set_url->s); @@ -285,7 +285,7 @@ db_con_t* db_virtual_init(const str* _set_url) char buffer[256]; char * token; handle_set_t* p; - + if(!_set_url || !_set_url->s){ LM_ERR("url or url.s NULL\n"); return NULL; @@ -303,7 +303,7 @@ db_con_t* db_virtual_init(const str* _set_url) return NULL; } - + /* find set_name in global */ memset(buffer, 0, 256); @@ -328,7 +328,7 @@ db_con_t* db_virtual_init(const str* _set_url) return NULL; } - + p = &private->hset_list[index]; /* alocat res */ @@ -446,7 +446,7 @@ int db_virtual_use_table(db_con_t* _h, const str* _t) memcpy(use_table.s, _t->s, _t->len); - + return rc2; } diff --git a/modules/db_virtual/dbase.h b/modules/db_virtual/dbase.h index 9897d78506a..47b5efeb558 100644 --- a/modules/db_virtual/dbase.h +++ b/modules/db_virtual/dbase.h @@ -102,15 +102,15 @@ typedef struct handle_con { typedef struct handle_set { /* index in the info_global list; used for the 1 to 1 relationship */ - int set_index; + int set_index; /* index in con_list; used for FAILOVER and ROUNDROBIN mode */ - int curent_con; + int curent_con; handle_con_t* con_list; int size; /* used for exactly once call of real init() and close() */ - int refcount; + int refcount; } handle_set_t; diff --git a/modules/dialog/README b/modules/dialog/README index beeed6c2c14..c6cbaea04ff 100644 --- a/modules/dialog/README +++ b/modules/dialog/README @@ -12,8 +12,7 @@ Vladut-Stefan Paiu Copyright © 2006-2009 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-03-08 11:33:05 +0200 - (Thu, 08 Mar 2012) $ + Revision $Revision: 8771 $ $Date$ __________________________________________________________ Table of Contents @@ -23,104 +22,119 @@ Vladut-Stefan Paiu 1.1. Overview 1.2. How it works 1.3. Dialog profiling - 1.4. Dependencies - - 1.4.1. OpenSIPS Modules - 1.4.2. External Libraries or Applications - - 1.5. Exported Parameters - - 1.5.1. enable_stats (integer) - 1.5.2. hash_size (integer) - 1.5.3. log_profile_hash_size (integer) - 1.5.4. rr_param (string) - 1.5.5. timeout_avp (string) - 1.5.6. default_timeout (integer) - 1.5.7. dlg_extra_hdrs (string) - 1.5.8. dlg_match_mode (integer) - 1.5.9. db_url (string) - 1.5.10. db_mode (integer) - 1.5.11. db_update_period (integer) - 1.5.12. ping_interval (integer) - 1.5.13. table_name (string) - 1.5.14. callid_column (string) - 1.5.15. from_uri_column (string) - 1.5.16. from_tag_column (string) - 1.5.17. to_uri_column (string) - 1.5.18. to_tag_column (string) - 1.5.19. caller_cseq_column (string) - 1.5.20. callee_cseq_column (string) - 1.5.21. caller_route_column (string) - 1.5.22. callee_route_column (string) - 1.5.23. caller_contact_column (string) - 1.5.24. callee_contact_column (string) - 1.5.25. caller_sock_column (string) - 1.5.26. callee_sock_column (string) - 1.5.27. dlg_id_column (string) - 1.5.28. state_column (string) - 1.5.29. start_time_column (string) - 1.5.30. timeout_column (string) - 1.5.31. profiles_column (string) - 1.5.32. vars_column (string) - 1.5.33. sflags_column (string) - 1.5.34. profiles_with_value (string) - 1.5.35. profiles_no_value (string) - 1.5.36. db_flush_vals_profiles (int) - 1.5.37. own_timer_proc (int) - 1.5.38. timer_bulk_del_no (int) - 1.5.39. cachedb_url (string) - 1.5.40. profile_value_prefix (string) - 1.5.41. profile_no_value_prefix (string) - 1.5.42. profile_size_prefix (string) - 1.5.43. profile_timeout (int) - - 1.6. Exported Functions - - 1.6.1. create_dialog() - 1.6.2. match_dialog() - 1.6.3. validate_dialog() - 1.6.4. fix_route_dialog() - 1.6.5. get_dialog_info(attr,var,key,key_val) - 1.6.6. set_dlg_profile(profile,[value]) - 1.6.7. unset_dlg_profile(profile,[value]) - 1.6.8. is_in_profile(profile,[value]) - 1.6.9. get_profile_size(profile,[value],size) - 1.6.10. set_dlg_flag(idx) - 1.6.11. test_and_set_dlg_flag(idx, value) - 1.6.12. reset_dlg_flag(idx) - 1.6.13. is_dlg_flag_set(idx) - 1.6.14. store_dlg_value(name,val) - 1.6.15. fetch_dlg_value(name,pvar) - 1.6.16. topology_hiding() - - 1.7. Exported statistics - - 1.7.1. active_dialogs - 1.7.2. early_dialogs - 1.7.3. processed_dialogs - 1.7.4. expired_dialogs - 1.7.5. failed_dialogs - - 1.8. Exported MI Functions - - 1.8.1. dlg_list - 1.8.2. dlg_list_ctx - 1.8.3. dlg_end_dlg - 1.8.4. profile_get_size - 1.8.5. profile_list_dlgs - 1.8.6. profile_get_values - 1.8.7. dlg_db_sync - 1.8.8. list_all_profiles - - 1.9. Exported pseudo-variables - - 1.9.1. $DLG_count - 1.9.2. $DLG_status - 1.9.3. $DLG_lifetime - 1.9.4. $DLG_flags - 1.9.5. $DLG_dir - 1.9.6. $DLG_did - 1.9.7. $dlg_val(name) + 1.4. Dialog replication + 1.5. Dependencies + + 1.5.1. OpenSIPS Modules + 1.5.2. External Libraries or Applications + + 1.6. Exported Parameters + + 1.6.1. enable_stats (integer) + 1.6.2. hash_size (integer) + 1.6.3. log_profile_hash_size (integer) + 1.6.4. rr_param (string) + 1.6.5. default_timeout (integer) + 1.6.6. dlg_extra_hdrs (string) + 1.6.7. dlg_match_mode (integer) + 1.6.8. db_url (string) + 1.6.9. db_mode (integer) + 1.6.10. db_update_period (integer) + 1.6.11. ping_interval (integer) + 1.6.12. table_name (string) + 1.6.13. callid_column (string) + 1.6.14. from_uri_column (string) + 1.6.15. from_tag_column (string) + 1.6.16. to_uri_column (string) + 1.6.17. to_tag_column (string) + 1.6.18. caller_cseq_column (string) + 1.6.19. callee_cseq_column (string) + 1.6.20. caller_route_column (string) + 1.6.21. callee_route_column (string) + 1.6.22. caller_contact_column (string) + 1.6.23. callee_contact_column (string) + 1.6.24. caller_sock_column (string) + 1.6.25. callee_sock_column (string) + 1.6.26. dlg_id_column (string) + 1.6.27. state_column (string) + 1.6.28. start_time_column (string) + 1.6.29. timeout_column (string) + 1.6.30. profiles_column (string) + 1.6.31. vars_column (string) + 1.6.32. sflags_column (string) + 1.6.33. profiles_with_value (string) + 1.6.34. profiles_no_value (string) + 1.6.35. db_flush_vals_profiles (int) + 1.6.36. own_timer_proc (int) + 1.6.37. timer_bulk_del_no (int) + 1.6.38. cachedb_url (string) + 1.6.39. profile_value_prefix (string) + 1.6.40. profile_no_value_prefix (string) + 1.6.41. profile_size_prefix (string) + 1.6.42. profile_timeout (int) + 1.6.43. accept_replicated_dialogs (int) + 1.6.44. replicate_dialogs_to (string) + 1.6.45. th_callid_passwd (string) + 1.6.46. th_callid_prefix (string) + 1.6.47. th_passed_contact_params (string) + + 1.7. Exported Functions + + 1.7.1. create_dialog() + 1.7.2. match_dialog() + 1.7.3. validate_dialog() + 1.7.4. fix_route_dialog() + 1.7.5. get_dialog_info(attr,var,key,key_val) + 1.7.6. set_dlg_profile(profile,[value]) + 1.7.7. unset_dlg_profile(profile,[value]) + 1.7.8. is_in_profile(profile,[value]) + 1.7.9. get_profile_size(profile,[value],size) + 1.7.10. set_dlg_flag(idx) + 1.7.11. test_and_set_dlg_flag(idx, value) + 1.7.12. reset_dlg_flag(idx) + 1.7.13. is_dlg_flag_set(idx) + 1.7.14. store_dlg_value(name,val) + 1.7.15. fetch_dlg_value(name,pvar) + 1.7.16. topology_hiding() + + 1.8. Exported statistics + + 1.8.1. active_dialogs + 1.8.2. early_dialogs + 1.8.3. processed_dialogs + 1.8.4. expired_dialogs + 1.8.5. failed_dialogs + 1.8.6. create_sent + 1.8.7. update_sent + 1.8.8. delete_sent + 1.8.9. create_recv + 1.8.10. update_recv + 1.8.11. delete_recv + + 1.9. Exported MI Functions + + 1.9.1. dlg_list + 1.9.2. dlg_list_ctx + 1.9.3. dlg_end_dlg + 1.9.4. profile_get_size + 1.9.5. profile_list_dlgs + 1.9.6. profile_get_values + 1.9.7. dlg_db_sync + 1.9.8. dlg_restore_db + 1.9.9. list_all_profiles + + 1.10. Exported pseudo-variables + + 1.10.1. $DLG_count + 1.10.2. $DLG_status + 1.10.3. $DLG_lifetime + 1.10.4. $DLG_flags + 1.10.5. $DLG_dir + 1.10.6. $DLG_did + 1.10.7. $DLG_end_reason + 1.10.8. $DLG_timeout + 1.10.9. $DLG_callee_callid + 1.10.10. $dlg_val(name) 2. Developer Guide @@ -137,62 +151,66 @@ Vladut-Stefan Paiu 1.2. Set hash_size parameter 1.3. Set hash_size parameter 1.4. Set rr_param parameter - 1.5. Set timeout_avp parameter - 1.6. Set default_timeout parameter - 1.7. Set dlf_extra_hdrs parameter - 1.8. Set dlg_match_mode parameter - 1.9. Set db_url parameter - 1.10. Set db_mode parameter - 1.11. Set db_update_period parameter - 1.12. Set ping_interval parameter - 1.13. Set table_name parameter - 1.14. Set callid_column parameter - 1.15. Set from_uri_column parameter - 1.16. Set from_tag_column parameter - 1.17. Set to_uri_column parameter - 1.18. Set to_tag_column parameter - 1.19. Set caller_cseq_column parameter - 1.20. Set callee_cseq_column parameter - 1.21. Set caller_route_column parameter - 1.22. Set to_route_column parameter - 1.23. Set caller_contact_column parameter - 1.24. Set callee_contact_column parameter - 1.25. Set caller_sock_column parameter - 1.26. Set callee_sock_column parameter - 1.27. Set dlg_id_column parameter - 1.28. Set state_column parameter - 1.29. Set start_time_column parameter - 1.30. Set timeout_column parameter - 1.31. Set profiles_column parameter - 1.32. Set vars_column parameter - 1.33. Set sflags_column parameter - 1.34. Set profiles_with_value parameter - 1.35. Set profiles_no_value parameter - 1.36. Set db_flush_vals_profiles parameter - 1.37. Set own_timer_proc parameter - 1.38. Set timer_bulk_del_no parameter - 1.39. Set cachedb_url parameter - 1.40. Set profile_value_prefix parameter - 1.41. Set profile_no_value_prefix parameter - 1.42. Set profile_size_prefix parameter - 1.43. Set profile_timeout parameter - 1.44. create_dialog() usage - 1.45. match_dialog() usage - 1.46. validate_dialog() usage - 1.47. fix_route_dialog() usage - 1.48. get_dialog_info usage - 1.49. set_dlg_profile usage - 1.50. unset_dlg_profile usage - 1.51. is_in_profile usage - 1.52. get_profile_size usage - 1.53. set_dlg_flag usage - 1.54. test_and_set_dlg_flag usage - 1.55. reset_dlg_flag usage - 1.56. is_dlg_flag_set usage - 1.57. store_dlg_value usage - 1.58. fetch_dlg_value usage - 1.59. topology_hiding usage - 1.60. calling match_dialog() function for topology hiding + 1.5. Set default_timeout parameter + 1.6. Set dlf_extra_hdrs parameter + 1.7. Set dlg_match_mode parameter + 1.8. Set db_url parameter + 1.9. Set db_mode parameter + 1.10. Set db_update_period parameter + 1.11. Set ping_interval parameter + 1.12. Set table_name parameter + 1.13. Set callid_column parameter + 1.14. Set from_uri_column parameter + 1.15. Set from_tag_column parameter + 1.16. Set to_uri_column parameter + 1.17. Set to_tag_column parameter + 1.18. Set caller_cseq_column parameter + 1.19. Set callee_cseq_column parameter + 1.20. Set caller_route_column parameter + 1.21. Set to_route_column parameter + 1.22. Set caller_contact_column parameter + 1.23. Set callee_contact_column parameter + 1.24. Set caller_sock_column parameter + 1.25. Set callee_sock_column parameter + 1.26. Set dlg_id_column parameter + 1.27. Set state_column parameter + 1.28. Set start_time_column parameter + 1.29. Set timeout_column parameter + 1.30. Set profiles_column parameter + 1.31. Set vars_column parameter + 1.32. Set sflags_column parameter + 1.33. Set profiles_with_value parameter + 1.34. Set profiles_no_value parameter + 1.35. Set db_flush_vals_profiles parameter + 1.36. Set own_timer_proc parameter + 1.37. Set timer_bulk_del_no parameter + 1.38. Set cachedb_url parameter + 1.39. Set profile_value_prefix parameter + 1.40. Set profile_no_value_prefix parameter + 1.41. Set profile_size_prefix parameter + 1.42. Set profile_timeout parameter + 1.43. Set accept_replicated_dialogs parameter + 1.44. Set replicate_dialogs_to parameter + 1.45. Set th_callid_passwd parameter + 1.46. Set th_callid_prefix parameter + 1.47. Set th_passed_contact_params parameter + 1.48. create_dialog() usage + 1.49. match_dialog() usage + 1.50. validate_dialog() usage + 1.51. fix_route_dialog() usage + 1.52. get_dialog_info usage + 1.53. set_dlg_profile usage + 1.54. unset_dlg_profile usage + 1.55. is_in_profile usage + 1.56. get_profile_size usage + 1.57. set_dlg_flag usage + 1.58. test_and_set_dlg_flag usage + 1.59. reset_dlg_flag usage + 1.60. is_dlg_flag_set usage + 1.61. store_dlg_value usage + 1.62. fetch_dlg_value usage + 1.63. topology_hiding usage + 1.64. calling match_dialog() function for topology hiding sequential requests Chapter 1. Admin Guide @@ -220,11 +238,9 @@ Chapter 1. Admin Guide The dialog is automatically destroyed when a “BYE” is received. In case of no “BYE”, the dialog lifetime is controlled via the - default timeout (see “default_timeout” - Section 1.5.6, + default timeout (see “default_timeout” - Section 1.6.5, “default_timeout (integer)”) and custom timeout (see - “timeout_avp” - Section 1.5.5, “timeout_avp (string)”). The - dialog timeout is reset each time a sequential (except ACKs) - request passes. + “$DLG_timeout” - Section 1.10.8, “$DLG_timeout”). 1.3. Dialog profiling @@ -261,23 +277,44 @@ Chapter 1. Admin Guide the name of the profile in the profiles_with_value or profiles_no_value parameters. -1.4. Dependencies +1.4. Dialog replication -1.4.1. OpenSIPS Modules + Dialog replication is a mechanism used to mirror all dialog + changes taking place in one OpenSIPS instance to one or more + other different instances. The logic is simplified by using the + core Binary Internal Interface to build and send the + replication-related UDP packets. + + The feature is especially useful when dealing with very large + systems, where failover through a database backend is no longer + feasible, due to the high amount of time required for the + backup instance to load the dialog information stored in a + typical dialog table by the crashed instance. + + Configuring both receival and sending of dialog replication + packets is trivial and can be done by using the + accept_replicated_dialogs and replicate_dialogs_to parameters + of the module. In addition to this, the module also exports + several statistics regarding the number of replication packets + sent/received. + +1.5. Dependencies + +1.5.1. OpenSIPS Modules The following modules must be loaded before this module: * TM - Transaction module * RR - Record-Route module -1.4.2. External Libraries or Applications +1.5.2. External Libraries or Applications The following libraries or applications must be installed before running OpenSIPS with this module loaded: * None. -1.5. Exported Parameters +1.6. Exported Parameters -1.5.1. enable_stats (integer) +1.6.1. enable_stats (integer) If the statistics support should be enabled or not. Via statistic variables, the module provide information about the @@ -291,7 +328,7 @@ Chapter 1. Admin Guide modparam("dialog", "enable_stats", 0) ... -1.5.2. hash_size (integer) +1.6.2. hash_size (integer) The size of the hash table internally used to keep the dialogs. A larger table is much faster but consumes more memory. The @@ -310,7 +347,7 @@ modparam("dialog", "enable_stats", 0) modparam("dialog", "hash_size", 1024) ... -1.5.3. log_profile_hash_size (integer) +1.6.3. log_profile_hash_size (integer) The size of the hash table internally used to store profile->dialog associations. A larger table can provide more @@ -325,7 +362,7 @@ modparam("dialog", "hash_size", 1024) modparam("dialog", "log_profile_hash_size", 5) #set a table size of 32 ... -1.5.4. rr_param (string) +1.6.4. rr_param (string) Name of the Record-Route parameter to be added with the dialog cookie. It is used for fast dialog matching of the sequential @@ -338,34 +375,19 @@ modparam("dialog", "log_profile_hash_size", 5) #set a table size of 32 modparam("dialog", "rr_param", "xyz") ... -1.5.5. timeout_avp (string) - - The specification of an AVP to contain a custom timeout (in - seconds) for the dialog. It may be used only in a request - (initial or sequential) context. - - Default value is “none”. - - Example 1.5. Set timeout_avp parameter -... -modparam("dialog", "timeout_avp", "$avp(10)") -... - - Make sure you call this before loose_route(). - -1.5.6. default_timeout (integer) +1.6.5. default_timeout (integer) The default dialog timeout (in seconds) if no custom one is set. Default value is “43200 (12 hours)”. - Example 1.6. Set default_timeout parameter + Example 1.5. Set default_timeout parameter ... modparam("dialog", "default_timeout", 21600) ... -1.5.7. dlg_extra_hdrs (string) +1.6.6. dlg_extra_hdrs (string) A string containing the extra headers (full format, with EOH) to be added in the requests generated by the module (like @@ -373,12 +395,12 @@ modparam("dialog", "default_timeout", 21600) Default value is “NULL”. - Example 1.7. Set dlf_extra_hdrs parameter + Example 1.6. Set dlf_extra_hdrs parameter ... modparam("dialog", "dlg_extra_hdrs", "Hint: credit expired\r\n") ... -1.5.8. dlg_match_mode (integer) +1.6.7. dlg_match_mode (integer) How the seqential requests should be matched against the known dialogs. The modes are a combination between matching based on @@ -394,12 +416,12 @@ modparam("dialog", "dlg_extra_hdrs", "Hint: credit expired\r\n") Default value is “0 (DID_ONLY)”. - Example 1.8. Set dlg_match_mode parameter + Example 1.7. Set dlg_match_mode parameter ... modparam("dialog", "dlg_match_mode", 1) ... -1.5.9. db_url (string) +1.6.8. db_url (string) If you want to store the information about the dialogs in a database a database url must be specified. @@ -407,13 +429,13 @@ modparam("dialog", "dlg_match_mode", 1) Default value is “mysql://opensips:opensipsrw@localhost/opensips”. - Example 1.9. Set db_url parameter + Example 1.8. Set db_url parameter ... modparam("dialog", "db_url", "dbdriver://username:password@dbhost/dbname ") ... -1.5.10. db_mode (integer) +1.6.9. db_mode (integer) Describe how to push into the DB the dialogs' information from memory. @@ -421,319 +443,319 @@ modparam("dialog", "db_url", "dbdriver://username:password@dbhost/dbname The supported modes are: * 0 - NO_DB - the memory content is not flushed into DB; * 1 - REALTIME - any dialog information changes will be - reflected into the database immediatly. + reflected into the database immediately. * 2 - DELAYED - the dialog information changes will be - flushed into DB periodically, based on a timre routine. + flushed into the DB periodically, based on a timer routine. * 3 - SHUTDOWN - the dialog information will be flushed into DB only at shutdown - no runtime updates. Default value is “0”. - Example 1.10. Set db_mode parameter + Example 1.9. Set db_mode parameter ... modparam("dialog", "db_mode", 1) ... -1.5.11. db_update_period (integer) +1.6.10. db_update_period (integer) The interval (seconds) at which to update dialogs' information if you chose to store the dialogs' info at a given interval. A - too short interval will generate intensiv database operations, + too short interval will generate intensive database operations, a too large one will not notice short dialogs. Default value is “60”. - Example 1.11. Set db_update_period parameter + Example 1.10. Set db_update_period parameter ... modparam("dialog", "db_update_period", 120) ... -1.5.12. ping_interval (integer) +1.6.11. ping_interval (integer) The interval (seconds) at which OpenSIPS will generate in-dialog pings for dialogs. Default value is “30”. - Example 1.12. Set ping_interval parameter + Example 1.11. Set ping_interval parameter ... modparam("dialog", "ping_interval", 20) ... -1.5.13. table_name (string) +1.6.12. table_name (string) If you want to store the information about the dialogs in a database a table name must be specified. Default value is “dialog”. - Example 1.13. Set table_name parameter + Example 1.12. Set table_name parameter ... modparam("dialog", "table_name", "my_dialog") ... -1.5.14. callid_column (string) +1.6.13. callid_column (string) The column's name in the database to store the dialogs' callid. Default value is “callid”. - Example 1.14. Set callid_column parameter + Example 1.13. Set callid_column parameter ... modparam("dialog", "callid_column", "callid_c_name") ... -1.5.15. from_uri_column (string) +1.6.14. from_uri_column (string) The column's name in the database to store the caller's sip address. Default value is “from_uri”. - Example 1.15. Set from_uri_column parameter + Example 1.14. Set from_uri_column parameter ... modparam("dialog", "from_uri_column", "from_uri_c_name") ... -1.5.16. from_tag_column (string) +1.6.15. from_tag_column (string) The column's name in the database to store the From tag from the Invite request. Default value is “from_tag”. - Example 1.16. Set from_tag_column parameter + Example 1.15. Set from_tag_column parameter ... modparam("dialog", "from_tag_column", "from_tag_c_name") ... -1.5.17. to_uri_column (string) +1.6.16. to_uri_column (string) The column's name in the database to store the calee's sip address. Default value is “to_uri”. - Example 1.17. Set to_uri_column parameter + Example 1.16. Set to_uri_column parameter ... modparam("dialog", "to_uri_column", "to_uri_c_name") ... -1.5.18. to_tag_column (string) +1.6.17. to_tag_column (string) The column's name in the database to store the To tag from the 200 OK response to the Invite request, if present. Default value is “to_tag”. - Example 1.18. Set to_tag_column parameter + Example 1.17. Set to_tag_column parameter ... modparam("dialog", "to_tag_column", "to_tag_c_name") ... -1.5.19. caller_cseq_column (string) +1.6.18. caller_cseq_column (string) The column's name in the database to store the cseq from caller side. Default value is “caller_cseq”. - Example 1.19. Set caller_cseq_column parameter + Example 1.18. Set caller_cseq_column parameter ... modparam("dialog", "caller_cseq_column", "column_name") ... -1.5.20. callee_cseq_column (string) +1.6.19. callee_cseq_column (string) The column's name in the database to store the cseq from callee side. Default value is “callee_cseq”. - Example 1.20. Set callee_cseq_column parameter + Example 1.19. Set callee_cseq_column parameter ... modparam("dialog", "callee_cseq_column", "column_name") ... -1.5.21. caller_route_column (string) +1.6.20. caller_route_column (string) The column's name in the database to store the route records from caller side (proxy to caller). Default value is “caller_route_set”. - Example 1.21. Set caller_route_column parameter + Example 1.20. Set caller_route_column parameter ... modparam("dialog", "caller_route_column", "column_name") ... -1.5.22. callee_route_column (string) +1.6.21. callee_route_column (string) The column's name in the database to store the route records from callee side (proxy to callee). Default value is “callee_route_set”. - Example 1.22. Set to_route_column parameter + Example 1.21. Set to_route_column parameter ... modparam("dialog", "to_route_column", "column_name") ... -1.5.23. caller_contact_column (string) +1.6.22. caller_contact_column (string) The column's name in the database to store the caller's contact uri. Default value is “from_contact”. - Example 1.23. Set caller_contact_column parameter + Example 1.22. Set caller_contact_column parameter ... modparam("dialog", "caller_contact_column", "column_name") ... -1.5.24. callee_contact_column (string) +1.6.23. callee_contact_column (string) The column's name in the database to store the callee's contact uri. Default value is “callee_contact”. - Example 1.24. Set callee_contact_column parameter + Example 1.23. Set callee_contact_column parameter ... modparam("dialog", "callee_contact_column", "column_name") ... -1.5.25. caller_sock_column (string) +1.6.24. caller_sock_column (string) The column's name in the database to store the information about the local interface receiving the traffic from caller. Default value is “caller_sock”. - Example 1.25. Set caller_sock_column parameter + Example 1.24. Set caller_sock_column parameter ... modparam("dialog", "caller_sock_column", "column_name") ... -1.5.26. callee_sock_column (string) +1.6.25. callee_sock_column (string) The column's name in the database to store information about the local interface receiving the traffic from callee. Default value is “callee_contact”. - Example 1.26. Set callee_sock_column parameter + Example 1.25. Set callee_sock_column parameter ... modparam("dialog", "callee_sock_column", "column_name") ... -1.5.27. dlg_id_column (string) +1.6.26. dlg_id_column (string) The column's name in the database to store the dialogs' id information. Default value is “hash_id”. - Example 1.27. Set dlg_id_column parameter + Example 1.26. Set dlg_id_column parameter ... modparam("dialog", "dlg_id_column", "dlg_id_c_name") ... -1.5.28. state_column (string) +1.6.27. state_column (string) The column's name in the database to store the dialogs' state information. Default value is “state”. - Example 1.28. Set state_column parameter + Example 1.27. Set state_column parameter ... modparam("dialog", "state_column", "state_c_name") ... -1.5.29. start_time_column (string) +1.6.28. start_time_column (string) The column's name in the database to store the dialogs' start time information. Default value is “start_time”. - Example 1.29. Set start_time_column parameter + Example 1.28. Set start_time_column parameter ... modparam("dialog", "start_time_column", "start_time_c_name") ... -1.5.30. timeout_column (string) +1.6.29. timeout_column (string) The column's name in the database to store the dialogs' timeout. Default value is “timeout”. - Example 1.30. Set timeout_column parameter + Example 1.29. Set timeout_column parameter ... modparam("dialog", "timeout_column", "timeout_c_name") ... -1.5.31. profiles_column (string) +1.6.30. profiles_column (string) The column's name in the database to store the dialogs' profiles. Default value is “profiles”. - Example 1.31. Set profiles_column parameter + Example 1.30. Set profiles_column parameter ... modparam("dialog", "profiles_column", "profiles_c_name") ... -1.5.32. vars_column (string) +1.6.31. vars_column (string) The column's name in the database to store the dialogs' vars. Default value is “vars”. - Example 1.32. Set vars_column parameter + Example 1.31. Set vars_column parameter ... modparam("dialog", "vars_column", "vars_c_name") ... -1.5.33. sflags_column (string) +1.6.32. sflags_column (string) The column's name in the database to store the dialogs' script flags. Default value is “script_flags”. - Example 1.33. Set sflags_column parameter + Example 1.32. Set sflags_column parameter ... modparam("dialog", "sflags_column", "sflags_c_name") ... -1.5.34. profiles_with_value (string) +1.6.33. profiles_with_value (string) List of names for profiles with values. Default value is “empty”. - Example 1.34. Set profiles_with_value parameter + Example 1.33. Set profiles_with_value parameter ... modparam("dialog", "profiles_with_value", "caller ; my_profile; share/s" ) ... -1.5.35. profiles_no_value (string) +1.6.34. profiles_no_value (string) List of names for profiles without values. Default value is “empty”. - Example 1.35. Set profiles_no_value parameter + Example 1.34. Set profiles_no_value parameter ... modparam("dialog", "profiles_no_value", "inbound ; outbound ; shared/s") ... -1.5.36. db_flush_vals_profiles (int) +1.6.35. db_flush_vals_profiles (int) Pushes dialog values, profiles and flags into the database along with other dialog state information (see db_mode 1 and @@ -741,48 +763,48 @@ modparam("dialog", "profiles_no_value", "inbound ; outbound ; shared/s") Default value is “empty”. - Example 1.36. Set db_flush_vals_profiles parameter + Example 1.35. Set db_flush_vals_profiles parameter ... modparam("dialog", "db_flush_vals_profiles", 1) ... -1.5.37. own_timer_proc (int) +1.6.36. own_timer_proc (int) - Whether the dialog timer should be a sepparate process or if - the tasks should be done in the global timer process. + Whether the dialog timer should be a separate process or if the + tasks should be done in the global timer process. Default value is “0”, run the timer in the global process. - Example 1.37. Set own_timer_proc parameter + Example 1.36. Set own_timer_proc parameter ... -modparam("dialog", "dlg_id_column", 1) +modparam("dialog", "own_timer_proc", 1) ... -1.5.38. timer_bulk_del_no (int) +1.6.37. timer_bulk_del_no (int) The number of dialogs that should be attempted to be deleted at the same time ( a single query ) from the DB back-end. Default value is “1”. - Example 1.38. Set timer_bulk_del_no parameter + Example 1.37. Set timer_bulk_del_no parameter ... modparam("dialog", "timer_bulk_del_no", 10) ... -1.5.39. cachedb_url (string) +1.6.38. cachedb_url (string) Enables distributed dialog profiles and specifies the backend that should be used by the CacheDB interface. Default value is “empty”. - Example 1.39. Set cachedb_url parameter + Example 1.38. Set cachedb_url parameter ... modparam("dialog", "cachedb_url", "redis://127.0.0.1:6379") ... -1.5.40. profile_value_prefix (string) +1.6.39. profile_value_prefix (string) Specifies what prefix should be added to the profiles with value when they are inserted into CacheDB backed. This is only @@ -790,12 +812,12 @@ modparam("dialog", "cachedb_url", "redis://127.0.0.1:6379") Default value is “dlg_val_”. - Example 1.40. Set profile_value_prefix parameter + Example 1.39. Set profile_value_prefix parameter ... modparam("dialog", "profile_value_prefix", "dlgv_") ... -1.5.41. profile_no_value_prefix (string) +1.6.40. profile_no_value_prefix (string) Specifies what prefix should be added to the profiles without value when they are inserted into CacheDB backed. This is only @@ -803,12 +825,12 @@ modparam("dialog", "profile_value_prefix", "dlgv_") Default value is “dlg_noval_”. - Example 1.41. Set profile_no_value_prefix parameter + Example 1.40. Set profile_no_value_prefix parameter ... modparam("dialog", "profile_no_value_prefix", "dlgnv_") ... -1.5.42. profile_size_prefix (string) +1.6.41. profile_size_prefix (string) Specifies what prefix should be added to the entity that holds the profiles with value size in CacheDB backed. This is only @@ -816,27 +838,93 @@ modparam("dialog", "profile_no_value_prefix", "dlgnv_") Default value is “dlg_size_”. - Example 1.42. Set profile_size_prefix parameter + Example 1.41. Set profile_size_prefix parameter ... modparam("dialog", "profile_size_prefix", "dlgs_") ... -1.5.43. profile_timeout (int) +1.6.42. profile_timeout (int) - Specifies ho long a dialog profile should be kept in the + Specifies how long a dialog profile should be kept in the CacheDB until it expires. This is only used when distributed profiles are enabled. Default value is “86400”. - Example 1.43. Set profile_timeout parameter + Example 1.42. Set profile_timeout parameter ... modparam("dialog", "profile_timeout", "43200") ... -1.6. Exported Functions +1.6.43. accept_replicated_dialogs (int) + + Registers the dialog module to the OpenSIPS Binary Internal + Interface. + + Default value is 0 (not registered). + + Example 1.43. Set accept_replicated_dialogs parameter +... +modparam("dialog", "accept_replicated_dialogs", 1) +... + +1.6.44. replicate_dialogs_to (string) + + Adds a new dialog replication destination. The destination will + receive all dialog-related events (creation, updating and + deletion) over UDP, using the Binary Internal Interface. + + Default value is “null” (no replication destinations). + + Example 1.44. Set replicate_dialogs_to parameter +... +modparam("dialog", "replicate_dialogs_to", "10.0.0.150:5062") +... + +1.6.45. th_callid_passwd (string) + + The string password that will be used for encoding/decoding the + callid in case of topology_hiding with callid mangling. + + Default value is “"OpenSIPS"” + + Example 1.45. Set th_callid_passwd parameter +... +modparam("dialog", "th_callid_passwd", "my_topo_hiding_secret") +... + +1.6.46. th_callid_prefix (string) + + The prefix that will be used for detecting callids which have + been encoded by the dialog topology hiding. Make sure to change + this value in case your SIP path contains multiple OpenSIPS + boxes with topology hiding. + + Default value is “"DLGCH_"” + + Example 1.46. Set th_callid_prefix parameter +... +modparam("dialog", "th_callid_prefix", "MYCALLIDPREFIX_") +... + +1.6.47. th_passed_contact_params (string) + + List of semicolon-separated Contact URI parameters that will be + passed from one side to the other for topology hiding calls. To + be used when end-to-end functionality uses such Contact + parameters. + + Default value is “empty” - do not pass any parameters + + Example 1.47. Set th_passed_contact_params parameter +... +modparam("dialog", "th_passed_contact_params", "paramname1;myparam;custo +m_param") +... + +1.7. Exported Functions -1.6.1. create_dialog() +1.7.1. create_dialog() The function creats the dialog for the currently processed request. The request must be an initial request. Optionally,the @@ -854,7 +942,7 @@ modparam("dialog", "profile_timeout", "43200") This function can be used from REQUEST_ROUTE. - Example 1.44. create_dialog() usage + Example 1.48. create_dialog() usage ... create_dialog(); ... @@ -868,7 +956,7 @@ create_dialog("Pp"); create_dialog("B"); ... -1.6.2. match_dialog() +1.7.2. match_dialog() This function is to be used to match a sequential (in-dialog) request to an existing dialog. In other words, the function @@ -889,7 +977,7 @@ create_dialog("B"); This function can be used from REQUEST_ROUTE. - Example 1.45. match_dialog() usage + Example 1.49. match_dialog() usage ... if (has_totag()) { loose_route(); @@ -899,14 +987,14 @@ create_dialog("B"); } ... -1.6.3. validate_dialog() +1.7.3. validate_dialog() The function checks the current received requests against the dialog (internal data) it belongs to. Performing several tests, the function will help to detect the bogus injected in-dialog requests (like malicious BYEs). - The performed tests are related to CSEQ sequance checking and + The performed tests are related to CSEQ sequence checking and routing information checking (contact and route set). The function returns true if a dialog exists for the request @@ -919,7 +1007,7 @@ create_dialog("B"); This function can be used from REQUEST_ROUTE. - Example 1.46. validate_dialog() usage + Example 1.50. validate_dialog() usage ... if (has_totag()) { loose_route(); @@ -931,7 +1019,7 @@ create_dialog("B"); } ... -1.6.4. fix_route_dialog() +1.7.4. fix_route_dialog() The function forces an in dialog SIP message to contain the ruri, route headers and dst_uri, as specified by the internal @@ -941,7 +1029,7 @@ create_dialog("B"); This function can be used from REQUEST_ROUTE. - Example 1.47. fix_route_dialog() usage + Example 1.51. fix_route_dialog() usage ... if (has_totag()) { loose_route(); @@ -951,14 +1039,16 @@ create_dialog("B"); } ... -1.6.5. get_dialog_info(attr,var,key,key_val) +1.7.5. get_dialog_info(attr,var,key,key_val) - The function extracts a dialog value from another dialog - it - search through all existing (ongoing) dialogs for a dialog that - has a dialog variable named "key" with the value "key_val" (so - a dialog where $dlg_val(key)=="key_val") - once found, it - return in pvar "var" the value of the the dialog variable - "attr" from the found dialog. + The function extracts a dialog value from another dialog. It + first searches through all existing (ongoing) dialogs for a + dialog that has a dialog variable named "key" with the value + "key_val" (so a dialog where $dlg_val(key)=="key_val"). If + found, it returns the value of the dialog variable "attr" from + the found dialog in the "var" pseudo-variable, otherwise + nothing is written in "var", and a negative error code is + returned. NOTE: the function does not require to be called in the context of a dialog - you can use it whenever / whereever for searching @@ -977,7 +1067,7 @@ create_dialog("B"); This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE, FAILURE_ROUTE and LOCAL_ROUTE. - Example 1.48. get_dialog_info usage + Example 1.52. get_dialog_info usage ... if ( get_dialog_info("callee","$var(x)","caller","$fu") ) { xlog("caller $fU has another ongoing, talking to callee $var(x)\ @@ -991,12 +1081,12 @@ $dlg_val(caller) = $fu; $dlg_val(callee) = $ru; ... -1.6.6. set_dlg_profile(profile,[value]) +1.7.6. set_dlg_profile(profile,[value]) - Inserts the current dialog into a profile. Note that the - profile does not supports values, this will be silently - discarded. Also, there is no check for inserting the same - dialog in the same profile for multiple times. + Inserts the current dialog into a profile. Note that if the + profile does not support values, this will be silently + discarded. A dialog may be inserted in the same profile + multiple times. NOTE: the dialog must be created before using this function (use create_dialog() function before). @@ -1010,13 +1100,13 @@ $dlg_val(callee) = $ru; This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.49. set_dlg_profile usage + Example 1.53. set_dlg_profile usage ... set_dlg_profile("inbound_call"); set_dlg_profile("caller","$fu"); ... -1.6.7. unset_dlg_profile(profile,[value]) +1.7.7. unset_dlg_profile(profile,[value]) Removes the current dialog from a profile. @@ -1032,13 +1122,13 @@ set_dlg_profile("caller","$fu"); This function can be used from BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.50. unset_dlg_profile usage + Example 1.54. unset_dlg_profile usage ... unset_dlg_profile("inbound_call"); unset_dlg_profile("caller","$fu"); ... -1.6.8. is_in_profile(profile,[value]) +1.7.8. is_in_profile(profile,[value]) Checks if the current dialog belongs to a profile. If the profile supports values, the check can be reinforced to take @@ -1059,7 +1149,7 @@ unset_dlg_profile("caller","$fu"); This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.51. is_in_profile usage + Example 1.55. is_in_profile usage ... if (is_in_profile("inbound_call")) { log("this request belongs to a inbound call\n"); @@ -1070,7 +1160,7 @@ if (is_in_profile("caller","XX")) { } ... -1.6.9. get_profile_size(profile,[value],size) +1.7.9. get_profile_size(profile,[value],size) Returns the number of dialogs belonging to a profile. If the profile supports values, the check can be reinforced to take @@ -1090,7 +1180,7 @@ if (is_in_profile("caller","XX")) { This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.52. get_profile_size usage + Example 1.56. get_profile_size usage ... get_profile_size("inbound_call","$avp(size)"); xlog("currently there are $avp(size) inbound calls\n"); @@ -1099,7 +1189,7 @@ get_profile_size("caller","$fu"); xlog("currently, the user %fu has $avp(size) active outgoing calls\n"); ... -1.6.10. set_dlg_flag(idx) +1.7.10. set_dlg_flag(idx) Sets the dialog flag index idx to true. The dialog flags are dialog persistent and they can be accessed (set and test) for @@ -1113,12 +1203,12 @@ xlog("currently, the user %fu has $avp(size) active outgoing calls\n"); This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.53. set_dlg_flag usage + Example 1.57. set_dlg_flag usage ... set_dlg_flag("3"); ... -1.6.11. test_and_set_dlg_flag(idx, value) +1.7.11. test_and_set_dlg_flag(idx, value) Atomically checks if the dialog flag index idx is equal to value. If true, changes the value with the oppsosite one. This @@ -1134,12 +1224,12 @@ set_dlg_flag("3"); This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.54. test_and_set_dlg_flag usage + Example 1.58. test_and_set_dlg_flag usage ... test_and_set_dlg_flag("3", "0"); ... -1.6.12. reset_dlg_flag(idx) +1.7.12. reset_dlg_flag(idx) Resets the dialog flag index idx to false. The dialog flags are dialog persistent and they can be accessed (set and test) for @@ -1153,12 +1243,12 @@ test_and_set_dlg_flag("3", "0"); This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.55. reset_dlg_flag usage + Example 1.59. reset_dlg_flag usage ... reset_dlg_flag("16"); ... -1.6.13. is_dlg_flag_set(idx) +1.7.13. is_dlg_flag_set(idx) Returns true if the dialog flag index idx is set. The dialog flags are dialog persistent and they can be accessed (set and @@ -1172,14 +1262,14 @@ reset_dlg_flag("16"); This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.56. is_dlg_flag_set usage + Example 1.60. is_dlg_flag_set usage ... if (is_dlg_flag_set("16")) { xlog("dialog flag 16 is set\n"); } ... -1.6.14. store_dlg_value(name,val) +1.7.14. store_dlg_value(name,val) Attaches to the dialog the value val under the name name. The values attached to dialogs are dialog persistent and they can @@ -1197,15 +1287,15 @@ if (is_dlg_flag_set("16")) { This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.57. store_dlg_value usage + Example 1.61. store_dlg_value usage ... store_dlg_value("inv_src_ip","$si"); store_dlg_value("account type","prepaid"); # or -$dlg_val("account_type") = "prepaid"; +$dlg_val(account_type) = "prepaid"; ... -1.6.15. fetch_dlg_value(name,pvar) +1.7.15. fetch_dlg_value(name,pvar) Fetches from the dialog the value of attribute named name. The values attached to dialogs are dialog persistent and they can @@ -1223,15 +1313,15 @@ $dlg_val("account_type") = "prepaid"; This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE and FAILURE_ROUTE. - Example 1.58. fetch_dlg_value usage + Example 1.62. fetch_dlg_value usage ... fetch_dlg_value("inv_src_ip","$avp(2)"); fetch_dlg_value("account type","$var(account)"); # or -$var(account) = $dlg_val("account_type"); +$var(account) = $dlg_val(account_type); ... -1.6.16. topology_hiding() +1.7.16. topology_hiding() Dialog module can also do a small overhead topology hiding. By calling this function on an initial Invite, for the current @@ -1261,14 +1351,34 @@ $var(account) = $dlg_val("account_type"); modules functionalities: profiles, dialog variables, dialog timeouts, etc.. - Example 1.59. topology_hiding usage + Optionally,the function also receives a string parameter, which + holds string flags. Current options for the string flags are : + * U - Propagate the Username in the Contact header URI + * C - Encode the callid header + There are many cases where propagating the callid towards + the callee side is not a good idea, since sometimes the + callid contains the IP of the actual caller side, thus + revealing part of the network topology. + When using the "C" flag, the callid will be automatically + encoded / decoded, transparent for the script writer - + inside OpenSIPS (script,MI functions, etc ) all the + variables related to the callid will represent the callid + value for the caller side. If the callid for the callee + side is needed, refer to the $DLG_callee_callid pvar. + + Example 1.63. topology_hiding usage ... if(!has_totag() && is_method("INVITE")) { topology_hiding(); } +... +... +if(!has_totag() && is_method("INVITE")) { + topology_hiding("U"); +} ... - Example 1.60. calling match_dialog() function for topology + Example 1.64. calling match_dialog() function for topology hiding sequential requests ... if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE @@ -1282,35 +1392,65 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE } ... -1.7. Exported statistics +1.8. Exported statistics -1.7.1. active_dialogs +1.8.1. active_dialogs Returns the number of current active dialogs (may be confirmed or not). -1.7.2. early_dialogs +1.8.2. early_dialogs Returns the number of early dialogs. -1.7.3. processed_dialogs +1.8.3. processed_dialogs Returns the total number of processed dialogs (terminated, expired or active) from the startup. -1.7.4. expired_dialogs +1.8.4. expired_dialogs Returns the total number of expired dialogs from the startup. -1.7.5. failed_dialogs +1.8.5. failed_dialogs Returns the number of failed dialogs ( dialogs were never established due to whatever reasons - internal error, negative reply, cancelled, etc ) -1.8. Exported MI Functions +1.8.6. create_sent + + Returns the number of replicated dialog create requests send to + other OpenSIPS instances. + +1.8.7. update_sent + + Returns the number of replicated dialog update requests send to + other OpenSIPS instances. + +1.8.8. delete_sent + + Returns the number of replicated dialog delete requests send to + other OpenSIPS instances. + +1.8.9. create_recv + + Returns the number of dialog create events received from other + OpenSIPS instances. + +1.8.10. update_recv + + Returns the number of dialog update events received from other + OpenSIPS instances. + +1.8.11. delete_recv + + Returns the number of dialog delete events received from other + OpenSIPS instances. -1.8.1. dlg_list +1.9. Exported MI Functions + +1.9.1. dlg_list Lists the description of the dialogs (calls). If no paramter is given, all dialogs will be listed. If a dialog identifier is @@ -1344,11 +1484,13 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE 40 10 -1.8.2. dlg_list_ctx +1.9.2. dlg_list_ctx The same as the “dlg_list” but including in the dialog description the associated context from modules sitting on top - of the dialog module. + of the dialog module. This function also prints the dialog's + values. In case of binary values, the non-printable chars are + represented in hex (e.g. \x00) Name: dlg_list_ctx @@ -1358,7 +1500,7 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE :dlg_list_ctx:_reply_fifo_file_ _empty_line_ -1.8.3. dlg_end_dlg +1.9.3. dlg_end_dlg Terminates an ongoing dialog. If dialog is established, BYEs are sent in both directions. If dialog is in unconfirmed or @@ -1384,7 +1526,7 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE 56 _empty_line_ -1.8.4. profile_get_size +1.9.4. profile_get_size Returns the number of dialogs belonging to a profile. If the profile supports values, the check can be reinforced to take @@ -1405,7 +1547,7 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE inbound_calls _empty_line_ -1.8.5. profile_list_dlgs +1.9.5. profile_list_dlgs Lists all the dialogs belonging to a profile. If the profile supports values, the check can be reinforced to take into @@ -1428,7 +1570,7 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE inbound_calls _empty_line_ -1.8.6. profile_get_values +1.9.6. profile_get_values Lists all the values belonging to a profile along with their count. If the profile does not support values a total count @@ -1445,7 +1587,7 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE inbound_calls _empty_line_ -1.8.7. dlg_db_sync +1.9.7. dlg_db_sync Will synchronize the information about the dialogs from the database with the OpenSIPS internal memory. To be used mainly @@ -1460,7 +1602,21 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE :dlg_db_sync:_reply_fifo_file_ _empty_line_ -1.8.8. list_all_profiles +1.9.8. dlg_restore_db + + Restores the dialog table after a potential desynchronization + event. The table is truncated, then populated with CONFIRMED + dialogs from memory. + + Name: dlg_restore_db + + It takes no parameters + + MI FIFO Command Format: + :dlg_restore_db:_reply_fifo_file_ + _empty_line_ + +1.9.9. list_all_profiles Lists all the dialog profiles, along with 1 or 0 if the given profile has/does not have an associated value. @@ -1473,14 +1629,14 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE :list_all_profiles:_reply_fifo_file_ _empty_line_ -1.9. Exported pseudo-variables +1.10. Exported pseudo-variables -1.9.1. $DLG_count +1.10.1. $DLG_count Returns the number of current active dialogs (may be confirmed or not). -1.9.2. $DLG_status +1.10.2. $DLG_status Returns the status of the dialog corresponding to the processed sequential request. This PV will be available only for @@ -1496,7 +1652,7 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE * 4 - Confirmed by a final reply and ACK received. * 5 - Dialog ended. -1.9.3. $DLG_lifetime +1.10.3. $DLG_lifetime Returns the duration (in seconds) of the dialog corresponding to the processed sequential request. The duration is calculated @@ -1506,16 +1662,16 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE NULL will be returned if there is no dialog for the request. -1.9.4. $DLG_flags +1.10.4. $DLG_flags - Returns the dialog flags array (as a single interger value) of + Returns the dialog flags array (as a single integer value) of the dialog corresponding to the processed sequential request. This PV will be available only for sequential requests, after doing loose_route(). NULL will be returned if there is no dialog for the request. -1.9.5. $DLG_dir +1.10.5. $DLG_dir Returns the direction of the request in dialog (as "UPSTREAM" or "DOWNSTREAM" string) - to be used for sequential request. @@ -1524,7 +1680,7 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE NULL will be returned if there is no dialog for the request. -1.9.6. $DLG_did +1.10.6. $DLG_did Returns the id of the dialog corresponding to the processed sequential request. The output format is entry ':' id (as @@ -1534,7 +1690,46 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BYE|UPDATE NULL will be returned if there is no dialog for the request. -1.9.7. $dlg_val(name) +1.10.7. $DLG_end_reason + + Returns the reason for the dialog termination. It can be one of + the following : + * Upstream BYE - Callee has sent a BYE + * Downstream BYE - Caller has sent a BYE + * Lifetime Timeout - Dialog lifetime expired + * MI Termination - Dialog ended via the MI interface + * Ping Timeout - Dialog ended because no reply to in-dialog + pings + * RTPProxy Timeout - Media timeout signaled by RTPProxy + + NULL will be returned if there is no dialog for the request, or + if the dialog is not ended in the current context. + +1.10.8. $DLG_timeout + + Used to set the dialog lifetime (in seconds). When read, the + variable returns the number of seconds until the dialog expires + and is destroyed. Note that reading the variable is only + possible after the dialog is created (for initial requests) or + after doing loose_route() (for sequential requests). Important + notice: using this variable with a REALTIME db_mode is very + inefficient, because every time the dialog value is changed, a + database update is done. + + NULL will be returned if there is no dialog for the request, + otherwise the number of seconds until the dialog expiration. + +1.10.9. $DLG_callee_callid + + Read only variable that will contain the callid as it is + propagated towards the callee side, in case + topology_hiding("C") is called. + + NULL will be returned if there is no dialog for the request or + if topology_hiding with callid encoding was not used for the + current dialog. + +1.10.10. $dlg_val(name) This is a read/write variable that allows access to the dialog attribute named name. This PV will be available only for @@ -1645,4 +1840,4 @@ Chapter 3. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/dialog/dialog.c b/modules/dialog/dialog.c index 2a9758a156d..f571b066ddb 100644 --- a/modules/dialog/dialog.c +++ b/modules/dialog/dialog.c @@ -17,22 +17,22 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2006-04-14 initial version (bogdan) * 2006-11-28 Added statistic support for the number of early and failed - * dialogs. (Jeffrey Magder - SOMA Networks) + * dialogs. (Jeffrey Magder - SOMA Networks) * 2007-04-30 added dialog matching without DID (dialog ID), but based only - * on RFC3261 elements - based on an original patch submitted + * on RFC3261 elements - based on an original patch submitted * by Michel Bensoussan (bogdan) * 2007-05-15 added saving dialogs' information to database (ancuta) - * 2007-07-04 added saving dialog cseq, contact, record route + * 2007-07-04 added saving dialog cseq, contact, record route * and bind_addresses(sock_info) for caller and callee (ancuta) - * 2008-04-14 added new type of callback to be triggered when dialogs are + * 2008-04-14 added new type of callback to be triggered when dialogs are * loaded from DB (bogdan) */ @@ -55,6 +55,8 @@ #include "../../mi/mi.h" #include "../tm/tm_load.h" #include "../rr/api.h" +#include "../../bin_interface.h" + #include "dlg_hash.h" #include "dlg_timer.h" #include "dlg_handlers.h" @@ -65,15 +67,16 @@ #include "dlg_profile.h" #include "dlg_vals.h" #include "dlg_tophiding.h" +#include "dlg_replication.h" static int mod_init(void); static int child_init(int rank); static void mod_destroy(void); /* module parameter */ -static int dlg_hash_size = 4096; int log_profile_hash_size = 4; -static char* rr_param = "did"; +str rr_param = {"did",3}; +static int dlg_hash_size = 4096; static str timeout_spec = {NULL, 0}; static int default_timeout = 60 * 60 * 12; /* 12 hours */ static int ping_interval = 30; /* seconds */ @@ -97,10 +100,15 @@ stat_var *processed_dlgs = 0; stat_var *expired_dlgs = 0; stat_var *failed_dlgs = 0; stat_var *early_dlgs = 0; +stat_var *create_sent = 0; +stat_var *update_sent = 0; +stat_var *delete_sent = 0; +stat_var *create_recv = 0; +stat_var *update_recv = 0; +stat_var *delete_recv = 0; struct tm_binds d_tmb; struct rr_binds d_rrb; -pv_spec_t timeout_avp; /* db stuff */ static str db_url = {NULL,0}; @@ -111,9 +119,20 @@ extern int last_dst_leg; /* cachedb stuff */ str cdb_url = {0,0}; +/* topo hiding */ +str topo_hiding_ct_params = {0,0}; +str topo_hiding_prefix = str_init("DLGCH_"); +str topo_hiding_seed = str_init("OpenSIPS"); + +/* dialog replication using the bpi interface */ +int accept_replicated_dlg=0; +struct replication_dest *replication_dests=NULL; + static int pv_get_dlg_count( struct sip_msg *msg, pv_param_t *param, pv_value_t *res); +static int add_replication_dest(modparam_t type, void *val); + /* commands wrappers and fixups */ static int fixup_profile(void** param, int param_no); static int fixup_get_profile2(void** param, int param_no); @@ -144,10 +163,15 @@ static int w_tsl_dlg_flag(struct sip_msg *msg, char *_idx, char *_val); int pv_get_dlg_lifetime(struct sip_msg *msg,pv_param_t *param,pv_value_t *res); int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); int pv_get_dlg_flags(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); +int pv_get_dlg_timeout(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); int pv_get_dlg_dir(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); int pv_get_dlg_did(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); +int pv_get_dlg_end_reason(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); int pv_set_dlg_flags(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val); +int pv_set_dlg_timeout(struct sip_msg *msg, pv_param_t *param, int op, + pv_value_t *val); +int pv_get_dlg_callee_callid(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); static cmd_export_t cmds[]={ {"create_dialog", (cmd_function)w_create_dialog, 0,NULL, @@ -201,6 +225,8 @@ static cmd_export_t cmds[]={ BRANCH_ROUTE | LOCAL_ROUTE }, {"topology_hiding",(cmd_function)w_topology_hiding,0,NULL, 0, REQUEST_ROUTE}, + {"topology_hiding",(cmd_function)w_topology_hiding1,1,fixup_create_dlg2, + 0, REQUEST_ROUTE}, {"match_dialog", (cmd_function)w_match_dialog, 0,NULL, 0, REQUEST_ROUTE}, {"load_dlg", (cmd_function)load_dlg, 0, 0, 0, 0}, @@ -211,8 +237,7 @@ static param_export_t mod_params[]={ { "enable_stats", INT_PARAM, &dlg_enable_stats }, { "hash_size", INT_PARAM, &dlg_hash_size }, { "log_profile_hash_size", INT_PARAM, &log_profile_hash_size }, - { "rr_param", STR_PARAM, &rr_param }, - { "timeout_avp", STR_PARAM, &timeout_spec.s }, + { "rr_param", STR_PARAM, &rr_param.s }, { "default_timeout", INT_PARAM, &default_timeout }, { "ping_interval", INT_PARAM, &ping_interval }, { "dlg_extra_hdrs", STR_PARAM, &dlg_extra_hdrs.s }, @@ -240,6 +265,7 @@ static param_export_t mod_params[]={ { "profiles_column", STR_PARAM, &profiles_column.s }, { "vars_column", STR_PARAM, &vars_column.s }, { "sflags_column", STR_PARAM, &sflags_column.s }, + { "mflags_column", STR_PARAM, &mflags_column.s }, { "db_update_period", INT_PARAM, &db_update_period }, { "profiles_with_value", STR_PARAM, &profiles_wv_s }, { "profiles_no_value", STR_PARAM, &profiles_nv_s }, @@ -252,6 +278,14 @@ static param_export_t mod_params[]={ { "profile_no_value_prefix", STR_PARAM, &cdb_noval_prefix.s }, { "profile_size_prefix", STR_PARAM, &cdb_size_prefix.s }, { "profile_timeout", INT_PARAM, &profile_timeout }, + /* dialog replication through UDP binary packets */ + { "accept_replicated_dialogs",INT_PARAM, &accept_replicated_dlg }, + { "replicate_dialogs_to", STR_PARAM|USE_FUNC_PARAM, + (void *)add_replication_dest }, + /* dialog topology hiding with callid mangling */ + { "th_callid_passwd", STR_PARAM, &topo_hiding_seed.s }, + { "th_callid_prefix",STR_PARAM, &topo_hiding_prefix.s }, + { "th_passed_contact_params",STR_PARAM, &topo_hiding_ct_params.s }, { 0,0,0 } }; @@ -262,6 +296,12 @@ static stat_export_t mod_stats[] = { {"processed_dialogs" , 0, &processed_dlgs }, {"expired_dialogs" , 0, &expired_dlgs }, {"failed_dialogs", 0, &failed_dlgs }, + {"create_sent", 0, &create_sent }, + {"update_sent", 0, &update_sent }, + {"delete_sent", 0, &delete_sent }, + {"create_recv", 0, &create_recv }, + {"update_recv", 0, &update_recv }, + {"delete_recv", 0, &delete_recv }, {0,0,0} }; @@ -271,6 +311,7 @@ static mi_export_t mi_cmds[] = { { "dlg_list_ctx", 0, mi_print_dlgs_ctx, 0, 0, 0}, { "dlg_end_dlg", 0, mi_terminate_dlg, 0, 0, 0}, { "dlg_db_sync", 0, mi_sync_db_dlg, 0, 0, 0}, + { "dlg_restore_db", 0, mi_restore_dlg_db, 0, 0, 0}, { "profile_get_size", 0, mi_get_profile, 0, 0, 0}, { "profile_list_dlgs", 0, mi_profile_list, 0, 0, 0}, { "profile_get_values", 0, mi_get_profile_values, 0, 0, 0}, @@ -294,13 +335,57 @@ static pv_export_t mod_items[] = { pv_set_dlg_val, pv_parse_name, 0, 0, 0}, { {"DLG_did", sizeof("DLG_did")-1}, 1000, pv_get_dlg_did, 0, 0, 0, 0, 0}, + { {"DLG_end_reason", sizeof("DLG_end_reason")-1}, 1000, + pv_get_dlg_end_reason,0,0, 0, 0, 0}, + { {"DLG_timeout", sizeof("DLG_timeout")-1}, 1000, + pv_get_dlg_timeout, pv_set_dlg_timeout, 0, 0, 0, 0 }, + { {"DLG_callee_callid", sizeof("DLG_callee_callid")-1}, 1000, + pv_get_dlg_callee_callid,0,0, 0, 0, 0}, { {0, 0}, 0, 0, 0, 0, 0, 0, 0 } }; +static module_dependency_t *get_deps_db_mode(param_export_t *param) +{ + int db_mode = *(int *)param->param_pointer; + + if (db_mode == DB_MODE_NONE || + (db_mode != DB_MODE_REALTIME && + db_mode != DB_MODE_DELAYED && + db_mode != DB_MODE_SHUTDOWN)) + return NULL; + + return alloc_module_dep(MOD_TYPE_SQLDB, NULL, DEP_ABORT); +} + +static module_dependency_t *get_deps_cachedb_url(param_export_t *param) +{ + char *cdb_url = *(char **)param->param_pointer; + + if (!cdb_url || strlen(cdb_url) == 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_CACHEDB, NULL, DEP_ABORT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "rr", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_mode", get_deps_db_mode }, + { "cachedb_url", get_deps_cachedb_url }, + { NULL, NULL }, + }, +}; + struct module_exports exports= { "dialog", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ mod_params, /* param exports */ mod_stats, /* exported statistics */ @@ -330,7 +415,7 @@ static int fixup_profile(void** param, int param_no) if (param_no==1) { profile = search_dlg_profile( &s ); if (profile==NULL) { - LM_CRIT("profile <%s> not definited\n",s.s); + LM_CRIT("profile <%s> not defined\n",s.s); return E_CFG; } pkg_free(*param); @@ -531,6 +616,16 @@ static int create_dialog_wrapper(struct sip_msg *req,int flags) return 1; } +static void set_mod_flag_wrapper (struct dlg_cell *dlg, unsigned int flags) +{ + dlg->mod_flags |= flags; +} + +static int is_mod_flag_set_wrapper (struct dlg_cell *dlg, unsigned int flags) +{ + return (dlg->mod_flags & flags) > 0; +} + int load_dlg( struct dlg_binds *dlgb ) { dlgb->register_dlgcb = register_dlgcb; @@ -544,6 +639,14 @@ int load_dlg( struct dlg_binds *dlgb ) dlgb->store_dlg_value = store_dlg_value; dlgb->fetch_dlg_value = fetch_dlg_value; dlgb->terminate_dlg = terminate_dlg; + + dlgb->match_dialog = w_match_dialog; + dlgb->fix_route_dialog = fix_route_dialog; + dlgb->validate_dialog = dlg_validate_dialog; + + dlgb->set_mod_flag = set_mod_flag_wrapper; + dlgb->is_mod_flag_set = is_mod_flag_set_wrapper; + return 1; } @@ -555,7 +658,7 @@ static int pv_get_dlg_count(struct sip_msg *msg, pv_param_t *param, int l; char *ch; - if(msg==NULL || res==NULL) + if(res==NULL) return -1; n = active_dlgs ? get_stat_val(active_dlgs) : 0; @@ -602,7 +705,14 @@ static int mod_init(void) profiles_column.len = strlen(profiles_column.s); vars_column.len = strlen(vars_column.s); sflags_column.len = strlen(sflags_column.s); + mflags_column.len = strlen(mflags_column.s); dialog_table_name.len = strlen(dialog_table_name.s); + topo_hiding_prefix.len = strlen(topo_hiding_prefix.s); + topo_hiding_seed.len = strlen(topo_hiding_seed.s); + if (topo_hiding_ct_params.s) { + topo_hiding_ct_params.len = strlen(topo_hiding_ct_params.s); + dlg_parse_passed_ct_params(&topo_hiding_ct_params); + } /* param checkings */ @@ -613,23 +723,16 @@ static int mod_init(void) return -1; } - if (rr_param==0 || rr_param[0]==0) { + if (rr_param.s==0 || rr_param.s[0]==0) { LM_ERR("empty rr_param!!\n"); return -1; - } else if (strlen(rr_param)>MAX_DLG_RR_PARAM_NAME) { + } + rr_param.len = strlen(rr_param.s); + if (rr_param.len>MAX_DLG_RR_PARAM_NAME) { LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME); return -1; } - if (timeout_spec.s) { - if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0 - && (timeout_avp.type!=PVT_AVP)){ - LM_ERR("malformed or non AVP timeout " - "AVP definition in '%.*s'\n", timeout_spec.len,timeout_spec.s); - return -1; - } - } - if (default_timeout<=0) { LM_ERR("0 default_timeout not accepted!!\n"); return -1; @@ -663,6 +766,10 @@ static int mod_init(void) LM_ERR("cannot init cachedb utils\n"); return -1; } + + cdb_val_prefix.len = strlen(cdb_val_prefix.s); + cdb_noval_prefix.len = strlen(cdb_noval_prefix.s); + cdb_size_prefix.len = strlen(cdb_size_prefix.s); } /* create profile hashes */ @@ -702,7 +809,13 @@ static int mod_init(void) } if (register_script_cb( dialog_cleanup, POST_SCRIPT_CB|REQ_TYPE_CB,0)<0) { - LM_ERR("cannot regsiter script callback"); + LM_ERR("cannot register script callback"); + return -1; + } + + if (accept_replicated_dlg && + bin_register_cb("dialog", receive_binary_packet) < 0) { + LM_ERR("Cannot register binary packet callback!\n"); return -1; } @@ -716,26 +829,25 @@ static int mod_init(void) } if (append_timer_to_process("dlg-pinger", dlg_ping_routine, NULL, ping_interval,dlg_own_timer_proc) < 0) { - LM_ERR("Failed to append ping timer \n"); + LM_ERR("Failed to append ping timer\n"); return -1; } } else { if ( register_timer( "dlg-timer", dlg_timer_routine, NULL, 1)<0 ) { - LM_ERR("failed to register timer \n"); + LM_ERR("failed to register timer\n"); return -1; } if ( register_timer( "dlg-pinger", dlg_ping_routine, NULL, ping_interval)<0) { - LM_ERR("failed to register timer 2 \n"); + LM_ERR("failed to register timer 2\n"); return -1; } } /* init handlers */ - init_dlg_handlers( rr_param, - timeout_spec.s?&timeout_avp:0, default_timeout); + init_dlg_handlers(default_timeout); /* init timer */ if (init_dlg_timer(dlg_ontimeout)!=0) { @@ -786,11 +898,20 @@ static int mod_init(void) run_load_callbacks(); } - /* if profiles should be kept in cachedb's */ - - destroy_dlg_callbacks( DLGCB_LOADED ); + mark_dlg_loaded_callbacks_run(); destroy_cachedb(0); + /* set dlg topo hiding callid mangling callbacks ( pre * post ) */ + if (register_raw_processing_cb(dlg_th_pre_raw,PRE_RAW_PROCESSING) < 0) { + LM_ERR("failed to initialize pre raw support\n"); + return -1; + } + + if (register_raw_processing_cb(dlg_th_post_raw,POST_RAW_PROCESSING) < 0) { + LM_ERR("failed to initialize post raw support\n"); + return -1; + } + return 0; } @@ -861,8 +982,7 @@ static int w_create_dialog2(struct sip_msg *req,char *param) { struct cell *t; str res = {0,0}; - int flags=0; - char *p; + int flags; if (fixup_get_svalue(req, (gparam_p)param, &res) !=0) { @@ -870,26 +990,7 @@ static int w_create_dialog2(struct sip_msg *req,char *param) return -1; } - for (p=res.s;pparsed_uri; - rr_param_len = strlen(rr_param); if (check_self(&r_uri->host,r_uri->port_no ? r_uri->port_no : SIP_PORT, 0) == 1 && msg->route == NULL) { /* Seems we are in the topo hiding case : * we are in the R-URI and there are no other route headers */ for (i=0;iu_params_no;i++) - if (r_uri->u_name[i].len == rr_param_len && - memcmp(rr_param,r_uri->u_name[i].s,rr_param_len)==0) { - LM_DBG("We found DID param in R-URI with value of %.*s \n", + if (r_uri->u_name[i].len == rr_param.len && + memcmp(rr_param.s,r_uri->u_name[i].s,rr_param.len)==0) { + LM_DBG("We found DID param in R-URI with value of %.*s\n", r_uri->u_val[i].len,r_uri->u_val[i].s); /* pass the param value to the matching funcs */ match_param = (void *)(&r_uri->u_val[i]); @@ -1005,19 +1105,19 @@ static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value) pve = (pv_elem_t *)value; if (((struct dlg_profile_table*)profile)->has_value) { - if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || + if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); return -1; } if ( set_dlg_profile( msg, &val_s, - (struct dlg_profile_table*)profile) < 0 ) { + (struct dlg_profile_table*)profile, 0) < 0 ) { LM_ERR("failed to set profile\n"); return -1; } } else { if ( set_dlg_profile( msg, NULL, - (struct dlg_profile_table*)profile) < 0 ) { + (struct dlg_profile_table*)profile, 0) < 0 ) { LM_ERR("failed to set profile\n"); return -1; } @@ -1034,7 +1134,7 @@ static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value) pve = (pv_elem_t *)value; if (((struct dlg_profile_table*)profile)->has_value) { - if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || + if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); return -1; @@ -1063,7 +1163,7 @@ static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value) pve = (pv_elem_t *)value; if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) { - if ( pv_printf_s(msg, pve, &val_s)!=0 || + if ( pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); return -1; @@ -1077,7 +1177,7 @@ static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value) } -static int w_get_profile_size(struct sip_msg *msg, char *profile, +static int w_get_profile_size(struct sip_msg *msg, char *profile, char *value, char *result) { pv_elem_t *pve; @@ -1093,7 +1193,7 @@ static int w_get_profile_size(struct sip_msg *msg, char *profile, sp_dest = (pv_spec_t *)result; if ( pve!=NULL && ((struct dlg_profile_table*)profile)->has_value) { - if ( pv_printf_s(msg, pve, &val_s)!=0 || + if ( pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); return -1; @@ -1195,7 +1295,7 @@ int w_store_dlg_value(struct sip_msg *msg, char *name, char *val) if ( (dlg=get_current_dialog())==NULL ) return -1; - if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || + if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); return -1; @@ -1273,7 +1373,7 @@ static int w_get_dlg_info(struct sip_msg *msg, char *attr, char *attr_val, str val_s; int n; - if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || + if ( pve==NULL || pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); return -1; @@ -1313,7 +1413,7 @@ int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param, char *ch = NULL; struct dlg_cell *dlg; - if(msg==NULL || res==NULL) + if(res==NULL) return -1; if ( (dlg=get_current_dialog())==NULL ) @@ -1338,7 +1438,7 @@ int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param, char *ch = NULL; struct dlg_cell *dlg; - if(msg==NULL || res==NULL) + if(res==NULL) return -1; if ( (dlg=get_current_dialog())==NULL ) @@ -1363,7 +1463,7 @@ int pv_get_dlg_flags(struct sip_msg *msg, pv_param_t *param, char *ch = NULL; struct dlg_cell *dlg; - if(msg==NULL || res==NULL) + if(res==NULL) return -1; if ( (dlg=get_current_dialog())==NULL ) @@ -1381,12 +1481,48 @@ int pv_get_dlg_flags(struct sip_msg *msg, pv_param_t *param, } +int pv_get_dlg_timeout(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res) +{ + int l = 0; + char *ch = NULL; + struct dlg_cell *dlg; + + if(res==NULL) + return -1; + + if ( (dlg=get_current_dialog())!=NULL ) { + + dlg_lock_dlg(dlg); + if (dlg->state < DLG_STATE_CONFIRMED_NA) + l = dlg->lifetime; + else + l = dlg->tl.timeout - get_ticks(); + dlg_unlock_dlg(dlg); + + } else if (msg->id == dlg_tmp_timeout_id && dlg_tmp_timeout != -1) { + l = dlg_tmp_timeout; + } else { + return pv_get_null( msg, param, res); + } + + res->ri = l; + + ch = int2str( (unsigned long)res->ri, &l); + res->rs.s = ch; + res->rs.len = l; + + res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT; + + return 0; +} + int pv_get_dlg_dir(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { struct dlg_cell *dlg; - if(msg==NULL || res==NULL) + if(res==NULL) return -1; if ( (dlg=get_current_dialog())==NULL || last_dst_leg<0) @@ -1413,7 +1549,7 @@ int pv_get_dlg_did(struct sip_msg *msg, pv_param_t *param, struct dlg_cell *dlg; str aux; - if(msg==NULL || res==NULL) + if(res==NULL) return -1; if ( (dlg=get_current_dialog())==NULL ) @@ -1445,6 +1581,23 @@ int pv_get_dlg_did(struct sip_msg *msg, pv_param_t *param, return 0; } +int pv_get_dlg_end_reason(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) +{ + struct dlg_cell *dlg; + + if(res==NULL) + return -1; + + if ( (dlg=get_current_dialog())==NULL || dlg->terminate_reason.s == NULL) { + return pv_get_null( msg, param, res); + } + + res->rs = dlg->terminate_reason; + res->flags = PV_VAL_STR; + + return 0; +} + int pv_set_dlg_flags(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) { @@ -1467,3 +1620,147 @@ int pv_set_dlg_flags(struct sip_msg *msg, pv_param_t *param, return 0; } + +int pv_set_dlg_timeout(struct sip_msg *msg, pv_param_t *param, + int op, pv_value_t *val) +{ + struct dlg_cell *dlg; + int timeout, db_update = 0, timer_update = 0; + + if (val==NULL || val->flags & PV_VAL_NULL) { + LM_ERR("cannot assign dialog timeout to NULL\n"); + return -1; + } + + if (!(val->flags&PV_VAL_INT)){ + /* try parsing the string */ + if (str2sint(&val->rs, &timeout) < 0) { + LM_ERR("assigning non-int value to dialog flags\n"); + return -1; + } + } else { + timeout = val->ri; + } + + if (timeout < 0) { + LM_ERR("cannot set a negative timeout\n"); + return -1; + } + if ((dlg = get_current_dialog()) != NULL) { + + dlg_lock_dlg(dlg); + dlg->lifetime = timeout; + /* update now only if realtime and the dialog is confirmed */ + if (dlg->state >= DLG_STATE_CONFIRMED && dlg_db_mode == DB_MODE_REALTIME) + db_update = 1; + else + dlg->flags |= DLG_FLAG_CHANGED; + if (dlg->state >= DLG_STATE_CONFIRMED_NA) + timer_update = 1; + dlg_unlock_dlg(dlg); + + if (db_update) + update_dialog_timeout_info(dlg); + + if (replication_dests) + replicate_dialog_updated(dlg); + + /* make sure we don't update it again later */ + dlg_tmp_timeout = -1; + dlg_tmp_timeout_id = -1; + + if (timer_update && update_dlg_timer(&dlg->tl, timeout) < 0) { + LM_ERR("failed to update timer\n"); + return -1; + } + } else { + /* store it until we match the dialog */ + dlg_tmp_timeout = timeout; + dlg_tmp_timeout_id = msg->id; + } + + return 0; +} + +static int add_replication_dest(modparam_t type, void *val) +{ + struct replication_dest *rd; + char *host; + int hlen, port; + int proto; + struct hostent *he; + str st; + + rd = pkg_malloc(sizeof(*rd)); + memset(rd, 0, sizeof(*rd)); + + if (parse_phostport(val, strlen(val), &host, &hlen, &port, &proto) < 0) { + LM_ERR("Bad replication destination IP!\n"); + return -1; + } + + if (proto == PROTO_NONE) + proto = PROTO_UDP; + + if (proto != PROTO_UDP) { + LM_ERR("Dialog replication only supports UDP packets!\n"); + return -1; + } + + st.s = host; + st.len = hlen; + he = sip_resolvehost(&st, (unsigned short *)&port, + (unsigned short *)&proto, 0, 0); + if (!he) { + LM_ERR("Cannot resolve host: %.*s\n", hlen, host); + return -1; + } + + hostent2su(&rd->to, he, 0, port); + + rd->next = replication_dests; + replication_dests = rd; + + return 1; +} + +static char *callid_buf=NULL; +static int callid_buf_len=0; +int pv_get_dlg_callee_callid(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) +{ + struct dlg_cell *dlg; + int req_len = 0,i; + + if(res==NULL) + return -1; + + if ( (dlg=get_current_dialog())==NULL || (dlg->flags & DLG_FLAG_TOPH_HIDE_CALLID) == 0) { + return pv_get_null( msg, param, res); + } + + + req_len = calc_base64_encode_len(dlg->callid.len) + topo_hiding_prefix.len; + + if (req_len*2 > callid_buf_len) { + callid_buf = pkg_realloc(callid_buf,req_len*2); + if (callid_buf == NULL) { + LM_ERR("No more pkg\n"); + return pv_get_null( msg, param, res); + } + + callid_buf_len = req_len*2; + } + + memcpy(callid_buf+req_len,topo_hiding_prefix.s,topo_hiding_prefix.len); + for (i=0;icallid.len;i++) + callid_buf[i] = dlg->callid.s[i] ^ topo_hiding_seed.s[i%topo_hiding_seed.len]; + + base64encode((unsigned char *)(callid_buf+topo_hiding_prefix.len+req_len), + (unsigned char *)(callid_buf),dlg->callid.len); + + res->rs.s = callid_buf+req_len; + res->rs.len = req_len; + res->flags = PV_VAL_STR; + + return 0; +} diff --git a/modules/dialog/dlg_cb.c b/modules/dialog/dlg_cb.c index 1e9bb7d138a..b3d2627efa0 100644 --- a/modules/dialog/dlg_cb.c +++ b/modules/dialog/dlg_cb.c @@ -15,17 +15,17 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2006-04-14 initial version (bogdan) * 2008-04-04 added direction reporting in dlg callbacks (bogdan) - * 2008-04-14 DLGCB_CREATED may be registered before the module + * 2008-04-14 DLGCB_CREATED may be registered before the module * initialization (bogdan) - * 2008-04-15 added new type of callback to be triggered when dialogs are + * 2008-04-15 added new type of callback to be triggered when dialogs are * loaded from DB (bogdan) */ @@ -38,6 +38,7 @@ static struct dlg_head_cbl* create_cbs = 0; +static int dlg_load_cbs_run = 0; static struct dlg_head_cbl* load_cbs = 0; static struct dlg_cb_params params = {NULL, DLG_DIR_NONE, NULL, NULL}; @@ -81,6 +82,11 @@ void destroy_dlg_callbacks_list(struct dlg_callback *cb) } } +void mark_dlg_loaded_callbacks_run(void) +{ + dlg_load_cbs_run = 1; +} + void destroy_dlg_callbacks(unsigned int types) { @@ -151,10 +157,9 @@ int register_dlgcb(struct dlg_cell *dlg, int types, dialog_cb f, create_cbs->first = cb; create_cbs->types |= types; } else if (types==DLGCB_LOADED) { - if (load_cbs==POINTER_CLOSED_MARKER) { + if (dlg_load_cbs_run) { /* run the callback on the spot */ run_load_callback(cb); - destroy_dlg_callbacks_list(cb); return 0; } if (load_cbs==0) { @@ -210,6 +215,22 @@ void run_load_callbacks( void ) return; } +void run_load_callback_per_dlg(struct dlg_cell *dlg) +{ + struct dlg_callback *cb; + + params.msg = NULL; + params.direction = DLG_DIR_NONE; + + if (load_cbs && load_cbs!=POINTER_CLOSED_MARKER) { + for ( cb=load_cbs->first; cb; cb=cb->next ) { + params.param = &cb->param; + cb->callback( dlg, DLGCB_LOADED, ¶ms ); + } + } + + return; +} void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg) { diff --git a/modules/dialog/dlg_cb.h b/modules/dialog/dlg_cb.h index 7628756a033..2957b27d9a7 100644 --- a/modules/dialog/dlg_cb.h +++ b/modules/dialog/dlg_cb.h @@ -15,15 +15,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2006-04-11 initial version (bogdan) * 2008-04-04 added direction reporting in dlg callbacks (bogdan) - * 2008-04-14 added new type of callback to be triggered when dialogs are + * 2008-04-14 added new type of callback to be triggered when dialogs are * loaded from DB (bogdan) * 2008-04-17 added new type of callback to be triggered right before the * dialog is destroyed (deleted from memory) (bogdan) @@ -44,7 +44,7 @@ struct dlg_cb_params { }; /* callback function prototype */ -typedef void (dialog_cb) (struct dlg_cell* dlg, int type, +typedef void (dialog_cb) (struct dlg_cell* dlg, int type, struct dlg_cb_params * params); /* function to free the callback param */ typedef void (param_free_cb) (void *param); @@ -86,6 +86,8 @@ void destroy_dlg_callbacks(unsigned int type); void destroy_dlg_callbacks_list(struct dlg_callback *cb); +void mark_dlg_loaded_callbacks_run(void); + int register_dlgcb( struct dlg_cell* dlg, int types, dialog_cb f, void *param, param_free_cb ff); void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg); @@ -95,5 +97,6 @@ void run_dlg_callbacks( int type , struct dlg_cell *dlg, struct sip_msg *msg, void run_load_callbacks( void ); +void run_load_callback_per_dlg(struct dlg_cell *dlg); #endif diff --git a/modules/dialog/dlg_db_handler.c b/modules/dialog/dlg_db_handler.c index 19fba9ba61d..997ff3bcf8f 100644 --- a/modules/dialog/dlg_db_handler.c +++ b/modules/dialog/dlg_db_handler.c @@ -15,14 +15,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2007-05-10 initial version (ancuta) - * 2007-07-06 additional information saved in the database: cseq, contact, + * 2007-07-06 additional information saved in the database: cseq, contact, * route set and socket_info for both caller and callee (ancuta) * 2009-09-09 support for early dialogs added; proper handling of cseq * while PRACK is used (bogdan) @@ -69,6 +69,7 @@ str mangled_tu_column = str_init(MANGLED_TU_COL); str vars_column = str_init(VARS_COL); str profiles_column = str_init(PROFILES_COL); str sflags_column = str_init(SFLAGS_COL); +str mflags_column = str_init(MFLAGS_COL); str flags_column = str_init(FLAGS_COL); str dialog_table_name = str_init(DIALOG_TABLE_NAME); int dlg_db_mode = DB_MODE_NONE; @@ -244,7 +245,8 @@ static int select_entire_dialog_table(db_res_t ** res, int *no_rows) &to_route_column, &from_contact_column, &to_contact_column, &from_sock_column, &to_sock_column, &vars_column, &profiles_column, &sflags_column, &from_ping_cseq_column, - &to_ping_cseq_column,&flags_column, &mangled_fu_column,&mangled_tu_column}; + &to_ping_cseq_column,&flags_column, &mangled_fu_column,&mangled_tu_column, + &mflags_column}; if(use_dialog_table() != 0){ return -1; @@ -257,8 +259,9 @@ static int select_entire_dialog_table(db_res_t ** res, int *no_rows) LM_ERR("Error while querying (fetch) database\n"); return -1; } - *no_rows = estimate_available_rows( 4+4+128+64+32+54+32+4+4+4+16+16 - +256+256+64+64+32+32+256+256+4+4+4+4,DIALOG_TABLE_TOTAL_COL_NO ); + *no_rows = estimate_available_rows( 4+255+128+64+128+64+64+64+11+11+4+4 + +512+512+128+128+64+64+4+4+4+4096+512+4+4+4 ,DIALOG_TABLE_TOTAL_COL_NO ); + if (*no_rows==0) *no_rows = 10; if(dialog_dbf.fetch_result(dialog_db_handle,res,*no_rows)<0){ LM_ERR("fetching rows failed\n"); @@ -290,7 +293,7 @@ struct socket_info * create_socket_info(db_val_t * vals, int n){ if (VAL_NULL(vals+n) || p.s==0 || p.s[0]==0){ sock = 0; } else { - if (parse_phostport( p.s, p.len, &host.s, &host.len, + if (parse_phostport( p.s, p.len, &host.s, &host.len, &port, &proto)!=0) { LM_ERR("bad socket <%.*s>\n", p.len, p.s); return 0; @@ -360,8 +363,9 @@ static inline char* read_pair(char *b, char *end, str *name, str *val) return (b==end)?NULL:b; } - -static void read_dialog_vars(char *b, int l, struct dlg_cell *dlg) +/* The function is always considered to be lock-less ( safe ) + * it's either called when dialog is not linked yes, or is under the dialog lock */ +void read_dialog_vars(char *b, int l, struct dlg_cell *dlg) { str name, val; char *end; @@ -379,21 +383,23 @@ static void read_dialog_vars(char *b, int l, struct dlg_cell *dlg) LM_DBG("new var found <%.*s>=<%.*s>\n",name.len,name.s,val.len,val.s); /* add the variable */ - if (store_dlg_value( dlg, &name, &val)!=0) + if (store_dlg_value_unsafe( dlg, &name, &val)!=0) LM_ERR("failed to add val, skipping...\n"); } while(p!=end); } -static void read_dialog_profiles(char *b, int l, struct dlg_cell *dlg,int double_check) +void read_dialog_profiles(char *b, int l, struct dlg_cell *dlg,int double_check, + char is_replicated) { struct dlg_profile_table *profile; struct dlg_profile_link *it; - str name, val; + str name, val,double_check_name; char *end; - char *p; + char *p,*s,*e; char bk; + int use_cached; end = b + l; p = b; @@ -407,9 +413,29 @@ static void read_dialog_profiles(char *b, int l, struct dlg_cell *dlg,int double LM_DBG("new profile found <%.*s>=<%.*s>\n",name.len,name.s,val.len,val.s); if (double_check) { + LM_DBG("Double checking profile - if it exists we'll skip it \n"); + use_cached = 0; + + /* check if this is a shared profile, and remove /s for manual + * matching */ + double_check_name = name; + s = memchr(name.s, '/', name.len); + + if (s) { + e = double_check_name.s + double_check_name.len; + double_check_name.len = s - double_check_name.s; + trim_spaces_lr( double_check_name ); + /* skip spaces after p */ + for (++s; *s == ' ' && s < e; s++); + if ( s < e && *s == 's') + use_cached=1; + } + for (it=dlg->profile_links;it;it=it->next) { - if (it->profile->name.len == name.len && - memcmp(it->profile->name.s,name.s,name.len) == 0) { + if (it->profile->use_cached == use_cached && + it->profile->name.len == double_check_name.len && + memcmp(it->profile->name.s,double_check_name.s, + double_check_name.len) == 0) { LM_DBG("Profile is already linked into the dlg\n"); goto next; } @@ -436,7 +462,8 @@ static void read_dialog_profiles(char *b, int l, struct dlg_cell *dlg,int double continue; } } - if (set_dlg_profile( NULL, profile->has_value?&val:NULL, profile) < 0 ) + if (set_dlg_profile( NULL, profile->has_value ? &val : NULL, profile, + is_replicated) < 0 ) LM_ERR("failed to add to profile, skipping....\n"); next: ; @@ -544,7 +571,7 @@ static int load_dialog_info_from_db(int dlg_hash_size) LM_ERR("inconsistent hash data in the dialog database: " "you may have restarted opensips using a different " "hash_size: please erase %.*s database and restart\n" - "db : %u, dlg : %u\n", + "dlg : %u, db : %u\n", dialog_table_name.len, dialog_table_name.s, dlg->h_entry,hash_entry); shm_free(dlg); @@ -558,7 +585,7 @@ static int load_dialog_info_from_db(int dlg_hash_size) next_id = d_table->entries[dlg->h_entry].next_id; d_table->entries[dlg->h_entry].next_id = - (next_id < dlg->h_id) ? (dlg->h_id+1) : next_id; + (next_id <= dlg->h_id) ? (dlg->h_id+1) : next_id; GET_STR_VALUE(to_tag, values, 5, 1, 1); @@ -595,14 +622,19 @@ static int load_dialog_info_from_db(int dlg_hash_size) dlg->legs_no[DLG_LEG_200OK] = DLG_FIRST_CALLEE_LEG; /* script variables */ - if (!VAL_NULL(values+17)) - read_dialog_vars( VAL_STR(values+17).s, - VAL_STR(values+17).len, dlg); + if (!VAL_NULL(values+17)) { + if (VAL_TYPE(values+17) == DB_BLOB) { + read_dialog_vars( VAL_BLOB(values+17).s, + VAL_BLOB(values+17).len, dlg); + } else { + LM_ERR("non-blob variables column - cannot store dialog variables\n"); + } + } /* profiles */ if (!VAL_NULL(values+18)) read_dialog_profiles( VAL_STR(values+18).s, - strlen(VAL_STR(values+18).s), dlg,0); + strlen(VAL_STR(values+18).s), dlg, 0, 0); /* script flags */ @@ -610,6 +642,11 @@ static int load_dialog_info_from_db(int dlg_hash_size) dlg->user_flags = VAL_INT(values+19); } + /* module flags */ + if (!VAL_NULL(values+25)) { + dlg->mod_flags = VAL_INT(values+25); + } + /* top hiding */ dlg->flags = VAL_INT(values+22); if (dlg_db_mode==DB_MODE_SHUTDOWN) @@ -643,14 +680,14 @@ static int load_dialog_info_from_db(int dlg_hash_size) dlg->lifetime = 0; - dlg->legs[DLG_CALLER_LEG].last_gen_cseq = + dlg->legs[DLG_CALLER_LEG].last_gen_cseq = (unsigned int)(VAL_INT(values+20)); - dlg->legs[callee_idx(dlg)].last_gen_cseq = + dlg->legs[callee_idx(dlg)].last_gen_cseq = (unsigned int)(VAL_INT(values+21)); if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { - if (0 != insert_ping_timer(dlg)) - LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg); + if (0 != insert_ping_timer(dlg)) + LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg); else { /* reference dialog as kept in ping timer list */ ref_dlg(dlg,1); @@ -744,7 +781,7 @@ int dlg_timer_remove_from_db(struct dlg_cell *cell) } /* store info in del holders */ - VAL_BIGINT(dlg_del_values+dlg_del_curr_no) = + VAL_BIGINT(dlg_del_values+dlg_del_curr_no) = ((long long)cell->h_entry << 32) | (cell->h_id); dlg_del_holder[dlg_del_curr_no]=cell; /* mark is as deleted so we don't care about it later @@ -757,7 +794,7 @@ int dlg_timer_remove_from_db(struct dlg_cell *cell) CON_PS_REFERENCE(dialog_db_handle) = &my_ps; CON_USE_OR_OP(dialog_db_handle); - if(dialog_dbf.delete(dialog_db_handle, dlg_del_keys, + if(dialog_dbf.delete(dialog_db_handle, dlg_del_keys, 0, dlg_del_values, dlg_bulk_del_no) < 0) LM_ERR("failed to delete bulk database information !!!\n"); @@ -785,7 +822,7 @@ int dlg_timer_flush_del(void) if (dlg_del_curr_no > 0) { CON_USE_OR_OP(dialog_db_handle); - if(dialog_dbf.delete(dialog_db_handle, dlg_del_keys, + if(dialog_dbf.delete(dialog_db_handle, dlg_del_keys, 0, dlg_del_values, dlg_del_curr_no) < 0) LM_ERR("failed to delete bulk database information !!!\n"); @@ -809,7 +846,7 @@ int remove_dialog_from_db(struct dlg_cell * cell) /*if the dialog hasn 't been yet inserted in the database*/ LM_DBG("trying to remove a dialog, update_flag is %i\n", cell->flags); - if (cell->flags & DLG_FLAG_NEW) + if (cell->flags & DLG_FLAG_NEW) return 0; if (use_dialog_table()!=0) @@ -835,6 +872,55 @@ int remove_dialog_from_db(struct dlg_cell * cell) return 0; } +int update_dialog_timeout_info(struct dlg_cell * cell) +{ + static db_ps_t my_ps_update = NULL; + struct dlg_entry entry; + db_val_t values[2]; + + db_key_t insert_keys[DIALOG_TABLE_TOTAL_COL_NO] = { + &dlg_id_column, &timeout_column}; + + if(use_dialog_table()!=0) + return -1; + + if (!(cell->flags & DLG_FLAG_CHANGED)) + return 0; + + /* save only dialog's state and timeout */ + VAL_TYPE(values) = DB_BIGINT; + VAL_TYPE(values+1) = DB_INT; + + /* lock the entry */ + entry = (d_table->entries)[cell->h_entry]; + dlg_lock( d_table, &entry); + + SET_BIGINT_VALUE(values, (((long long)cell->h_entry << 32) | + cell->h_id)); + SET_INT_VALUE(values+1, (unsigned int)( (unsigned int)time(0) + + cell->tl.timeout - get_ticks()) ); + + CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update; + + if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, + (values), (insert_keys+1), (values+1), 1, 1)) !=0){ + LM_ERR("could not update database timeout info\n"); + goto error; + } + + /* dialog saved */ + run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0); + + cell->flags &= ~(DLG_FLAG_CHANGED); + + dlg_unlock( d_table, &entry); + return 0; + +error: + dlg_unlock( d_table, &entry); + return -1; +} + int update_dialog_dbinfo(struct dlg_cell * cell) { static db_ps_t my_ps_insert = NULL; @@ -844,17 +930,17 @@ int update_dialog_dbinfo(struct dlg_cell * cell) db_val_t values[DIALOG_TABLE_TOTAL_COL_NO]; int callee_leg; - db_key_t insert_keys[DIALOG_TABLE_TOTAL_COL_NO] = { + db_key_t insert_keys[DIALOG_TABLE_TOTAL_COL_NO] = { &dlg_id_column, &call_id_column, &from_uri_column, &from_tag_column, &to_uri_column, &to_tag_column, &from_sock_column, &to_sock_column, &start_time_column, &mangled_fu_column, &mangled_tu_column, - + &state_column, &timeout_column, &from_cseq_column, &to_cseq_column, &from_ping_cseq_column, &to_ping_cseq_column,&flags_column, &vars_column, &profiles_column, &sflags_column, - &from_route_column, + &mflags_column, &from_route_column, &to_route_column, &from_contact_column,&to_contact_column}; if(use_dialog_table()!=0) @@ -866,17 +952,17 @@ int update_dialog_dbinfo(struct dlg_cell * cell) /* save all the current dialogs information*/ VAL_TYPE(values) = DB_BIGINT; - VAL_TYPE(values+8) = VAL_TYPE(values+11) = VAL_TYPE(values+12) = - VAL_TYPE(values+15) =VAL_TYPE(values+16) = VAL_TYPE(values+17) = - VAL_TYPE(values+20) = DB_INT; + VAL_TYPE(values+8) = VAL_TYPE(values+11) = VAL_TYPE(values+12) = + VAL_TYPE(values+15) =VAL_TYPE(values+16) = VAL_TYPE(values+17) = + VAL_TYPE(values+20) = VAL_TYPE(values+21) = DB_INT; - VAL_TYPE(values+1) = VAL_TYPE(values+2) = VAL_TYPE(values+3) = - VAL_TYPE(values+4) = VAL_TYPE(values+5) = VAL_TYPE(values+6) = + VAL_TYPE(values+1) = VAL_TYPE(values+2) = VAL_TYPE(values+3) = + VAL_TYPE(values+4) = VAL_TYPE(values+5) = VAL_TYPE(values+6) = VAL_TYPE(values+7) = VAL_TYPE(values+9) = VAL_TYPE(values+10) = - VAL_TYPE(values+13) = VAL_TYPE(values+14) = - VAL_TYPE(values+18) = VAL_TYPE(values+19) = VAL_TYPE(values+21) = - VAL_TYPE(values+22) = VAL_TYPE(values+23) = - VAL_TYPE(values+24) = DB_STR; + VAL_TYPE(values+13) = VAL_TYPE(values+14) = + VAL_TYPE(values+18) = VAL_TYPE(values+19) = VAL_TYPE(values+22) = + VAL_TYPE(values+23) = VAL_TYPE(values+24) = + VAL_TYPE(values+25) = DB_STR; /* lock the entry */ entry = (d_table->entries)[cell->h_entry]; @@ -893,7 +979,7 @@ int update_dialog_dbinfo(struct dlg_cell * cell) SET_STR_VALUE(values+6, cell->legs[DLG_CALLER_LEG].bind_addr->sock_str); if (cell->legs[callee_leg].bind_addr) { - SET_STR_VALUE(values+7, + SET_STR_VALUE(values+7, cell->legs[callee_leg].bind_addr->sock_str); } else { VAL_NULL(values+7) = 1; @@ -914,14 +1000,14 @@ int update_dialog_dbinfo(struct dlg_cell * cell) SET_INT_VALUE(values+16,cell->legs[callee_leg].last_gen_cseq); SET_INT_VALUE(values+17, cell->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); set_final_update_cols(values+18, cell, 0); - SET_STR_VALUE(values+21, cell->legs[DLG_CALLER_LEG].route_set); - SET_STR_VALUE(values+22, cell->legs[callee_leg].route_set); - SET_STR_VALUE(values+23, cell->legs[DLG_CALLER_LEG].contact); - SET_STR_VALUE(values+24, cell->legs[callee_leg].contact); + SET_STR_VALUE(values+22, cell->legs[DLG_CALLER_LEG].route_set); + SET_STR_VALUE(values+23, cell->legs[callee_leg].route_set); + SET_STR_VALUE(values+24, cell->legs[DLG_CALLER_LEG].contact); + SET_STR_VALUE(values+25, cell->legs[callee_leg].contact); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_insert; - if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, + if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, DIALOG_TABLE_TOTAL_COL_NO)) !=0){ LM_ERR("could not add another dialog to db\n"); goto error; @@ -937,7 +1023,7 @@ int update_dialog_dbinfo(struct dlg_cell * cell) VAL_TYPE(values) = DB_BIGINT; VAL_TYPE(values+11) = VAL_TYPE(values+12) = VAL_TYPE(values+15) = VAL_TYPE(values+16) = VAL_TYPE(values+17) = VAL_TYPE(values+20) = - DB_INT; + VAL_TYPE(values+21) = DB_INT; VAL_TYPE(values+13) = VAL_TYPE(values+14) = VAL_TYPE(values+18) = VAL_TYPE(values+19) = DB_STR; @@ -961,8 +1047,8 @@ int update_dialog_dbinfo(struct dlg_cell * cell) CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update; - if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, - (values), (insert_keys+11), (values+11), 1, 10)) !=0){ + if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, + (values), (insert_keys+11), (values+11), 1, 11)) !=0){ LM_ERR("could not update database info\n"); goto error; } @@ -974,18 +1060,22 @@ int update_dialog_dbinfo(struct dlg_cell * cell) } else if (cell->flags & DLG_FLAG_VP_CHANGED) { VAL_TYPE(values) = DB_BIGINT; VAL_TYPE(values+20) = DB_INT; + VAL_TYPE(values+21) = DB_INT; VAL_TYPE(values+18) = VAL_TYPE(values+19) = DB_STR; /* lock the entry */ entry = (d_table->entries)[cell->h_entry]; dlg_lock( d_table, &entry); + SET_BIGINT_VALUE(values, (((long long)cell->h_entry << 32) | + cell->h_id)); + set_final_update_cols(values+18, cell, 0); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update_vp; - if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, - (values), (insert_keys+18), (values+18), 1, 3)) !=0){ + if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, + (values), (insert_keys+18), (values+18), 1, 4)) !=0){ LM_ERR("could not update database info\n"); goto error; } @@ -1006,7 +1096,8 @@ int update_dialog_dbinfo(struct dlg_cell * cell) } -static inline unsigned int write_pair( char *b, str *name, str *val) +static inline unsigned int write_pair( char *b, str *name, str *name_suffix, + str *val) { int i,j; @@ -1015,6 +1106,10 @@ static inline unsigned int write_pair( char *b, str *name, str *val) b[j++] = '\\'; b[j++] = name->s[i]; } + if (name_suffix) { + memcpy(b+j,name_suffix->s,name_suffix->len); + j+=name_suffix->len; + } b[j++] = '#'; for( i=0 ; val && ilen ; i++) { if (val->s[i]=='|' || val->s[i]=='#' || val->s[i]=='\\') @@ -1027,7 +1122,7 @@ static inline unsigned int write_pair( char *b, str *name, str *val) } -static str* write_dialog_vars( struct dlg_val *vars) +str* write_dialog_vars( struct dlg_val *vars) { static str o = {NULL,0}; static int o_l=0; @@ -1059,7 +1154,7 @@ static str* write_dialog_vars( struct dlg_val *vars) o.len = l; p = o.s; for ( v=vars ; v ; v=v->next) { - p += write_pair( p, &v->name, &v->val); + p += write_pair( p, &v->name,NULL, &v->val); } if (o.len!=p-o.s) { LM_CRIT("BUG - buffer overflow allocated %d, written %d\n", @@ -1072,9 +1167,9 @@ static str* write_dialog_vars( struct dlg_val *vars) } -static str* write_dialog_profiles( struct dlg_profile_link *links) +str* write_dialog_profiles( struct dlg_profile_link *links) { - static str o = {NULL,0}; + static str o = {NULL,0},cached_marker={"/s",2}; static int o_l = 0; struct dlg_profile_link *link; unsigned int l,i; @@ -1089,6 +1184,8 @@ static str* write_dialog_profiles( struct dlg_profile_link *links) for( i=0 ; ivalue.len ; i++ ) if (link->value.s[i]=='|' || link->value.s[i]=='#' || link->value.s[i]=='\\') l++; + if (link->profile->use_cached) + l+=cached_marker.len; } /* allocate the string to be stored */ @@ -1106,7 +1203,11 @@ static str* write_dialog_profiles( struct dlg_profile_link *links) o.len = l; p = o.s; for ( link=links; link ; link=link->next) { - p += write_pair( p, &link->profile->name, &link->value); + if (link->profile->use_cached) + p += write_pair( p, &link->profile->name, &cached_marker, + &link->value); + else + p += write_pair( p, &link->profile->name, NULL, &link->value); } if (o.len!=p-o.s) { LM_CRIT("BUG - buffer overflow allocated %d, written %d\n", @@ -1150,10 +1251,12 @@ static inline void set_final_update_cols(db_val_t *vals, struct dlg_cell *cell, } } SET_INT_VALUE(vals+2, cell->user_flags); + SET_INT_VALUE(vals+3, cell->mod_flags); } else { VAL_NULL(vals) = 1; VAL_NULL(vals+1) = 1; SET_INT_VALUE(vals+2, 0); + SET_INT_VALUE(vals+3, 0); } } @@ -1168,7 +1271,7 @@ void dialog_update_db(unsigned int ticks, void * param) int index; db_val_t values[DIALOG_TABLE_TOTAL_COL_NO]; struct dlg_entry *entry; - struct dlg_cell * cell,*next_cell; + struct dlg_cell * cell,*next_cell; unsigned char on_shutdown; int callee_leg,ins_done=0; static query_list_t *ins_list = NULL; @@ -1182,7 +1285,8 @@ void dialog_update_db(unsigned int ticks, void * param) /*update chunk */ &state_column, &timeout_column, &from_cseq_column, &to_cseq_column, &from_ping_cseq_column, &to_ping_cseq_column, - &vars_column, &profiles_column, &sflags_column, &flags_column}; + &vars_column, &profiles_column, &sflags_column, + &mflags_column, &flags_column}; if (dialog_db_handle==0 || use_dialog_table()!=0) return; @@ -1191,15 +1295,16 @@ void dialog_update_db(unsigned int ticks, void * param) /*save the current dialogs information*/ VAL_TYPE(values) = DB_BIGINT; - VAL_TYPE(values+8) = + VAL_TYPE(values+8) = VAL_TYPE(values+15) = VAL_TYPE(values+16) = VAL_TYPE(values+19) = - VAL_TYPE(values+20) = VAL_TYPE(values+23) = VAL_TYPE(values+24)= DB_INT; + VAL_TYPE(values+20) = VAL_TYPE(values+23) = VAL_TYPE(values+24)= + VAL_TYPE(values+25) = DB_INT; - VAL_TYPE(values+1) = VAL_TYPE(values+2) = VAL_TYPE(values+3) = - VAL_TYPE(values+4) = VAL_TYPE(values+5) = VAL_TYPE(values+6) = - VAL_TYPE(values+7) = VAL_TYPE(values+9) = VAL_TYPE(values+10) = + VAL_TYPE(values+1) = VAL_TYPE(values+2) = VAL_TYPE(values+3) = + VAL_TYPE(values+4) = VAL_TYPE(values+5) = VAL_TYPE(values+6) = + VAL_TYPE(values+7) = VAL_TYPE(values+9) = VAL_TYPE(values+10) = VAL_TYPE(values+11) = VAL_TYPE(values+12) = VAL_TYPE(values+13) = - VAL_TYPE(values+14) = VAL_TYPE(values+17) = VAL_TYPE(values+18) = + VAL_TYPE(values+14) = VAL_TYPE(values+17) = VAL_TYPE(values+18) = VAL_TYPE(values+21) = VAL_TYPE(values+22) = DB_STR; for(index = 0; index< d_table->size; index++){ @@ -1243,7 +1348,7 @@ void dialog_update_db(unsigned int ticks, void * param) SET_STR_VALUE(values+6, cell->legs[DLG_CALLER_LEG].bind_addr->sock_str); if (cell->legs[callee_leg].bind_addr) { - SET_STR_VALUE(values+7, + SET_STR_VALUE(values+7, cell->legs[callee_leg].bind_addr->sock_str); } else { VAL_NULL(values+7) = 1; @@ -1272,15 +1377,16 @@ void dialog_update_db(unsigned int ticks, void * param) SET_INT_VALUE(values+19, cell->legs[DLG_CALLER_LEG].last_gen_cseq); SET_INT_VALUE(values+20, cell->legs[callee_leg].last_gen_cseq); - set_final_update_cols(values+21, cell, on_shutdown); - SET_INT_VALUE(values+24, cell->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); + set_final_update_cols(values+21, cell, + (on_shutdown) || (cell->flags&DLG_FLAG_CHANGED) ); + SET_INT_VALUE(values+25, cell->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_insert; if (con_set_inslist(&dialog_dbf,dialog_db_handle, &ins_list,insert_keys,DIALOG_TABLE_TOTAL_COL_NO) < 0 ) CON_RESET_INSLIST(dialog_db_handle); - if((dialog_dbf.insert(dialog_db_handle, insert_keys, + if((dialog_dbf.insert(dialog_db_handle, insert_keys, values, DIALOG_TABLE_TOTAL_COL_NO)) !=0){ LM_ERR("could not add another dialog to db\n"); goto error; @@ -1317,12 +1423,12 @@ void dialog_update_db(unsigned int ticks, void * param) SET_INT_VALUE(values+20, cell->legs[callee_leg].last_gen_cseq); set_final_update_cols(values+21, cell, 1); - SET_INT_VALUE(values+24, cell->flags); + SET_INT_VALUE(values+25, cell->flags); CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update; - if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, - (values), (insert_keys+15), (values+15), 1, 10)) !=0) { + if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, + (values), (insert_keys+15), (values+15), 1, 11)) !=0) { LM_ERR("could not update database info\n"); goto error; } @@ -1340,8 +1446,8 @@ void dialog_update_db(unsigned int ticks, void * param) CON_PS_REFERENCE(dialog_db_handle) = &my_ps_update_vp; - if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, - (values), (insert_keys+21), (values+21), 1, 3)) !=0) { + if((dialog_dbf.update(dialog_db_handle, (insert_keys), 0, + (values), (insert_keys+21), (values+21), 1, 4)) !=0) { LM_ERR("could not update database info\n"); goto error; } @@ -1412,7 +1518,7 @@ static int sync_dlg_db_mem(void) continue; } - hash_entry = (int)(VAL_BIGINT(values) & 0xffffffff00000000); + hash_entry = (int)(VAL_BIGINT(values) >> 32); hash_id = (int)(VAL_BIGINT(values) & 0x00000000ffffffff); if (VAL_NULL(values+6) || VAL_NULL(values+7)) { @@ -1434,13 +1540,13 @@ static int sync_dlg_db_mem(void) /* TODO - check about hash resize ? maybe hash was lowered & we overflow the hash */ known_dlg = 0; - d_entry = &(d_table->entries[VAL_INT(values)]); + d_entry = &(d_table->entries[hash_entry]); /* lock the whole entry */ dlg_lock( d_table, d_entry); for (it=d_entry->first;it;it=it->next) - if (it->callid.len == callid.len && + if (it->callid.len == callid.len && it->legs[DLG_CALLER_LEG].tag.len == from_tag.len && memcmp(it->callid.s,callid.s,callid.len)==0 && memcmp(it->legs[DLG_CALLER_LEG].tag.s,from_tag.s,from_tag.len)==0) { @@ -1477,7 +1583,7 @@ static int sync_dlg_db_mem(void) if(dlg->h_entry != hash_entry){ LM_ERR("inconsistent hash data in the dialog database: " "you may have restarted opensips using a different " - "hash_size: please erase %.*s database and restart\n", + "hash_size: please erase %.*s database and restart\n", dialog_table_name.len, dialog_table_name.s); shm_free(dlg); goto error; @@ -1490,7 +1596,7 @@ static int sync_dlg_db_mem(void) next_id = d_table->entries[dlg->h_entry].next_id; d_table->entries[dlg->h_entry].next_id = - (next_id < dlg->h_id) ? (dlg->h_id+1) : next_id; + (next_id <= dlg->h_id) ? (dlg->h_id+1) : next_id; dlg->start_ts = VAL_INT(values+6); @@ -1525,14 +1631,19 @@ static int sync_dlg_db_mem(void) dlg->legs_no[DLG_LEG_200OK] = DLG_FIRST_CALLEE_LEG; /* script variables */ - if (!VAL_NULL(values+17)) - read_dialog_vars( VAL_STR(values+17).s, - VAL_STR(values+17).len, dlg); + if (!VAL_NULL(values+17)) { + if (VAL_TYPE(values+17) == DB_BLOB) { + read_dialog_vars( VAL_BLOB(values+17).s, + VAL_BLOB(values+17).len, dlg); + } else { + LM_ERR("non-blob variables column - cannot store dialog variables\n"); + } + } /* profiles */ if (!VAL_NULL(values+18)) read_dialog_profiles( VAL_STR(values+18).s, - strlen(VAL_STR(values+18).s), dlg,0); + strlen(VAL_STR(values+18).s), dlg, 0, 0); /* script flags */ @@ -1540,6 +1651,11 @@ static int sync_dlg_db_mem(void) dlg->user_flags = VAL_INT(values+19); } + /* module flags */ + if (!VAL_NULL(values+25)) { + dlg->mod_flags = VAL_INT(values+25); + } + /* top hiding */ dlg->flags = VAL_INT(values+22); if (dlg_db_mode==DB_MODE_SHUTDOWN) @@ -1573,14 +1689,14 @@ static int sync_dlg_db_mem(void) dlg->lifetime = 0; - dlg->legs[DLG_CALLER_LEG].last_gen_cseq = + dlg->legs[DLG_CALLER_LEG].last_gen_cseq = (unsigned int)(VAL_INT(values+20)); - dlg->legs[callee_idx(dlg)].last_gen_cseq = + dlg->legs[callee_idx(dlg)].last_gen_cseq = (unsigned int)(VAL_INT(values+21)); if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { - if (0 != insert_ping_timer(dlg)) - LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg); + if (0 != insert_ping_timer(dlg)) + LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg); else { /* reference dialog as kept in ping timer list */ ref_dlg(dlg,1); @@ -1591,6 +1707,8 @@ static int sync_dlg_db_mem(void) /* to be later removed by timer */ ref_dlg(dlg,1); } + + run_load_callback_per_dlg(dlg); } else { /* we already saw this dialog before * check which is the newer version */ @@ -1604,9 +1722,9 @@ static int sync_dlg_db_mem(void) } else if (known_dlg->state == VAL_INT(values+7)) { LM_DBG("mem has same state as DB \n"); /* same state :-( no way to tell which is newer */ - + /* play nice and store longest timeout, although not always correct*/ - db_timeout = (unsigned int)(VAL_INT(values+8)) + + db_timeout = (unsigned int)(VAL_INT(values+8)) + get_ticks(); if (db_timeout<=(unsigned int)time(0)) db_timeout = 0; @@ -1620,14 +1738,14 @@ static int sync_dlg_db_mem(void) if (!VAL_NULL(values+9)) { cseq1.s = VAL_STR(values+9).s; cseq1.len = strlen(cseq1.s); - + str2int(&cseq1,&db_caller_cseq); str2int(&known_dlg->legs[DLG_CALLER_LEG].r_cseq,&dlg_caller_cseq); /* Is DB cseq newer ? */ if (db_caller_cseq > dlg_caller_cseq) { if (known_dlg->legs[DLG_CALLER_LEG].r_cseq.len < cseq1.len) { - known_dlg->legs[DLG_CALLER_LEG].r_cseq.s = + known_dlg->legs[DLG_CALLER_LEG].r_cseq.s = shm_realloc(known_dlg->legs[DLG_CALLER_LEG].r_cseq.s,cseq1.len); if (!known_dlg->legs[DLG_CALLER_LEG].r_cseq.s) { LM_ERR("no more shm\n"); @@ -1639,7 +1757,7 @@ static int sync_dlg_db_mem(void) known_dlg->legs[DLG_CALLER_LEG].r_cseq.len = cseq1.len; } } else { - /* DB has a null cseq - just keep + /* DB has a null cseq - just keep * what we have so far */ ; } @@ -1656,7 +1774,7 @@ static int sync_dlg_db_mem(void) /* Is DB cseq newer ? */ if (db_callee_cseq > dlg_callee_cseq) { if (known_dlg->legs[callee_leg_idx].r_cseq.len < cseq2.len) { - known_dlg->legs[callee_leg_idx].r_cseq.s = + known_dlg->legs[callee_leg_idx].r_cseq.s = shm_realloc(known_dlg->legs[callee_leg_idx].r_cseq.s,cseq2.len); if (!known_dlg->legs[callee_leg_idx].r_cseq.s) { LM_ERR("no more shm\n"); @@ -1668,7 +1786,7 @@ static int sync_dlg_db_mem(void) known_dlg->legs[callee_leg_idx].r_cseq.len = cseq2.len; } } else { - /* DB has a null cseq - just keep + /* DB has a null cseq - just keep * what we have so far */ ; } @@ -1686,9 +1804,14 @@ static int sync_dlg_db_mem(void) /* update script variables * if already found, delete the old ones * and replace with new one */ - if (!VAL_NULL(values+17)) - read_dialog_vars( VAL_STR(values+17).s, - VAL_STR(values+17).len, known_dlg); + if (!VAL_NULL(values+17)) { + if (VAL_TYPE(values+17) == DB_BLOB) { + read_dialog_vars( VAL_BLOB(values+17).s, + VAL_BLOB(values+17).len, known_dlg); + } else { + LM_ERR("non-blob variables column - cannot store dialog variables\n"); + } + } /* skip flags - keep what we have - anyway can't tell which is new */ @@ -1696,7 +1819,7 @@ static int sync_dlg_db_mem(void) * is dlg is already in that profile*/ if (!VAL_NULL(values+18)) read_dialog_profiles( VAL_STR(values+18).s, - strlen(VAL_STR(values+18).s), known_dlg,1); + strlen(VAL_STR(values+18).s), known_dlg, 1, 0); dlg_unlock( d_table, d_entry); } else { @@ -1707,7 +1830,7 @@ static int sync_dlg_db_mem(void) known_dlg->state = VAL_INT(values+7); /* update timeout */ - known_dlg->tl.timeout = (unsigned int)(VAL_INT(values+8)) + + known_dlg->tl.timeout = (unsigned int)(VAL_INT(values+8)) + get_ticks(); if (known_dlg->tl.timeout<=(unsigned int)time(0)) known_dlg->tl.timeout = 0; @@ -1720,7 +1843,7 @@ static int sync_dlg_db_mem(void) cseq1.len = strlen(cseq1.s); if (known_dlg->legs[DLG_CALLER_LEG].r_cseq.len < cseq1.len) { - known_dlg->legs[DLG_CALLER_LEG].r_cseq.s = + known_dlg->legs[DLG_CALLER_LEG].r_cseq.s = shm_realloc(known_dlg->legs[DLG_CALLER_LEG].r_cseq.s,cseq1.len); if (!known_dlg->legs[DLG_CALLER_LEG].r_cseq.s) { LM_ERR("no more shm\n"); @@ -1738,7 +1861,7 @@ static int sync_dlg_db_mem(void) callee_leg_idx = callee_idx(known_dlg); if (known_dlg->legs[callee_leg_idx].r_cseq.len < cseq2.len) { - known_dlg->legs[callee_leg_idx].r_cseq.s = + known_dlg->legs[callee_leg_idx].r_cseq.s = shm_realloc(known_dlg->legs[callee_leg_idx].r_cseq.s,cseq2.len); if (!known_dlg->legs[callee_leg_idx].r_cseq.s) { LM_ERR("no more shm\n"); @@ -1752,9 +1875,9 @@ static int sync_dlg_db_mem(void) } /* update ping cseqs */ - known_dlg->legs[DLG_CALLER_LEG].last_gen_cseq = + known_dlg->legs[DLG_CALLER_LEG].last_gen_cseq = (unsigned int)(VAL_INT(values+20)); - known_dlg->legs[callee_idx(known_dlg)].last_gen_cseq = + known_dlg->legs[callee_idx(known_dlg)].last_gen_cseq = (unsigned int)(VAL_INT(values+21)); /* update flags */ @@ -1765,15 +1888,20 @@ static int sync_dlg_db_mem(void) /* update script variables * if already found, delete the old one * and replace with new one */ - if (!VAL_NULL(values+17)) - read_dialog_vars( VAL_STR(values+17).s, - VAL_STR(values+17).len, known_dlg); + if (!VAL_NULL(values+17)) { + if (VAL_TYPE(values+17) == DB_BLOB) { + read_dialog_vars( VAL_BLOB(values+17).s, + VAL_BLOB(values+17).len, known_dlg); + } else { + LM_ERR("non-blob variables column - cannot store dialog variables\n"); + } + } /* profiles - do not insert into a profile * is dlg is already in that profile*/ if (!VAL_NULL(values+18)) read_dialog_profiles( VAL_STR(values+18).s, - strlen(VAL_STR(values+18).s), known_dlg,1); + strlen(VAL_STR(values+18).s), known_dlg, 1, 0); dlg_unlock( d_table, d_entry); } @@ -1802,11 +1930,160 @@ static int sync_dlg_db_mem(void) return -1; } +/* + * truncates and restores the dialog table with CONFIRMED dialogs from memory + */ +static int restore_dlg_db(void) +{ + int i, callee_leg, ins_done = 0; + struct dlg_entry *e; + struct dlg_cell *cell; + static query_list_t *ins_list = NULL; + static db_ps_t my_ps_insert = NULL; + + db_val_t values[DIALOG_TABLE_TOTAL_COL_NO]; + + db_key_t insert_keys[DIALOG_TABLE_TOTAL_COL_NO] = { + &dlg_id_column, &call_id_column, &from_uri_column, + &from_tag_column, &to_uri_column, &to_tag_column, + &from_sock_column, &to_sock_column, &start_time_column, + &from_route_column, &to_route_column, &from_contact_column, + &to_contact_column, &mangled_fu_column, &mangled_tu_column, + &state_column, &timeout_column, &from_cseq_column, + &to_cseq_column, &from_ping_cseq_column, &to_ping_cseq_column, + &vars_column, &profiles_column, &sflags_column, + &mflags_column, &flags_column}; + + VAL_TYPE(values) = DB_BIGINT; + VAL_TYPE(values+8) = + VAL_TYPE(values+15) = VAL_TYPE(values+16) = VAL_TYPE(values+19) = + VAL_TYPE(values+20) = VAL_TYPE(values+23) = VAL_TYPE(values+24)= + VAL_TYPE(values+25) = DB_INT; + + VAL_TYPE(values+1) = VAL_TYPE(values+2) = VAL_TYPE(values+3) = + VAL_TYPE(values+4) = VAL_TYPE(values+5) = VAL_TYPE(values+6) = + VAL_TYPE(values+7) = VAL_TYPE(values+9) = VAL_TYPE(values+10) = + VAL_TYPE(values+11) = VAL_TYPE(values+12) = VAL_TYPE(values+13) = + VAL_TYPE(values+14) = VAL_TYPE(values+17) = VAL_TYPE(values+18) = + VAL_TYPE(values+21) = VAL_TYPE(values+22) = DB_STR; + + if (remove_all_dialogs_from_db() != 0) { + LM_ERR("Failed to truncate dialog table!\n"); + return -1; + } + + for (i = 0; i < d_table->size; i++) { + e = d_table->entries + i; + + dlg_lock(d_table, e); + + for (cell = e->first; cell; cell = cell->next) { + + if (cell->state != DLG_STATE_CONFIRMED && + cell->state != DLG_STATE_CONFIRMED_NA) + continue; + + callee_leg = callee_idx(cell); + + SET_BIGINT_VALUE(values, (((long long)cell->h_entry << 32) | + cell->h_id)); + SET_STR_VALUE(values+1, cell->callid); + SET_STR_VALUE(values+2, cell->from_uri); + + SET_STR_VALUE(values+3, cell->legs[DLG_CALLER_LEG].tag); + SET_STR_VALUE(values+4, cell->to_uri); + SET_STR_VALUE(values+5, cell->legs[callee_leg].tag); + + SET_STR_VALUE(values+6, + cell->legs[DLG_CALLER_LEG].bind_addr->sock_str); + if (cell->legs[callee_leg].bind_addr) { + SET_STR_VALUE(values+7, + cell->legs[callee_leg].bind_addr->sock_str); + } else { + VAL_NULL(values+7) = 1; + } + + SET_INT_VALUE(values+8, cell->start_ts); + + SET_STR_VALUE(values+9, cell->legs[DLG_CALLER_LEG].route_set); + SET_STR_VALUE(values+10, + cell->legs[callee_leg].route_set); + SET_STR_VALUE(values+11, cell->legs[DLG_CALLER_LEG].contact); + SET_STR_VALUE(values+12, + cell->legs[callee_leg].contact); + + + SET_STR_VALUE(values+13,cell->legs[callee_leg].from_uri); + SET_STR_VALUE(values+14,cell->legs[callee_leg].to_uri); + + SET_INT_VALUE(values+15, cell->state); + SET_INT_VALUE(values+16, (unsigned int)((unsigned int)time(0) + + cell->tl.timeout - get_ticks()) ); + + SET_STR_VALUE(values+17, cell->legs[DLG_CALLER_LEG].r_cseq); + SET_STR_VALUE(values+18, cell->legs[callee_leg].r_cseq); + + SET_INT_VALUE(values+19, cell->legs[DLG_CALLER_LEG].last_gen_cseq); + SET_INT_VALUE(values+20, cell->legs[callee_leg].last_gen_cseq); + + set_final_update_cols(values+21, cell, 1); + SET_INT_VALUE(values+25, cell->flags & ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED| + DLG_FLAG_VP_CHANGED)); + + CON_PS_REFERENCE(dialog_db_handle) = &my_ps_insert; + if (con_set_inslist(&dialog_dbf,dialog_db_handle, + &ins_list,insert_keys,DIALOG_TABLE_TOTAL_COL_NO) < 0 ) + CON_RESET_INSLIST(dialog_db_handle); + + if((dialog_dbf.insert(dialog_db_handle, insert_keys, + values, DIALOG_TABLE_TOTAL_COL_NO)) !=0){ + LM_ERR("could not add another dialog to db\n"); + + dlg_unlock(d_table, e); + return -1; + } + + if (ins_done == 0) + ins_done = 1; + + /* dialog saved */ + run_dlg_callbacks( DLGCB_SAVED, cell, 0, DLG_DIR_NONE, 0); + + cell->flags &= ~(DLG_FLAG_NEW |DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED); + } + + dlg_unlock(d_table, e); + } + + if (ins_done) { + LM_DBG("attempting to flush rows to DB\n"); + /* flush everything to DB + * so that next-time timer fires + * we are sure that DB updates will be succesful */ + if (ql_flush_rows(&dialog_dbf,dialog_db_handle,ins_list) < 0) + LM_ERR("failed to flush rows to DB\n"); + } + + return 0; +} + struct mi_root* mi_sync_db_dlg(struct mi_root *cmd, void *param) { + if (dlg_db_mode == 0) + return init_mi_tree( 400, MI_SSTR("Cannot sync in no-db mode")); if (sync_dlg_db_mem() < 0) return init_mi_tree( 400, MI_SSTR("Sync mem with DB failed")); else return init_mi_tree( 200, MI_SSTR(MI_OK)); } +struct mi_root* mi_restore_dlg_db(struct mi_root *cmd, void *param) +{ + if (dlg_db_mode == 0) + return init_mi_tree( 400, MI_SSTR("Cannot restore db in no-db mode!")); + if (restore_dlg_db() < 0) + return init_mi_tree( 400, MI_SSTR("Restore dlg DB failed!")); + else + return init_mi_tree( 200, MI_SSTR(MI_OK)); +} + diff --git a/modules/dialog/dlg_db_handler.h b/modules/dialog/dlg_db_handler.h index 6c00e802da9..d477762043a 100644 --- a/modules/dialog/dlg_db_handler.h +++ b/modules/dialog/dlg_db_handler.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -58,10 +58,11 @@ #define VARS_COL "vars" #define PROFILES_COL "profiles" #define SFLAGS_COL "script_flags" +#define MFLAGS_COL "module_flags" #define FLAGS_COL "flags" #define DIALOG_TABLE_NAME "dialog" -#define DLG_TABLE_VERSION 8 +#define DLG_TABLE_VERSION 10 /*every minute the dialogs' information will be refreshed*/ #define DB_DEFAULT_UPDATE_PERIOD 60 @@ -70,7 +71,7 @@ #define DB_MODE_DELAYED 2 #define DB_MODE_SHUTDOWN 3 -#define DIALOG_TABLE_TOTAL_COL_NO 25 +#define DIALOG_TABLE_TOTAL_COL_NO 26 extern str dlg_id_column; extern str call_id_column; @@ -94,6 +95,7 @@ extern str from_sock_column; extern str profiles_column; extern str vars_column; extern str sflags_column; +extern str mflags_column; extern str th_column; extern str dialog_table_name; extern int dlg_db_mode; @@ -108,8 +110,16 @@ void destroy_dlg_db(); int remove_dialog_from_db(struct dlg_cell * cell); int update_dialog_dbinfo(struct dlg_cell * cell); +int update_dialog_timeout_info(struct dlg_cell * cell); void dialog_update_db(unsigned int ticks, void * param); +void read_dialog_vars(char *b, int l, struct dlg_cell *dlg); +void read_dialog_profiles(char *b, int l, struct dlg_cell *dlg, + int double_check, char is_replicated); +str* write_dialog_vars(struct dlg_val *vars); +str* write_dialog_profiles(struct dlg_profile_link *links); + struct mi_root* mi_sync_db_dlg(struct mi_root *cmd, void *param); +struct mi_root* mi_restore_dlg_db(struct mi_root *cmd, void *param); #endif diff --git a/modules/dialog/dlg_handlers.c b/modules/dialog/dlg_handlers.c index 520e4f4841a..1ba2f16cc4d 100644 --- a/modules/dialog/dlg_handlers.c +++ b/modules/dialog/dlg_handlers.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -28,17 +28,17 @@ * 2007-03-06 syncronized state machine added for dialog state. New tranzition * design based on events; removed num_1xx and num_2xx (bogdan) * 2007-04-30 added dialog matching without DID (dialog ID), but based only - * on RFC3261 elements - based on an original patch submitted + * on RFC3261 elements - based on an original patch submitted * by Michel Bensoussan (bogdan) - * 2007-05-17 new feature: saving dialog info into a database if + * 2007-05-17 new feature: saving dialog info into a database if * realtime update is set(ancuta) - * 2007-07-06 support for saving additional dialog info : cseq, contact, + * 2007-07-06 support for saving additional dialog info : cseq, contact, * route_set and socket_info for both caller and callee (ancuta) * 2007-07-10 Optimized dlg_match_mode 2 (DID_NONE), it now employs a proper - * hash table lookup and isn't dependant on the is_direction - * function (which requires an RR param like dlg_match_mode 0 - * anyways.. ;) ; based on a patch from - * Tavis Paquette + * hash table lookup and isn't dependant on the is_direction + * function (which requires an RR param like dlg_match_mode 0 + * anyways.. ;) ; based on a patch from + * Tavis Paquette * and Peter Baer (bogdan) * 2008-04-04 added direction reporting in dlg callbacks (bogdan) * 2009-09-09 support for early dialogs added; proper handling of cseq @@ -70,9 +70,10 @@ #include "dlg_profile.h" #include "dlg_req_within.h" #include "dlg_tophiding.h" +#include "dlg_replication.h" + +extern str rr_param; -static str rr_param; -static pv_spec_t *timeout_avp; static int default_timeout; static int shutdown_done = 0; @@ -86,14 +87,11 @@ extern stat_var *expired_dlgs; extern stat_var *failed_dlgs; int last_dst_leg = -1; +int dlg_tmp_timeout = -1; +int dlg_tmp_timeout_id = -1; -void init_dlg_handlers(char *rr_param_p, - pv_spec_t *timeout_avp_p ,int default_timeout_p) +void init_dlg_handlers(int default_timeout_p) { - rr_param.s = rr_param_p; - rr_param.len = strlen(rr_param.s); - - timeout_avp = timeout_avp_p; default_timeout = default_timeout_p; } @@ -161,7 +159,7 @@ static inline void get_routing_info(struct sip_msg *msg, int is_req, } } - /* extract the RR parts - parse all headers as we can have multiple + /* extract the RR parts - parse all headers as we can have multiple RR headers in the same message */ if( parse_headers(msg,HDR_EOH_F,0)<0 ){ LM_ERR("failed to parse record route header\n"); @@ -186,12 +184,12 @@ static inline void get_routing_info(struct sip_msg *msg, int is_req, /*usage: dlg: the dialog to add cseq, contact & record_route * msg: sip message - * flag: 0-for a request(INVITE), + * flag: 0-for a request(INVITE), * 1- for a reply(200 ok) * * for a request: get record route in normal order * for a reply : get in reverse order, skipping the ones from the request and - * the proxies' own + * the proxies' own */ static int init_leg_info( struct dlg_cell *dlg, struct sip_msg *msg, struct cell* t, str *tag,str *mangled_from,str *mangled_to) @@ -236,7 +234,7 @@ static int init_leg_info( struct dlg_cell *dlg, struct sip_msg *msg, LM_DBG("route_set %.*s, contact %.*s, cseq %.*s and bind_addr %.*s\n", rr_set.len, ZSW(rr_set.s), contact.len, ZSW(contact.s), - cseq.len, cseq.s, + cseq.len, cseq.s, msg->rcv.bind_address->sock_str.len, msg->rcv.bind_address->sock_str.s); @@ -283,7 +281,7 @@ static inline str* extract_mangled_touri(str *mangled_to_hdr) LM_ERR("bad to header [%.*s]\n",mangled_to_hdr->len,mangled_to_hdr->s); return NULL; } - + extracted_to_uri = to_b.uri; free_to_params(&to_b); @@ -342,7 +340,12 @@ static inline void push_reply_in_dialog(struct sip_msg *rpl, struct cell* t, } else { tag = get_to(rpl)->tag_value; if (tag.s==0 || tag.len==0) { - LM_ERR("missing TAG param in TO hdr :-/\n"); + /* Don't print error for final replies in DLG_STATE_UNCONFIRMED */ + if (!(dlg->state == DLG_STATE_UNCONFIRMED && + rpl->first_line.u.reply.statuscode >= 300)) { + LM_ERR("[%d] reply in dlg state [%d]: missing TAG param in TO hdr\n", + rpl->first_line.u.reply.statuscode, dlg->state); + } tag.s = 0; tag.len = 0; } @@ -391,6 +394,7 @@ static inline void push_reply_in_dialog(struct sip_msg *rpl, struct cell* t, ((t->relaied_reply_branch>=0)? (t->uac[t->relaied_reply_branch].added_rr):0); + LM_DBG("Skipping %d ,%d, %d, %d \n",skip_rrs, dlg->from_rr_nb,t->relaied_reply_branch,t->uac[t->relaied_reply_branch].added_rr); get_routing_info(rpl, 0, &skip_rrs, &contact, &rr_set); dlg_update_routing( dlg, leg, &rr_set, &contact ); if( rr_set.s ) @@ -441,7 +445,7 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) } } push_reply_in_dialog( rpl, t, dlg,&mangled_from,&mangled_to); - if((dlg->flags & DLG_FLAG_TOPHIDING) && + if((dlg->flags & DLG_FLAG_TOPHIDING) && dlg_th_onreply(dlg, rpl,req, 1, DLG_DIR_UPSTREAM) < 0) LM_ERR("Failed to transform the reply for topology hiding\n"); } else { @@ -458,8 +462,12 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) /* reference and attached to script */ ref_dlg(dlg,1); current_dlg_pointer = t->dialog_ctx; - return; } + return; + } + if (type==TMCB_RESPONSE_OUT) { + if (dlg->state == DLG_STATE_CONFIRMED_NA && replication_dests) + replicate_dialog_created(dlg); } if (type==TMCB_TRANS_DELETED) @@ -471,12 +479,13 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) else event = DLG_EVENT_RPL3xx; - next_state_dlg( dlg, event, &old_state, &new_state, &unref); + last_dst_leg = DLG_CALLER_LEG; + next_state_dlg(dlg, event, DLG_DIR_UPSTREAM, &old_state, &new_state, + &unref, 0); - if (new_state==DLG_STATE_EARLY) { + if (new_state==DLG_STATE_EARLY && old_state!=DLG_STATE_EARLY) { run_dlg_callbacks(DLGCB_EARLY, dlg, rpl, DLG_DIR_UPSTREAM, 0); - if (old_state!=DLG_STATE_EARLY) - if_update_stat(dlg_enable_stats, early_dlgs, 1); + if_update_stat(dlg_enable_stats, early_dlgs, 1); return; } @@ -517,7 +526,7 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) } } - /* save the settings to the database, + /* save the settings to the database, * if realtime saving mode configured- save dialog now * else: the next time the timer will fire the update*/ dlg->flags |= DLG_FLAG_NEW; @@ -538,8 +547,10 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) LM_DBG("dialog %p failed (negative reply)\n", dlg); /*destroy linkers */ - destroy_linkers(dlg->profile_links); + dlg_lock_dlg(dlg); + destroy_linkers(dlg->profile_links, 0); dlg->profile_links = NULL; + dlg_unlock_dlg(dlg); /* dialog setup not completed (3456XX) */ run_dlg_callbacks( DLGCB_FAILED, dlg, rpl, DLG_DIR_UPSTREAM, 0); @@ -691,8 +702,8 @@ static void dlg_seq_down_onreply_mod_cseq(struct cell* t, int type, if (update_msg_cseq((struct sip_msg *)param->rpl,&((dlg_cseq_wrapper *)*param->param)->cseq,0) != 0) LM_ERR("failed to update CSEQ in msg\n"); - if (type==TMCB_RESPONSE_FWDED && - (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN) { + if (type==TMCB_RESPONSE_FWDED && + (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN) { run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl, DLG_DIR_DOWNSTREAM, 0); return; @@ -726,8 +737,8 @@ static void dlg_seq_down_onreply(struct cell* t, int type, if (shutdown_done || dlg==0) return; - if (type==TMCB_RESPONSE_FWDED && - (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN) { + if (type==TMCB_RESPONSE_FWDED && + (dlg->cbs.types)&DLGCB_RESPONSE_WITHIN) { run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl, DLG_DIR_DOWNSTREAM, 0); return; @@ -736,27 +747,10 @@ static void dlg_seq_down_onreply(struct cell* t, int type, return; } -inline static int get_dlg_timeout(struct sip_msg *req) -{ - pv_value_t pv_val; - - if( timeout_avp && pv_get_spec_value( req, timeout_avp, &pv_val)==0 - && pv_val.flags&PV_VAL_INT && pv_val.ri>0 ) { - return pv_val.ri; - } - LM_DBG("invalid AVP value, use default timeout\n"); - return default_timeout; -} - -inline static int get_dlg_timeout_update(struct sip_msg *req) +inline static int get_dlg_timeout(struct sip_msg *msg) { - pv_value_t pv_val; - - if( timeout_avp && pv_get_spec_value( req, timeout_avp, &pv_val)==0 - && pv_val.flags&PV_VAL_INT && pv_val.ri>0 ) { - return pv_val.ri; - } - return 0; + return ((dlg_tmp_timeout != -1 && dlg_tmp_timeout_id == msg->id) ? + dlg_tmp_timeout: default_timeout); } @@ -808,7 +802,7 @@ void dlg_onreq(struct cell* t, int type, struct tmcb_params *param) /* fully init dialog -> check if attached to the transaction */ if (t->dialog_ctx==NULL) { - /* set a callback to remove the ref when transaction + /* set a callback to remove the ref when transaction * is destroied */ if ( d_tmb.register_tmcb( NULL, t, TMCB_TRANS_DELETED, tmcb_unreference_dialog, (void*)current_dlg_pointer, NULL)<0){ @@ -823,7 +817,7 @@ void dlg_onreq(struct cell* t, int type, struct tmcb_params *param) return; } - /* dialog was previously created by create_dialog() + /* dialog was previously created by create_dialog() -> just do the last settings */ run_create_callbacks( current_dlg_pointer, param->req); @@ -831,8 +825,6 @@ void dlg_onreq(struct cell* t, int type, struct tmcb_params *param) current_dlg_pointer->initial_t_hash_index = t->hash_index; current_dlg_pointer->initial_t_label = t->label; - current_dlg_pointer->lifetime = get_dlg_timeout(param->req); - t->dialog_ctx = (void*)current_dlg_pointer; /* dialog is fully initialized */ @@ -845,7 +837,7 @@ int dlg_create_dialog(struct cell* t, struct sip_msg *req,unsigned int flags) { struct dlg_cell *dlg; str s; - int extra_ref; + int extra_ref,types; /* module is stricly designed for dialog calls */ if (req->first_line.u.request.method_value!=METHOD_INVITE) @@ -909,9 +901,14 @@ int dlg_create_dialog(struct cell* t, struct sip_msg *req,unsigned int flags) goto error; } - if ( d_tmb.register_tmcb( req, t, - TMCB_RESPONSE_PRE_OUT|TMCB_RESPONSE_FWDED|TMCB_TRANS_CANCELLED, - dlg_onreply, (void*)dlg, unreference_dialog_create)<0 ) { + types = TMCB_RESPONSE_PRE_OUT|TMCB_RESPONSE_FWDED|TMCB_TRANS_CANCELLED; + /* replicate dialogs after the 200 OK was fwded - speed & after all msg + * processing was done ( eg. ACC ) */ + if (replication_dests) + types |= TMCB_RESPONSE_OUT; + + if ( d_tmb.register_tmcb( req, t,types,dlg_onreply, + (void*)dlg, unreference_dialog_create)<0 ) { LM_ERR("failed to register TMCB\n"); goto error; } @@ -924,11 +921,11 @@ int dlg_create_dialog(struct cell* t, struct sip_msg *req,unsigned int flags) LM_DBG("t hash_index = %u, t label = %u\n",t->hash_index,t->label); dlg->initial_t_hash_index = t->hash_index; dlg->initial_t_label = t->label; - dlg->lifetime = get_dlg_timeout(req); t->dialog_ctx = (void*) dlg; dlg->flags |= DLG_FLAG_ISINIT; } + dlg->lifetime = get_dlg_timeout(req); if_update_stat( dlg_enable_stats, processed_dlgs, 1); @@ -958,7 +955,7 @@ static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req, static inline int switch_cseqs(struct dlg_cell *dlg,unsigned int leg_no) { str* r_cseq,*prev_cseq; - + r_cseq = &dlg->legs[leg_no].r_cseq; prev_cseq = &dlg->legs[leg_no].prev_cseq; @@ -980,14 +977,14 @@ static inline int switch_cseqs(struct dlg_cell *dlg,unsigned int leg_no) memcpy( prev_cseq->s, r_cseq->s, r_cseq->len ); prev_cseq->len = r_cseq->len; - + LM_DBG("prev_cseq = %.*s for leg %d\n",prev_cseq->len,prev_cseq->s,leg_no); return 0; } static inline void log_bogus_dst_leg(struct dlg_cell *dlg) { - if (last_dst_leg>=dlg->legs_no[DLG_LEGS_USED]) + if (last_dst_leg>=dlg->legs_no[DLG_LEGS_USED]) LM_CRIT("bogus dst leg %d in state %d for dlg %p [%u:%u] with " "clid '%.*s' and tags '%.*s' '%.*s'. legs used %d\n", last_dst_leg,dlg->state, dlg, dlg->h_entry, dlg->h_id, @@ -1009,7 +1006,6 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) int old_state; int unref; int event; - int timeout; unsigned int update_val; unsigned int dir,dst_leg,src_leg; int ret = 0,ok = 1; @@ -1017,8 +1013,8 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) str *msg_cseq; char *final_cseq; - /* as this callback is triggered from loose_route, which can be - accidentaly called more than once from script, we need to be sure + /* as this callback is triggered from loose_route, which can be + accidentaly called more than once from script, we need to be sure we do this only once !*/ if (current_dlg_pointer) return; @@ -1068,25 +1064,32 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) return; } if (match_dialog(dlg,&callid,&ftag,&ttag,&dir, &dst_leg )==0){ - LM_WARN("tight matching failed for %.*s with " - "callid='%.*s'/%d," - " ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n", - req->first_line.u.request.method.len, - req->first_line.u.request.method.s, - callid.len, callid.s, callid.len, - ftag.len, ftag.s, ftag.len, - ttag.len, ttag.s, ttag.len, dir); - LM_WARN("dialog identification elements are " - "callid='%.*s'/%d, " - "caller tag='%.*s'/%d, callee tag='%.*s'/%d\n", - dlg->callid.len, dlg->callid.s, dlg->callid.len, - dlg->legs[DLG_CALLER_LEG].tag.len, - dlg->legs[DLG_CALLER_LEG].tag.s, - dlg->legs[DLG_CALLER_LEG].tag.len, - dlg->legs[callee_idx(dlg)].tag.len, - ZSW(dlg->legs[callee_idx(dlg)].tag.s), - dlg->legs[callee_idx(dlg)].tag.len); + if (!accept_replicated_dlg) { + /* not an error when accepting replicating dialogs - + we might have generated a different h_id when + accepting the replicated dialog */ + LM_WARN("tight matching failed for %.*s with " + "callid='%.*s'/%d," + " ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n", + req->first_line.u.request.method.len, + req->first_line.u.request.method.s, + callid.len, callid.s, callid.len, + ftag.len, ftag.s, ftag.len, + ttag.len, ttag.s, ttag.len, dir); + LM_WARN("dialog identification elements are " + "callid='%.*s'/%d, " + "caller tag='%.*s'/%d, callee tag='%.*s'/%d\n", + dlg->callid.len, dlg->callid.s, dlg->callid.len, + dlg->legs[DLG_CALLER_LEG].tag.len, + dlg->legs[DLG_CALLER_LEG].tag.s, + dlg->legs[DLG_CALLER_LEG].tag.len, + dlg->legs[callee_idx(dlg)].tag.len, + ZSW(dlg->legs[callee_idx(dlg)].tag.s), + dlg->legs[callee_idx(dlg)].tag.len); + } unref_dlg(dlg, 1); + /* potentially fall through to SIP-wise dialog matching, + depending on seq_match_mode */ dlg = NULL; } } @@ -1123,8 +1126,7 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) /* save last_dst_leg before running state machine * helpful for logging various bogus cases according to the RFC */ last_dst_leg = dst_leg; - - next_state_dlg( dlg, event, &old_state, &new_state, &unref); + next_state_dlg( dlg, event, dir, &old_state, &new_state, &unref, 0); /* set current dialog - it will keep a ref! */ set_current_dialog(dlg); @@ -1138,11 +1140,19 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) /* run actions for the transition */ if (event==DLG_EVENT_REQBYE && new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) { - + /*destroy linkers */ - destroy_linkers(dlg->profile_links); + dlg_lock_dlg(dlg); + destroy_linkers(dlg->profile_links, 0); dlg->profile_links = NULL; - + dlg_unlock_dlg(dlg); + + if (!dlg->terminate_reason.s) { + if (last_dst_leg == 0) + init_dlg_term_reason(dlg,"Upstream BYE",sizeof("Upstream BYE")-1); + else + init_dlg_term_reason(dlg,"Downstream BYE",sizeof("Downstream BYE")-1); + } LM_DBG("BYE successfully processed - dst_leg = %d\n",last_dst_leg); @@ -1224,16 +1234,22 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) LM_DBG("sequential request successfully processed (dst_leg=%d)\n", dst_leg); + if (dlg_tmp_timeout != -1 && dlg_tmp_timeout_id == req->id) { + dlg->lifetime = dlg_tmp_timeout; + dlg->lifetime_dirty = 1; + } else { + dlg->lifetime_dirty = 0; + } + /* within dialog request */ run_dlg_callbacks( DLGCB_REQ_WITHIN, dlg, req, dir, 0); - timeout = get_dlg_timeout_update(req); /* update timer during sequential request? */ - if (timeout != 0) { - dlg->lifetime = timeout; + if (dlg->lifetime_dirty) { if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) LM_ERR("failed to update dialog lifetime\n"); } + LM_DBG("dialog_timeout: %d\n", dlg->lifetime); if ( event!=DLG_EVENT_REQACK ) { if (dst_leg==-1 || switch_cseqs(dlg, dst_leg) != 0 || @@ -1254,13 +1270,13 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) } } - if (dlg->flags & DLG_FLAG_PING_CALLER || + if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { dlg_lock (d_table, d_entry); if (dlg->legs[dst_leg].last_gen_cseq) { - + update_val = ++(dlg->legs[dst_leg].last_gen_cseq); dlg_unlock( d_table, d_entry ); @@ -1277,11 +1293,14 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) dlg->flags |= DLG_FLAG_CHANGED; if ( dlg_db_mode==DB_MODE_REALTIME ) update_dialog_dbinfo(dlg); + + if (replication_dests) + replicate_dialog_updated(dlg); } } else { - if (dlg->flags & DLG_FLAG_PING_CALLER || + if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { dlg_lock (d_table, d_entry); @@ -1294,7 +1313,7 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) LM_ERR("failed to update ACK msg cseq\n"); } } - else + else dlg_unlock( d_table, d_entry ); } } @@ -1377,6 +1396,9 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) dlg->flags |= DLG_FLAG_CHANGED; if(dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); + + if (replication_dests) + replicate_dialog_updated(dlg); } return; @@ -1403,6 +1425,9 @@ void dlg_ontimeout( struct dlg_tl *tl) if ( (dlg->flags&DLG_FLAG_BYEONTIMEOUT) && (dlg->state==DLG_STATE_CONFIRMED_NA || dlg->state==DLG_STATE_CONFIRMED)) { + + init_dlg_term_reason(dlg,"Lifetime Timeout",sizeof("Lifetime Timeout")-1); + /* we just send the BYEs in both directions */ dlg_end_dlg( dlg, NULL); /* dialog is no longer refed by timer; from now one it is refed @@ -1413,7 +1438,10 @@ void dlg_ontimeout( struct dlg_tl *tl) return ; } - next_state_dlg( dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref); + /* act like as if we've received a BYE from caller */ + last_dst_leg = dlg->legs_no[DLG_LEG_200OK]; + next_state_dlg( dlg, DLG_EVENT_REQBYE, DLG_DIR_DOWNSTREAM, &old_state, + &new_state, &unref, 0); if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) { LM_DBG("timeout for dlg with CallID '%.*s' and tags '%.*s' '%.*s'\n", @@ -1424,8 +1452,10 @@ void dlg_ontimeout( struct dlg_tl *tl) ZSW(dlg->legs[callee_idx(dlg)].tag.s)); /*destroy linkers */ - destroy_linkers(dlg->profile_links); + dlg_lock_dlg(dlg); + destroy_linkers(dlg->profile_links, 0); dlg->profile_links = NULL; + dlg_unlock_dlg(dlg); /* dialog timeout */ run_dlg_callbacks( DLGCB_EXPIRED, dlg, 0, DLG_DIR_NONE, 0); @@ -1518,20 +1548,23 @@ int fix_route_dialog(struct sip_msg *req,struct dlg_cell *dlg) LM_ERR("failed to parse headers when looking after ROUTEs\n"); return -1; } - + buf = req->buf; if (req->route) { - for (it=req->route;it;it=it->sibling) + for (it=req->route;it;it=it->sibling) { + if (it->parsed && ((rr_t*)it->parsed)->deleted) + continue; if ((lmp = del_lump(req,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { LM_ERR("del_lump failed \n"); return -1; } + } } if ( leg->route_set.len !=0 && leg->route_set.s) { - lmp = anchor_lump(req,req->headers->name.s - buf,0,0); + lmp = anchor_lump(req,req->headers->name.s - buf,0); if (lmp == 0) { LM_ERR("failed anchoring new lump\n"); @@ -1556,7 +1589,7 @@ int fix_route_dialog(struct sip_msg *req,struct dlg_cell *dlg) pkg_free(route); return -1; } - + LM_DBG("Setting route header to <%s> \n",route); if (parse_rr_body(leg->route_set.s,leg->route_set.len,&head) != 0) { @@ -1584,11 +1617,13 @@ int fix_route_dialog(struct sip_msg *req,struct dlg_cell *dlg) LM_ERR("failed to parse headers when looking after ROUTEs\n"); return -1; } - + buf = req->buf; if (req->route) { for (it=req->route;it;it=it->sibling) + if (it->parsed && ((rr_t*)it->parsed)->deleted) + continue; if ((lmp = del_lump(req,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { LM_ERR("del_lump failed \n"); return -1; @@ -1616,7 +1651,7 @@ int fix_route_dialog(struct sip_msg *req,struct dlg_cell *dlg) return -1; } - lmp = anchor_lump(req,req->headers->name.s - buf,0,0); + lmp = anchor_lump(req,req->headers->name.s - buf,0); if (lmp == 0) { LM_ERR("failed anchoring new lump\n"); free_rr(&head); @@ -1649,14 +1684,14 @@ int fix_route_dialog(struct sip_msg *req,struct dlg_cell *dlg) } if (lmp == NULL) { - lmp = anchor_lump(req,req->headers->name.s - buf,0,0); + lmp = anchor_lump(req,req->headers->name.s - buf,0); if (lmp == 0) { LM_ERR("failed anchoring new lump\n"); return -1; } } - + if (leg->contact.len && leg->contact.s) { size = leg->contact.len + ROUTE_PREF_LEN + ROUTE_SUFF_LEN; remote_contact = pkg_malloc(size); @@ -1805,7 +1840,7 @@ int dlg_validate_dialog( struct sip_msg* req, struct dlg_cell *dlg) return 0; } -int terminate_dlg(unsigned int h_entry, unsigned int h_id) +int terminate_dlg(unsigned int h_entry, unsigned int h_id,str *reason) { struct dlg_cell * dlg = NULL; int ret = 0; @@ -1814,7 +1849,9 @@ int terminate_dlg(unsigned int h_entry, unsigned int h_id) if(!dlg) return 0; - + + init_dlg_term_reason(dlg,reason->s,reason->len); + if ( dlg_end_dlg( dlg, 0) ) { LM_ERR("Failed to end dialog"); ret = -1; diff --git a/modules/dialog/dlg_handlers.h b/modules/dialog/dlg_handlers.h index 4cd45627d18..dbbd36e857e 100644 --- a/modules/dialog/dlg_handlers.h +++ b/modules/dialog/dlg_handlers.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -58,8 +58,10 @@ typedef struct _dlg_cseq dlg_cseq_wrapper; typedef int (*create_dlg_f)(struct sip_msg *req,int flags); -void init_dlg_handlers(char *rr_param, - pv_spec_t *timeout_avp, int default_timeout); +typedef void (*set_mod_flag_f)(struct dlg_cell *dlg, unsigned int flags); +typedef int (*is_mod_flag_set_f)(struct dlg_cell *dlg, unsigned int flags); + +void init_dlg_handlers(int default_timeout); void destroy_dlg_handlers(); @@ -71,12 +73,14 @@ void dlg_onroute(struct sip_msg* req, str *rr_param, void *param); void dlg_ontimeout( struct dlg_tl *tl); +typedef int (*validate_dialog_f) (struct sip_msg* req, struct dlg_cell *dlg); int dlg_validate_dialog( struct sip_msg* req, struct dlg_cell *dlg); +typedef int (*fix_route_dialog_f) (struct sip_msg *req,struct dlg_cell *dlg); int fix_route_dialog(struct sip_msg *req,struct dlg_cell *dlg); -int terminate_dlg(unsigned int h_entry, unsigned int h_id); -typedef int (*terminate_dlg_f)(unsigned int h_entry, unsigned int h_id); +int terminate_dlg(unsigned int h_entry, unsigned int h_id,str *reason); +typedef int (*terminate_dlg_f)(unsigned int h_entry, unsigned int h_id,str *reason); void unreference_dialog(void *dialog); diff --git a/modules/dialog/dlg_hash.c b/modules/dialog/dlg_hash.c index 33cbfa8eca3..ef1140d2797 100644 --- a/modules/dialog/dlg_hash.c +++ b/modules/dialog/dlg_hash.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -25,16 +25,16 @@ * 2007-03-06 syncronized state machine added for dialog state. New tranzition * design based on events; removed num_1xx and num_2xx (bogdan) * 2007-04-30 added dialog matching without DID (dialog ID), but based only - * on RFC3261 elements - based on an original patch submitted + * on RFC3261 elements - based on an original patch submitted * by Michel Bensoussan (bogdan) * 2007-07-06 additional information stored in order to save it in the db: - * cseq, route_set, contact and sock_info for both caller and + * cseq, route_set, contact and sock_info for both caller and * callee (ancuta) * 2007-07-10 Optimized dlg_match_mode 2 (DID_NONE), it now employs a proper - * hash table lookup and isn't dependant on the is_direction - * function (which requires an RR param like dlg_match_mode 0 - * anyways.. ;) ; based on a patch from - * Tavis Paquette + * hash table lookup and isn't dependant on the is_direction + * function (which requires an RR param like dlg_match_mode 0 + * anyways.. ;) ; based on a patch from + * Tavis Paquette * and Peter Baer (bogdan) * 2008-04-17 added new type of callback to be triggered right before the * dialog is destroyed (deleted from memory) (bogdan) @@ -55,8 +55,10 @@ #include "../../md5utils.h" #include "../../parser/parse_to.h" #include "../tm/tm_load.h" +#include "../../script_cb.h" #include "dlg_hash.h" #include "dlg_profile.h" +#include "dlg_replication.h" #define MAX_LDG_LOCKS 2048 #define MIN_LDG_LOCKS 2 @@ -69,8 +71,6 @@ extern int last_dst_leg; struct dlg_table *d_table = NULL; struct dlg_cell *current_dlg_pointer = NULL ; -#define dlg_hash(_callid) core_hash(_callid, 0, d_table->size) - int dialog_cleanup( struct sip_msg *msg, void *param ) { @@ -79,9 +79,10 @@ int dialog_cleanup( struct sip_msg *msg, void *param ) current_dlg_pointer = NULL; } last_dst_leg = -1; + dlg_tmp_timeout = -1; + dlg_tmp_timeout_id = -1; - /* need to return non-zero - 0 will break the exec of the request */ - return 1; + return SCB_RUN_ALL; } @@ -96,8 +97,11 @@ struct dlg_cell *get_current_dialog(void) } else { /* use current transaction to get dialog */ trans = d_tmb.t_gett(); - if (trans==NULL || trans==T_UNDEFINED) - return NULL; + if (trans==NULL || trans==T_UNDEFINED) { + /* no transaction - perhaps internally terminated + dialog - trust the module */ + return current_dlg_pointer; + } return (struct dlg_cell*)trans->dialog_ctx; } } @@ -163,7 +167,7 @@ static inline void free_dlg_dlg(struct dlg_cell *dlg) destroy_dlg_callbacks_list(dlg->cbs.first); if (dlg->profile_links) - destroy_linkers(dlg->profile_links); + destroy_linkers(dlg->profile_links, 0); if (dlg->legs) { for( i=0 ; ilegs_no[DLG_LEGS_USED] ; i++) { @@ -189,6 +193,8 @@ static inline void free_dlg_dlg(struct dlg_cell *dlg) shm_free(dv); } + if (dlg->terminate_reason.s) + shm_free(dlg->terminate_reason.s); shm_free(dlg); } @@ -307,21 +313,22 @@ struct dlg_cell* build_new_dlg( str *callid, str *from_uri, str *to_uri, /* first time it will called for a CALLER leg - at that time there will be no leg allocated, so automatically CALLER gets the first position, while the CALLEE legs will follow into the array in the same order they came */ -int dlg_add_leg_info(struct dlg_cell *dlg, str* tag, str *rr, +int dlg_add_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,str *cseq, struct socket_info *sock, str *mangled_from,str *mangled_to) { - struct dlg_leg* leg; + struct dlg_leg* leg,*new_legs; rr_t *head = NULL, *rrp; if ( (dlg->legs_no[DLG_LEGS_ALLOCED]-dlg->legs_no[DLG_LEGS_USED])==0) { - dlg->legs_no[DLG_LEGS_ALLOCED] += 2; - dlg->legs = (struct dlg_leg*)shm_realloc(dlg->legs, - dlg->legs_no[DLG_LEGS_ALLOCED]*sizeof(struct dlg_leg)); - if (dlg->legs==NULL) { + new_legs = (struct dlg_leg*)shm_realloc(dlg->legs, + (dlg->legs_no[DLG_LEGS_ALLOCED]+2)*sizeof(struct dlg_leg)); + if (new_legs==NULL) { LM_ERR("Failed to resize legs array\n"); return -1; } + dlg->legs=new_legs; + dlg->legs_no[DLG_LEGS_ALLOCED] += 2; memset( dlg->legs+dlg->legs_no[DLG_LEGS_ALLOCED]-2, 0, 2*sizeof(struct dlg_leg)); } @@ -429,7 +436,7 @@ int dlg_add_leg_info(struct dlg_cell *dlg, str* tag, str *rr, /* set cseq for caller to 0 * future requests to the caller leg will update this - * needed for proper validation of in-dialog requests + * needed for proper validation of in-dialog requests * * TM also increases this value by one, if dialog * is terminated from the middle, so 0 is ok*/ @@ -459,7 +466,7 @@ int dlg_add_leg_info(struct dlg_cell *dlg, str* tag, str *rr, int dlg_update_cseq(struct dlg_cell * dlg, unsigned int leg, str *cseq,int inv) { str* update_cseq; - + if (inv == 1) update_cseq = &dlg->legs[leg].inv_cseq; else @@ -758,8 +765,8 @@ static inline void log_next_state_dlg(const int event, } -void next_state_dlg(struct dlg_cell *dlg, int event, - int *old_state, int *new_state, int *unref) +void next_state_dlg(struct dlg_cell *dlg, int event, int dir, int *old_state, + int *new_state, int *unref, char is_replicated) { struct dlg_entry *d_entry; @@ -784,7 +791,7 @@ void next_state_dlg(struct dlg_cell *dlg, int event, unref_dlg_unsafe(dlg,1,d_entry); /* unref from TM CBs*/ break; case DLG_STATE_DELETED: - /* as the dialog aleady is in DELETE state, it is + /* as the dialog aleady is in DELETE state, it is dangerous to directly unref it from here as it might be last ref -> dialog will be destroied and we will end up with a dangling pointer :D - bogdan */ @@ -851,6 +858,10 @@ void next_state_dlg(struct dlg_cell *dlg, int event, switch (dlg->state) { case DLG_STATE_CONFIRMED_NA: case DLG_STATE_CONFIRMED: + if (dir == DLG_DIR_DOWNSTREAM && last_dst_leg!=dlg->legs_no[DLG_LEG_200OK] ) + /* to end the call, the BYE must be received + * on the same leg as the 200 OK for INVITE */ + break; dlg->flags |= DLG_FLAG_HASBYE; dlg->state = DLG_STATE_DELETED; *unref = 1; /* unref from hash -> dialog ended */ @@ -860,7 +871,7 @@ void next_state_dlg(struct dlg_cell *dlg, int event, default: /* only case for BYEs in early or unconfirmed states * is for requests generate by caller or callee. - * We never internally generate BYEs for early dialogs + * We never internally generate BYEs for early dialogs * * RFC says caller may send BYEs for early dialogs, * while the callee side MUST not send such requests*/ @@ -899,23 +910,36 @@ void next_state_dlg(struct dlg_cell *dlg, int event, dlg_unlock( d_table, d_entry); + if (!is_replicated && replication_dests && + (*old_state == DLG_STATE_CONFIRMED_NA || *old_state == DLG_STATE_CONFIRMED) && + dlg->state == DLG_STATE_DELETED) + replicate_dialog_deleted(dlg); + + LM_DBG("dialog %p changed from state %d to " "state %d, due event %d\n",dlg,*old_state,*new_state,event); } /**************************** MI functions ******************************/ +static char *dlg_val_buf; static inline int internal_mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context) { struct mi_node* node= NULL; struct mi_node* node1 = NULL; + struct mi_node* node2 = NULL; + struct mi_node* node3 = NULL; struct mi_attr* attr= NULL; struct dlg_profile_link *dl; struct dlg_val* dv; int len; char* p; - int i; + int i, j; + time_t _ts; + struct tm* t; + char date_buf[MI_DATE_BUF_LEN]; + int date_buf_len; node = add_mi_node_child(rpl, 0, "dialog",6 , 0, 0 ); if (node==0) @@ -936,16 +960,40 @@ static inline int internal_mi_print_dlg(struct mi_node *rpl, if (node1==0) goto error; - p= int2str((unsigned long)dlg->start_ts, &len); + _ts = (time_t)dlg->start_ts; + p= int2str((unsigned long)_ts, &len); node1 = add_mi_node_child(node,MI_DUP_VALUE,"timestart",9, p, len); if (node1==0) goto error; + if (_ts) { + t = localtime(&_ts); + date_buf_len = strftime(date_buf, MI_DATE_BUF_LEN - 1, + "%Y-%m-%d %H:%M:%S", t); + if (date_buf_len != 0) { + node1 = add_mi_node_child(node,MI_DUP_VALUE, "datestart", 9, + date_buf, date_buf_len); + if (node1==0) + goto error; + } + } - p= int2str((unsigned long)(dlg->tl.timeout?((unsigned int)time(0) + - dlg->tl.timeout - get_ticks()):0), &len); + _ts = (time_t)(dlg->tl.timeout?((unsigned int)time(0) + + dlg->tl.timeout - get_ticks()):0); + p= int2str((unsigned long)_ts, &len); node1 = add_mi_node_child(node,MI_DUP_VALUE, "timeout", 7, p, len); if (node1==0) goto error; + if (_ts) { + t = localtime(&_ts); + date_buf_len = strftime(date_buf, MI_DATE_BUF_LEN - 1, + "%Y-%m-%d %H:%M:%S", t); + if (date_buf_len != 0) { + node1 = add_mi_node_child(node,MI_DUP_VALUE, "dateout", 7, + date_buf, date_buf_len); + if (node1==0) + goto error; + } + } node1 = add_mi_node_child(node, MI_DUP_VALUE, "callid", 6, dlg->callid.s, dlg->callid.len); @@ -988,44 +1036,52 @@ static inline int internal_mi_print_dlg(struct mi_node *rpl, goto error; node1 = add_mi_node_child(node, 0,"caller_bind_addr",16, - dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str.s, + dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str.s, dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str.len); if(node1 == 0) goto error; } + node1 = add_mi_node_child(node, MI_IS_ARRAY, "CALLEES", 7, NULL, 0); + if(node1 == 0) + goto error; + for( i=1 ; i < dlg->legs_no[DLG_LEGS_USED] ; i++ ) { - node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_tag", 10, + node2 = add_mi_node_child(node1, 0, "callee", 6, NULL, 0); + if(node2 == 0) + goto error; + + node3 = add_mi_node_child(node2, MI_DUP_VALUE, "callee_tag", 10, dlg->legs[i].tag.s, dlg->legs[i].tag.len); - if(node1 == 0) + if(node3 == 0) goto error; - node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_contact", 14, + node3 = add_mi_node_child(node2, MI_DUP_VALUE, "callee_contact", 14, dlg->legs[i].contact.s, dlg->legs[i].contact.len); - if(node1 == 0) + if(node3 == 0) goto error; - node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_cseq", 11, + node3 = add_mi_node_child(node2, MI_DUP_VALUE, "caller_cseq", 11, dlg->legs[i].r_cseq.s, dlg->legs[i].r_cseq.len); - if(node1 == 0) + if(node3 == 0) goto error; - node1 = add_mi_node_child(node, MI_DUP_VALUE,"callee_route_set",16, + node3 = add_mi_node_child(node2, MI_DUP_VALUE,"callee_route_set",16, dlg->legs[i].route_set.s, dlg->legs[i].route_set.len); - if(node1 == 0) + if(node3 == 0) goto error; if (dlg->legs[i].bind_addr) { - node1 = add_mi_node_child(node, 0, + node3 = add_mi_node_child(node2, 0, "callee_bind_addr",16, - dlg->legs[i].bind_addr->sock_str.s, + dlg->legs[i].bind_addr->sock_str.s, dlg->legs[i].bind_addr->sock_str.len); } else { - node1 = add_mi_node_child(node, 0, + node3 = add_mi_node_child(node2, 0, "callee_bind_addr",16,0,0); } - if(node1 == 0) + if(node3 == 0) goto error; } @@ -1033,16 +1089,52 @@ static inline int internal_mi_print_dlg(struct mi_node *rpl, node1 = add_mi_node_child(node, 0, "context", 7, 0, 0); if(node1 == 0) goto error; - /* print dlg values -> iterate the list */ - for( dv=dlg->vals ; dv ; dv=dv->next) { - addf_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("value"), - "%.*s = %.*s",dv->name.len,dv->name.s,dv->val.len,dv->val.s); + if (dlg->vals) { + node2 = add_mi_node_child(node1, 0, "values", 6, 0, 0); + if(node2 == 0) + goto error; + /* print dlg values -> iterate the list */ + for( dv=dlg->vals ; dv ; dv=dv->next) { + /* escape non-printable chars */ + p = pkg_realloc(dlg_val_buf, 4 * dv->val.len + 1); + if (!p) { + LM_ERR("not enough mem to allocate: %d\n", dv->val.len); + continue; + } + for (i = 0, j = 0; i < dv->val.len; i++) { + if (dv->val.s[i] < 0x20 || dv->val.s[i] >= 0x7F) { + p[j++] = '\\'; + switch ((unsigned char)dv->val.s[i]) { + case 0x8: p[j++] = 'b'; break; + case 0x9: p[j++] = 't'; break; + case 0xA: p[j++] = 'n'; break; + case 0xC: p[j++] = 'f'; break; + case 0xD: p[j++] = 'r'; break; + default: + p[j++] = 'x'; + j += snprintf(&p[j], 3, "%02x", + (unsigned char)dv->val.s[i]); + break; + } + } else { + p[j++] = dv->val.s[i]; + } + } + add_mi_node_child(node2, MI_DUP_NAME|MI_DUP_VALUE,dv->name.s,dv->name.len, + p,j); + dlg_val_buf = p; + } } /* print dlg profiles */ - for( dl=dlg->profile_links ; dl ; dl=dl->next) { - addf_mi_node_child(node1, MI_DUP_VALUE, MI_SSTR("profile"), - "%.*s = %.*s",dl->profile->name.len,dl->profile->name.s, - dl->value.len,ZSW(dl->value.s)); + if (dlg->profile_links) { + node3 = add_mi_node_child(node1, MI_IS_ARRAY, "profiles", 8, 0, 0); + if(node3 == 0) + goto error; + for( dl=dlg->profile_links ; dl ; dl=dl->next) { + add_mi_node_child(node3, MI_DUP_NAME|MI_DUP_VALUE, + dl->profile->name.s,dl->profile->name.len, + ZSW(dl->value.s),dl->value.len); + } } /* print external context info */ run_dlg_callbacks( DLGCB_MI_CONTEXT, dlg, NULL, @@ -1109,7 +1201,7 @@ static int internal_mi_print_dlgs(struct mi_root *rpl_tree,struct mi_node *rpl, } -static int match_downstream_dialog(struct dlg_cell *dlg, +static int match_downstream_dialog(struct dlg_cell *dlg, str *callid, str *ftag) { if (dlg->callid.len!=callid->len || @@ -1205,6 +1297,7 @@ struct mi_root * mi_print_dlgs(struct mi_root *cmd_tree, void *param ) if (rpl_tree==0) goto error; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; if (dlg==NULL) { if ( internal_mi_print_dlgs(rpl_tree, rpl, 0, idx, cnt)!=0 ) @@ -1242,6 +1335,7 @@ struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd_tree, void *param ) if (rpl_tree==0) goto error; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; if (dlg==NULL) { if ( internal_mi_print_dlgs(rpl_tree, rpl, 1, idx, cnt)!=0 ) diff --git a/modules/dialog/dlg_hash.h b/modules/dialog/dlg_hash.h index 0b8159ad2c1..b7ad72a36d4 100644 --- a/modules/dialog/dlg_hash.h +++ b/modules/dialog/dlg_hash.h @@ -15,19 +15,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2006-04-14 initial version (bogdan) - * 2006-11-28 Added num_100s and num_200s to dlg_cell, to aid in adding + * 2006-11-28 Added num_100s and num_200s to dlg_cell, to aid in adding * statistics tracking of the number of early, and active dialogs. * (Jeffrey Magder - SOMA Networks) * 2007-03-06 syncronized state machine added for dialog state. New tranzition * design based on events; removed num_1xx and num_2xx (bogdan) - * 2007-07-06 added flags, cseq, contact, route_set and bind_addr + * 2007-07-06 added flags, cseq, contact, route_set and bind_addr * to struct dlg_cell in order to store these information into db * (ancuta) * 2008-04-17 added new dialog flag to avoid state tranzitions from DELETED to @@ -62,16 +62,18 @@ #define DLG_EVENT_REQBYE 7 #define DLG_EVENT_REQ 8 -#define DLG_FLAG_NEW (1<<0) -#define DLG_FLAG_CHANGED (1<<1) -#define DLG_FLAG_HASBYE (1<<2) -#define DLG_FLAG_BYEONTIMEOUT (1<<3) -#define DLG_FLAG_ISINIT (1<<4) -#define DLG_FLAG_PING_CALLER (1<<5) -#define DLG_FLAG_PING_CALLEE (1<<6) -#define DLG_FLAG_TOPHIDING (1<<7) -#define DLG_FLAG_VP_CHANGED (1<<8) -#define DLG_FLAG_DB_DELETED (1<<9) +#define DLG_FLAG_NEW (1<<0) +#define DLG_FLAG_CHANGED (1<<1) +#define DLG_FLAG_HASBYE (1<<2) +#define DLG_FLAG_BYEONTIMEOUT (1<<3) +#define DLG_FLAG_ISINIT (1<<4) +#define DLG_FLAG_PING_CALLER (1<<5) +#define DLG_FLAG_PING_CALLEE (1<<6) +#define DLG_FLAG_TOPHIDING (1<<7) +#define DLG_FLAG_VP_CHANGED (1<<8) +#define DLG_FLAG_DB_DELETED (1<<9) +#define DLG_FLAG_TOPH_KEEP_USER (1<<10) +#define DLG_FLAG_TOPH_HIDE_CALLID (1<<11) #define DLG_CALLER_LEG 0 #define DLG_FIRST_CALLEE_LEG 1 @@ -112,14 +114,17 @@ struct dlg_cell unsigned int h_entry; unsigned int state; unsigned int lifetime; + unsigned int lifetime_dirty; /* 1 if lifetime timer should be updated */ unsigned int start_ts; /* start time (absolute UNIX ts)*/ unsigned int flags; unsigned int from_rr_nb; unsigned int user_flags; + unsigned int mod_flags; unsigned int initial_t_hash_index; unsigned int initial_t_label; struct dlg_tl tl; struct dlg_ping_list *pl; + str terminate_reason; str callid; str from_uri; str to_uri; @@ -153,6 +158,8 @@ struct dlg_table extern struct dlg_table *d_table; extern struct dlg_cell *current_dlg_pointer; +extern int dlg_tmp_timeout; +extern int dlg_tmp_timeout_id; #define callee_idx(_dlg) \ (((_dlg)->legs_no[DLG_LEG_200OK]==0)? \ @@ -163,6 +170,8 @@ extern struct dlg_cell *current_dlg_pointer; struct dlg_cell *get_current_dialog(); +#define dlg_hash(_callid) core_hash(_callid, 0, d_table->size) + #define dlg_lock(_table, _entry) \ lock_set_get( (_table)->locks, (_entry)->lock_idx); #define dlg_unlock(_table, _entry) \ @@ -237,6 +246,37 @@ inline void destroy_dlg(struct dlg_cell *dlg); }\ }while(0) +/* + * @input - str + * @return - integer flag bitmask + */ +#define parse_create_dlg_flags(input) \ + ({ \ + char *___p; \ + int ___flags = 0; \ + for (___p=(input).s; ___p < (input).s + (input).len; ___p++) \ + { \ + switch (*___p) \ + { \ + case 'P': \ + ___flags |= DLG_FLAG_PING_CALLER; \ + LM_DBG("will ping caller\n"); \ + break; \ + case 'p': \ + ___flags |= DLG_FLAG_PING_CALLEE; \ + LM_DBG("will ping callee\n"); \ + break; \ + case 'B': \ + ___flags |= DLG_FLAG_BYEONTIMEOUT; \ + LM_DBG("bye on timeout activated\n"); \ + break; \ + default: \ + LM_DBG("unknown create_dialog flag : [%c] ." \ + "Skipping\n", *___p); \ + } \ + } \ + ___flags; \ + }) int dialog_cleanup( struct sip_msg *msg, void *param ); @@ -247,7 +287,7 @@ void destroy_dlg_table(); struct dlg_cell* build_new_dlg(str *callid, str *from_uri, str *to_uri, str *from_tag); -int dlg_add_leg_info(struct dlg_cell *dlg, str* tag, str *rr, +int dlg_add_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,str *cseq, struct socket_info *sock, str *mangled_from,str *mangled_to); @@ -271,7 +311,7 @@ void unref_dlg(struct dlg_cell *dlg, unsigned int cnt); void ref_dlg(struct dlg_cell *dlg, unsigned int cnt); void next_state_dlg(struct dlg_cell *dlg, int event, - int *old_state, int *new_state, int *unref); + int dir, int *old_state, int *new_state, int *unref, char is_replicated); struct mi_root * mi_print_dlgs(struct mi_root *cmd, void *param ); struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd, void *param ); @@ -399,4 +439,19 @@ static inline int match_dialog(struct dlg_cell *dlg, str *callid, int mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context); +static inline void init_dlg_term_reason(struct dlg_cell *dlg,char *reason,int reason_len) +{ + if (!dlg->terminate_reason.s) { + dlg->terminate_reason.s = shm_malloc(reason_len); + if (dlg->terminate_reason.s) { + dlg->terminate_reason.len = reason_len; + memcpy(dlg->terminate_reason.s,reason, + reason_len); + LM_DBG("Setting DLG term reason to [%.*s] \n", + dlg->terminate_reason.len,dlg->terminate_reason.s); + } else + LM_ERR("Failed to initialize the terminate reason \n"); + } +} + #endif diff --git a/modules/dialog/dlg_load.h b/modules/dialog/dlg_load.h index 53664bed0dd..885febf9b04 100644 --- a/modules/dialog/dlg_load.h +++ b/modules/dialog/dlg_load.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -35,7 +35,8 @@ #include "dlg_vals.h" #include "../../sr_module.h" -typedef struct dlg_cell *(*get_dlg_f)( void ); +typedef struct dlg_cell *(*get_dlg_f) (void); +typedef int (*match_dialog_f) (struct sip_msg *); struct dlg_binds { register_dlgcb_f register_dlgcb; @@ -44,11 +45,18 @@ struct dlg_binds { add_profiles_f add_profiles; search_dlg_profile_f search_profile; set_dlg_profile_f set_profile; - set_dlg_profile_f unset_profile; + unset_dlg_profile_f unset_profile; get_profile_size_f get_profile_size; store_dlg_value_f store_dlg_value; fetch_dlg_value_f fetch_dlg_value; terminate_dlg_f terminate_dlg; + + match_dialog_f match_dialog; + validate_dialog_f validate_dialog; + fix_route_dialog_f fix_route_dialog; + + set_mod_flag_f set_mod_flag; + is_mod_flag_set_f is_mod_flag_set; }; diff --git a/modules/dialog/dlg_profile.c b/modules/dialog/dlg_profile.c index b56a836e8ae..fe7141c5086 100644 --- a/modules/dialog/dlg_profile.c +++ b/modules/dialog/dlg_profile.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -80,8 +80,8 @@ static gen_lock_set_t * get_a_lock_set(int no ) } ret = lock_set_init( new ); - - + + if( ret == NULL ) { lock_set_dealloc( new ); @@ -238,7 +238,7 @@ static int dlg_fill_value(str *name, str *value) int val_len = calc_base64_encode_len(value->len); int len = cdb_val_prefix.len /* prefix */ + name->len /* profile name */ + - dlg_prof_sep.len /* value separator */ + + dlg_prof_sep.len /* value separator */ + val_len /* profile value, b64 encoded */; /* reallocate the appropriate size */ @@ -246,6 +246,7 @@ static int dlg_fill_value(str *name, str *value) LM_ERR("cannot realloc profile with value buffer\n"); return -1; } + dlg_prof_val_buf.s = buf; dlg_prof_val_buf.len = cdb_val_prefix.len; @@ -253,6 +254,7 @@ static int dlg_fill_value(str *name, str *value) DLG_COPY(dlg_prof_val_buf, &dlg_prof_sep); base64encode((unsigned char*)dlg_prof_val_buf.s + dlg_prof_val_buf.len, (unsigned char *)value->s, value->len); + dlg_prof_val_buf.len += val_len; return 0; @@ -298,34 +300,13 @@ int init_cachedb(void) LM_ERR("cachedb function not initialized\n"); return -1; } - + cdbc = cdbf.init(&cdb_url); if (!cdbc) { LM_ERR("cannot connect to cachedb_url %.*s\n", cdb_url.len, cdb_url.s); return -1; } - dlg_prof_val_buf.s = pkg_malloc(cdb_val_prefix.len + 32); - if (!dlg_prof_val_buf.s) { - LM_ERR("no more memory to allocate buffer\n"); - return -1; - } - - dlg_prof_noval_buf.s = pkg_malloc(cdb_noval_prefix.len + 32); - if (!dlg_prof_noval_buf.s) { - LM_ERR("no more memory to allocate buffer\n"); - return -1; - } - - dlg_prof_size_buf.s = pkg_malloc(cdb_size_prefix.len + 32); - if (!dlg_prof_size_buf.s) { - LM_ERR("no more memory to allocate buffer\n"); - return -1; - } - - /* copy prefixes in buffer */ - memcpy(dlg_prof_val_buf.s, cdb_val_prefix.s, cdb_val_prefix.len); - memcpy(dlg_prof_noval_buf.s, cdb_noval_prefix.s, cdb_noval_prefix.len); - memcpy(dlg_prof_size_buf.s, cdb_size_prefix.s, cdb_size_prefix.len); + LM_DBG("Inited cachedb \n"); return 0; } @@ -368,6 +349,29 @@ int init_cachedb_utils(void) return -1; } + dlg_prof_val_buf.s = pkg_malloc(cdb_val_prefix.len + 32); + if (!dlg_prof_val_buf.s) { + LM_ERR("no more memory to allocate buffer\n"); + return -1; + } + + dlg_prof_noval_buf.s = pkg_malloc(cdb_noval_prefix.len + 32); + if (!dlg_prof_noval_buf.s) { + LM_ERR("no more memory to allocate buffer\n"); + return -1; + } + + dlg_prof_size_buf.s = pkg_malloc(cdb_size_prefix.len + 32); + if (!dlg_prof_size_buf.s) { + LM_ERR("no more memory to allocate buffer\n"); + return -1; + } + + /* copy prefixes in buffer */ + memcpy(dlg_prof_val_buf.s, cdb_val_prefix.s, cdb_val_prefix.len); + memcpy(dlg_prof_noval_buf.s, cdb_noval_prefix.s, cdb_noval_prefix.len); + memcpy(dlg_prof_size_buf.s, cdb_size_prefix.s, cdb_size_prefix.len); + return 0; } @@ -480,12 +484,12 @@ static struct dlg_profile_table* new_dlg_profile( str *name, unsigned int size, profile->name.s = ((char*)profile->entries) + size*sizeof( map_t ); } else { - + profile->counts = ( int *)(profile + 1); profile->name.s = (char*) (profile->counts) + size*sizeof( int ) ; } - + /* copy the name of the profile */ memcpy( profile->name.s, name->s, name->len ); profile->name.len = name->len; @@ -505,7 +509,7 @@ static struct dlg_profile_table* new_dlg_profile( str *name, unsigned int size, static void destroy_dlg_profile(struct dlg_profile_table *profile) { int i; - + if (profile==NULL) return; if( profile -> has_value && !profile -> use_cached ) @@ -513,7 +517,7 @@ static void destroy_dlg_profile(struct dlg_profile_table *profile) for( i= 0; i < profile->size; i++) map_destroy( profile->entries[i], NULL ); } - + shm_free( profile ); return; } @@ -530,24 +534,24 @@ void destroy_dlg_profiles(void) } destroy_all_locks(); - + return; } -void destroy_linkers(struct dlg_profile_link *linker) +void destroy_linkers(struct dlg_profile_link *linker, char is_replicated) { map_t entry; struct dlg_profile_link *l; void ** dest; - + while(linker) { l = linker; linker = linker->next; /* unlink from profile table */ - + if (!l->profile->use_cached) { lock_set_get( l->profile->locks, l->hash_idx); @@ -567,9 +571,9 @@ void destroy_linkers(struct dlg_profile_link *linker) } else l->profile->counts[l->hash_idx]--; - + lock_set_release( l->profile->locks, l->hash_idx ); - } else { + } else if (!is_replicated) { if (!cdbc) { LM_WARN("CacheDB not initialized - some information might" " not be deleted from the cachedb engine\n"); @@ -628,7 +632,7 @@ inline static unsigned int calc_hash_profile( str *value, struct dlg_cell *dlg, static void link_dlg_profile(struct dlg_profile_link *linker, - struct dlg_cell *dlg) + struct dlg_cell *dlg, char is_replicated) { unsigned int hash; map_t p_entry; @@ -670,7 +674,7 @@ static void link_dlg_profile(struct dlg_profile_link *linker, linker->profile->counts[hash]++; lock_set_release( linker->profile->locks,hash ); - } else { + } else if (!is_replicated) { if (!cdbc) { LM_WARN("Cachedb not initialized yet - cannot update profile\n"); LM_WARN("Make sure that the dialog profile information is persistent\n"); @@ -713,7 +717,7 @@ static void link_dlg_profile(struct dlg_profile_link *linker, int set_dlg_profile(struct sip_msg *msg, str *value, - struct dlg_profile_table *profile) + struct dlg_profile_table *profile, char is_replicated) { struct dlg_cell *dlg; struct dlg_profile_link *linker; @@ -745,7 +749,7 @@ int set_dlg_profile(struct sip_msg *msg, str *value, } /* add linker to the dialog and profile */ - link_dlg_profile( linker, dlg); + link_dlg_profile( linker, dlg, is_replicated); dlg->flags |= DLG_FLAG_VP_CHANGED; return 0; @@ -800,7 +804,7 @@ int unset_dlg_profile(struct sip_msg *msg, str *value, dlg->flags |= DLG_FLAG_VP_CHANGED; dlg_unlock( d_table, d_entry); /* remove linker from profile table and free it */ - destroy_linkers(linker); + destroy_linkers(linker, 0); return 1; } @@ -855,7 +859,7 @@ unsigned int get_profile_size(struct dlg_profile_table *profile, str *value) if (dlg_fill_name(&profile->name) < 0) goto failed; - if (cdbf.get_counter(cdbc, &dlg_prof_noval_buf, (int *)&n) == -1) { + if (cdbf.get_counter(cdbc, &dlg_prof_noval_buf, (int *)&n) < 0) { LM_ERR("cannot fetch profile from CacheDB\n"); goto failed; } @@ -870,7 +874,7 @@ unsigned int get_profile_size(struct dlg_profile_table *profile, str *value) n += profile->counts[i]; lock_set_release( profile->locks, i); - + } } @@ -883,7 +887,7 @@ unsigned int get_profile_size(struct dlg_profile_table *profile, str *value) if (dlg_fill_size(&profile->name) < 0) goto failed; - if (cdbf.get_counter(cdbc, &dlg_prof_size_buf, (int *)&n) == -1) { + if (cdbf.get_counter(cdbc, &dlg_prof_size_buf, (int *)&n) < 0) { LM_ERR("cannot fetch profile from CacheDB\n"); goto failed; } @@ -910,7 +914,7 @@ unsigned int get_profile_size(struct dlg_profile_table *profile, str *value) if (dlg_fill_value(&profile->name, value) < 0) goto failed; - if (cdbf.get_counter(cdbc, &dlg_prof_val_buf, (int *)&n) == -1) { + if (cdbf.get_counter(cdbc, &dlg_prof_val_buf, (int *)&n) < 0) { LM_ERR("cannot fetch profile from CacheDB\n"); goto failed; } @@ -989,7 +993,7 @@ struct mi_root * mi_get_profile(struct mi_root *cmd_tree, void *param ) return NULL; } - attr = add_mi_attr(node, MI_DUP_VALUE, "name", 4, + attr = add_mi_attr(node, MI_DUP_VALUE, "name", 4, profile->name.s, profile->name.len); if(attr == NULL) { goto error; @@ -1075,12 +1079,13 @@ struct mi_root * mi_get_profile_values(struct mi_root *cmd_tree, void *param ) return init_mi_tree( 404, MI_SSTR("Profile not found")); if (profile->use_cached) return init_mi_tree( 405, MI_SSTR("Unsupported command for shared profiles")); - + /* gather dialog count for all values in this profile */ rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK)); if (rpl_tree==0) goto error; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; ret = 0; @@ -1096,7 +1101,7 @@ struct mi_root * mi_get_profile_values(struct mi_root *cmd_tree, void *param ) else { n = 0; - + for( i=0; isize; i++ ) { lock_set_get( profile->locks, i); @@ -1112,7 +1117,7 @@ struct mi_root * mi_get_profile_values(struct mi_root *cmd_tree, void *param ) if ( ret ) goto error; - + return rpl_tree; error: @@ -1158,6 +1163,7 @@ struct mi_root * mi_profile_list(struct mi_root *cmd_tree, void *param ) if (rpl_tree==0) return 0; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; /* go through the hash and print the dialogs */ @@ -1166,7 +1172,7 @@ struct mi_root * mi_profile_list(struct mi_root *cmd_tree, void *param ) d_entry = &(d_table->entries[i]); lock_set_get(d_table->locks,d_entry->lock_idx); - + cur_dlg = d_entry->first; while( cur_dlg ) { @@ -1206,7 +1212,7 @@ struct mi_root * mi_profile_list(struct mi_root *cmd_tree, void *param ) lock_set_release(d_table->locks,d_entry->lock_idx); } - + return rpl_tree; error: @@ -1231,10 +1237,11 @@ struct mi_root * mi_list_all_profiles(struct mi_root *cmd_tree, void *param ) return 0; rpl = &rpl_tree->node; - + rpl->flags |= MI_IS_ARRAY; + profile = profiles; while (profile) { - + if (add_mi_node_child(rpl, 0, profile->name.s, profile->name.len, (profile->has_value? "1" : "0"), 1) == NULL) { LM_ERR("Out of mem\n"); diff --git a/modules/dialog/dlg_profile.h b/modules/dialog/dlg_profile.h index bf58bafddfb..af50689233c 100644 --- a/modules/dialog/dlg_profile.h +++ b/modules/dialog/dlg_profile.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -41,7 +41,7 @@ struct lock_set_list { gen_lock_set_t * locks; struct lock_set_list * next; - + }; struct dlg_profile_link { @@ -66,7 +66,7 @@ struct dlg_profile_table { /* * information for profiles with values */ - + map_t * entries; /* @@ -80,7 +80,10 @@ struct dlg_profile_table { }; typedef int (*set_dlg_profile_f)(struct sip_msg *msg, str *value, - struct dlg_profile_table *profile); + struct dlg_profile_table *profile, char is_replicated); + +typedef int (*unset_dlg_profile_f)(struct sip_msg *msg, str *value, + struct dlg_profile_table *profile); typedef unsigned int (*get_profile_size_f)(struct dlg_profile_table *profile, str *value); @@ -102,10 +105,10 @@ void destroy_dlg_profiles(); struct dlg_profile_table* search_dlg_profile(str *name); -void destroy_linkers(struct dlg_profile_link *linker); +void destroy_linkers(struct dlg_profile_link *linker, char is_replicated); int set_dlg_profile(struct sip_msg *msg, str *value, - struct dlg_profile_table *profile); + struct dlg_profile_table *profile, char is_replicated); int unset_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *profile); diff --git a/modules/dialog/dlg_replication.c b/modules/dialog/dlg_replication.c new file mode 100644 index 00000000000..204bdf22daf --- /dev/null +++ b/modules/dialog/dlg_replication.c @@ -0,0 +1,625 @@ +/* + * dialog module - basic support for dialog tracking + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2013-04-12 initial version (Liviu) + */ + +#include "dlg_hash.h" +#include "dlg_db_handler.h" +#include "dlg_profile.h" + +#include "dlg_replication.h" + +extern int active_dlgs_cnt; +extern int early_dlgs_cnt; + +extern int last_dst_leg; + +extern int dlg_enable_stats; + +extern stat_var *active_dlgs; +extern stat_var *processed_dlgs; + +extern stat_var *create_sent; +extern stat_var *update_sent; +extern stat_var *delete_sent; +extern stat_var *create_recv; +extern stat_var *update_recv; +extern stat_var *delete_recv; + +static struct socket_info * fetch_socket_info(str *addr) +{ + struct socket_info *sock; + int port, proto; + str host; + + if (!addr->s || addr->s[0] == 0) + return NULL; + + if (parse_phostport(addr->s, addr->len, &host.s, &host.len, + &port, &proto) != 0) { + LM_ERR("bad socket <%.*s>\n", addr->len, addr->s); + return NULL; + } + + sock = grep_sock_info(&host, (unsigned short)port, (unsigned short)proto); + if (!sock) { + LM_WARN("non-local socket <%.*s>...ignoring\n", addr->len, addr->s); + } + + return sock; +} + +/* Binary Packet receiving functions */ + + +/** + * replicates a confirmed dialog from another OpenSIPS instance + * by reading the relevant information using the Binary Packet Interface + */ +int dlg_replicated_create(struct dlg_cell *cell, str *ftag, str *ttag, int safe) +{ + int next_id, h_entry; + unsigned int dir, dst_leg; + str callid, from_uri, to_uri, from_tag, to_tag; + str cseq1,cseq2,contact1,contact2,rroute1,rroute2,mangled_fu,mangled_tu; + str sock, vars, profiles; + struct dlg_cell *dlg = NULL; + struct socket_info *caller_sock, *callee_sock; + struct dlg_entry *d_entry; + + if_update_stat(dlg_enable_stats, processed_dlgs, 1); + + LM_DBG("Received replicated dialog!\n"); + if (!cell) { + bin_pop_str(&callid); + bin_pop_str(&from_tag); + bin_pop_str(&to_tag); + bin_pop_str(&from_uri); + bin_pop_str(&to_uri); + + dlg = get_dlg(&callid, &from_tag, &to_tag, &dir, &dst_leg); + + h_entry = dlg_hash(&callid); + d_entry = &d_table->entries[h_entry]; + + if (safe) + dlg_lock(d_table, d_entry); + + if (dlg) { + LM_DBG("Dialog with ci '%.*s' is already created\n", + callid.len, callid.s); + unref_dlg_unsafe(dlg, 1, d_entry); + dlg_unlock(d_table, d_entry); + return 0; + } + + dlg = build_new_dlg(&callid, &from_uri, &to_uri, &from_tag); + if (!dlg) { + LM_ERR("Failed to create replicated dialog!\n"); + goto pre_linking_error; + } + } else { + h_entry = dlg_hash(&cell->callid); + d_entry = &d_table->entries[h_entry]; + + if (safe) + dlg_lock(d_table, d_entry); + + from_tag = *ftag; + to_tag = *ttag; + dlg = cell; + } + + bin_pop_int(&dlg->h_id); + bin_pop_int(&dlg->start_ts); + bin_pop_int(&dlg->state); + + next_id = d_table->entries[dlg->h_entry].next_id; + + d_table->entries[dlg->h_entry].next_id = + (next_id <= dlg->h_id) ? (dlg->h_id + 1) : next_id; + + if (bin_pop_str(&sock)) + goto pre_linking_error; + + caller_sock = fetch_socket_info(&sock); + + if (bin_pop_str(&sock)) + goto pre_linking_error; + + callee_sock = fetch_socket_info(&sock); + + if (!caller_sock || !callee_sock) { + LM_ERR("Dialog in DB doesn't match any listening sockets\n"); + goto pre_linking_error; + } + + bin_pop_str(&cseq1); + bin_pop_str(&cseq2); + bin_pop_str(&rroute1); + bin_pop_str(&rroute2); + bin_pop_str(&contact1); + bin_pop_str(&contact2); + bin_pop_str(&mangled_fu); + bin_pop_str(&mangled_tu); + + /* add the 2 legs */ + if (dlg_add_leg_info(dlg, &from_tag, &rroute1, &contact1, + &cseq1, caller_sock, 0, 0) != 0 || + dlg_add_leg_info(dlg, &to_tag, &rroute2, &contact2, + &cseq2, callee_sock, &mangled_fu, &mangled_tu) != 0) { + LM_ERR("dlg_set_leg_info failed\n"); + goto pre_linking_error; + } + + dlg->legs_no[DLG_LEG_200OK] = DLG_FIRST_CALLEE_LEG; + + /* link the dialog into the hash */ + dlg->h_id = d_entry->next_id++; + if (!d_entry->first) + d_entry->first = d_entry->last = dlg; + else { + d_entry->last->next = dlg; + dlg->prev = d_entry->last; + d_entry->last = dlg; + } + dlg->ref++; + d_entry->cnt++; + + bin_pop_str(&vars); + bin_pop_str(&profiles); + bin_pop_int(&dlg->user_flags); + bin_pop_int(&dlg->flags); + bin_pop_int((void *)&dlg->tl.timeout); + bin_pop_int(&dlg->legs[DLG_CALLER_LEG].last_gen_cseq); + bin_pop_int(&dlg->legs[callee_idx(dlg)].last_gen_cseq); + + if (dlg->tl.timeout <= (unsigned int)time(0)) + dlg->tl.timeout = 0; + else + dlg->tl.timeout -= (unsigned int)time(0); + + /* restore the timer values */ + if (insert_dlg_timer(&dlg->tl, (int)dlg->tl.timeout) != 0) { + LM_CRIT("Unable to insert dlg %p [%u:%u] " + "with clid '%.*s' and tags '%.*s' '%.*s'\n", + dlg, dlg->h_entry, dlg->h_id, + dlg->callid.len, dlg->callid.s, + dlg->legs[DLG_CALLER_LEG].tag.len, + dlg->legs[DLG_CALLER_LEG].tag.s, + dlg->legs[callee_idx(dlg)].tag.len, + ZSW(dlg->legs[callee_idx(dlg)].tag.s)); + goto error; + } + + if (dlg->state == DLG_STATE_CONFIRMED_NA || + dlg->state == DLG_STATE_CONFIRMED) + active_dlgs_cnt++; + + /* reference the dialog as kept in the timer list */ + ref_dlg_unsafe(dlg, 1); + + LM_DBG("Received initial timeout of %d for dialog %.*s, safe = %d\n",dlg->tl.timeout,callid.len,callid.s,safe); + + dlg->lifetime = 0; + + /* + Do not replicate the pinging - we might terminate dialogs badly when running + as backup + if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { + if (insert_ping_timer(dlg) != 0) + LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg); + else { + ref_dlg_unsafe(dlg, 1); + } + } + */ + + if (dlg_db_mode == DB_MODE_DELAYED) { + /* to be later removed by timer */ + ref_dlg_unsafe(dlg, 1); + } + + if (vars.s && vars.len != 0) + read_dialog_vars(vars.s, vars.len, dlg); + + dlg_unlock(d_table, d_entry); + + if (profiles.s && profiles.len != 0) + read_dialog_profiles(profiles.s, profiles.len, dlg, 0, 1); + + if_update_stat(dlg_enable_stats, active_dlgs, 1); + + run_load_callback_per_dlg(dlg); + + return 0; + +pre_linking_error: + dlg_unlock(d_table, d_entry); + if (dlg) + destroy_dlg(dlg); + return -1; + +error: + dlg_unlock(d_table, d_entry); + if (dlg) + unref_dlg(dlg, 1); + + return -1; +} + +/** + * replicates the remote update of an ongoing dialog locally + * by reading the relevant information using the Binary Packet Interface + */ +int dlg_replicated_update(void) +{ + struct dlg_cell *dlg; + str call_id, from_tag, to_tag, from_uri, to_uri, vars, profiles; + unsigned int dir, dst_leg; + int timeout, h_entry; + str st; + struct dlg_entry *d_entry; + + bin_pop_str(&call_id); + bin_pop_str(&from_tag); + bin_pop_str(&to_tag); + bin_pop_str(&from_uri); + bin_pop_str(&to_uri); + + LM_DBG("replicated update for ['%.*s' '%.*s' '%.*s' '%.*s' '%.*s']\n", + call_id.len, call_id.s, from_tag.len, from_tag.s, to_tag.len, to_tag.s, + from_uri.len, from_uri.s, to_uri.len, to_uri.s); + + dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg); + + h_entry = dlg_hash(&call_id); + d_entry = &d_table->entries[h_entry]; + + dlg_lock(d_table, d_entry); + + if (!dlg) { + /* TODO: change to LM_DBG */ + LM_ERR("dialog not found, building new\n"); + + dlg = build_new_dlg(&call_id, &from_uri, &to_uri, &from_tag); + if (!dlg) { + LM_ERR("Failed to create replicated dialog!\n"); + goto error; + } + + return dlg_replicated_create(dlg, &from_tag, &to_tag, 0); + } + + bin_skip_int(2); + bin_pop_int(&dlg->state); + + bin_skip_str(2); + + bin_pop_str(&st); + if (dlg_update_cseq(dlg, DLG_CALLER_LEG, &st, 0) != 0) { + LM_ERR("failed to update caller cseq\n"); + goto error; + } + + bin_pop_str(&st); + if (dlg_update_cseq(dlg, callee_idx(dlg), &st, 0) != 0) { + LM_ERR("failed to update callee cseq\n"); + goto error; + } + + bin_skip_str(6); + bin_pop_str(&vars); + bin_pop_str(&profiles); + bin_pop_int(&dlg->user_flags); + bin_pop_int(&dlg->flags); + + bin_pop_int(&timeout); + bin_skip_int(2); + LM_DBG("Received updated timeout of %d for dialog %.*s\n",timeout,call_id.len,call_id.s); + + if (dlg->lifetime != timeout) { + dlg->lifetime = timeout; + if (update_dlg_timer(&dlg->tl, dlg->lifetime) == -1) + LM_ERR("failed to update dialog lifetime!\n"); + } + + unref_dlg_unsafe(dlg, 1, d_entry); + + if (vars.s && vars.len != 0) + read_dialog_vars(vars.s, vars.len, dlg); + + dlg_unlock(d_table, d_entry); + + if (profiles.s && profiles.len != 0) + read_dialog_profiles(profiles.s, profiles.len, dlg, 1, 1); + + return 0; + +error: + dlg_unlock(d_table, d_entry); + return -1; +} + +/** + * replicates the remote deletion of a dialog locally + * by reading the relevant information using the Binary Packet Interface + */ +int dlg_replicated_delete(void) +{ + str call_id, from_tag, to_tag; + unsigned int dir, dst_leg; + struct dlg_cell *dlg; + int old_state, new_state, unref, ret; + + bin_pop_str(&call_id); + bin_pop_str(&from_tag); + bin_pop_str(&to_tag); + + LM_DBG("Deleting dialog with callid: %.*s\n", call_id.len, call_id.s); + + dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg); + if (!dlg) { + LM_ERR("dialog not found (callid: |%.*s| ftag: |%.*s|\n", + call_id.len, call_id.s, from_tag.len, from_tag.s); + return -1; + } + + destroy_linkers(dlg->profile_links, 1); + dlg->profile_links = NULL; + + /* simulate BYE received from caller */ + last_dst_leg = dlg->legs_no[DLG_LEG_200OK]; + next_state_dlg(dlg, DLG_EVENT_REQBYE, DLG_DIR_DOWNSTREAM, &old_state, + &new_state, &unref, 1); + + if (old_state == new_state) { + LM_ERR("duplicate dialog delete request (callid: |%.*s|" + "ftag: |%.*s|\n", call_id.len, call_id.s, from_tag.len, from_tag.s); + return -1; + } + + ret = remove_dlg_timer(&dlg->tl); + if (ret < 0) { + LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] " + "with clid '%.*s' and tags '%.*s' '%.*s'\n", + dlg, dlg->h_entry, dlg->h_id, + dlg->callid.len, dlg->callid.s, + dlg->legs[DLG_CALLER_LEG].tag.len, + dlg->legs[DLG_CALLER_LEG].tag.s, + dlg->legs[callee_idx(dlg)].tag.len, + ZSW(dlg->legs[callee_idx(dlg)].tag.s)); + } else if (ret > 0) { + LM_DBG("dlg expired (not in timer list) on dlg %p [%u:%u] " + "with clid '%.*s' and tags '%.*s' '%.*s'\n", + dlg, dlg->h_entry, dlg->h_id, + dlg->callid.len, dlg->callid.s, + dlg->legs[DLG_CALLER_LEG].tag.len, + dlg->legs[DLG_CALLER_LEG].tag.s, + dlg->legs[callee_idx(dlg)].tag.len, + ZSW(dlg->legs[callee_idx(dlg)].tag.s)); + } else { + /* dialog sucessfully removed from timer -> unref */ + unref++; + } + + unref_dlg(dlg, 1 + unref); + if_update_stat(dlg_enable_stats, active_dlgs, -1); + + return 0; +} + +/* Binary Packet sending functions */ + + +/** + * replicates a locally created dialog to all the destinations + * specified with the 'replicate_dialogs' modparam + */ +void replicate_dialog_created(struct dlg_cell *dlg) +{ + struct replication_dest *d; + static str module_name = str_init("dialog"); + int callee_leg; + str *vars, *profiles; + + if (bin_init(&module_name, REPLICATION_DLG_CREATED) != 0) + goto error; + + callee_leg = callee_idx(dlg); + + bin_push_str(&dlg->callid); + bin_push_str(&dlg->legs[DLG_CALLER_LEG].tag); + bin_push_str(&dlg->legs[callee_leg].tag); + + bin_push_str(&dlg->from_uri); + bin_push_str(&dlg->to_uri); + + bin_push_int(dlg->h_id); + bin_push_int(dlg->start_ts); + bin_push_int(dlg->state); + + bin_push_str(&dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str); + if (dlg->legs[callee_leg].bind_addr) + bin_push_str(&dlg->legs[callee_leg].bind_addr->sock_str); + else + bin_push_str(NULL); + + bin_push_str(&dlg->legs[DLG_CALLER_LEG].r_cseq); + bin_push_str(&dlg->legs[callee_leg].r_cseq); + bin_push_str(&dlg->legs[DLG_CALLER_LEG].route_set); + bin_push_str(&dlg->legs[callee_leg].route_set); + bin_push_str(&dlg->legs[DLG_CALLER_LEG].contact); + bin_push_str(&dlg->legs[callee_leg].contact); + bin_push_str(&dlg->legs[callee_leg].from_uri); + bin_push_str(&dlg->legs[callee_leg].to_uri); + + /* XXX: on shutdown only? */ + vars = write_dialog_vars(dlg->vals); + profiles = write_dialog_profiles(dlg->profile_links); + + bin_push_str(vars); + bin_push_str(profiles); + bin_push_int(dlg->user_flags); + bin_push_int(dlg->flags & + ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); + bin_push_int((unsigned int)time(0) + dlg->tl.timeout - get_ticks()); + bin_push_int(dlg->legs[DLG_CALLER_LEG].last_gen_cseq); + bin_push_int(dlg->legs[callee_leg].last_gen_cseq); + + for (d = replication_dests; d; d = d->next) + bin_send(&d->to); + + if_update_stat(dlg_enable_stats,create_sent,1); + return; + +error: + LM_ERR("Failed to replicate created dialog\n"); +} + +/** + * replicates a local dialog update to all the destinations + * specified with the 'replicate_dialogs' modparam + */ +void replicate_dialog_updated(struct dlg_cell *dlg) +{ + struct replication_dest *d; + static str module_name = str_init("dialog"); + int callee_leg; + str *vars, *profiles; + + if (bin_init(&module_name, REPLICATION_DLG_UPDATED) != 0) + goto error; + + callee_leg = callee_idx(dlg); + + bin_push_str(&dlg->callid); + bin_push_str(&dlg->legs[DLG_CALLER_LEG].tag); + bin_push_str(&dlg->legs[callee_leg].tag); + + bin_push_str(&dlg->from_uri); + bin_push_str(&dlg->to_uri); + + bin_push_int(dlg->h_id); + bin_push_int(dlg->start_ts); + bin_push_int(dlg->state); + + bin_push_str(&dlg->legs[DLG_CALLER_LEG].bind_addr->sock_str); + if (dlg->legs[callee_leg].bind_addr) + bin_push_str(&dlg->legs[callee_leg].bind_addr->sock_str); + else + bin_push_str(NULL); + + bin_push_str(&dlg->legs[DLG_CALLER_LEG].r_cseq); + bin_push_str(&dlg->legs[callee_leg].r_cseq); + bin_push_str(&dlg->legs[DLG_CALLER_LEG].route_set); + bin_push_str(&dlg->legs[callee_leg].route_set); + bin_push_str(&dlg->legs[DLG_CALLER_LEG].contact); + bin_push_str(&dlg->legs[callee_leg].contact); + bin_push_str(&dlg->legs[callee_leg].from_uri); + bin_push_str(&dlg->legs[callee_leg].to_uri); + + /* XXX: on shutdown only? */ + vars = write_dialog_vars(dlg->vals); + profiles = write_dialog_profiles(dlg->profile_links); + + bin_push_str(vars); + bin_push_str(profiles); + bin_push_int(dlg->user_flags); + bin_push_int(dlg->flags & + ~(DLG_FLAG_NEW|DLG_FLAG_CHANGED|DLG_FLAG_VP_CHANGED)); + bin_push_int((unsigned int)time(0) + dlg->tl.timeout - get_ticks()); + bin_push_int(dlg->legs[DLG_CALLER_LEG].last_gen_cseq); + bin_push_int(dlg->legs[callee_leg].last_gen_cseq); + + for (d = replication_dests; d; d = d->next) + bin_send(&d->to); + + if_update_stat(dlg_enable_stats,update_sent,1); + return; + +error: + LM_ERR("Failed to replicate updated dialog\n"); +} + +/** + * replicates a local dialog delete event to all the destinations + * specified with the 'replicate_dialogs' modparam + */ +void replicate_dialog_deleted(struct dlg_cell *dlg) +{ + struct replication_dest *d; + static str module_name = str_init("dialog"); + + if (bin_init(&module_name, REPLICATION_DLG_DELETED) != 0) + goto error; + + bin_push_str(&dlg->callid); + bin_push_str(&dlg->legs[DLG_CALLER_LEG].tag); + bin_push_str(&dlg->legs[callee_idx(dlg)].tag); + + for (d = replication_dests; d; d = d->next) + bin_send(&d->to); + + if_update_stat(dlg_enable_stats,delete_sent,1); + return; +error: + LM_ERR("Failed to replicate deleted dialog\n"); +} + +/** + * receive_binary_packet (callback) - receives a cmd_type, specifying the + * purpose of the data encoded in the received UDP packet + */ +void receive_binary_packet(int info_type) +{ + int rc; + + LM_DBG("Received a binary packet!\n"); + + switch (info_type) { + case REPLICATION_DLG_CREATED: + rc = dlg_replicated_create(NULL, NULL, NULL, 1); + if_update_stat(dlg_enable_stats, create_recv, 1); + break; + + case REPLICATION_DLG_UPDATED: + rc = dlg_replicated_update(); + if_update_stat(dlg_enable_stats, update_recv, 1); + break; + + case REPLICATION_DLG_DELETED: + rc = dlg_replicated_delete(); + if_update_stat(dlg_enable_stats, delete_recv, 1); + break; + + default: + rc = -1; + LM_ERR("Invalid dialog binary packet command: %d\n", info_type); + } + + if (rc != 0) + LM_ERR("Failed to process a binary packet!\n"); +} + diff --git a/modules/dialog/dlg_replication.h b/modules/dialog/dlg_replication.h new file mode 100644 index 00000000000..7c6753d4af1 --- /dev/null +++ b/modules/dialog/dlg_replication.h @@ -0,0 +1,58 @@ +/* + * dialog module - basic support for dialog tracking + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2013-04-12 initial version (Liviu) + */ + +#include "../../ut.h" +#include "../../bin_interface.h" +#include "../../socket_info.h" +#include "../../timer.h" + +#ifndef _DIALOG_DLG_REPLICATION_H_ +#define _DIALOG_DLG_REPLICATION_H_ + +#define REPLICATION_DLG_CREATED 1 +#define REPLICATION_DLG_UPDATED 2 +#define REPLICATION_DLG_DELETED 3 + +extern int accept_replicated_dlg; +extern struct replication_dest *replication_dests; + +struct replication_dest { + union sockaddr_union to; + struct replication_dest *next; +}; + +void replicate_dialog_created(struct dlg_cell *dlg); +void replicate_dialog_updated(struct dlg_cell *dlg); +void replicate_dialog_deleted(struct dlg_cell *dlg); + +int dlg_replicated_create(struct dlg_cell *cell, str *ftag, str *ttag, int safe); +int dlg_replicated_update(void); +int dlg_replicated_delete(void); + +void receive_binary_packet(int info_type); + +#endif /* _DIALOG_DLG_REPLICATION_H_ */ + diff --git a/modules/dialog/dlg_req_within.c b/modules/dialog/dlg_req_within.c index 3b7ccbf8ec7..538b7872bb8 100644 --- a/modules/dialog/dlg_req_within.c +++ b/modules/dialog/dlg_req_within.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -112,7 +112,7 @@ dlg_t * build_dlg_t(struct dlg_cell * cell, int dst_leg, int src_leg) LM_ERR("failed to parse route set\n"); goto error; } - } + } /*remote target--- Request URI*/ if (cell->legs[dst_leg].contact.s==0 || cell->legs[dst_leg].contact.len==0){ @@ -121,7 +121,7 @@ dlg_t * build_dlg_t(struct dlg_cell * cell, int dst_leg, int src_leg) } td->rem_target = cell->legs[dst_leg].contact; - td->rem_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_from_uri(cell,dst_leg): + td->rem_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_from_uri(cell,dst_leg): *dlg_leg_to_uri(cell,dst_leg); td->loc_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_to_uri(cell,dst_leg): *dlg_leg_from_uri(cell,dst_leg); @@ -179,7 +179,7 @@ dlg_t * build_dialog_info(struct dlg_cell * cell, int dst_leg, int src_leg) LM_ERR("failed to parse route set\n"); goto error; } - } + } /*remote target--- Request URI*/ if (cell->legs[dst_leg].contact.s==0 || cell->legs[dst_leg].contact.len==0){ @@ -188,7 +188,7 @@ dlg_t * build_dialog_info(struct dlg_cell * cell, int dst_leg, int src_leg) } td->rem_target = cell->legs[dst_leg].contact; - td->rem_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_from_uri(cell,dst_leg): + td->rem_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_from_uri(cell,dst_leg): *dlg_leg_to_uri(cell,dst_leg); td->loc_uri = (dst_leg==DLG_CALLER_LEG)? *dlg_leg_to_uri(cell,dst_leg): *dlg_leg_from_uri(cell,dst_leg); @@ -210,19 +210,24 @@ dlg_t * build_dialog_info(struct dlg_cell * cell, int dst_leg, int src_leg) static void dual_bye_event(struct dlg_cell* dlg, struct sip_msg *req, int extra_unref) { int event, old_state, new_state, unref, ret; + struct dlg_cell *curr; event = DLG_EVENT_REQBYE; - next_state_dlg(dlg, event, &old_state, &new_state, &unref); + last_dst_leg = dlg->legs_no[DLG_LEG_200OK]; + next_state_dlg(dlg, event, DLG_DIR_DOWNSTREAM, &old_state, &new_state, + &unref, 0); unref += extra_unref; if(new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED){ - + LM_DBG("removing dialog with h_entry %u and h_id %u\n", dlg->h_entry, dlg->h_id); /*destroy linkers */ - destroy_linkers(dlg->profile_links); + dlg_lock_dlg(dlg); + destroy_linkers(dlg->profile_links, 0); dlg->profile_links = NULL; + dlg_unlock_dlg(dlg); /* remove from timer */ ret = remove_dlg_timer(&dlg->tl); @@ -245,8 +250,11 @@ static void dual_bye_event(struct dlg_cell* dlg, struct sip_msg *req, int extra_ unref++; } + curr = current_dlg_pointer; + current_dlg_pointer = dlg; /* dialog terminated (BYE) */ run_dlg_callbacks( DLGCB_TERMINATED, dlg, req, DLG_DIR_NONE, 0); + current_dlg_pointer = curr; LM_DBG("first final reply\n"); /* derefering the dialog */ @@ -281,6 +289,8 @@ void bye_reply_cb(struct cell* t, int type, struct tmcb_params* ps) } LM_DBG("receiving a final reply %d\n",ps->code); + /* mark the transaction as belonging to this dialog */ + t->dialog_ctx = *(ps->param); dual_bye_event( (struct dlg_cell *)(*(ps->param)), ps->req, 1); } @@ -291,7 +301,7 @@ static inline int build_extra_hdr(struct dlg_cell * cell, str *extra_hdrs, { char *p; - str_hdr->len = dlg_extra_hdrs.len + + str_hdr->len = dlg_extra_hdrs.len + (extra_hdrs?extra_hdrs->len:0); str_hdr->s = (char*)pkg_malloc( str_hdr->len * sizeof(char) ); @@ -316,7 +326,7 @@ static inline int build_extra_hdr(struct dlg_cell * cell, str *extra_hdrs, return 0; -error: +error: return -1; } @@ -468,6 +478,8 @@ struct mi_root * mi_terminate_dlg(struct mi_root *cmd_tree, void *param ){ /* lookup_dlg has incremented the reference count !! */ if(dlg){ + init_dlg_term_reason(dlg,"MI Termination",sizeof("MI Termination")-1); + if ( dlg_end_dlg( dlg, mi_extra_hdrs) ) { status = 500; msg = MI_DLG_OPERATION_ERR; @@ -485,7 +497,7 @@ struct mi_root * mi_terminate_dlg(struct mi_root *cmd_tree, void *param ){ end: return init_mi_tree(404, MI_DIALOG_NOT_FOUND, MI_DIALOG_NOT_FOUND_LEN); - + error: return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); diff --git a/modules/dialog/dlg_req_within.h b/modules/dialog/dlg_req_within.h index b1a91341428..1091b3e0b8f 100644 --- a/modules/dialog/dlg_req_within.h +++ b/modules/dialog/dlg_req_within.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/dialog/dlg_timer.c b/modules/dialog/dlg_timer.c index d2df95351de..959aa16dd3d 100644 --- a/modules/dialog/dlg_timer.c +++ b/modules/dialog/dlg_timer.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -255,7 +255,7 @@ int insert_ping_timer(struct dlg_cell* dlg) LM_ERR("no more shm mem\n"); return -1; } - + node->dlg = dlg; node->next = 0; node->prev = 0; @@ -549,7 +549,7 @@ void reply_from_caller(struct cell* t, int type, struct tmcb_params* ps) LM_ERR("Null callback parameter\n"); return; } - + rpl = ps->rpl; statuscode = ps->code; dlg = *(ps->param); @@ -567,7 +567,7 @@ void reply_from_caller(struct cell* t, int type, struct tmcb_params* ps) if (statuscode == 481) { - /* call/transaction does not exist + /* call/transaction does not exist * terminate the dialog */ LM_INFO("terminating dialog ( due to 481 ) " "with callid = [%.*s] \n",dlg->callid.len,dlg->callid.s); @@ -596,7 +596,7 @@ void reply_from_callee(struct cell* t, int type, struct tmcb_params* ps) LM_ERR("Null callback parameter\n"); return; } - + rpl = ps->rpl; statuscode = ps->code; dlg = *(ps->param); @@ -614,7 +614,7 @@ void reply_from_callee(struct cell* t, int type, struct tmcb_params* ps) if (statuscode == 481) { - /* call/transaction does not exist + /* call/transaction does not exist * terminate the dialog */ LM_INFO("terminating dialog ( due to 481 ) " "with callid = [%.*s] \n",dlg->callid.len,dlg->callid.s); @@ -646,6 +646,7 @@ void dlg_ping_routine(unsigned int ticks , void * attr) shm_free(it); it = curr; + init_dlg_term_reason(dlg,"Ping Timeout",sizeof("Ping Timeout")-1); /* FIXME - maybe better not to send BYE both ways as we know for * sure one end in down . */ dlg_end_dlg(dlg,0); @@ -659,7 +660,7 @@ void dlg_ping_routine(unsigned int ticks , void * attr) dlg = it->dlg; LM_DBG("dialog %p-%.*s has terminated\n",dlg,dlg->callid.len,dlg->callid.s); curr = it->next; - /* if marked as to be deleted, we let it go + /* if marked as to be deleted, we let it go * for the ping timer list as well */ unref_dlg(dlg,1); shm_free(it); diff --git a/modules/dialog/dlg_timer.h b/modules/dialog/dlg_timer.h index d1262689953..4cef3ec6a6f 100644 --- a/modules/dialog/dlg_timer.h +++ b/modules/dialog/dlg_timer.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/dialog/dlg_tophiding.c b/modules/dialog/dlg_tophiding.c index 9ca7a567f6f..deceef7f826 100644 --- a/modules/dialog/dlg_tophiding.c +++ b/modules/dialog/dlg_tophiding.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -33,10 +33,16 @@ #include "../../data_lump.h" #include "../tm/tm_load.h" +#include "../../mod_fix.h" +#include "../../parser/contact/parse_contact.h" #include "dlg_tophiding.h" #include "dlg_handlers.h" extern struct tm_binds d_tmb; +extern str rr_param; + +extern str topo_hiding_prefix; +extern str topo_hiding_seed; #define RECORD_ROUTE "Record-Route: " #define RECORD_ROUTE_LEN (sizeof(RECORD_ROUTE)-1) @@ -57,13 +63,13 @@ int dlg_del_vias(struct sip_msg* req) if(it) { /* delete first via1 to set the type (the build_req_buf_from_sip_req will know not to add lump in via1)*/ if (del_lump(req,it->name.s - buf,it->len, 0) == 0) { - LM_ERR("del_lump failed \n"); + LM_ERR("del_lump failed\n"); return -1; } LM_DBG("Delete via [%.*s]\n", it->len, it->name.s); for (it=it->sibling; it; it=it->sibling) { if (del_lump(req,it->name.s - buf,it->len, 0) == 0) { - LM_ERR("del_lump failed \n"); + LM_ERR("del_lump failed\n"); return -1; } LM_DBG("Delete via [%.*s]\n", it->len, it->name.s); @@ -73,14 +79,62 @@ int dlg_del_vias(struct sip_msg* req) return 0; } +struct th_ct_params { + str param_name; + struct th_ct_params *next; +}; + +#define init_new_ct_node(start,len) \ + do { \ + el = pkg_malloc(sizeof(struct th_ct_params));\ + if (!el) { \ + LM_ERR("No more pkg mem\n"); \ + return -1; \ + } \ + el->param_name.len = len; \ + el->param_name.s = start; \ + el->next = th_param_list; \ + th_param_list = el; \ + } while (0) + +struct th_ct_params *th_param_list=NULL; +int dlg_parse_passed_ct_params(str *params) +{ + char *p,*s,*end; + struct th_ct_params* el; + int len; + + p = params->s; + end = p+params->len; + while (1) { + s = memchr(p,';',end-p); + if (!s) { + len = end-p; + if (len > 0) + init_new_ct_node(p,len); + break; + } + + len = s-p; + if (len > 0) + init_new_ct_node(p,len); + p=s+1; + } + + return 0; +} + int dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg) { -// str local_contact; struct lump* lump, *crt, *prev_crt =0, *a, *foo; int offset; int len,n; - char *prefix=NULL,*suffix=NULL,*p,*p_init; - int prefix_len,suffix_len; + char *prefix=NULL,*suffix=NULL,*p,*p_init,*ct_username=NULL; + int prefix_len,suffix_len,ct_username_len=0; + struct sip_uri ctu; + str contact; + struct th_ct_params* el; + int i; if(!msg->contact) { @@ -94,6 +148,27 @@ int dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg) } prefix_len = 5; /* flags & DLG_FLAG_TOPH_KEEP_USER) { + if ( parse_contact(msg->contact)<0 || + ((contact_body_t *)msg->contact->parsed)->contacts==NULL || + ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + LM_ERR("bad Contact HDR\n"); + } else { + contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; + if(parse_uri(contact.s, contact.len, &ctu) < 0) { + LM_ERR("Bad Contact URI\n"); + } else { + ct_username = ctu.user.s; + ct_username_len = ctu.user.len; + LM_DBG("Trying to propagate username [%.*s]\n",ct_username_len, + ct_username); + if (ct_username_len > 0) + prefix_len += 1 + /* @ */ + ct_username_len; + } + } + } + prefix = pkg_malloc(prefix_len); if (!prefix) { LM_ERR("no more pkg\n"); @@ -101,6 +176,35 @@ int dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg) } suffix_len = RR_DLG_PARAM_SIZE+1; /* > */ + if (th_param_list) { + if ( parse_contact(msg->contact)<0 || + ((contact_body_t *)msg->contact->parsed)->contacts==NULL || + ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + LM_ERR("bad Contact HDR\n"); + } else { + contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; + if(parse_uri(contact.s, contact.len, &ctu) < 0) { + LM_ERR("Bad Contact URI\n"); + } else { + for (el=th_param_list;el;el=el->next) { + /* we just iterate over the unknown params */ + for (i=0;iparam_name.len == ctu.u_name[i].len && + (memcmp(el->param_name.s,ctu.u_name[i].s, + el->param_name.len) == 0)) { + if (ctu.u_val[i].len) + suffix_len += 1 /* ; */ + ctu.u_name[i].len + + ctu.u_val[i].len + 1; /* = and value */ + else + suffix_len += 1 /* ; */ + ctu.u_name[i].len; + } + + } + } + } + } + } + suffix = pkg_malloc(suffix_len); if (!suffix) { LM_ERR("no more pkg\n"); @@ -108,11 +212,15 @@ int dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg) } memcpy(prefix,"flags & DLG_FLAG_TOPH_KEEP_USER && ct_username_len > 0) { + memcpy(prefix+5,ct_username,ct_username_len); + prefix[prefix_len-1] = '@'; + } + p_init = p = suffix; *p++ = ';'; - memcpy(p,"did",3); - p+=3; + memcpy(p,rr_param.s,rr_param.len); + p+=rr_param.len; *p++ = '='; n = RR_DLG_PARAM_SIZE - (p-p_init); @@ -125,6 +233,26 @@ int dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg) if (int2reverse_hex( &p, &n, dlg->h_id)==-1) return -1; + if (th_param_list) { + for (el=th_param_list;el;el=el->next) { + /* we just iterate over the unknown params */ + for (i=0;iparam_name.len == ctu.u_name[i].len && + memcmp(el->param_name.s,ctu.u_name[i].s, + el->param_name.len) == 0) { + *p++ = ';'; + memcpy(p,ctu.u_name[i].s,ctu.u_name[i].len); + p+=ctu.u_name[i].len; + if (ctu.u_val[i].len) { + *p++ = '='; + memcpy(p,ctu.u_val[i].s,ctu.u_val[i].len); + p+=ctu.u_val[i].len; + } + } + } + } + } + *p++ = '>'; suffix_len = p - p_init; @@ -174,7 +302,7 @@ int dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg) } if ((lump = del_lump(msg, msg->contact->body.s - msg->buf, msg->contact->body.len,HDR_CONTACT_T)) == 0) { - LM_ERR("del_lump failed \n"); + LM_ERR("del_lump failed\n"); goto error; } @@ -182,6 +310,8 @@ int dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg) LM_ERR("failed inserting 'record_route; it; it=it->sibling) { /* changed here for contact - it was & it->sibling */ /* skip the one added by this proxy */ if ((lmp = del_lump(rpl, it->name.s - buf, it->len,HDR_RECORDROUTE_T)) == 0) { - LM_ERR("del_lump failed \n"); + LM_ERR("del_lump failed\n"); return -1; } LM_DBG("Delete record route: [%.*s]\n", it->len, it->name.s); @@ -246,7 +374,7 @@ int dlg_th_onreply(struct dlg_cell *dlg, struct sip_msg *rpl, struct sip_msg *re LM_DBG("deleted rr stuff\n"); /* add Via headers */ - lmp = anchor_lump(rpl,rpl->headers->name.s - buf,0,0); + lmp = anchor_lump(rpl,rpl->headers->name.s - buf,0); if (lmp == 0) { LM_ERR("failed anchoring new lump\n"); @@ -321,7 +449,7 @@ int dlg_th_onreply(struct dlg_cell *dlg, struct sip_msg *rpl, struct sip_msg *re } /* hide via, route sets and contacts */ -int w_topology_hiding(struct sip_msg *req) +static int topology_hiding(struct sip_msg *req,int extra_flags) { struct dlg_cell *dlg; struct hdr_field *it; @@ -338,10 +466,15 @@ int w_topology_hiding(struct sip_msg *req) LM_ERR("Failed to create dialog\n"); return -1; } - dlg = get_current_dialog(); + /* double check if the dialog can be retrieved */ + if (!(dlg = get_current_dialog())) { + LM_ERR("failed to get dialog\n"); + return -1; + } } dlg->flags |= DLG_FLAG_TOPHIDING; + dlg->flags |= extra_flags; /* delete also the added record route and the did param */ for(crt=req->add_rm; crt;) { @@ -349,7 +482,7 @@ int w_topology_hiding(struct sip_msg *req) if(crt->type != HDR_RECORDROUTE_T) /* check on before list for parameters */ for( lump=crt->before ; lump ; lump=lump->before ) { - /* we are looking for the lump that adds the + /* we are looking for the lump that adds the * suffix of the RR header */ if ( lump->type==HDR_RECORDROUTE_T && lump->op==LUMP_ADD) { @@ -426,6 +559,43 @@ int w_topology_hiding(struct sip_msg *req) return 1; } +int w_topology_hiding1(struct sip_msg *req,char *param) +{ + str res = {0,0}; + int flags=0; + char *p; + + if (fixup_get_svalue(req, (gparam_p)param, &res) !=0) + { + LM_ERR("no create dialog flags\n"); + return -1; + } + + for (p=res.s;precord_route;it;it=it->sibling) { if (del_lump(req, it->name.s - buf, it->len,HDR_RECORDROUTE_T) == 0) { - LM_ERR("del_lump failed \n"); + LM_ERR("del_lump failed\n"); return -1; } LM_DBG("Delete record route: [%.*s]\n", it->len, it->name.s); @@ -502,3 +672,310 @@ int dlg_th_onroute(struct dlg_cell *dlg, struct sip_msg *req, int dir) return 0; } + +int dlg_th_decode_callid(struct sip_msg *msg) +{ + struct lump *del; + str new_callid; + int i,max_size; + + if (msg->callid == NULL) { + LM_ERR("Message with no callid\n"); + return -1; + } + + max_size = calc_max_base64_decode_len(msg->callid->body.len - topo_hiding_prefix.len); + new_callid.s = pkg_malloc(max_size); + if (new_callid.s==NULL) { + LM_ERR("No more pkg\n"); + return -1; + } + + new_callid.len = base64decode((unsigned char *)(new_callid.s), + (unsigned char *)(msg->callid->body.s + topo_hiding_prefix.len), + msg->callid->body.len - topo_hiding_prefix.len); + for (i=0;icallid->body.s-msg->buf, msg->callid->body.len, HDR_CALLID_T); + if (del==NULL) { + LM_ERR("Failed to delete old callid\n"); + pkg_free(new_callid.s); + return -1; + } + + if (insert_new_lump_after(del,new_callid.s,new_callid.len,HDR_CALLID_T)==NULL) { + LM_ERR("Failed to insert new callid\n"); + pkg_free(new_callid.s); + return -1; + } + + return 0; + + return 0; +} + +int dlg_th_encode_callid(struct sip_msg *msg) +{ + struct lump *del; + str new_callid; + int i; + + if (msg->callid == NULL) { + LM_ERR("Message with no callid\n"); + return -1; + } + + new_callid.len = calc_base64_encode_len(msg->callid->body.len); + new_callid.len += topo_hiding_prefix.len; + new_callid.s = pkg_malloc(new_callid.len); + if (new_callid.s==NULL) { + LM_ERR("Failed to allocate callid len\n"); + return -1; + } + + if (new_callid.s == NULL) { + LM_ERR("Failed to encode callid\n"); + return -1; + } + + memcpy(new_callid.s,topo_hiding_prefix.s,topo_hiding_prefix.len); + for (i=0;icallid->body.len;i++) + msg->callid->body.s[i] ^= topo_hiding_seed.s[i%topo_hiding_seed.len]; + + base64encode((unsigned char *)(new_callid.s+topo_hiding_prefix.len), + (unsigned char *)(msg->callid->body.s),msg->callid->body.len); + + /* reset the callid back to original value - some might still need it ( eg. post script ) + FIXME : use bigger buffer here ? mem vs cpu */ + for (i=0;icallid->body.len;i++) + msg->callid->body.s[i] ^= topo_hiding_seed.s[i%topo_hiding_seed.len]; + + del=del_lump(msg, msg->callid->body.s-msg->buf, msg->callid->body.len, HDR_CALLID_T); + if (del==NULL) { + LM_ERR("Failed to delete old callid\n"); + pkg_free(new_callid.s); + return -1; + } + + if (insert_new_lump_after(del,new_callid.s,new_callid.len,HDR_CALLID_T)==NULL) { + LM_ERR("Failed to insert new callid\n"); + pkg_free(new_callid.s); + return -1; + } + + return 0; +} + +int dlg_th_needs_decoding(struct sip_msg *msg) +{ + if (msg->callid == NULL) { + LM_ERR("Message with no callid\n"); + return 0; + } + + if (msg->callid->body.len > topo_hiding_prefix.len && + memcmp(msg->callid->body.s,topo_hiding_prefix.s, + topo_hiding_prefix.len) == 0) + return 1; + + return 0; +} + +static inline char *dlg_th_rebuild_req(struct sip_msg *msg,int *len) +{ + return build_req_buf_from_sip_req(msg,(unsigned int*)len, + NULL,PROTO_NONE,MSG_TRANS_NOVIA_FLAG); +} + +static inline char *dlg_th_rebuild_rpl(struct sip_msg *msg,int *len) +{ + return build_res_buf_from_sip_res(msg,(unsigned int*)len, + NULL,MSG_TRANS_NOVIA_FLAG); +} + +#define MSG_SKIP_BITMASK (METHOD_REGISTER|METHOD_PUBLISH|METHOD_NOTIFY|METHOD_SUBSCRIBE) +int dlg_th_callid_pre_parse(struct sip_msg *msg,int want_from) +{ + /* do not throw errors from the upcoming parsing operations */ + set_proc_debug_level(L_ALERT); + + if (parse_msg(msg->buf,msg->len,msg)!=0) { + LM_ERR("Invalid SIP msg\n"); + goto error; + } + + if (parse_headers(msg,HDR_EOH_F,0)<0) { + LM_ERR("Failed to parse SIP headers\n"); + goto error; + } + + if (msg->cseq==NULL || get_cseq(msg)==NULL) { + LM_ERR("Failed to parse CSEQ header\n"); + goto error; + } + + if((get_cseq(msg)->method_id)&MSG_SKIP_BITMASK) { + LM_DBG("Skipping %d for DLG callid topo hiding\n",get_cseq(msg)->method_id); + goto error; + } + + if (parse_to_header(msg)<0 || msg->to==NULL || get_to(msg)==NULL) { + LM_ERR("cannot parse TO header\n"); + goto error; + } + + if (parse_from_header(msg)<0 || msg->from==NULL || get_from(msg)==NULL) { + LM_ERR("cannot parse TO header\n"); + goto error; + } + + reset_proc_debug_level(); + return 0; + +error: + reset_proc_debug_level(); + return -1; +} + +int dlg_th_pre_raw(str *data) +{ + struct sip_msg msg; + + memset(&msg,0,sizeof(struct sip_msg)); + msg.buf=data->s; + msg.len=data->len; + if (dlg_th_callid_pre_parse(&msg,0) < 0) + goto done; + + if (msg.first_line.type==SIP_REQUEST) { + if (get_to(&msg)->tag_value.len>0) { + /* sequential request, check if callid needs to be unmasked */ + if (dlg_th_needs_decoding(&msg)) { + if (dlg_th_decode_callid(&msg) < 0) { + LM_ERR("Failed to decode callid for sequential request\n"); + goto error; + } + goto rebuild_msg; + } + } else { + /* initial request, don't do anything + callid masking will be done on the out side */ + } + } else if (msg.first_line.type==SIP_REPLY) { + /* we might need to decode callid if mangled */ + if (dlg_th_needs_decoding(&msg)) { + if (dlg_th_decode_callid(&msg) < 0) { + LM_ERR("Failed to decode callid for reply\n"); + goto error; + } + goto rebuild_rpl; + } else { + /* encoding will be done on the out side */ + } + } else { + /* non sip, most likely, let it through */ + return 0; + } + +done: + free_sip_msg(&msg); + return 0; + +rebuild_msg: + data->s = dlg_th_rebuild_req(&msg,&data->len); + free_sip_msg(&msg); + return 0; + +rebuild_rpl: + data->s = dlg_th_rebuild_rpl(&msg,&data->len); + free_sip_msg(&msg); + return 0; +error: + free_sip_msg(&msg); + return -1; +} + +int dlg_th_post_raw(str *data) +{ + struct sip_msg msg; + struct dlg_cell *dlg; + + dlg = get_current_dialog(); + if (dlg == NULL || (dlg->flags & DLG_FLAG_TOPH_HIDE_CALLID) == 0 ) { + /* dialog module not involved or not callid topo hiding + - let is pass freely */ + return 0; + } + + memset(&msg,0,sizeof(struct sip_msg)); + msg.buf=data->s; + msg.len=data->len; + if (dlg_th_callid_pre_parse(&msg,1) < 0) + goto done; + + if (msg.first_line.type==SIP_REQUEST) { + if (get_to(&msg)->tag_value.len>0) { + /* sequential request, check if callid needs to be unmasked */ + if (get_from(&msg)->tag_value.len != 0) { + if (memcmp(get_from(&msg)->tag_value.s, + dlg->legs[0].tag.s,dlg->legs[0].tag.len) == 0) { + /* request from caller - need to encode callid */ + if (dlg_th_encode_callid(&msg) < 0) { + LM_ERR("Failed to mask callid for initial request\n"); + goto error; + } + goto rebuild_req; + } else { + /* let request go through - was decoded on the in side */ + } + } else { + /* no from tag in request - kinda foobar ? - let it through */ + goto done; + } + } else { + /* initial request, mask callid */ + if (dlg_th_encode_callid(&msg) < 0) { + LM_ERR("Failed to mask callid for initial request\n"); + goto error; + } + goto rebuild_req; + } + } else if (msg.first_line.type==SIP_REPLY) { + /* we need to look at the direction */ + if (get_from(&msg)->tag_value.len != 0) { + if (memcmp(get_from(&msg)->tag_value.s, + dlg->legs[0].tag.s,dlg->legs[0].tag.len) == 0) { + /* reply going to caller - + decode was done on the receiving end, let it unchanged */ + } else { + /* reply going to callee , need to encode callid */ + if (dlg_th_encode_callid(&msg) < 0) { + LM_ERR("Failed to decode callid for reply\n"); + goto error; + } + goto rebuild_rpl; + } + } else { + /* no from tag in reply - kinda foobar ? - let it through */ + goto done; + } + } + +done: + free_sip_msg(&msg); + return 0; + +rebuild_req: + data->s = dlg_th_rebuild_req(&msg,&data->len); + free_sip_msg(&msg); + return 0; +rebuild_rpl: + data->s = dlg_th_rebuild_rpl(&msg,&data->len); + free_sip_msg(&msg); + return 0; + +error: + free_sip_msg(&msg); + return -1; +} diff --git a/modules/dialog/dlg_tophiding.h b/modules/dialog/dlg_tophiding.h index eb76d4ff642..e3a28dee9a0 100644 --- a/modules/dialog/dlg_tophiding.h +++ b/modules/dialog/dlg_tophiding.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -32,8 +32,13 @@ #include "dlg_hash.h" int w_topology_hiding(struct sip_msg *req); +int w_topology_hiding1(struct sip_msg *req,char *param); int dlg_th_onroute(struct dlg_cell *dlg, struct sip_msg *req, int dir); -int dlg_th_onreply(struct dlg_cell *dlg, struct sip_msg *rpl, +int dlg_th_onreply(struct dlg_cell *dlg, struct sip_msg *rpl, struct sip_msg *req,int init_req, int dir); +int dlg_th_pre_raw(str *data); +int dlg_th_post_raw(str *data); +int dlg_parse_passed_ct_params(str *params); + #endif diff --git a/modules/dialog/dlg_vals.c b/modules/dialog/dlg_vals.c index 5b24c8f435e..690b9497c81 100644 --- a/modules/dialog/dlg_vals.c +++ b/modules/dialog/dlg_vals.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -68,8 +68,7 @@ static inline struct dlg_val *new_dlg_val(str *name, str *val) return dv; } - -int store_dlg_value(struct dlg_cell *dlg, str *name, str *val) +int store_dlg_value_unsafe(struct dlg_cell *dlg, str *name, str *val) { struct dlg_val *dv=NULL; struct dlg_val *it; @@ -83,9 +82,6 @@ int store_dlg_value(struct dlg_cell *dlg, str *name, str *val) id = _get_name_id(name); - /* lock dialog */ - dlg_lock_dlg( dlg ); - /* iterate the list */ for( it_prev=NULL, it=dlg->vals ; it ; it_prev=it,it=it->next) { if (id==it->id && name->len==it->name.len && @@ -104,29 +100,41 @@ int store_dlg_value(struct dlg_cell *dlg, str *name, str *val) } dlg->flags |= DLG_FLAG_VP_CHANGED; - /* unlock dialog */ - dlg_unlock_dlg( dlg ); - shm_free(it); return 0; } } - /* not found -> simply add a new one */ + /* not found */ + if (val==NULL) + return 0; + + /* has value ? -> simply add a new one */ /* insert at the beginning of the list */ dv->next = dlg->vals; dlg->vals = dv; dlg->flags |= DLG_FLAG_VP_CHANGED; - /* unlock dialog */ - dlg_unlock_dlg( dlg ); return 0; } +int store_dlg_value(struct dlg_cell *dlg, str *name, str *val) +{ + int ret; + + /* lock dialog */ + dlg_lock_dlg( dlg ); + ret = store_dlg_value_unsafe(dlg,name,val); + /* unlock dialog */ + dlg_unlock_dlg( dlg ); + + return ret; +} static str val_buf = { NULL, 0}; +static int val_buf_size; int fetch_dlg_value(struct dlg_cell *dlg, str *name,str *ival, int val_has_buf) @@ -139,7 +147,11 @@ int fetch_dlg_value(struct dlg_cell *dlg, str *name,str *ival, int val_has_buf) id = _get_name_id(name); - val = val_has_buf ? ival : &val_buf; + if (!val_has_buf) { + val = &val_buf; + val->len = val_buf_size; + } else + val = ival; /* lock dialog */ dlg_lock_dlg( dlg ); @@ -153,10 +165,16 @@ int fetch_dlg_value(struct dlg_cell *dlg, str *name,str *ival, int val_has_buf) if (dv->val.len > val->len) { val->s = (char*)pkg_realloc(val->s,dv->val.len); if (val->s==NULL) { + if (!val_has_buf) + val_buf_size = 0; + dlg_unlock_dlg( dlg ); LM_ERR("failed to do realloc for %d\n",dv->val.len); return -1; } + + if (!val_has_buf) + val_buf_size = dv->val.len; } memcpy( val->s, dv->val.s, dv->val.len ); val->len = dv->val.len; @@ -191,7 +209,7 @@ int check_dlg_value_unsafe(struct dlg_cell *dlg, str *name, str *val) if (id==dv->id && name->len==dv->name.len && memcmp(name->s,dv->name.s,name->len)==0 ) { LM_DBG("var found with val <%.*s>!\n",dv->val.len,dv->val.s); - if ( val->len==dv->val.len && + if ( val->len==dv->val.len && memcmp(val->s,dv->val.s,val->len)==0) { LM_DBG("var found!\n"); return 0; diff --git a/modules/dialog/dlg_vals.h b/modules/dialog/dlg_vals.h index a30605fb746..46f5875d52c 100644 --- a/modules/dialog/dlg_vals.h +++ b/modules/dialog/dlg_vals.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -58,6 +58,7 @@ typedef int (*fetch_dlg_value_f)(struct dlg_cell *dlg, int store_dlg_value(struct dlg_cell *dlg, str *name, str *val); +int store_dlg_value_unsafe(struct dlg_cell *dlg, str *name, str *val); int fetch_dlg_value(struct dlg_cell *dlg, str *name, str *val,int val_has_buf); diff --git a/modules/dialog/doc/dialog_admin.xml b/modules/dialog/doc/dialog_admin.xml index 634a7cec209..6e7fa3377b1 100644 --- a/modules/dialog/doc/dialog_admin.xml +++ b/modules/dialog/doc/dialog_admin.xml @@ -34,9 +34,7 @@ received. In case of no BYE, the dialog lifetime is controlled via the default timeout (see default_timeout - ) and custom timeout (see - timeout_avp - ). The - dialog timeout is reset each time a sequential (except ACKs) request - passes. + $DLG_timeout - ).
@@ -91,6 +89,32 @@
+
+ Dialog replication + + Dialog replication is a mechanism used to + mirror all dialog changes taking place in one OpenSIPS instance to one or + more other different instances. The logic is simplified by using the core + Binary Internal Interface to build and send the + replication-related UDP packets. + + + The feature is especially useful when dealing with very large systems, + where failover through a database backend is no longer feasible, due to the + high amount of time required for the backup instance to load the dialog + information stored in a typical dialog table by the + crashed instance. + + + Configuring both receival and sending of dialog replication packets is + trivial and can be done by using the + accept_replicated_dialogs and + replicate_dialogs_to parameters of the + module. In addition to this, the module also exports several statistics + regarding the number of replication packets sent/received. + +
+
Dependencies
@@ -228,33 +252,6 @@ modparam("dialog", "rr_param", "xyz")
-
- <varname>timeout_avp</varname> (string) - - The specification of an AVP to contain a custom timeout (in seconds) - for the dialog. It may be used only in a request - (initial or sequential) context. - - - - Default value is none. - - - - Set <varname>timeout_avp</varname> parameter - -... -modparam("dialog", "timeout_avp", "$avp(10)") -... - - - - - Make sure you call this before loose_route(). - - -
-
<varname>default_timeout</varname> (integer) @@ -374,12 +371,12 @@ modparam("dialog", "db_url", "&exampledb;") 1 - REALTIME - any dialog information - changes will be reflected into the database immediatly. + changes will be reflected into the database immediately. 2 - DELAYED - the dialog information - changes will be flushed into DB periodically, based on a - timre routine. + changes will be flushed into the DB periodically, based on a + timer routine. 3 - SHUTDOWN - the dialog information @@ -405,7 +402,7 @@ modparam("dialog", "db_mode", 1) <varname>db_update_period</varname> (integer) The interval (seconds) at which to update dialogs' information if you chose to store the dialogs' info at a given interval. - A too short interval will generate intensiv database operations, a too large one will not notice short dialogs. + A too short interval will generate intensive database operations, a too large one will not notice short dialogs. @@ -943,7 +940,7 @@ modparam("dialog", "db_flush_vals_profiles", 1) <varname>own_timer_proc</varname> (int) Whether the dialog timer should be a - sepparate process or if the tasks should be done in the + separate process or if the tasks should be done in the global timer process. @@ -956,7 +953,7 @@ modparam("dialog", "db_flush_vals_profiles", 1) Set <varname>own_timer_proc</varname> parameter ... -modparam("dialog", "dlg_id_column", 1) +modparam("dialog", "own_timer_proc", 1) ... @@ -1074,7 +1071,7 @@ modparam("dialog", "profile_size_prefix", "dlgs_")
<varname>profile_timeout</varname> (int) - Specifies ho long a dialog profile should be kept in the CacheDB + Specifies how long a dialog profile should be kept in the CacheDB until it expires. This is only used when distributed profiles are enabled. @@ -1093,7 +1090,108 @@ modparam("dialog", "profile_timeout", "43200")
+
+ <varname>accept_replicated_dialogs</varname> (int) + + Registers the dialog module to the &osips; Binary + Internal Interface. + + + + Default value is 0 (not registered). + + + + Set <varname>accept_replicated_dialogs</varname> parameter + +... +modparam("dialog", "accept_replicated_dialogs", 1) +... + + +
+
+ <varname>replicate_dialogs_to</varname> (string) + + Adds a new dialog replication destination. The destination will + receive all dialog-related events (creation, updating and deletion) + over UDP, using the Binary Internal Interface. + + + + Default value is null (no replication destinations). + + + + Set <varname>replicate_dialogs_to</varname> parameter + +... +modparam("dialog", "replicate_dialogs_to", "10.0.0.150:5062") +... + + +
+ +
+ <varname>th_callid_passwd</varname> (string) + + The string password that will be used for encoding/decoding the callid in case of topology_hiding with callid mangling. + + + + Default value is "OpenSIPS" + + + + Set <varname>th_callid_passwd</varname> parameter + +... +modparam("dialog", "th_callid_passwd", "my_topo_hiding_secret") +... + + +
+ +
+ <varname>th_callid_prefix</varname> (string) + + The prefix that will be used for detecting callids which have been encoded by the dialog topology hiding. Make sure to change this value in case your SIP path contains multiple OpenSIPS boxes with topology hiding. + + + + Default value is "DLGCH_" + + + + Set <varname>th_callid_prefix</varname> parameter + +... +modparam("dialog", "th_callid_prefix", "MYCALLIDPREFIX_") +... + + +
+ +
+ <varname>th_passed_contact_params</varname> (string) + + List of semicolon-separated Contact URI parameters that will be passed from one side to the other for topology hiding calls. To be used when end-to-end functionality uses such Contact parameters. + + + + Default value is empty - do not pass any parameters + + + + Set <varname>th_passed_contact_params</varname> parameter + +... +modparam("dialog", "th_passed_contact_params", "paramname1;myparam;custom_param") +... + + +
@@ -1200,7 +1298,7 @@ create_dialog("B"); injected in-dialog requests (like malicious BYEs). - The performed tests are related to CSEQ sequance checking and routing + The performed tests are related to CSEQ sequence checking and routing information checking (contact and route set). @@ -1281,12 +1379,13 @@ create_dialog("B"); get_dialog_info(attr,var,key,key_val) - The function extracts a dialog value from another dialog - it search - through all existing (ongoing) dialogs for a dialog - that has a dialog variable named "key" with the value "key_val" - (so a dialog where $dlg_val(key)=="key_val") - once found, it return - in pvar "var" the value of the the dialog variable "attr" from the - found dialog. + The function extracts a dialog value from another dialog. It first searches + through all existing (ongoing) dialogs for a dialog that has a dialog + variable named "key" with the value "key_val" + (so a dialog where $dlg_val(key)=="key_val"). If found, it returns + the value of the dialog variable "attr" from the + found dialog in the "var" pseudo-variable, otherwise nothing is written + in "var", and a negative error code is returned. NOTE: the function does not require to be called in the context of @@ -1343,10 +1442,9 @@ $dlg_val(callee) = $ru; set_dlg_profile(profile,[value]) - Inserts the current dialog into a profile. Note that the profile does - not supports values, this will be silently discarded. Also, there is - no check for inserting the same dialog in the same profile for multiple - times. + Inserts the current dialog into a profile. Note that if the profile does + not support values, this will be silently discarded. A dialog may be + inserted in the same profile multiple times. NOTE: the dialog must be created before using this function (use @@ -1679,7 +1777,7 @@ if (is_dlg_flag_set("16")) { store_dlg_value("inv_src_ip","$si"); store_dlg_value("account type","prepaid"); # or -$dlg_val("account_type") = "prepaid"; +$dlg_val(account_type) = "prepaid"; ... @@ -1718,7 +1816,7 @@ $dlg_val("account_type") = "prepaid"; fetch_dlg_value("inv_src_ip","$avp(2)"); fetch_dlg_value("account type","$var(account)"); # or -$var(account) = $dlg_val("account_type"); +$var(account) = $dlg_val(account_type); ... @@ -1757,6 +1855,26 @@ $var(account) = $dlg_val("account_type"); dialog module is that you can use all the dialog modules functionalities: profiles, dialog variables, dialog timeouts, etc.. + + Optionally,the function also receives a string parameter, which holds string flags. + Current options for the string flags are : + + + U - Propagate the Username in the Contact header URI + + + + C - Encode the callid header + + + There are many cases where propagating the callid towards the callee side is not a good idea, since sometimes the callid contains the IP of the actual caller side, thus revealing part of the network topology. + + + When using the "C" flag, the callid will be automatically encoded / decoded, transparent for the script writer - inside OpenSIPS (script,MI functions, etc ) all the variables related to the callid will represent the callid value for the caller side. If the callid for the callee side is needed, refer to the $DLG_callee_callid pvar. + + + + <function>topology_hiding</function> usage @@ -1765,6 +1883,11 @@ if(!has_totag() && is_method("INVITE")) { topology_hiding(); } ... +... +if(!has_totag() && is_method("INVITE")) { + topology_hiding("U"); +} +... @@ -1822,6 +1945,54 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BY negative reply, cancelled, etc )
+
+ <varname>create_sent</varname> + + Returns the number of replicated dialog + create requests send to other OpenSIPS + instances. + +
+
+ <varname>update_sent</varname> + + Returns the number of replicated dialog + update requests send to other OpenSIPS + instances. + +
+
+ <varname>delete_sent</varname> + + Returns the number of replicated dialog + delete requests send to other OpenSIPS + instances. + +
+
+ <varname>create_recv</varname> + + Returns the number of dialog + create events received from other + OpenSIPS instances. + +
+
+ <varname>update_recv</varname> + + Returns the number of dialog + update events received from other + OpenSIPS instances. + +
+
+ <varname>delete_recv</varname> + + Returns the number of dialog + delete events received from other + OpenSIPS instances. + +
@@ -1891,6 +2062,9 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BY dialog description the associated context from modules sitting on top of the dialog module. + This function also prints the dialog's values. In case of + binary values, the non-printable chars are represented in hex + (e.g. \x00) Name: dlg_list_ctx @@ -2066,6 +2240,25 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BY +
+ <varname>dlg_restore_db</varname> + + Restores the dialog table after a potential desynchronization event. + The table is truncated, then populated with CONFIRMED dialogs from memory. + + + Name: dlg_restore_db + + It takes no parameters + + MI FIFO Command Format: + + + :dlg_restore_db:_reply_fifo_file_ + _empty_line_ + +
+
<varname>list_all_profiles</varname> @@ -2152,7 +2345,7 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BY
<varname>$DLG_flags</varname> - Returns the dialog flags array (as a single interger value) + Returns the dialog flags array (as a single integer value) of the dialog corresponding to the processed sequential request. This PV will be available only for sequential requests, after doing loose_route(). @@ -2188,6 +2381,70 @@ if (has_totag() && (uri == myself) && is_method("INVITE|ACK|BY
+
+ <varname>$DLG_end_reason</varname> + + Returns the reason for the dialog termination. It can be + one of the following : + + + + Upstream BYE - Callee has sent a BYE + + + + Downstream BYE - Caller has sent a BYE + + + + Lifetime Timeout - Dialog lifetime expired + + + + MI Termination - Dialog ended via the MI interface + + + + Ping Timeout - Dialog ended because no reply to in-dialog pings + + + + RTPProxy Timeout - Media timeout signaled by RTPProxy + + + + + + NULL will be returned if there is no dialog for the request, + or if the dialog is not ended in the current context. + +
+ +
+ <varname>$DLG_timeout</varname> + + Used to set the dialog lifetime (in seconds). When read, the variable + returns the number of seconds until the dialog expires and is destroyed. + Note that reading the variable is only possible after the dialog is created + (for initial requests) or after doing loose_route() (for sequential requests). + Important notice: using this variable with a REALTIME db_mode is very inefficient, + because every time the dialog value is changed, a database update is done. + + + NULL will be returned if there is no dialog for the request, otherwise the + number of seconds until the dialog expiration. + +
+ +
+ <varname>$DLG_callee_callid</varname> + + Read only variable that will contain the callid as it is propagated towards the callee side, in case topology_hiding("C") is called. + + + NULL will be returned if there is no dialog for the request or if topology_hiding with callid encoding was not used for the current dialog. + +
<varname>$dlg_val(name)</varname> diff --git a/modules/dialplan/README b/modules/dialplan/README index 380acc655f2..67ad12037cc 100644 --- a/modules/dialplan/README +++ b/modules/dialplan/README @@ -2,16 +2,13 @@ dialplan Module Andreea-Ancuta Onofrei - Voice Sistem SRL - Edited by Andreea-Ancuta Onofrei Copyright © 2007-2008 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-20 17:11:05 +0300 - (Mon, 20 Jul 2009) $ + Revision $Revision: 5895 $ $Date$ __________________________________________________________ Table of Contents @@ -32,22 +29,23 @@ Andreea-Ancuta Onofrei 1.6. Exported Parameters - 1.6.1. db_url (string) - 1.6.2. table_name (string) - 1.6.3. dpid_col (string) - 1.6.4. pr_col (string) - 1.6.5. match_op_col (string) - 1.6.6. match_exp_col (string) - 1.6.7. match_flags_col (string) - 1.6.8. subst_exp_col (string) - 1.6.9. repl_exp_col (string) - 1.6.10. attrs_col (string) - 1.6.11. disabled_col (integer) - 1.6.12. attrs_pvar (string) + 1.6.1. partition (string) + 1.6.2. db_url (string) + 1.6.3. table_name (string) + 1.6.4. dpid_col (string) + 1.6.5. pr_col (string) + 1.6.6. match_op_col (string) + 1.6.7. match_exp_col (string) + 1.6.8. match_flags_col (string) + 1.6.9. subst_exp_col (string) + 1.6.10. repl_exp_col (string) + 1.6.11. attrs_col (string) + 1.6.12. disabled_col (integer) 1.7. Exported Functions - 1.7.1. dp_translate([table/]id, src/dest) + 1.7.1. dp_translate([partition:]id, src/dest[, + attrs_pvar]) 1.8. Exported MI Functions @@ -60,21 +58,23 @@ Andreea-Ancuta Onofrei List of Examples - 1.1. Set db_url parameter - 1.2. Set table_name parameter - 1.3. Set dpid_col parameter - 1.4. Set pr_col parameter - 1.5. Set match_op_col parameter - 1.6. Set match_exp_col parameter - 1.7. Set match_flags_col parameter - 1.8. Set subs_exp_col parameter - 1.9. Set repl_exp_col parameter - 1.10. Set attrs_col parameter - 1.11. Set disabled_col parameter - 1.12. Set attrs_pvar parameter - 1.13. dp_translate usage + 1.1. Set partition parameter + 1.2. Set default partition with partition parameter + 1.3. Set db_url parameter + 1.4. Set table_name parameter + 1.5. Set dpid_col parameter + 1.6. Set pr_col parameter + 1.7. Set match_op_col parameter + 1.8. Set match_exp_col parameter + 1.9. Set match_flags_col parameter + 1.10. Set subs_exp_col parameter + 1.11. Set repl_exp_col parameter + 1.12. Set attrs_col parameter + 1.13. Set disabled_col parameter 1.14. dp_translate usage 1.15. dp_translate usage + 1.16. dp_translate usage + 1.17. dp_translate usage Chapter 1. Admin Guide @@ -87,10 +87,12 @@ Chapter 1. Admin Guide 1.2. How it works At startup, the module will load a set of transformation rules - from a database. Every database raw will be stored in memory as - a translation rule. Each rule will describe how the matching - should be made, how the input value should be modified and - which attributes should be set for the matching transformation. + from multiple databases. Each database will be stored in a + partition which will have db_url and table_name parameters. + Every database row will be stored in memory as a translation + rule. Each rule will describe how the matching should be made, + how the input value should be modified and which attributes + should be set for the matching transformation. The module expects an input value which will be matched against a rules via regexp or string matching. Overlapping matching @@ -208,148 +210,161 @@ Chapter 1. Admin Guide 1.6. Exported Parameters -1.6.1. db_url (string) +1.6.1. partition (string) - The translation rules will be loaded using this database url. + This can be used to define new db_url and table_name parameters + from which to load the translation rules. These parameters will + be held in partitions. The db_url parameter is mandatory. The + order of the parameters does not matter. Multiple partitions + can be defined and you can also define the default partition + here. The name of this partition is "default". In order to be + able to use a table from a partition, its name must be found in + the "version" table belonging to the database defined in the + partition's db_url. - Default value is - “mysql://opensips:opensipsrw@localhost/opensips”. + Example 1.1. Set partition parameter +... +modparam("dialplan", "partition", " part2 : table_name = dialplan ; db_u +rl = mysql://user:passwb@localhost/db;") +... - Example 1.1. Set db_url parameter + Example 1.2. Set default partition with partition parameter +... +modparam("dialplan", "partition", " default : table_name = dialplan ; +db_url = mysql://user:passwb@localhost/db;") +... + +1.6.2. db_url (string) + + The translation rules will be loaded using this database + url.This will be the db_url parameter value for the default + partition. + + Example 1.3. Set db_url parameter ... modparam("dialplan", "db_url", "mysql://user:passwb@localhost/db") ... -1.6.2. table_name (string) +1.6.3. table_name (string) - The table's name from which to load the translation rules. + The table's name from which to load the translation rules.This + will be the table_name parameter value for the default + partition. The db_url must be defined for the default partition + in order to be able to define it's table name. Default value is “dialplan”. - Example 1.2. Set table_name parameter + Example 1.4. Set table_name parameter ... modparam("dialplan", "table_name", "my_table") ... -1.6.3. dpid_col (string) +1.6.4. dpid_col (string) The column name to store the dialplan ID group. Default value is “dpid”. - Example 1.3. Set dpid_col parameter + Example 1.5. Set dpid_col parameter ... modparam("dialplan", "dpid_col", "column_name") ... -1.6.4. pr_col (string) +1.6.5. pr_col (string) The column name to store the priority of the corresponding rule - from the database raw. + from the database row. Default value is “pr”. - Example 1.4. Set pr_col parameter + Example 1.6. Set pr_col parameter ... modparam("dialplan", "pr_col", "column_name") ... -1.6.5. match_op_col (string) +1.6.6. match_op_col (string) The column name to store the type of matching of the rule. Default value is “match_op”. - Example 1.5. Set match_op_col parameter + Example 1.7. Set match_op_col parameter ... modparam("dialplan", "match_op_col", "column_name") ... -1.6.6. match_exp_col (string) +1.6.7. match_exp_col (string) The column name to store the rule match expression. Default value is “match_exp”. - Example 1.6. Set match_exp_col parameter + Example 1.8. Set match_exp_col parameter ... modparam("dialplan", "match_exp_col", "column_name") ... -1.6.7. match_flags_col (string) +1.6.8. match_flags_col (string) The column name to store various matching flags. Currently 0 - case sensitive matching, 1 - case insensitive matching. Default value is “match_flags”. - Example 1.7. Set match_flags_col parameter + Example 1.9. Set match_flags_col parameter ... modparam("dialplan", "match_flags_col", "column_name") ... -1.6.8. subst_exp_col (string) +1.6.9. subst_exp_col (string) The column name to store the rule's substitution expression. Default value is “subst_exp”. - Example 1.8. Set subs_exp_col parameter + Example 1.10. Set subs_exp_col parameter ... modparam("dialplan", "subst_exp_col", "column_name") ... -1.6.9. repl_exp_col (string) +1.6.10. repl_exp_col (string) The column name to store the rule's replacement expression. Default value is “repl_exp”. - Example 1.9. Set repl_exp_col parameter + Example 1.11. Set repl_exp_col parameter ... modparam("dialplan", "repl_exp_col", "column_name") ... -1.6.10. attrs_col (string) +1.6.11. attrs_col (string) The column name to store the rule's attributes to be set to the message. Default value is “attrs”. - Example 1.10. Set attrs_col parameter + Example 1.12. Set attrs_col parameter ... modparam("dialplan", "attrs_col", "column_name") ... -1.6.11. disabled_col (integer) +1.6.12. disabled_col (integer) The column name that indicates if the dialplan rule is disabled. Default value is “disabled”. - Example 1.11. Set disabled_col parameter + Example 1.13. Set disabled_col parameter ... modparam("dialplan", "disabled_col", "disabled_column") ... -1.6.12. attrs_pvar (string) - - The pvar to store the rule's attributes, after translation - (dp_translate() succeeds). This parameter can be any PVAR that - can be written. - - Default value is “NULL”. - - Example 1.12. Set attrs_pvar parameter -... -modparam("dialplan", "attrs_pvar", "$avp(dest)") -... - 1.7. Exported Functions -1.7.1. dp_translate([table/]id, src/dest) +1.7.1. dp_translate([partition:]id, src/dest[, attrs_pvar]) Will try to translate the src string into dest string according to the translation rules with dialplan ID equal to id. @@ -360,38 +375,52 @@ modparam("dialplan", "attrs_pvar", "$avp(dest)") + integer - the dialplan id is statically assigned + pvar - the dialplan id is the value of an existing pseudo-variable (as integer value) - * table - Specifies the table where the search will take - place. This parameter can be ommited. The default table is - dialplan. The table parameter can have the following types: + * partition - Specifies the partition where the search will + take place. This parameter can be ommited. If the paramater + is omitted the default partition will be used if exists. + The partition parameter can have the following types: + string - the table name is statically assigned + + pvar - the partition name is the value of an existing + pseudo-variable (as string value) * src/dest - input and output of the function. If this parameter is missing the default parameter “ruri.user/ruri.user” will be used, thus translating the request uri. The “src” variable can be any type of pseudo-variable. The “dest” variable can be also any type of - pseudo-variable, but it must be a writtable one. + pseudo-variable, but it must be a writable one. + * attrs_pvar (output, optional) - a pseudo-variable which + will hold the attributes of the matched translation rule. This function can be used from REQUEST_ROUTE, BRANCH_ROUTE. - Example 1.13. dp_translate usage + Example 1.14. dp_translate usage ... dp_translate("240", "$ruri.user/$avp(dest)"); xlog("translated to var $avp(dest) \n"); ... - Example 1.14. dp_translate usage + Example 1.15. dp_translate usage ... $avp(src) = $ruri.user; -dp_translate("$var(x)", "$avp(src)/$var(y)"); -xlog("translated to var $var(y) \n"); +dp_translate("$var(x)", "$avp(src)/$var(y)", "$var(attrs)"); +xlog("translated to var $var(y) with attributes: '$var(attrs)'\n"); ... - Example 1.15. dp_translate usage + Example 1.16. dp_translate usage ... $avp(src) = $uri.user; -dp_translate("example_table/$var(x)", "$avp(src)/$var(y)"); -xlog("translated to var $var(y) \n"); +dp_translate("example_partition:$var(x)", "$avp(src)/$var(y)", "$avp(att +rs)"); +xlog("translated to var $var(y) with attributes: '$avp(attrs)'\n"); +... + + Example 1.17. dp_translate usage +... +$var(partition) = "default"; +$var(id) = 10; +dp_translate("$var(partition):$var(id)", "$avp(src)/$var(y)"); +xlog("translate to var $var(y) partition $var(partition)") ... 1.8. Exported MI Functions @@ -404,9 +433,9 @@ xlog("translated to var $var(y) \n"); Name: dp_reload Parameters: 1 - * table_name - Table to be realoaded. If no table is - specified, the table specified in the "table_name" - parameter (default dialplan) will be reloaded. + * table_name - Partition to be reloaded. If no table is + specified, the table specified in the "partition" parameter + (default "default") will be reloaded. MI DATAGRAM Command Format: :dp_reload: @@ -420,9 +449,9 @@ xlog("translated to var $var(y) \n"); Name: dp_translate Parameters: 2 - * [Table Name/]Dialplan ID - The dpid of the rules used to - match the input string. The table name can be ommited. The - default table is dialplan. + * [Partition Name:]Dialplan ID - The dpid of the rules used + to match the input string. The table name can be ommited. + The default table is dialplan. * Input String MI DATAGRAM Command Format: @@ -443,8 +472,7 @@ xlog("translated to var $var(y) \n"); Chapter 2. Developer's Guide Revision History - Revision $Revision$ $Date: 2009-07-20 17:11:05 +0300 - (Mon, 20 Jul 2009) $ + Revision $Revision: 5895 $ $Date$ The module does not provide any API to use in other OpenSIPS modules. diff --git a/modules/dialplan/dialplan.c b/modules/dialplan/dialplan.c index 2c59fe04c3e..78e2ce564cf 100644 --- a/modules/dialplan/dialplan.c +++ b/modules/dialplan/dialplan.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -41,12 +41,24 @@ #include "../../mem/mem.h" #include "../../mi/mi.h" #include "../../parser/parse_to.h" +#include "../../mod_fix.h" #include "dialplan.h" #include "dp_db.h" -#define DEFAULT_PARAM "$ruri.user" +#define DEFAULT_PARAM "$ruri.user" +#define DEFAULT_PARTITION "default" +#define PARAM_URL "db_url" +#define PARAM_TABLE "table_name" +#define DP_CHAR_COLON ':' +#define DP_CHAR_SLASH '/' +#define DP_CHAR_EQUAL '=' +#define DP_CHAR_SCOLON ';' +#define DP_TYPE_URL 0 +#define DP_TYPE_TABLE 1 +#define is_space(p) (*(p) == ' ' || *(p) == '\t' || \ + *(p) == '\r' || *(p) == '\n') static int mod_init(void); static int child_init(int rank); @@ -55,39 +67,44 @@ static int mi_child_init(); static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree,void *param); static struct mi_root * mi_translate(struct mi_root *cmd_tree, void *param); -static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2); +static int dp_translate_f(struct sip_msg *m, char *id, char *out, char *attrs); static int dp_trans_fixup(void ** param, int param_no); - -str attr_pvar_s = {NULL,0}; -pv_spec_t * attr_pvar = NULL; +static int dp_set_partition(modparam_t type, void* val); +static void dp_print_list(void); str default_param_s = str_init(DEFAULT_PARAM); +str default_dp_partition = {NULL, 0}; dp_param_p default_par2 = NULL; + static param_export_t mod_params[]={ - { "db_url", STR_PARAM, &dp_db_url.s }, - { "table_name", STR_PARAM, &dp_table_name.s }, + { "partition", STR_PARAM|USE_FUNC_PARAM, + (void*)dp_set_partition}, + { "db_url", STR_PARAM, &default_dp_db_url.s}, + { "table_name", STR_PARAM, &default_dp_table.s }, { "dpid_col", STR_PARAM, &dpid_column.s }, - { "pr_col", STR_PARAM, &pr_column.s }, + { "pr_col", STR_PARAM, &pr_column.s }, { "match_op_col", STR_PARAM, &match_op_column.s }, { "match_exp_col", STR_PARAM, &match_exp_column.s }, - { "match_flags_col",STR_PARAM, &match_flags_column.s }, + { "match_flags_col", STR_PARAM, &match_flags_column.s }, { "subst_exp_col", STR_PARAM, &subst_exp_column.s }, { "repl_exp_col", STR_PARAM, &repl_exp_column.s }, { "attrs_col", STR_PARAM, &attrs_column.s }, + { "timerec_col", STR_PARAM, &timerec_column.s }, { "disabled_col", STR_PARAM, &disabled_column.s}, - { "attrs_pvar", STR_PARAM, &attr_pvar_s.s}, - { "attribute_pvar", STR_PARAM, &attr_pvar_s.s}, {0,0,0} }; static mi_export_t mi_cmds[] = { - { "dp_reload", 0, mi_reload_rules, MI_NO_INPUT_FLAG, 0, mi_child_init}, - { "dp_translate", 0, mi_translate, 0, 0, 0}, + { "dp_reload", 0, mi_reload_rules, 0, 0, mi_child_init}, + { "dp_translate", 0, mi_translate, 0, 0, 0}, { 0, 0, 0, 0, 0, 0} }; static cmd_export_t cmds[]={ + {"dp_translate",(cmd_function)dp_translate_f, 3, dp_trans_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE|BRANCH_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"dp_translate",(cmd_function)dp_translate_f, 2, dp_trans_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE|BRANCH_ROUTE| STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, @@ -97,10 +114,22 @@ static cmd_export_t cmds[]={ {0,0,0,0,0,0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_WARN }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports= { "dialplan", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ mod_params, /* param exports */ 0, /* exported statistics */ @@ -113,14 +142,276 @@ struct module_exports exports= { child_init /* per-child init function */ }; +static inline void dp_str_copy(str* dest, str* source) +{ + + dest->len = source->len; + dest->s = pkg_malloc(source->len); + memcpy(dest->s, source->s, source->len); + +} + +static inline char* strchrchr(char* str, char c1, char c2) +{ + + char* ret = NULL; + + if (!str) + return NULL; + + for (ret = str; (ret = *ret == '\0' ? NULL : ret) + && *ret != c1 && *ret != c2; ret++); + + return ret; +} + +static inline char* memchrchr(char* str, char c1, char c2, int len) +{ + + int i; + + if (len == 0) + return NULL; + + for (i = 0; i < len; i++) { + register char c = *(str + i); + if(c == c1 || c == c2) + return str + i; + } + + return NULL; + +} + + +static dp_head_p dp_get_head(str part_name){ + + dp_head_p start; + + for (start = dp_hlist; start && + str_strcmp(&part_name, &start->partition); + start = start->next); + + return start; + +} + + +/*Inserts table_name/db url into the list of heads*/ +static int dp_head_insert(int dp_insert_type, str content, + str partition) +{ +#define h_insert(type, url_addr, table_addr, ins_addr ) \ + do{ \ + if( type == DP_TYPE_URL ) { \ + dp_str_copy(url_addr, ins_addr); \ + } else { \ + dp_str_copy(table_addr, ins_addr); \ + } \ + }while(0); + + dp_head_p start = dp_hlist; + dp_head_p tmp = NULL; + + /*First Insertion*/ + if (!dp_hlist) { + dp_hlist = pkg_malloc(sizeof *dp_hlist + partition.len); + if (!dp_hlist) { + LM_ERR("No more pkg mem\n"); + return -1; + } + memset(dp_hlist, 0, sizeof *dp_hlist); + + dp_hlist->partition.s = (char *) (dp_hlist + 1); + dp_str_copy(&dp_hlist->partition, &partition); + + h_insert( dp_insert_type, &dp_hlist->dp_db_url, + &dp_hlist->dp_table_name, &content); + dp_hlist->next = NULL; + return 0; + } + + while (start != NULL) { + if (!str_strcmp(&partition, &start->partition)) { + h_insert( dp_insert_type, &start->dp_db_url, + &start->dp_table_name, &content); + start->next = NULL; + return 0; + } + if (!start->next) { + break; + } + start = (dp_head_p)start->next; + } + + tmp = pkg_malloc(sizeof(dp_head_t)); + + if (!tmp) { + LM_ERR("No more pkg mem\n"); + return -1; + + } + dp_str_copy(&tmp->partition, &partition); + + h_insert( dp_insert_type, &tmp->dp_db_url, + &tmp->dp_table_name, &content); + start->next = (dp_head_p)tmp; + return 0; +#undef h_insert + +} + + +static str* str_n_dup(const str* src, int size){ + + str* res; + + if (!(res = pkg_malloc(sizeof(str) + size + 1))) { + LM_ERR("No more pkg mem\n"); + return NULL; + } + + res->s = (char*)res + sizeof(str); + memcpy(res->s, src->s, size); + res->len = size; + + return res; +} + + +static inline str* get_param(const char ch_type, str* main_str) +{ + str* dst = NULL; + char* end; + int ptr; + + + while ( is_space( main_str->s )) { + main_str->s++; + main_str->len--; + } + end = memchr(main_str->s, ch_type, main_str->len); + + if (!end) { + LM_ERR("Invalid partition string definition\n"); + return NULL; + } + + ptr = end - main_str->s; + main_str->len -= ptr + 1; + + while (is_space(main_str->s + ptr - 1)) { + ptr--; + } + + dst = str_n_dup(main_str, ptr); + + main_str->s = end + 1; + + return dst; +} + + +static int dp_create_head(str part_desc) +{ + + str tmp = { part_desc.s, part_desc.len }; + str* partition = NULL, *param_type = NULL, *param_value = NULL; + + char* end; + int ptr, ulen = strlen(PARAM_URL), tlen = strlen(PARAM_TABLE); + + while (is_space( tmp.s)) { + tmp.s++; + tmp.len--; + } + + end = memchr( tmp.s, DP_CHAR_COLON, tmp.len); + ptr = end - part_desc.s; + + tmp.len -= ptr+1; + + while ( is_space( part_desc.s + ptr - 1)) + ptr--; + + partition = str_n_dup( &tmp, ptr); + + tmp.s = end; + + if (!tmp.s) { + LM_ERR("Invalid partition string definition\n"); + return -1; + } + + tmp.s++; + + do { + if(! (param_type = get_param(DP_CHAR_EQUAL , &tmp))){ + LM_ERR("In getting parameter type\n"); + return -1; + } + if(! (param_value = get_param(DP_CHAR_SCOLON, &tmp))){ + LM_ERR("In getting parameter value\n"); + return -1; + } + + if ( !memcmp(param_type->s, PARAM_URL, ulen)) { + dp_head_insert( DP_TYPE_URL, *param_value, + *partition); + } else if ( !memcmp( param_type->s, PARAM_TABLE, tlen)) { + dp_head_insert( DP_TYPE_TABLE, *param_value, + *partition); + } else { + LM_ERR("Invalid parameter type\n"); + return -1; + } + } while(tmp.len > 0); + + return 0; +} + + +static int dp_set_partition(modparam_t type, void* val) +{ + + str p; + p.s = (char *)val; + p.len = strlen(val); + + if (dp_create_head(p)) { + LM_ERR("Error creating head!\n"); + return -1; + } + + return 0; +} + + +static void dp_print_list(void) +{ + dp_head_p start = dp_hlist; + + if (!start) + LM_DBG("List is empty\n"); + + while (start != NULL) { + LM_DBG("Partition %.*s url %.*s table %.*s\n", start->partition.len, + start->partition.s, start->dp_db_url.len,start->dp_db_url.s, + start->dp_table_name.len, start->dp_table_name.s); + start = (dp_head_p)start->next; + } +} + static int mod_init(void) { + + str def_str = str_init(DEFAULT_PARTITION); + dp_head_p el = dp_get_head(def_str); + LM_INFO("initializing module...\n"); - init_db_url( dp_db_url , 0 /*cannot be null*/); - dp_table_name.len = strlen(dp_table_name.s); - dpid_column.len = strlen( dpid_column.s); + dpid_column.len = strlen(dpid_column.s); pr_column.len = strlen(pr_column.s); match_op_column.len = strlen(match_op_column.s); match_exp_column.len = strlen(match_exp_column.s); @@ -128,28 +419,66 @@ static int mod_init(void) subst_exp_column.len = strlen(subst_exp_column.s); repl_exp_column.len = strlen(repl_exp_column.s); attrs_column.len = strlen(attrs_column.s); + timerec_column.len = strlen(timerec_column.s); disabled_column.len = strlen(disabled_column.s); - if(attr_pvar_s.s) { - attr_pvar = (pv_spec_t *)shm_malloc(sizeof(pv_spec_t)); - if(!attr_pvar){ - LM_ERR("out of shm memory\n"); - return -1; + if (default_dp_db_url.s) { + default_dp_db_url.len = strlen(default_dp_db_url.s); + + if (!el) { + default_dp_partition.len = sizeof(DEFAULT_PARTITION) - 1; + default_dp_partition.s = pkg_malloc(default_dp_partition.len); + + if (!default_dp_partition.s) { + LM_ERR("No more pkg memory\n"); + return -1; + } + memcpy(default_dp_partition.s, DEFAULT_PARTITION, + default_dp_partition.len); + } else { + default_dp_partition.s = el->partition.s; + default_dp_partition.len = el->partition.len; } - attr_pvar_s.len = strlen(attr_pvar_s.s); - if (pv_parse_spec(&attr_pvar_s, attr_pvar)==NULL) { - LM_ERR("invalid pvar name\n"); - return E_CFG; + dp_head_insert( DP_TYPE_URL, default_dp_db_url, + default_dp_partition); + } + + if (default_dp_table.s) { + if (!default_dp_partition.s) { + if (!el) { + LM_ERR("DB URL not defined for partition default!\n"); + return -1; + } else { + default_dp_partition.s = el->partition.s; + default_dp_partition.len = el->partition.len; + } } - if ( attr_pvar->type==PVT_NULL || attr_pvar->type==PVT_EMPTY - || attr_pvar->type==PVT_NONE ) { - LM_ERR("NULL/EMPTY Parameter TYPE for ATTR PVAR\n");\ - return E_CFG; + + default_dp_table.len = strlen(default_dp_table.s); + dp_head_insert( DP_TYPE_TABLE, default_dp_table, + default_dp_partition); + } + + el = dp_hlist; + + for (el = dp_hlist; el ; el = el->next) { + //db_url must be set + if (!el->dp_db_url.s) { + LM_ERR("DB URL is not defined for partition %.*s!\n", + el->partition.len,el->partition.s); + return -1; } - if (attr_pvar->setf==NULL) { - LM_ERR("the ATTR PVAR is read-only!!\n"); - return E_CFG; + + if (!el->dp_table_name.s) { + el->dp_table_name.len = sizeof(DP_TABLE_NAME) - 1; + el->dp_table_name.s = pkg_malloc(el->dp_table_name.len); + if(!el->dp_table_name.s){ + LM_ERR("No more pkg mem\n"); + return -1; + } + memcpy(el->dp_table_name.s, DP_TABLE_NAME, + el->dp_table_name.len); } } @@ -172,15 +501,16 @@ static int mod_init(void) return -1; } + dp_print_list(); if(init_data() != 0) { LM_ERR("could not initialize data\n"); return -1; } return 0; +#undef init_db_url_part } - static int child_init(int rank) { return 0; @@ -189,22 +519,41 @@ static int child_init(int rank) static void mod_destroy(void) { + dp_connection_list_p el; /*destroy shared memory*/ if(default_par2){ shm_free(default_par2); default_par2 = NULL; } - if(attr_pvar){ - shm_free(attr_pvar); - attr_pvar = NULL; + + LM_DBG("Disconnecting from all databases\n"); + for(el = dp_conns; el ; el = el->next){ + dp_disconnect_db(el); + + LM_DBG("Succesfully disconnected from DB %.*s\n" , + el->db_url.len, el->db_url.s); } + + destroy_data(); } static int mi_child_init(void) { - return dp_connect_db(); + + dp_connection_list_p el; + + /*Connect to DB s and get rules*/ + for(el = dp_conns; el; el = el->next){ + if (init_db_data(el) != 0) { + LM_ERR("Unable to init db data\n"); + shm_free(el); + return -1; + } + } + + return 0; } @@ -212,19 +561,41 @@ static int dp_get_ivalue(struct sip_msg* msg, dp_param_p dp, int *val) { pv_value_t value; - if(dp->type==DP_VAL_INT) { - *val = dp->v.id; - return 0; + switch (dp->type) { + case DP_VAL_STR : + *val = dp->v.id; + return 0; + case DP_VAL_INT : + *val = dp->v.pv_id.id; + return 0; + default : + break; } LM_DBG("searching %d\n",dp->v.sp[0].type); - if( pv_get_spec_value( msg, &dp->v.sp[0], &value)!=0 - || value.flags&(PV_VAL_NULL|PV_VAL_EMPTY) || !(value.flags&PV_VAL_INT)) { - LM_ERR("no PV or NULL or non-STR val found (error in scripts)\n"); + if (pv_get_spec_value( msg, &dp->v.sp[0], &value)!=0) { + LM_ERR("no PV found (error in script)\n"); + return -1; + } + + if (value.flags&(PV_VAL_NULL|PV_VAL_EMPTY)) { + LM_ERR("NULL or empty val found (error in script)\n"); return -1; } - *val = value.ri; + + if (value.flags&PV_VAL_INT) { + *val = value.ri; + } else if (value.flags&PV_VAL_STR) { + if (str2sint(&value.rs, val) != 0) { + LM_ERR("Unbale to convert to INT [%.*s]\n", value.rs.len, value.rs.s); + return -1; + } + } else { + LM_ERR("non-INT/STR val found (error in script)\n"); + return -1; + } + return 0; } @@ -237,7 +608,7 @@ static int dp_get_svalue(struct sip_msg * msg, pv_spec_t spec, str* val) if ( pv_get_spec_value(msg,&spec,&value)!=0 || value.flags&PV_VAL_NULL || value.flags&PV_VAL_EMPTY || !(value.flags&PV_VAL_STR)){ - LM_ERR("no PV or NULL or non-STR val found (error in scripts)\n"); + LM_ERR("no PV or NULL or non-STR val found (error in script)\n"); return -1; } @@ -247,7 +618,7 @@ static int dp_get_svalue(struct sip_msg * msg, pv_spec_t spec, str* val) static int dp_update(struct sip_msg * msg, pv_spec_t * src, pv_spec_t * dest, - str * repl, str * attrs) + str * repl) { pv_value_t val; @@ -260,81 +631,116 @@ static int dp_update(struct sip_msg * msg, pv_spec_t * src, pv_spec_t * dest, } } - if(!attr_pvar) - return 0; - - val.flags = PV_VAL_STR; - val.rs = *attrs; - if (pv_set_value( msg, attr_pvar, 0, &val)!=0) { - LM_ERR("falied to set the attr value!\n"); - return -1; - } - return 0; } - -static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2) +static int dp_translate_f(struct sip_msg *msg, char *str1, char *str2, + char *attr_spec) { + int dpid; str input, output; dpl_id_p idp; dp_param_p id_par, repl_par; - str attrs, * attrs_par; - dp_table_list_p table; + str attrs, *attrs_par; + dp_connection_list_p connection; + pv_value_t pval; + str partition_name; - if(!msg) + if (!msg) return -1; - /*verify first param's value*/ + /* verify first param's value */ id_par = (dp_param_p) str1; + if (dp_get_ivalue(msg, id_par, &dpid) != 0){ LM_ERR("no dpid value\n"); return -1; } - LM_DBG("dpid is %i\n", dpid); - repl_par = (str2!=NULL)? ((dp_param_p)str2):default_par2; + switch( id_par->type ) { + case DP_VAL_INT : + if (dp_get_svalue(msg, id_par->v.pv_id.partition, + &partition_name)) { + LM_ERR("invalid partition\n"); + return -1; + } + goto GET_CONN; + case DP_VAL_SPEC : + if (dp_get_svalue(msg, id_par->v.sp[1], + &partition_name)) { + LM_ERR("invalid partition\n"); + return -1; + } + GET_CONN: + if (!(id_par->hash = dp_get_connection(&partition_name))) { + LM_ERR("invalid partition\n"); + return -1; + } + + break; + default : + break; + } + + LM_DBG("dpid is %i partition is %.*s\n", dpid, + id_par->hash->partition.len, id_par->hash->partition.s); + + repl_par = (str2!=NULL) ? ((dp_param_p)str2) : default_par2; if (dp_get_svalue(msg, repl_par->v.sp[0], &input)!=0){ LM_ERR("invalid param 2\n"); return -1; } LM_DBG("input is %.*s\n", input.len, input.s); - table = id_par->hash ? id_par->hash : dp_get_default_table(); + connection = id_par->hash; /* ref the data for reading */ - lock_start_read( table->ref_lock ); + lock_start_read( connection->ref_lock ); - if ((idp = select_dpid(table, dpid, table->crt_index)) ==0 ){ + if ((idp = select_dpid(connection, dpid, connection->crt_index)) == 0) { LM_DBG("no information available for dpid %i\n", dpid); goto error; } - attrs_par = (!attr_pvar)?NULL:&attrs; - if (translate(msg, input, &output, idp, attrs_par)!=0){ + LM_DBG("Checking %.*s with dpid %i => output %.*s\n", + input.len, input.s, idp->dp_id, output.len, output.s); + + attrs_par = attr_spec ? &attrs : NULL; + if (translate(msg, input, &output, idp, attrs_par) != 0) { LM_DBG("could not translate %.*s " "with dpid %i\n", input.len, input.s, idp->dp_id); goto error; } + LM_DBG("input %.*s with dpid %i => output %.*s\n", input.len, input.s, idp->dp_id, output.len, output.s); - /*set the output*/ - if (dp_update(msg, &repl_par->v.sp[0], &repl_par->v.sp[1], - &output, attrs_par) !=0){ + /* set the output */ + if (dp_update(msg, &repl_par->v.sp[0], &repl_par->v.sp[1], &output) != 0) { LM_ERR("cannot set the output\n"); goto error; } /* we are done reading -> unref the data */ - lock_stop_read( table->ref_lock ); + lock_stop_read( connection->ref_lock ); + + if (attr_spec) { + pval.flags = PV_VAL_STR; + pval.rs = attrs; + + if (pv_set_value(msg, (pv_spec_p)attr_spec, 0, &pval) != 0) { + LM_ERR("failed to set value '%.*s' for the attr pvar!\n", + attrs.len, attrs.s); + goto error; + } + } return 1; error: /* we are done reading -> unref the data */ - lock_stop_read( table->ref_lock ); + lock_stop_read( connection->ref_lock ); return -1; } @@ -351,46 +757,48 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2) /** * Parses a dp command of the type "table_name/dpid". Skips all whitespaces. */ -static char *parse_dp_command(char * p, int len, str * table_name) + +static char *parse_dp_command(char * p, int len, str * partition_name) { char *s, *q; - while (*p == ' ') { + while (is_space(p)) { p++; len--; } if (len <= 0) { - s = strchr(p, '/'); + s = strchrchr(p, DP_CHAR_SLASH, DP_CHAR_COLON); } else { - s = memchr(p, '/', len); + s = memchrchr(p, DP_CHAR_SLASH, DP_CHAR_COLON, len); } - if (s != 0) { q = s+1; - while (s > p && *(s-1) == ' ') + while (s > p && is_space(s-1)) s--; if (s == p || (*q == '\0')) return NULL; - table_name->s = p; - table_name->len = s-p; + partition_name->s = p; + partition_name->len = s-p; p = q; - while (*p == ' ') + while (is_space(p)) p++; } else { - table_name->s = 0; - table_name->len = 0; + partition_name->s = 0; + partition_name->len = 0; } return p; } +#undef is_space + /* first param: DPID: type: INT, AVP, SVAR * second param: SRC/DST type: RURI, RURI_USERNAME, AVP, SVAR * default value for the second param: $ru.user/$ru.user @@ -400,10 +808,10 @@ static int dp_trans_fixup(void ** param, int param_no){ int dpid; dp_param_p dp_par= NULL; char *p, *s = NULL; - str lstr, table_name; - dp_table_list_t *list = NULL; + str lstr, partition_name; + dp_connection_list_t *list = NULL; - if(param_no!=1 && param_no!=2) + if (param_no < 1 || param_no > 3) return 0; p = (char*)*param; @@ -419,25 +827,35 @@ static int dp_trans_fixup(void ** param, int param_no){ } memset(dp_par, 0, sizeof(dp_param_t)); - if(param_no == 1) { - p = parse_dp_command(p, -1, &table_name); + switch (param_no) { + case 1: + p = parse_dp_command(p, -1, &partition_name); if (p == NULL) { LM_ERR("Invalid dp command\n"); return E_CFG; } - if (table_name.s && table_name.len) { - list = dp_add_table(&table_name); + if (!partition_name.s && !partition_name.len) { + partition_name.s = DEFAULT_PARTITION; + partition_name.len = sizeof(DEFAULT_PARTITION) - 1; + } - if (list == NULL) { - LM_ERR("Unable to alloc table entry\n"); - return E_OUT_OF_MEM; + if (*partition_name.s != PV_MARKER) { + list = dp_get_connection(&partition_name); + + if(!list){ + LM_ERR("Partition with name [%.*s] is not defined\n", + partition_name.len, partition_name.s ); + return -1; } + dp_par->type = DP_VAL_STR; + + } else { + dp_par->type = DP_VAL_SPEC; } - if(*p != '$') { - dp_par->type = DP_VAL_INT; + if (*p != PV_MARKER) { lstr.s = p; lstr.len = strlen(p); if(str2sint(&lstr, &dpid) != 0) { LM_ERR("bad number <%s>\n",(char *)(*param)); @@ -445,20 +863,41 @@ static int dp_trans_fixup(void ** param, int param_no){ return E_CFG; } - dp_par->type = DP_VAL_INT; - dp_par->v.id = dpid; - + if(dp_par->type == DP_VAL_SPEC){ + /*int dpid and pv partition_name*/ + dp_par->type = DP_VAL_INT; + dp_par->v.pv_id.id = dpid; + if( !pv_parse_spec( &partition_name, + &dp_par->v.pv_id.partition)) + goto error; + } else { + /*DP_VAL_STR remains DP_VAL_STR + ( int dpid and str partition_name)*/ + dp_par->v.id = dpid; + } } else { + if (dp_par->type == DP_VAL_STR) { + /*pv dpid and str partition_name*/ + dp_par->type = DP_VAL_STR_SPEC; + } else { + /*DP_VAL_SPEC remains DP_VAL_SPEC + ( pv dpid and pv partition_name) */ + if( !pv_parse_spec( &partition_name, + &dp_par->v.sp[1])) + goto error; + } + lstr.s = p; lstr.len = strlen(p); if (pv_parse_spec( &lstr, &dp_par->v.sp[0])==NULL) goto error; verify_par_type(dp_par->v.sp[0]); - dp_par->type = DP_VAL_SPEC; } dp_par->hash = list; - } else { + break; + + case 2: if( ((s = strchr(p, '/')) == 0) ||( *(s+1)=='\0')) goto error; *s = '\0'; s++; @@ -480,8 +919,12 @@ static int dp_trans_fixup(void ** param, int param_no){ } dp_par->type = DP_VAL_SPEC; + break; + + case 3: + return fixup_pvar(param); } - + *param = (void *)dp_par; return 0; @@ -496,14 +939,14 @@ static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree, void *param) { struct mi_node *node = NULL; struct mi_root *rpl_tree = NULL; - dp_table_list_t *el; + dp_connection_list_t *el; if (cmd_tree) node = cmd_tree->node.kids; if (node == NULL) { - /* Reload rules from all tables */ + /* Reload rules from all partitions */ if(dp_load_all_db() != 0){ LM_ERR("failed to reload database\n"); return 0; @@ -511,10 +954,10 @@ static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree, void *param) } else if (node->value.s == NULL || node->value.len == 0) { return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); } else { - el = dp_get_table(&node->value); + el = dp_get_connection(&node->value); if (!el) return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); - /* Reload rules from specified table */ + /* Reload rules from specified partition */ LM_DBG("Reloading rules from table %.*s\n", node->value.len, node->value.s); if(dp_load_db(el) != 0){ LM_ERR("failed to reload database data\n"); @@ -525,13 +968,13 @@ static struct mi_root * mi_reload_rules(struct mi_root *cmd_tree, void *param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==0) return 0; - + return rpl_tree; } -/* +/* * mi cmd: dp_translate - * + * * * * */ @@ -541,12 +984,12 @@ static struct mi_root * mi_translate(struct mi_root *cmd, void *param) struct mi_node* root, *node; char *p; dpl_id_p idp; - str dpid_str, table_str; + str dpid_str, partition_str; str input; int dpid; str attrs; str output= {0, 0}; - dp_table_list_p table = NULL; + dp_connection_list_p connection = NULL; node = cmd->node.kids; if(node == NULL) @@ -559,25 +1002,26 @@ static struct mi_root * mi_translate(struct mi_root *cmd, void *param) return init_mi_tree(404, "Empty id parameter", 18); } - p = parse_dp_command(dpid_str.s, dpid_str.len, &table_str); + p = parse_dp_command(dpid_str.s, dpid_str.len, &partition_str); if (p == NULL) { LM_ERR("Invalid dp command\n"); return init_mi_tree(404, "Invalid dp command", 18); } - if (table_str.s == NULL || table_str.len == 0) { - table = dp_get_default_table(); - } else { - table = dp_get_table(&table_str); - } + if (partition_str.s == NULL || partition_str.len == 0) { + partition_str.s = DEFAULT_PARTITION; + partition_str.len = sizeof(DEFAULT_PARTITION) - 1; + } + + connection = dp_get_connection(&partition_str); dpid_str.len -= (p - dpid_str.s); dpid_str.s = p; - if (!table) { - LM_ERR("Unable to get table\n"); - return init_mi_tree(400, "Wrong db table parameter", 24); + if (!connection) { + LM_ERR("Unable to get connection\n"); + return init_mi_tree(400, "Wrong db connection parameter", 24); } if(str2sint(&dpid_str, &dpid) != 0) { @@ -598,21 +1042,22 @@ static struct mi_root * mi_translate(struct mi_root *cmd, void *param) } /* ref the data for reading */ - lock_start_read( table->ref_lock ); + lock_start_read( connection->ref_lock ); - if ((idp = select_dpid(table, dpid, table->crt_index)) ==0 ){ + if ((idp = select_dpid(connection, dpid, connection->crt_index)) ==0 ){ LM_ERR("no information available for dpid %i\n", dpid); - lock_stop_read( table->ref_lock ); + lock_stop_read( connection->ref_lock ); return init_mi_tree(404, "No information available for dpid", 33); } if (translate(NULL, input, &output, idp, &attrs)!=0){ - LM_DBG("could not translate %.*s with dpid %i\n", + LM_DBG("could not translate %.*s with dpid %i\n", input.len, input.s, idp->dp_id); - goto error1; + lock_stop_read( connection->ref_lock ); + return init_mi_tree(404, "No translation", 14); } /* we are done reading -> unref the data */ - lock_stop_read( table->ref_lock ); + lock_stop_read( connection->ref_lock ); LM_DBG("input %.*s with dpid %i => output %.*s\n", input.len, input.s, idp->dp_id, output.len, output.s); @@ -632,9 +1077,6 @@ static struct mi_root * mi_translate(struct mi_root *cmd, void *param) goto error; return rpl; -error1: - /* we are done reading -> unref the data */ - lock_stop_read( table->ref_lock ); error: if(rpl) @@ -690,5 +1132,5 @@ pcre * wrap_pcre_compile(char * pattern, int flags) void wrap_pcre_free( pcre* re) { shm_free(re); - + } diff --git a/modules/dialplan/dialplan.h b/modules/dialplan/dialplan.h index 7142bf767a8..ff34f7aadee 100644 --- a/modules/dialplan/dialplan.h +++ b/modules/dialplan/dialplan.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -29,7 +29,9 @@ #include "../../parser/msg_parser.h" #include "../../rw_locking.h" +#include "../../time_rec.h" +#include "../../db/db.h" #include "../../re.h" #include @@ -47,8 +49,10 @@ typedef struct dpl_node{ int match_flags; str match_exp, subst_exp, repl_exp; /*keeping the original strings*/ pcre * match_comp, * subst_comp; /*compiled patterns*/ - struct subst_expr * repl_comp; + struct subst_expr * repl_comp; str attrs; + str timerec; + tmrec_t *parsed_timerec; struct dpl_node * next; /*next rule*/ }dpl_node_t, *dpl_node_p; @@ -68,34 +72,49 @@ typedef struct dpl_id{ struct dpl_id * next; }dpl_id_t,*dpl_id_p; -typedef struct dp_table_list { +typedef struct dp_connection_list { + dpl_id_t *hash[2]; str table_name; + str partition; + str db_url; int crt_index, next_index; + db_con_t** dp_db_handle; + db_func_t dp_dbf; + rw_lock_t *ref_lock; - struct dp_table_list * next; -} dp_table_list_t, *dp_table_list_p; + struct dp_connection_list * next; +} dp_connection_list_t, *dp_connection_list_p; #define DP_VAL_INT 0 #define DP_VAL_SPEC 1 +#define DP_VAL_STR 2 +#define DP_VAL_STR_SPEC 3 + +typedef struct dp_pv_int { + int id; + pv_spec_t partition; +} dp_pv_int_t; typedef struct dp_param{ int type; union { int id; pv_spec_t sp[2]; + dp_pv_int_t pv_id; } v; - dp_table_list_p hash; + + dp_connection_list_p hash; }dp_param_t, *dp_param_p; int init_data(); void destroy_data(); -int dp_load_db(dp_table_list_p dp_table); +int dp_load_db(dp_connection_list_p dp_table); int dp_load_all_db(void); -dpl_id_p select_dpid(dp_table_list_p table, int id, int index); +dpl_id_p select_dpid(dp_connection_list_p table, int id, int index); struct subst_expr* repl_exp_parse(str subst); void repl_expr_free(struct subst_expr *se); @@ -115,6 +134,6 @@ pcre * wrap_pcre_compile(char * pattern, int flags); void wrap_pcre_free( pcre*); -extern rw_lock_t *ref_lock; +extern rw_lock_t *ref_lock; #endif diff --git a/modules/dialplan/doc/dialplan_admin.xml b/modules/dialplan/doc/dialplan_admin.xml index fc30db612cc..3765b240988 100644 --- a/modules/dialplan/doc/dialplan_admin.xml +++ b/modules/dialplan/doc/dialplan_admin.xml @@ -15,9 +15,10 @@
How it works - At startup, the module will load a set of transformation rules from a - database. Every database raw will be stored in memory as a translation - rule. Each rule will describe how the matching should be made, how the + At startup, the module will load a set of transformation rules from multiple + databases. Each database will be stored in a partition which will have db_url + and table_name parameters. Every database row will be stored in memory as a + translation rule. Each rule will describe how the matching should be made, how the input value should be modified and which attributes should be set for the matching transformation. @@ -280,16 +281,43 @@
Exported Parameters +
- <varname>db_url</varname> (string) + <varname>partition</varname> (string) - The translation rules will be loaded using this database url. + This can be used to define new db_url and table_name parameters from which + to load the translation rules. These parameters will be held in partitions. + The db_url parameter is mandatory. The order of the parameters does not matter. + Multiple partitions can be defined and you can also define the default partition + here. The name of this partition is "default". In order to be able to use a table + from a partition, its name must be found in the "version" table belonging to the + database defined in the partition's db_url. + + + Set <varname>partition</varname> parameter + +... +modparam("dialplan", "partition", " part2 : table_name = dialplan ; db_url = mysql://user:passwb@localhost/db;") +... + + + + + Set <varname>default partition</varname> with partition parameter + +... +modparam("dialplan", "partition", " default : table_name = dialplan ; db_url = mysql://user:passwb@localhost/db;") +... + + +
+ +
+ <varname>db_url</varname> (string) - - Default value is - &defaultdb;. - + The translation rules will be loaded using this database url.This + will be the db_url parameter value for the default partition. Set <varname>db_url</varname> parameter @@ -304,7 +332,10 @@ modparam("dialplan", "db_url", "mysql://user:passwb@localhost/db")
<varname>table_name</varname> (string) - The table's name from which to load the translation rules. + The table's name from which to load the translation rules.This + will be the table_name parameter value for the default partition. + The db_url must be defined for the default partition in order to + be able to define it's table name. @@ -344,7 +375,7 @@ modparam("dialplan", "dpid_col", "column_name")
<varname>pr_col</varname> (string) - The column name to store the priority of the corresponding rule from the database raw. + The column name to store the priority of the corresponding rule from the database row. @@ -502,37 +533,14 @@ modparam("dialplan", "disabled_col", "disabled_column")
- -
- <varname>attrs_pvar</varname> (string) - - The pvar to store the rule's attributes, after translation (dp_translate() succeeds). - This parameter can be any PVAR that can be written. - - - - Default value is NULL. - - - - Set <varname>attrs_pvar</varname> parameter - -... -modparam("dialplan", "attrs_pvar", "$avp(dest)") -... - - -
-
-
Exported Functions
- <function moreinfo="none">dp_translate([table/]id, src/dest)</function> + <function moreinfo="none">dp_translate([partition:]id, src/dest[, attrs_pvar])</function> Will try to translate the src string into dest string according to @@ -550,26 +558,35 @@ modparam("dialplan", "attrs_pvar", "$avp(dest)") integer - the dialplan id is statically assigned - + pvar - the dialplan id is the value of an existing pseudo-variable (as integer value) + - table - Specifies the table where the search will - take place. This parameter can be ommited. The default table is dialplan. - The table parameter can have the following types: + partition - Specifies the partition where the search will + take place. This parameter can be ommited. If the paramater is omitted the default + partition will be used if exists. + The partition parameter can have the following types: string - the table name is statically assigned + + + pvar - the partition name is the value of an + existing pseudo-variable (as string value) + + + @@ -585,9 +602,16 @@ modparam("dialplan", "attrs_pvar", "$avp(dest)") The dest variable can be also any type of - pseudo-variable, but it must be a writtable one. + pseudo-variable, but it must be a writable one. + + + + attrs_pvar (output, optional) - a pseudo-variable + which will hold the attributes of the matched translation rule. + + This function can be used from REQUEST_ROUTE, BRANCH_ROUTE. @@ -606,8 +630,8 @@ xlog("translated to var $avp(dest) \n"); ... $avp(src) = $ruri.user; -dp_translate("$var(x)", "$avp(src)/$var(y)"); -xlog("translated to var $var(y) \n"); +dp_translate("$var(x)", "$avp(src)/$var(y)", "$var(attrs)"); +xlog("translated to var $var(y) with attributes: '$var(attrs)'\n"); ... @@ -616,8 +640,19 @@ xlog("translated to var $var(y) \n"); ... $avp(src) = $uri.user; -dp_translate("example_table/$var(x)", "$avp(src)/$var(y)"); -xlog("translated to var $var(y) \n"); +dp_translate("example_partition:$var(x)", "$avp(src)/$var(y)", "$avp(attrs)"); +xlog("translated to var $var(y) with attributes: '$avp(attrs)'\n"); +... + + + + <function>dp_translate</function> usage + +... +$var(partition) = "default"; +$var(id) = 10; +dp_translate("$var(partition):$var(id)", "$avp(src)/$var(y)"); +xlog("translate to var $var(y) partition $var(partition)") ... @@ -641,9 +676,9 @@ xlog("translated to var $var(y) \n"); Parameters: 1 - table_name - Table to be realoaded. - If no table is specified, the table specified in the "table_name" - parameter (default dialplan) will be reloaded. + table_name - Partition to be reloaded. + If no table is specified, the table specified in the "partition" + parameter (default "default") will be reloaded. @@ -667,7 +702,7 @@ xlog("translated to var $var(y) \n"); Parameters: 2 - [Table Name/]Dialplan ID - The dpid of the rules used to match the input string. The table name can be ommited. The default table is dialplan. + [Partition Name:]Dialplan ID - The dpid of the rules used to match the input string. The table name can be ommited. The default table is dialplan. Input String diff --git a/modules/dialplan/dp_db.c b/modules/dialplan/dp_db.c index c254b72a10f..1799d230190 100644 --- a/modules/dialplan/dp_db.c +++ b/modules/dialplan/dp_db.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -29,24 +29,26 @@ #include "../../dprint.h" #include "../../ut.h" -#include "../../db/db.h" +#include "../../time_rec.h" + #include "dp_db.h" -#include "dialplan.h" - -str dp_db_url = {NULL, 0}; -str dp_table_name = str_init(DP_TABLE_NAME); -str dpid_column = str_init(DPID_COL); -str pr_column = str_init(PR_COL); -str match_op_column = str_init(MATCH_OP_COL); -str match_exp_column = str_init(MATCH_EXP_COL); -str match_flags_column = str_init(MATCH_FLAGS_COL); -str subst_exp_column = str_init(SUBST_EXP_COL); -str repl_exp_column = str_init(REPL_EXP_COL); -str disabled_column = str_init(DISABLED_COL); -str attrs_column = str_init(ATTRS_COL); - -static db_con_t* dp_db_handle = 0; /* database connection handle */ -static db_func_t dp_dbf; + +dp_head_p dp_hlist = NULL; + +str default_dp_db_url = {NULL, 0}; +str default_dp_table = {NULL, 0}; +str dp_table_name = str_init(DP_TABLE_NAME); +str dpid_column = str_init(DPID_COL); +str pr_column = str_init(PR_COL); +str match_op_column = str_init(MATCH_OP_COL); +str match_exp_column = str_init(MATCH_EXP_COL); +str match_flags_column = str_init(MATCH_FLAGS_COL); +str subst_exp_column = str_init(SUBST_EXP_COL); +str repl_exp_column = str_init(REPL_EXP_COL); +str disabled_column = str_init(DISABLED_COL); +str attrs_column = str_init(ATTRS_COL); +str timerec_column = str_init(TIMEREC_COL); + #define GET_STR_VALUE(_res, _values, _index)\ do{\ @@ -58,69 +60,93 @@ static db_func_t dp_dbf; (_res).len = strlen(VAL_STR((_values)+ (_index)).s);\ }while(0); +int dp_connect_db(dp_connection_list_p conn); void destroy_rule(dpl_node_t * rule); void destroy_hash(dpl_id_t **rules_hash); dpl_node_t * build_rule(db_val_t * values); -int add_rule2hash(dpl_node_t * rule, dp_table_list_t *table, int index); +int add_rule2hash(dpl_node_t * rule, dp_connection_list_t *table, int index); void list_rule(dpl_node_t * ); void list_hash(dpl_id_t * , rw_lock_t *); -dp_table_list_p dp_tables = NULL; -dp_table_list_p dp_default_table = NULL; +dp_connection_list_p dp_conns = NULL; -dp_table_list_p dp_get_default_table(void) -{ - return dp_default_table; -} +int test_db(dp_connection_list_p dp_connection){ -int init_db_data(dp_table_list_p dp_table) -{ - if(dp_table_name.s == 0){ - LM_ERR("invalid database table name\n"); + if (dp_connection->partition.s == 0) { + LM_ERR("invalid partition name\n"); return -1; } - /* Find a database module */ - if (db_bind_mod(&dp_db_url, &dp_dbf) < 0){ + if (db_bind_mod(&dp_connection->db_url, &dp_connection->dp_dbf) < 0){ LM_ERR("unable to bind to a database driver\n"); return -1; } - if(dp_connect_db() !=0) + if (dp_connect_db(dp_connection) !=0) return -1; - if(db_check_table_version(&dp_dbf, dp_db_handle, &dp_table->table_name, - DP_TABLE_VERSION) < 0) { + + if (db_check_table_version(&dp_connection->dp_dbf, + *dp_connection->dp_db_handle, &dp_connection->table_name, + DP_TABLE_VERSION) < 0) { LM_ERR("error during table version check.\n"); goto error; } - if(dp_load_db(dp_table) != 0){ - LM_ERR("failed to load database data\n"); + dp_disconnect_db(dp_connection); + + return 0; + +error: + + dp_disconnect_db(dp_connection); + return -1; +} + + +int init_db_data(dp_connection_list_p dp_connection) +{ + if (dp_connection->partition.s == 0) { + LM_ERR("invalid partition name\n"); + return -1; + } + + if (dp_connect_db(dp_connection) !=0) + return -1; + + + if (db_check_table_version(&dp_connection->dp_dbf, + *dp_connection->dp_db_handle, &dp_connection->table_name, + DP_TABLE_VERSION) < 0) { + LM_ERR("error during table version check.\n"); goto error; } - dp_disconnect_db(); + + if(dp_load_db(dp_connection) != 0){ + LM_ERR("failed to load database data\n"); + goto error; + } return 0; error: - dp_disconnect_db(); + dp_disconnect_db(dp_connection); return -1; } -int dp_connect_db(void) +int dp_connect_db(dp_connection_list_p conn) { - if(dp_db_handle){ + if (*conn->dp_db_handle) { LM_CRIT("BUG: connection to DB already open\n"); return -1; } - if ((dp_db_handle = dp_dbf.init(&dp_db_url)) == 0){ + if ((*conn->dp_db_handle = conn->dp_dbf.init(&conn->db_url)) == 0) { LM_ERR("unable to connect to the database\n"); return -1; } @@ -129,22 +155,30 @@ int dp_connect_db(void) } -void dp_disconnect_db(void) +void dp_disconnect_db(dp_connection_list_p dp_conn) { - if(dp_db_handle){ - dp_dbf.close(dp_db_handle); - dp_db_handle = 0; + if (*dp_conn->dp_db_handle) { + dp_conn->dp_dbf.close(*dp_conn->dp_db_handle); + *dp_conn->dp_db_handle = 0; } } int init_data(void) { - dp_default_table = dp_add_table(&dp_table_name); - if (!dp_default_table) { - LM_ERR("couldn't add the default table\n"); - return -1; + dp_head_p start, tmp = NULL; + + for (start = dp_hlist ; start; start = start->next) { + if(tmp) + pkg_free(tmp); + + LM_DBG("Adding partition with name [%.*s]\n", + start->partition.len, start->partition.s); + dp_add_connection(start); + + tmp = start; } + pkg_free(tmp); return 0; } @@ -152,22 +186,23 @@ int init_data(void) void destroy_data(void) { - dp_table_list_t *el, *next; + dp_connection_list_t *el, *next; - for (el = dp_tables; el && (next = el->next, 1); el = next) { + LM_DBG("Destroying data\n"); + for (el = dp_conns; el && (next = el->next, 1); el = next) { destroy_hash(&el->hash[0]); destroy_hash(&el->hash[1]); lock_destroy_rw(el->ref_lock); + shm_free(el); - el = 0; } } int dp_load_all_db(void) { - dp_table_list_t *el; + dp_connection_list_t *el; - for (el = dp_tables; el; el = el->next) { + for (el = dp_conns; el; el = el->next) { if (dp_load_db(el) < 0) { LM_ERR("unable to load %.*s table\n", el->table_name.len, el->table_name.s); @@ -178,7 +213,7 @@ int dp_load_all_db(void) } /*load rules from DB*/ -int dp_load_db(dp_table_list_p dp_table) +int dp_load_db(dp_connection_list_p dp_conn) { int i, nr_rows; db_res_t * res = 0; @@ -187,7 +222,7 @@ int dp_load_db(dp_table_list_p dp_table) db_key_t query_cols[DP_TABLE_COL_NO] = { &dpid_column, &pr_column, &match_op_column, &match_exp_column, &match_flags_column, - &subst_exp_column, &repl_exp_column, &attrs_column }; + &subst_exp_column, &repl_exp_column, &attrs_column, &timerec_column }; db_key_t order = &pr_column; /* disabled condition */ db_key_t cond_cols[1] = { &disabled_column }; @@ -195,50 +230,62 @@ int dp_load_db(dp_table_list_p dp_table) dpl_node_t *rule; int no_rows = 10; - - if( dp_table->crt_index != dp_table->next_index){ + + + lock_start_write( dp_conn->ref_lock ); + + if( dp_conn->crt_index != dp_conn->next_index){ LM_WARN("a load command already generated, aborting reload...\n"); + lock_stop_write( dp_conn->ref_lock ); return 0; } - if (dp_dbf.use_table(dp_db_handle, &dp_table->table_name) < 0){ + dp_conn->next_index = dp_conn->crt_index == 0 ? 1 : 0; + + lock_stop_write( dp_conn->ref_lock ); + + if (dp_conn->dp_dbf.use_table(*dp_conn->dp_db_handle, &dp_conn->table_name) < 0){ LM_ERR("error in use_table\n"); - return -1; + goto err1; } VAL_TYPE(cond_val) = DB_INT; VAL_NULL(cond_val) = 0; VAL_INT(cond_val) = 0; - if (DB_CAPABILITY(dp_dbf, DB_CAP_FETCH)) { - if(dp_dbf.query(dp_db_handle,cond_cols,0,cond_val,query_cols,1, - DP_TABLE_COL_NO, order, 0) < 0){ + if (DB_CAPABILITY(dp_conn->dp_dbf, DB_CAP_FETCH)) { + if(dp_conn->dp_dbf.query(*dp_conn->dp_db_handle,cond_cols, + 0,cond_val,query_cols,1, + DP_TABLE_COL_NO, order, 0) < 0){ LM_ERR("failed to query database!\n"); - return -1; + + goto err1; } no_rows = estimate_available_rows( 4+4+4+64+4+64+64+128, DP_TABLE_COL_NO); if (no_rows==0) no_rows = 10; - if(dp_dbf.fetch_result(dp_db_handle, &res, no_rows)<0) { + if(dp_conn->dp_dbf.fetch_result(*dp_conn->dp_db_handle, + &res, no_rows)<0) { LM_ERR("failed to fetch\n"); if (res) - dp_dbf.free_result(dp_db_handle, res); - return -1; + dp_conn->dp_dbf.free_result(*dp_conn->dp_db_handle, res); + + goto err1; } } else { /*select the whole table and all the columns*/ - if(dp_dbf.query(dp_db_handle,cond_cols,0,cond_val,query_cols,1, + if(dp_conn->dp_dbf.query(*dp_conn->dp_db_handle, + cond_cols,0,cond_val,query_cols,1, DP_TABLE_COL_NO, order, &res) < 0){ LM_ERR("failed to query database\n"); - return -1; + + goto err1; } } nr_rows = RES_ROW_N(res); - lock_start_write( dp_table->ref_lock ); - dp_table->next_index = dp_table->crt_index == 0 ? 1 : 0; if(nr_rows == 0){ LM_WARN("no data in the db\n"); @@ -250,65 +297,83 @@ int dp_load_db(dp_table_list_p dp_table) rows = RES_ROWS(res); values = ROW_VALUES(rows+i); - if ((rule = build_rule(values)) == NULL ) { + if ((rule = build_rule(values)) == NULL) { LM_WARN(" failed to build rule -> skipping\n"); continue; } rule->table_id = i; - if(add_rule2hash(rule , dp_table, dp_table->next_index) != 0) { + if(add_rule2hash(rule , dp_conn, dp_conn->next_index) != 0) { LM_ERR("add_rule2hash failed\n"); goto err2; } } - if (DB_CAPABILITY(dp_dbf, DB_CAP_FETCH)) { - if(dp_dbf.fetch_result(dp_db_handle, &res, no_rows)<0) { + + if (DB_CAPABILITY(dp_conn->dp_dbf, DB_CAP_FETCH)) { + if(dp_conn->dp_dbf.fetch_result(*dp_conn->dp_db_handle, + &res, no_rows)<0) { LM_ERR("failure while fetching!\n"); if (res) - dp_dbf.free_result(dp_db_handle, res); - lock_stop_write( dp_table->ref_lock ); - return -1; + dp_conn->dp_dbf.free_result(*dp_conn->dp_db_handle, res); + goto err1; } } else { break; } } while(RES_ROW_N(res)>0); + end: - destroy_hash(&dp_table->hash[dp_table->crt_index]); + + /*update data*/ - dp_table->crt_index = dp_table->next_index; + lock_start_write( dp_conn->ref_lock ); - /* release the exclusive writing access */ - lock_stop_write( dp_table->ref_lock ); + destroy_hash(&dp_conn->hash[dp_conn->crt_index]); - list_hash(dp_table->hash[dp_table->crt_index], dp_table->ref_lock); + dp_conn->crt_index = dp_conn->next_index; - dp_dbf.free_result(dp_db_handle, res); + lock_stop_write( dp_conn->ref_lock ); + + list_hash(dp_conn->hash[dp_conn->crt_index], dp_conn->ref_lock); + + dp_conn->dp_dbf.free_result(*dp_conn->dp_db_handle, res); return 0; +err1: + + lock_start_write( dp_conn->ref_lock ); + + dp_conn->next_index = dp_conn->crt_index; + + lock_stop_write( dp_conn->ref_lock ); + + return -1; + err2: if(rule) destroy_rule(rule); - destroy_hash(&dp_table->hash[dp_table->next_index]); - dp_dbf.free_result(dp_db_handle, res); - dp_table->next_index = dp_table->crt_index; + destroy_hash(&dp_conn->hash[dp_conn->next_index]); + dp_conn->dp_dbf.free_result(*dp_conn->dp_db_handle, res); + + lock_start_write( dp_conn->ref_lock ); + + dp_conn->next_index = dp_conn->crt_index; /* if lock defined - release the exclusive writing access */ - if(dp_table->ref_lock) - /* release the readers */ - lock_stop_write( dp_table->ref_lock ); + + lock_stop_write( dp_conn->ref_lock ); return -1; } int str_to_shm(str src, str * dest) { - if(src.len ==0 || src.s ==0) + if (src.len ==0 || src.s ==0) return 0; dest->s = (char*)shm_malloc((src.len+1) * sizeof(char)); - if(!dest->s){ + if (!dest->s) { LM_ERR("out of shm memory\n"); return -1; } @@ -320,14 +385,55 @@ int str_to_shm(str src, str * dest) return 0; } +static inline tmrec_t* parse_time_def(char *time_str) { + + tmrec_p time_rec; + char *p,*s; + + p = time_str; + time_rec = 0; + + time_rec = tmrec_new(SHM_ALLOC); + if (time_rec==0) { + LM_ERR("no more shm mem\n"); + goto error; + } + + /* empty definition? */ + if ( time_str==0 || *time_str==0 ) + goto done; + + load_TR_value( p, s, time_rec, tr_parse_dtstart, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_duration, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_freq, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_until, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_interval, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_byday, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_bymday, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_byyday, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_byweekno, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_bymonth, parse_error, done); + + /* success */ +done: + return time_rec; +parse_error: + LM_ERR("parse error in <%s> around position %i\n", + time_str, (int)(long)(p-time_str)); +error: + if (time_rec) + tmrec_free( time_rec ); + return 0; +} /*compile the expressions, and if ok, build the rule */ dpl_node_t * build_rule(db_val_t * values) { + tmrec_t *parsed_timerec; pcre * match_comp, *subst_comp; struct subst_expr * repl_comp; dpl_node_t * new_rule; - str match_exp, subst_exp, repl_exp, attrs; + str match_exp, subst_exp, repl_exp, attrs, timerec; int matchop; int namecount; @@ -338,7 +444,8 @@ dpl_node_t * build_rule(db_val_t * values) return NULL; } - match_comp = subst_comp =0; + parsed_timerec = 0; + match_comp = subst_comp = 0; repl_comp = 0; new_rule = 0; @@ -420,9 +527,28 @@ dpl_node_t * build_rule(db_val_t * values) if(str_to_shm(attrs, &new_rule->attrs)!=0) goto err; - LM_DBG("attrs are %.*s\n", + LM_DBG("attrs are %.*s\n", new_rule->attrs.len, new_rule->attrs.s); + /* Retrieve and Parse Timerec Matching Pattern */ + GET_STR_VALUE(timerec, values, 8); + if(timerec.len && timerec.s) { + parsed_timerec = parse_time_def(timerec.s); + if(!parsed_timerec) { + LM_ERR("failed to parse timerec pattern %.*s\n", + timerec.len, timerec.s); + goto err; + } + + if(str_to_shm(timerec, &new_rule->timerec) != 0) + goto err; + + new_rule->parsed_timerec = parsed_timerec; + + LM_DBG("timerecs are %.*s\n", + new_rule->timerec.len, new_rule->timerec.s); + } + if (match_comp) new_rule->match_comp = match_comp; @@ -435,38 +561,37 @@ dpl_node_t * build_rule(db_val_t * values) return new_rule; err: - if(subst_comp) wrap_pcre_free(subst_comp); - if(repl_comp) repl_expr_free(repl_comp); - if(new_rule) destroy_rule(new_rule); + if(parsed_timerec) shm_free(parsed_timerec); + if(match_comp) wrap_pcre_free(match_comp); + if(subst_comp) wrap_pcre_free(subst_comp); + if(repl_comp) repl_expr_free(repl_comp); + if(new_rule) destroy_rule(new_rule); return NULL; } -int add_rule2hash(dpl_node_t * rule, dp_table_list_t *table, int index) +int add_rule2hash(dpl_node_t * rule, dp_connection_list_t *conn, int index) { dpl_id_p crt_idp; dpl_index_p indexp; int new_id, bucket = 0; - if(!table){ + if(!conn){ LM_ERR("data not allocated\n"); return -1; } new_id = 0; - crt_idp = select_dpid(table, rule->dpid, index); - + crt_idp = select_dpid(conn, rule->dpid, index); /*didn't find a dpl_id*/ if(!crt_idp){ - crt_idp = shm_malloc(sizeof(dpl_id_t) + - (DP_INDEX_HASH_SIZE+1) * sizeof(dpl_index_t)); + crt_idp = shm_malloc(sizeof(dpl_id_t) + (DP_INDEX_HASH_SIZE+1) * sizeof(dpl_index_t)); if(!crt_idp){ LM_ERR("out of shm memory (crt_idp)\n"); return -1; } - memset(crt_idp, 0, sizeof(dpl_id_t) + - (DP_INDEX_HASH_SIZE+1) * sizeof(dpl_index_t)); + memset(crt_idp, 0, sizeof(dpl_id_t) + (DP_INDEX_HASH_SIZE+1) * sizeof(dpl_index_t)); crt_idp->dp_id = rule->dpid; crt_idp->rule_hash = (dpl_index_t*)(crt_idp + 1); new_id = 1; @@ -502,13 +627,12 @@ int add_rule2hash(dpl_node_t * rule, dp_table_list_t *table, int index) indexp->last_rule = rule; if(new_id){ - crt_idp->next = table->hash[table->next_index]; - table->hash[table->next_index] = crt_idp; + crt_idp->next = conn->hash[conn->next_index]; + conn->hash[conn->next_index] = crt_idp; } LM_DBG("added the rule id %i pr %i next %p to the " " %i bucket\n", rule->dpid, - rule->pr, rule->next, rule->matchop == REGEX_OP? - DP_INDEX_HASH_SIZE : bucket); + rule->pr, rule->next, rule->matchop == REGEX_OP ? DP_INDEX_HASH_SIZE : bucket); return 0; @@ -536,7 +660,7 @@ void destroy_hash(dpl_id_t **rules_hash) i++, indexp = &crt_idp->rule_hash[i]) { for (rulep = indexp->first_rule; rulep; rulep=indexp->first_rule) { - + destroy_rule(rulep); indexp->first_rule = rulep->next; @@ -559,7 +683,7 @@ void destroy_rule(dpl_node_t * rule){ if(!rule) return; - LM_DBG("destroying rule with priority %i\n", + LM_DBG("destroying rule with priority %i\n", rule->pr); if(rule->match_comp) @@ -577,26 +701,32 @@ void destroy_rule(dpl_node_t * rule){ if(rule->subst_exp.s) shm_free(rule->subst_exp.s); - + if(rule->repl_exp.s) shm_free(rule->repl_exp.s); - + if(rule->attrs.s) shm_free(rule->attrs.s); + + if(rule->timerec.s) + shm_free(rule->timerec.s); + + if(rule->parsed_timerec) + shm_free(rule->parsed_timerec); } -dpl_id_p select_dpid(dp_table_list_p table, int id, int index) +dpl_id_p select_dpid(dp_connection_list_p conn, int id, int index) { dpl_id_p idp; - if(!table || !table->hash[index]) + if(!conn || !conn->hash[index]) return NULL; - for(idp = table->hash[index]; idp!=NULL; idp = idp->next) + for(idp = conn->hash[index]; idp!=NULL; idp = idp->next) if(idp->dp_id == id) return idp; - + return NULL; } @@ -636,45 +766,50 @@ void list_hash(dpl_id_t * hash, rw_lock_t * ref_lock) void list_rule(dpl_node_t * rule) { LM_DBG("RULE %p: pr %i next %p match_exp %.*s match_flags %d, " - "subst_exp %.*s, repl_exp %.*s and attrs %.*s\n", rule, + "subst_exp %.*s, repl_exp %.*s and attrs %.*s and timerec %.*s\n", rule, rule->pr, rule->next, - rule->match_exp.len, rule->match_exp.s, - rule->match_flags, - rule->subst_exp.len, rule->subst_exp.s, - rule->repl_exp.len, rule->repl_exp.s, - rule->attrs.len, rule->attrs.s); + rule->match_exp.len, rule->match_exp.s, + rule->match_flags, + rule->subst_exp.len, rule->subst_exp.s, + rule->repl_exp.len, rule->repl_exp.s, + rule->attrs.len, rule->attrs.s, + rule->timerec.len, rule->timerec.s); } -/* Retrieves the corresponding entry of the given table name */ -dp_table_list_p dp_get_table(str * table) +/* Retrieves the corresponding entry of the given partition name */ +dp_connection_list_p dp_get_connection(str * partition) { - dp_table_list_t *el; + dp_connection_list_t *el; - el = dp_tables; - while (el && str_strcmp(table, &el->table_name)) { + el = dp_conns; + while (el && str_strcmp(partition, &el->partition)) { el = el->next; } return el; } -/* Adds a new separate table and loads all its rules in shm */ -dp_table_list_p dp_add_table(str * table) +/* Adds a new separate partition and loads all rules from database in shm */ +dp_connection_list_p dp_add_connection(dp_head_p head) { - dp_table_list_t *el; + dp_connection_list_t *el; - if ((el = dp_get_table(table)) != NULL) + if ((el = dp_get_connection(&head->partition)) != NULL){ return el; + } - el = shm_malloc(sizeof(*el) + table->len); + int all_size = sizeof(dp_connection_list_t) +head->dp_table_name.len + + head->partition.len + head->dp_db_url.len; + el = shm_malloc(all_size); + + if(!el) + LM_ERR("No more shm\n"); - if (el == NULL) { + if (!el) { LM_ERR("No more shm mem\n"); return NULL; } - memset(el, 0, sizeof(*el)); - /* create & init lock */ if((el->ref_lock = lock_init_rw()) == NULL) { LM_ERR("Failed to init lock\n"); @@ -682,20 +817,45 @@ dp_table_list_p dp_add_table(str * table) return NULL; } - el->table_name.s = (char *)(el + 1); - el->table_name.len = table->len; - memcpy(el->table_name.s, table->s, table->len); - if (init_db_data(el) != 0) { - LM_ERR("Unable to init db data\n"); + /*Set table name*/ + el->table_name.s = (char*)el + sizeof(*el); + el->table_name.len = head->dp_table_name.len; + memcpy(el->table_name.s, head->dp_table_name.s, head->dp_table_name.len); + + + /*Set partition*/ + el->partition.s = el->table_name.s + el->table_name.len; + el->partition.len = head->partition.len; + memcpy(el->partition.s, head->partition.s, head->partition.len); + + /*Set db_url*/ + el->db_url.s = el->partition.s + el->partition.len; + el->db_url.len = head->dp_db_url.len; + memcpy(el->db_url.s, head->dp_db_url.s, head->dp_db_url.len); + + el->dp_db_handle = pkg_malloc(sizeof(db_con_t*)); + if (!el->dp_db_handle) { + LM_ERR("No more shm mem\n"); + return NULL; + } + + *el->dp_db_handle = 0; + + if (test_db(el) != 0) { + LM_ERR("Unable to test db\n"); shm_free(el); return NULL; } - el->next = dp_tables; - dp_tables = el; + *el->dp_db_handle = 0; + + el->next = dp_conns; + dp_conns = el; - LM_DBG("Added dialplan table [%.*s].\n", table->len, table->s); + LM_DBG("Added dialplan partition [%.*s] table [%.*s].\n", + head->partition.len, head->partition.s, + head->dp_table_name.len, head->dp_table_name.s); return el; } diff --git a/modules/dialplan/dp_db.h b/modules/dialplan/dp_db.h index 85163454560..0f26aad2242 100644 --- a/modules/dialplan/dp_db.h +++ b/modules/dialplan/dp_db.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -29,40 +29,56 @@ #include "../../str.h" #include "../../db/db.h" +#include "dialplan.h" +#define DP_PARTITION "default" #define DP_TABLE_NAME "dialplan" -#define DPID_COL "dpid" -#define PR_COL "pr" +#define DPID_COL "dpid" +#define PR_COL "pr" #define MATCH_OP_COL "match_op" #define MATCH_EXP_COL "match_exp" #define MATCH_FLAGS_COL "match_flags" #define SUBST_EXP_COL "subst_exp" #define REPL_EXP_COL "repl_exp" #define DISABLED_COL "disabled" -#define ATTRS_COL "attrs" +#define ATTRS_COL "attrs" +#define TIMEREC_COL "timerec" -#define DP_TABLE_VERSION 4 -#define DP_TABLE_COL_NO 8 -extern str dp_db_url; +#define DP_TABLE_VERSION 5 +#define DP_TABLE_COL_NO 9 + +typedef struct dp_head{ + str partition;/*Attribute that uniquely identifies head*/ + str dp_db_url; + str dp_table_name; + struct dp_head* next; +} dp_head_t, *dp_head_p; + + +extern dp_head_p dp_hlist; +extern dp_connection_list_p dp_conns; +extern str default_dp_db_url; +extern str default_dp_table; extern str dp_table_name; -extern str dpid_column; -extern str pr_column; -extern str match_op_column; -extern str match_exp_column; -extern str match_flags_column; -extern str subst_exp_column; -extern str repl_exp_column; -extern str attrs_column; -extern str disabled_column; +extern str dpid_column; +extern str pr_column; +extern str match_op_column; +extern str match_exp_column; +extern str match_flags_column; +extern str subst_exp_column; +extern str repl_exp_column; +extern str attrs_column; +extern str timerec_column; +extern str disabled_column; struct dp_param_list; int init_db_data(); -int dp_connect_db(); -struct dp_table_list * dp_add_table(str * table); -struct dp_table_list * dp_get_table(str * table); -struct dp_table_list * dp_get_default_table(); +//int dp_connect_db(dp_connection_list_p conn, dp_head_p head); +struct dp_connection_list * dp_add_connection(dp_head_p head ); +struct dp_connection_list * dp_get_connection(str * partition); +struct dp_connection_list * dp_get_default_connection(); void dp_disconnect_db(); #endif diff --git a/modules/dialplan/dp_repl.c b/modules/dialplan/dp_repl.c index 82aaa17a440..6cc5f8fdac4 100644 --- a/modules/dialplan/dp_repl.c +++ b/modules/dialplan/dp_repl.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -25,6 +25,7 @@ */ #include "../../re.h" +#include "../../time_rec.h" #include "dialplan.h" #define MAX_REPLACE_WITH 10 @@ -151,8 +152,8 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule, /*search for the pattern from the compiled subst_exp*/ if(test_match(string, rule->subst_comp,matches,MAX_MATCHES) <= 0){ LM_ERR("the string %.*s " - "matched the match_exp %.*s but not the subst_exp %.*s!\n", - string.len, string.s, + "matched the match_exp %.*s but not the subst_exp %.*s!\n", + string.len, string.s, rule->match_exp.len, rule->match_exp.s, rule->subst_exp.len, rule->subst_exp.s); return -1; @@ -175,10 +176,10 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule, /* offset- offset in the replacement string */ result->len = repl_nb = offset = 0; - + while( repl_nb < repl_comp->n_escapes){ token = repl_comp->replace[repl_nb]; - + if(offset< token.offset){ if((repl_comp->replacement.len < offset)|| (result->len + token.offset -offset >= MAX_PHONE_NB_DIGITS)){ @@ -186,7 +187,7 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule, goto error; } /*copy from the replacing string*/ - memcpy(result->s + result->len, repl_comp->replacement.s + offset, + memcpy(result->s + result->len, repl_comp->replacement.s + offset, token.offset-offset); result->len += (token.offset - offset); offset += token.offset-offset; /*update the offset*/ @@ -194,7 +195,7 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule, switch(token.type) { case REPLACE_NMATCH: - /*copy from the match subexpression*/ + /*copy from the match subexpression*/ match_nb = token.u.nmatch; match_begin = string.s + matches[2*match_nb]; @@ -238,7 +239,7 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule, LM_DBG("replace spec attempted on no message\n"); break; } - if(pv_get_spec_value(msg, + if(pv_get_spec_value(msg, &repl_comp->replace[repl_nb].u.spec, &sv)!=0){ LM_CRIT( "item substitution returned error\n"); break; /* ignore, we can continue */ @@ -261,7 +262,7 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule, if( repl_nb && token.offset+token.size < repl_comp->replacement.len){ /*copy from the replacing string*/ memcpy(result->s + result->len, - repl_comp->replacement.s + token.offset+token.size, + repl_comp->replacement.s + token.offset+token.size, repl_comp->replacement.len -(token.offset+token.size) ); result->len +=repl_comp->replacement.len-(token.offset+token.size); } @@ -275,11 +276,95 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule, return -1; } +int timerec_print(tmrec_p _trp) +{ + static char *_wdays[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; + int i; + + if(!_trp) + { + LM_DBG("\n(null)\n"); + return -1; + } + LM_DBG("Recurrence definition\n-- start time ---\n"); + LM_DBG("Sys time: %d\n", (int)_trp->dtstart); + LM_DBG("Time: %02d:%02d:%02d\n", _trp->ts.tm_hour, + _trp->ts.tm_min, _trp->ts.tm_sec); + LM_DBG("Date: %s, %04d-%02d-%02d\n", _wdays[_trp->ts.tm_wday], + _trp->ts.tm_year+1900, _trp->ts.tm_mon+1, _trp->ts.tm_mday); + LM_DBG("---\n"); + LM_DBG("End time: %d\n", (int)_trp->dtend); + LM_DBG("Duration: %d\n", (int)_trp->duration); + LM_DBG("Until: %d\n", (int)_trp->until); + LM_DBG("Freq: %d\n", (int)_trp->freq); + LM_DBG("Interval: %d\n", (int)_trp->interval); + if(_trp->byday) + { + LM_DBG("Byday: "); + for(i=0; i<_trp->byday->nr; i++) + LM_DBG(" %d%s", _trp->byday->req[i], _wdays[_trp->byday->xxx[i]]); + LM_DBG("\n"); + } + if(_trp->bymday) + { + LM_DBG("Bymday: %d:", _trp->bymday->nr); + for(i=0; i<_trp->bymday->nr; i++) + LM_DBG(" %d", _trp->bymday->xxx[i]*_trp->bymday->req[i]); + LM_DBG("\n"); + } + if(_trp->byyday) + { + LM_DBG("Byyday:"); + for(i=0; i<_trp->byyday->nr; i++) + LM_DBG(" %d", _trp->byyday->xxx[i]*_trp->byyday->req[i]); + LM_DBG("\n"); + } + if(_trp->bymonth) + { + LM_DBG("Bymonth: %d:", _trp->bymonth->nr); + for(i=0; i< _trp->bymonth->nr; i++) + LM_DBG(" %d", _trp->bymonth->xxx[i]*_trp->bymonth->req[i]); + LM_DBG("\n"); + } + if(_trp->byweekno) + { + LM_DBG("Byweekno: "); + for(i=0; i<_trp->byweekno->nr; i++) + LM_DBG(" %d", _trp->byweekno->xxx[i]*_trp->byweekno->req[i]); + LM_DBG("\n"); + } + LM_DBG("Weekstart: %d\n", _trp->wkst); + return 0; +} + +// Validate Passed Time Recurrence Instance +static inline int check_time(tmrec_t *time_rec) { + ac_tm_t att; + + // No TimeRec: Rule is Valid + if(time_rec->dtstart == 0) + return 1; + + // Uncomment to enable Debug + // timerec_print(time_rec); + + // Set Current Time + memset(&att, 0, sizeof(att)); + if(ac_tm_set_time(&att, time(0))) + return -1; + + // Check_Tmrec will return 0 on successfully time recurrence match + if(check_tmrec(time_rec, &att, 0) != 0) + return 0; + + // Recurrence Matched -- Validating Rule + return 1; +} + #define DP_MAX_ATTRS_LEN 32 static char dp_attrs_buf[DP_MAX_ATTRS_LEN+1]; -int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, - str * attrs) -{ +int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, str * attrs) { + dpl_node_p rulep, rrulep; int string_res = -1, regexp_res = -1, bucket; @@ -298,9 +383,19 @@ int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, if(rulep->match_exp.len != input.len) continue; - LM_DBG("Comparing (input %.*s) with (rule %.*s) [%d]\n", + LM_DBG("Comparing (input %.*s) with (rule %.*s) [%d] and timerec %.*s\n", input.len, input.s, rulep->match_exp.len, rulep->match_exp.s, - rulep->match_flags); + rulep->match_flags, rulep->timerec.len, rulep->timerec.s); + + // Check for Time Period if Set + if(rulep->parsed_timerec) { + LM_DBG("Timerec exists for rule checking: %.*s\n", rulep->timerec.len, rulep->timerec.s); + // Doesn't matches time period continue with next rule + if(!check_time(rulep->parsed_timerec)) { + LM_DBG("Time rule doesn't match: skip next!\n"); + continue; + } + } if (rulep->match_flags & DP_CASE_INSENSITIVE) { string_res = strncasecmp(rulep->match_exp.s,input.s,input.len); @@ -314,9 +409,18 @@ int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, } /* try to match the input in the regexp bucket */ - for (rrulep = idp->rule_hash[DP_INDEX_HASH_SIZE].first_rule; - rrulep; rrulep=rrulep->next) { - + for (rrulep = idp->rule_hash[DP_INDEX_HASH_SIZE].first_rule; rrulep; rrulep=rrulep->next) { + + // Check for Time Period if Set + if(rrulep->parsed_timerec) { + LM_DBG("Timerec exists for rule checking: %.*s\n", rrulep->timerec.len, rrulep->timerec.s); + // Doesn't matches time period continue with next rule + if(!check_time(rrulep->parsed_timerec)) { + LM_DBG("Time rule doesn't match: skip next!\n"); + continue; + } + } + regexp_res = (test_match(input, rrulep->match_comp, matches, MAX_MATCHES) >= 0 ? 0 : -1); @@ -334,7 +438,10 @@ int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, /* pick the rule with lowest table index if both match and prio are equal */ if ((string_res | regexp_res) == 0) { - if (rrulep->table_id < rulep->table_id) { + if (rulep->pr < rrulep->pr) { + rulep = rrulep; + } else if (rrulep->pr == rulep->pr && + rrulep->table_id < rulep->table_id) { rulep = rrulep; } } @@ -377,7 +484,7 @@ int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, int test_match(str string, pcre * exp, int * out, int out_max) { int i, result_count; - + if(!exp){ LM_ERR("invalid compiled expression\n"); return -1; diff --git a/modules/dispatcher/README b/modules/dispatcher/README index a55f566f14b..c530ce978c5 100644 --- a/modules/dispatcher/README +++ b/modules/dispatcher/README @@ -6,6 +6,12 @@ Daniel-Constantin Mierla Edited by +Ovidiu Sas + + + +Edited by + Daniel-Constantin Mierla @@ -20,8 +26,7 @@ Carsten Bock Copyright © 2005-2010 Voice-System.RO Revision History - Revision $Revision$ $Date: 2010-04-12 16:02:58 +0300 - (Mon, 12 Apr 2010) $ + Revision $Revision: 6771 $ $Date$ __________________________________________________________ Table of Contents @@ -37,41 +42,43 @@ Carsten Bock 1.3. Exported Parameters 1.3.1. db_url (string) - 1.3.2. flags (int) - 1.3.3. force_dst (int) - 1.3.4. use_default (int) - 1.3.5. attrs_avp (str) - 1.3.6. hash_pvar (str) - 1.3.7. setid_pvar (str) - 1.3.8. ds_ping_method (string) - 1.3.9. ds_ping_from (string) - 1.3.10. ds_ping_interval (int) - 1.3.11. ds_probing_sock (str) - 1.3.12. ds_probing_threshhold (int) - 1.3.13. ds_probing_mode (int) - 1.3.14. ds_define_blacklist (str) - 1.3.15. options_reply_codes (str) - 1.3.16. dst_avp (str) - 1.3.17. grp_avp (str) - 1.3.18. cnt_avp (str) - 1.3.19. sock_avp (str) - 1.3.20. pvar_algo_pattern (str) - 1.3.21. table_name (string) - 1.3.22. setid_col (string) - 1.3.23. destination_col (string) - 1.3.24. flags_col (string) - 1.3.25. weight_col (string) - 1.3.26. attrs_col (string) - 1.3.27. socket_col (string) + 1.3.2. attrs_avp (str) + 1.3.3. hash_pvar (str) + 1.3.4. setid_pvar (str) + 1.3.5. ds_ping_method (string) + 1.3.6. ds_ping_from (string) + 1.3.7. ds_ping_interval (int) + 1.3.8. ds_probing_sock (str) + 1.3.9. ds_probing_threshhold (int) + 1.3.10. ds_probing_mode (int) + 1.3.11. ds_define_blacklist (str) + 1.3.12. options_reply_codes (str) + 1.3.13. dst_avp (str) + 1.3.14. grp_avp (str) + 1.3.15. cnt_avp (str) + 1.3.16. sock_avp (str) + 1.3.17. pvar_algo_pattern (str) + 1.3.18. table_name (string) + 1.3.19. partition (string) + 1.3.20. setid_col (string) + 1.3.21. destination_col (string) + 1.3.22. state_col (string) + 1.3.23. weight_col (string) + 1.3.24. attrs_col (string) + 1.3.25. socket_col (string) 1.4. Exported Functions - 1.4.1. ds_select_dst(set, alg [, max_results]) - 1.4.2. ds_select_domain(set, alg [, max_results]) - 1.4.3. ds_next_dst() - 1.4.4. ds_next_domain() + 1.4.1. ds_select_dst(set, alg [, "[flags] [M + max_results]"]) + + 1.4.2. ds_select_domain(set, alg [, "[flags] [M + max_results]"]) + + 1.4.3. ds_next_dst([partition_name]) + 1.4.4. ds_next_domain([partition_name]) 1.4.5. ds_mark_dst() - 1.4.6. ds_mark_dst("s") + 1.4.6. ds_mark_dst([partition_name], "s") 1.4.7. ds_count(set, filter, result) 1.4.8. ds_is_in_list(ip, port [,set [,active_only]]) @@ -93,55 +100,80 @@ Carsten Bock List of Examples - 1.1. Set “db_url” parameter - 1.2. Set the “flags” parameter - 1.3. Set the “force_dst” parameter - 1.4. Set the “use_default” parameter - 1.5. Set the “attrs_avp” parameter - 1.6. Use $avp(273) for hashing: - 1.7. Use combination of PVs for hashing: - 1.8. Set the “setid_pvar” parameter - 1.9. Set the “ds_ping_method” parameter - 1.10. Set the “ds_ping_from” parameter - 1.11. Set the “ds_ping_interval” parameter - 1.12. Set the “ds_probing_sock” parameter - 1.13. Set the “ds_probing_threshhold” parameter - 1.14. Set the “ds_probing_mode” parameter - 1.15. Set the “ds_define_blacklist” parameter - 1.16. Set the “options_reply_codes” parameter - 1.17. Set the “dst_avp” parameter - 1.18. Set the “grp_avp” parameter - 1.19. Set the “cnt_avp” parameter - 1.20. Set the “sock_avp” parameter - 1.21. Set the “pvar_algo_pattern” parameter - 1.22. Set “table_name” parameter - 1.23. Set “setid_col” parameter - 1.24. Set “destination_col” parameter - 1.25. Set “flags_col” parameter - 1.26. Set “weight_col” parameter - 1.27. Set “attrs_col” parameter - 1.28. Set “socket_col” parameter - 1.29. ds_select_dst usage - 1.30. ds_count usage - 1.31. ds_is_in_list usage - 1.32. OpenSIPS config script - sample dispatcher usage + 1.1. Set the 'default' partition's“db_url” parameter + 1.2. Set the 'default' partition's “attrs_avp” parameter + 1.3. Use $avp(273) for hashing: + 1.4. Use combination of PVs for hashing: + 1.5. Set the “setid_pvar” parameter + 1.6. Set the “ds_ping_method” parameter + 1.7. Set the “ds_ping_from” parameter + 1.8. Set the “ds_ping_interval” parameter + 1.9. Set the “ds_probing_sock” parameter + 1.10. Set the “ds_probing_threshhold” parameter + 1.11. Set the “ds_probing_mode” parameter + 1.12. Set the 'default' partition's “ds_define_blacklist” + parameter + + 1.13. Set the “options_reply_codes” parameter + 1.14. Set the 'default' partition's “dst_avp” parameter + 1.15. Set the 'default' partition's “grp_avp” parameter + 1.16. Set the 'default' partition's “cnt_avp” parameter + 1.17. Set the 'default' partition's “sock_avp” parameter + 1.18. Set the “pvar_algo_pattern” parameter + 1.19. Set the 'default' partition's “table_name” parameter + 1.20. Create a new partition called 'part2' + 1.21. Set “setid_col” parameter + 1.22. Set “destination_col” parameter + 1.23. Set “state_col” parameter + 1.24. Set “weight_col” parameter + 1.25. Set “attrs_col” parameter + 1.26. Set “socket_col” parameter + 1.27. ds_select_dst usage + 1.28. ds_count usage + 1.29. ds_is_in_list usage + 1.30. OpenSIPS config script - sample dispatcher usage Chapter 1. Admin Guide 1.1. Overview This modules implements a dispatcher for destination addresses. - It computes hashes over parts of the request and selects an - address from a destination set. The selected address is then - used as outbound proxy. + It computes hashes over various parts of the request and + selects an address from a destination set. The selected address + is then used as outbound proxy. The module can be used as a stateless load balancer, having no guarantee of fair distribution. - For the distribution algotrithm, the module allows the + For the distribution algorithm, the module allows the definition of weights for the destination. This is useful in order to get a different ratio of traffic between destinations. + Since version 1.12 the dispatcher module keeps its destination + sets into different partitions. Each partition is described by + its own db_url, table_name, dst_avp, grp_avp, cnt_avp, + sock_avp, attr_avp and blacklists. Setting any of this + parameters using modparam will alter the default partition's + properties. In order to create a new partition the "partition" + parameter should be used (see below for more details). If none + of the 8 partition specific parameters are defined for the + default partition, then this partition will not be created. If + the default partition is created each undefined parameter from + all other partitions will take the value of the corresponding + one from the default partition. If there is no default + partition, the default value specified in the parameter's + description will be used. Functions taking set arguments will + now take a set number preceded by a partition name and + colon(i.e "part_name: 5"). If a set is not preceded by any + partition name the default partition will be used. Thus, the + following arguments are equivalent: "default : 4" vs "4". + Remember that in order to be able to use a table from a + partition, its name must be found in the "version" table + belonging to the database defined in the partition's db_url. + Also, in version 1.12 the "flags" parameter has been moved to + to ds_select_dst and ds_select_domain along with "force_dst" + and "use_default" flags. + 1.2. Dependencies 1.2.1. OpenSIPS modules @@ -159,82 +191,41 @@ Chapter 1. Admin Guide 1.3.1. db_url (string) - Database where to load the destinations from. + Database where to load the destinations from. Setting this + parameter will only change the default partition's db_url. Use + the partition parameter to create and alter other partitions. - Default value is “NULL” (use default DB URL from core). + Default value is “NULL”. At least one db_url should be defined + for the dispatcher module to work. - Example 1.1. Set “db_url” parameter + Example 1.1. Set the 'default' partition's“db_url” parameter ... modparam("dispatcher", "db_url", "mysql://user:passwb@localhost/database ") ... -1.3.2. flags (int) - - Various flags that affect dispatcher's behaviour. The flags are - defined as a bitmask on an integer value. If flag 1 is set only - the username part of the uri will be used when computing an uri - based hash. If no flags are set the username, hostname and port - will be used The port is used only if different from 5060 - (normal sip uri) or 5061 (in the sips case). - - If flag 2 is set, then the failover support is enabled. The - functions exported by the module will store the rest of - addresses from the destination set in AVP, and use these AVPs - to contact next address when the current-tried fails. - - Default value is “0”. - - Example 1.2. Set the “flags” parameter - ... - modparam("dispatcher", "flags", 3) - ... - -1.3.3. force_dst (int) - - If set to 1, force overwriting of destination address when that - is already set. - - Default value is “0”. - - Example 1.3. Set the “force_dst” parameter -... -modparam("dispatcher", "force_dst", 1) -... - -1.3.4. use_default (int) - - If the parameter is set to 1, the last address in destination - set is used as last option to send the message. For example, it - is good when wanting to send the call to an anouncement server - saying: "the gateways are full, try later". - - Default value is “0”. - - Example 1.4. Set the “use_default” parameter - ... - modparam("dispatcher", "use_default", 1) - ... - -1.3.5. attrs_avp (str) +1.3.2. attrs_avp (str) The name of the avp to contain the attributes string of the current destination. When a destination is selected, automatically, this AVP will provide the attributes string - this is an opaque string (from OpenSIPS point of view) : it is loaded from destination definition ( via DB) and blindly - provided in the script. + provided in the script. Setting this parameter will only change + the default partition's attrs_avp. Use the partition parameter + to create and alter other partitions. Note Default value is “null” - don't provide ATTRIBUTEs. - Example 1.5. Set the “attrs_avp” parameter - ... - modparam("dispatcher", "attrs_avp", "$avp(272)") - ... + Example 1.2. Set the 'default' partition's “attrs_avp” + parameter +... +modparam("dispatcher", "attrs_avp", "$avp(272)") +... -1.3.6. hash_pvar (str) +1.3.3. hash_pvar (str) String with PVs used for the hashing algorithm 7. @@ -245,17 +236,17 @@ Note Default value is “null” - disabled. - Example 1.6. Use $avp(273) for hashing: + Example 1.3. Use $avp(273) for hashing: ... modparam("dispatcher", "hash_pvar", "$avp(273)") ... - Example 1.7. Use combination of PVs for hashing: + Example 1.4. Use combination of PVs for hashing: ... modparam("dispatcher", "hash_pvar", "hash the $fU@$ci") ... -1.3.7. setid_pvar (str) +1.3.4. setid_pvar (str) The name of the PV where to store the set ID (group ID) when calling ds_is_in_list() without group parameter (third @@ -263,12 +254,12 @@ modparam("dispatcher", "hash_pvar", "hash the $fU@$ci") Default value is “null” - don't set PV. - Example 1.8. Set the “setid_pvar” parameter - ... - modparam("dispatcher", "setid_pvar", "$var(setid)") - ... + Example 1.5. Set the “setid_pvar” parameter +... +modparam("dispatcher", "setid_pvar", "$var(setid)") +... -1.3.8. ds_ping_method (string) +1.3.5. ds_ping_method (string) With this Method you can define, with which method you want to probe the failed gateways. This method is only available, if @@ -276,12 +267,12 @@ modparam("dispatcher", "hash_pvar", "hash the $fU@$ci") Default value is “OPTIONS”. - Example 1.9. Set the “ds_ping_method” parameter + Example 1.6. Set the “ds_ping_method” parameter ... modparam("dispatcher", "ds_ping_method", "INFO") ... -1.3.9. ds_ping_from (string) +1.3.6. ds_ping_from (string) With this Method you can define the "From:"-Line for the request, sent to the failed gateways. This method is only @@ -290,12 +281,12 @@ modparam("dispatcher", "ds_ping_method", "INFO") Default value is “sip:dispatcher@localhost”. - Example 1.10. Set the “ds_ping_from” parameter + Example 1.7. Set the “ds_ping_from” parameter ... modparam("dispatcher", "ds_ping_from", "sip:proxy@sip.somehost.com") ... -1.3.10. ds_ping_interval (int) +1.3.7. ds_ping_interval (int) With this Method you can define the interval for sending a request to a failed gateway. This parameter is only used, when @@ -304,12 +295,12 @@ modparam("dispatcher", "ds_ping_from", "sip:proxy@sip.somehost.com") Default value is “0” (disabled). - Example 1.11. Set the “ds_ping_interval” parameter + Example 1.8. Set the “ds_ping_interval” parameter ... modparam("dispatcher", "ds_ping_interval", 30) ... -1.3.11. ds_probing_sock (str) +1.3.8. ds_probing_sock (str) A socket description [proto:]host[:port] of the local socket (which is used by OpenSIPS for SIP traffic) to be used (if @@ -317,12 +308,12 @@ modparam("dispatcher", "ds_ping_interval", 30) Default value is “NULL(none)”. - Example 1.12. Set the “ds_probing_sock” parameter + Example 1.9. Set the “ds_probing_sock” parameter ... modparam("dispatcher", "ds_probing_sock", "udp:192.168.1.100:5077") ... -1.3.12. ds_probing_threshhold (int) +1.3.9. ds_probing_threshhold (int) If you want to set a gateway into probing mode, you will need a specific number of requests until it will change from "active" @@ -331,12 +322,12 @@ modparam("dispatcher", "ds_probing_sock", "udp:192.168.1.100:5077") Default value is “3”. - Example 1.13. Set the “ds_probing_threshhold” parameter + Example 1.10. Set the “ds_probing_threshhold” parameter ... modparam("dispatcher", "ds_probing_threshhold", 10) ... -1.3.13. ds_probing_mode (int) +1.3.10. ds_probing_mode (int) Controls what gateways are tested to see if they are reachable. If set to 0, only the gateways with state PROBING are tested, @@ -346,28 +337,31 @@ modparam("dispatcher", "ds_probing_threshhold", 10) Default value is “0”. - Example 1.14. Set the “ds_probing_mode” parameter + Example 1.11. Set the “ds_probing_mode” parameter ... modparam("dispatcher", "ds_probing_mode", 1) ... -1.3.14. ds_define_blacklist (str) +1.3.11. ds_define_blacklist (str) - Defines a blacklist based on a dispatching setid. This list - will contain the IPs (no port, all protocols) of the - destinations matching the given setid. + Defines a blacklist based on a dispatching setid from the + 'default' partition. This list will contain the IPs (no port, + all protocols) of the destinations matching the given setid. + Use the 'partition' parameter if you want to define blacklists + based on other partitions' sets. Multiple instances of this param are allowed. Default value is “NULL”. - Example 1.15. Set the “ds_define_blacklist” parameter + Example 1.12. Set the 'default' partition's + “ds_define_blacklist” parameter ... modparam("dispatcher", "ds_define_blacklist", "list= 1,4,3") modparam("dispatcher", "ds_define_blacklist", "blist2= 2,10,6") ... -1.3.15. options_reply_codes (str) +1.3.12. options_reply_codes (str) This parameter must contain a list of SIP reply codes separated by comma. The codes defined here will be considered as valid @@ -376,12 +370,12 @@ modparam("dispatcher", "ds_define_blacklist", "blist2= 2,10,6") Default value is “NULL”. - Example 1.16. Set the “options_reply_codes” parameter + Example 1.13. Set the “options_reply_codes” parameter ... modparam("dispatcher", "options_reply_codes", "501, 403") ... -1.3.16. dst_avp (str) +1.3.13. dst_avp (str) This is mainly for internal usage and represents the name of the avp which will hold the list with addresses, in the order @@ -390,55 +384,72 @@ modparam("dispatcher", "options_reply_codes", "501, 403") destination set. The first dst_avp_id is the selected destinations. All the other addresses from the destination set will be added in the avp list to be able to implement serial - forking. + forking. Setting this parameter will only change the default + partition's dst_avp. Use the partition parameter to create and + alter other partitions. - Default value is “$avp(ds_dst_failover)” + For the 'default' partition the default value is + “$avp(ds_dst_failover)”. For any other partition, the default + value is “$avp(ds_dst_failover_partitionname)”. - Example 1.17. Set the “dst_avp” parameter - ... - modparam("dispatcher", "dst_avp", "$avp(271)") - ... + Example 1.14. Set the 'default' partition's “dst_avp” parameter +... +modparam("dispatcher", "dst_avp", "$avp(271)") +... -1.3.17. grp_avp (str) +1.3.14. grp_avp (str) This is mainly for internal usage and represents the name of the avp storing the group id of the destination set. Good to - have it for later usage or checks. + have it for later usage or checks. Setting this parameter will + only change the default partition's grp_avp. Use the partition + parameter to create and alter other partitions. - Default value is “$avp(ds_grp_failover)”. + For the 'default' partition the default value is + “$avp(ds_grp_failover)”. For any other partition, the default + value is “$avp(ds_grp_failover_partitionname)”. - Example 1.18. Set the “grp_avp” parameter + Example 1.15. Set the 'default' partition's “grp_avp” parameter ... modparam("dispatcher", "grp_avp", "$avp(273)") ... -1.3.18. cnt_avp (str) +1.3.15. cnt_avp (str) This is mainly for internal usage and represents the name of the avp storing the number of destination addresses kept in - dst_avp avps. + dst_avp avps. Setting this parameter will only change the + default partition's cnt_avp. Use the partition parameter to + create and alter other partitions. - Default value is “$avp(ds_cnt_failover)”. + For the 'default' partition the default value is + “$avp(ds_cnt_failover)”. For any other partition, the default + value is “$avp(ds_cnt_failover_partitionname)”. - Example 1.19. Set the “cnt_avp” parameter + Example 1.16. Set the 'default' partition's “cnt_avp” parameter ... modparam("dispatcher", "cnt_avp", "$avp(274)") ... -1.3.19. sock_avp (str) +1.3.16. sock_avp (str) This is mainly for internal usage and represents the name of the avp storing the sockets to be used for the destination - addresses kept in dst_avp avps. + addresses kept in dst_avp avps. Setting this parameter will + only change the default partition's sock_avp. Use the partition + parameter to create and alter other partitions. - Default value is “$avp(ds_sock_failover)”. + For the 'default' partition the default value is + “$avp(ds_sock_failover)”. For any other partition, the default + value is “$avp(ds_sock_failover_partitionname)”. - Example 1.20. Set the “sock_avp” parameter + Example 1.17. Set the 'default' partition's “sock_avp” + parameter ... modparam("dispatcher", "sock_avp", "$avp(275)") ... -1.3.20. pvar_algo_pattern (str) +1.3.17. pvar_algo_pattern (str) This parameter is used by the PVAR(9) algorithm to specify the pseudovariable pattern used to detect the load of each @@ -448,105 +459,135 @@ modparam("dispatcher", "sock_avp", "$avp(275)") Default value is “none”. - Example 1.21. Set the “pvar_algo_pattern” parameter + Example 1.18. Set the “pvar_algo_pattern” parameter ... -modparam("dispatcher", "sock_avp", "$stat(load_%u)") +modparam("dispatcher", "pvar_algo_pattern", "$stat(load_%u)") ... -1.3.21. table_name (string) +1.3.18. table_name (string) If you want to load the sets of gateways from the database you - must set this parameter as the database name. + must set this parameter as the database name. Setting this + parameter will only change the default partition's table_name. + Use the partition parameter to create and alter other + partitions. - Default value is “dispatcher”. + For every partition the default value is “dispatcher”. - Example 1.22. Set “table_name” parameter + Example 1.19. Set the 'default' partition's “table_name” + parameter ... modparam("dispatcher", "table_name", "my_dispatcher") ... -1.3.22. setid_col (string) +1.3.19. partition (string) + + Using this parameter the partition specific parameters (db_url, + table_name, dst_avp, grp_avp, cnt_avp, sock_avp, attrs_avp, + ds_define_blacklist) can be defined. + + The syntax is: "partition_name: param1 = value1; param2 = + value2; param3 = value3". Each value format is the same as the + one used to define a specific parameter using modparam. + + Whenever a new partition_name is provided, a new partition will + be automatically created. The 'default' partition can also be + defined using this parameter. + + Example 1.20. Create a new partition called 'part2' +... +modparam("dispatcher", "partition", "part2 : db_url=mysql://user:passwd@ +localhost/database; table_name = ds_table; ds_define_blacklist= list2= 4 +,6;") +... + +1.3.20. setid_col (string) The column's name in the database storing the gateway's group id. Default value is “setid”. - Example 1.23. Set “setid_col” parameter + Example 1.21. Set “setid_col” parameter ... modparam("dispatcher", "setid_col", "groupid") ... -1.3.23. destination_col (string) +1.3.21. destination_col (string) The column's name in the database storing the destination's sip uri. Default value is “destination”. - Example 1.24. Set “destination_col” parameter + Example 1.22. Set “destination_col” parameter ... modparam("dispatcher", "destination_col", "uri") ... -1.3.24. flags_col (string) +1.3.22. state_col (string) - The column's name in the database storing the flags for + The column's name in the database storing the state of the destination uri. - Default value is “flags”. + Default value is “state”. - Example 1.25. Set “flags_col” parameter + Example 1.23. Set “state_col” parameter ... -modparam("dispatcher", "flags_col", "dstflags") +modparam("dispatcher", "state_col", "dststate") ... -1.3.25. weight_col (string) +1.3.23. weight_col (string) The column's name in the database storing the weight for destination uri. Default value is “weight”. - Example 1.26. Set “weight_col” parameter + Example 1.24. Set “weight_col” parameter ... modparam("dispatcher", "weight_col", "dstweight") ... -1.3.26. attrs_col (string) +1.3.24. attrs_col (string) The column's name in the database storing the attributes (opaque string) for destination uri. Default value is “attrs”. - Example 1.27. Set “attrs_col” parameter + Example 1.25. Set “attrs_col” parameter ... modparam("dispatcher", "attrs_col", "dstattrs") ... -1.3.27. socket_col (string) +1.3.25. socket_col (string) The column's name in the database storing the socket (as string) for destination uri. Default value is “socket”. - Example 1.28. Set “socket_col” parameter + Example 1.26. Set “socket_col” parameter ... modparam("dispatcher", "socket_col", "my_sock") ... 1.4. Exported Functions -1.4.1. ds_select_dst(set, alg [, max_results]) +1.4.1. ds_select_dst(set, alg [, "[flags] [M max_results]"]) - The method selects a destination from addresses set. + The method selects a destination from the given set of + addresses. It will overwrite the "destination URI" of a SIP + request ($du). Meaning of the parameters is as follows: - * set - the id of the set from where to pick up destination - address. - * alg - the algorithm used to select the destination address. + * set - a partition name followed by colon and an id of the + set or a list of sets from where to pick up destination + address (variables are accepted). If the partition name is + missing, the default partition will be used. + * alg - the algorithm(s) used to select the destination + address (variables are accepted). + “0” - hash over callid + “1” - hash over from uri. + “2” - hash over to uri. @@ -565,70 +606,108 @@ modparam("dispatcher", "socket_col", "my_sock") chosen. + “X” - if the algorithm is not implemented, the first entry in set is chosen. + * flags - If specified, this will be the flags which in + previous versions were specified at startup. The flags are + the failover support flag('f'/'F') letters, the user only + flag('u'/'U') and will specify that only the uri user part + will be used for hashing, the force destination + flag('S'/'s') which will Skip overwriting the destination + address if it is already set and the use default flag('D', + 'd') which will use the last address in destination set as + last option to send the message.You can also specify these + flags using PVs. The flags are being kept per partition. * max_results - If specified, only that many results will be put into the specified avp for failover. This allows having many destinations but limit the useless traffic in case of - a number that is bound to fail everywhere. - - If the bit 2 in 'flags' is set, the rest of the addresses from - the destination set is stored in AVP list. You can use - 'ds_next_dst()' to use next address to achieve serial forking - to all possible destinations. + a number that is bound to fail everywhere. It can accept + variables. The definition must begin with 'M' character + either you use static definition or PVs. + + If the character 'f' in 'flags' is set, the rest of the + addresses from the destination set is stored in AVP list. You + can use 'ds_next_dst()' to use next address to achieve serial + forking to all possible destinations. If multiple dispatching + groups are used, the AVP list is constructed based on the + position of each dispatching id in the list: first one has the + higher priority, followed by the second one and so on. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.29. ds_select_dst usage + Example 1.27. ds_select_dst usage ... ds_select_dst("1", "0"); ... -ds_select_dst("1", "0", "5"); +ds_select_dst("part2 : 1", "0", "M 5"); +... +ds_select_dst("part3 : 1", "0", "fUsD"); +... +ds_select_dst("part4 : 2", "0", "fuD M 5,2"); +... +# dispatch over multiple dispatching groups +$var(partition_name) = "p4" +$var(setid) = "1, 2"; +$var(alg) = "4, 2"; +$var(max) = "2,3"; +$var(flags) = " sFDU"; +ds_select_dst("$var(partition_name):$var(setid)", "$var(alg)", "$var(fla +gs) M $var(max)"); ... -1.4.2. ds_select_domain(set, alg [, max_results]) +1.4.2. ds_select_domain(set, alg [, "[flags] [M max_results]"]) The method selects a destination from addresses set and rewrites the host and port from R-URI. The parameters have same meaning as for ds_select_dst(). - If the bit 2 in 'flags' is set, the rest of the addresses from - the destination set is stored in AVP list. You can use - 'ds_next_domain()' to use next address to achieve serial - forking to all possible destinations. + If the character 'f' in 'flags' is set, the rest of the + addresses from the destination set is stored in AVP list. You + can use 'ds_next_domain()' to use next address to achieve + serial forking to all possible destinations. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. -1.4.3. ds_next_dst() +1.4.3. ds_next_dst([partition_name]) Takes the next destination address from the AVPs with id - 'dst_avp_id' and sets the dst_uri (outbound proxy address). + partition.'dst_avp_id' and sets the dst_uri (outbound proxy + address). If partition_name is omitted, the default partition + will be used.This function is using the flags set in + ds_select_dst or ds_select_domain. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. -1.4.4. ds_next_domain() +1.4.4. ds_next_domain([partition_name]) Takes the next destination address from the AVPs with id - 'dst_avp_id' and sets the domain part of the request uri. + partition.'dst_avp_id' and sets the domain part of the request + uri. If partition_name is omitted, the default partition will + be used.This function is using the flags set in ds_select_dst + or ds_select_domain. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. 1.4.5. ds_mark_dst() - Mark the last used address from destination set as inactive, in - order to be ingnored in the future. In this way it can be - implemented an automatic detection of failed gateways. When an - address is marked as inactive, it will be ignored by - 'ds_select_dst' and 'ds_select_domain'. + Mark the last used address from the 'default' partition's + destination set as inactive, in order to be ignored in the + future. In this way it can be implemented an automatic + detection of failed gateways. When an address is marked as + inactive, it will be ignored by 'ds_select_dst' and + 'ds_select_domain'. This function is using the flags set in + ds_select_dst or ds_select_domain. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. -1.4.6. ds_mark_dst("s") +1.4.6. ds_mark_dst([partition_name], "s") - Mark the last used address from destination set as inactive - ("i"/"I"/"0"), active ("a"/"A"/"1") or probing ("p"/"P"/"2"). - With this function, an automatic detection of failed gateways - can be implemented. When an address is marked as inactive or - probing, it will be ignored by 'ds_select_dst' and - 'ds_select_domain'. + Mark the last used address from partition's destination set as + inactive ("i"/"I"/"0"), active ("a"/"A"/"1") or probing + ("p"/"P"/"2"). With this function, an automatic detection of + failed gateways can be implemented. When an address is marked + as inactive or probing, it will be ignored by 'ds_select_dst' + and 'ds_select_domain'. If partition_name is omitted, the + default partition will be used. This function is using the + flags set in ds_select_dst or ds_select_domain. possible parameters: * "i", "I" or "0" - the last destination should be set to @@ -637,7 +716,7 @@ ds_select_dst("1", "0", "5"); active. * "p", "P" or "2" - the last destination will be set to probing. Note: You will need to call this function - "threshhold"-times, before it will be actually set to + "threshold"-times, before it will be actually set to probing. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. @@ -645,15 +724,13 @@ ds_select_dst("1", "0", "5"); 1.4.7. ds_count(set, filter, result) Returns the number of active, inactive or probing destinations - in a set, or combinations between these properties. + in a partition's set, or combinations between these properties. Meaning of the parameters: - * set - a set of dispatching destinations. The set parameter - can have the following types: - + integer - the dispatching set is passed in a static - manner - + pvar - the dispatching set is the value of an existing - pseudo-variable (as integer value) + * set - a partition name followed by colon and an id of a set + of dispatching destinations (variables are accepted). If + the partition name is missing, the default partition will + be used. * filter - which destinations should be counted. Either active destinations("a", "A" or "1"), inactive destinations("i", "I" or "0") or probing ones("p", "P" or @@ -666,13 +743,13 @@ ds_select_dst("1", "0", "5"); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, LOCAL_ROUTE, TIMER_ROUTE, EVENT_ROUTE - Example 1.30. ds_count usage + Example 1.28. ds_count usage ... if (ds_count("1", "a", "$avp(result)")) { ... } ... -if (ds_count("$avp(set)", "ip", "$avp(result)")) { +if (ds_count("$avp(partition) : $avp(set)", "ip", "$avp(result)")) { ... } ... @@ -689,9 +766,13 @@ if (ds_count("$avp(set)", "ip", "$avp(result)")) { PORT to test against the dispatcher list. This can be empty - in this case the port will excluded from the matching of IP against the dispatcher list. - * set (optional) - the set ID of a dispatcher list to test - agaist - if missing, all the dispatching sets will the - checked. + * set (optional) - a partition name followed by colon and the + set ID of a dispatcher list to test against. If the + partition name is omitted the default partition will be + used. If the set id is missing, all the dispatching sets + will the checked. If a partition name is specified then it + must be followed by colon regardless of the set id being + specified or not. * active_only (optional) - search only through the active destinations (ignore the ones in probing and inactive mode). @@ -699,14 +780,20 @@ if (ds_count("$avp(set)", "ip", "$avp(result)")) { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE and ONREPLY_ROUTE. - Example 1.31. ds_is_in_list usage + Example 1.29. ds_is_in_list usage ... if (ds_is_in_list("$si", "$sp")) { # source IP:PORT is in a dispatcher list } ... if (ds_is_in_list("$rd", "$rp", "2")) { - # source RURI (ip and port) is in the dispatcher list id "2" + # source RURI (ip and port) is in the dispatcher list id "2" of +the default partition +} +... +if (ds_is_in_list("$rd", "$rp", "part2:2")) { + # source RURI (ip and port) is in the dispatcher list id "2" of +the partition called 'part2' } ... @@ -724,38 +811,42 @@ if (ds_is_in_list("$rd", "$rp", "2")) { + “a”: active + “i”: inactive + “p”: probing - * _group_: destination group id + * _group_: partition name followed by colon and destination + group id. If the partition name is omitted, the default + partition will be used * _address_: address of the destination in the _group_ MI FIFO Command Format: - :ds_set_state:_reply_fifo_file_ - _state_ - _group_ - _address_ - _empty_line_ +:ds_set_state:_reply_fifo_file_ +_state_ +_group_ +_address_ +_empty_line_ 1.5.2. ds_list - It lists the groups and included destinations. + It lists the groups and included destinations of all the + partitions. Name: ds_list Parameters: none MI FIFO Command Format: - :ds_list:_reply_fifo_file_ - _empty_line_ +:ds_list:_reply_fifo_file_ +_empty_line_ 1.5.3. ds_reload - It reloads the groups and included destinations. + It reloads the groups and included destinations for all + partitions. Name: ds_reload Parameters: none MI DATAGRAM Command Format: - ":ds_reload:\n." +":ds_reload:\n." 1.6. Exported Events @@ -765,6 +856,7 @@ if (ds_is_in_list("$rd", "$rp", "2")) { destination as activated or deactivated. Parameters: + * partition - the partition name of the destination. * group - the group of the destination. * address - the address of the destination. * status - active if the destination gets activated or @@ -776,14 +868,14 @@ if (ds_is_in_list("$rd", "$rp", "2")) { Next picture displays a sample usage of dispatcher. - Example 1.32. OpenSIPS config script - sample dispatcher usage + Example 1.30. OpenSIPS config script - sample dispatcher usage ... # # $Id$ # sample config file for dispatcher module # -debug=9 # debug level (cmd line: -dddddddddd) +debug=9 # debug level (cmd line: -ddddddd) fork=no log_stderror=yes # (cmd line: -E) @@ -849,7 +941,7 @@ Chapter 2. Frequently Asked Questions 2.3. - What happend with the ds_is_from_list() function? + What happened with the ds_is_from_list() function? The function was replaced by the more generic ds_is_in_list() function that takes as parameters the IP and PORT to test @@ -859,7 +951,7 @@ Chapter 2. Frequently Asked Questions 2.4. - What happend with the list_file module parameter ? + What happened with the list_file module parameter ? The support for text file (for provisioning destinations) was dropped. Only the DB support (provisioning via a DB table) is @@ -897,4 +989,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389 + https://github.com/OpenSIPS/opensips/issues diff --git a/modules/dispatcher/dispatch.c b/modules/dispatcher/dispatch.c index cb4e185b401..b44720d4fe3 100644 --- a/modules/dispatcher/dispatch.c +++ b/modules/dispatcher/dispatch.c @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -29,18 +29,19 @@ * 2005-12-10 added failover support via avp (daniel) * 2006-08-15 added support for authorization username hashing (carsten) * 2007-01-11 Added a function to check if a specific gateway is in a - * group (carsten) + * group (carsten) * 2007-01-12 Added a threshhold for automatic deactivation (carsten) * 2007-02-09 Added active probing of failed destinations and automatic - * re-enabling of destinations (carsten) + * re-enabling of destinations (carsten) * 2007-05-08 Ported the changes to SVN-Trunk, renamed ds_is_domain to - * ds_is_from_list and modified the function to work with IPv6 adresses. - * 2007-07-18 removed index stuff - * added DB support to load/reload data(ancuta) + * ds_is_from_list and modified the function to work with IPv6 adresses. + * 2007-07-18 removed index stuff + * added DB support to load/reload data(ancuta) * 2007-09-17 added list-file support for reload data (carstenbock) * 2009-05-18 Added support for weights for the destinations; * added support for custom "attrs" (opaque string) (bogdan) - + * 2013-12-02 Added support state persistency (restart and reload) (bogdan) + * 2013-12-05 Added a safer reload mechanism based on locking read/writter (bogdan) */ #include @@ -64,61 +65,92 @@ #include "../../db/db.h" #include "../../db/db_res.h" #include "../../str.h" +#include "../../rw_locking.h" #include "dispatch.h" +#include "ds_bl.h" + +#define DS_TABLE_VERSION 7 -#define DS_TABLE_VERSION 5 +extern ds_partition_t *partitions; extern struct socket_info *probing_sock; extern event_id_t dispatch_evi_id; +extern ds_partition_t *default_partition; + +int init_ds_data(ds_partition_t *partition) +{ + partition->data = (ds_data_t**)shm_malloc( sizeof(ds_data_t*) ); + if (partition->data==NULL) { + LM_ERR("failed to allocate data holder in shm\n"); + return -1; + } -extern int ds_force_dst; + *partition->data = NULL; -static db_func_t ds_dbf; -static db_con_t* ds_db_handle=0; -ds_set_p *ds_lists=NULL; -int *ds_list_nr = NULL; -int *crt_idx = NULL; -int *next_idx = NULL; + /* create & init lock */ + if ((partition->lock = lock_init_rw()) == NULL) { + LM_CRIT("failed to init reader/writer lock\n"); + return -1; + } -#define _ds_list (ds_lists[*crt_idx]) -#define _ds_list_nr (*ds_list_nr) + return 0; +} -void destroy_list(int); -int init_data(void) +/* destroy entire dispatching data */ +static void ds_destroy_data_set( ds_data_t *d) { - int * p; + ds_set_p sp; + ds_set_p sp_curr; + ds_dest_p dest; - ds_lists = (ds_set_p*)shm_malloc(2*sizeof(ds_set_p)); - if(!ds_lists) - { - LM_ERR("Out of memory\n"); - return -1; + /* free the list of sets */ + sp = d->sets; + while(sp) { + sp_curr = sp; + sp = sp->next; + + dest = sp_curr->dlist; + if (dest) { + do { + if(dest->uri.s!=NULL) + shm_free(dest->uri.s); + if(dest->param) + shm_free(dest->param); + dest = dest->next; + }while(dest); + shm_free(sp_curr->dlist); + } + shm_free(sp_curr); } - ds_lists[0] = ds_lists[1] = 0; + /* free the data holder */ + shm_free(d); +} - p = (int*)shm_malloc(3*sizeof(int)); - if(!p) - { - LM_ERR("Out of memory\n"); - return -1; - } - crt_idx = p; - next_idx = p+1; - ds_list_nr = p+2; - *crt_idx= *next_idx = 0; +/* destroy current dispatching data */ +void ds_destroy_data(ds_partition_t *partition) +{ + if (partition->data && *partition->data) + ds_destroy_data_set( *partition->data ); - return 0; + /* destroy rw lock */ + if (partition->lock) { + lock_destroy_rw( partition->lock ); + partition->lock = 0; + } } -int add_dest2list(int id, str uri, struct socket_info *sock, int flags, - int weight, str attrs, int list_idx, int * setn) + +int add_dest2list(int id, str uri, struct socket_info *sock, int state, + int weight, int prio, str attrs, ds_data_t *d_data) { ds_dest_p dp = NULL; ds_set_p sp = NULL; + short new_set = 0; + ds_dest_p dp_it, dp_prev; struct sip_uri puri; /* For DNS-Lookups */ @@ -133,12 +165,9 @@ int add_dest2list(int id, str uri, struct socket_info *sock, int flags, } /* get dest set */ - sp = ds_lists[list_idx]; - while(sp) - { + for( sp=d_data->sets ; sp ; sp=sp->next) { if(sp->id == id) break; - sp = sp->next; } if(sp==NULL) @@ -147,16 +176,13 @@ int add_dest2list(int id, str uri, struct socket_info *sock, int flags, if(sp==NULL) { LM_ERR("no more memory.\n"); - goto err; + return -1; } - + + new_set = 1; memset(sp, 0, sizeof(ds_set_t)); - sp->next = ds_lists[list_idx]; - ds_lists[list_idx] = sp; - *setn = *setn+1; + sp->id = id; } - sp->id = id; - sp->nr++; dp = (ds_dest_p)shm_malloc(sizeof(ds_dest_t)); if(dp==NULL) @@ -167,26 +193,70 @@ int add_dest2list(int id, str uri, struct socket_info *sock, int flags, memset(dp, 0, sizeof(ds_dest_t)); /* store uri and attrs strings */ - dp->uri.s = (char*)shm_malloc( (uri.len+1+attrs.len+1)*sizeof(char)); - if(dp->uri.s==NULL) - { - LM_ERR("no more shm memory!\n"); - goto err; - } - memcpy(dp->uri.s, uri.s, uri.len); - dp->uri.s[uri.len]='\0'; + dp->uri.len = uri.len; - if (attrs.len) { + if (puri.user.len == 0 && puri.passwd.len == 0 && puri.params.len == 0 + && puri.headers.len == 0) { + + /* The uri from db is good for ds_select_dst */ + dp->uri.s = shm_malloc(uri.len + 1 + attrs.len + 1); + if(dp->uri.s==NULL){ + LM_ERR("no more shm memory!\n"); + goto err; + } + dp->dst_uri = dp->uri; dp->attrs.s = dp->uri.s + dp->uri.len + 1; + } + else { + dp->dst_uri.len = uri_typestrlen(puri.type) + 1 + puri.host.len + + (puri.port.len ? puri.port.len + 1 : 0); + dp->uri.s = shm_malloc(uri.len + 1 + dp->dst_uri.len + 1 + attrs.len + 1); + if(dp->uri.s==NULL){ + LM_ERR("no more shm memory!\n"); + goto err; + } + + dp->attrs.s = dp->uri.s + dp->uri.len + 1 + dp->dst_uri.len + 1; + dp->dst_uri.s = dp->uri.s + dp->uri.len + 1; + char *p = uri_type2str(puri.type, dp->dst_uri.s); + *(p++) = ':'; + + memcpy(p, puri.host.s, puri.host.len); + p += puri.host.len; + + if (puri.port.len) { + *(p++) = ':'; + memcpy(p, puri.port.s, puri.port.len); + } + dp->dst_uri.s[dp->dst_uri.len]='\0'; + } + + memcpy(dp->uri.s, uri.s, dp->uri.len); + + if (attrs.len) { memcpy(dp->attrs.s, attrs.s, attrs.len); dp->attrs.s[attrs.len]='\0'; dp->attrs.len = attrs.len; } + else dp->attrs.s = NULL; - /* copy flags, weight & socket */ - dp->flags = flags; - dp->weight = weight; + /* copy state, weight & socket */ dp->sock = sock; + dp->weight = weight; + switch (state) { + case 0: + dp->flags = 0; + break; + case 1: + dp->flags = DS_INACTIVE_DST; + break; + case 2: + dp->flags = DS_PROBING_DST; + break; + default: + LM_CRIT("BUG: unknown state %d for destination %.*s\n", + state, uri.len, uri.s); + } /* Do a DNS-Lookup for the Host-Name: */ proxy = mk_proxy( &puri.host, puri.port_no, puri.proto, @@ -199,6 +269,7 @@ int add_dest2list(int id, str uri, struct socket_info *sock, int flags, hostent2ip_addr( &dp->ips[0], &proxy->host, proxy->addr_idx); dp->ports[0] = proxy->port; dp->ips_cnt = 1; + dp->priority = prio; LM_DBG("first gw ip addr [%s]:%d\n", ip_addr2a(&dp->ips[0]), dp->ports[0]); /* get the next available IPs from DNS */ @@ -214,10 +285,32 @@ int add_dest2list(int id, str uri, struct socket_info *sock, int flags, free_proxy(proxy); pkg_free(proxy); - dp->next = sp->dlist; - sp->dlist = dp; + /* + * search the proper place based on priority + * put them in reverse order, since they will be reindexed + */ + for (dp_prev = NULL, dp_it = sp->dlist; + dp_it && dp_it->priority < prio; + dp_prev = dp_it, dp_it = dp_it->next); + + if (!dp_prev) { + dp->next = sp->dlist; + sp->dlist = dp; + } else { + dp->next = dp_prev->next; + dp_prev->next = dp; + } + sp->nr++; + + + if (new_set) { + sp->next = d_data->sets; + d_data->sets = sp; + d_data->sets_no++; + } - LM_DBG("dest [%d/%d] <%.*s> successfully loaded\n", sp->id, sp->nr, dp->uri.len, dp->uri.s); + LM_DBG("dest [%d/%d] <%.*s> <%.*s> successfully loaded\n", sp->id, sp->nr, + dp->uri.len, dp->uri.s, dp->dst_uri.len, dp->dst_uri.s); return 0; err: @@ -228,18 +321,22 @@ int add_dest2list(int id, str uri, struct socket_info *sock, int flags, shm_free(dp->uri.s); shm_free(dp); } + + if (sp != NULL && new_set) + shm_free(sp); + return -1; } /* compact destinations from sets for fast access */ -int reindex_dests(int list_idx, int setn) +int reindex_dests( ds_data_t *d_data) { int j; int weight; ds_set_p sp = NULL; ds_dest_p dp = NULL, dp0= NULL; - for( sp=ds_lists[list_idx] ; sp!= NULL ; sp->dlist=dp0, sp=sp->next ) + for( sp=d_data->sets ; sp!= NULL ; sp->dlist=dp0, sp=sp->next ) { dp0 = (ds_dest_p)shm_malloc(sp->nr*sizeof(ds_dest_t)); if(dp0==NULL) @@ -260,16 +357,13 @@ int reindex_dests(int list_idx, int setn) dp = sp->dlist; sp->dlist = dp->next; - + shm_free(dp); dp=NULL; } /* updated the weights (pre-calculate the weight limits)*/ for( j=0,weight=0 ; jnr ; j++ ) { - if (ds_use_default && dp0[j].next==NULL) - /* skip the last default record */ - break; dp0[j].weight += weight; weight = dp0[j].weight; } @@ -277,7 +371,7 @@ int reindex_dests(int list_idx, int setn) } - LM_DBG("found [%d] dest sets\n", setn); + LM_DBG("found [%d] dest sets\n", d_data->sets_no); return 0; err1: @@ -315,6 +409,7 @@ void ds_pvar_parse_pattern(str pattern) ds_pattern_prefix.len = pattern.s + pattern.len - ds_pattern_prefix.s; } + ds_pvar_param_p ds_get_pvar_param(str uri) { str name; @@ -344,11 +439,12 @@ ds_pvar_param_p ds_get_pvar_param(str uri) shm_free(param); return NULL; } - + return param; } -int ds_pvar_algo(struct sip_msg *msg, ds_set_p set, ds_dest_p **sorted_set) + +int ds_pvar_algo(struct sip_msg *msg, ds_set_p set, ds_dest_p **sorted_set, int ds_use_default) { pv_value_t val; int i, j, k, end_idx, cnt; @@ -423,61 +519,58 @@ int ds_pvar_algo(struct sip_msg *msg, ds_set_p set, ds_dest_p **sorted_set) } -int ds_connect_db(void) +int ds_connect_db(ds_partition_t *partition) { - if(!ds_db_url.s) + if(!partition->db_url.s) return -1; - if (ds_db_handle) + if (*partition->db_handle) { LM_CRIT("BUG - db connection found already open\n"); return -1; } - if ((ds_db_handle = ds_dbf.init(&ds_db_url)) == 0){ - + if ((*partition->db_handle = partition->dbf.init(&partition->db_url)) == 0) return -1; - } + return 0; } -void ds_disconnect_db(void) + +void ds_disconnect_db(ds_partition_t *partition) { - if(ds_db_handle) + if(*partition->db_handle) { - ds_dbf.close(ds_db_handle); - ds_db_handle = 0; + partition->dbf.close(*partition->db_handle); + *partition->db_handle = 0; } } + /*initialize and verify DB stuff*/ -int init_ds_db(void) +int init_ds_db(ds_partition_t *partition) { int _ds_table_version; - int ret; - if(ds_table_name.s == 0) - { + if(partition->table_name.s == 0){ LM_ERR("invalid database name\n"); return -1; } - + /* Find a database module */ - if (db_bind_mod(&ds_db_url, &ds_dbf) < 0) - { + if (db_bind_mod(&partition->db_url, &partition->dbf) < 0) { LM_ERR("Unable to bind to a database driver\n"); return -1; } - - if(ds_connect_db()!=0){ - + + if(ds_connect_db(partition)!=0){ LM_ERR("unable to connect to the database\n"); return -1; } - - _ds_table_version = db_table_version(&ds_dbf, ds_db_handle, &ds_table_name); - if (_ds_table_version < 0) - { + + _ds_table_version = db_table_version(&partition->dbf, *partition->db_handle, + &partition->table_name); + if (_ds_table_version < 0) { LM_ERR("failed to query table version\n"); return -1; } else if (_ds_table_version != DS_TABLE_VERSION) { @@ -487,19 +580,119 @@ int init_ds_db(void) return -1; } - ret = ds_load_db(); + return 0; +} + + +static void ds_inherit_state( ds_data_t *old_data , ds_data_t *new_data) +{ + ds_set_p new_set, old_set; + ds_dest_p new_ds, old_ds; + + /* search the new sets through the old sets */ + for ( new_set=new_data->sets ; new_set ; new_set=new_set->next ) { + for ( old_set=old_data->sets ; old_set ; old_set=old_set->next ) { + if (new_set->id==old_set->id) + break; + } + if (old_set==NULL) { + LM_DBG("new set id %d not found in old sets\n",new_set->id); + continue; + } + LM_DBG("set id %d found in old sets\n",new_set->id); + + /* sets are matching, try to match the destinations, one by one */ + for ( new_ds=new_set->dlist ; new_ds ; new_ds=new_ds->next ) { + for ( old_ds=old_set->dlist ; old_ds ; old_ds=old_ds->next ) { + if (new_ds->uri.len==old_ds->uri.len && + strncasecmp(new_ds->uri.s, old_ds->uri.s, old_ds->uri.len)==0 ) { + LM_DBG("DST <%.*s> found in old set, copying state\n", + new_ds->uri.len,new_ds->uri.s); + new_ds->flags = old_ds->flags; + break; + } + } + if (old_ds==NULL) + LM_DBG("DST <%.*s> not found in old set\n", + new_ds->uri.len,new_ds->uri.s); + } + } +} + - ds_disconnect_db(); +void ds_flusher_routine(unsigned int ticks, void* param) +{ + db_key_t key_cmp; + db_val_t val_cmp; + db_key_t key_set; + db_val_t val_set; + ds_set_p list; + int j; + + ds_partition_t *partition; + for (partition = partitions; partition; partition = partition->next){ + if (*partition->db_handle==NULL) + continue; + + val_cmp.type = DB_STR; + val_cmp.nul = 0; - return ret; + val_set.type = DB_INT; + val_set.nul = 0; + + /* update the gateways */ + if (partition->dbf.use_table(*partition->db_handle, + &partition->table_name) < 0) { + LM_ERR("cannot select table \"%.*s\"\n", + partition->table_name.len, partition->table_name.s); + continue; + } + key_cmp = &ds_dest_uri_col; + key_set = &ds_dest_state_col; + + if (*partition->data) { + /* Iterate over the groups and the entries of each group */ + for(list = (*partition->data)->sets; list!= NULL; list= list->next) { + for(j=0; jnr; j++) { + /* If the Flag of the entry is STATE_DIRTY -> flush do db */ + if ( (list->dlist[j].flags&DS_STATE_DIRTY_DST)==0 ) + /* nothing to do for this destination */ + continue; + + /* populate the update */ + val_cmp.val.str_val = list->dlist[j].uri; + val_set.val.int_val = + (list->dlist[j].flags&DS_INACTIVE_DST) ? 1 : + ((list->dlist[j].flags&DS_PROBING_DST)?2:0); + + /* update the state of this gateway */ + LM_DBG("updating the state of destination <%.*s> to %d\n", + list->dlist[j].uri.len, list->dlist[j].uri.s, + val_set.val.int_val); + + if ( partition->dbf.update(*partition->db_handle,&key_cmp,0, + &val_cmp,&key_set,&val_set,1,1)<0 ) { + LM_ERR("DB update failed\n"); + } else { + list->dlist[j].flags &= ~DS_STATE_DIRTY_DST; + } + } + } + } + } + + return; } + /*load groups of destinations from DB*/ -int ds_load_db(void) +static ds_data_t* ds_load_data(ds_partition_t *partition) { - int i, id, nr_rows, setn, cnt; - int flags; + ds_data_t *d_data; + int i, id, nr_rows, cnt; + int state; int weight; + int prio; struct socket_info *sock; str uri; str attrs; @@ -509,50 +702,44 @@ int ds_load_db(void) db_val_t * values; db_row_t * rows; - db_key_t query_cols[6] = {&ds_set_id_col, &ds_dest_uri_col, - &ds_dest_sock_col, &ds_dest_flags_col, - &ds_dest_weight_col, &ds_dest_attrs_col}; + db_key_t query_cols[7] = {&ds_set_id_col, &ds_dest_uri_col, + &ds_dest_sock_col, &ds_dest_state_col, + &ds_dest_weight_col, &ds_dest_attrs_col, &ds_dest_prio_col}; - if( (*crt_idx) != (*next_idx)) - { - LM_WARN("load command already generated, aborting reload...\n"); - return 0; - } - - if(ds_db_handle == NULL){ + if(*partition->db_handle == NULL){ LM_ERR("invalid DB handler\n"); - return -1; + return NULL; } - if (ds_dbf.use_table(ds_db_handle, &ds_table_name) < 0) - { + if (partition->dbf.use_table(*partition->db_handle, &partition->table_name) < 0) { LM_ERR("error in use_table\n"); - return -1; + return NULL; + } + + d_data = (ds_data_t*)shm_malloc( sizeof(ds_data_t) ); + if (d_data==NULL) { + LM_ERR("failed to allocate new data structure in shm\n"); + return NULL; } + memset( d_data, 0, sizeof(ds_data_t)); /*select the whole table and all the columns*/ - if(ds_dbf.query(ds_db_handle,0,0,0,query_cols,0,6,0,&res) < 0) - { + if(partition->dbf.query(*partition->db_handle,0,0,0,query_cols,0,7,0,&res) < 0) { LM_ERR("error while querying database\n"); - return -1; + goto error; } - *next_idx = (*crt_idx + 1)%2; - destroy_list(*next_idx); - nr_rows = RES_ROW_N(res); rows = RES_ROWS(res); - if(nr_rows == 0) - { + if(nr_rows == 0) { LM_WARN("no dispatching data in the db -- empty destination set\n"); goto load_done; } - setn = 0; cnt = 0; - for(i=0; i in group %d\n",uri.len,uri.s,id); continue; } else { @@ -615,75 +808,62 @@ int ds_load_db(void) } if (cnt==0) { - LM_WARN("No record loaded from db, running on empty set\n"); + LM_WARN("No record loaded from db, running on empty sets\n"); } else { - if(reindex_dests(*next_idx, setn)!=0) - { + if(reindex_dests( d_data )!=0) { LM_ERR("error on reindex\n"); - goto err2; + goto error2; } } load_done: - /*update data*/ - _ds_list_nr = setn; - *crt_idx = *next_idx; - ds_dbf.free_result(ds_db_handle, res); - - return 0; - -err2: - destroy_list(*next_idx); - ds_dbf.free_result(ds_db_handle, res); - *next_idx = *crt_idx; + partition->dbf.free_result(*partition->db_handle, res); + return d_data; - return -1; +error: + ds_destroy_data_set( d_data ); + return NULL; +error2: + ds_destroy_data_set( d_data ); + partition->dbf.free_result(*partition->db_handle, res); + return NULL; } -/*called from dispatcher.c: free all*/ -int ds_destroy_list(void) + +int ds_reload_db(ds_partition_t *partition) { - if (ds_lists) { - destroy_list(0); - destroy_list(1); - shm_free(ds_lists); + ds_data_t *old_data; + ds_data_t *new_data; + + new_data = ds_load_data(partition); + if (new_data==NULL) { + LM_ERR("failed to load the new data, dropping the reload\n"); + return -1; } - if (crt_idx) - shm_free(crt_idx); + lock_start_write( partition->lock ); - return 0; -} + /* no more activ readers -> do the swapping */ + old_data = *partition->data; + *partition->data = new_data; -void destroy_list(int list_id) -{ - ds_set_p sp; - ds_set_p sp_curr; - ds_dest_p dest; + lock_stop_write( partition->lock ); - sp = ds_lists[list_id]; + /* destroy old data */ + if (old_data) { + /* copy the state of the destinations from the old set + * (for the matching ids) */ + ds_inherit_state( old_data, new_data); + ds_destroy_data_set( old_data ); + } - while(sp) { - sp_curr = sp; - sp = sp->next; + /* update the Black Lists with the new gateways */ + populate_ds_bls( new_data->sets, partition->name); - dest = sp_curr->dlist; - if (dest) { - do { - if(dest->uri.s!=NULL) - shm_free(dest->uri.s); - if(dest->param) - shm_free(dest->param); - dest = dest->next; - }while(dest); - shm_free(sp_curr->dlist); - } - shm_free(sp_curr); - } - - ds_lists[list_id] = NULL; + return 0; } + /** * */ @@ -709,8 +889,8 @@ unsigned int ds_get_hash(str *x, str *y) } v=0; for (;p<(x->s+x->len); p++) - { - v<<=8; + { + v<<=8; v+=*p; } h+=v^(v>>3); @@ -718,7 +898,7 @@ unsigned int ds_get_hash(str *x, str *y) if(y) { p=y->s; - if (y->len>=4) + if (y->len>=4) { for (; p<=(y->s+y->len-4); p+=4) { @@ -726,11 +906,11 @@ unsigned int ds_get_hash(str *x, str *y) h+=v^(v>>3); } } - + v=0; for (;p<(y->s+y->len); p++) - { - v<<=8; + { + v<<=8; v+=*p; } h+=v^(v>>3); @@ -759,7 +939,7 @@ static inline int get_uri_hash_keys(str* key1, str* key2, str* uri, struct sip_uri* parsed_uri, int flags) { struct sip_uri tmp_p_uri; /* used only if parsed_uri==0 */ - + if (parsed_uri==0) { if (parse_uri(uri->s, uri->len, &tmp_p_uri)<0) @@ -776,7 +956,7 @@ static inline int get_uri_hash_keys(str* key1, str* key2, uri->len, uri->len?uri->s:""); goto error; } - + /* we want: user@host:port if port !=5060 * user@host if port==5060 * user if the user flag is set*/ @@ -809,36 +989,36 @@ static inline int get_uri_hash_keys(str* key1, str* key2, /** * */ -int ds_hash_fromuri(struct sip_msg *msg, unsigned int *hash) +int ds_hash_fromuri(struct sip_msg *msg, unsigned int *hash, int ds_flags) { str from; str key1; str key2; - + if(msg==NULL || hash == NULL) { LM_ERR("bad parameters\n"); return -1; } - + if(parse_from_header(msg)<0) { LM_ERR("cannot parse From hdr\n"); return -1; } - + if(msg->from==NULL || get_from(msg)==NULL) { LM_ERR("cannot get From uri\n"); return -1; } - + from = get_from(msg)->uri; trim(&from); if (get_uri_hash_keys(&key1, &key2, &from, 0, ds_flags)<0) return -1; *hash = ds_get_hash(&key1, &key2); - + return 0; } @@ -847,12 +1027,12 @@ int ds_hash_fromuri(struct sip_msg *msg, unsigned int *hash) /** * */ -int ds_hash_touri(struct sip_msg *msg, unsigned int *hash) +int ds_hash_touri(struct sip_msg *msg, unsigned int *hash, int ds_flags) { str to; str key1; str key2; - + if(msg==NULL || hash == NULL) { LM_ERR("bad parameters\n"); @@ -864,15 +1044,15 @@ int ds_hash_touri(struct sip_msg *msg, unsigned int *hash) LM_ERR("cannot parse To hdr\n"); return -1; } - - + + to = get_to(msg)->uri; trim(&to); - + if (get_uri_hash_keys(&key1, &key2, &to, 0, ds_flags)<0) return -1; *hash = ds_get_hash(&key1, &key2); - + return 0; } @@ -889,32 +1069,32 @@ int ds_hash_callid(struct sip_msg *msg, unsigned int *hash) LM_ERR("bad parameters\n"); return -1; } - + if(msg->callid==NULL && ((parse_headers(msg, HDR_CALLID_F, 0)==-1) || (msg->callid==NULL)) ) { LM_ERR("cannot parse Call-Id\n"); return -1; } - + cid.s = msg->callid->body.s; cid.len = msg->callid->body.len; trim(&cid); - + *hash = ds_get_hash(&cid, NULL); - + return 0; } -int ds_hash_ruri(struct sip_msg *msg, unsigned int *hash) +int ds_hash_ruri(struct sip_msg *msg, unsigned int *hash, int ds_flags) { str* uri; str key1; str key2; - - + + if(msg==NULL || hash == NULL) { LM_ERR("bad parameters\n"); @@ -924,15 +1104,16 @@ int ds_hash_ruri(struct sip_msg *msg, unsigned int *hash) LM_ERR("bad request uri\n"); return -1; } - + uri=GET_RURI(msg); if (get_uri_hash_keys(&key1, &key2, uri, &msg->parsed_uri, ds_flags)<0) return -1; - + *hash = ds_get_hash(&key1, &key2); return 0; } + int ds_hash_authusername(struct sip_msg *msg, unsigned int *hash) { /* Header, which contains the authorization */ @@ -941,7 +1122,7 @@ int ds_hash_authusername(struct sip_msg *msg, unsigned int *hash) str username = {0, 0}; /* The Credentials from this request */ auth_body_t* cred; - + if(msg==NULL || hash == NULL) { LM_ERR("bad parameters\n"); @@ -982,14 +1163,14 @@ int ds_hash_authusername(struct sip_msg *msg, unsigned int *hash) LM_ERR("No Authorization-Username or Credentials!\n"); return 1; } - + username.s = cred->digest.username.user.s; username.len = cred->digest.username.user.len; trim(&username); - + *hash = ds_get_hash(&username, NULL); - + return 0; } @@ -998,7 +1179,7 @@ int ds_hash_pvar(struct sip_msg *msg, unsigned int *hash) { /* The String to create the hash */ str hash_str = {0, 0}; - + if(msg==NULL || hash == NULL || hash_param_model == NULL) { LM_ERR("bad parameters\n"); @@ -1018,54 +1199,59 @@ int ds_hash_pvar(struct sip_msg *msg, unsigned int *hash) LM_DBG("Hashing %.*s!\n", hash_str.len, hash_str.s); *hash = ds_get_hash(&hash_str, NULL); - + return 0; } -static inline int ds_get_index(int group, ds_set_p *index) + +static inline int ds_get_index(int group, ds_set_p *index, ds_partition_t *partition) { ds_set_p si = NULL; - - if(index==NULL || group<0 || _ds_list==NULL) + + if(index==NULL || group<0 || (*partition->data)->sets==NULL) return -1; - + /* get the index of the set */ - si = _ds_list; - while(si) - { - if(si->id == group) - { + for ( si=(*partition->data)->sets ; si ; si = si->next ) { + if(si->id == group) { *index = si; break; } - si = si->next; } - if(si==NULL) - { - LM_ERR("destination set [%d] not found\n", group); + if(si==NULL) { + LM_ERR("destination set [%d] not found in partition [%.*s]\n", group, + partition->name.len, partition->name.s); return -1; } return 0; } + static inline int ds_update_dst(struct sip_msg *msg, str *uri, struct socket_info *sock, int mode) { struct action act; + uri_type utype; + int typelen; + switch(mode) { case 1: act.type = SET_HOSTPORT_T; act.elem[0].type = STR_ST; - act.elem[0].u.s = *uri; - if (uri->len>4 && strncasecmp(uri->s,"sip:",4)==0) { - act.elem[0].u.s.s += 4; - act.elem[0].u.s.len -= 4; + + utype = str2uri_type(uri->s); + if (utype == ERROR_URI_T) { + LM_ERR("Uknown uri type\n"); + return -1; } + typelen = uri_typestrlen(utype); + act.elem[0].u.s.s = uri->s + typelen + 1; + act.elem[0].u.s.len = uri->len - typelen - 1; act.next = 0; - + if (do_action(&act, msg) < 0) { LM_ERR("error while setting host\n"); return -1; @@ -1083,44 +1269,47 @@ static inline int ds_update_dst(struct sip_msg *msg, str *uri, return 0; } -static int is_default_destination_entry(ds_set_p idx, int i) { +static int is_default_destination_entry(ds_set_p idx, int i, int ds_use_default) { return ds_use_default!=0 && i==(idx->nr-1); } -static int count_inactive_destinations(ds_set_p idx) { +static int count_inactive_destinations(ds_set_p idx, int ds_use_default) { int count = 0, i; for(i=0; inr; i++) if(idx->dlist[i].flags & DS_INACTIVE_DST) /* only count inactive entries that are not default */ - if(!is_default_destination_entry(idx, i)) + if(!is_default_destination_entry(idx, i, ds_use_default)) count++; return count; } -static inline int push_ds_2_avps( ds_dest_t *ds ) +static inline int push_ds_2_avps( ds_dest_t *ds, ds_partition_t *partition ) { char buf[2+16+1]; /* a hexa string */ int_str avp_val; avp_val.s.len = 1 + sprintf( buf, "%p", ds->sock ); avp_val.s.s = buf; - if(add_avp(AVP_VAL_STR|sock_avp_type, sock_avp_name, avp_val)!=0) { + if(add_avp(AVP_VAL_STR| partition->sock_avp_type, + partition->sock_avp_name, avp_val)!=0) { LM_ERR("failed to add SOCK avp\n"); return -1; } - avp_val.s = ds->uri; - if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0) { + avp_val.s = ds->dst_uri; + if(add_avp(AVP_VAL_STR| partition->dst_avp_type, + partition->dst_avp_name, avp_val)!=0) { LM_ERR("failed to add DST avp\n"); return -1; } - if (attrs_avp_name >= 0) { + if (partition->attrs_avp_name >= 0) { avp_val.s = ds->attrs; - if(add_avp(AVP_VAL_STR|attrs_avp_type,attrs_avp_name,avp_val)!=0) { + if(add_avp(AVP_VAL_STR| partition->attrs_avp_type, + partition->attrs_avp_name, avp_val)!=0) { LM_ERR("failed to add ATTR avp\n"); return -1; } @@ -1132,7 +1321,7 @@ static inline int push_ds_2_avps( ds_dest_t *ds ) /** * */ -int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_results) +int ds_select_dst(struct sip_msg *msg, ds_select_ctl_p ds_select_ctl, int ds_flags) { int i, cnt, i_unwrapped; unsigned int ds_hash; @@ -1145,67 +1334,67 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_resul ds_dest_p dest = NULL; ds_dest_p selected = NULL; static ds_dest_p *sorted_set = NULL; - - if(msg==NULL) - { + if(msg==NULL) { LM_ERR("bad parameters\n"); return -1; } - - if(_ds_list==NULL || _ds_list_nr<=0) - { + + if ( (*ds_select_ctl->partition->data)->sets==NULL) { LM_DBG("empty destination set\n"); return -1; } - if((mode==0) && (ds_force_dst==0) + if((ds_select_ctl->mode==0) && (ds_flags&DS_FORCE_DST) && (msg->dst_uri.s!=NULL || msg->dst_uri.len>0)) { LM_ERR("destination already set [%.*s]\n", msg->dst_uri.len, msg->dst_uri.s); return -1; } - + + + /* access ds data under reader's lock */ + lock_start_read( ds_select_ctl->partition->lock ); /* get the index of the set */ - if(ds_get_index(set, &idx)!=0) + if(ds_get_index(ds_select_ctl->set, &idx, ds_select_ctl->partition)!=0) { - LM_ERR("destination set [%d] not found\n", set); - return -1; + LM_ERR("destination set [%d] not found\n", ds_select_ctl->set); + goto error; } - - LM_DBG("set [%d]\n", set); + + LM_DBG("set [%d]\n", ds_select_ctl->set); ds_hash = 0; ds_id = -1; - switch(alg) + switch(ds_select_ctl->alg) { case 0: if(ds_hash_callid(msg, &ds_hash)!=0) { LM_ERR("can't get callid hash\n"); - return -1; + goto error; } break; case 1: - if(ds_hash_fromuri(msg, &ds_hash)!=0) + if(ds_hash_fromuri(msg, &ds_hash, ds_flags)!=0) { LM_ERR("can't get From uri hash\n"); - return -1; + goto error; } break; case 2: - if(ds_hash_touri(msg, &ds_hash)!=0) + if(ds_hash_touri(msg, &ds_hash, ds_flags)!=0) { LM_ERR("can't get To uri hash\n"); - return -1; + goto error; } break; case 3: - if (ds_hash_ruri(msg, &ds_hash)!=0) + if (ds_hash_ruri(msg, &ds_hash, ds_flags)!=0) { LM_ERR("can't get ruri hash\n"); - return -1; + goto error; } break; case 4: @@ -1226,7 +1415,7 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_resul break; default: LM_ERR("can't get authorization hash\n"); - return -1; + goto error; break; } break; @@ -1237,7 +1426,7 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_resul if (ds_hash_pvar(msg, &ds_hash)!=0) { LM_ERR("can't get PV hash\n"); - return -1; + goto error; } break; case 8: @@ -1246,18 +1435,20 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_resul case 9: if (!ds_has_pattern && ds_pattern_suffix.len == 0 ) { LM_WARN("no pattern specified - using first entry...\n"); - alg = 8; + ds_select_ctl->alg = 8; break; } - if ((ds_id = ds_pvar_algo(msg, idx, &sorted_set)) <= 0) + if ((ds_id = ds_pvar_algo(msg, idx, &sorted_set, ds_flags&DS_USE_DEFAULT)) <= 0) { LM_ERR("can't get destination index\n"); - return -1; + goto error; } ds_id = 0; break; default: - LM_WARN("algo %d not implemented - using first entry...\n", alg); + LM_WARN("dispatching via [%d] with unknown algo [%d]" + ": defaulting to 0 - first entry\n", + ds_select_ctl->set, ds_select_ctl->alg); ds_id = 0; } @@ -1273,15 +1464,14 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_resul break; } } - LM_DBG("alg hash [%u], id [%u]\n", ds_hash, ds_id); cnt = 0; - if (alg != 9) { + if (ds_select_ctl->alg != 9) { i=ds_id; while ( idx->dlist[i].flags&(DS_INACTIVE_DST|DS_PROBING_DST) ) { - if(ds_use_default!=0) { + if(ds_flags&DS_USE_DEFAULT) { if (idx->nr>1) i = (i+1)%(idx->nr-1); } else { @@ -1289,14 +1479,14 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_resul } if(i==ds_id) { - if(ds_use_default!=0) + if(ds_flags&DS_USE_DEFAULT) { i = idx->nr-1; if (idx->dlist[i].flags&(DS_INACTIVE_DST|DS_PROBING_DST)) - return -1; + goto error; break; } else { - return -1; + goto error; } } } @@ -1306,90 +1496,106 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_resul selected = sorted_set[0]; } - if(ds_update_dst(msg, &selected->uri, selected->sock, mode)!=0) + if(ds_select_ctl->set_destination + && ds_update_dst(msg, &selected->dst_uri, selected->sock, ds_select_ctl->mode)!=0) { LM_ERR("cannot set dst addr\n"); - return -1; + goto error; } /* if alg is round-robin then update the shortcut to next to be used */ - if(alg==4) + if(ds_select_ctl->alg==4) idx->last = (ds_id+1) % idx->nr; - - LM_DBG("selected [%d-%d/%d] <%.*s>\n", alg, set, ds_id, - selected->uri.len, selected->uri.s); + + LM_DBG("selected [%d-%d/%d] <%.*s>\n", ds_select_ctl->alg, ds_select_ctl->set, ds_id, + selected->dst_uri.len, selected->dst_uri.s); if(!(ds_flags&DS_FAILOVER_ON)) goto done; + if(ds_select_ctl->reset_AVP) + { + /* do some AVP cleanup before start populating new ones */ + destroy_avps( 0 /*all types*/, ds_select_ctl->partition->dst_avp_name, 1); + destroy_avps( 0 /*all types*/, ds_select_ctl->partition->grp_avp_name, 1); + destroy_avps( 0 /*all types*/, ds_select_ctl->partition->cnt_avp_name, 1); + destroy_avps( 0 /*all types*/,ds_select_ctl->partition->sock_avp_name, 1); + if (ds_select_ctl->partition->attrs_avp_name>0) + destroy_avps( 0 /*all types*/, + ds_select_ctl->partition->attrs_avp_name, 1 /*all*/); + ds_select_ctl->reset_AVP = 0; + } - /* do some AVP cleanup before start populating new ones */ - destroy_avps( 0 /*all types*/, dst_avp_name, 1 /*all*/); - destroy_avps( 0 /*all types*/, grp_avp_name, 1 /*all*/); - destroy_avps( 0 /*all types*/, cnt_avp_name, 1 /*all*/); - destroy_avps( 0 /*all types*/,sock_avp_name, 1 /*all*/); - if (attrs_avp_name>0) - destroy_avps( 0 /*all types*/,attrs_avp_name, 1 /*all*/); - - - if(ds_use_default!=0 && ds_id!=idx->nr-1) + if((ds_flags&DS_USE_DEFAULT) && ds_id!=idx->nr-1) { - if (push_ds_2_avps( &idx->dlist[idx->nr-1] ) != 0 ) - return -1; + if (push_ds_2_avps( &idx->dlist[idx->nr-1], ds_select_ctl->partition ) != 0 ) + goto error; cnt++; } - inactive_dst_count = count_inactive_destinations(idx); + inactive_dst_count = count_inactive_destinations(idx, ds_flags&DS_USE_DEFAULT); /* don't count inactive and default entries into total */ - destination_entries_to_skip = idx->nr - inactive_dst_count - (ds_use_default!=0); - destination_entries_to_skip -= max_results; + destination_entries_to_skip = idx->nr - inactive_dst_count - (ds_flags&DS_USE_DEFAULT?1:0); + destination_entries_to_skip -= ds_select_ctl->max_results; /* add to avp */ for(i_unwrapped = ds_id-1+idx->nr; i_unwrapped>ds_id; i_unwrapped--) { i = i_unwrapped % idx->nr; - dest = (alg == 9 ? sorted_set[i] : &idx->dlist[i]); + dest = (ds_select_ctl->alg == 9 ? sorted_set[i] : &idx->dlist[i]); if((dest->flags & DS_INACTIVE_DST) - || (ds_use_default!=0 && i==(idx->nr-1))) + || ((ds_flags&DS_USE_DEFAULT) && i==(idx->nr-1))) continue; if(destination_entries_to_skip > 0) { - LM_DBG("skipped entry [%d/%d] (would create more than %i results)\n", set, i, max_results); + LM_DBG("skipped entry [%d/%d] (would create more than %i results)\n", + ds_select_ctl->set, i, ds_select_ctl->max_results); destination_entries_to_skip--; continue; } - LM_DBG("using entry [%d/%d]\n", set, i); - if (push_ds_2_avps( dest ) != 0 ) - return -1; + LM_DBG("using entry [%d/%d]\n", ds_select_ctl->set, i); + if (push_ds_2_avps( dest, ds_select_ctl->partition ) != 0 ) + goto error; cnt++; } /* add to avp the first used dst */ avp_val.s = selected->uri; - if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0) - return -1; + if(add_avp(AVP_VAL_STR|ds_select_ctl->partition->dst_avp_type, + ds_select_ctl->partition->dst_avp_name, + avp_val)!=0) + goto error; cnt++; done: - if (attrs_avp_name>0) { + if (ds_select_ctl->partition->attrs_avp_name>0) { avp_val.s = selected->attrs; - if(add_avp(AVP_VAL_STR|attrs_avp_type,attrs_avp_name,avp_val)!=0) - return -1; + if(add_avp(AVP_VAL_STR | ds_select_ctl->partition->attrs_avp_type, + ds_select_ctl->partition->attrs_avp_name,avp_val)!=0) + goto error; } /* add to avp the group id */ - avp_val.n = set; - if(add_avp(grp_avp_type, grp_avp_name, avp_val)!=0) - return -1; + avp_val.n = ds_select_ctl->set; + if(add_avp(ds_select_ctl->partition->grp_avp_type, + ds_select_ctl->partition->grp_avp_name, avp_val)!=0) + goto error; /* add to avp the number of dst */ avp_val.n = cnt; - if(add_avp(cnt_avp_type, cnt_avp_name, avp_val)!=0) - return -1; + if(add_avp(ds_select_ctl->partition->cnt_avp_type, + ds_select_ctl->partition->cnt_avp_name, avp_val)!=0) + goto error; + lock_stop_read( ds_select_ctl->partition->lock ); return 1; + +error: + lock_stop_read( ds_select_ctl->partition->lock ); + return -1; } -int ds_next_dst(struct sip_msg *msg, int mode) + +int ds_next_dst(struct sip_msg *msg, int mode, ds_partition_t *partition) { struct socket_info *sock; struct usr_avp *avp; @@ -1398,13 +1604,8 @@ int ds_next_dst(struct sip_msg *msg, int mode) int_str avp_value; int_str sock_avp_value; - if(!(ds_flags&DS_FAILOVER_ON) || dst_avp_name < 0) - { - LM_WARN("failover support disabled\n"); - return -1; - } - - tmp_avp = search_first_avp(dst_avp_type, dst_avp_name, NULL, 0); + tmp_avp = search_first_avp(partition->dst_avp_type, partition->dst_avp_name, + NULL, 0); if(tmp_avp==NULL) return -1; /* used avp deleted -- strange */ @@ -1413,8 +1614,9 @@ int ds_next_dst(struct sip_msg *msg, int mode) destroy_avp(tmp_avp); /* remove old attribute AVP (from prev destination) */ - if (attrs_avp_name >= 0) { - attr_avp = search_first_avp(attrs_avp_type, attrs_avp_name, NULL, 0); + if (partition->attrs_avp_name >= 0) { + attr_avp = search_first_avp(partition->attrs_avp_type, + partition->attrs_avp_name, NULL, 0); if (attr_avp) destroy_avp(attr_avp); } @@ -1423,14 +1625,15 @@ int ds_next_dst(struct sip_msg *msg, int mode) return -1; /* no more avps or value is int */ /* get AVP with next destination socket */ - tmp_avp = search_first_avp(sock_avp_type, sock_avp_name, - &sock_avp_value, 0); - if (tmp_avp) { + tmp_avp = search_first_avp(partition->sock_avp_type, partition->sock_avp_name, + &sock_avp_value, 0); + if (!tmp_avp) { /* this shuold not happen, it is a bogus state */ sock = NULL; } else { if (sscanf( sock_avp_value.s.s, "%p", (void**)&sock ) != 1) sock = NULL; + destroy_avp(tmp_avp); } if(ds_update_dst(msg, &avp_value.s, sock, mode)!=0) @@ -1444,96 +1647,101 @@ int ds_next_dst(struct sip_msg *msg, int mode) } -int ds_mark_dst(struct sip_msg *msg, int mode) +int ds_mark_dst(struct sip_msg *msg, int mode, ds_partition_t *partition) { int group, ret; struct usr_avp *prev_avp; int_str avp_value; - - if(!(ds_flags&DS_FAILOVER_ON)) - { - LM_WARN("failover support disabled\n"); - return -1; - } - prev_avp = search_first_avp(grp_avp_type, grp_avp_name, &avp_value, 0); - + prev_avp = search_first_avp(partition->grp_avp_type, partition->grp_avp_name, + &avp_value, 0); + if(prev_avp==NULL || prev_avp->flags&AVP_VAL_STR) return -1; /* grp avp deleted -- strange */ group = avp_value.n; - - prev_avp = search_first_avp(dst_avp_type, dst_avp_name, &avp_value, 0); - + + prev_avp = search_first_avp(partition->dst_avp_type, partition->dst_avp_name, + &avp_value, 0); + if(prev_avp==NULL || !(prev_avp->flags&AVP_VAL_STR)) return -1; /* dst avp deleted -- strange */ - + if(mode==1) { - ret = ds_set_state(group, &avp_value.s, - DS_INACTIVE_DST|DS_PROBING_DST, 0); + ret = ds_set_state(group, &avp_value.s, + DS_INACTIVE_DST|DS_PROBING_DST, 0, partition); } else if(mode==2) { - ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1); + ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1, partition); if (ret == 0) ret = ds_set_state(group, &avp_value.s, - DS_INACTIVE_DST, 0); + DS_INACTIVE_DST, 0, partition); } else { - ret = ds_set_state(group, &avp_value.s, DS_INACTIVE_DST, 1); + ret = ds_set_state(group, &avp_value.s, DS_INACTIVE_DST, 1, partition); if (ret == 0) ret = ds_set_state(group, &avp_value.s, - DS_PROBING_DST, 0); + DS_PROBING_DST, 0, partition); } - + LM_DBG("mode [%d] grp [%d] dst [%.*s]\n", mode, group, avp_value.s.len, avp_value.s.s); - + return (ret==0)?1:-1; } /* event parameters */ +static str partition_str = str_init("partition"); static str group_str = str_init("group"); static str address_str = str_init("address"); static str status_str = str_init("status"); static str inactive_str = str_init("inactive"); static str active_str = str_init("active"); -int ds_set_state(int group, str *address, int state, int type) +int ds_set_state(int group, str *address, int state, int type, + ds_partition_t *partition) { int i=0; ds_set_p idx = NULL; evi_params_p list = NULL; + int old_flags; - if(_ds_list==NULL || _ds_list_nr<=0) - { + if ( (*partition->data)->sets==NULL ){ LM_DBG("empty destination set\n"); return -1; } - + + /* access ds data under reader's lock */ + lock_start_read( partition->lock ); + /* get the index of the set */ - if(ds_get_index(group, &idx)!=0) - { + if(ds_get_index(group, &idx, partition)!=0) { LM_ERR("destination set [%d] not found\n", group); + lock_stop_read( partition->lock ); return -1; } while(inr) { - if(idx->dlist[i].uri.len==address->len + if(idx->dlist[i].uri.len==address->len && strncasecmp(idx->dlist[i].uri.s, address->s, address->len)==0) { - + /* remove the Probing/Inactive-State? Set the fail-count to 0. */ if (state == DS_PROBING_DST) { if (type) { if (idx->dlist[i].flags & DS_INACTIVE_DST) { LM_INFO("Ignoring the request to set this destination" " to probing: It is already inactive!\n"); + lock_stop_read( partition->lock ); return 0; } - + idx->dlist[i].failure_count++; /* Fire only, if the Threshold is reached. */ - if (idx->dlist[i].failure_count - < probing_threshhold) return 0; if (idx->dlist[i].failure_count - > probing_threshhold) + < probing_threshhold) { + lock_stop_read( partition->lock ); + return 0; + } + if (idx->dlist[i].failure_count + > probing_threshhold) idx->dlist[i].failure_count = probing_threshhold; } @@ -1543,30 +1751,47 @@ int ds_set_state(int group, str *address, int state, int type) idx->dlist[i].failure_count = 0; state &= ~DS_RESET_FAIL_DST; } - + + /* set the new state of the destination */ + old_flags = idx->dlist[i].flags; if(type) idx->dlist[i].flags |= state; else idx->dlist[i].flags &= ~state; + if ( idx->dlist[i].flags != old_flags) + idx->dlist[i].flags |= DS_STATE_DIRTY_DST; + if (dispatch_evi_id == EVI_ERROR) { LM_ERR("event not registered %d\n", dispatch_evi_id); } else if (evi_probe_event(dispatch_evi_id)) { - if (!(list = evi_get_params())) + if (!(list = evi_get_params())) { + lock_stop_read( partition->lock ); + return 0; + } + if (partition != default_partition + && evi_param_add_str(list, &partition_str, &partition->name)){ + LM_ERR("unable to add partition parameter\n"); + evi_free_params(list); + lock_stop_read( partition->lock ); return 0; + } if (evi_param_add_int(list, &group_str, &group)) { LM_ERR("unable to add group parameter\n"); evi_free_params(list); + lock_stop_read( partition->lock ); return 0; } if (evi_param_add_str(list, &address_str, address)) { LM_ERR("unable to add address parameter\n"); evi_free_params(list); + lock_stop_read( partition->lock ); return 0; } if (evi_param_add_str(list, &status_str, type ? &inactive_str : &active_str)) { LM_ERR("unable to add status parameter\n"); evi_free_params(list); + lock_stop_read( partition->lock ); return 0; } @@ -1576,62 +1801,22 @@ int ds_set_state(int group, str *address, int state, int type) } else { LM_DBG("no event sent\n"); } + lock_stop_read( partition->lock ); return 0; } i++; } + lock_stop_read( partition->lock ); return -1; } -int ds_print_list(FILE *fout) -{ - int j; - ds_set_p list; - - if(_ds_list==NULL || _ds_list_nr<=0) - { - LM_DBG("empty destination sets\n"); - return -1; - } - - fprintf(fout, "\nnumber of destination sets: %d\n", _ds_list_nr); - - for(list = _ds_list; list!= NULL; list= list->next) - { - for(j=0; jnr; j++) - { - fprintf(fout, "\n set #%d\n", list->id); - - if (list->dlist[j].flags&DS_INACTIVE_DST) - fprintf(fout, " Disabled "); - else if (list->dlist[j].flags&DS_PROBING_DST) - fprintf(fout, " Probing "); - else { - fprintf(fout, " Active"); - /* Optional: Print the tries for this host. */ - if (list->dlist[j].failure_count > 0) { - fprintf(fout, " (Fail %d/%d)", - list->dlist[j].failure_count, - probing_threshhold); - } else { - fprintf(fout, " "); - } - } - - fprintf(fout, " %.*s\n", - list->dlist[j].uri.len, list->dlist[j].uri.s); - } - } - return 0; -} - /* Checks, if the request (sip_msg *_m) comes from a host in a set * (set-id or -1 for all sets) */ int ds_is_in_list(struct sip_msg *_m, pv_spec_t *pv_ip, pv_spec_t *pv_port, - int set, int active_only) + int set, int active_only, ds_partition_t *partition) { pv_value_t val; ds_set_p list; @@ -1672,7 +1857,10 @@ int ds_is_in_list(struct sip_msg *_m, pv_spec_t *pv_ip, pv_spec_t *pv_port, memset(&val, 0, sizeof(pv_value_t)); val.flags = PV_VAL_INT|PV_TYPE_INT; - for(list = _ds_list; list!= NULL; list= list->next) { + /* access ds data under reader's lock */ + lock_start_read( partition->lock ); + + for(list = (*partition->data)->sets ; list!= NULL; list= list->next) { if ((set == -1) || (set == list->id)) { /* interate through all elements/destinations in the list */ for(j=0; jnr; j++) { @@ -1691,135 +1879,174 @@ int ds_is_in_list(struct sip_msg *_m, pv_spec_t *pv_ip, pv_spec_t *pv_port, (int)EQ_T, &val)<0) { LM_ERR("setting PV failed\n"); - return -2; + goto error; } } - if (attrs_avp_name>= 0) { + if (partition->attrs_avp_name>= 0) { avp_val.s = list->dlist[j].attrs; - if(add_avp(AVP_VAL_STR|attrs_avp_type,attrs_avp_name,avp_val)!=0) - return -1; + if(add_avp(AVP_VAL_STR|partition->attrs_avp_type, + partition->attrs_avp_name,avp_val)!=0) + goto error; } + + lock_stop_read( partition->lock ); return 1; } } } } } + +error: + lock_stop_read( partition->lock ); return -1; } -int ds_print_mi_list(struct mi_node* rpl) +int ds_print_mi_list(struct mi_node* rpl, ds_partition_t *partition) { int len, j; char* p; - char c; ds_set_p list; struct mi_node* node = NULL; + struct mi_node* node1; struct mi_node* set_node = NULL; struct mi_attr* attr = NULL; - - if(_ds_list==NULL || _ds_list_nr<=0) - { + + if ( (*partition->data)->sets==NULL ) { LM_DBG("empty destination sets\n"); return 0; } - p= int2str(_ds_list_nr, &len); - node = add_mi_node_child(rpl, MI_DUP_VALUE, "SET_NO",6, p, len); - if(node== NULL) - return -1; + /* access ds data under reader's lock */ + lock_start_read( partition->lock ); - for(list = _ds_list; list!= NULL; list= list->next) - { + for(list = (*partition->data)->sets ; list!= NULL; list= list->next) { p = int2str(list->id, &len); - set_node= add_mi_node_child(rpl, MI_DUP_VALUE,"SET", 3, p, len); + set_node= add_mi_node_child(rpl, MI_IS_ARRAY|MI_DUP_VALUE, + "SET", 3, p, len); if(set_node == NULL) - return -1; + goto error; for(j=0; jnr; j++) - { - node= add_mi_node_child(set_node, 0, "URI", 3, - list->dlist[j].uri.s, list->dlist[j].uri.len); - if(node == NULL) - return -1; - - if (list->dlist[j].flags & DS_INACTIVE_DST) c = 'I'; - else if (list->dlist[j].flags & DS_PROBING_DST) c = 'P'; - else c = 'A'; - - attr = add_mi_attr (node, MI_DUP_VALUE, "flag",4, &c, 1); - if(attr == 0) - return -1; - - } + { + node= add_mi_node_child(set_node, MI_DUP_VALUE, "URI", 3, + list->dlist[j].uri.s, list->dlist[j].uri.len); + if(node == NULL) + goto error; + + if (list->dlist[j].flags & DS_INACTIVE_DST) + attr = add_mi_attr (node, 0, "state",5, "Inactive", 8); + else if (list->dlist[j].flags & DS_PROBING_DST) + attr = add_mi_attr (node, 0, "state",5, "Probing", 7); + else + attr = add_mi_attr (node, 0, "state",5, "Active", 6); + + if(attr == NULL) + goto error; + + if (list->dlist[j].sock) + { + p = socket2str(list->dlist[j].sock, NULL, &len, 0); + if (p) + { + node1= add_mi_node_child(node, MI_DUP_VALUE, + "socket", 6, p, len); + if(node1 == NULL) + goto error; + } + } + + if (list->dlist[j].attrs.s) + { + node1= add_mi_node_child(node, MI_DUP_VALUE, "attr", 4, + list->dlist[j].attrs.s, list->dlist[j].attrs.len); + if(node1 == NULL) + goto error; + } + } } + lock_stop_read( partition->lock ); return 0; +error: + lock_stop_read( partition->lock ); + return -1; } + /** * Callback-Function for the OPTIONS-Request * This Function is called, as soon as the Transaction is finished * (e. g. a Response came in, the timeout was hit, ...) - * - */ + * + */ static void ds_options_callback( struct cell *t, int type, struct tmcb_params *ps ) { - int group = 0; str uri = {0, 0}; + /* The Param does contain the group, in which the failed host * can be found.*/ - if (!ps->param) - { + if (!ps->param) { LM_DBG("No parameter provided, OPTIONS-Request was finished" " with code %d\n", ps->code); return; } + /* The param is a (void*) Pointer, so we need to dereference it and * cast it to an int. */ - group = (int)(long)(*ps->param); + + ds_options_callback_param_t *cb_param = + (ds_options_callback_param_t*)(*ps->param); + /* The SIP-URI is taken from the Transaction. * Remove the "To: " (s+4) and the trailing new-line (s - 4 (To: ) * - 2 (\r\n)). */ uri.s = t->to.s + 4; uri.len = t->to.len - 6; LM_DBG("OPTIONS-Request was finished with code %d (to %.*s, group %d)\n", - ps->code, uri.len, uri.s, group); - /* ps->code contains the result-code of the request. - * + ps->code, uri.len, uri.s, cb_param->set_id); + + /* ps->code contains the result-code of the request; * We accept "200 OK" by default and the custom codes * defined in options_reply_codes parameter*/ - if ((ps->code == 200) || check_options_rplcode(ps->code)) - { + if ((ps->code == 200) || check_options_rplcode(ps->code)) { /* Set the according entry back to "Active": * remove the Probing/Inactive Flag and reset the failure counter. */ - if (ds_set_state(group, &uri, - DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0) != 0) + if (ds_set_state(cb_param->set_id, &uri, + DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0, + cb_param->partition) != 0) { LM_ERR("Setting the state failed (%.*s, group %d)\n", uri.len, - uri.s, group); + uri.s, cb_param->set_id); } } - /* if we always probe, and we get a timeout + /* if we always probe, and we get a timeout * or a reponse that is not within the allowed * reply codes, then disable*/ - if(ds_probing_mode==1 && (ps->code == 408 || !check_options_rplcode(ps->code))) + if(ds_probing_mode==1 && ps->code != 200 && + (ps->code == 408 || !check_options_rplcode(ps->code))) { - if (ds_set_state(group, &uri, DS_PROBING_DST, 1) != 0) + if (ds_set_state(cb_param->set_id, &uri, DS_PROBING_DST, 1, + cb_param->partition) != 0) { LM_ERR("Setting the probing state failed (%.*s, group %d)\n", - uri.len, uri.s, group); + uri.len, uri.s, cb_param->set_id); } } return; } +void shm_free_cb_param(void *param) +{ + shm_free(param); +} + /* * Timer for checking inactive destinations - * + * * This timer is regularly fired. */ void ds_check_timer(unsigned int ticks, void* param) @@ -1828,66 +2055,83 @@ void ds_check_timer(unsigned int ticks, void* param) ds_set_p list; int j; - /* Check for the list. */ - if(_ds_list==NULL || _ds_list_nr<=0) - return; + ds_partition_t *partition = partitions; - /* Iterate over the groups and the entries of each group: */ - for(list = _ds_list; list!= NULL; list= list->next) - { - for(j=0; jnr; j++) + for (partition = partitions; partition; partition = partition->next){ + /* Check for the list. */ + if ( (*partition->data)->sets==NULL ) + continue; + + /* access ds data under reader's lock */ + lock_start_read( partition->lock ); + + /* Iterate over the groups and the entries of each group: */ + for( list=(*partition->data)->sets ; list!= NULL ; list= list->next) { - /* If the Flag of the entry has "Probing set, send a probe: */ - if ( ((list->dlist[j].flags&DS_INACTIVE_DST)==0) && - (ds_probing_mode==1 || (list->dlist[j].flags&DS_PROBING_DST)!=0) ) + for(j=0; jnr; j++) { - LM_DBG("probing set #%d, URI %.*s\n", list->id, - list->dlist[j].uri.len, list->dlist[j].uri.s); - - /* Execute the Dialog using the "request"-Method of the - * TM-Module.*/ - if (tmb.new_auto_dlg_uac(&ds_ping_from, - &list->dlist[j].uri, - list->dlist[j].sock?list->dlist[j].sock:probing_sock, - &dlg) != 0 ) { - LM_ERR("failed to create new TM dlg\n"); - continue; - } - dlg->state = DLG_CONFIRMED; - if (tmb.t_request_within(&ds_ping_method, - NULL, - NULL, - dlg, - ds_options_callback, - (void*)(long)list->id, - NULL) < 0) { - LM_ERR("unable to execute dialog\n"); + /* If the Flag of the entry has "Probing set, send a probe: */ + if ( ((list->dlist[j].flags&DS_INACTIVE_DST)==0) && + (ds_probing_mode==1 || (list->dlist[j].flags&DS_PROBING_DST)!=0) ) + { + LM_DBG("probing set #%d, URI %.*s\n", list->id, + list->dlist[j].uri.len, list->dlist[j].uri.s); + + /* Execute the Dialog using the "request"-Method of the + * TM-Module.*/ + if (tmb.new_auto_dlg_uac(&ds_ping_from, + &list->dlist[j].uri, + list->dlist[j].sock?list->dlist[j].sock:probing_sock, + &dlg) != 0 ) { + LM_ERR("failed to create new TM dlg\n"); + continue; + } + dlg->state = DLG_CONFIRMED; + + ds_options_callback_param_t *cb_param = + shm_malloc(sizeof(*cb_param)); + + if (cb_param == NULL) { + LM_CRIT("No more shared memory\n"); + continue; + } + cb_param->partition = partition; + cb_param->set_id = list->id; + if (tmb.t_request_within(&ds_ping_method, + NULL, + NULL, + dlg, + ds_options_callback, + (void*)cb_param, + shm_free_cb_param) < 0) { + LM_ERR("unable to execute dialog\n"); + } + tmb.free_dlg(dlg); } - tmb.free_dlg(dlg); } } + + lock_stop_read( partition->lock ); } } -int ds_count(struct sip_msg *msg, int set_id, const char *cmp, pv_spec_p ret) + +int ds_count(struct sip_msg *msg, int set_id, const char *cmp, pv_spec_p ret, + ds_partition_t *partition) { pv_value_t pv_val; ds_set_p set; ds_dest_p dst; int count, active = 0, inactive = 0, probing = 0; - set = ds_lists[*crt_idx]; - LM_DBG("Searching for set: %d, filtering: %d\n", set_id, *cmp); - while (set && set->id != set_id) - { - set = set->next; - } + /* access ds data under reader's lock */ + lock_start_read( partition->lock ); - if (!set) - { - LM_ERR("INVALID SET!\n"); + if ( ds_get_index( set_id, &set, partition)!=0 ) { + LM_ERR("INVALID SET %d (not found)!\n",set_id); + lock_stop_read( partition->lock ); return -1; } @@ -1907,6 +2151,8 @@ int ds_count(struct sip_msg *msg, int set_id, const char *cmp, pv_spec_p ret) } } + lock_stop_read( partition->lock ); + switch (*cmp) { case DS_COUNT_ACTIVE: diff --git a/modules/dispatcher/dispatch.h b/modules/dispatcher/dispatch.h index 023e199f791..9f260b664c5 100644 --- a/modules/dispatcher/dispatch.h +++ b/modules/dispatcher/dispatch.h @@ -2,7 +2,7 @@ * $Id$ * * dispatcher module - * + * * Copyright (C) 2004-2006 FhG Fokus * * This file is part of opensips, a free SIP server. @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -32,6 +32,8 @@ * to ds_is_from_list. * 2009-05-18 Added support for weights for the destinations; * added support for custom "attrs" (opaque string) (bogdan) + * 2013-12-02 Added support state persistency (restart and reload) (bogdan) + * 2013-12-05 Added a safer reload mechanism based on locking read/writter (bogdan) */ #ifndef _DISPATCH_H_ @@ -41,15 +43,19 @@ #include "../../pvar.h" #include "../../parser/msg_parser.h" #include "../tm/tm_load.h" - -#include "ds_bl.h" +#include "../../db/db.h" +#include "../../rw_locking.h" #define DS_HASH_USER_ONLY 1 /* use only the uri user part for hashing */ #define DS_FAILOVER_ON 2 /* store the other dest in avps */ +#define DS_USE_DEFAULT 4 /* use last address in destination set as last option */ +#define DS_FORCE_DST 8 /* if not set it will force overwriting the destination address + if already set */ #define DS_INACTIVE_DST 1 /* inactive destination */ #define DS_PROBING_DST 2 /* checking destination */ #define DS_RESET_FAIL_DST 4 /* Reset-Failure-Counter */ +#define DS_STATE_DIRTY_DST 8 /* STATE is dirty */ #define DS_PV_ALGO_MARKER "%u" /* Marker to indicate where the URI should be inserted in the pvar */ @@ -61,12 +67,17 @@ #define DS_COUNT_INACTIVE 2 #define DS_COUNT_PROBING 4 +#define DS_PARTITION_DELIM ':' +#define DS_DEFAULT_PARTITION_NAME "default" + typedef struct _ds_dest { str uri; + str dst_uri; /* Actual uri used in ds_select_dst ds_select_domain */ str attrs; int flags; int weight; + int priority; struct socket_info *sock; struct ip_addr ips[DS_MAX_IPS]; /* IP-Address of the entry */ unsigned short int ports[DS_MAX_IPS]; /* Port of the request URI */ @@ -86,6 +97,12 @@ typedef struct _ds_set struct _ds_set *next; } ds_set_t, *ds_set_p; +typedef struct _ds_data +{ + ds_set_t *sets; + unsigned int sets_no; +} ds_data_t; + typedef struct _ds_pvar_param { pv_spec_t pvar; @@ -93,33 +110,61 @@ typedef struct _ds_pvar_param } ds_pvar_param_t, *ds_pvar_param_p; -extern ds_set_p *ds_lists; -extern int *crt_idx; -extern int *next_idx; +typedef struct _ds_partition +{ + str name; /* Partition name */ + str table_name; /* Table name */ + str db_url; /* DB url */ + + db_con_t **db_handle; + db_func_t dbf; + ds_data_t **data; /* dispatching data holder */ + rw_lock_t *lock; /* reader-writers lock for reloading the data */ + + int dst_avp_name; + unsigned short dst_avp_type; + + int grp_avp_name; + unsigned short grp_avp_type; + + int cnt_avp_name; + unsigned short cnt_avp_type; + + int sock_avp_name; + unsigned short sock_avp_type; + + int attrs_avp_name; + unsigned short attrs_avp_type; + + struct _ds_partition *next; +} ds_partition_t; + + +typedef struct _ds_select_ctl +{ + int set; /* set id to process */ + ds_partition_t *partition; /* partition of set_id */ + int alg; /* algorith to aply */ + int mode; /* set destination uri */ + int max_results; /* max destinaitons to process */ + int reset_AVP; /* reset AVPs flag */ + int set_destination; /* set destination flag */ +} ds_select_ctl_t, *ds_select_ctl_p; + +typedef struct +{ + ds_partition_t *partition; + int set_id; +} ds_options_callback_param_t; -extern str ds_db_url; -extern str ds_table_name; extern str ds_set_id_col; extern str ds_dest_uri_col; extern str ds_dest_sock_col; -extern str ds_dest_flags_col; +extern str ds_dest_state_col; extern str ds_dest_weight_col; +extern str ds_dest_prio_col; extern str ds_dest_attrs_col; -extern int ds_flags; -extern int ds_use_default; - -extern int dst_avp_name; -extern unsigned short dst_avp_type; -extern int grp_avp_name; -extern unsigned short grp_avp_type; -extern int cnt_avp_name; -extern unsigned short cnt_avp_type; -extern int sock_avp_name; -extern unsigned short sock_avp_type; -extern int attrs_avp_name; -extern unsigned short attrs_avp_type; - extern pv_elem_t * hash_param_model; extern str ds_setid_pvname; @@ -130,29 +175,35 @@ struct tm_binds tmb; extern str ds_ping_method; extern str ds_ping_from; extern int probing_threshhold; /* number of failed requests, - before a destination is taken into probing */ + before a destination is taken into probing */ extern int ds_probing_mode; -int init_data(); -int init_ds_db(); -int ds_connect_db(); -void ds_disconnect_db(); -int ds_load_db(); -int ds_destroy_list(); -int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_results); -int ds_next_dst(struct sip_msg *msg, int mode); -int ds_set_state(int group, str *address, int state, int type); -int ds_mark_dst(struct sip_msg *msg, int mode); -int ds_print_list(FILE *fout); -int ds_print_mi_list(struct mi_node* rpl); -int ds_count(struct sip_msg *msg, int set_id, const char *cmp, pv_spec_p ret); + +int init_ds_db(ds_partition_t *partition); +int ds_connect_db(ds_partition_t *partition); +void ds_disconnect_db(ds_partition_t *partition); +int ds_reload_db(ds_partition_t *partition); + +int init_ds_data(ds_partition_t *partition); +void ds_destroy_data(ds_partition_t *partition); + +int ds_select_dst(struct sip_msg *msg, ds_select_ctl_p ds_select_ctl, int ds_flags); +int ds_next_dst(struct sip_msg *msg, int mode, ds_partition_t *partition); +int ds_set_state(int group, str *address, int state, int type, + ds_partition_t *partition); +int ds_mark_dst(struct sip_msg *msg, int mode, ds_partition_t *partition); +int ds_print_mi_list(struct mi_node* rpl, ds_partition_t *partition); +int ds_count(struct sip_msg *msg, int set_id, const char *cmp, pv_spec_p ret, + ds_partition_t *partition); int ds_is_in_list(struct sip_msg *_m, pv_spec_t *addr, pv_spec_t *port, - int set, int active_only); + int set, int active_only, ds_partition_t *partition); /* * Timer for checking inactive destinations */ void ds_check_timer(unsigned int ticks, void* param); +void ds_flusher_routine(unsigned int ticks, void* param); + int check_options_rplcode(int code); diff --git a/modules/dispatcher/dispatcher.c b/modules/dispatcher/dispatcher.c index 2810c9db436..23d052b3919 100644 --- a/modules/dispatcher/dispatcher.c +++ b/modules/dispatcher/dispatcher.c @@ -18,23 +18,25 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History * ------- * 2004-07-31 first version, by daniel * 2007-01-11 Added a function to check if a specific gateway is in a group - * (carsten - Carsten Bock, BASIS AudioNet GmbH) + * (carsten - Carsten Bock, BASIS AudioNet GmbH) * 2007-02-09 Added active probing of failed destinations and automatic - * re-enabling of destinations (carsten) + * re-enabling of destinations (carsten) * 2007-05-08 Ported the changes to SVN-Trunk and renamed ds_is_domain - * to ds_is_from_list. (carsten) - * 2007-07-18 Added support for load/reload groups from DB - * reload triggered from ds_reload MI_Command (ancuta) + * to ds_is_from_list. (carsten) + * 2007-07-18 Added support for load/reload groups from DB + * reload triggered from ds_reload MI_Command (ancuta) * 2009-05-18 Added support for weights for the destinations; - * added support for custom "attrs" (opaque string) (bogdan) + * added support for custom "attrs" (opaque string) (bogdan) + * 2013-12-02 Added support state persistency (restart and reload) (bogdan) + * 2013-12-05 Added a safer reload mechanism based on locking read/writter (bogdan) */ #include @@ -54,41 +56,27 @@ #include "../../db/db.h" #include "dispatch.h" +#include "ds_bl.h" +#include "ds_fixups.h" #define DS_SET_ID_COL "setid" #define DS_DEST_URI_COL "destination" #define DS_DEST_SOCK_COL "socket" -#define DS_DEST_FLAGS_COL "flags" +#define DS_DEST_STATE_COL "state" #define DS_DEST_WEIGHT_COL "weight" +#define DS_DEST_PRIO_COL "priority" #define DS_DEST_ATTRS_COL "attrs" #define DS_TABLE_NAME "dispatcher" +#define DS_PARTITION_DELIM ':' /** parameters */ -int ds_force_dst = 0; -int ds_flags = 0; -int ds_use_default = 0; -static str dst_avp_param = str_init("$avp(ds_dst_failover)"); -static str grp_avp_param = str_init("$avp(ds_grp_failover)"); -static str cnt_avp_param = str_init("$avp(ds_cnt_failover)"); -static str sock_avp_param = str_init("$avp(ds_sock_failover)"); -static str attrs_avp_param = {NULL, 0}; static str pvar_algo_param = str_init(""); str hash_pvar_param = {NULL, 0}; -int dst_avp_name; -unsigned short dst_avp_type; -int grp_avp_name; -unsigned short grp_avp_type; -int cnt_avp_name; -unsigned short cnt_avp_type; -int sock_avp_name; -unsigned short sock_avp_type; -int attrs_avp_name; -unsigned short attrs_avp_type; - pv_elem_t * hash_param_model = NULL; + int probing_threshhold = 3; /* number of failed requests, before a destination is taken into probing */ str ds_ping_method = {"OPTIONS",7}; @@ -96,80 +84,134 @@ str ds_ping_from = {"sip:dispatcher@localhost", 24}; static int ds_ping_interval = 0; int ds_probing_mode = 0; -/*db */ -str ds_db_url = {NULL, 0}; +/* db partiton info */ + +typedef struct _ds_db_head +{ + str partition_name; + str db_url; + str table_name; + + str dst_avp; + str grp_avp; + str cnt_avp; + str sock_avp; + str attrs_avp; + + struct _ds_db_head *next; +} ds_db_head_t; + + +ds_db_head_t default_db_head = { + str_init(DS_DEFAULT_PARTITION_NAME), + {NULL, 0}, + {NULL, 0}, + + + {NULL, 0}, + {NULL, 0}, + {NULL, 0}, + {NULL, 0}, + {NULL, 0}, + NULL +}; +ds_db_head_t *ds_db_heads = NULL; + +typedef struct { + str name; + str default_value; + str* (*getter_func)(ds_db_head_t*); +} partition_specific_param_t; + +#define DEF_GETTER_FUNC(PARAM_FIELD) str* getter_ ## PARAM_FIELD (ds_db_head_t \ + *head) { \ + return &(head-> PARAM_FIELD);} +#define GETTER_FUNC(PARAM_FIELD) &getter_ ## PARAM_FIELD +#define PARTITION_SPECIFIC_PARAM(PARAM_NAME, DEFAULT_VALUE) \ + {str_init(#PARAM_NAME), str_init(DEFAULT_VALUE), GETTER_FUNC(PARAM_NAME)} + + +/*db common attributes*/ str ds_set_id_col = str_init(DS_SET_ID_COL); str ds_dest_uri_col = str_init(DS_DEST_URI_COL); str ds_dest_sock_col = str_init(DS_DEST_SOCK_COL); -str ds_dest_flags_col = str_init(DS_DEST_FLAGS_COL); +str ds_dest_state_col = str_init(DS_DEST_STATE_COL); str ds_dest_weight_col= str_init(DS_DEST_WEIGHT_COL); +str ds_dest_prio_col = str_init(DS_DEST_PRIO_COL); str ds_dest_attrs_col = str_init(DS_DEST_ATTRS_COL); -str ds_table_name = str_init(DS_TABLE_NAME); str ds_setid_pvname = {NULL, 0}; pv_spec_t ds_setid_pv; static str options_reply_codes_str= {0, 0}; static int* options_reply_codes = NULL; -static int options_codes_no; +static int options_codes_no; static char *probing_sock_s = NULL; struct socket_info *probing_sock = NULL; +ds_partition_t *partitions = NULL, *default_partition = NULL; + /* event */ static str dispatcher_event = str_init("E_DISPATCHER_STATUS"); event_id_t dispatch_evi_id; + /** module functions */ static int mod_init(void); +static int ds_child_init(int rank); static int w_ds_select_dst(struct sip_msg*, char*, char*); static int w_ds_select_dst_limited(struct sip_msg*, char*, char*, char*); static int w_ds_select_domain(struct sip_msg*, char*, char*); static int w_ds_select_domain_limited(struct sip_msg*, char*, char*, char*); -static int w_ds_next_dst(struct sip_msg*, char*, char*); -static int w_ds_next_domain(struct sip_msg*, char*, char*); -static int w_ds_mark_dst0(struct sip_msg*, char*, char*); -static int w_ds_mark_dst1(struct sip_msg*, char*, char*); +static int w_ds_next_dst(struct sip_msg*, char*); +static int w_ds_next_domain(struct sip_msg*, char*); +static int w_ds_mark_dst(struct sip_msg*, char*, char*); +static int w_ds_mark_dst1(struct sip_msg*, char *); static int w_ds_count(struct sip_msg*, char*, const char *, char*); -static int w_ds_is_in_list2(struct sip_msg*, char*, char*); -static int w_ds_is_in_list3(struct sip_msg*, char*, char*, char*); -static int w_ds_is_in_list4(struct sip_msg*, char*, char*, char*, char*); +static int w_ds_is_in_list(struct sip_msg*, char*, char*, char*, char*); static void destroy(void); -static int in_list_fixup(void** param, int param_no); -static int ds_count_fixup(void** param, int param_no); - static struct mi_root* ds_mi_set(struct mi_root* cmd, void* param); static struct mi_root* ds_mi_list(struct mi_root* cmd, void* param); static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param); static int mi_child_init(void); +/* Parameters setters */ + +static int set_partition_arguments(unsigned int type, void * val); static cmd_export_t cmds[]={ - {"ds_select_dst", (cmd_function)w_ds_select_dst, 2, fixup_igp_igp, 0, + {"ds_select_dst", (cmd_function)w_ds_select_dst, 2, ds_select_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"ds_select_dst", (cmd_function)w_ds_select_dst_limited, 3, fixup_igp_igp_igp, 0, + {"ds_select_dst", (cmd_function)w_ds_select_dst_limited, 3, ds_select_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"ds_select_domain", (cmd_function)w_ds_select_domain, 2, fixup_igp_igp, 0, + {"ds_select_domain", (cmd_function)w_ds_select_domain, 2, ds_select_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"ds_select_domain", (cmd_function)w_ds_select_domain_limited, 3, fixup_igp_igp_igp, 0, + {"ds_select_domain", (cmd_function)w_ds_select_domain_limited, 3, ds_select_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE}, {"ds_next_dst", (cmd_function)w_ds_next_dst, 0, NULL , 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"ds_next_domain", (cmd_function)w_ds_next_domain, 0, NULL , 0, + {"ds_next_dst", (cmd_function)w_ds_next_dst, 1, ds_next_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE}, + {"ds_next_domain", (cmd_function)w_ds_next_domain, 0, NULL , 0, + REQUEST_ROUTE|FAILURE_ROUTE}, + {"ds_next_domain", (cmd_function)w_ds_next_domain, 1, ds_next_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"ds_mark_dst", (cmd_function)w_ds_mark_dst0, 0, NULL , 0, + {"ds_mark_dst", (cmd_function)w_ds_mark_dst, 0, NULL , 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"ds_mark_dst", (cmd_function)w_ds_mark_dst1, 1, NULL , 0, + {"ds_mark_dst", (cmd_function)w_ds_mark_dst1, 1, fixup_sgp_null, 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"ds_is_in_list", (cmd_function)w_ds_is_in_list2, 2, in_list_fixup, 0, + {"ds_mark_dst", (cmd_function)w_ds_mark_dst, 2, ds_mark_fixup, 0, + REQUEST_ROUTE|FAILURE_ROUTE}, + {"ds_is_in_list", (cmd_function)w_ds_is_in_list, 2, in_list_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"ds_is_in_list", (cmd_function)w_ds_is_in_list3, 3, in_list_fixup, 0, + {"ds_is_in_list", (cmd_function)w_ds_is_in_list, 3, in_list_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"ds_is_in_list", (cmd_function)w_ds_is_in_list4, 4, in_list_fixup, 0, + {"ds_is_in_list", (cmd_function)w_ds_is_in_list, 4, in_list_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"ds_count", (cmd_function)w_ds_count, 3, ds_count_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, @@ -178,22 +220,21 @@ static cmd_export_t cmds[]={ static param_export_t params[]={ - {"db_url", STR_PARAM, &ds_db_url.s}, - {"table_name", STR_PARAM, &ds_table_name.s}, + {"partition", STR_PARAM | USE_FUNC_PARAM, (void*)&set_partition_arguments}, + {"db_url", STR_PARAM, &default_db_head.db_url.s}, + {"table_name", STR_PARAM, &default_db_head.table_name.s}, {"setid_col", STR_PARAM, &ds_set_id_col.s}, {"destination_col", STR_PARAM, &ds_dest_uri_col.s}, {"socket_col", STR_PARAM, &ds_dest_sock_col.s}, - {"flags_col", STR_PARAM, &ds_dest_flags_col.s}, + {"state_col", STR_PARAM, &ds_dest_state_col.s}, {"weight_col", STR_PARAM, &ds_dest_weight_col.s}, + {"priority_col", STR_PARAM, &ds_dest_prio_col.s}, {"attrs_col", STR_PARAM, &ds_dest_attrs_col.s}, - {"force_dst", INT_PARAM, &ds_force_dst}, - {"flags", INT_PARAM, &ds_flags}, - {"use_default", INT_PARAM, &ds_use_default}, - {"dst_avp", STR_PARAM, &dst_avp_param.s}, - {"grp_avp", STR_PARAM, &grp_avp_param.s}, - {"cnt_avp", STR_PARAM, &cnt_avp_param.s}, - {"sock_avp", STR_PARAM, &sock_avp_param.s}, - {"attrs_avp", STR_PARAM, &attrs_avp_param.s}, + {"dst_avp", STR_PARAM, &default_db_head.dst_avp.s}, + {"grp_avp", STR_PARAM, &default_db_head.grp_avp.s}, + {"cnt_avp", STR_PARAM, &default_db_head.cnt_avp.s}, + {"sock_avp", STR_PARAM, &default_db_head.sock_avp.s}, + {"attrs_avp", STR_PARAM, &default_db_head.attrs_avp.s}, {"hash_pvar", STR_PARAM, &hash_pvar_param.s}, {"setid_pvar", STR_PARAM, &ds_setid_pvname.s}, {"pvar_algo_pattern", STR_PARAM, &pvar_algo_param.s}, @@ -208,6 +249,13 @@ static param_export_t params[]={ {0,0,0} }; +static module_dependency_t *get_deps_ds_ping_interval(param_export_t *param) +{ + if (*(int *)param->param_pointer <= 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_DEFAULT, "tm", DEP_ABORT); +} static mi_export_t mi_cmds[] = { { "ds_set_state", 0, ds_mi_set, 0, 0, 0 }, @@ -216,12 +264,24 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "ds_ping_interval", get_deps_ds_ping_interval }, + { NULL, NULL }, + }, +}; /** module exports */ struct module_exports exports= { "dispatcher", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, params, 0, /* exported statistics */ @@ -231,126 +291,413 @@ struct module_exports exports= { mod_init, /* module initialization function */ (response_function) 0, (destroy_function) destroy, - 0, /* per-child init function */ + ds_child_init, /* per-child init function */ }; -/** - * init module function - */ -static int mod_init(void) +DEF_GETTER_FUNC(db_url); +DEF_GETTER_FUNC(table_name); +DEF_GETTER_FUNC(dst_avp); +DEF_GETTER_FUNC(grp_avp); +DEF_GETTER_FUNC(cnt_avp); +DEF_GETTER_FUNC(sock_avp); +DEF_GETTER_FUNC(attrs_avp); + +static partition_specific_param_t partition_params[] = { + {str_init("db_url"), {NULL, 0}, GETTER_FUNC(db_url)}, + PARTITION_SPECIFIC_PARAM (table_name, DS_TABLE_NAME), + PARTITION_SPECIFIC_PARAM (dst_avp, "$avp(ds_dst_failover)"), + PARTITION_SPECIFIC_PARAM (grp_avp, "$avp(ds_grp_failover)"), + PARTITION_SPECIFIC_PARAM (cnt_avp, "$avp(ds_cnt_failover)"), + PARTITION_SPECIFIC_PARAM (sock_avp, "$avp(ds_sock_failover)"), + PARTITION_SPECIFIC_PARAM (attrs_avp, ""), +}; + +static const unsigned int partition_param_count = sizeof (partition_params) / + sizeof (partition_specific_param_t); + +/* + Splits the arg from "partition_name[DELIM]value" to partition_name + and value. The arg is modified and will contain only value +*/ + +static int split_partition_argument(str *arg, str *partition_name) { - pv_spec_t avp_spec; + char *delim_pos = memchr(arg->s, DS_PARTITION_DELIM, arg->len); + partition_name->s = NULL; + partition_name->len = 0; - LM_DBG("initializing ...\n"); + if (delim_pos == NULL) { + /* No delim so the default partition is used */ + return 0; + } else if (delim_pos - arg->s + 1 == arg->len){ + + LM_WARN("possibly empty parameter %.*s\n", arg->len, arg->s); + return 0; + } else { + + switch (DS_PARTITION_DELIM) { + + case ':': + if (*(delim_pos + 1) == '/'){ + /* Fake delimiter as in mysql://... */ + return 0; + } + /* else An actual delimiter has been found */ + break; + + default: + LM_CRIT("Partition delimiter %c was not properly implemented\n", + DS_PARTITION_DELIM); + return -1; + break; + } + } - /* Load stuff from DB */ - init_db_url( ds_db_url , 0 /*cannot be null*/); - if(init_data()!= 0) + partition_name->s = arg->s; + partition_name->len = delim_pos - arg->s; + + arg->s = delim_pos + 1; + arg->len -= partition_name->len + 1; + + str_trim_spaces_lr(*partition_name); + for (;arg->s[0] == ' ' && arg->len; ++arg->s, --arg->len); + return 0; +} + +/* + Parse an argument "partition_name[DELIM]arg_value". + The arg string will be modified and will contain only "arg_value" + The found_head will contain the head which has the name + "partition_name" + If the head doesn't exist it will be created +*/ +static int parse_partition_argument(str *arg, ds_db_head_t **found_head) +{ + str partition_name; + + if (split_partition_argument(arg, &partition_name) != 0) return -1; - ds_table_name.len = strlen(ds_table_name.s); - ds_set_id_col.len = strlen(ds_set_id_col.s); - ds_dest_uri_col.len = strlen(ds_dest_uri_col.s); - ds_dest_sock_col.len = strlen(ds_dest_sock_col.s); - ds_dest_flags_col.len = strlen(ds_dest_flags_col.s); - ds_dest_weight_col.len = strlen(ds_dest_weight_col.s); - ds_dest_attrs_col.len = strlen(ds_dest_attrs_col.s); + if (partition_name.len == 0 + || str_strcmp(&default_db_head.partition_name, &partition_name) == 0){ - if(init_ds_db()!= 0) - { - LM_ERR("failed to load data from database\n"); + *found_head = &default_db_head; + return 0; + } + + /* There is a partition name in arg so we won't use default head*/ + ds_db_head_t *heads_it; + for (heads_it = ds_db_heads; heads_it; heads_it = heads_it->next) + if (memcmp(partition_name.s, heads_it->partition_name.s, + partition_name.len) == 0){ + + /* This partition already exists */ + *found_head = heads_it; + return 0; + } + + /* The partition does not exist - we create it */ + + ds_db_head_t *new_partition = pkg_malloc(sizeof (ds_db_head_t)); + if (new_partition == NULL) { + LM_ERR("failed to alocate data in shm\n"); return -1; } + /* Set default head values */ + + memset(new_partition, 0, sizeof(ds_db_head_t)); + new_partition->next = ds_db_heads; + ds_db_heads = new_partition; + new_partition->partition_name = partition_name; + + *found_head = new_partition; + return 0; +} + +/* + Find partition by name. Return null if no partition is matching the name +*/ + +static ds_partition_t* find_partition_by_name (const str *partition_name) +{ + if (partition_name->len == 0) + return default_partition; + + ds_partition_t *part_it; + + for (part_it = partitions; part_it; part_it = part_it->next) + if (str_strcmp(&part_it->name, partition_name) == 0) + break; + + return part_it; //and NULL if there's no partition matching the name +} + + +/* We parse the "partition" argument as: partition_name:arg1=val1; arg2=val2;*/ + +static int set_partition_arguments(unsigned int type, void *val) +{ + static const char end_pair_delim = ';'; + static const char eq_val_delim = '='; + static const str blacklist_param = str_init("ds_define_blacklist"); + unsigned int i; + + str raw_line = {(char*)val, strlen(val)}; + str arg, value; + ds_db_head_t *head = NULL; + + if (raw_line.s[raw_line.len - 1] != end_pair_delim) + raw_line.s[raw_line.len++] = end_pair_delim; + + if (parse_partition_argument(&raw_line, &head) != 0) + return -1; + + char *first_pos = raw_line.s; /* just for error messages */ + char *end_pair_pos = q_memchr(raw_line.s, end_pair_delim, raw_line.len); + char *eq_pos = q_memchr(raw_line.s, eq_val_delim, raw_line.len); + + while (end_pair_pos != NULL && eq_pos != NULL) { + + arg.s = raw_line.s; + arg.len = eq_pos - arg.s; + value.s = eq_pos + 1; + value.len = end_pair_pos - eq_pos - 1; + str_trim_spaces_lr(arg); + str_trim_spaces_lr(value); + + if (arg.len <= 0 || value.len <= 0) { + LM_ERR("Wrong format in partition arguments specifier at pos %d\n", + (int)(arg.s - first_pos + 1)); + return -1; + } + + for (i = 0; i < partition_param_count; ++i) + if (str_strcmp(&arg, &partition_params[i].name) == 0) { + *(partition_params[i].getter_func(head)) = value; + break; + } + + if ( i == partition_param_count) { + if (str_strcmp(&blacklist_param, &arg) == 0) { + value.s[value.len] = 0; + if (set_ds_bl_partition(value.s, head->partition_name) != 0) + return -1; + } + else{ + /* No paramater found */ + LM_ERR("No such parameter known: %.*s\n", arg.len, arg.s); + return -1; + } + } + + raw_line.s = end_pair_pos + 1; + end_pair_pos = q_memchr(raw_line.s, end_pair_delim, raw_line.len); + eq_pos = q_memchr(raw_line.s, eq_val_delim, raw_line.len); + } + + return 0; +} + +static int partition_init(ds_db_head_t *db_head, ds_partition_t *partition) +{ + + /* Load stuff from DB. URL cannot be null!*/ + if (db_head->db_url.s == NULL){ + LM_ERR("[%.*s] DB URL is not defined!\n", db_head->partition_name.len, + db_head->partition_name.s); + return -1; + } + + memset(partition, 0, sizeof(ds_partition_t)); + partition->name = db_head->partition_name; + partition->table_name = db_head->table_name; + partition->db_url = db_head->db_url; + partition->db_handle = pkg_malloc(sizeof(struct db_con_t *)); + if (partition->db_handle == NULL) { + LM_ERR("Failed to allocate private data\n"); + return -1; + } + *partition->db_handle = NULL; + /* handle AVPs spec */ - dst_avp_param.len = strlen(dst_avp_param.s); - if (pv_parse_spec(&dst_avp_param, &avp_spec)==0 + pv_spec_t avp_spec; + + if (pv_parse_spec(&db_head->dst_avp, &avp_spec)==0 || avp_spec.type!=PVT_AVP) { LM_ERR("malformed or non AVP %.*s AVP definition\n", - dst_avp_param.len, dst_avp_param.s); + db_head->dst_avp.len, db_head->dst_avp.s); return -1; } - if(pv_get_avp_name(0, &(avp_spec.pvp), &dst_avp_name,&dst_avp_type)!=0) { - LM_ERR("[%.*s]- invalid AVP definition\n", dst_avp_param.len, - dst_avp_param.s); + if(pv_get_avp_name(0, &(avp_spec.pvp), &partition->dst_avp_name, + &partition->dst_avp_type)!=0) { + LM_ERR("[%.*s]- invalid AVP definition\n", db_head->dst_avp.len, + db_head->dst_avp.s); return -1; } - grp_avp_param.len=strlen(grp_avp_param.s); - if (pv_parse_spec(&grp_avp_param, &avp_spec)==0 + if (pv_parse_spec(&db_head->grp_avp, &avp_spec)==0 || avp_spec.type!=PVT_AVP) { LM_ERR("malformed or non AVP %.*s AVP definition\n", - grp_avp_param.len, grp_avp_param.s); + db_head->grp_avp.len, db_head->grp_avp.s); return -1; } - if(pv_get_avp_name(0, &(avp_spec.pvp), &grp_avp_name,&grp_avp_type)!=0) { - LM_ERR("[%.*s]- invalid AVP definition\n", grp_avp_param.len, - grp_avp_param.s); + if(pv_get_avp_name(0, &(avp_spec.pvp), &partition->grp_avp_name, + &partition->grp_avp_type)!=0) { + LM_ERR("[%.*s]- invalid AVP definition\n", db_head->grp_avp.len, + db_head->grp_avp.s); return -1; } - cnt_avp_param.len=strlen(cnt_avp_param.s); - if (pv_parse_spec(&cnt_avp_param, &avp_spec)==0 + if (pv_parse_spec(&db_head->cnt_avp, &avp_spec)==0 || avp_spec.type!=PVT_AVP) { LM_ERR("malformed or non AVP %.*s AVP definition\n", - cnt_avp_param.len, cnt_avp_param.s); + db_head->cnt_avp.len, db_head->cnt_avp.s); return -1; } - if(pv_get_avp_name(0, &(avp_spec.pvp), &cnt_avp_name,&cnt_avp_type)!=0) { - LM_ERR("[%.*s]- invalid AVP definition\n", cnt_avp_param.len, - cnt_avp_param.s); + if(pv_get_avp_name(0, &(avp_spec.pvp), &partition->cnt_avp_name, + &partition->cnt_avp_type)!=0) { + LM_ERR("[%.*s]- invalid AVP definition\n", db_head->cnt_avp.len, + db_head->cnt_avp.s); return -1; } - sock_avp_param.len=strlen(sock_avp_param.s); - if (pv_parse_spec(&sock_avp_param, &avp_spec)==0 + if (pv_parse_spec(&db_head->sock_avp, &avp_spec)==0 || avp_spec.type!=PVT_AVP) { LM_ERR("malformed or non AVP %.*s AVP definition\n", - sock_avp_param.len, sock_avp_param.s); + db_head->sock_avp.len, db_head->sock_avp.s); return -1; } - if(pv_get_avp_name(0, &(avp_spec.pvp), &sock_avp_name,&sock_avp_type)!=0){ - LM_ERR("[%.*s]- invalid AVP definition\n", sock_avp_param.len, - sock_avp_param.s); + if(pv_get_avp_name(0, &(avp_spec.pvp), &partition->sock_avp_name, + &partition->sock_avp_type)!=0){ + LM_ERR("[%.*s]- invalid AVP definition\n", db_head->sock_avp.len, + db_head->sock_avp.s); return -1; } - if (attrs_avp_param.s && (attrs_avp_param.len=strlen(attrs_avp_param.s)) > 0) { - if (pv_parse_spec(&attrs_avp_param, &avp_spec)==0 + if (db_head->attrs_avp.s && db_head->attrs_avp.len > 0) { + if (pv_parse_spec(&db_head->attrs_avp, &avp_spec)==0 || avp_spec.type!=PVT_AVP) { LM_ERR("malformed or non AVP %.*s AVP definition\n", - attrs_avp_param.len, attrs_avp_param.s); + db_head->attrs_avp.len, db_head->attrs_avp.s); return -1; } - if (pv_get_avp_name(0, &(avp_spec.pvp), &attrs_avp_name, - &attrs_avp_type)!=0){ - LM_ERR("[%.*s]- invalid AVP definition\n", attrs_avp_param.len, - attrs_avp_param.s); + if (pv_get_avp_name(0, &(avp_spec.pvp), &partition->attrs_avp_name, + &partition->attrs_avp_type)!=0){ + LM_ERR("[%.*s]- invalid AVP definition\n", db_head->attrs_avp.len, + db_head->attrs_avp.s); return -1; } } else { - attrs_avp_name = -1; - attrs_avp_type = 0; + partition->attrs_avp_name = -1; + partition->attrs_avp_type = 0; } - if (init_ds_bls()!=0) { - LM_ERR("failed to init DS blacklists\n"); - return E_CFG; + return 0; +} + + +static int inherit_from_default_head(ds_db_head_t *head) +{ + if (head == &default_db_head) + return 0; + + unsigned int i; + + for (i = 0; i < partition_param_count; ++i) { + str *def_param = partition_params[i].getter_func(&default_db_head); + str *p_param = partition_params[i].getter_func(head); + + if (p_param->len == 0 && def_param->len > 0) { + /* Paramater not specified for function */ + if (strstr(partition_params[i].name.s, "avp") + && def_param->len > 0) { + + char *avp_end = q_memrchr(def_param->s, ')', def_param->len); + if (avp_end == NULL) { + LM_ERR ("wrong avp name %.*s\n", def_param->len, + def_param->s); + return -1; + } + + p_param->len = def_param->len + 1 + head->partition_name.len; + p_param->s = pkg_malloc(p_param->len); + if (p_param->s == NULL) { + LM_ERR ("no more private memory\n"); + return -1; + } + + int fix_len = avp_end - def_param->s; + int rem_len = def_param->len - fix_len; + memcpy(p_param->s, def_param->s, fix_len); + p_param->s[fix_len] = '_'; + memcpy(p_param->s + fix_len + 1, head->partition_name.s, + head->partition_name.len); + memcpy(p_param->s + fix_len + 1 + head->partition_name.len, + def_param->s + fix_len, rem_len); + } + else + memcpy(p_param, def_param, sizeof(str)); + } } + return 0; +} - if (populate_ds_bls()) { - LM_ERR("Failed to populate DS blacklist\n"); - return E_CFG; +void set_default_head_values(ds_db_head_t *head) +{ + unsigned int i; + + for (i = 0; i < partition_param_count; ++i) { + str *p_val = partition_params[i].getter_func(head); + if (p_val->s == NULL) + *p_val = partition_params[i].default_value; + else + p_val->len = strlen(p_val -> s); } +} + +static inline int check_if_default_head_is_ok(void) +{ + unsigned int i; + + for (i = 0; i < partition_param_count; ++i) + if (partition_params[i].getter_func(&default_db_head)->s != NULL) + return 1; + + return 0; +} + + +/** + * init module function + */ +static int mod_init(void) +{ + + LM_DBG("initializing ...\n"); + + if (check_if_default_head_is_ok()) { + default_db_head.next = ds_db_heads; + ds_db_heads = &default_db_head; + } + set_default_head_values(&default_db_head); + + ds_set_id_col.len = strlen(ds_set_id_col.s); + ds_dest_uri_col.len = strlen(ds_dest_uri_col.s); + ds_dest_sock_col.len = strlen(ds_dest_sock_col.s); + ds_dest_state_col.len = strlen(ds_dest_state_col.s); + ds_dest_weight_col.len = strlen(ds_dest_weight_col.s); + ds_dest_attrs_col.len = strlen(ds_dest_attrs_col.s); + if (hash_pvar_param.s && (hash_pvar_param.len=strlen(hash_pvar_param.s))>0 ) { if(pv_parse_format(&hash_pvar_param, &hash_param_model) < 0 || hash_param_model==NULL) { LM_ERR("malformed PV string: %s\n", hash_pvar_param.s); return -1; - } + } } else { hash_param_model = NULL; } @@ -368,6 +715,54 @@ static int mod_init(void) if (pvar_algo_param.len) ds_pvar_parse_pattern(pvar_algo_param); + + if (init_ds_bls()!=0) { + LM_ERR("failed to init DS blacklists\n"); + return E_CFG; + } + + /* Creating partitions from head */ + ds_db_head_t *head_it = ds_db_heads; + while (head_it){ + if (inherit_from_default_head(head_it) != 0) + return -1; + + ds_partition_t *partition = shm_malloc (sizeof(ds_partition_t)); + if (partition_init(head_it, partition) != 0) + return -1; + partition->next = partitions; + partitions = partition; + + if (init_ds_data(partition)!=0) { + LM_ERR("failed to init DS data holder\n"); + return -1; + } + + /* open DB connection to load provisioning data */ + if (init_ds_db(partition)!= 0) { + LM_ERR("failed to init database support\n"); + return -1; + } + + /* do the actual data load */ + if (ds_reload_db(partition)!=0) { + LM_ERR("failed to load data from DB\n"); + return -1; + } + + /* close DB connection */ + ds_disconnect_db(partition); + ds_db_head_t *aux = head_it; + + /* We keep track of corespondig default parition */ + if (head_it == &default_db_head) + default_partition = partition; + + head_it = head_it->next; + if (aux != &default_db_head) + pkg_free(aux); + } + /* Only, if the Probing-Timer is enabled the TM-API needs to be loaded: */ if (ds_ping_interval > 0) { @@ -422,19 +817,57 @@ static int mod_init(void) } } - dispatch_evi_id = evi_publish_event(dispatcher_event); + /* register timer to flush the state of destination back to DB */ + if (register_timer("ds-flusher",ds_flusher_routine,NULL, 30)<0){ + LM_ERR("failed to register timer for DB flushing!\n"); + return -1; + } + + dispatch_evi_id = evi_publish_event(dispatcher_event); if (dispatch_evi_id == EVI_ERROR) LM_ERR("cannot register dispatcher event\n"); + return 0; } -static int mi_child_init(void) +/* + * Per process init function + */ +#include "../../pt.h" +static int ds_child_init(int rank) { - if(ds_db_url.s) - return ds_connect_db(); + /* we need DB connection from the timer procs (for the flushing) + * and from the main proc (for final flush on shutdown) */ + if ( (process_no==0 || rank==PROC_TIMER) ) { + + ds_partition_t *partition_it; + + for (partition_it = partitions; partition_it; + partition_it = partition_it->next){ + + if (partition_it->db_url.s) + if (ds_connect_db(partition_it) != 0) + return -1; + } + + } return 0; +} + +static int mi_child_init(void) +{ + ds_partition_t *partition_it; + + for (partition_it = partitions; partition_it; + partition_it = partition_it->next) + + if (partition_it->db_url.s) + if (ds_connect_db(partition_it) != 0) + return -1; + + return 0; } @@ -444,243 +877,375 @@ static int mi_child_init(void) static void destroy(void) { LM_DBG("destroying module ...\n"); - ds_destroy_list(); + + /* flush the state of the destinations */ + ds_flusher_routine(0, NULL); + + ds_partition_t *part_it = partitions, *aux; + + while (part_it) { + ds_destroy_data(part_it); + aux = part_it; + part_it = part_it->next; + + ds_disconnect_db(aux); + pkg_free(aux->db_handle); + shm_free(aux); + } /* destroy blacklists */ destroy_ds_bls(); } +static int get_flags_int_value(struct sip_msg* msg, pv_spec_t* pvs){ + + /*Get flags literal value*/ + pv_value_t value; + int ds_flags = 0; + if (pv_get_spec_value(msg, pvs, &value)) { + LM_ERR("no valid PV value found(error in scripts)\n"); + return -1; + } + + /*Parse string and get flags integer value*/ + + for ( ; value.rs.len > 0; value.rs.s++, value.rs.len--) { + switch (*value.rs.s) { + case ' ' : + break; + case 'f' : + case 'F' : + ds_flags |= DS_FAILOVER_ON; + break; + case 'u' : + case 'U' : + ds_flags |= DS_HASH_USER_ONLY; + break; + case 'd' : + case 'D' : + ds_flags |= DS_USE_DEFAULT; + break; + case 's' : + case 'S' : + ds_flags |= DS_FORCE_DST; + break; + default : + LM_ERR("Invalid flags PV value\n"); + return -1; + } + } + return ds_flags; +} +#define CHECK_AND_EXPAND_LIST(_list_) \ + do{\ + if (_list_->type == GPARAM_TYPE_PVS) { \ + _list_ ## _exp_end = _list_->next; \ + _list_ ## _exp_start = set_list_from_pvs(msg, _list_->v.pvs,\ + _list_->next);\ + if (_list_ ## _exp_start == NULL) {\ + LM_ERR("error when expanding " #_list_ " variable\n");\ + return -1;\ + }\ + _list_ = _list_ ## _exp_start;\ + }\ + } while (0) + +#define TRY_FREE_EXPANDED_LIST(_list_) \ + do {\ + if (_list_ ## _exp_start && _list_ == _list_ ## _exp_end) {\ + free_int_list(_list_ ## _exp_start, _list_ ## _exp_end);\ + _list_ ## _exp_start = NULL; \ + }\ + } while (0) /** * */ -static int w_ds_select_dst(struct sip_msg* msg, char* set, char* alg) +static int w_ds_select(struct sip_msg* msg, char* part_set, char* alg, char* max_results_flags, int mode) { - int a, s; - + int ret; + int run_prev_ds_select = 0; + int ds_flags = 0; + ds_select_ctl_t prev_ds_select_ctl, ds_select_ctl; if(msg==NULL) return -1; - if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0) - { - LM_ERR("no dst set value\n"); + + ds_select_ctl.mode = mode; + ds_select_ctl.max_results = 1000; + ds_select_ctl.reset_AVP = 1; + ds_select_ctl.set_destination = 1; + + /* Retrieve dispatcher set */ + ds_param_t *part_set_param = (ds_param_t*)part_set; + + if (fixup_get_partition(msg, &part_set_param->partition, + &ds_select_ctl.partition) != 0 ||ds_select_ctl.partition == NULL) { + LM_ERR("unknown partition\n"); return -1; } - if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0) - { - LM_ERR("no alg value\n"); - return -1; + + int_list_t *set_list = part_set_param->sets; + int_list_t *set_list_exp_start = NULL, *set_list_exp_end = NULL; + + /* Retrieve dispatcher algorithm */ + int_list_t *alg_list = (int_list_t *)alg; + int_list_t *alg_list_exp_start = NULL, *alg_list_exp_end = NULL; + + /* Retrieve dispatcher max results */ + + /*Pointer to the start of the list*/ + flags_int_list_t* lst_flgs_param = (flags_int_list_t *)max_results_flags; + + int_list_t *max_results_ptr = NULL; + /*In case this parameter is not specified*/ + if (max_results_flags) + max_results_ptr = lst_flgs_param->list; + + int_list_t *max_list = max_results_ptr; + int_list_t *max_list_exp_start = NULL, *max_list_exp_end = NULL; + + /* Retrieve dispatcher flags */ + + if (max_results_flags) { + ds_flags_t* flags= lst_flgs_param->flags; + if (flags->type == DS_FLAGS_TYPE_INT) { + ds_flags = flags->v.ival; + } else { + ds_flags = get_flags_int_value(msg, flags->v.pvs); + if (ds_flags < 0) { + LM_ERR("Invalid value in flags PV\n"); + return -1; + } + } } - return ds_select_dst(msg, s, a, 0 /*set dst uri*/, 1000); -} + /* Avoid compiler warning */ + memset(&prev_ds_select_ctl, 0, sizeof(ds_select_ctl_t)); -/** - * same wrapper as w_ds_select_dst, but it allows cutting down the result set - */ -static int w_ds_select_dst_limited(struct sip_msg* msg, char* set, char* alg, char* max_results) -{ - int a, s, m; + ds_select_ctl.set_destination = 0; - if(msg==NULL) - return -1; - if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0) - { - LM_ERR("no dst set value\n"); - return -1; + /* Parse the params in reverse order. + * We need to runt the first entry last to properly populate ds_select_dst AVPs. + * On the first ds_select_dst run we need to reset AVPs. + * On the last ds_select_dst run we need to set destination. */ + do { + CHECK_AND_EXPAND_LIST(set_list); + ds_select_ctl.set = set_list->v.ival; + + CHECK_AND_EXPAND_LIST(alg_list); + ds_select_ctl.alg = alg_list->v.ival; + if (max_results_ptr) { + CHECK_AND_EXPAND_LIST(max_list); + ds_select_ctl.max_results = max_list->v.ival; + } + + if (run_prev_ds_select) { + LM_DBG("ds_select: %d %d %d %d %d\n", + prev_ds_select_ctl.set, prev_ds_select_ctl.alg, prev_ds_select_ctl.max_results, + prev_ds_select_ctl.reset_AVP, prev_ds_select_ctl.set_destination); + ret = ds_select_dst(msg, &prev_ds_select_ctl, ds_flags); + if (ret<0) return ret; + /* stop resetting AVPs. */ + ds_select_ctl.reset_AVP = 0; + } else { + /* Enable running ds_select_dst on next loop. */ + run_prev_ds_select = 1; + } + prev_ds_select_ctl = ds_select_ctl; + + set_list = set_list->next; + alg_list = alg_list->next; + if (max_results_ptr) { + max_list = max_list->next; + } + + TRY_FREE_EXPANDED_LIST(set_list); + TRY_FREE_EXPANDED_LIST(alg_list); + TRY_FREE_EXPANDED_LIST(max_list); + + } while (set_list && alg_list && + (max_results_ptr ? max_list : set_list)); + + if (max_results_ptr && max_list != NULL) { + LM_ERR("extra max slot(s)\n"); + goto error; } - if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0) - { - LM_ERR("no alg value\n"); - return -1; + + if (set_list != NULL) { + LM_ERR("extra set(s)\n"); + goto error; } - if(fixup_get_ivalue(msg, (gparam_p)max_results, &m)!=0) - { - LM_ERR("no max results value\n"); - return -1; + + if (alg_list != NULL) { + LM_ERR("extra algorithm(s)\n"); + goto error; } - return ds_select_dst(msg, s, a, 0 /*set dst uri*/, m); + /* last ds_select_dst run: setting destination. */ + ds_select_ctl.set_destination = 1; + LM_DBG("ds_select: %d %d %d %d %d\n", + ds_select_ctl.set, ds_select_ctl.alg, ds_select_ctl.max_results, + ds_select_ctl.reset_AVP, ds_select_ctl.set_destination); + return ds_select_dst(msg, &ds_select_ctl, ds_flags); + +error: + return -1; } /** * */ -static int w_ds_select_domain(struct sip_msg* msg, char* set, char* alg) +static int w_ds_select_all(struct sip_msg* msg, char* set, char* alg, int mode) { - int a, s; - if(msg==NULL) - return -1; - - if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0) - { - LM_ERR("no dst set value\n"); - return -1; - } - if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0) - { - LM_ERR("no alg value\n"); - return -1; - } + return w_ds_select(msg, set, alg, NULL, mode); +} - return ds_select_dst(msg, s, a, 1/*set host port*/, 1000); +/** + * max_results can also mean the flags parameter + */ +static int w_ds_select_limited(struct sip_msg* msg, char* set, char* alg, char* max_results, int mode) +{ + return w_ds_select(msg, set, alg, max_results, mode); } /** * */ -static int w_ds_select_domain_limited(struct sip_msg* msg, char* set, char* alg, char* max_results) +static int w_ds_select_dst(struct sip_msg* msg, char* set, char* alg) { - int a, s, m; - if(msg==NULL) - return -1; - - if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0) - { - LM_ERR("no dst set value\n"); - return -1; - } - if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0) - { - LM_ERR("no alg value\n"); - return -1; - } - if(fixup_get_ivalue(msg, (gparam_p)max_results, &m)!=0) - { - LM_ERR("no max results value\n"); - return -1; - } - - return ds_select_dst(msg, s, a, 1/*set host port*/, m); + return w_ds_select_all(msg, set, alg, 0); } /** - * + * same wrapper as w_ds_select_dst, but it allows cutting down the result set + * max_results can also mean flags */ -static int w_ds_next_dst(struct sip_msg *msg, char *str1, char *str2) +static int w_ds_select_dst_limited(struct sip_msg* msg, char* set, char* alg, char* max_results) { - return ds_next_dst(msg, 0/*set dst uri*/); + return w_ds_select_limited(msg, set, alg, max_results, 0); } /** * */ -static int w_ds_next_domain(struct sip_msg *msg, char *str1, char *str2) +static int w_ds_select_domain(struct sip_msg* msg, char* set, char* alg) { - return ds_next_dst(msg, 1/*set host port*/); + return w_ds_select_all(msg, set, alg, 1); } /** - * + * same wrapper as w_ds_select_domain, but it allows cutting down the result set + * max_results can also mean the flags parameter */ -static int w_ds_mark_dst0(struct sip_msg *msg, char *str1, char *str2) +static int w_ds_select_domain_limited(struct sip_msg* msg, char* set, char* alg, char* max_results) { - return ds_mark_dst(msg, 0); + return w_ds_select_limited(msg, set, alg, max_results, 1); } +#define GET_AND_CHECK_PARTITION(_param_, _part_) \ + do {\ + if (_param_ == NULL) \ + _part_ = default_partition; \ + else if (fixup_get_partition(msg, (gpartition_t *)_param_, &_part_) != 0) \ + return -1; \ + if (_part_ == NULL) { \ + LM_ERR("Unknown partition\n"); \ + return -1; \ + } \ + } while (0) + /** * */ -static int w_ds_mark_dst1(struct sip_msg *msg, char *str1, char *str2) +static int w_ds_next_dst(struct sip_msg *msg, char *part_param) { - if(str1 && (str1[0]=='i' || str1[0]=='I' || str1[0]=='0')) - return ds_mark_dst(msg, 0); - else if(str1 && (str1[0]=='p' || str1[0]=='P' || str1[0]=='2')) - return ds_mark_dst(msg, 2); - else - return ds_mark_dst(msg, 1); + ds_partition_t *partition; + + GET_AND_CHECK_PARTITION(part_param, partition); + return ds_next_dst(msg, 0, partition); } -static int in_list_fixup(void** param, int param_no) +/** + * + */ +static int w_ds_next_domain(struct sip_msg *msg, char *part_param) { - if (param_no==1) { - /* the ip to test */ - return fixup_pvar(param); - } else if (param_no==2) { - /* the port to test */ - if (*param==NULL) { - return 0; - } else if ( *((char*)*param)==0 ) { - pkg_free(*param); - *param = NULL; - return 0; - } - return fixup_pvar(param); - } else if (param_no==3) { - /* the group to check in */ - return fixup_uint(param); - } else if (param_no==4) { - /* active only check ? */ - return fixup_uint(param); - } else { - LM_CRIT("bug - too many params (%d) in is_in_list()\n",param_no); - return -1; - } + ds_partition_t *partition; + + GET_AND_CHECK_PARTITION(part_param, partition); + return ds_next_dst(msg, 1, partition); } -static int ds_count_fixup(void** param, int param_no) + +/** + * + */ +static int w_ds_mark_dst(struct sip_msg *msg, char *str1, char *str2) { - char *s; - int i, code = 0; + str arg = {NULL, 0}; + ds_partition_t *partition = default_partition; - if (param_no > 3) - return 0; + if (str2 != NULL) { + /* We have two args */ + if (str1 != NULL) + GET_AND_CHECK_PARTITION(str1, partition); - s = (char *)*param; - i = strlen(s); + if (fixup_get_svalue(msg, (gparam_p)str2, &arg) != 0) + goto error; + } + else { + if (str1 != NULL && fixup_get_svalue(msg, (gparam_p)str1, &arg) != 0) + goto error; + } - switch (param_no) - { - case 1: - return fixup_igp(param); - case 2: + if (arg.len > 1) { + LM_ERR ("unknown option %.*s\n", arg.len, arg.s); + return -1; + } - while (i--) - { - switch (s[i]) - { - /* active */ - case 'a': - case 'A': - case '1': - code |= DS_COUNT_ACTIVE; - break; - - /* inactive */ - case 'i': - case 'I': - case '0': - code |= DS_COUNT_INACTIVE; - break; - - /* probing */ - case 'p': - case 'P': - case '2': - code |= DS_COUNT_PROBING; - break; - } - } - break; + if (partition == NULL) { + LM_ERR ("unknown partition\n"); + return -1; + } - case 3: - return fixup_igp(param); + if((arg.s == NULL || arg.s[0]=='i' || arg.s[0]=='I' || arg.s[0]=='0')) + return ds_mark_dst(msg, 0, partition); + else if(arg.s && (arg.s[0]=='p' || arg.s[0]=='P' || arg.s[0]=='2')) + return ds_mark_dst(msg, 2, partition); + else if(arg.s && (arg.s[0]=='a' || arg.s[0]=='A' || arg.s[0]=='1')) + return ds_mark_dst(msg, 1, partition); + else { + LM_ERR ("unknown option %.*s\n", arg.len, arg.s); + return -1; } - s[0] = (char)code; - s[1] = '\0'; +error: + LM_ERR("wrong arguments\n"); + return -1; +} - return 0; + +static int w_ds_mark_dst1(struct sip_msg *msg, char *flags) +{ + return w_ds_mark_dst(msg, flags, NULL); } + + /************************** MI STUFF ************************/ +#define MI_ERR_RELOAD "ERROR Reloading data" +#define MI_NOT_SUPPORTED "DB mode not configured" +#define MI_UNK_PARTITION "ERROR Unknown partition" + static struct mi_root* ds_mi_set(struct mi_root* cmd_tree, void* param) { - str sp; + str sp, partition_name; int ret; unsigned int group, state; struct mi_node* node; + ds_partition_t *partition; node = cmd_tree->node.kids; if(node == NULL) @@ -689,25 +1254,42 @@ static struct mi_root* ds_mi_set(struct mi_root* cmd_tree, void* param) if(sp.len<=0 || !sp.s) { LM_ERR("bad state value\n"); - return init_mi_tree( 500, "bad state value", 15); + return init_mi_tree( 500, MI_SSTR("Bad state value") ); } - state = 1; if(sp.s[0]=='0' || sp.s[0]=='I' || sp.s[0]=='i') state = 0; + else if(sp.s[0]=='p' || sp.s[0]=='P' || sp.s[0]=='2') + state = 2; + else if(sp.s[0]=='a' || sp.s[0]=='A' || sp.s[0]=='1') + state = 1; + else + return init_mi_tree( 500, MI_SSTR("Bad state value") ); + node = node->next; if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); sp = node->value; if(sp.s == NULL) { - return init_mi_tree(500, "group not found", 15); + return init_mi_tree(500, MI_SSTR("group not found")); + } + + if (split_partition_argument(&sp, &partition_name) != 0) { + LM_ERR("bad group format\n"); + return init_mi_tree(500, MI_SSTR("bad group format")); + } + + partition = find_partition_by_name(&partition_name); + if (partition == NULL) { + LM_ERR("partition does not exist\n"); + return init_mi_tree(404, MI_SSTR(MI_UNK_PARTITION) ); } if(str2int(&sp, &group)) { LM_ERR("bad group value\n"); - return init_mi_tree( 500, "bad group value", 16); + return init_mi_tree( 500, MI_SSTR("bad group value")); } node= node->next; @@ -717,18 +1299,27 @@ static struct mi_root* ds_mi_set(struct mi_root* cmd_tree, void* param) sp = node->value; if(sp.s == NULL) { - return init_mi_tree(500,"address not found", 18 ); + return init_mi_tree(500, MI_SSTR("address not found")); } - if(state==1) - ret = ds_set_state(group, &sp, DS_INACTIVE_DST, 0); - else - ret = ds_set_state(group, &sp, DS_INACTIVE_DST, 1); + if (state==1) { + /* set active */ + ret = ds_set_state(group, &sp, DS_INACTIVE_DST|DS_PROBING_DST, + 0, partition); + } else if (state==2) { + /* set probing */ + ret = ds_set_state(group, &sp, DS_PROBING_DST, 1, partition); + if (ret==0) + ret = ds_set_state(group, &sp, DS_INACTIVE_DST, 0, partition); + } else { + /* set inactive */ + ret = ds_set_state(group, &sp, DS_INACTIVE_DST, 1, partition); + if (ret == 0) + ret = ds_set_state(group, &sp, DS_PROBING_DST, 0, partition); + } if(ret!=0) - { - return init_mi_tree(404, "destination not found", 21); - } + return init_mi_tree(404, MI_SSTR("destination not found")); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); } @@ -737,67 +1328,110 @@ static struct mi_root* ds_mi_set(struct mi_root* cmd_tree, void* param) static struct mi_root* ds_mi_list(struct mi_root* cmd_tree, void* param) { struct mi_root* rpl_tree; + struct mi_node* part_node; rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return 0; + rpl_tree->node.flags |= MI_IS_ARRAY; - if( ds_print_mi_list(&rpl_tree->node)< 0 ) - { + ds_partition_t *part_it; + for (part_it = partitions; part_it; part_it = part_it->next) { + part_node = add_mi_node_child(&rpl_tree->node, MI_IS_ARRAY, "PARTITION", + 9, part_it->name.s, part_it->name.len); + + if (part_node == NULL + || ds_print_mi_list(part_node, part_it) < 0) { LM_ERR("failed to add node\n"); free_mi_tree(rpl_tree); return 0; + } } return rpl_tree; } -#define MI_ERR_RELOAD "ERROR Reloading data" -#define MI_ERR_RELOAD_LEN (sizeof(MI_ERR_RELOAD)-1) -#define MI_NOT_SUPPORTED "DB mode not configured" -#define MI_NOT_SUPPORTED_LEN (sizeof(MI_NOT_SUPPORTED)-1) static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param) { - if (ds_load_db()<0) - return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN); - - if (populate_ds_bls()<0) { - return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN); + struct mi_node* node = cmd_tree->node.kids; + if(node != NULL){ + ds_partition_t *partition = find_partition_by_name(&node->value); + if (partition == NULL) + return init_mi_tree(500, MI_SSTR(MI_UNK_PARTITION) ); + if (ds_reload_db(partition) < 0) + return init_mi_tree(500, MI_SSTR(MI_ERR_RELOAD)); + else + return init_mi_tree(200, MI_SSTR(MI_OK_S) ); } - return init_mi_tree(200, MI_OK_S, MI_OK_LEN); -} - + ds_partition_t *part_it; + for (part_it = partitions; part_it; part_it = part_it->next) + if (ds_reload_db(part_it)<0) + return init_mi_tree(500, MI_SSTR(MI_ERR_RELOAD)); -static int w_ds_is_in_list2(struct sip_msg *msg, char *ip, char *port) -{ - return ds_is_in_list(msg, (pv_spec_t*)ip, (pv_spec_t*)port, -1, 0); + return init_mi_tree(200, MI_SSTR(MI_OK_S)); } -static int w_ds_is_in_list3(struct sip_msg *msg,char *ip,char *port,char *set) +static int w_ds_is_in_list(struct sip_msg *msg,char *ip,char *port,char *set, + char *active_only) { - return ds_is_in_list(msg,(pv_spec_t*)ip,(pv_spec_t*)port,(int)(long)set,0); -} + ds_partition_t *partition = default_partition; + int i_set = -1; + + if (set != NULL) { + ds_param_t *setparam = (ds_param_t*)set; + if (fixup_get_partition(msg, &setparam->partition, &partition) != 0) + goto wrong_set_arg; + + if (setparam->sets == NULL) + i_set = -1; + else + if (setparam->sets->type == GPARAM_TYPE_INT) { + if (setparam->sets->next == NULL) + i_set = setparam->sets->v.ival; + else { + LM_ERR("Only one set is allowed\n"); + return -1; + } + } + else { + int_list_t *tmp_lst = set_list_from_pvs(msg, setparam->sets->v.pvs, NULL); + if (tmp_lst == NULL){ + LM_ERR("Wrong set var value\n"); + return -1; + } + if (tmp_lst->next != NULL) { + LM_ERR("Only one set is allowd\n"); + return -1; + } + i_set = tmp_lst->v.ival; + free_int_list(tmp_lst, NULL); + } + } + if (partition == NULL) { + LM_ERR ("unknown partition\n"); + return -1; + } + return ds_is_in_list(msg,(pv_spec_t*)ip,(pv_spec_t*)port, i_set, + (int)(long)active_only, partition); -static int w_ds_is_in_list4(struct sip_msg *msg,char *ip,char *port,char *set, - char *active_only) -{ - return ds_is_in_list(msg,(pv_spec_t*)ip,(pv_spec_t*)port, - (int)(long)set, (int)(long)active_only); +wrong_set_arg: + LM_ERR("wrong format for set argument\n"); + return -1; } static int w_ds_count(struct sip_msg* msg, char *set, const char *cmp, char *res) { - int s = 0; + unsigned int s = 0; gparam_p ret = (gparam_p) res; + ds_partition_t *partition; - if (fixup_get_ivalue(msg, (gparam_p)set, &s)!=0) - { - LM_ERR("No dst set value\n"); + if (fixup_get_partition_set(msg, (ds_param_t*)set, &partition, &s) != 0){ + LM_ERR("wrong format for set argument. Only one set is accepted\n"); return -1; } @@ -807,14 +1441,14 @@ static int w_ds_count(struct sip_msg* msg, char *set, const char *cmp, char *res return -1; } - return ds_count(msg, s, cmp, ret->v.pvs); + return ds_count(msg, s, cmp, ret->v.pvs, partition); } int check_options_rplcode(int code) { int i; - + for (i =0; i< options_codes_no; i++) { if(options_reply_codes[i] == code) diff --git a/modules/dispatcher/doc/dispatcher.cfg b/modules/dispatcher/doc/dispatcher.cfg index 023afc655e8..d8633fcfea1 100644 --- a/modules/dispatcher/doc/dispatcher.cfg +++ b/modules/dispatcher/doc/dispatcher.cfg @@ -3,7 +3,7 @@ # sample config file for dispatcher module # -debug=9 # debug level (cmd line: -dddddddddd) +debug=9 # debug level (cmd line: -ddddddd) fork=no log_stderror=yes # (cmd line: -E) diff --git a/modules/dispatcher/doc/dispatcher.xml b/modules/dispatcher/doc/dispatcher.xml index fef76e51cf0..70381975bac 100644 --- a/modules/dispatcher/doc/dispatcher.xml +++ b/modules/dispatcher/doc/dispatcher.xml @@ -24,6 +24,11 @@ Mierla team@voice-system.ro + + Ovidiu + Sas + osas@voipembedded.com + Daniel-Constantin Mierla diff --git a/modules/dispatcher/doc/dispatcher_admin.xml b/modules/dispatcher/doc/dispatcher_admin.xml index 53c54401e71..de5d075413a 100644 --- a/modules/dispatcher/doc/dispatcher_admin.xml +++ b/modules/dispatcher/doc/dispatcher_admin.xml @@ -1,15 +1,15 @@ - + &adminguide;
Overview - This modules implements a dispatcher for destination addresses. It - computes hashes over parts of the request and selects an address from - a destination set. The selected address is then used as outbound + This modules implements a dispatcher for destination addresses. It + computes hashes over various parts of the request and selects an + address from a destination set. The selected address is then used as outbound proxy. @@ -17,10 +17,29 @@ guarantee of fair distribution. - For the distribution algotrithm, the module allows the definition of + For the distribution algorithm, the module allows the definition of weights for the destination. This is useful in order to get a different ratio of traffic between destinations. + + Since version 1.12 the dispatcher module keeps its destination sets into + different partitions. Each partition is described by its own db_url, table_name, + dst_avp, grp_avp, cnt_avp, sock_avp, attr_avp and blacklists. Setting any of this parameters + using modparam will alter the default partition's properties. In order to create + a new partition the "partition" parameter should be used (see below for more details). + If none of the 8 partition specific parameters are defined for the default partition, + then this partition will not be created. If the default partition is created each + undefined parameter from all other partitions will take the value of the corresponding + one from the default partition. If there is no default partition, the default value + specified in the parameter's description will be used. Functions taking set arguments + will now take a set number preceded by a partition name and colon(i.e "part_name: 5"). + If a set is not preceded by any partition name the default partition will be used. + Thus, the following arguments are equivalent: "default : 4" vs "4". + Remember that in order to be able to use a table from a partition, its name must be + found in the "version" table belonging to the database defined in the partition's db_url. + Also, in version 1.12 the "flags" parameter has been moved to to ds_select_dst and + ds_select_domain along with "force_dst" and "use_default" flags. +
Dependencies @@ -59,106 +78,37 @@ <varname>db_url</varname> (string) Database where to load the destinations from. + Setting this parameter will only change the default partition's + db_url. Use the partition parameter to create and alter + other partitions. - Default value is NULL (use default DB URL from core). - - - - Set <quote>db_url</quote> parameter - -... -modparam("dispatcher", "db_url", "mysql://user:passwb@localhost/database") -... - - -
- -
- <varname>flags</varname> (int) - - Various flags that affect dispatcher's behaviour. The flags are defined - as a bitmask on an integer value. - If flag 1 is set only the username - part of the uri will be used when computing an uri based hash. - If no flags are set the username, hostname and port will be used - The port is used only if different from 5060 (normal sip uri) or 5061 - (in the sips case). - - - If flag 2 is set, then the failover support is enabled. The functions - exported by the module will store the rest of addresses from the - destination set in AVP, and use these AVPs to contact next address when - the current-tried fails. - - - - Default value is 0. - - - - Set the <quote>flags</quote> parameter - - ... - modparam("dispatcher", "flags", 3) - ... - - -
- -
- <varname>force_dst</varname> (int) - - If set to 1, force overwriting of destination address when that is - already set. - - - - Default value is 0. + Default value is NULL. At least one db_url should + be defined for the dispatcher module to work. - Set the <quote>force_dst</quote> parameter + Set the 'default' partition's<quote>db_url</quote> parameter ... -modparam("dispatcher", "force_dst", 1) +modparam("dispatcher", "db_url", "mysql://user:passwb@localhost/database") ...
-
- <varname>use_default</varname> (int) - - If the parameter is set to 1, the last address in destination set - is used as last option to send the message. For example, it is good - when wanting to send the call to an anouncement server saying: - "the gateways are full, try later". - - - - Default value is 0. - - - - Set the <quote>use_default</quote> parameter - - ... - modparam("dispatcher", "use_default", 1) - ... - - -
-
<varname>attrs_avp</varname> (str) The name of the avp to contain the attributes string of the current destination. When a destination is selected, automatically, this AVP - will provide the attributes string - this is an opaque string (from + will provide the attributes string - this is an opaque string (from OpenSIPS point of view) : it is loaded from destination definition ( via DB) and blindly provided in the script. + Setting this parameter will only change the default partition's + attrs_avp. Use the partition parameter to create and alter + other partitions. @@ -168,12 +118,12 @@ modparam("dispatcher", "force_dst", 1) - Set the <quote>attrs_avp</quote> parameter - - ... - modparam("dispatcher", "attrs_avp", "$avp(272)") - ... - + Set the 'default' partition's <quote>attrs_avp</quote> parameter + +... +modparam("dispatcher", "attrs_avp", "$avp(272)") +... +
@@ -225,19 +175,19 @@ modparam("dispatcher", "hash_pvar", "hash the $fU@$ci")
Set the <quote>setid_pvar</quote> parameter - - ... - modparam("dispatcher", "setid_pvar", "$var(setid)") - ... - + +... +modparam("dispatcher", "setid_pvar", "$var(setid)") +... +
<varname>ds_ping_method</varname> (string) - With this Method you can define, with which method you want to probe - the failed gateways. This method is only available, if compiled with + With this Method you can define, with which method you want to probe + the failed gateways. This method is only available, if compiled with the probing of failed gateways enabled. @@ -258,8 +208,8 @@ modparam("dispatcher", "ds_ping_method", "INFO")
<varname>ds_ping_from</varname> (string) - With this Method you can define the "From:"-Line for the request, - sent to the failed gateways. This method is only available, if + With this Method you can define the "From:"-Line for the request, + sent to the failed gateways. This method is only available, if compiled with the probing of failed gateways enabled. @@ -275,14 +225,14 @@ modparam("dispatcher", "ds_ping_from", "sip:proxy@sip.somehost.com") ... -
+
<varname>ds_ping_interval</varname> (int) - With this Method you can define the interval for sending a request to - a failed gateway. This parameter is only used, when the TM-Module is - loaded. If set to 0, the pinging of failed requests + With this Method you can define the interval for sending a request to + a failed gateway. This parameter is only used, when the TM-Module is + loaded. If set to 0, the pinging of failed requests is disabled. @@ -298,13 +248,13 @@ modparam("dispatcher", "ds_ping_interval", 30) ... -
+
<varname>ds_probing_sock</varname> (str) A socket description [proto:]host[:port] of the local socket (which - is used by OpenSIPS for SIP traffic) to be used (if multiple) for + is used by OpenSIPS for SIP traffic) to be used (if multiple) for sending the probing messages from. @@ -320,13 +270,13 @@ modparam("dispatcher", "ds_probing_sock", "udp:192.168.1.100:5077") ... -
+
<varname>ds_probing_threshhold</varname> (int) - If you want to set a gateway into probing mode, you will need a - specific number of requests until it will change from "active" to + If you want to set a gateway into probing mode, you will need a + specific number of requests until it will change from "active" to probing. The number of attempts can be set with this parameter. @@ -370,9 +320,12 @@ modparam("dispatcher", "ds_probing_mode", 1)
<varname>ds_define_blacklist</varname> (str) - Defines a blacklist based on a dispatching setid. + Defines a blacklist based on a dispatching setid from the 'default' + partition. This list will contain the IPs (no port, all protocols) of the destinations matching the given setid. + Use the 'partition' parameter if you want to define blacklists + based on other partitions' sets. Multiple instances of this param are allowed. @@ -383,7 +336,8 @@ modparam("dispatcher", "ds_probing_mode", 1) - Set the <quote>ds_define_blacklist</quote> parameter + Set the 'default' partition's <quote>ds_define_blacklist</quote> + parameter ... modparam("dispatcher", "ds_define_blacklist", "list= 1,4,3") @@ -396,8 +350,8 @@ modparam("dispatcher", "ds_define_blacklist", "blist2= 2,10,6")
<varname>options_reply_codes</varname> (str) - This parameter must contain a list of SIP reply codes separated by - comma. The codes defined here will be considered as valid reply codes + This parameter must contain a list of SIP reply codes separated by + comma. The codes defined here will be considered as valid reply codes for OPTIONS messages used for pinging, apart for 200. @@ -418,43 +372,53 @@ modparam("dispatcher", "options_reply_codes", "501, 403")
<varname>dst_avp</varname> (str) - This is mainly for internal usage and represents the name of the avp + This is mainly for internal usage and represents the name of the avp which will hold the list with addresses, in the order they have been selected by the chosen algorithm. If use_default is 1, the value of last dst_avp_id is the last address in destination set. The first dst_avp_id is the selected destinations. All the other addresses from the destination set will be added in the avp list to be able to implement serial forking. + Setting this parameter will only change the default partition's + dst_avp. Use the partition parameter to create and alter + other partitions. - Default value is $avp(ds_dst_failover) + For the 'default' partition the default value + is $avp(ds_dst_failover). For any other partition, + the default value is $avp(ds_dst_failover_partitionname). - Set the <quote>dst_avp</quote> parameter - - ... - modparam("dispatcher", "dst_avp", "$avp(271)") - ... - + Set the 'default' partition's <quote>dst_avp</quote> parameter + +... +modparam("dispatcher", "dst_avp", "$avp(271)") +... +
<varname>grp_avp</varname> (str) - This is mainly for internal usage and represents the name of the avp + This is mainly for internal usage and represents the name of the avp storing the group id of the destination set. Good to have it for later usage or checks. + Setting this parameter will only change the default partition's + grp_avp. Use the partition parameter to create and alter + other partitions. - Default value is $avp(ds_grp_failover). + For the 'default' partition the default value + is $avp(ds_grp_failover). For any other partition, + the default value is $avp(ds_grp_failover_partitionname). - Set the <quote>grp_avp</quote> parameter + Set the 'default' partition's <quote>grp_avp</quote> parameter ... modparam("dispatcher", "grp_avp", "$avp(273)") @@ -466,16 +430,21 @@ modparam("dispatcher", "grp_avp", "$avp(273)")
<varname>cnt_avp</varname> (str) - This is mainly for internal usage and represents the name of the avp + This is mainly for internal usage and represents the name of the avp storing the number of destination addresses kept in dst_avp avps. + Setting this parameter will only change the default partition's + cnt_avp. Use the partition parameter to create and alter + other partitions. - Default value is $avp(ds_cnt_failover). + For the 'default' partition the default value + is $avp(ds_cnt_failover). For any other partition, + the default value is $avp(ds_cnt_failover_partitionname). - Set the <quote>cnt_avp</quote> parameter + Set the 'default' partition's <quote>cnt_avp</quote> parameter ... modparam("dispatcher", "cnt_avp", "$avp(274)") @@ -487,17 +456,22 @@ modparam("dispatcher", "cnt_avp", "$avp(274)")
<varname>sock_avp</varname> (str) - This is mainly for internal usage and represents the name of the avp + This is mainly for internal usage and represents the name of the avp storing the sockets to be used for the destination addresses kept in dst_avp avps. + Setting this parameter will only change the default partition's + sock_avp. Use the partition parameter to create and alter + other partitions. - Default value is $avp(ds_sock_failover). + For the 'default' partition the default value + is $avp(ds_sock_failover). For any other partition, + the default value is $avp(ds_sock_failover_partitionname). - Set the <quote>sock_avp</quote> parameter + Set the 'default' partition's <quote>sock_avp</quote> parameter ... modparam("dispatcher", "sock_avp", "$avp(275)") @@ -526,7 +500,7 @@ modparam("dispatcher", "sock_avp", "$avp(275)") Set the <quote>pvar_algo_pattern</quote> parameter ... -modparam("dispatcher", "sock_avp", "$stat(load_%u)") +modparam("dispatcher", "pvar_algo_pattern", "$stat(load_%u)") ... @@ -538,15 +512,18 @@ modparam("dispatcher", "sock_avp", "$stat(load_%u)") If you want to load the sets of gateways from the database you must set this parameter as the database name. + Setting this parameter will only change the default partition's + table_name. Use the partition parameter to create and alter + other partitions. - Default value is dispatcher. + For every partition the default value is dispatcher. - Set <quote>table_name</quote> parameter - + Set the 'default' partition's <quote>table_name</quote> parameter + ... modparam("dispatcher", "table_name", "my_dispatcher") ... @@ -554,6 +531,32 @@ modparam("dispatcher", "table_name", "my_dispatcher")
+ +
+ <varname>partition</varname> (string) + + Using this parameter the partition specific parameters (db_url, table_name, dst_avp, + grp_avp, cnt_avp, sock_avp, attrs_avp, ds_define_blacklist) can be defined. + + + The syntax is: "partition_name: param1 = value1; param2 = value2; param3 = value3". + Each value format is the same as the one used to define a specific parameter using modparam. + + + Whenever a new partition_name is provided, a new partition will be automatically created. + The 'default' partition can also be defined using this parameter. + + + Create a new partition called 'part2' + +... +modparam("dispatcher", "partition", "part2 : db_url=mysql://user:passwd@localhost/database; table_name = ds_table; ds_define_blacklist= list2= 4,6;") +... + + +
+ +
<varname>setid_col</varname> (string) @@ -566,7 +569,7 @@ modparam("dispatcher", "table_name", "my_dispatcher") Set <quote>setid_col</quote> parameter - + ... modparam("dispatcher", "setid_col", "groupid") ... @@ -587,7 +590,7 @@ modparam("dispatcher", "setid_col", "groupid") Set <quote>destination_col</quote> parameter - + ... modparam("dispatcher", "destination_col", "uri") ... @@ -596,21 +599,21 @@ modparam("dispatcher", "destination_col", "uri")
- <varname>flags_col</varname> (string) + <varname>state_col</varname> (string) - The column's name in the database storing the flags for + The column's name in the database storing the state of the destination uri. - Default value is flags. + Default value is state. - Set <quote>flags_col</quote> parameter - + Set <quote>state_col</quote> parameter + ... -modparam("dispatcher", "flags_col", "dstflags") +modparam("dispatcher", "state_col", "dststate") ... @@ -629,7 +632,7 @@ modparam("dispatcher", "flags_col", "dstflags") Set <quote>weight_col</quote> parameter - + ... modparam("dispatcher", "weight_col", "dstweight") ... @@ -650,7 +653,7 @@ modparam("dispatcher", "weight_col", "dstweight") Set <quote>attrs_col</quote> parameter - + ... modparam("dispatcher", "attrs_col", "dstattrs") ... @@ -661,7 +664,7 @@ modparam("dispatcher", "attrs_col", "dstattrs")
<varname>socket_col</varname> (string) - The column's name in the database storing the socket (as + The column's name in the database storing the socket (as string) for destination uri. @@ -671,7 +674,7 @@ modparam("dispatcher", "attrs_col", "dstattrs") Set <quote>socket_col</quote> parameter - + ... modparam("dispatcher", "socket_col", "my_sock") ... @@ -688,23 +691,26 @@ modparam("dispatcher", "socket_col", "my_sock") Exported Functions
- <function moreinfo="none">ds_select_dst(set, alg [, max_results])</function> + <function moreinfo="none">ds_select_dst(set, alg [, "[flags] [M max_results]"])</function> - The method selects a destination from addresses set. + The method selects a destination from the given set of addresses. It will + overwrite the "destination URI" of a SIP request ($du). Meaning of the parameters is as follows: - set - the id of the set from where to pick - up destination address. + set - a partition name followed by colon and an + id of the set or a list of sets + from where to pick up destination address (variables are accepted). + If the partition name is missing, the default partition will be used. - alg - the algorithm used to select the - destination address. + alg - the algorithm(s) used to select the + destination address (variables are accepted). @@ -734,7 +740,9 @@ modparam("dispatcher", "socket_col", "my_sock") - 5 - hash over authorization-username (Proxy-Authorization or "normal" authorization). If no username is found, round robin is used. + 5 - hash over authorization-username + (Proxy-Authorization or "normal" authorization). + If no username is found, round robin is used. @@ -756,12 +764,12 @@ modparam("dispatcher", "socket_col", "my_sock") 9 - The pvar_algo_pattern - parameter is used to determine the load on each server. If the + parameter is used to determine the load on each server. If the parameter is not specified, then the first entry in the set is chosen. - + X - if the algorithm is not implemented, the @@ -772,36 +780,63 @@ modparam("dispatcher", "socket_col", "my_sock") - max_results - If specified, only that many results + flags - If specified, this will be the flags which + in previous versions were specified at startup. The flags are the failover + support flag('f'/'F') letters, the user only flag('u'/'U') and will specify + that only the uri user part will be used for hashing, the force destination + flag('S'/'s') which will Skip overwriting the destination address if it is + already set and the use default flag('D', 'd') which will use the last address + in destination set as last option to send the message.You can also specify + these flags using PVs. The flags are being kept per partition. + + + + + max_results - If specified, only that many results will be put into the specified avp for failover. This allows having many destinations but limit the useless traffic in case of a number that is - bound to fail everywhere. + bound to fail everywhere. It can accept variables. The definition must + begin with 'M' character either you use static definition or PVs. - If the bit 2 in 'flags' is set, the rest of the addresses from the + If the character 'f' in 'flags' is set, the rest of the addresses from the destination set is stored in AVP list. You can use 'ds_next_dst()' to use next address to achieve serial forking to all possible - destinations. + destinations. If multiple dispatching groups are used, the AVP list + is constructed based on the position of each dispatching id in the list: + first one has the higher priority, followed by the second one and so on. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. <function>ds_select_dst</function> usage - + ... ds_select_dst("1", "0"); ... -ds_select_dst("1", "0", "5"); +ds_select_dst("part2 : 1", "0", "M 5"); +... +ds_select_dst("part3 : 1", "0", "fUsD"); +... +ds_select_dst("part4 : 2", "0", "fuD M 5,2"); +... +# dispatch over multiple dispatching groups +$var(partition_name) = "p4" +$var(setid) = "1, 2"; +$var(alg) = "4, 2"; +$var(max) = "2,3"; +$var(flags) = " sFDU"; +ds_select_dst("$var(partition_name):$var(setid)", "$var(alg)", "$var(flags) M $var(max)"); ...
- <function moreinfo="none">ds_select_domain(set, alg [, max_results])</function> + <function moreinfo="none">ds_select_domain(set, alg [, "[flags] [M max_results]"])</function> The method selects a destination from addresses set and rewrites the @@ -809,7 +844,7 @@ ds_select_dst("1", "0", "5"); ds_select_dst(). - If the bit 2 in 'flags' is set, the rest of the addresses from the + If the character 'f' in 'flags' is set, the rest of the addresses from the destination set is stored in AVP list. You can use 'ds_next_domain()' to use next address to achieve serial forking to all possible destinations. @@ -820,11 +855,13 @@ ds_select_dst("1", "0", "5");
- <function moreinfo="none">ds_next_dst()</function> + <function moreinfo="none">ds_next_dst([partition_name])</function> - Takes the next destination address from the AVPs with id 'dst_avp_id' - and sets the dst_uri (outbound proxy address). + Takes the next destination address from the AVPs with id + partition.'dst_avp_id' and sets the dst_uri (outbound proxy address). + If partition_name is omitted, the default partition will be used.This + function is using the flags set in ds_select_dst or ds_select_domain. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. @@ -832,11 +869,13 @@ ds_select_dst("1", "0", "5");
- <function moreinfo="none">ds_next_domain()</function> + <function moreinfo="none">ds_next_domain([partition_name])</function> - Takes the next destination address from the AVPs with id 'dst_avp_id' - and sets the domain part of the request uri. + Takes the next destination address from the AVPs with id + partition.'dst_avp_id' and sets the domain part of the request uri. + If partition_name is omitted, the default partition will be used.This + function is using the flags set in ds_select_dst or ds_select_domain. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. @@ -847,10 +886,12 @@ ds_select_dst("1", "0", "5"); ds_mark_dst() - Mark the last used address from destination set as inactive, in order - to be ingnored in the future. In this way it can be implemented an - automatic detection of failed gateways. When an address is marked as - inactive, it will be ignored by 'ds_select_dst' and 'ds_select_domain'. + Mark the last used address from the 'default' partition's destination + set as inactive, in order to be ignored in the future. In this way it + can be implemented an automatic detection of failed gateways. + When an address is marked as inactive, it will be ignored by + 'ds_select_dst' and 'ds_select_domain'. This function is using the flags + set in ds_select_dst or ds_select_domain. This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. @@ -858,12 +899,16 @@ ds_select_dst("1", "0", "5");
- <function moreinfo="none">ds_mark_dst("s")</function> + <function moreinfo="none">ds_mark_dst([partition_name], "s")</function> - Mark the last used address from destination set as inactive ("i"/"I"/"0"), active ("a"/"A"/"1") or probing ("p"/"P"/"2"). - With this function, an automatic detection of failed gateways can be implemented. When an address is marked as - inactive or probing, it will be ignored by 'ds_select_dst' and 'ds_select_domain'. + Mark the last used address from partition's destination set as + inactive ("i"/"I"/"0"), active ("a"/"A"/"1") or probing ("p"/"P"/"2"). + With this function, an automatic detection of failed gateways can be implemented. + When an address is marked as inactive or probing, it will be ignored by + 'ds_select_dst' and 'ds_select_domain'. + If partition_name is omitted, the default partition will be used. This function + is using the flags set in ds_select_dst or ds_select_domain. possible parameters: @@ -874,7 +919,7 @@ ds_select_dst("1", "0", "5"); "a", "A" or "1" - the last destination should be set to active. - "p", "P" or "2" - the last destination will be set to probing. Note: You will need to call this function "threshhold"-times, before it will be actually set to probing. + "p", "P" or "2" - the last destination will be set to probing. Note: You will need to call this function "threshold"-times, before it will be actually set to probing. @@ -886,26 +931,17 @@ ds_select_dst("1", "0", "5"); ds_count(set, filter, result) - Returns the number of active, inactive or probing destinations in a set, - or combinations between these properties. + Returns the number of active, inactive or probing destinations in a + partition's set, or combinations between these properties. Meaning of the parameters: - set - a set of dispatching destinations. - The set parameter can have the following types: + + set - a partition name followed by colon and an + id of a set of dispatching destinations (variables are accepted). + If the partition name is missing, the default partition will be used. - - - integer - the dispatching set is passed - in a static manner - - - - pvar - the dispatching set is the value - of an existing pseudo-variable (as integer value) - - @@ -934,13 +970,13 @@ ds_select_dst("1", "0", "5"); <function>ds_count</function> usage - + ... if (ds_count("1", "a", "$avp(result)")) { ... } ... -if (ds_count("$avp(set)", "ip", "$avp(result)")) { +if (ds_count("$avp(partition) : $avp(set)", "ip", "$avp(result)")) { ... } ... @@ -953,7 +989,7 @@ if (ds_count("$avp(set)", "ip", "$avp(result)")) { ds_is_in_list(ip, port [,set [,active_only]]) - This function returns true, if the parameters ip and port point to a + This function returns true, if the parameters ip and port point to a host from the dispatcher-list; otherwise false. @@ -961,41 +997,48 @@ if (ds_count("$avp(set)", "ip", "$avp(result)")) { - ip - a PV (pseudo-variable) containing + ip - a PV (pseudo-variable) containing (as string) the IP to test against the dispatcher list. This cannot be empty. port - a PV (pseudo-variable) containing - (as integer) the PORT to test against the dispatcher list. This - can be empty - in this case the port will excluded from the + (as integer) the PORT to test against the dispatcher list. This + can be empty - in this case the port will excluded from the matching of IP against the dispatcher list. - set (optional) - the set ID of a - dispatcher list to test agaist - if missing, all the dispatching - sets will the checked. + set (optional) - a partition name followed + by colon and the set ID of a dispatcher list to test against. + If the partition name is omitted the default partition will be used. + If the set id is missing, all the dispatching + sets will the checked. If a partition name is specified then it must + be followed by colon regardless of the set id being specified or not. - active_only (optional) - search only - through the active destinations (ignore the ones in probing + active_only (optional) - search only + through the active destinations (ignore the ones in probing and inactive mode). - This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE and ONREPLY_ROUTE. <function>ds_is_in_list</function> usage - + ... if (ds_is_in_list("$si", "$sp")) { # source IP:PORT is in a dispatcher list } ... if (ds_is_in_list("$rd", "$rp", "2")) { - # source RURI (ip and port) is in the dispatcher list id "2" + # source RURI (ip and port) is in the dispatcher list id "2" of the default partition +} +... +if (ds_is_in_list("$rd", "$rp", "part2:2")) { + # source RURI (ip and port) is in the dispatcher list id "2" of the partition called 'part2' } ... @@ -1011,7 +1054,7 @@ if (ds_is_in_list("$rd", "$rp", "2")) { ds_set_state - Sets the status for a destination address (can be use to mark the destination + Sets the status for a destination address (can be use to mark the destination as active or inactive). @@ -1020,34 +1063,36 @@ if (ds_is_in_list("$rd", "$rp", "2")) { Parameters: _state_ : state of the destination address - - a: active - i: inactive - p: probing - - + + a: active + i: inactive + p: probing + + + + _group_: partition name followed by colon + and destination group id. If the partition name is omitted, + the default partition will be used - _group_: destination group id - _address_: address of the destination in the _group_ MI FIFO Command Format: - - :ds_set_state:_reply_fifo_file_ - _state_ - _group_ - _address_ - _empty_line_ - -
+ +:ds_set_state:_reply_fifo_file_ +_state_ +_group_ +_address_ +_empty_line_ + +
<function moreinfo="none">ds_list</function> - It lists the groups and included destinations. + It lists the groups and included destinations of all the partitions. Name: ds_list @@ -1056,17 +1101,17 @@ if (ds_is_in_list("$rd", "$rp", "2")) { MI FIFO Command Format: - - :ds_list:_reply_fifo_file_ - _empty_line_ - -
+ +:ds_list:_reply_fifo_file_ +_empty_line_ + +
<function moreinfo="none">ds_reload</function> - It reloads the groups and included destinations. + It reloads the groups and included destinations for all partitions. Name: ds_reload @@ -1075,13 +1120,13 @@ if (ds_is_in_list("$rd", "$rp", "2")) { MI DATAGRAM Command Format: - - ":ds_reload:\n." - -
+ +":ds_reload:\n." + +
+ +
-
-
Exported Events
@@ -1089,11 +1134,14 @@ if (ds_is_in_list("$rd", "$rp", "2")) { E_DISPATCHER_STATUS - This event is raised when the dispatcher module marks a destination as + This event is raised when the dispatcher module marks a destination as activated or deactivated. Parameters: + + partition - the partition name of the destination. + group - the group of the destination. @@ -1119,11 +1167,11 @@ if (ds_is_in_list("$rd", "$rp", "2")) { &osips; config script - sample dispatcher usage - + ... &dispatchercfg; ... - +
diff --git a/modules/dispatcher/doc/dispatcher_faq.xml b/modules/dispatcher/doc/dispatcher_faq.xml index 7570e94aec9..78bbf847f63 100644 --- a/modules/dispatcher/doc/dispatcher_faq.xml +++ b/modules/dispatcher/doc/dispatcher_faq.xml @@ -1,7 +1,7 @@ - + &faqguide; @@ -35,13 +35,13 @@ - What happend with the ds_is_from_list() + What happened with the ds_is_from_list() function? - The function was replaced by the more generic - ds_is_in_list() function that takes as + The function was replaced by the more generic + ds_is_in_list() function that takes as parameters the IP and PORT to test against the dispatcher list. @@ -52,7 +52,7 @@ - What happend with the list_file + What happened with the list_file module parameter ? @@ -82,7 +82,7 @@ First at all check if your question was already answered on one of - our mailing lists: + our mailing lists: @@ -93,8 +93,8 @@ - E-mails regarding any stable version should be sent to - &osipsusersmail; and e-mail regarding development versions or SVN + E-mails regarding any stable version should be sent to + &osipsusersmail; and e-mail regarding development versions or SVN snapshots should be send to &osipsdevmail;. diff --git a/modules/dispatcher/ds_bl.c b/modules/dispatcher/ds_bl.c index f50a5050b9e..008694bb89f 100644 --- a/modules/dispatcher/ds_bl.c +++ b/modules/dispatcher/ds_bl.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -34,55 +34,61 @@ #include "../../trim.h" #include "../../ip_addr.h" -#include "dispatch.h" #include "ds_bl.h" static struct ds_bl *dsbl_lists = NULL; -static char **blacklists = NULL; -static unsigned int bl_size = 0; +static ds_bl_temp_t *blacklists = NULL; int set_ds_bl(modparam_t type, void *val) { - blacklists = pkg_realloc( blacklists, (bl_size+1) * sizeof(*blacklists)); - if (blacklists == NULL) { - LM_ERR("REALLOC failed.\n"); + static const str default_part_name = str_init(DS_DEFAULT_PARTITION_NAME); + return set_ds_bl_partition((char*)val, default_part_name); +} + +int set_ds_bl_partition(char *val, str partition_name) +{ + ds_bl_temp_t *new_bl = pkg_malloc(sizeof (ds_bl_temp_t)); + + if (new_bl == NULL) { + LM_ERR ("no more private memory\n"); return -1; } - blacklists[bl_size] = (char*)val; - bl_size++; - + new_bl->text = val; + new_bl->partition_name = partition_name; + new_bl->next = blacklists; + blacklists = new_bl; return 0; } int init_ds_bls(void) { - unsigned int i; struct ds_bl *dsbl; str name; str val; char *p; + ds_bl_temp_t *bs_it = blacklists, *aux; LM_DBG("Initialising ds blacklists\n"); if (blacklists == NULL) return 0; - for(i = 0; i < bl_size; i++ ) { - LM_DBG("processing bl definition <%s>\n", blacklists[i]); + while (bs_it) { + LM_DBG("processing bl definition <%s>\n", bs_it->text); /* get name */ - p = strchr( blacklists[i], '='); - if (p==NULL || p==blacklists[i]) { - LM_ERR("blacklist definition <%s> has no name", blacklists[i]); + p = strchr( bs_it->text, '='); + if (p==NULL || p==bs_it->text) { + LM_ERR("blacklist definition <%s> has no name", bs_it->text); return -1; } - name.s = blacklists[i]; + name.s = bs_it->text; name.len = p - name.s; trim(&name); if (name.len == 0) { - LM_ERR("empty name in blacklist definition <%s>\n", blacklists[i]); + LM_ERR("empty name in blacklist definition <%s>\n", bs_it->text); return -1; } LM_DBG("found list name <%.*s>\n", name.len, name.s); @@ -93,11 +99,12 @@ int init_ds_bls(void) return -1; } memset(dsbl, 0, sizeof(*dsbl)); + dsbl->partition_name = bs_it->partition_name; /* fill in the types */ p++; do { if (dsbl->no_sets == DS_BL_MAX_SETS) { - LM_ERR("too many types per rule <%s>\n", blacklists[i]); + LM_ERR("too many types per rule <%s>\n", bs_it->text); shm_free(dsbl); return -1; } @@ -111,7 +118,7 @@ int init_ds_bls(void) } trim(&val); if (val.len == 0) { - LM_ERR("invalid types listing in <%s>\n", blacklists[i]); + LM_ERR("invalid types listing in <%s>\n", bs_it->text); shm_free(dsbl); return -1; } @@ -124,9 +131,6 @@ int init_ds_bls(void) dsbl->no_sets++; } while(p != NULL); - pkg_free(blacklists[i]); - blacklists[i] = NULL; - /* create backlist for it */ dsbl->bl = create_bl_head( 313131, 0/*flags*/, NULL, NULL, &name); if (dsbl->bl == NULL) { @@ -135,12 +139,15 @@ int init_ds_bls(void) return -1; } + aux = bs_it; + bs_it = bs_it->next; + pkg_free(aux); + /* link it */ dsbl->next = dsbl_lists; dsbl_lists = dsbl; } - pkg_free(blacklists); blacklists = NULL; return 0; @@ -158,7 +165,7 @@ void destroy_ds_bls(void) } -int populate_ds_bls(void) +int populate_ds_bls(ds_set_t *sets, str partition_name) { unsigned int i,k; struct ds_bl *dsbl; @@ -169,14 +176,17 @@ int populate_ds_bls(void) struct net *set_net; LM_DBG("Updating ds blacklists...\n"); + //TODO this could be done better /* each bl list at a time */ for(dsbl = dsbl_lists; dsbl; dsbl = dsbl->next) { + if (str_strcmp(&partition_name, &dsbl->partition_name) != 0) + continue; dsbl_first = dsbl_last = NULL; /* each blacklisted set at a time */ for (i = 0; i < dsbl->no_sets; i++) { /* search if any set matches the one above */ - for(set = ds_lists[*crt_idx]; set ;set = set->next) { + for( set=sets ; set ; set = set->next) { if (set->id == dsbl->sets[i]) { LM_DBG("Set [%d] matches. Adding all destinations:\n", set->id); for (dst = set->dlist; dst; dst = dst->next) { @@ -206,7 +216,10 @@ int populate_ds_bls(void) /* the new content for the BL */ if (dsbl->bl && add_list_to_head( dsbl->bl, dsbl_first, dsbl_last, 1, 0) != 0) { - LM_ERR("UPDATE blacklist failed.\n"); + LM_ERR("UPDATE blacklist failed for list <%.*s> in partition <%.*s>." + " Possibly, none of the sets in this list exists\n", + dsbl->bl->name.len, dsbl->bl->name.s, partition_name.len, + partition_name.s); return -1; } } diff --git a/modules/dispatcher/ds_bl.h b/modules/dispatcher/ds_bl.h index bd45c77c101..ba06849feb8 100644 --- a/modules/dispatcher/ds_bl.h +++ b/modules/dispatcher/ds_bl.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -29,22 +29,32 @@ #define _DS_BL_H_ #include "../../blacklists.h" +#include "dispatch.h" #define DS_BL_MAX_SETS 32 +typedef struct _ds_bl_temp { + char *text; + str partition_name; + struct _ds_bl_temp *next; +} ds_bl_temp_t; + struct ds_bl { unsigned int no_sets; unsigned int sets[DS_BL_MAX_SETS]; + + str partition_name; struct bl_head *bl; struct ds_bl *next; }; int set_ds_bl(modparam_t type, void *val); +int set_ds_bl_partition(char *val, str partition_name); int init_ds_bls(void); void destroy_ds_bls(void); -int populate_ds_bls(void); +int populate_ds_bls(ds_set_t *sets, str partition_name); #endif /* _DS_BL_H_ */ diff --git a/modules/dispatcher/ds_fixups.c b/modules/dispatcher/ds_fixups.c new file mode 100644 index 00000000000..5549e85435d --- /dev/null +++ b/modules/dispatcher/ds_fixups.c @@ -0,0 +1,760 @@ +/** + * + * dispatcher module fixup functions + * + * Copyright (C) 2004-2005 FhG Fokus + * Copyright (C) 2006-2010 Voice Sistem SRL + * Copyright (C) 2014 OpenSIPS Foundation + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History + * ------- + * 2014-07-08 initial version (Andrei Datcu) +*/ + + +#include "ds_fixups.h" +#include "../../ut.h" + +#define LIST_DELIM ',' + +extern ds_partition_t *default_partition; +extern ds_partition_t *partitions; + +/* + * Expand a pvar into a list of ints +*/ + +int_list_t *set_list_from_pvs(struct sip_msg *msg, pv_spec_t *pvs, int_list_t *end) +{ + int_list_t *result = end, *new_el; + pv_value_t value; + + if (pv_get_spec_value(msg, pvs, &value) != 0 || value.flags&PV_VAL_NULL + || (!(value.flags&PV_VAL_INT) && !(value.flags&PV_VAL_STR))) { + + LM_ERR("no valid PV value found (error in scripts)\n"); + return NULL; + } + + if (value.flags & PV_VAL_INT) { + /* Just one element */ + + new_el = pkg_malloc(sizeof(int_list_t)); + if (new_el == NULL) { + LM_ERR("no more shared memory\n"); + return NULL; + } + + new_el->v.ival = value.ri; + new_el->type = GPARAM_TYPE_INT; + new_el->next = end; + + return new_el; + } + + str sval = value.rs; + + if (sval.s == NULL) + goto wrong_value; + + char * delim; + do{ + delim = q_memchr(sval.s, LIST_DELIM, sval.len); + str s_num = {sval.s, delim ? delim - sval.s : sval.len}; + sval.len -= s_num.len + 1; + sval.s = delim + 1; + str_trim_spaces_lr(s_num); + + unsigned int u_num; + if (s_num.len == 0 || str2int(&s_num, &u_num) != 0) + goto wrong_value; + + new_el = pkg_malloc(sizeof(int_list_t)); + if (new_el == NULL) { + goto no_memory; + } + + new_el->v.ival = u_num; + new_el->type = GPARAM_TYPE_INT; + new_el->next = result; + result = new_el; + + } while (delim); + + if (sval.len > 0) + goto wrong_value; + +return result; + +no_memory: + while(result != end) { + if (result->type == GPARAM_TYPE_PVS) + pkg_free(result->v.pvs); + int_list_t *aux = result; + result = result->next; + pkg_free(aux); + } + LM_ERR("no more private memory\n"); + return NULL; + +wrong_value: + while(result != end) { + if (result->type == GPARAM_TYPE_PVS) + pkg_free(result->v.pvs); + int_list_t *aux = result; + result = result->next; + pkg_free(aux); + } + LM_ERR("wrong var value <%.*s>\n", value.rs.len, value.rs.s); + return NULL; + +} + +/* + * Create an int list from a string. Eg ("1, 2, 4") +*/ + +static int set_list_from_string(str input, int_list_t **result) +{ + str original_input = input; + int_list_t *new_el; + unsigned int uset; + + *result = NULL; + if (input.s == NULL || input.len == 0) + return 0; + + if (str2int(&input, &uset) == 0) { + /* Just one set in the list */ + *result = shm_malloc(sizeof(int_list_t)); + if (*result == NULL) + goto no_memory; + (*result)->v.ival = uset; + (*result)->type = GPARAM_TYPE_INT; + (*result)->next = NULL; + return 0; + } + + char * delim, *pvdelim; + unsigned int u_num; + do{ + delim = q_memchr(input.s, LIST_DELIM, input.len); + str s_tok = {input.s, delim ? delim - input.s : input.len}; + int full_tok_len = s_tok.len; + + str_trim_spaces_lr(s_tok); + if (s_tok.len == 0) + goto wrong_value; + else if (s_tok.s[0] == PV_MARKER) { + new_el = shm_malloc(sizeof(int_list_t)); + if (new_el == NULL) + goto no_memory; + + new_el->type = GPARAM_TYPE_PVS; + new_el->v.pvs = shm_malloc(sizeof(pv_spec_t)); + if (new_el->v.pvs == NULL) { + shm_free(new_el); + goto no_memory; + } + + if ((pvdelim = pv_parse_spec(&s_tok, new_el->v.pvs)) == NULL) { + shm_free(new_el->v.pvs); + shm_free(new_el); + goto wrong_value; + } + + new_el->next = *result; + *result = new_el; + + if (delim) + if (delim != pvdelim) + goto wrong_value; + else { + input.len -= delim - input.s + 1; + input.s = delim + 1; + } + else { + input.len -= pvdelim - input.s + 1; + input.s = pvdelim; + } + } + else if (str2int(&s_tok, &u_num) == 0) { + new_el = shm_malloc(sizeof(int_list_t)); + if (new_el == NULL) + goto no_memory; + + new_el->v.ival = u_num; + new_el->type = GPARAM_TYPE_INT; + new_el->next = *result; + *result = new_el; + + input.len -= full_tok_len + 1; + input.s = delim + 1; + } + else goto wrong_value; + } while (delim); + + if (input.len > 0) + goto wrong_value; + + return 0; + +no_memory: + while(*result) { + if ((*result)->type == GPARAM_TYPE_PVS) + shm_free((*result)->v.pvs); + int_list_t *aux = *result; + *result = (*result)->next; + shm_free(aux); + } + LM_ERR("no more shared memory\n"); + return -1; + +wrong_value: + while(*result) { + if ((*result)->type == GPARAM_TYPE_PVS) + shm_free((*result)->v.pvs); + int_list_t *aux = *result; + *result = (*result)->next; + shm_free(aux); + } + LM_ERR("wrong format for set/set list. Token <%.*s>\n", original_input.len, original_input.s); + return -1; +} + +/* + * Create a general partition from a string (variable or plain-text name) +*/ + +static int get_gpart(str *input, gpartition_t *partition) +{ + + if (input->s == NULL) { + partition->type = GPART_TYPE_POINTER; + partition->v.p = default_partition; + return 0; + } + + if (input->s[0] == PV_MARKER) { + + partition->type = GPART_TYPE_PVS; + partition->v.pvs = shm_malloc(sizeof(pv_spec_t)); + + if (partition->v.pvs == NULL) { + LM_ERR ("no more shared memory\n"); + return -1; + } + + char *end; + if ((end = pv_parse_spec(input, partition->v.pvs)) == NULL) { + LM_ERR ("cannot parse variable\n"); + return -1; + } + if (end - input->s != input->len) { + LM_ERR ("wrong format for partition\n"); + return -1; + } + + return 0; + } + + /* We have a static partition name */ + ds_partition_t *part_it = partitions; + for (; part_it; part_it = part_it->next) + if (str_strcmp(&part_it->name, input) == 0) { + partition->type = GPART_TYPE_POINTER; + partition->v.p = part_it; + return 0; + } + LM_ERR ("partition <%.*s> not found\n", input->len, input->s); + return -1; +} + +/* + * Fixup for a string like "partition_name:set1, set2 + * The set list may be missing" +*/ + +static int fixup_partition_sets_null(void **param) +{ + str s_param = {(char*)*param, strlen(*param)}; + str part_name = {NULL, 0}; + + char *delim = q_memchr(s_param.s, DS_PARTITION_DELIM, s_param.len); + + if (delim) { + part_name.s = s_param.s; + part_name.len = delim - s_param.s; + s_param.s = delim + 1; + s_param.len -= part_name.len + 1; + str_trim_spaces_lr(part_name); + } + + str_trim_spaces_lr(s_param); + + ds_param_t *final_param = shm_malloc(sizeof (ds_param_t)); + + if (final_param == NULL) { + LM_CRIT ("no more shared memory!\n"); + return -1; + } + + if (get_gpart(&part_name, &final_param->partition) != 0) { + shm_free(final_param); + return -1; + } + + if ((set_list_from_string(s_param, &final_param->sets)) != 0){ + shm_free(final_param); + return -1; + } + + *param = (void*)final_param; + return 0; +} + +/* + * Fixup for a string like "partition_name:set1, set2 + * The set list is mandatory" +*/ + +int fixup_partition_sets(void **param) +{ + if (fixup_partition_sets_null(param) != 0) + return -1; + + if (((ds_param_t*)*param)->sets == NULL) { + /* Null sets are not allowed */ + LM_ERR("A set must be specified!\n"); + return -1; + } + return 0; +} + +/* + * Fixup for a string like "partition_name:set_no" + * + * Only one set number is allowed and it must not be missing +*/ + +int fixup_partition_one_set(void **param) +{ + if (fixup_partition_sets(param) != 0) + return -1; + if (((ds_param_t*)*param)->sets->next != NULL) { + LM_ERR("Only one set is accepted\n"); + return -1; + } + return 0; +} + +/* + * Fixup for partition_name. + * Turns char* into gpartition_t (i.e. pvspec or partition_t*) +*/ + +int fixup_partition(void **param) +{ + gpartition_t *partition = shm_malloc (sizeof(gpartition_t)); + str input = {(char*)(*param), strlen((char*)(*param))}; + str_trim_spaces_lr(input); + + if (get_gpart(&input, partition) != 0) { + shm_free(partition); + return -1; + } + + *param = (void*)partition; + return 0; +} + +/* + * Get the actual partition from a gpartition_t +*/ + +int fixup_get_partition(struct sip_msg *msg, const gpartition_t *gpart, + ds_partition_t **partition) +{ + if (gpart->type == GPART_TYPE_POINTER) { + *partition = gpart->v.p; + return 0; + } + + pv_value_t value; + + if(pv_get_spec_value(msg, gpart->v.pvs, &value)!=0 + || value.flags&PV_VAL_NULL || !(value.flags&PV_VAL_STR)) { + LM_ERR("no valid PV value found (error in scripts)\n"); + return -1; + } + + if (value.rs.len == 0) { + *partition = default_partition; + return 0; + } + + ds_partition_t *part_it = partitions; + + for (; part_it; part_it = part_it->next) + if (part_it->name.len == value.rs.len && + memcmp(part_it->name.s, value.rs.s, value.rs.len) == 0) { + *partition = part_it; + return 0; + } + + *partition = NULL; + return 0; +} + +/* + * Fixup for an int list +*/ + +int fixup_int_list(void **param) +{ + str input = {(char*)(*param), strlen((char*)(*param))}; + int_list_t *lst; + if (set_list_from_string(input, &lst) != 0 || lst == NULL) + return -1; + *param = (void*)(lst); + return 0; +} + +/* + * Set the given flag in the flags structure integer value + */ +static int ds_set_flag(ds_flags_t* flags, int ds_flag) +{ + + if (flags->type == DS_FLAGS_TYPE_PVS) + goto err; + + flags->type = DS_FLAGS_TYPE_INT; + if (!(flags->v.ival & ds_flag)) + flags->v.ival |= ds_flag; + else { + LM_ERR("more than one flag with the same meaning given\n"); + return -1; + } + + return 0; + + err: + LM_ERR("Invalid flags parameter\n"); + shm_free(flags); + return -1; +} + + +/* + * Fixup for flags + */ + +int fixup_flags(void **param, ds_flags_t* flags) +{ + + #define PV_DELIM ')' + #define FLAG_ERR(_flag_msg_)\ + do{\ + LM_ERR("Cannot set " #_flag_msg_ " flag\n");\ + return -1;\ + } while(0); + + char* param_p = (char *)(*param); + + for( ; *param_p != '\0' ; param_p++) { + switch (*param_p) { + case ' ': + (*param)++; + break; + case 'f': + case 'F': + if (ds_set_flag(flags, DS_FAILOVER_ON)) + FLAG_ERR(failover (F)); + break; + case 'u': + case 'U': + if (ds_set_flag(flags, DS_HASH_USER_ONLY)) + FLAG_ERR(hash user (U)); + break; + case 'd': + case 'D': + if (ds_set_flag(flags, DS_USE_DEFAULT)) + FLAG_ERR(use default (D)); + break; + case 's': + case 'S': + if (ds_set_flag(flags, DS_FORCE_DST)) + FLAG_ERR(force dst (S)); + break; + case PV_MARKER: + + if (flags->type == DS_FLAGS_TYPE_PVS) { + LM_ERR("M letter must come before " + "the max_results PV\n"); + return -1; + } + flags->type = DS_FLAGS_TYPE_PVS; + flags->v.pvs = shm_malloc(sizeof(pv_spec_t)); + if (!flags->v.pvs) + goto mem; + + char* end = memchr(param_p, PV_DELIM,strlen(param_p)); + if (!end) + goto pv_err; + str input = {param_p, end - param_p+1}; + + if (!pv_parse_spec(&input, flags->v.pvs)) + goto pv_err; + + param_p = ++end; + break; + case 'M': + + if ((char*)(*param) == param_p) { + /*No flags defined.Default value 0*/ + flags->type = DS_FLAGS_TYPE_INT; + flags->v.ival = 0; + } + *param = ++param_p; + + return 0; + default : + LM_ERR("Invalid definition\n"); + return -1; + } + } + + *param = param_p; + return 0; + + mem: + LM_ERR("No more shm\n"); + return -1; + pv_err: + LM_ERR("Invalid pv definition\n"); + shm_free(flags->v.pvs); + shm_free(flags); + return -1; + #undef FLAG_ERR +} + +/* + * Free an expanded list (obtained with set_list_from_pvs) + * Delete everything in the range [start, end). + * Do not use this function to erase any other lists +*/ + +void free_int_list(int_list_t *start, int_list_t *end) +{ + int_list_t *aux; + while (start != end) { + aux = start; + start = start->next; + pkg_free(aux); + } +} + +/* + * Get a partition and a set from a general ds_param structure +*/ + +inline int fixup_get_partition_set(struct sip_msg *msg, const ds_param_t *param, + ds_partition_t **partition, unsigned int *uset) +{ + if (fixup_get_partition(msg, ¶m->partition, partition) != 0) + return -1; + + if (*partition == NULL) { + LM_ERR("unknown partition\n"); + return -1; + } + + if (param->sets->type == GPARAM_TYPE_INT) { + *uset = param->sets->v.ival; + return 0; + } + + int_list_t *tmp = set_list_from_pvs(msg, param->sets->v.pvs, NULL); + if (tmp == NULL || tmp->next != NULL) { + LM_ERR("Wrong variable value for set\n"); + return -1; + } + *uset = tmp->v.ival; + free_int_list(tmp, NULL); + return 0; +} + +/* Fixup function for ds_next_dst and ds_next_domain functions */ +int ds_next_fixup(void **param, int param_no) +{ + if (param_no > 1) { + LM_CRIT ("Too many parameters for ds_next_dst/ds_next_domain\n"); + return -1; + } + + return fixup_partition(param); +} + +/* Fixup function for ds_mark_dst command */ +int ds_mark_fixup(void **param, int param_no) +{ + if (param_no == 1) + return fixup_partition(param); + else if (param_no == 2) + return fixup_sgp(param); + else + return -1; +} + +/* Fixup function for ds_is_in_list command */ +int in_list_fixup(void** param, int param_no) +{ + if (param_no==1) { + /* the ip to test */ + return fixup_pvar(param); + } else if (param_no==2) { + /* the port to test */ + if (*param==NULL) { + return 0; + } else if ( *((char*)*param)==0 ) { + pkg_free(*param); + *param = NULL; + return 0; + } + return fixup_pvar(param); + } else if (param_no==3) { + if (fixup_partition_sets_null(param) != 0) + return -1; + int_list_t *sets = ((ds_param_t*)*param)->sets; + if (sets && sets->next) { + LM_ERR("Only one set is accepted\n"); + return -1; + } + return 0; + } else if (param_no==4) { + /* active only check ? */ + return fixup_uint(param); + } else { + LM_CRIT("bug - too many params (%d) in is_in_list()\n",param_no); + return -1; + } +} + + +/* Fixup function for ds_select_dst and ds_select_domain commands */ +int ds_select_fixup(void** param, int param_no) +{ + ds_flags_t* flags; + flags_int_list_t* result; + + if (param_no > 3) { + LM_CRIT("Too many params for ds_select_*\n"); + return -1; + } + + switch (param_no) { + case 1: + return fixup_partition_sets(param); + case 2: + return fixup_int_list(param); + case 3: + result = shm_malloc(sizeof(flags_int_list_t)); + flags = shm_malloc(sizeof(ds_flags_t)); + /*Fixing flags*/ + int rc = fixup_flags(param, flags); + if (rc) { + LM_ERR("Cannot fixup flags\n"); + return -1; + } + /*Fixing max_results list*/ + if (((char *)(*param))[0] != '\0') { + rc = fixup_int_list(param); + if (rc) { + LM_ERR("Cannot fixup list\n"); + return -1; + } + } + + result->flags = flags; + result->list = (int_list_t*)(*param); + *param = result; + return 0; + } + + return 0; +} + +/* Fixup function for ds_count command */ +int ds_count_fixup(void** param, int param_no) +{ + char *s; + int i, code = 0; + + if (param_no > 3) + return 0; + + s = (char *)*param; + i = strlen(s); + + switch (param_no) + { + case 1: + return fixup_partition_one_set(param); + case 2: + + while (i--) + { + switch (s[i]) + { + /* active */ + case 'a': + case 'A': + case '1': + code |= DS_COUNT_ACTIVE; + break; + + /* inactive */ + case 'i': + case 'I': + case '0': + code |= DS_COUNT_INACTIVE; + break; + + /* probing */ + case 'p': + case 'P': + case '2': + code |= DS_COUNT_PROBING; + break; + } + } + break; + + case 3: + return fixup_igp(param); + } + + s[0] = (char)code; + s[1] = '\0'; + + return 0; +} + + diff --git a/modules/dispatcher/ds_fixups.h b/modules/dispatcher/ds_fixups.h new file mode 100644 index 00000000000..f24ef727c7c --- /dev/null +++ b/modules/dispatcher/ds_fixups.h @@ -0,0 +1,101 @@ +/** + * + * dispatcher module fixup functions + * + * Copyright (C) 2004-2005 FhG Fokus + * Copyright (C) 2006-2010 Voice Sistem SRL + * Copyright (C) 2014 OpenSIPS Foundation + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History + * ------- + * 2014-07-08 initial version (Andrei Datcu) +*/ + + +#ifndef _DS_FIXUPS_H_ +#define _DS_FIXUPS_H_ + + +#include "dispatch.h" +#include "../../mod_fix.h" + +/* Structure that contains a general description of a partition: + * either its name through a pv_spec or a pointer to the coresponding + * ds_partition_t partition +*/ +typedef struct +{ + union { + ds_partition_t *p; + pv_spec_t *pvs; + } v; + enum gparttype_t {GPART_TYPE_POINTER, GPART_TYPE_PVS} type; +} gpartition_t; + + +typedef struct _int_list_t +{ + union { + int ival; + pv_spec_t *pvs; + } v; + int type; + struct _int_list_t *next; +} int_list_t; + +/* Structure that describes a general pair of a partition and a set list */ +typedef struct +{ + gpartition_t partition; + int_list_t *sets; +} ds_param_t; + +/*Structure that will keep the flags as an integer or PV*/ +typedef struct +{ + union { + int ival; + pv_spec_t *pvs; + } v; + enum flagstype_t {DS_FLAGS_TYPE_INT, DS_FLAGS_TYPE_PVS} type; +} ds_flags_t; + +typedef struct flags_int_list { + int_list_t* list; + ds_flags_t* flags; +} flags_int_list_t; + +int_list_t *set_list_from_pvs(struct sip_msg *msg, pv_spec_t *pvs, int_list_t *end); +void free_int_list(int_list_t *start, int_list_t *end); + +int fixup_get_partition(struct sip_msg *msg, const gpartition_t *gpart, + ds_partition_t **partition); +inline int fixup_get_partition_set(struct sip_msg *msg, const ds_param_t *param, + ds_partition_t **partition, unsigned int *uset); +int fixup_partition_sets(void **param); +int fixup_partition_one_set(void **param); +int fixup_int_list(void **param); + +int ds_next_fixup(void **param, int param_no); +int ds_mark_fixup(void **param, int param_no); +int in_list_fixup(void** param, int param_no); +int ds_select_fixup(void** param, int param_no); +int ds_count_fixup(void** param, int param_no); + +#endif diff --git a/modules/diversion/README b/modules/diversion/README index c65e1561aaa..d538e272652 100644 --- a/modules/diversion/README +++ b/modules/diversion/README @@ -14,8 +14,7 @@ Saul Ibarra Corretge Copyright © 2004 FhG FOKUS Revision History - Revision $Revision$ $Date: 2012-05-30 20:07:17 +0300 - (Wed, 30 May 2012) $ + Revision $Revision: 9064 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/diversion/diversion.c b/modules/diversion/diversion.c index 1043425087e..16389f28294 100644 --- a/modules/diversion/diversion.c +++ b/modules/diversion/diversion.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Diversion Header Field Support @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -89,9 +89,11 @@ static param_export_t params[] = { * Module interface */ struct module_exports exports = { - "diversion", + "diversion", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -139,12 +141,12 @@ static inline int add_diversion_helper(struct sip_msg* msg, str* s) msg_id = msg->id; anchor = 0; } - + if (!msg->diversion && parse_headers(msg, HDR_DIVERSION_F, 0) == -1) { LM_ERR("header parsing failed\n"); return -1; } - + if (msg->diversion) { /* Insert just before the topmost Diversion header */ ptr = msg->diversion->name.s; @@ -154,13 +156,13 @@ static inline int add_diversion_helper(struct sip_msg* msg, str* s) } if (!anchor) { - anchor = anchor_lump(msg, ptr - msg->buf, 0, 0); + anchor = anchor_lump(msg, ptr - msg->buf, 0); if (!anchor) { LM_ERR("can't get anchor\n"); return -2; } } - + if (!insert_new_lump_before(anchor, s->s, s->len, 0)) { LM_ERR("can't insert lump\n"); return -3; diff --git a/modules/dns_cache/dns_cache.c b/modules/dns_cache/dns_cache.c index 34340a9b953..a69942e45c7 100644 --- a/modules/dns_cache/dns_cache.c +++ b/modules/dns_cache/dns_cache.c @@ -60,12 +60,23 @@ static param_export_t params[]={ {0,0,0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_CACHEDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /** module exports */ struct module_exports exports= { "dns_cache", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -143,7 +154,7 @@ static char* serialize_he_rdata(struct hostent *he,int *buf_len,int do_encoding) unsigned char *p; int i,len=0,needed_len=0,base64_len=0,alias_no=0,addr_no=0; - /* addr_type, name_len, alias_no, addr_no */ + /* addr_type, name_len, alias_no, addr_no */ len+=sizeof(int)*4; /* compute needed buffer length */ @@ -171,14 +182,14 @@ static char* serialize_he_rdata(struct hostent *he,int *buf_len,int do_encoding) base64_len = calc_base64_encode_len(len); needed_len=len+base64_len; } else - needed_len = len; + needed_len = len; if (he_buf == NULL || needed_len > he_buf_len) { /* realloc if not enough space */ - he_buf = pkg_realloc(he_buf,needed_len); + he_buf = pkg_realloc(he_buf,needed_len); if (he_buf == NULL) { LM_ERR("No more pkg\n"); - return NULL; + return NULL; } he_buf_len = needed_len; } @@ -190,13 +201,13 @@ static char* serialize_he_rdata(struct hostent *he,int *buf_len,int do_encoding) p+=sizeof(int); /* copy h_name len */ - len=strlen(he->h_name)+1; + len=strlen(he->h_name)+1; memcpy(p,&len,sizeof(int)); p+=sizeof(int); /* copy h_name */ memcpy(p,he->h_name,len); p+=len; - + /* copy number of aliases */ memcpy(p,&alias_no,sizeof(int)); p+=sizeof(int); @@ -234,11 +245,11 @@ static char* serialize_he_rdata(struct hostent *he,int *buf_len,int do_encoding) /* do encoding, and return pointer after unencoded data */ base64encode(p,he_buf,len); - return (char *)p; + return (char *)p; } else { if (buf_len) *buf_len = needed_len; - return (char *)he_buf; + return (char *)he_buf; } } @@ -255,7 +266,7 @@ static struct hostent* deserialize_he_rdata(char *buff,int buf_len,int do_decodi unsigned char *p; int max_len=0; int i,alias_no=0,addr_no=0,len=0; - + /* max estimation of needed buffer */ if (do_decoding) { max_len=calc_max_base64_decode_len(buf_len); @@ -265,10 +276,10 @@ static struct hostent* deserialize_he_rdata(char *buff,int buf_len,int do_decodi if (dec_he_buf == NULL || max_len > dec_he_buf_len) { /* realloc buff if not enough space */ - dec_he_buf = pkg_realloc(dec_he_buf,max_len); + dec_he_buf = pkg_realloc(dec_he_buf,max_len); if (dec_he_buf == NULL) { LM_ERR("No more pkg\n"); - return NULL; + return NULL; } dec_he_buf_len = max_len; } @@ -280,7 +291,7 @@ static struct hostent* deserialize_he_rdata(char *buff,int buf_len,int do_decodi hap = h_addr_ptrs; *hap = NULL; dec_global_he.h_addr_list = h_addr_ptrs; - + if (do_decoding) { /* decode base64 buf */ base64decode(dec_he_buf,(unsigned char *)buff,buf_len); @@ -313,19 +324,19 @@ static struct hostent* deserialize_he_rdata(char *buff,int buf_len,int do_decodi memcpy(&len,p,sizeof(int)); p+=sizeof(int); *ap++ = (char *)p; - p+=len; + p+=len; } /* get number of addresses */ - memcpy(&addr_no,p,sizeof(int)); + memcpy(&addr_no,p,sizeof(int)); p+=sizeof(int); for (i=0;i rdata_buf_len) { - rdata_buf = pkg_realloc(rdata_buf,needed_len); + rdata_buf = pkg_realloc(rdata_buf,needed_len); if (rdata_buf == NULL) { LM_ERR("No more pkg\n"); - return NULL; + return NULL; } rdata_buf_len = needed_len; } p = rdata_buf; - + for (it=head;it;it=it->next) { /* copy non-pointer fields of the struct */ memcpy(p,it,rdata_struct_len); p+=rdata_struct_len; - + switch (it->type) { case T_A: /* copy all 4 bytes */ memcpy(p,it->rdata,sizeof(struct a_rdata)); p+=sizeof(struct a_rdata); - break; + break; case T_AAAA: /* copy all 16 bytes */ memcpy(p,it->rdata,sizeof(struct aaaa_rdata)); p+=sizeof(struct aaaa_rdata); - break; + break; case T_CNAME: cname_rd=(struct cname_rdata *)it->rdata; entry_len=strlen(cname_rd->name); @@ -386,11 +397,11 @@ static char* serialize_dns_rdata(struct rdata *head,int buf_len,int *len,int do_ /* copy alias */ memcpy(p,cname_rd->name,entry_len+1); p+=entry_len+1; - break; + break; case T_NAPTR: /* copy priority, etc */ - memcpy(p,it->rdata,2*sizeof(unsigned short) + - sizeof(unsigned int)); + memcpy(p,it->rdata,2*sizeof(unsigned short) + + sizeof(unsigned int)); p+=2*sizeof(unsigned short) + sizeof(unsigned int); naptr_rd=it->rdata; /* copy flags, flags_len was copied above */ @@ -411,7 +422,7 @@ static char* serialize_dns_rdata(struct rdata *head,int buf_len,int *len,int do_ p+=sizeof(unsigned int); memcpy(p,naptr_rd->repl,naptr_rd->repl_len+1); p+=naptr_rd->repl_len+1; - break; + break; case T_SRV: srv_rd=it->rdata; memcpy(p,srv_rd,4*sizeof(unsigned short) + @@ -419,18 +430,18 @@ static char* serialize_dns_rdata(struct rdata *head,int buf_len,int *len,int do_ p+=4*sizeof(unsigned short) + sizeof(unsigned int); memcpy(p,srv_rd->name,srv_rd->name_len+1); p+=srv_rd->name_len+1; - break; + break; case T_TXT: txt_rd=it->rdata; entry_len=strlen(txt_rd->txt); memcpy(p,&entry_len,sizeof(int)); p+=sizeof(int); memcpy(p,txt_rd->txt,entry_len+1); - p+=entry_len+1; - break; + p+=entry_len+1; + break; case T_EBL: ebl_rd=it->rdata; - memcpy(p,ebl_rd,sizeof(unsigned char) + + memcpy(p,ebl_rd,sizeof(unsigned char) + sizeof(unsigned int)); p+=sizeof(unsigned char) + sizeof(unsigned int); memcpy(p,ebl_rd->separator,ebl_rd->separator_len+1); @@ -439,21 +450,21 @@ static char* serialize_dns_rdata(struct rdata *head,int buf_len,int *len,int do_ p+=sizeof(unsigned int); memcpy(p,ebl_rd->apex,ebl_rd->apex_len+1); p+=ebl_rd->apex_len+1; - break; + break; default: LM_ERR("Unexpected DNS record type\n"); return NULL; } } - + if (do_encoding) { if (*len) *len = base64_len; /* encode and return beggining of encoding */ base64encode(p,rdata_buf,buf_len); - return (char *)p; - } else { + return (char *)p; + } else { if (*len) *len = needed_len; return (char *)rdata_buf; @@ -473,7 +484,7 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin struct ebl_rdata *ebl_rd; head=it=NULL; - last=&head; + last=&head; if (do_decoding) { max_len = calc_max_base64_decode_len(buf_len); @@ -483,17 +494,17 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin if (dec_rdata_buf == NULL || max_len > dec_rdata_buf_len) { /* realloc buff if not enough space */ - dec_rdata_buf = pkg_realloc(dec_rdata_buf,max_len); + dec_rdata_buf = pkg_realloc(dec_rdata_buf,max_len); if (dec_rdata_buf == NULL) { LM_ERR("No more pkg\n"); - return NULL; + return NULL; } dec_rdata_buf_len = max_len; } if (do_decoding) { /* decode base64 buf */ - actual_len = base64decode(dec_rdata_buf,(unsigned char *)buff,buf_len); + actual_len = base64decode(dec_rdata_buf,(unsigned char *)buff,buf_len); p = dec_rdata_buf; } else { memcpy(dec_rdata_buf,buff,buf_len); @@ -502,7 +513,7 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin } while ( p < dec_rdata_buf+actual_len) { - it = pkg_malloc(sizeof(struct rdata)); + it = pkg_malloc(sizeof(struct rdata)); if (it == 0) { LM_ERR("no more pkg mem\n"); goto it_alloc_error; @@ -510,44 +521,44 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin /* copy type, class & ttl */ memcpy(it,p,rdata_struct_len); - p+=rdata_struct_len; + p+=rdata_struct_len; it->next=0; it->rdata=0; switch (it->type) { case T_A: - it->rdata = pkg_malloc(sizeof(struct a_rdata)); + it->rdata = pkg_malloc(sizeof(struct a_rdata)); if (it->rdata == 0) { LM_ERR("no more pkg\n"); goto rdata_alloc_error; } memcpy(p,it->rdata,sizeof(struct a_rdata)); - p+=sizeof(struct a_rdata); + p+=sizeof(struct a_rdata); *last=it; last=&(it->next); - break; + break; case T_AAAA: - it->rdata = pkg_malloc(sizeof(struct aaaa_rdata)); + it->rdata = pkg_malloc(sizeof(struct aaaa_rdata)); if (it->rdata == 0) { LM_ERR("no more pkg\n"); goto rdata_alloc_error; } memcpy(p,it->rdata,sizeof(struct aaaa_rdata)); - p+=sizeof(struct aaaa_rdata); + p+=sizeof(struct aaaa_rdata); *last=it; last=&(it->next); - break; + break; case T_CNAME: - it->rdata = pkg_malloc(sizeof(struct cname_rdata)); + it->rdata = pkg_malloc(sizeof(struct cname_rdata)); if (it->rdata == 0) { LM_ERR("no more pkg\n"); goto rdata_alloc_error; - } + } memcpy(&entry_len,p,sizeof(int)); - p+=sizeof(int); + p+=sizeof(int); memcpy(((struct cname_rdata*)it->rdata)->name, p,entry_len+1); - p+=entry_len+1; + p+=entry_len+1; *last=it; last=&(it->next); break; @@ -558,7 +569,7 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin goto rdata_alloc_error; } naptr_rd = (struct naptr_rdata*)it->rdata; - memcpy(naptr_rd,p,2*sizeof(unsigned short) + + memcpy(naptr_rd,p,2*sizeof(unsigned short) + sizeof(unsigned int)); p+=2*sizeof(unsigned short) + sizeof(unsigned int); memcpy(naptr_rd->flags,p,naptr_rd->flags_len+1); @@ -585,7 +596,7 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin goto rdata_alloc_error; } srv_rd = (struct srv_rdata*)it->rdata; - memcpy(srv_rd,p,4*sizeof(unsigned short) + + memcpy(srv_rd,p,4*sizeof(unsigned short) + sizeof(unsigned int)); p+=4*sizeof(unsigned short) + sizeof(unsigned int); memcpy(srv_rd->name,p,srv_rd->name_len+1); @@ -601,9 +612,9 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin } txt_rd = (struct txt_rdata*)it->rdata; memcpy(&entry_len,p,sizeof(int)); - p+=sizeof(int); + p+=sizeof(int); memcpy(txt_rd->txt,p,entry_len+1); - p+=entry_len+1; + p+=entry_len+1; *last=it; last=&(it->next); break; @@ -614,9 +625,9 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin goto rdata_alloc_error; } ebl_rd = (struct ebl_rdata*)it->rdata; - memcpy(ebl_rd,p,sizeof(unsigned char) + - sizeof(unsigned int)); - p+=sizeof(unsigned char)+sizeof(unsigned int); + memcpy(ebl_rd,p,sizeof(unsigned char) + + sizeof(unsigned int)); + p+=sizeof(unsigned char)+sizeof(unsigned int); memcpy(ebl_rd->separator,p,ebl_rd->separator_len+1); p+=ebl_rd->separator_len+1; memcpy(&ebl_rd->apex_len,p,sizeof(unsigned int)); @@ -632,7 +643,7 @@ static struct rdata* deserialize_dns_rdata(char *buff,int buf_len,int do_decodin return head; rdata_alloc_error: - if (it) + if (it) pkg_free(it); it_alloc_error: if (head) @@ -662,7 +673,7 @@ char* create_keyname_for_record(char *name,int r_type,int name_len,int *res_len) } else { /* binary key, convert to str */ inet_ntop(name_len==4?AF_INET:AF_INET6,name,p,name_len==4? - INET_ADDRSTRLEN:INET6_ADDRSTRLEN); + INET_ADDRSTRLEN:INET6_ADDRSTRLEN); x=strlen(p); *res_len += x; p+=x; @@ -710,12 +721,12 @@ char* create_keyname_for_record(char *name,int r_type,int name_len,int *res_len) LM_ERR("invalid r_type %d\n",r_type); return NULL; } - + return keyname_buff; } /* gets value from cache for the corresponding entry - * Params : + * Params : * name - what is wished to be resolved - binary IP for PTR and strings for other queries * r_type - type of DNS query * name_len - only used in case of PTR @@ -723,16 +734,16 @@ char* create_keyname_for_record(char *name,int r_type,int name_len,int *res_len) int get_dnscache_strvalue(char *name,int r_type,int name_len,str *res) { str key; - + /* generate key */ key.s=create_keyname_for_record(name,r_type,name_len,&key.len); if (key.s == NULL) { LM_ERR("failed to create key\n"); return -1; } - + LM_DBG("gen key [%.*s]\n",key.len,key.s); - + /* fetch from backend */ if (cdbf.get(cdbc, &key, res) < 0) { LM_DBG("cannot retrieve key\n"); @@ -755,7 +766,7 @@ void* get_dnscache_value(char *name,int r_type,int name_len) if (cdbc == NULL) { /* assume dns request before forking - cache is not ready yet */ - return NULL; + return NULL; } if (get_dnscache_strvalue(name,r_type,name_len,&value) < 0) { @@ -782,7 +793,7 @@ void* get_dnscache_value(char *name,int r_type,int name_len) } else { head = deserialize_dns_rdata(value.s,value.len, CACHEDB_CAPABILITY(&cdbf,CACHEDB_CAP_BINARY_VALUE)?0:1); - if (head == NULL) { + if (head == NULL) { LM_ERR("failed to deserialize rdata struct\n"); pkg_free(value.s); return NULL; @@ -810,7 +821,7 @@ int put_dnscache_value(char *name,int r_type,void *record,int rdata_len, if (cdbc == NULL) { /* assume dns request before forking - cache is not ready yet */ - return -1; + return -1; } /* generate key */ @@ -825,11 +836,11 @@ int put_dnscache_value(char *name,int r_type,void *record,int rdata_len, * with the default timeout */ value.s = FAILURE_MARKER; value.len= FAILURE_MARKER_LEN; - key_ttl = blacklist_timeout; + key_ttl = blacklist_timeout; } else { if (r_type == T_A || r_type == T_AAAA || r_type == T_PTR) { value.s = serialize_he_rdata((struct hostent *)record, - &value.len,CACHEDB_CAPABILITY(&cdbf,CACHEDB_CAP_BINARY_VALUE)?0:1); + &value.len,CACHEDB_CAPABILITY(&cdbf,CACHEDB_CAP_BINARY_VALUE)?0:1); if (value.s == NULL) { LM_ERR("failed to serialize he rdata\n"); return -1; diff --git a/modules/domain/README b/modules/domain/README index d350ec32d54..67f80b0c5d7 100644 --- a/modules/domain/README +++ b/modules/domain/README @@ -12,8 +12,7 @@ Juha Heinanen Copyright © 2002-2008 Juha Heinanen Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -28,12 +27,14 @@ Juha Heinanen 1.3.2. db_mode (integer) 1.3.3. domain_table (string) 1.3.4. domain_col (string) + 1.3.5. attrs_col (string) 1.4. Exported Functions - 1.4.1. is_from_local() - 1.4.2. is_uri_host_local() - 1.4.3. is_domain_local(pseudo_variable) + 1.4.1. is_from_local([attrs_pvar]) + 1.4.2. is_uri_host_local([attrs_pvar]) + 1.4.3. is_domain_local(pseudo_variable [, + attrs_pvar]) 1.5. Exported MI Functions @@ -54,9 +55,10 @@ Juha Heinanen 1.2. db_mode example 1.3. Setting domain_table parameter 1.4. Setting domain_col parameter - 1.5. is_from_local usage - 1.6. is_uri_host_local usage - 1.7. is_domain_local usage + 1.5. Setting attrs_col parameter + 1.6. is_from_local usage + 1.7. is_uri_host_local usage + 1.8. is_domain_local usage Chapter 1. Admin Guide @@ -127,42 +129,65 @@ modparam("domain", "domain_table", "new_name") Example 1.4. Setting domain_col parameter modparam("domain", "domain_col", "domain_name") +1.3.5. attrs_col (string) + + Name of column containing attributes in domain table. + + Default value is “attrs”. + + Example 1.5. Setting attrs_col parameter +modparam("domain", "attrs_col", "attributes") + 1.4. Exported Functions -1.4.1. is_from_local() +1.4.1. is_from_local([attrs_pvar]) Checks based on domain table if host part of From header uri is - one of the local domains that the proxy is responsible for + one of the local domains that the proxy is responsible for. The + argument is optional and if present it should contain a + writable pseudo variable that will be populated with the + attributes from the database. This function can be used from REQUEST_ROUTE. - Example 1.5. is_from_local usage + Example 1.6. is_from_local usage ... if (is_from_local()) { ... }; ... +if (is_from_local("$var(attrs)")) { + xlog("Domain attributes are $var(attrs)\n"); + ... +}; +... -1.4.2. is_uri_host_local() +1.4.2. is_uri_host_local([attrs_pvar]) If called from route or failure route block, checks based on domain table if host part of Request-URI is one of the local domains that the proxy is responsible for. If called from branch route, the test is made on host part of URI of first branch, which thus must have been appended to the transaction - before is_uri_host_local() is called. + before is_uri_host_local() is called. The argument is optional + and if present it should contain a writable pseudo variable + that will be populated with the attributes from the database. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.6. is_uri_host_local usage + Example 1.7. is_uri_host_local usage ... if (is_uri_host_local()) { ... }; ... +if (is_uri_host_local("$var(attrs)")) { + xlog("Domain attributes are $var(attrs)\n"); + ... +}; -1.4.3. is_domain_local(pseudo_variable) +1.4.3. is_domain_local(pseudo_variable [, attrs_pvar]) This function checks if the domain contained in the pseudo_variable is local. @@ -175,10 +200,14 @@ if (is_uri_host_local()) { * is_domain_local("$rd") is same as is_uri_host_local() * is_domain_local("$fd") is same as is_from_local() + The second argument is optional and if present it should + contain a writable pseudo variable that will be populated with + the attributes from the database. + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.7. is_domain_local usage + Example 1.8. is_domain_local usage ... if (is_domain_local("$rd")) { ... @@ -195,6 +224,10 @@ if (is_domain_local("$avp(850)")) { if (is_domain_local("$avp(some_avp)")) { ... }; +if (is_domain_local("$avp(some_avp)", "$avp(attrs)")) { + xlog("Domain attributes are $avp(attrs)\n"); + ... +}; ... 1.5. Exported MI Functions diff --git a/modules/domain/api.c b/modules/domain/api.c index e117425f130..3f81679334a 100644 --- a/modules/domain/api.c +++ b/modules/domain/api.c @@ -31,6 +31,6 @@ int bind_domain(domain_api_t* api) } api->is_domain_local = is_domain_local; - + return 0; } diff --git a/modules/domain/doc/domain_admin.xml b/modules/domain/doc/domain_admin.xml index b2af5e95b0c..e9d3bcb220a 100644 --- a/modules/domain/doc/domain_admin.xml +++ b/modules/domain/doc/domain_admin.xml @@ -105,6 +105,21 @@ modparam("domain", "domain_table", "new_name") Setting domain_col parameter modparam("domain", "domain_col", "domain_name") + +
+
+
+ <varname>attrs_col</varname> (string) + + Name of column containing attributes in domain table. + + + Default value is attrs. + + + Setting attrs_col parameter + +modparam("domain", "attrs_col", "attributes")
@@ -113,10 +128,13 @@ modparam("domain", "domain_col", "domain_name")
Exported Functions
- <function moreinfo="none">is_from_local()</function> + <function moreinfo="none">is_from_local([attrs_pvar])</function> Checks based on domain table if host part of From header uri is - one of the local domains that the proxy is responsible for + one of the local domains that the proxy is responsible for. + The argument is optional and if present it should contain a writable + pseudo variable that will be populated with the attributes from the + database. This function can be used from REQUEST_ROUTE. @@ -128,12 +146,17 @@ modparam("domain", "domain_col", "domain_name") if (is_from_local()) { ... }; +... +if (is_from_local("$var(attrs)")) { + xlog("Domain attributes are $var(attrs)\n"); + ... +}; ...
- <function moreinfo="none">is_uri_host_local()</function> + <function moreinfo="none">is_uri_host_local([attrs_pvar])</function> If called from route or failure route block, checks based on domain table if host part of Request-URI is one @@ -142,6 +165,9 @@ if (is_from_local()) { part of URI of first branch, which thus must have been appended to the transaction before is_uri_host_local() is called. + The argument is optional and if present it should contain a writable + pseudo variable that will be populated with the attributes from the + database. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, @@ -155,11 +181,15 @@ if (is_uri_host_local()) { ... }; ... +if (is_uri_host_local("$var(attrs)")) { + xlog("Domain attributes are $var(attrs)\n"); + ... +};
- <function moreinfo="none">is_domain_local(pseudo_variable)</function> + <function moreinfo="none">is_domain_local(pseudo_variable [, attrs_pvar])</function> This function checks if the domain contained in the pseudo_variable is local. @@ -180,6 +210,11 @@ if (is_uri_host_local()) { + The second argument is optional and if present it should contain a writable + pseudo variable that will be populated with the attributes from the + database. + + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. @@ -202,6 +237,10 @@ if (is_domain_local("$avp(850)")) { if (is_domain_local("$avp(some_avp)")) { ... }; +if (is_domain_local("$avp(some_avp)", "$avp(attrs)")) { + xlog("Domain attributes are $avp(attrs)\n"); + ... +}; ... diff --git a/modules/domain/domain.c b/modules/domain/domain.c index 34212b0ddb0..75d003ee2bd 100644 --- a/modules/domain/domain.c +++ b/modules/domain/domain.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Domain table related functions @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2004-06-07 updated to the new DB api, moved reload_table here, created + * 2004-06-07 updated to the new DB api, moved reload_table here, created * domain_db_{init.bind,ver,close} (andrei) * 2004-09-06 is_uri_host_local() can now be called also from * failure route (juhe) @@ -40,6 +40,8 @@ #include "../../pvar.h" #include "../../str.h" +#define DOMAIN_TABLE_VERSION 3 + static db_con_t* db_handle=0; static db_func_t domain_dbf; @@ -57,7 +59,7 @@ int domain_db_bind(const str* db_url) int domain_db_init(const str* db_url) -{ +{ if (domain_dbf.init==0){ LM_ERR("Unbound database module\n"); goto error; @@ -93,21 +95,25 @@ int domain_db_ver(str* name, int version) } - /* - * Check if domain is local + * Check if domain is local and store attributes in a pvar */ -int is_domain_local(str* _host) +int is_domain_local_pvar(struct sip_msg *msg, str* _host, char *pvar) { + pv_spec_t *pv = (pv_spec_t *)pvar; + pv_value_t val; + db_val_t *values; + if (db_mode == 0) { db_key_t keys[1]; db_val_t vals[1]; - db_key_t cols[1]; + db_key_t cols[2]; db_res_t* res = NULL; keys[0] = &domain_col; cols[0] = &domain_col; - + cols[1] = &domain_attrs_col; + if (domain_dbf.use_table(db_handle, &domain_table) < 0) { LM_ERR("Error while trying to use domain table\n"); return -3; @@ -115,33 +121,58 @@ int is_domain_local(str* _host) VAL_TYPE(vals) = DB_STR; VAL_NULL(vals) = 0; - + VAL_STR(vals).s = _host->s; VAL_STR(vals).len = _host->len; - if (domain_dbf.query(db_handle, keys, 0, vals, cols, 1, 1, 0, &res) < 0 + if (domain_dbf.query(db_handle, keys, 0, vals, cols, 1, 2, 0, &res) < 0 ) { LM_ERR("Error while querying database\n"); return -3; } if (RES_ROW_N(res) == 0) { - LM_DBG("Realm '%.*s' is not local\n", + LM_DBG("Realm '%.*s' is not local\n", _host->len, ZSW(_host->s)); domain_dbf.free_result(db_handle, res); return -1; } else { - LM_DBG("Realm '%.*s' is local\n", + LM_DBG("Realm '%.*s' is local\n", _host->len, ZSW(_host->s)); + if (pvar) { + /* XXX: what shall we do if there are duplicate entries? */ + /* we only check the first row - razvanc */ + values = ROW_VALUES(RES_ROWS(res)); + if (!VAL_NULL(values +1)) { + if (VAL_TYPE(values + 1) == DB_STR) { + val.rs = VAL_STR(values + 1); + } else { + val.rs.s = (char *)VAL_STRING(values + 1); + val.rs.len = strlen(val.rs.s); + } + val.flags = PV_VAL_STR; + if (pv_set_value(msg, pv, 0, &val) != 0) + LM_ERR("Cannot set attributes value\n"); + } + } domain_dbf.free_result(db_handle, res); return 1; } } else { - return hash_table_lookup (_host); + return hash_table_lookup (msg, _host, pv); } - + +} + +/* + * Check if domain is local + */ +int is_domain_local(str* _host) +{ + return is_domain_local_pvar(NULL, _host, NULL); } + /* * Check if host in From uri is local */ @@ -154,7 +185,7 @@ int is_from_local(struct sip_msg* _msg, char* _s1, char* _s2) return -2; } - return is_domain_local(&(puri->host)); + return is_domain_local_pvar(_msg, &(puri->host), _s1); } @@ -167,7 +198,7 @@ int is_uri_host_local(struct sip_msg* _msg, char* _s1, char* _s2) LM_ERR("Error while parsing R-URI\n"); return -1; } - return is_domain_local(&(_msg->parsed_uri.host)); + return is_domain_local_pvar(_msg, &(_msg->parsed_uri.host), _s1); } @@ -181,13 +212,13 @@ int w_is_domain_local(struct sip_msg* _msg, char* _sp, char* _s2) sp = (pv_spec_t *)_sp; - if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) { + if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) { if (pv_val.flags & PV_VAL_STR) { if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) { LM_DBG("Missing domain name\n"); return -1; } - return is_domain_local(&(pv_val.rs)); + return is_domain_local_pvar(_msg, &(pv_val.rs), _s2); } else { LM_DBG("Pseudo variable value is not string\n"); return -1; @@ -205,8 +236,7 @@ int w_is_domain_local(struct sip_msg* _msg, char* _sp, char* _s2) */ int reload_domain_table ( void ) { - db_val_t vals[1]; - db_key_t cols[1]; + db_key_t cols[2]; db_res_t* res = NULL; db_row_t* row; db_val_t* val; @@ -214,17 +244,17 @@ int reload_domain_table ( void ) struct domain_list **new_hash_table; int i; + str domain, attrs; + cols[0] = &domain_col; + cols[1] = &domain_attrs_col; if (domain_dbf.use_table(db_handle, &domain_table) < 0) { LM_ERR("Error while trying to use domain table\n"); return -3; } - VAL_TYPE(vals) = DB_STR; - VAL_NULL(vals) = 0; - - if (domain_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 1, 0, &res) < 0) { + if (domain_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 2, 0, &res) < 0) { LM_ERR("Error while querying database\n"); return -3; } @@ -241,20 +271,37 @@ int reload_domain_table ( void ) row = RES_ROWS(res); LM_DBG("Number of rows in domain table: %d\n", RES_ROW_N(res)); - + for (i = 0; i < RES_ROW_N(res); i++) { val = ROW_VALUES(row + i); - if ((ROW_N(row) == 1) && (VAL_TYPE(val) == DB_STRING)) { - - LM_DBG("Value: %s inserted into domain hash table\n",VAL_STRING(val)); - - if (hash_table_install(new_hash_table,(char*)VAL_STRING(val))==-1){ - LM_ERR("Hash table problem\n"); - domain_dbf.free_result(db_handle, res); - return -3; - } + if (VAL_TYPE(val) == DB_STRING) { + domain.s = (char *)VAL_STRING(val); + domain.len = strlen(domain.s); + } else if (VAL_TYPE(val) == DB_STR) { + domain = VAL_STR(val); + } else { + LM_ERR("Database problem on domain column\n"); + domain_dbf.free_result(db_handle, res); + return -3; + } + if (VAL_NULL(val + 1)) { + /* add a marker to determine whether the attributes exist or not */ + attrs.len = 0; + attrs.s = NULL; + } else if (VAL_TYPE(val + 1) == DB_STRING) { + attrs.s = (char *)VAL_STRING(val + 1); + attrs.len = strlen(attrs.s); + } else if (VAL_TYPE(val + 1) == DB_STR) { + attrs = VAL_STR(val + 1); } else { - LM_ERR("Database problem\n"); + LM_ERR("Database problem on attrs column\n"); + domain_dbf.free_result(db_handle, res); + return -3; + } + LM_DBG("Value: %s inserted into domain hash table\n",VAL_STRING(val)); + + if (hash_table_install(new_hash_table, &domain, &attrs)==-1){ + LM_ERR("Hash table problem\n"); domain_dbf.free_result(db_handle, res); return -3; } @@ -262,7 +309,7 @@ int reload_domain_table ( void ) domain_dbf.free_result(db_handle, res); *hash_table = new_hash_table; - + return 1; } diff --git a/modules/domain/domain.h b/modules/domain/domain.h index 9267392c369..8d47f4ae369 100644 --- a/modules/domain/domain.h +++ b/modules/domain/domain.h @@ -16,15 +16,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef DOMAIN_H #define DOMAIN_H - + #include "../../parser/msg_parser.h" diff --git a/modules/domain/domain_mod.c b/modules/domain/domain_mod.c index c4090a47401..ca98cbdef94 100644 --- a/modules/domain/domain_mod.c +++ b/modules/domain/domain_mod.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -62,7 +62,7 @@ static int mi_child_init(void); * increment this value if you change the table in * an backwards incompatible way */ -#define TABLE_VERSION 2 +#define TABLE_VERSION 3 #define DOMAIN_TABLE "domain" #define DOMAIN_TABLE_LEN (sizeof(DOMAIN_TABLE) - 1) @@ -70,6 +70,9 @@ static int mi_child_init(void); #define DOMAIN_COL "domain" #define DOMAIN_COL_LEN (sizeof(DOMAIN_COL) - 1) +#define DOMAIN_ATTRS_COL "attrs" +#define DOMAIN_ATTRS_COL_LEN (sizeof(DOMAIN_ATTRS_COL) - 1) + /* * Module parameter variables */ @@ -77,6 +80,7 @@ static str db_url = {NULL, 0}; int db_mode = 0; /* Database usage mode: 0 = no cache, 1 = cache */ str domain_table = {DOMAIN_TABLE, DOMAIN_TABLE_LEN}; /* Name of domain table */ str domain_col = {DOMAIN_COL, DOMAIN_COL_LEN}; /* Name of domain column */ +str domain_attrs_col = {DOMAIN_ATTRS_COL, DOMAIN_ATTRS_COL_LEN}; /* Name of attributes column */ /* * Other module variables @@ -89,17 +93,29 @@ struct domain_list **hash_table_2 = 0; /* Pointer to hash table 2 */ static int is_domain_alias(char* name, int len, unsigned short port, unsigned short proto); +static int fixup_wpvar_null(void **param, int param_no); +static int fixup_pvar_wpvar(void **param, int param_no); + /* * Exported functions */ static cmd_export_t cmds[] = { {"is_from_local", (cmd_function)is_from_local, 0, 0, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"is_from_local", (cmd_function)is_from_local, 1, fixup_wpvar_null, + fixup_free_pvar_null, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE| + LOCAL_ROUTE}, {"is_uri_host_local", (cmd_function)is_uri_host_local, 0, 0, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"is_uri_host_local", (cmd_function)is_uri_host_local, 1, fixup_wpvar_null, + fixup_free_pvar_null, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE| + LOCAL_ROUTE}, {"is_domain_local", (cmd_function)w_is_domain_local, 1, fixup_pvar_null, fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, + {"is_domain_local", (cmd_function)w_is_domain_local, 2, fixup_pvar_wpvar, + fixup_free_pvar_pvar, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| + LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"bind_domain", (cmd_function)bind_domain, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -113,6 +129,7 @@ static param_export_t params[] = { {"db_mode", INT_PARAM, &db_mode }, {"domain_table", STR_PARAM, &domain_table.s}, {"domain_col", STR_PARAM, &domain_col.s }, + {"attrs_col", STR_PARAM, &domain_attrs_col.s }, {0, 0, 0} }; @@ -132,8 +149,10 @@ static mi_export_t mi_cmds[] = { */ struct module_exports exports = { "domain", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -147,6 +166,53 @@ struct module_exports exports = { }; +static int fixup_wpvar(void **param) +{ + int ret; + pv_spec_t *spec; + ret = fixup_pvar(param); + if (ret != 0) { + LM_ERR("cannot parse pvar\n"); + return -1; + } + spec = *(pv_spec_t **)param; + if (!spec) { + LM_BUG("cannot find spec"); + return -1; + } + if (!spec->setf) + { + LM_ERR("pvar not writable\n"); + return -1; + } + return 0; +} + +static int fixup_wpvar_null(void **param, int param_no) +{ + if(param_no != 1) + { + LM_ERR("invalid parameter number %d\n", param_no); + return E_UNSPEC; + } + return fixup_wpvar(param); +} + +static int fixup_pvar_wpvar(void **param, int param_no) +{ + if (param_no == 1) + { + return fixup_pvar(param); + } + if (param_no != 2) + { + LM_ERR("invalid parameter number %d\n", param_no); + return E_UNSPEC; + } + return fixup_wpvar(param); +} + + static int mod_init(void) { int i; @@ -156,6 +222,7 @@ static int mod_init(void) init_db_url( db_url , 0 /*cannot be null*/); domain_table.len = strlen(domain_table.s); domain_col.len = strlen(domain_col.s); + domain_attrs_col.len = strlen(domain_attrs_col.s); /* Check if database module has been loaded */ if (domain_db_bind(&db_url) < 0) return -1; diff --git a/modules/domain/domain_mod.h b/modules/domain/domain_mod.h index 1f224d21191..eba8cb8c5f0 100644 --- a/modules/domain/domain_mod.h +++ b/modules/domain/domain_mod.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -49,6 +49,7 @@ */ struct domain_list { str domain; + str attrs; struct domain_list *next; }; @@ -65,6 +66,7 @@ typedef struct param_source { extern int db_mode; /* Database usage mode: 0 = no cache, 1 = cache */ extern str domain_table; /* Domain table name */ extern str domain_col; /* Domain column name */ +extern str domain_attrs_col; /* Domain attributes column name */ /* diff --git a/modules/domain/hash.c b/modules/domain/hash.c index c12f7a3654b..bf7ad0ae799 100644 --- a/modules/domain/hash.c +++ b/modules/domain/hash.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -38,25 +38,30 @@ /* Add domain to hash table */ -int hash_table_install (struct domain_list **hash_table, char *domain) +int hash_table_install (struct domain_list **hash_table, str *d, str *a) { struct domain_list *np; unsigned int hash_val; - np = (struct domain_list *) shm_malloc(sizeof(*np)); + np = (struct domain_list *) shm_malloc(sizeof(*np) + d->len + a->len); if (np == NULL) { LM_ERR("Cannot allocate memory for hash table entry\n"); return -1; } - - np->domain.len = strlen(domain); - np->domain.s = (char *) shm_malloc(np->domain.len); - if (np->domain.s == NULL) { - LM_ERR("Cannot allocate memory for domain string\n"); - shm_free(np); - return -1; + memset(np, 0, sizeof(*np)); + + np->domain.len = d->len; + np->domain.s = (char *)(np + 1); + memcpy(np->domain.s, d->s, d->len); + + np->attrs.len = a->len; + /* check to see if there is a value there */ + if (a->s) { + np->attrs.s = np->domain.s + d->len; + memcpy(np->attrs.s, a->s, a->len); + } else { + np->attrs.s = NULL; } - (void) strncpy(np->domain.s, domain, np->domain.len); hash_val = dom_hash(&np->domain); np->next = hash_table[hash_val]; @@ -67,13 +72,20 @@ int hash_table_install (struct domain_list **hash_table, char *domain) /* Check if domain exists in hash table */ -int hash_table_lookup (str *domain) +int hash_table_lookup (struct sip_msg *msg, str *domain, pv_spec_t *pv) { struct domain_list *np; + pv_value_t val; for (np = (*hash_table)[dom_hash(domain)]; np != NULL; np = np->next) { - if ((np->domain.len == domain->len) && - (strncasecmp(np->domain.s, domain->s, domain->len) == 0)) { + if ((np->domain.len == domain->len) && + (strncasecmp(np->domain.s, domain->s, domain->len) == 0)) { + if (pv && np->attrs.s) { + val.rs = np->attrs; + val.flags = PV_VAL_STR; + if (pv_set_value(msg, pv, 0, &val) != 0) + LM_ERR("cannot set attributes value\n"); + } return 1; } } @@ -93,10 +105,17 @@ int hash_table_mi_print(struct domain_list **hash_table, struct mi_node* rpl) for (i = 0; i < DOM_HASH_SIZE; i++) { np = hash_table[i]; while (np) { - node = add_mi_node_child(rpl, 0, 0, 0, + node = add_mi_node_child(rpl, 0, 0, 0, np->domain.s, np->domain.len); if(node == 0) return -1; + if (np->attrs.s) { + if (!add_mi_attr(node, 0, "attributes", 10, + np->attrs.s, np->attrs.len)) { + LM_ERR("cannot add attributes\n"); + return -1; + } + } np = np->next; } @@ -109,14 +128,13 @@ void hash_table_free (struct domain_list **hash_table) { int i; struct domain_list *np, *next; - + if(hash_table==0) return; for (i = 0; i < DOM_HASH_SIZE; i++) { np = hash_table[i]; while (np) { - shm_free(np->domain.s); next = np->next; shm_free(np); np = next; diff --git a/modules/domain/hash.h b/modules/domain/hash.h index b56dc32a1b3..e3822825b17 100644 --- a/modules/domain/hash.h +++ b/modules/domain/hash.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -30,8 +30,8 @@ #include "domain_mod.h" #include "../../mi/mi.h" -int hash_table_install (struct domain_list **hash_table, char *domain); -int hash_table_lookup (str *domain); +int hash_table_install (struct domain_list **hash_table, str *d, str *a); +int hash_table_lookup (struct sip_msg *msg, str *domain, pv_spec_t *pv); int hash_table_mi_print(struct domain_list **hash_table, struct mi_node* rpl); void hash_table_free (struct domain_list **hash_table); diff --git a/modules/domain/mi.c b/modules/domain/mi.c index 9ec85f8f5ab..4f530e5e7d4 100644 --- a/modules/domain/mi.c +++ b/modules/domain/mi.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -64,6 +64,7 @@ struct mi_root* mi_domain_dump(struct mi_root *cmd_tree, void *param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return 0; + rpl_tree->node.flags |= MI_IS_ARRAY; if(hash_table_mi_print(*hash_table, &rpl_tree->node)< 0) { diff --git a/modules/domain/mi.h b/modules/domain/mi.h index e55f9b59696..8ab401f6862 100644 --- a/modules/domain/mi.h +++ b/modules/domain/mi.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/domainpolicy/README b/modules/domainpolicy/README index e36672e37fc..47663b12d9d 100644 --- a/modules/domainpolicy/README +++ b/modules/domainpolicy/README @@ -23,8 +23,7 @@ Klaus Darilion Copyright © 2002, 2003, 2006 Juha Heinanen, Otmar Lendl, Klaus Darilion Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/domainpolicy/domainpolicy.c b/modules/domainpolicy/domainpolicy.c index e202e987594..4b83d69fdac 100644 --- a/modules/domainpolicy/domainpolicy.c +++ b/modules/domainpolicy/domainpolicy.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Domain Policy related functions @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -107,7 +107,7 @@ static void stack_to_avp(struct avp_stack *stack) { for(j=0; j< stack->i; j++) { /* AVP names can be integer or string based */ - LM_DBG("process AVP: name='%s' value='%s'\n", + LM_DBG("process AVP: name='%s' value='%s'\n", stack->avp[j].att, stack->avp[j].val); /* we will only use string avps @@ -120,10 +120,10 @@ static void stack_to_avp(struct avp_stack *stack) { LM_ERR("cannot find %s avp\n", avp_val.s.s); continue; } - LM_DBG("create string named AVP \n", + LM_DBG("create string named AVP \n", avp_val.s.len, ZSW(avp_val.s.s)); - avp_val.s.s = stack->avp[j].val; + avp_val.s.s = stack->avp[j].val; avp_val.s.len = strlen(avp_val.s.s); /* string type explicitely forced with s: */ @@ -249,7 +249,7 @@ static inline int parse_naptr_regexp(char* first, int len, str* pattern, /* * Tests if one result record is "greater" that the other. Non-NAPTR records - * greater that NAPTR record. An invalid NAPTR record is greater than a + * greater that NAPTR record. An invalid NAPTR record is greater than a * valid one. Valid NAPTR records are compared based on their * (order,preference). * @@ -271,16 +271,16 @@ static inline int naptr_greater(struct rdata* a, struct rdata* b) if (!IS_D2PNAPTR(na)) return 1; - + if (!IS_D2PNAPTR(nb)) return 0; - + return (((na->order) << 16) + na->pref) > (((nb->order) << 16) + nb->pref); } - - + + /* * Bubble sorts result record list according to naptr (order,preference). */ @@ -289,38 +289,38 @@ static inline void naptr_sort(struct rdata** head) struct rdata *p, *q, *r, *s, *temp, *start; /* r precedes p and s points to the node up to which comparisons - are to be made */ + are to be made */ s = NULL; start = *head; - while ( s != start -> next ) { - r = p = start ; + while ( s != start -> next ) { + r = p = start ; q = p -> next ; - while ( p != s ) { - if ( naptr_greater(p, q) ) { - if ( p == start ) { - temp = q -> next ; - q -> next = p ; + while ( p != s ) { + if ( naptr_greater(p, q) ) { + if ( p == start ) { + temp = q -> next ; + q -> next = p ; p -> next = temp ; - start = q ; - r = q ; + start = q ; + r = q ; } else { - temp = q -> next ; - q -> next = p ; + temp = q -> next ; + q -> next = p ; p -> next = temp ; - r -> next = q ; - r = q ; - } + r -> next = q ; + r = q ; + } } else { - r = p ; - p = p -> next ; - } - q = p -> next ; - if ( q == s ) s = p ; + r = p ; + p = p -> next ; + } + q = p -> next ; + if ( q == s ) s = p ; } } *head = start; -} +} /* * input: rule straight from the DDDS + avp-stack. @@ -334,7 +334,7 @@ static int check_rule(str *rule, char *service, int service_len, struct avp_stac /* for the select */ db_key_t keys[2]; db_val_t vals[2]; - db_key_t cols[4]; + db_key_t cols[4]; db_res_t* res; db_row_t* row; db_val_t* val; @@ -344,7 +344,7 @@ static int check_rule(str *rule, char *service, int service_len, struct avp_stac LM_INFO("checking for '%.*s'.\n", rule->len, ZSW(rule->s)); - if ((service_len != 11) || (strncasecmp("d2p+sip:fed", service, 11) && + if ((service_len != 11) || (strncasecmp("d2p+sip:fed", service, 11) && strncasecmp("d2p+sip:std", service, 11) && strncasecmp("d2p+sip:dom", service, 11))) { LM_ERR("can only cope with d2p+sip:fed, d2p+sip:std,and d2p+sip:dom " "for now (and not %.*s).\n", service_len, service); @@ -385,11 +385,11 @@ static int check_rule(str *rule, char *service, int service_len, struct avp_stac LM_ERR("querying database\n"); return -1; } - + LM_INFO("querying database OK\n"); if (RES_ROW_N(res) == 0) { - LM_DBG("rule '%.*s' is not know.\n", + LM_DBG("rule '%.*s' is not know.\n", rule->len, ZSW(rule->s)); domainpolicy_dbf.free_result(db_handle, res); return 0; @@ -406,7 +406,7 @@ static int check_rule(str *rule, char *service, int service_len, struct avp_stac val = ROW_VALUES(row + i); - if ((VAL_TYPE(val) != DB_STRING) || + if ((VAL_TYPE(val) != DB_STRING) || (VAL_TYPE(val+1) != DB_STRING) || (VAL_TYPE(val+2) != DB_STRING) || (VAL_TYPE(val+3) != DB_STRING)) { @@ -422,7 +422,7 @@ static int check_rule(str *rule, char *service, int service_len, struct avp_stac LM_INFO("DB returned %s/%s \n",VAL_STRING(val+2),VAL_STRING(val+3)); - if (!stack_push(stack, (char *) VAL_STRING(val+2), + if (!stack_push(stack, (char *) VAL_STRING(val+2), (char *) VAL_STRING(val+3))) { return(-1); } @@ -482,7 +482,7 @@ int dp_can_connect_str(str *domain, int rec_level) { LM_INFO("doing DDDS with %.*s\n",domain->len, ZSW(domain->s)); head = get_record(domain->s, T_NAPTR); if (head == 0) { - LM_NOTICE("no NAPTR record found for %.*s.\n", + LM_NOTICE("no NAPTR record found for %.*s.\n", domain->len, ZSW(domain->s)); return(DP_DDDS_RET_NOTFOUND); } @@ -499,7 +499,7 @@ int dp_can_connect_str(str *domain, int rec_level) { continue; } LM_DBG("order %u, pref %u, flen %u, flags '%.*s', slen %u, " - "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n", + "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n", naptr->order, naptr->pref, naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len, @@ -523,7 +523,7 @@ int dp_can_connect_str(str *domain, int rec_level) { } LM_DBG("considering order %u, pref %u, flen %u, flags '%.*s', slen %u, " - "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n", + "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n", naptr->order, naptr->pref, naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len, @@ -554,7 +554,7 @@ int dp_can_connect_str(str *domain, int rec_level) { /* * NAPTRs we don't care about */ - if (!IS_D2PNAPTR(naptr)) + if (!IS_D2PNAPTR(naptr)) continue; /* @@ -662,7 +662,7 @@ int dp_can_connect_str(str *domain, int rec_level) { return(DP_DDDS_RET_POSITIVE); } - LM_INFO("returning %d.\n", + LM_INFO("returning %d.\n", (found_anything ? DP_DDDS_RET_NEGATIVE : DP_DDDS_RET_NOTFOUND)); return( found_anything ? DP_DDDS_RET_NEGATIVE : DP_DDDS_RET_NOTFOUND ); } @@ -757,7 +757,7 @@ int dp_apply_policy(struct sip_msg* _msg, char* _s1, char* _s2) { */ didsomething = 0; /* if no AVP is set, there is no need to set the DURI in the end */ - + if (parse_sip_msg_uri(_msg) < 0) { LM_ERR("failed to parse R-URI\n"); return -1; @@ -818,7 +818,7 @@ int dp_apply_policy(struct sip_msg* _msg, char* _s1, char* _s2) { } memcpy(at, domain->s, domain->len); at = at + domain->len; } - + /* search for suffix and add it to duri buffer */ avp = search_first_avp(0, domain_suffix_name, &val, 0); if (avp) { @@ -863,9 +863,9 @@ int dp_apply_policy(struct sip_msg* _msg, char* _s1, char* _s2) { LM_ERR("duri buffer to small to copy port\n"); return -1; } - *at = ':'; at = at + 1; + *at = ':'; at = at + 1; /* add : as delimiter between domain and port */ - memcpy(at, _msg->parsed_uri.port.s, _msg->parsed_uri.port.len); + memcpy(at, _msg->parsed_uri.port.s, _msg->parsed_uri.port.len); at = at + _msg->parsed_uri.port.len; } else { LM_DBG("port not found in RURI, no need to copy it to DURI\n"); diff --git a/modules/domainpolicy/domainpolicy.h b/modules/domainpolicy/domainpolicy.h index 94c13e20fe5..1ef9d70fa2c 100644 --- a/modules/domainpolicy/domainpolicy.h +++ b/modules/domainpolicy/domainpolicy.h @@ -16,15 +16,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef DOMAINPOLICY_H #define DOMAINPOLICY_H - + #include "../../parser/msg_parser.h" diff --git a/modules/domainpolicy/domainpolicy_mod.c b/modules/domainpolicy/domainpolicy_mod.c index b6cedf4bc3c..c7fc823ef64 100644 --- a/modules/domainpolicy/domainpolicy_mod.c +++ b/modules/domainpolicy/domainpolicy_mod.c @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -91,7 +91,7 @@ str send_socket_avp = str_init(DEF_SEND_SOCKET_AVP); * Other module variables */ -int port_override_name, transport_override_name, domain_prefix_name, +int port_override_name, transport_override_name, domain_prefix_name, domain_suffix_name, domain_replacement_name, send_socket_name; /* @@ -123,14 +123,25 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "domainpolicy", + "domainpolicy", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ diff --git a/modules/domainpolicy/domainpolicy_mod.h b/modules/domainpolicy/domainpolicy_mod.h index f9cc5a4e7e3..799895dcf20 100644 --- a/modules/domainpolicy/domainpolicy_mod.h +++ b/modules/domainpolicy/domainpolicy_mod.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -47,7 +47,7 @@ extern str domainpolicy_col_val; /* Value column name */ * Other module variables */ -extern int port_override_name, transport_override_name, +extern int port_override_name, transport_override_name, domain_prefix_name, domain_suffix_name, domain_replacement_name, send_socket_name, target_name; extern str domain_replacement_avp; diff --git a/modules/drouting/README b/modules/drouting/README index bc8baf440d1..265461977cd 100644 --- a/modules/drouting/README +++ b/modules/drouting/README @@ -16,8 +16,7 @@ Anca-Maria Vamanu Copyright © 2009-2012 www.opensips-solutions.com Revision History - Revision $Revision$ $Date: 2012-03-22 20:43:49 +0200 - (Thu, 22 Mar 2012) $ + Revision $Revision: 8834 $ $Date$ __________________________________________________________ Table of Contents @@ -47,34 +46,52 @@ Anca-Maria Vamanu 1.3.5. drc_table(str) 1.3.6. ruri_avp (str) 1.3.7. gw_id_avp (str) - 1.3.8. gw_attrs_avp (str) - 1.3.9. gw_priprefix_avp (str) - 1.3.10. rule_id_avp (str) - 1.3.11. rule_attrs_avp (str) - 1.3.12. rule_prefix_avp (str) - 1.3.13. carrier_id_avp (str) - 1.3.14. carrier_attrs_avp (str) + 1.3.8. gw_priprefix_avp (str) + 1.3.9. rule_id_avp (str) + 1.3.10. rule_prefix_avp (str) + 1.3.11. carrier_id_avp (str) + 1.3.12. gw_sock_avp (str) + 1.3.13. gw_attrs_avp (str) + 1.3.14. rule_attrs_avp (str) 1.3.15. define_blacklist (str) 1.3.16. default_group (int) 1.3.17. force_dns (int) - 1.3.18. probing_interval (integer) - 1.3.19. probing_method (string) - 1.3.20. probing_from (string) - 1.3.21. probing_reply_codes (string) - 1.3.22. use_domain (int) - 1.3.23. drg_user_col (str) - 1.3.24. drg_domain_col (str) - 1.3.25. drg_grpid_col (str) + 1.3.18. persistent_state (int) + 1.3.19. probing_interval (integer) + 1.3.20. probing_method (string) + 1.3.21. probing_from (string) + 1.3.22. probing_reply_codes (string) + 1.3.23. use_domain (int) + 1.3.24. drg_user_col (str) + 1.3.25. drg_domain_col (str) + 1.3.26. drg_grpid_col (str) + 1.3.27. use_partitions (int) + 1.3.28. db_partitions_url (int) + 1.3.29. db_partitions_table (int) 1.4. Exported Functions - 1.4.1. do_routing([[[groupID],flags],gw_whitelist]) - 1.4.2. route_to_carrier(carrier_id) - 1.4.3. route_to_gw(gw_id) - 1.4.4. use_next_gw()/next_routing() - 1.4.5. goes_to_gw([[type],flags]) - 1.4.6. is_from_gw( [type, [flag]]) - 1.4.7. dr_is_gw(src_pv, [type, [flag]]) + 1.4.1. do_routing([part_and_or_groupID], [flags], + [gw_whitelist], [rule_attrs_pvar], + [gw_attrs_pvar], [carrier_attrs_pvar]) + + 1.4.2. route_to_carrier(part_and_or_carrier_id, + [gw_attrs_pvar], [carrier_attrs_pvar]) + + 1.4.3. route_to_gw(gw_id, [gw_attrs_pvar]) + 1.4.4. use_next_gw([partition','] [rule_attrs_pvar], + [gw_attrs_pvar], + [carrier_attrs_pvar])/next_routing() + + 1.4.5. goes_to_gw([partition','] [type], [flags], + [gw_attrs_pvar]) + + 1.4.6. is_from_gw([partition','] [type], [flag], + [gw_attrs_pvar]) + + 1.4.7. dr_is_gw([partition,] src_avp, [type], + [flag], [gw_attrs_pvar]) + 1.4.8. dr_disable() 1.5. Exported MI Functions @@ -82,8 +99,14 @@ Anca-Maria Vamanu 1.5.1. dr_reload 1.5.2. dr_gw_status 1.5.3. dr_carrier_status + 1.5.4. dr_reload_status + 1.5.5. dr_number_routing + + 1.6. Exported Events - 1.6. Installation + 1.6.1. E_DROUTING_STATUS + + 1.7. Installation 2. Developer Guide @@ -96,34 +119,52 @@ Anca-Maria Vamanu 1.5. Set drc_table parameter 1.6. Set ruri_avp parameter 1.7. Set gw_id_avp parameter - 1.8. Set gw_attrs_avp parameter - 1.9. Set gw_priprefix_avp parameter - 1.10. Set rule_id_avp parameter - 1.11. Set rule_attrs_avp parameter - 1.12. Set rule_prefix_avp parameter - 1.13. Set carrier_id_avp parameter - 1.14. Set carrier_attrs_avp parameter + 1.8. Set gw_priprefix_avp parameter + 1.9. Set rule_id_avp parameter + 1.10. Set rule_prefix_avp parameter + 1.11. Set carrier_id_avp parameter + 1.12. Set gw_sock_avp parameter + 1.13. Set gw_attrs_avp parameter + 1.14. Set rule_attrs_avp parameter 1.15. Set define_blacklist parameter 1.16. Set default_group parameter 1.17. Set force_dns parameter - 1.18. Set probing_interval parameter - 1.19. Set probing_method parameter - 1.20. Set probing_from parameter - 1.21. Set probing_reply_codes parameter - 1.22. Set use_domain parameter - 1.23. Set drg_user_col parameter - 1.24. Set drg_domain_col parameter - 1.25. Set drg_grpid_col parameter - 1.26. do_routing usage - 1.27. route_to_carrier usage - 1.28. route_to_gw usage - 1.29. use_next_gw usage - 1.30. goes_to_gw usage - 1.31. is_from_gw usage - 1.32. dr_is_gw usage - 1.33. dr_disable() usage - 1.34. dr_gw_status usage - 1.35. dr_carrier_status usage + 1.18. Set the persistent_state parameter + 1.19. Set probing_interval parameter + 1.20. Set probing_method parameter + 1.21. Set probing_from parameter + 1.22. Set probing_reply_codes parameter + 1.23. Set use_domain parameter + 1.24. Set drg_user_col parameter + 1.25. Set drg_domain_col parameter + 1.26. Set drg_grpid_col parameter + 1.27. Set use_partitions parameter + 1.28. Set db_partitions_url parameter + 1.29. Set db_partitions_table parameter + 1.30. do_routing usage + 1.31. route_to_carrier usage when use_partitions parameter is 0 + 1.32. route_to_carrier usage when use_partitions parameter is 1 + 1.33. route_to_carrier usage when use_partitions parameter is 1 + with pseudovariables + + 1.34. route_to_gw usage when use_partition parameter is 0 + 1.35. route_to_gw usage when use_partition parameter is 1 + 1.36. use_next_gw usage + 1.37. use_next_gw usage when use_partition parameter is 1 + 1.38. goes_to_gw usage when use_partitions parameter is 0 + 1.39. goes_to_gw usage, when use_partitions parameter is 1 + 1.40. is_from_gw usage when use_partitions is 0 + 1.41. is_from_gw usage when use_partitions is 1 + 1.42. dr_is_gw usage when use_partitions is 0 + 1.43. dr_is_gw usage when use_partitions is 1 + 1.44. dr_disable() usage when use_partitions is 0 + 1.45. dr_disable() usage when use_partitions is 1 + 1.46. dr_gw_status usage when use_partitions is set to 0 + 1.47. dr_gw_status usage when use_partitionsis set to 1 + 1.48. dr_carrier_status usage when use_partitions is 0 + 1.49. dr_carrier_status usage when use_partitions is 1 + 1.50. dr_reload_status usage when use_partitions is 0 + 1.51. dr_reload_status usage when use_partitions is 1 Chapter 1. Admin Guide @@ -158,33 +199,39 @@ Chapter 1. Admin Guide The dynamic routing implementation for OpenSIPS is designed with the following properties: - * routing info (destinations, carriers, rules, groups) are + * The routing info (destinations, carriers, rules, groups) is stored in a database and loaded into memory at start up - time; reload at runtime via an Management Interface - command. - * weigth-based or random selection of the destinations (from + time; reload at runtime via a Management Interface command. + * weight-based or random selection of the destinations (from a rule or from a carrier), failure detection of gateways (with switching to next available gateway). * able to handle large volume of routing info (10M of rules) with minimal speed/time and memory consumption penalties - * script integration - Pseudo variables support in functions; + * script integration - Pseudo-variable support in functions; scripting route triggering when rules are matched * bidirectional behavior - inbound and outbound processing (strip and prefixing when sending and receiving from a destination/GW) - * blacklisting - the module allows definition of backlists + * blacklisting - the module allows definition of blacklists based on the destination IPs. This blacklists are to be used to prevent malicious forwarding to GWs (based on DNS lookups) when the script logic does none-GE forwarding (like foreign domains). + * loading routing information from multiple databases - the + gateways, rules, groups and carriers can be grouped by + partitions, and each partition may be loaded from different + databases/tables. This makes the routing process partition + based. In order to be able to use a table from a partition, + its name must be found in the "version" table belonging to + the database defined in the partition's db_url. 1.1.3. Performance There were several tests performed regarding the performance of the module when dealing with a large number of routing rules. - The tests were performed with a set of 383000 rules and to - values were measured: + The tests were performed with a set of 383000 rules and + measured: * time to load from DB * used shared memory @@ -201,7 +248,7 @@ Chapter 1. Admin Guide 1.1.4. Dynamic Routing Concepts DR engine uses several concepts in order to define how the - routing should be done (describing all the dependecies between + routing should be done (describing all the dependencies between destinations and routing rules). 1.1.4.1. Destination/Gateways @@ -209,8 +256,8 @@ Chapter 1. Admin Guide These are the end SIP entities where actually the traffic needs to be sent after routing. They are stored in a table called “dr_gateways”. Gateway addresses are stored in a separate table - because of need to access them independent of Dynamic Routing - processing (e.g., adding/ removing gateway PRI prefix + because of the need to access them independent of Dynamic + Routing processing (e.g., adding/ removing gateway PRI prefix before/after performing other operation -- receiving/relaying to gateway). @@ -255,9 +302,9 @@ Chapter 1. Admin Guide 1.1.4.3. Routing Rules - These are the actual rule which control the routing - like - based on different criterias (prefix, time, priority, etc) they - will decide to which gateways the call will be sent. + These are the actual rules which control the routing. Using + different criterias (prefix, time, priority, etc), they will + decide to which gateways the call will be sent. Default name for the table storing rule definitions is “dr_rules”. @@ -265,21 +312,21 @@ Chapter 1. Admin Guide In DR, a carrier is defined by: * group (list of numbers) - rules can be grouped (a rule may belong to multiple groups in the same time ) and you can - use only a certian group at a point; like having a + use only a certain group at a point; like having a “premium” or “standard” or “interstate” or “intrastate” groups of rules to be used in different cases * prefix (string with digits only) - prefix to be used for matching this rule (longest prefix matching) * time validity (time recurrence string) - when this rule is valid from time point of view (see RFC 2445) - * priority (number) - prority off the rule - higher value, + * priority (number) - priority of the rule - higher value, higher priority (see rule section alg) * script route ID (string) - if defined, then execute the route with the specified ID when this rule is matched. That's it, a route which can be used to perform custom operations on message. NOTE that no modification is performed at signaling level and you must NOT do any - signalling operations in that script route + signaling operations in that script route * list of GWs/carriers (string) - a comma separated list of gateways or carriers (defined by IDs) to be used for this rule; the carrier IDs are prefixed with “#” sign. For each @@ -292,12 +339,12 @@ Chapter 1. Admin Guide More on time recurrence: * A date-time expression that defines the time recurrence to - match for current rule. Time recurrences are based closely - on the specification of recurring intervals of time in the - Internet Calendaring and Scheduling Core Object - Specification (calendar COS), RFC 2445. The set of - attributes used in routing rule specification is subset of - time recurrence attributes. + be matched for current rule. Time recurrences are based + closely on the recurring time intervals from the Internet + Calendaring and Scheduling Core Object Specification + (calendar COS), RFC 2445. The set of attributes used in + routing rule specification is a subset of time recurrence + attributes. * The value stored in database has the format of: ||||||||| @@ -325,11 +372,11 @@ Chapter 1. Admin Guide If a certain flag is set, then the processing is stopped after executing the route block. * The rule must contain a chain of gateways and carriers. The - module will execute serial forking for each address in - chain (in which order the destinations will be tried, - depends on the defintion order or depends on the weights - (weights selection must be enabled). The next address in - chain is used only if the previously has failed. + module will execute serial forking for each address in the + chain (ordering is either done by simply using the + definition order or it may weight-based - weight selection + must be enabled). The next address in chain is used only if + the previously has failed. * With the right gateway address found, the prefix (PRI) of the gateway is added to the request URI and then the request is forwarded. @@ -349,7 +396,7 @@ Chapter 1. Admin Guide should be done (probe_mode column): * (0) - no probing at all; * (1) - probing only when the destination is in disabled mode - (disabling via MI command will competely stop the probing + (disabling via MI command will completely stop the probing also). The destination will be automatically re-enabled when the probing will succeed next time; * (2) - probing all the time. If disabled, the destination @@ -434,7 +481,7 @@ modparam("drouting", "drg_table", "groups") The name of the db table storing definitions of the carriers that will be used directly by the routing rules. - Default value is “dr_gw_lists”. + Default value is “dr_carriers”. Example 1.5. Set drc_table parameter ... @@ -446,7 +493,11 @@ modparam("drouting", "drc_table", "my_dr_carriers") The name of the avp for storing Request URIs to be later used (alternative destiantions for the current one). - Default value is “$avp(0xad346b2f)”. + Default value is “$avp(___dr_ruri__)” if use_partitions + parameter is 0 or “$avp(___dr_ruri__partition_name)” where + partition_name is the name of the partition containing the AVP + (as fetched from the database) if use_partitions parameter is + 1. Example 1.6. Set ruri_avp parameter ... @@ -461,7 +512,11 @@ modparam("drouting", "ruri_avp", '$avp(33)') the use_next_gw() function), the AVP will be updated with the ID of the new selected gateway/destination. - Default value is “$avp(0xad346b30)”. + Default value is “$avp(___dr_gw_id__)” if use_partitions + parameter is 0 or “$avp(___dr_gw_id__partition_name)” where + partition_name is the name of the partition containing the AVP + (as fetched from the database) if use_partitions parameter is + 1. Example 1.7. Set gw_id_avp parameter ... @@ -469,22 +524,7 @@ modparam("drouting", "gw_id_avp", '$avp(gw_id)') modparam("drouting", "gw_id_avp", '$avp(334)') ... -1.3.8. gw_attrs_avp (str) - - The name of the avp for storing the attributes of the current - selected destination/gateway - once a new destination is - selected (via the use_next_gw() function), the AVP will be - updated with the attrs of the new used destination. - - Default value is “NULL”. - - Example 1.8. Set gw_attrs_avp parameter -... -modparam("drouting", "gw_attrs_avp", '$avp(gw_attrs)') -modparam("drouting", "gw_attrs_avp", '$avp(67)') -... - -1.3.9. gw_priprefix_avp (str) +1.3.8. gw_priprefix_avp (str) The name of the avp for storing the PRI prefix of the current selected destination/gateway - once a new destination is @@ -493,76 +533,102 @@ modparam("drouting", "gw_attrs_avp", '$avp(67)') Default value is “NULL”. - Example 1.9. Set gw_priprefix_avp parameter + Example 1.8. Set gw_priprefix_avp parameter ... modparam("drouting", "gw_priprefix_avp", '$avp(gw_priprefix)') ... -1.3.10. rule_id_avp (str) +1.3.9. rule_id_avp (str) The name of the avp for storing the id of the current matched routing rule (see dr_rules table). Default value is “NULL”. - Example 1.10. Set rule_id_avp parameter + Example 1.9. Set rule_id_avp parameter ... modparam("drouting", "rule_id_avp", '$avp(rule_id)') modparam("drouting", "rule_id_avp", '$avp(335)') ... -1.3.11. rule_attrs_avp (str) - - The name of the avp for storing the attributes of the current - matched routing rule (see dr_rules table). - - Default value is “NULL”. - - Example 1.11. Set rule_attrs_avp parameter -... -modparam("drouting", "rule_attrs_avp", '$avp(rule_attrs)') -modparam("drouting", "rule_attrs_avp", '$avp(66)') -... - -1.3.12. rule_prefix_avp (str) +1.3.10. rule_prefix_avp (str) The actual prefix that matched the routing rule (the part from RURI username that matched the routing rule). Default value is “NULL”. - Example 1.12. Set rule_prefix_avp parameter + Example 1.10. Set rule_prefix_avp parameter ... modparam("drouting", "rule_prefix_avp", '$avp(dr_prefix)') ... -1.3.13. carrier_id_avp (str) +1.3.11. carrier_id_avp (str) AVP to be populate with the ID string for the carrier the current GW belongs to. Default value is “NULL”. - Example 1.13. Set carrier_id_avp parameter + Example 1.11. Set carrier_id_avp parameter ... modparam("drouting", "carrier_id_avp", '$avp(carrier_id)') ... -1.3.14. carrier_attrs_avp (str) +1.3.12. gw_sock_avp (str) - AVP to be populate with the attributes string for the carrier - the current GW belongs to. + The name of the avp for storing sockets for alternative + destinations defined by ruri_avp. - Default value is “NULL”. + Default value is “$avp(___dr_sock__)” if use_partitions + parameter is 0 or “$avp(___dr_sock__partition_name)” where + partition_name is the name of the partition containing the AVP + (as fetched from the database) if use_partitions parameter is + 1. + + Example 1.12. Set gw_sock_avp parameter +... +modparam("drouting", "gw_sock_avp", '$avp(dr_sock)') +modparam("drouting", "gw_sock_avp", '$avp(77)') +... + +1.3.13. gw_attrs_avp (str) + + The name of the avp for storing GW attrs in case they are + requested at least once in the script. + + Default value is “$avp(___dr_gw_att__)” if use_partitions + parameter is 0 or “$avp(___dr_gw_att__partition_name)” where + partition_name is the name of the partition containing the AVP + (as fetched from the database) if use_partitions parameter is + 1. + + Example 1.13. Set gw_attrs_avp parameter +... +modparam("drouting", "gw_attrs_avp", '$avp(dr_attrs_gw)') +modparam("drouting", "gw_attrs_avp", '$avp(11)') +... + +1.3.14. rule_attrs_avp (str) - Example 1.14. Set carrier_attrs_avp parameter + The name of the avp for storing rule attrs in case they are + requested at least once in the script. + + Default value is “$avp(___dr_ru_att__)” if use_partitions + parameter is 0 or “$avp(___dr_ru_att__partition_name)” where + partition_name is the name of the partition containing the AVP + (as fetched from the database) if use_partitions parameter is + 1. + + Example 1.14. Set rule_attrs_avp parameter ... -modparam("drouting", "carrier_attrs_avp", '$avp(carrier_attrs)') +modparam("drouting", "rule_attrs_avp", '$avp(dr_rule_attr)') +modparam("drouting", "rule_attrs_avp", '$avp(11)') ... 1.3.15. define_blacklist (str) - Defines a backlist based on a list of GW types - the list will + Defines a blacklist based on a list of GW types - the list will contain the IPs (no port, all protocols) of the GWs with the specified types. @@ -601,7 +667,20 @@ modparam("drouting", "default_group", 4) modparam("drouting", "force_dns", 0) ... -1.3.18. probing_interval (integer) +1.3.18. persistent_state (int) + + Specifies whether the state column should be loaded at startup + and flushed during runtime or not. + + Default value is “1” (enabled). + + Example 1.18. Set the persistent_state parameter +... +# disable all DB operations with the state of a gateway +modparam("drouting", "persistent_state", 0) +... + +1.3.19. probing_interval (integer) How often (in seconds) the probing of a destination should be done. If set to 0, the probing will be disabled as @@ -609,34 +688,34 @@ modparam("drouting", "force_dns", 0) Default value is “30”. - Example 1.18. Set probing_interval parameter + Example 1.19. Set probing_interval parameter ... modparam("drouting", "probing_interval", 60) ... -1.3.19. probing_method (string) +1.3.20. probing_method (string) The SIP method to be used for the probing requests. Default value is “"OPTIONS"”. - Example 1.19. Set probing_method parameter + Example 1.20. Set probing_method parameter ... modparam("drouting", "probing_method", "INFO") ... -1.3.20. probing_from (string) +1.3.21. probing_from (string) The FROM SIP URI to be advertised in the SIP probing requests. Default value is “"sip:prober@localhost"”. - Example 1.20. Set probing_from parameter + Example 1.21. Set probing_from parameter ... modparam("drouting", "probing_from", "sip:pinger@192.168.2.10") ... -1.3.21. probing_reply_codes (string) +1.3.22. probing_reply_codes (string) A comma separted list of SIP reply codes. The codes defined here will be considered as valid reply codes for probing @@ -644,62 +723,105 @@ modparam("drouting", "probing_from", "sip:pinger@192.168.2.10") Default value is “NULL”. - Example 1.21. Set probing_reply_codes parameter + Example 1.22. Set probing_reply_codes parameter ... modparam("drouting", "probing_reply_codes", "501, 403") ... -1.3.22. use_domain (int) +1.3.23. use_domain (int) Flag to configure whether to use domain match when querying database for user's routing group. Default value is “1”. - Example 1.22. Set use_domain parameter + Example 1.23. Set use_domain parameter ... modparam("drouting", "use_domain", 0) ... -1.3.23. drg_user_col (str) +1.3.24. drg_user_col (str) The name of the column in group db table where the username is stored. Default value is “username”. - Example 1.23. Set drg_user_col parameter + Example 1.24. Set drg_user_col parameter ... modparam("drouting", "drg_user_col", "user") ... -1.3.24. drg_domain_col (str) +1.3.25. drg_domain_col (str) The name of the column in group db table where the domain is stored. Default value is “domain”. - Example 1.24. Set drg_domain_col parameter + Example 1.25. Set drg_domain_col parameter ... modparam("drouting", "drg_domain_col", "host") ... -1.3.25. drg_grpid_col (str) +1.3.26. drg_grpid_col (str) The name of the column in group db table where the group id is stored. Default value is “groupid”. - Example 1.25. Set drg_grpid_col parameter + Example 1.26. Set drg_grpid_col parameter ... modparam("drouting", "drg_grpid_col", "grpid") ... +1.3.27. use_partitions (int) + + Flag to configure whether to use partitions for routing. If + this flag is set then the db_partitions_url and + db_partitions_table variables become mandatory. + + Default value is “0”. + + Example 1.27. Set use_partitions parameter +... +modparam("drouting", "use_partitions", 1) +... + +1.3.28. db_partitions_url (int) + + The url to the database containing partition-specific + information. (partition-specific information includes partition + name, url to the database where information about the partition + is preserved, the names of the tables in which it is preserved + and the AVPs that can be accessed using the .cfg script). The + use_partitions parameter must be set to 1. + + Default value is “"NULL"”. + + Example 1.28. Set db_partitions_url parameter +... +modparam("drouting", "db_partitions_url", "mysql://user:password@localho +st/opensips_partitions") +... + +1.3.29. db_partitions_table (int) + + The name of the table containing partition definitions. To be + used with use_partitions and db_partitions_url. + + Default value is “dr_partitions”. + + Example 1.29. Set db_partitions_table parameter +... +modparam("drouting", "db_partitions_table", "partition_defs") +... + 1.4. Exported Functions -1.4.1. do_routing([[[groupID],flags],gw_whitelist]) +1.4.1. do_routing([part_and_or_groupID], [flags], [gw_whitelist], +[rule_attrs_pvar], [gw_attrs_pvar], [carrier_attrs_pvar]) Function to trigger routing of the message according to the rules in the database table and the configured parameters. @@ -707,96 +829,216 @@ modparam("drouting", "drg_grpid_col", "grpid") This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and LOCAL_ROUTE. - The function can take two optional parameters: - * groupID - the routing group the caller belongs to - this - may be a static numerical value or an AVP specification - (value must be numerical type, string types are ignored!). - If none specified, the function will automatically try to - query the dr_group table to get this information; - * flags - Controlls the behavior of the function. Possible + If you set use_partitions to 1 the part_or_groupID parameter + becomes mandatory. + + All parameters are optional. Any of them may be ignored, + provided the necessary separation marks "," are properly + placed. + * part_and_or_groupID - Specifies the group of the caller for + routing purposes. Depending on the value of the + use_partitions parameter, it contains: + + the routing group the caller belongs to if + use_partitions is 0 - this may be a statical numerical + value or an AVP specification (value must be numerical + type, string types are ignored!). If none specified + the function will automatically try to query the + dr_group table to get this information + + the partition and routing group the caller belongs to, + the format is: "partition':'[groupID]" if + use_partitions parameter is 1 - both the partition + name and the groupId may be statical values or AVP + specifications. If no group is specified the function + will try to query the dr_group table for the given + partition to get this information. + * flags - Controls the behavior of the function. Possible flags are: + W - Instead of using the destination (from the rule definition) in the given order, sort them based on their weight. + F - Enable rule fallback; normally the engine is using a single rule for routing a call; by setting this - flag, the enging will fallback and use rules with less + flag, the engine will fallback and use rules with less priority or shorter prefix when all the destination from the current rules failed. - + L - Do strict lenght matching over the prefix - - actually DR engine will do full number maching and not - prefix matching anymore. + + L - Do strict length matching over the prefix - + actually DR engine will do full number matching and + not prefix matching anymore. + C - Only check if the dialed number matches any routing rule, without loading / applying any routing info (no GW is set, the RURI is not altered) * gw_whitelist - a comma separated white list of gateways. - This will force routing over this list of carriers or - gateways (a subset of what found in the prefix rules). - - Example 1.26. do_routing usage -... -# all groups, sort on order + This will force routing over, at most, this list of + carriers or gateways (in other words, the whitelist will be + intersected with the results of the search through the + rules). + * rule_attrs_pvar (output, optional)- a writable + pseudo-variable which will be populated with the attributes + of the matched dynamic routing rule. + * gw_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched gateway. + * carrier_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched carrier. + + Example 1.30. do_routing usage +... +# all groups, sort on order, use_partitions is 0 do_routing(); ... -# group id 0, sort on order +# all groups, sort on order, use_partitions is 1, route by partition nam +ed "part" +do_routing("part:"); +... +# group id 0, sort on order, use_partitions is 0 do_routing("0"); ... -# group id from $avp(10), sort on order +# group id 0, sort on order, use_partitions is 1, route by partition nam +ed "part" +do_routing("part:0"); +... +# group id from $avp(10), sort on order, use_partitions is 0 do_routing("$avp(10)"); ... -# all groups, sort on weights -do_routing("","W"); +# all groups, sort on weights, use_partitions is 0 +do_routing("", "W"); +... +# all groups, use_partitions is 1, partition and group supplied by AVPs, + do strict length matching +do_routing("$avp(partition):$avp(grp)","L") ... -# group id 2, sort on order, fallback rule -do_routing("2","F"); +# group id 2, sort on order, fallback rule and also return the gateway a +ttributes +do_routing("2", "F", , , "$var(gw_attributes)"); ... -1.4.2. route_to_carrier(carrier_id) +1.4.2. route_to_carrier(part_and_or_carrier_id, [gw_attrs_pvar], +[carrier_attrs_pvar]) Function to trigger the direct routing to a given carrier. In this case the routing is not done prefix based, but carrier based (call will be sent to the GWs of that carrier, based on - carrier policy) + carrier policy). This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and LOCAL_ROUTE.. - Function takes a single mandatory parameter, the ID of the - carrier to be used (variables are accepted). + If you set use_partitions parameter to 1 you must supply the + partition in which the carrier has been defined. + + * part_and_or_carrier_id (mandatory): + + the ID (name) of the carrier to be used, if + use_partitions parameter is 0; pseudo-variables are + accepted. + + the partition and carrier to be used, if + use_partitions parameter is 1. The format is + "partition_name':'carrierId"; pseudo-variables are + accepted. + * gw_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the currently matched gateway of this carrier. + * carrier_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of this carrier. + + Example 1.31. route_to_carrier usage when use_partitions + parameter is 0 +... +if ( route_to_carrier("my_top_carrier", , "$var(carrier_att)") ) { + xlog("Routing to \"my_top_carrier\" - $var(carrier_att)\n"); + t_on_failure("next_gw"); + t_relay(); + exit; +} +... + + Example 1.32. route_to_carrier usage when use_partitions + parameter is 1 +... +if ( route_to_carrier("my_partition:my_top_carrier", , "$var(carrier_att +)") ) { + xlog("Routing to \"my_top_carrier\" - $var(carrier_att)\n"); + t_on_failure("next_gw"); + t_relay(); + exit; +} +... - Example 1.27. route_to_carrier usage + Example 1.33. route_to_carrier usage when use_partitions + parameter is 1 with pseudovariables ... -if ( route_to_carrier("my_top_carrier") ) { +if ( route_to_carrier("$var(my_partition):$var(carrierId)") ) { + xlog("Routing to \"my_top_carrier\" - $var(carrier_att)\n"); t_on_failure("next_gw"); t_relay(); exit; } ... -1.4.3. route_to_gw(gw_id) +1.4.3. route_to_gw(gw_id, [gw_attrs_pvar]) - Function to trigger the direct routing to a given gateway. - Attributes and per-gw preocessing will be available. + Function to trigger the direct routing to a given gateway (or + list of gateways). Attributes and per-gw processing will be + available. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and LOCAL_ROUTE. - Function takes a single mandatory parameter, the ID of the - gateway to be used (variables are accepted). - - Example 1.28. route_to_gw usage + If you set use_partitions parameter to 1 you must supply the + partition in which the gateway has been defined. + + * gw_id (mandatory) - the list of gateways to be used. + + a comma separated list of gateway ID's to be used, if + no use_partition parameter is 0. Pseudo-variables are + accepted. + + the desired partition, followed by a comma separated + list of gateway ID's from that partition to be used, + if use_partition parameter is 1. The format is: + "partition_name':'gwId1, gwId2, gwId3". + Pseudo-variables are accepted. + * gw_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the currently matched gateway. + + Example 1.34. route_to_gw usage when use_partition parameter is + 0 ... if ( route_to_gw("gw_europe") ) { t_relay(); exit; } +... +if ( route_to_gw("gw1,gw2,gw3", "$var(gw_attrs)") ) { + xlog("Relaying to first gateway from our list - $var(gw_attrs)\n +"); + t_relay(); + exit; +} ... -1.4.4. use_next_gw()/next_routing() + Example 1.35. route_to_gw usage when use_partition parameter is + 1 +... +if ( route_to_gw("my_partition:gw_europe") ) { + t_relay(); + exit; +} +... +if ( route_to_gw("my_partition:gw1,gw2,gw3", "$var(gw_attrs)") ) { + xlog("Relaying to first gateway from our list - $var(gw_attrs)\n +"); + t_relay(); + exit; +} +... + +1.4.4. use_next_gw([partition','] [rule_attrs_pvar], +[gw_attrs_pvar], [carrier_attrs_pvar])/next_routing() The function takes the next available destination (set by - do_routing, as alternative destinations) and push it into RURI. - Note that the function just sets the RURI (nothing more). + do_routing, as alternative destinations) and pushes it into the + RURI. Note that the function just sets the RURI (nothing more). If a new RURI is set, the used destination is removed from the pending set of alternative destinations. @@ -806,17 +1048,60 @@ if ( route_to_gw("gw_europe") ) { The function returns true only if a new RURI was set. False is returned is no other alternative destinations are found or in - case of internal processing error. - - Example 1.29. use_next_gw usage + case of an internal processing error. It may take the following + optional parameters: + + If you set use_partitions parameter to 1 you must supply the + partition (the partition becomes mandatory) in which the + gateways have been defined. + + * partition (mandatory if use_partitions parameter is 1, + otherwise it will be omitted altogether) It is the + partition in which the gateways have been defined. + * rule_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched dynamic routing rule. + * gw_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched gateway. + * carrier_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched carrier. + + Example 1.36. use_next_gw usage ... if (use_next_gw()) { t_relay(); exit; } ... +# Also fetch the carrier attributes, if any +if (use_next_gw(, , "$var(carrier_attrs)")) { + xlog("Carrier attributes of current gateway: $var(carrier_attrs) +\n"); + t_relay(); + exit; +} +... + + Example 1.37. use_next_gw usage when use_partition parameter is + 1 +... +if (use_next_gw("my_partition")) { + t_relay(); + exit; +} +... +# Also fetch the carrier attributes, if any +if (use_next_gw("my_partition", , "$var(carrier_attrs)")) { + xlog("Carrier attributes of current gateway: $var(carrier_attrs) +\n"); + t_relay(); + exit; +} +... -1.4.5. goes_to_gw([[type],flags]) +1.4.5. goes_to_gw([partition','] [type], [flags], [gw_attrs_pvar]) Function returns true if the destination of the current request (destination URI or Request URI) points (as IP) to one of the @@ -828,61 +1113,108 @@ if (use_next_gw()) { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE. - The function can take two optional parameters: - * type (optional) - GW/destination type to be checked; a - negative value (ex: -1) means match any group; + If you set use_partitions parameter to 1 you must supply the + partition (the partition becomes mandatory) in which the + gateways have been defined. + + If use_partitions parameter is 0 all parameters are optional. + Any of them may be ignored, provided the necessary separation + marks "," are properly placed. + * partition (mandatory if use_partitions parameter is 1, + otherwise it will be omitted altogether) - the name of the + partition containing the gateway/destination to be checked. + * type (optional) - GW/destination type to be checked; when + omitting this parameter or specifying a negative value i.e. + "-1", matching will be done against all groups (in a given + partition if use_partition parameter is 1; if + use_partitions is 1 the partition being mandatory at this + point, it is not possible to do matching against all the + partitions) * flags (optional) - what operations should be performed when a GW matches: + 's' (Strip) - apply to the username of RURI the strip defined by the GW + 'p' (Prefix) - apply to the username of RURI the prefix defined by the GW - + 'a' (Attributes) - return the attributes string - defined by the GW into gw_attrs_avp AVP + 'i' (Gateway ID) - return the gateway id into gw_id_avp AVP + 'n' (Ignore port) - ignores port number during matching + + 'c' (Carrier ID) - return the carrier id into + carrier_id_avp AVP + * gw_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched gateway. + + Example 1.38. goes_to_gw usage when use_partitions parameter is + 0 +... +if (goes_to_gw("1", , "$var(gw_attrs)")) { + sl_send_reply("403","Forbidden"); + exit; +} +... - Example 1.30. goes_to_gw usage + Example 1.39. goes_to_gw usage, when use_partitions parameter + is 1 ... -if (goes_to_gw("1")) { +if (goes_to_gw("my_partition", "1", , "$var(gw_attrs)")) { sl_send_reply("403","Forbidden"); exit; } ... -1.4.6. is_from_gw( [type, [flag]]) +1.4.6. is_from_gw([partition','] [type], [flag], [gw_attrs_pvar]) - The function checks if the sender of the message is a gateway - from a certain group. + The function checks if the sender of the message (its source + IP) is a gateway from a certain group. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and ONREPLY_ROUTE. - The function can take two optional parameters: - * type (optional) - GW/destination type to be checked; a - negative value (ex: -1) means match any group; + If you set use_partitions parameter to 1 you must supply the + partition (the partition becomes mandatory) in which the + gateways have been defined. + + If use_partitions parameter is 0 all parameters are optional. + Any of them may be ignored, provided the necessary separation + marks "," are properly placed. + * partition (mandatory if use_partitions parameter is 1, + otherwise it will be omitted altogether) - Partition + containing the destination/gw to be checked. + * type (optional) - GW/destination type to be checked; when + omitting this parameter or specifying a negative value i.e. + "-1", matching will be done against all groups * flags (optional) - what operations should be performed when a GW matches: + 's' (Strip) - apply to the username of RURI the strip defined by the GW + 'p' (Prefix) - apply to the username of RURI the prefix defined by the GW - + 'a' (Attributes) - return the attributes string - defined by the GW into gw_attrs_avp AVP + 'i' (Gateway ID) - return the gateway id into gw_id_avp AVP + 'n' (Ignore port) - ignores port number during matching + + 'c' (Carrier ID) - return the carrier id into + carrier_id_avp AVP + * gw_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched gateway. - Example 1.31. is_from_gw usage + Example 1.40. is_from_gw usage when use_partitions is 0 ... if (is_from_gw("3","1") { } ... -1.4.7. dr_is_gw(src_pv, [type, [flag]]) + Example 1.41. is_from_gw usage when use_partitions is 1 +... +if (is_from_gw("my_partition","3","1") { +} +... + +1.4.7. dr_is_gw([partition,] src_avp, [type], [flag], +[gw_attrs_pvar]) The function checks if the ip address in pvar src_pv is a gateway from a certain group. @@ -891,27 +1223,44 @@ if (is_from_gw("3","1") { FAILURE_ROUTE, BRANCH_ROUTE, LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE and EVENT_ROUTE. + If you set use_partitions parameter to 1 you must supply the + partition (the partition becomes mandatory) in which the + gateways have been defined. + Meaning of the parameters is as follows: - * src_pv (mandatory) - pvar containing SIP URI. May be a - script var or avp. - * type (optional) - GW/destination type to be checked; a - negative value (ex: -1) means match any group; + * partition (mandatory if use_partitions parameter is 1, + otherwise it will be omitted altogether) - Partition + containing the destinations/gateways to be checked. + * src_avp (mandatory) - avp containing a SIP URI. Does not + support other OpenSIPS pseudo-variables. + * type (optional) - GW/destination type to be checked; when + omitting this parameter or specifying a negative value i.e. + "-1", matching will be done against all groups * flags (optional) - what operations should be performed when a GW matches: + 's' (Strip) - apply to the username of RURI the strip defined by the GW + 'p' (Prefix) - apply to the username of RURI the prefix defined by the GW - + 'a' (Attributes) - return the attributes string - defined by the GW into gw_attrs_avp pvar + 'i' (Gateway ID) - return the gateway id into gw_id_avp pvar + 'n' (Ignore port) - ignores port number + + 'c' (Carrier ID) - return the carrier id into + carrier_id_avp AVP + * gw_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched gateway. - Example 1.32. dr_is_gw usage + Example 1.42. dr_is_gw usage when use_partitions is 0 ... if (dr_is_gw("$avp(uac)","3") { } +... + + Example 1.43. dr_is_gw usage when use_partitions is 1 +... +if (dr_is_gw("my_partition","$avp(uac)","3") { +} ... 1.4.8. dr_disable() @@ -924,82 +1273,211 @@ if (dr_is_gw("$avp(uac)","3") { This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.33. dr_disable() usage + If you set use_partitions parameter to 1 you must supply the + partition (the partition becomes mandatory) in which the + gateway to be disabled is defined. + * partition (mandatory if use_partitions parameter is 1, + otherwise it will be omitted altogether) - Partition + containing the destination/gateway to be disabled. + + Example 1.44. dr_disable() usage when use_partitions is 0 ... if (t_check_status("(408)|(5[0-9][0-9])")) { dr_disable(); } +... + + Example 1.45. dr_disable() usage when use_partitions is 1 +... +if (t_check_status("(408)|(5[0-9][0-9])")) { + dr_disable("my_partition"); + +} + ... 1.5. Exported MI Functions 1.5.1. dr_reload - Command to reload routing rules from database. + Command to reload routing rules from database. If + use_partitions is set to 1 you can reload just a partition + given a parameter, if no parameter is supplied then all the + partitions will be reloaded. - It takes no parameter. + If use_partitions is 0 it takes no parameter. MI FIFO Command Format: :dr_reload:fifo_reply + partition_name (optional) _empty_line_ 1.5.2. dr_gw_status Gets or sets the status (enabled or disabled) of a gateway. The - function may take from 0 to 2 parameters. If none, it will list - all gateways along with their status. If one parameter is - provided, that must be the id of a gateway and the function - will return the status of that gateway. If 2 parameters are - provided, first must be the ID of the ID of a GW and the second - must be the new status to be forced for that GW (0 - disable, 1 - - enable). + function may take from 0 to 3 parameters. + * if use_partitions is set to 0 - if no parameter is + provided, it will list all gateways along with their + status. If one parameter is provided, that must be the id + of a gateway and the function will return the status of + that gateway. If 2 parameters are provided, first must be + the ID of the ID of a GW and the second must be the new + status to be forced for that GW (0 - disable, 1 - enable). + * if use_partitions is set to 1 - the first parameter must be + the partition (the partition is mandatory). If just one + parameter is provided it will the display the statuses of + all the gateways in the given partition. If two parameters + are provided, the first must be the partition, and the + second must be the gateway Id. If three parameters are + provided, the first must be the partition, the second must + be the gateway and the third will be the new status to be + forced for tat GW (0 - disable, 1 - enable) MI FIFO Command Format: :dr_gw_status:_reply_fifo_file_ + partition_name (mandatory if use_partitions is 1, otherw +ise will be omitted altogether) GW_id status (optional) _empty_line_ - Example 1.34. dr_gw_status usage + Example 1.46. dr_gw_status usage when use_partitions is set to + 0 $ ./opensipsctl fifo dr_gw_status 2 -Enabled:: no -$ ./opensipsctl fifo dr_gw_status 2 1 +State:: Active +$ ./opensipsctl fifo dr_gw_status 2 0 $ ./opensipsctl fifo dr_gw_status 2 -Enabled:: yes +Enabled:: Disabled MI +$ ./opensipsctl fifo dr_gw_status 3 +Enabled:: Inactive + + Example 1.47. dr_gw_status usage when use_partitionsis set to 1 +$ ./opensipsctl fifo dr_gw_status part_1 my_gw +State:: Active +$ ./opensipsctl fifo dr_gw_status my_partition 3 0 +$ ./opensipsctl fifo dr_gw_status partition7 dsbl_gw 2 +Enabled:: Disabled MI +$ ./opensipsctl fifo dr_gw_status partition8 gw3 +Enabled:: Inactive 1.5.3. dr_carrier_status Gets or sets the status (enabled or disabled) of a carrier. The - function may take from 0 to 2 parameters. If none, it will list - all carriers along with their status. If one parameter is - provided, that must be the id of a carrier and the function - will return the status of that carrier. If 2 parameters are - provided, first must be the ID of the ID of a carrier and the - second must be the new status to be forced for that carrier (0 - - disable, 1 - enable). + function may take from 0 to 3 parameters. + * if use_partition is set to 0 - if no parameter is provided + it will list all the carriers along with their status. If + one parameter is provided, that must be the id of carrier + and the function will return the status of that carrier. If + 2 parameters are provided, first must be the Id of a + carrier and the second must be the new status to be forced + for that carrier + * if use_partition is set to 1 - the first parameter must be + the partition (the partition becomes mandatory). If one + parameter is supplied, it will be the partition, and it + will display the statuses of the carriers contained in that + partition. If two parameters are supplied, the second must + be the carrierId, and the command will display the status + of the selected carrier. If three parameters are supplied, + the first two will be the partition name and the carrierId + while the third parameter will be the new status to be + forced for that carrier. MI FIFO Command Format: :dr_carrier_status:_reply_fifo_file_ + partition_name (mandatory if use_partition is 1, otherwi +se it will be omitted) carrier_id status (optional) _empty_line_ - Example 1.35. dr_carrier_status usage + Example 1.48. dr_carrier_status usage when use_partitions is 0 $ ./opensipsctl fifo dr_carrier_status CR1 Enabled:: no $ ./opensipsctl fifo dr_carrier_status CR1 1 $ ./opensipsctl fifo dr_carrier_status CR1 Enabled:: yes -1.6. Installation + Example 1.49. dr_carrier_status usage when use_partitions is 1 +$ ./opensipsctl fifo dr_carrier_status my_partition CR1 +Enabled:: no +$ ./opensipsctl fifo dr_carrier_status partition_1 CR1 1 +$ ./opensipsctl fifo dr_carrier_status partition_3 CR1 +Enabled:: yes + +1.5.4. dr_reload_status + + Gets the time of the last reload for any partition. The + function may take at most one parameter. + * if use_partition is set to 0 - the function doesn't receive + any parameter. It will list the date of the last reload for + the default (and only) partition. + * if use_partition is set to 1 - if no parameter is supplied + it will list the time of the last update for every + partition. If one parameter is supplied, then this must be + the partition name, and the function will list the time of + the last reload for that given partition. + + MI FIFO Command Format: + :dr_reload_status:_reply_fifo_file_ + partition_name (if use_partition is 1 it may be omitted, + but if use_partition +is 0 it must be omitted) + _empty_line_ - The module requires 4 table in OpenSIPS database: dr_groups, - dr_gateways, dr_carriers, dr_rules. The SQL syntax to create - them can be found in drouting-create.sql script in the database - directories in the opensips/scripts folder. You can also find - the complete database documentation on the project webpage, + Example 1.50. dr_reload_status usage when use_partitions is 0 +$ ./opensipsctl fifo dr_reload_status +Date:: Tue Aug 12 12:26:00 2014 + + Example 1.51. dr_reload_status usage when use_partitions is 1 +$ ./opensipsctl fifo dr_reload_status +Partition:: part_test Date=Tue Aug 12 12:24:13 2014 +Partition:: part_2 Date=Tue Aug 12 12:24:13 2014 +$ ./opensipsctl fifo dr_reload_status part_test +Partition:: part_test Date=Tue Aug 12 12:24:13 2014 + +1.5.5. dr_number_routing + + Gets the matched prefix along with the list of the gateways / + carriers to which a number would be routed when using the + do_routing function + * if use_partition is set to 1 the function will have 3 + parameters: + + partition name + + group id - the group id of the rules to check against + + number - the number to test against + * if use_partition is set to 0 the function will have 2 + parameters: + + group id - the group id of the rules to check against + + number - the number to test against + + Note: The group id may be omitted - just as with the do_routing + function. + +1.6. Exported Events + +1.6.1. E_DROUTING_STATUS + + This event is raised when the module changes the state of a + gateway, either through MI or probing. + + Parameters: + * gwid - the gateway identifier. + * address - the address of the gateway. + * status - disabled MI if the gateway was disabled using MI + commands, probing if the gateway is being pinged, inactive + if it was disabled from the script or active if the gateway + is enabled. + +1.7. Installation + + The module requires 4 tables in the OpenSIPS database: + dr_groups, dr_gateways, dr_carriers, dr_rules. The SQL syntax + to create them can be found in the drouting-create.sql script, + located in the database directories of the opensips/scripts + folder. You can also find the complete database documentation + on the project webpage, http://www.opensips.org/html/docs/db/db-schema-devel.html. Chapter 2. Developer Guide diff --git a/modules/drouting/doc/drouting_admin.xml b/modules/drouting/doc/drouting_admin.xml index c6232479a41..3a4b941f45b 100644 --- a/modules/drouting/doc/drouting_admin.xml +++ b/modules/drouting/doc/drouting_admin.xml @@ -2,7 +2,7 @@ &adminguide; - +
Overview
@@ -11,7 +11,7 @@ Dynamic Routing is a module for selecting (based on multiple criteria) the best gateway/destination to be used for delivering a certain call. Least Cost Routing (LCR) is a special case of dynamic - routing - when the rules are ordered based on costs. Dynamic Routing + routing - when the rules are ordered based on costs. Dynamic Routing comes with many features regarding routing rule selection: @@ -50,15 +50,15 @@ - routing info (destinations, carriers, rules, groups) are stored in a + The routing info (destinations, carriers, rules, groups) is stored in a database and loaded into memory at start up time; reload at runtime via - an Management Interface command. + a Management Interface command. - weigth-based or random selection of the destinations (from a rule or + weight-based or random selection of the destinations (from a rule or from a carrier), failure detection of gateways (with switching to next available gateway). @@ -70,30 +70,41 @@ speed/time and memory consumption penalties - + - script integration - Pseudo variables support in functions; scripting + script integration - Pseudo-variable support in functions; scripting route triggering when rules are matched - + - bidirectional behavior - inbound and outbound processing (strip and + bidirectional behavior - inbound and outbound processing (strip and prefixing when sending and receiving from a destination/GW) - blacklisting - the module allows definition of backlists based on the - destination IPs. This blacklists are to be used to prevent malicious + blacklisting - the module allows definition of blacklists based on the + destination IPs. This blacklists are to be used to prevent malicious forwarding to GWs (based on DNS lookups) when the script logic does none-GE forwarding (like foreign domains). + + + loading routing information from multiple databases - the gateways, rules, groups and + carriers can be grouped by partitions, and each partition may be loaded + from different databases/tables. This makes the routing process partition + based. In order to be able to use a table from a partition, its name must + be found in the "version" table belonging to the database defined in the + partition's db_url. + + +
@@ -105,8 +116,7 @@ when dealing with a large number of routing rules. - The tests were performed with a set of 383000 rules and to values were - measured: + The tests were performed with a set of 383000 rules and measured: time to load from DB @@ -114,13 +124,13 @@ The time to load was varying between 4 seconds and 8 seconds, depending of - the caching of the DB client - the first load was the slowest (as the DB - query hits the disk drive); the following are faster as data is already + the caching of the DB client - the first load was the slowest (as the DB + query hits the disk drive); the following are faster as data is already cached in the DB client. So technically speaking, the time to load (without the time to query which is DB type dependent) is ~4 seconds - After loading the data into shared memory ~ 96M of memory were used + After loading the data into shared memory ~ 96M of memory were used exclusively for the DR data.
@@ -130,7 +140,7 @@ Dynamic Routing Concepts DR engine uses several concepts in order to define how the routing - should be done (describing all the dependecies between destinations + should be done (describing all the dependencies between destinations and routing rules). @@ -139,9 +149,9 @@ These are the end SIP entities where actually the traffic needs to be sent after routing. They are stored in a table called dr_gateways. - Gateway addresses are stored in a separate table because of need to access them + Gateway addresses are stored in a separate table because of the need to access them independent of Dynamic Routing processing (e.g., adding/ removing gateway PRI - prefix before/after performing other operation -- receiving/relaying to gateway). + prefix before/after performing other operation -- receiving/relaying to gateway). In DR, a gateway is defined by: @@ -170,7 +180,7 @@ Carriers The carrier concept is used if you need to group gateways in order to - have a better control on how the GWs will be used by DR rules; like + have a better control on how the GWs will be used by DR rules; like in what order the GWs will be used. @@ -188,7 +198,7 @@ flags : 0x1 - use weight for sorting the list and not definition order; 0x2 - use only the first gateway from the carrier - (depending on the sorting); 0x4 - disable the usage of this + (depending on the sorting); 0x4 - disable the usage of this carrier attributes (not used by DR engine, but only pushed to script level when routing to this carrier) @@ -202,12 +212,12 @@
Routing Rules - These are the actual rule which control the routing - like based on - different criterias (prefix, time, priority, etc) they will decide + These are the actual rules which control the routing. Using + different criterias (prefix, time, priority, etc), they will decide to which gateways the call will be sent. - Default name for the table storing rule definitions is + Default name for the table storing rule definitions is dr_rules. @@ -216,26 +226,26 @@ group (list of numbers) - rules can be grouped (a rule may belong to multiple groups in the same time ) and you can - use only a certian group at a point; like having a premium or - standard or interstate or - intrastate groups of rules to be used in different + use only a certain group at a point; like having a premium or + standard or interstate or + intrastate groups of rules to be used in different cases prefix (string with digits only) - prefix to be used for matching this rule (longest prefix matching) time validity (time recurrence string) - when this rule is valid from time point of view (see RFC 2445) - priority (number) - prority off the rule - higher value, + priority (number) - priority of the rule - higher value, higher priority (see rule section alg) - script route ID (string) - if defined, then execute the + script route ID (string) - if defined, then execute the route with the specified ID when this rule is matched. That's it, a route - which can be used to perform custom operations on message. NOTE that no + which can be used to perform custom operations on message. NOTE that no modification is performed at signaling level and you must NOT do - any signalling operations in that script route + any signaling operations in that script route list of GWs/carriers (string) - a comma separated list - of gateways or carriers (defined by IDs) to be used for this rule; the + of gateways or carriers (defined by IDs) to be used for this rule; the carrier IDs are prefixed with # sign. For each ID (GW or - carrier) you may specify a weight. For how this list will be interpreted - (as order) see the rule selection section. Example of list: + carrier) you may specify a weight. For how this list will be interpreted + (as order) see the rule selection section. Example of list: gw1,gw4,#cr3 or gw1=10,gw4=10,#cr3=80 attributes (not used by DR engine, but only pushed @@ -247,11 +257,11 @@ - A date-time expression that defines the time recurrence to match for - current rule. Time recurrences are based closely on the specification - of recurring intervals of time in the Internet Calendaring and Scheduling + A date-time expression that defines the time recurrence to be matched for + current rule. Time recurrences are based closely on the recurring time + intervals from the Internet Calendaring and Scheduling Core Object Specification (calendar COS), RFC 2445. The set of attributes - used in routing rule specification is subset of time recurrence attributes. + used in routing rule specification is a subset of time recurrence attributes. The value stored in database has the format of: @@ -277,15 +287,15 @@ - the module discovers the routing group of the originating user. This + the module discovers the routing group of the originating user. This step is skipped if a routing group is passed from the script as parameter. - once the group is known, in the subset of the rules for this group the + once the group is known, in the subset of the rules for this group the module looks for the one that matches the destination based on "prefix" - column. The set of rules with the longest prefix is chosen. If no digit + column. The set of rules with the longest prefix is chosen. If no digit from the prefix matches, the default rules are used (rules with no prefix) @@ -298,18 +308,17 @@ - Once found the rule, it may contain a route ID to execute. If a certain + Once found the rule, it may contain a route ID to execute. If a certain flag is set, then the processing is stopped after executing the route block. - The rule must contain a chain of gateways and carriers. The module will - execute serial forking for each address in chain (in which order the - destinations will be tried, depends on the defintion order or depends on - the weights (weights selection must be enabled). The next address in chain - is used only if the previously has failed. + The rule must contain a chain of gateways and carriers. The module will + execute serial forking for each address in the chain (ordering is either done + by simply using the definition order or it may weight-based - weight selection must be + enabled). The next address in chain is used only if the previously has failed. @@ -322,7 +331,7 @@ If no rule is found to match the selection criteria an default action must - be taken (e.g., error response sent back). If the gateway in the chain has + be taken (e.g., error response sent back). If the gateway in the chain has no prefix the request is forwarded without adding any prefix to the request URI. @@ -345,7 +354,7 @@ (1) - probing only when the destination is - in disabled mode (disabling via MI command will competely stop the + in disabled mode (disabling via MI command will completely stop the probing also). The destination will be automatically re-enabled when the probing will succeed next time; @@ -416,7 +425,7 @@
- +
Exported Parameters
@@ -425,14 +434,14 @@ The database url. - Default value is NULL. + Default value is NULL. Set <varname>db_url</varname> parameter ... -modparam("drouting", "db_url", +modparam("drouting", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") ... @@ -497,11 +506,11 @@ modparam("drouting", "drg_table", "groups")
<varname>drc_table</varname>(str) - The name of the db table storing definitions of the carriers that will + The name of the db table storing definitions of the carriers that will be used directly by the routing rules. - Default value is dr_gw_lists. + Default value is dr_carriers. @@ -517,11 +526,13 @@ modparam("drouting", "drc_table", "my_dr_carriers")
<varname>ruri_avp</varname> (str) - The name of the avp for storing Request URIs to be later used + The name of the avp for storing Request URIs to be later used (alternative destiantions for the current one). - Default value is $avp(0xad346b2f). + Default value is $avp(___dr_ruri__) if use_partitions parameter is 0 + or $avp(___dr_ruri__partition_name) where partition_name is the name of the partition + containing the AVP (as fetched from the database) if use_partitions parameter is 1. @@ -540,12 +551,14 @@ modparam("drouting", "ruri_avp", '$avp(33)') <varname>gw_id_avp</varname> (str) The name of the avp for storing the id of the current selected - gateway/destination - once a new destination is selected (via the + gateway/destination - once a new destination is selected (via the use_next_gw() function), the AVP will be updated with the ID of the new selected gateway/destination. - Default value is $avp(0xad346b30). + Default value is $avp(___dr_gw_id__) if use_partitions parameter is 0 + or $avp(___dr_gw_id__partition_name) where partition_name is the name of the partition + containing the AVP (as fetched from the database) if use_partitions parameter is 1. @@ -559,35 +572,11 @@ modparam("drouting", "gw_id_avp", '$avp(334)')
- -
- <varname>gw_attrs_avp</varname> (str) - - The name of the avp for storing the attributes of the current selected - destination/gateway - once a new destination is selected (via the - use_next_gw() function), the AVP will be updated with the attrs of the - new used destination. - - - Default value is NULL. - - - - Set <varname>gw_attrs_avp</varname> parameter - -... -modparam("drouting", "gw_attrs_avp", '$avp(gw_attrs)') -modparam("drouting", "gw_attrs_avp", '$avp(67)') -... - - -
-
<varname>gw_priprefix_avp</varname> (str) The name of the avp for storing the PRI prefix of the current selected - destination/gateway - once a new destination is selected (via the + destination/gateway - once a new destination is selected (via the use_next_gw() function), the AVP will be updated with the PRI prefix of the new used destination. @@ -627,23 +616,21 @@ modparam("drouting", "rule_id_avp", '$avp(335)')
-
- <varname>rule_attrs_avp</varname> (str) + <varname>rule_prefix_avp</varname> (str) - The name of the avp for storing the attributes of the current matched - routing rule (see dr_rules table). + The actual prefix that matched the routing rule (the part from RURI + username that matched the routing rule). Default value is NULL. - Set <varname>rule_attrs_avp</varname> parameter + Set <varname>rule_prefix_avp</varname> parameter ... -modparam("drouting", "rule_attrs_avp", '$avp(rule_attrs)') -modparam("drouting", "rule_attrs_avp", '$avp(66)') +modparam("drouting", "rule_prefix_avp", '$avp(dr_prefix)') ... @@ -651,20 +638,20 @@ modparam("drouting", "rule_attrs_avp", '$avp(66)')
- <varname>rule_prefix_avp</varname> (str) + <varname>carrier_id_avp</varname> (str) - The actual prefix that matched the routing rule (the part from RURI - username that matched the routing rule). + AVP to be populate with the ID string for the carrier the + current GW belongs to. Default value is NULL. - Set <varname>rule_prefix_avp</varname> parameter + Set <varname>carrier_id_avp</varname> parameter ... -modparam("drouting", "rule_prefix_avp", '$avp(dr_prefix)') +modparam("drouting", "carrier_id_avp", '$avp(carrier_id)') ... @@ -672,51 +659,78 @@ modparam("drouting", "rule_prefix_avp", '$avp(dr_prefix)')
- <varname>carrier_id_avp</varname> (str) + <varname>gw_sock_avp</varname> (str) - AVP to be populate with the ID string for the carrier the - current GW belongs to. + The name of the avp for storing sockets for alternative destinations + defined by ruri_avp. - Default value is NULL. + Default value is $avp(___dr_sock__) if use_partitions parameter is 0 + or $avp(___dr_sock__partition_name) where partition_name is the name of the partition + containing the AVP (as fetched from the database) if use_partitions parameter is 1. - Set <varname>carrier_id_avp</varname> parameter + Set <varname>gw_sock_avp</varname> parameter ... -modparam("drouting", "carrier_id_avp", '$avp(carrier_id)') +modparam("drouting", "gw_sock_avp", '$avp(dr_sock)') +modparam("drouting", "gw_sock_avp", '$avp(77)') ...
- -
- <varname>carrier_attrs_avp</varname> (str) +
+ <varname>gw_attrs_avp</varname> (str) - AVP to be populate with the attributes string for the carrier the - current GW belongs to. + The name of the avp for storing GW attrs in case they are requested at least + once in the script. - Default value is NULL. + Default value is $avp(___dr_gw_att__) if use_partitions parameter is 0 + or $avp(___dr_gw_att__partition_name) where partition_name is the name of the partition + containing the AVP (as fetched from the database) if use_partitions parameter is 1. - Set <varname>carrier_attrs_avp</varname> parameter + Set <varname>gw_attrs_avp</varname> parameter ... -modparam("drouting", "carrier_attrs_avp", '$avp(carrier_attrs)') +modparam("drouting", "gw_attrs_avp", '$avp(dr_attrs_gw)') +modparam("drouting", "gw_attrs_avp", '$avp(11)') ...
+
+ <varname>rule_attrs_avp</varname> (str) + + The name of the avp for storing rule attrs in case they are requested at least + once in the script. + + + Default value is $avp(___dr_ru_att__) if use_partitions parameter is 0 + or $avp(___dr_ru_att__partition_name) where partition_name is the name of the partition + containing the AVP (as fetched from the database) if use_partitions parameter is 1. + + + + Set <varname>rule_attrs_avp</varname> parameter + +... +modparam("drouting", "rule_attrs_avp", '$avp(dr_rule_attr)') +modparam("drouting", "rule_attrs_avp", '$avp(11)') +... + + +
<varname>define_blacklist</varname> (str) - Defines a backlist based on a list of GW types - the list will contain + Defines a blacklist based on a list of GW types - the list will contain the IPs (no port, all protocols) of the GWs with the specified types. @@ -760,8 +774,8 @@ modparam("drouting", "default_group", 4)
<varname>force_dns</varname> (int) - Force DNS resolving of GW/destination names (if not IPs) during - startup. If not enabled, the GW name will be blindly used during + Force DNS resolving of GW/destination names (if not IPs) during + startup. If not enabled, the GW name will be blindly used during routing. @@ -778,6 +792,27 @@ modparam("drouting", "force_dns", 0)
+
+ <varname>persistent_state</varname> (int) + + Specifies whether the state column + should be loaded at startup and flushed during runtime or not. + + + Default value is 1 (enabled). + + + + Set the <varname>persistent_state</varname> parameter + +... +# disable all DB operations with the state of a gateway +modparam("drouting", "persistent_state", 0) +... + + +
+
<varname>probing_interval</varname> (integer) @@ -940,64 +975,189 @@ modparam("drouting", "drg_grpid_col", "grpid")
+ +
+ <varname>use_partitions</varname> (int) + + Flag to configure whether to use partitions for routing. If this + flag is set then the db_partitions_url and + db_partitions_table + variables become mandatory. + + + Default value is 0. + + + + Set <varname>use_partitions</varname> parameter + +... +modparam("drouting", "use_partitions", 1) +... + + +
+ +
+ <varname>db_partitions_url</varname> (int) + + The url to the database containing partition-specific + information. (partition-specific information includes + partition name, url to the database where information about + the partition is preserved, the names of the tables in which it + is preserved and the AVPs that can be accessed using the .cfg + script). The use_partitions parameter + must be set to 1. + + + Default value is "NULL". + + + + Set <varname>db_partitions_url</varname> parameter + +... +modparam("drouting", "db_partitions_url", "mysql://user:password@localhost/opensips_partitions") +... + + +
+ +
+ <varname>db_partitions_table</varname> (int) + + The name of the table containing partition definitions. To be + used with use_partitions and db_partitions_url. + + + Default value is dr_partitions. + + + + Set <varname>db_partitions_table</varname> parameter + +... +modparam("drouting", "db_partitions_table", "partition_defs") +... + + +
+
Exported Functions
- <function moreinfo="none">do_routing([[[groupID],flags],gw_whitelist])</function> + <function moreinfo="none">do_routing([part_and_or_groupID], [flags], [gw_whitelist], [rule_attrs_pvar], [gw_attrs_pvar], [carrier_attrs_pvar])</function> - Function to trigger routing of the message according to the + Function to trigger routing of the message according to the rules in the database table and the configured parameters. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and LOCAL_ROUTE. - The function can take two optional parameters: + If you set use_partitions to 1 the + part_or_groupID parameter becomes mandatory. + + + All parameters are optional. Any of them may be ignored, provided + the necessary separation marks "," are properly placed. - groupID - the routing group the - caller belongs to - this may be a static numerical - value or an AVP specification (value must be numerical - type, string types are ignored!). If none specified, the - function will automatically try to query the dr_group - table to get this information; + + part_and_or_groupID - Specifies the group of the caller + for routing purposes. Depending on the value of the use_partitions + parameter, it contains: + + + + + the routing group the caller belongs to if use_partitions + is 0 - this may be a statical numerical value or an AVP specification (value + must be numerical type, string types are ignored!). If none specified the + function will automatically try to query the dr_group table to get this information + + + + + the partition and routing group the caller belongs to, the format is: + "partition':'[groupID]" if use_partitions + parameter is 1 - both the partition name and the groupId may be statical + values or AVP specifications. If no group is specified the function will + try to query the dr_group table for the given partition to get this information. + + + - flags - Controlls the behavior of the + + flags - Controls the behavior of the function. Possible flags are: + - W - Instead of using the destination + + W - Instead of using the destination (from the rule definition) in the given order, sort them based on their weight. + - F - Enable rule fallback; normally + + F - Enable rule fallback; normally the engine is using a single rule for routing a call; by - setting this flag, the enging will fallback and use - rules with less priority or shorter prefix when all the + setting this flag, the engine will fallback and use + rules with less priority or shorter prefix when all the destination from the current rules failed. + - L - Do strict lenght matching over the - prefix - actually DR engine will do full number maching and + + L - Do strict length matching over the + prefix - actually DR engine will do full number matching and not prefix matching anymore. + - C - Only check if the dialed number + + C - Only check if the dialed number matches any routing rule, without loading / applying any routing info (no GW is set, the RURI is not altered) + - gw_whitelist - a comma separated white - list of gateways. This will force routing over this list of - carriers or gateways (a subset of what found in the prefix rules). + + gw_whitelist - a comma separated white + list of gateways. This will force routing over, at most, this + list of carriers or gateways (in other words, the whitelist + will be intersected with the results of the search through the rules). + + + + + rule_attrs_pvar (output, optional)- a writable + pseudo-variable which will be populated with the attributes + of the matched dynamic routing rule. + + + + + gw_attrs_pvar (output, optional) + - a writable pseudo-variable which will be populated with + the attributes of the matched gateway. + + + + + carrier_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched carrier. + @@ -1006,20 +1166,29 @@ modparam("drouting", "drg_grpid_col", "grpid") <function>do_routing</function> usage ... -# all groups, sort on order +# all groups, sort on order, use_partitions is 0 do_routing(); ... -# group id 0, sort on order +# all groups, sort on order, use_partitions is 1, route by partition named "part" +do_routing("part:"); +... +# group id 0, sort on order, use_partitions is 0 do_routing("0"); ... -# group id from $avp(10), sort on order +# group id 0, sort on order, use_partitions is 1, route by partition named "part" +do_routing("part:0"); +... +# group id from $avp(10), sort on order, use_partitions is 0 do_routing("$avp(10)"); ... -# all groups, sort on weights -do_routing("","W"); +# all groups, sort on weights, use_partitions is 0 +do_routing("", "W"); +... +# all groups, use_partitions is 1, partition and group supplied by AVPs, do strict length matching +do_routing("$avp(partition):$avp(grp)","L") ... -# group id 2, sort on order, fallback rule -do_routing("2","F"); +# group id 2, sort on order, fallback rule and also return the gateway attributes +do_routing("2", "F", , , "$var(gw_attributes)"); ... @@ -1027,26 +1196,94 @@ do_routing("2","F");
- <function moreinfo="none">route_to_carrier(carrier_id)</function> + <function moreinfo="none">route_to_carrier(part_and_or_carrier_id, [gw_attrs_pvar], [carrier_attrs_pvar])</function> Function to trigger the direct routing to a given carrier. In this case the routing is not done prefix based, but carrier based (call will be - sent to the GWs of that carrier, based on carrier policy) + sent to the GWs of that carrier, based on carrier policy). This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and LOCAL_ROUTE.. - Function takes a single mandatory parameter, the ID of the carrier - to be used (variables are accepted). + If you set use_partitions parameter to 1 you must supply + the partition in which the carrier has been defined. + + + + + + part_and_or_carrier_id (mandatory): + + + + + the ID (name) of the carrier to be used, if use_partitions + parameter is 0; pseudo-variables are accepted. + + + + + the partition and carrier to be used, if use_partitions parameter + is 1. The format is "partition_name':'carrierId"; pseudo-variables are accepted. + + + + + + + gw_attrs_pvar (output, optional) + - a writable pseudo-variable which will be populated with + the attributes of the currently matched gateway of this carrier. + + + + + carrier_attrs_pvar (output, optional) + - a writable pseudo-variable which will be populated with the attributes + of this carrier. + + + - <function>route_to_carrier</function> usage + <function>route_to_carrier</function> usage when <varname>use_partitions</varname> + parameter is 0 ... -if ( route_to_carrier("my_top_carrier") ) { +if ( route_to_carrier("my_top_carrier", , "$var(carrier_att)") ) { + xlog("Routing to \"my_top_carrier\" - $var(carrier_att)\n"); + t_on_failure("next_gw"); + t_relay(); + exit; +} +... + + + + + <function>route_to_carrier</function> usage when <varname>use_partitions</varname> + parameter is 1 + +... +if ( route_to_carrier("my_partition:my_top_carrier", , "$var(carrier_att)") ) { + xlog("Routing to \"my_top_carrier\" - $var(carrier_att)\n"); + t_on_failure("next_gw"); + t_relay(); + exit; +} +... + + + + <function>route_to_carrier</function> usage when <varname>use_partitions</varname> + parameter is 1 with pseudovariables + +... +if ( route_to_carrier("$var(my_partition):$var(carrierId)") ) { + xlog("Routing to \"my_top_carrier\" - $var(carrier_att)\n"); t_on_failure("next_gw"); t_relay(); exit; @@ -1058,22 +1295,57 @@ if ( route_to_carrier("my_top_carrier") ) {
- <function moreinfo="none">route_to_gw(gw_id)</function> + <function moreinfo="none">route_to_gw(gw_id, [gw_attrs_pvar])</function> - Function to trigger the direct routing to a given gateway. Attributes - and per-gw preocessing will be available. + Function to trigger the direct routing to a given gateway (or list of gateways). + Attributes and per-gw processing will be available. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and LOCAL_ROUTE. - Function takes a single mandatory parameter, the ID of the gateway - to be used (variables are accepted). + If you set use_partitions parameter to 1 you must supply + the partition in which the gateway has been defined. + + + + + + gw_id (mandatory) - the list + of gateways to be used. + + + + a comma separated list of gateway ID's to be used, if + no use_partition parameter is 0. Pseudo-variables + are accepted. + + + + + the desired partition, followed by a comma separated list of gateway ID's + from that partition to be used, if use_partition parameter + is 1. The format is: "partition_name':'gwId1, gwId2, gwId3". Pseudo-variables + are accepted. + + + + + + + + gw_attrs_pvar (output, optional) + - a writable pseudo-variable which will be populated with + the attributes of the currently matched gateway. + + + - <function>route_to_gw</function> usage + <function>route_to_gw</function> usage when <varname>use_partition</varname> + parameter is 0 ... if ( route_to_gw("gw_europe") ) { @@ -1081,21 +1353,46 @@ if ( route_to_gw("gw_europe") ) { exit; } ... +if ( route_to_gw("gw1,gw2,gw3", "$var(gw_attrs)") ) { + xlog("Relaying to first gateway from our list - $var(gw_attrs)\n"); + t_relay(); + exit; +} +... + + + + + <function>route_to_gw</function> usage when <varname>use_partition</varname> + parameter is 1 + +... +if ( route_to_gw("my_partition:gw_europe") ) { + t_relay(); + exit; +} +... +if ( route_to_gw("my_partition:gw1,gw2,gw3", "$var(gw_attrs)") ) { + xlog("Relaying to first gateway from our list - $var(gw_attrs)\n"); + t_relay(); + exit; +} +...
- <function moreinfo="none">use_next_gw()/next_routing()</function> + <function moreinfo="none">use_next_gw([partition','] [rule_attrs_pvar], [gw_attrs_pvar], [carrier_attrs_pvar])/next_routing()</function> - The function takes the next available destination (set by do_routing, - as alternative destinations) and push it into RURI. Note that the + The function takes the next available destination (set by do_routing, + as alternative destinations) and pushes it into the RURI. Note that the function just sets the RURI (nothing more). - If a new RURI is set, the used destination is removed from the + If a new RURI is set, the used destination is removed from the pending set of alternative destinations. @@ -1104,8 +1401,46 @@ if ( route_to_gw("gw_europe") ) { The function returns true only if a new RURI was set. False is returned is no other alternative destinations are found or in case - of internal processing error. + of an internal processing error. It may take the following optional parameters: + + + If you set use_partitions parameter to 1 you must supply + the partition (the partition becomes mandatory) in which the gateways have been defined. + + + + + + partition (mandatory if use_partitions + parameter is 1, otherwise it will be omitted altogether) It is + the partition in which the gateways have been defined. + + + + + rule_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched dynamic routing rule. + + + + + gw_attrs_pvar (output, optional) + - a writable pseudo-variable which will be populated with + the attributes of the matched gateway. + + + + + carrier_attrs_pvar (output, optional) - a writable + pseudo-variable which will be populated with the attributes + of the matched carrier. + + + + + <function>use_next_gw</function> usage @@ -1115,16 +1450,43 @@ if (use_next_gw()) { exit; } ... +# Also fetch the carrier attributes, if any +if (use_next_gw(, , "$var(carrier_attrs)")) { + xlog("Carrier attributes of current gateway: $var(carrier_attrs)\n"); + t_relay(); + exit; +} +... + + + + + <function>use_next_gw</function> usage when <varname>use_partition</varname> + parameter is 1 + +... +if (use_next_gw("my_partition")) { + t_relay(); + exit; +} +... +# Also fetch the carrier attributes, if any +if (use_next_gw("my_partition", , "$var(carrier_attrs)")) { + xlog("Carrier attributes of current gateway: $var(carrier_attrs)\n"); + t_relay(); + exit; +} +...
- <function moreinfo="none">goes_to_gw([[type],flags])</function> + <function moreinfo="none">goes_to_gw([partition','] [type], [flags], [gw_attrs_pvar])</function> - Function returns true if the destination of the current request + Function returns true if the destination of the current request (destination URI or Request URI) points (as IP) to one of the gateways. There no DNS lookups done if the domain part of the URI is not an IP. @@ -1136,47 +1498,94 @@ if (use_next_gw()) { and LOCAL_ROUTE. - The function can take two optional parameters: + If you set use_partitions parameter to 1 you must supply + the partition (the partition becomes mandatory) in which the gateways have been defined. + + + If use_partitions parameter is 0 + all parameters are optional. Any of them may be ignored, provided + the necessary separation marks "," are properly placed. - type (optional) - GW/destination - type to be checked; a negative value (ex: -1) means - match any group; + + partition (mandatory if use_partitions + parameter is 1, otherwise it will be omitted altogether) - the name + of the partition containing the gateway/destination to be checked. + - flags (optional) - what operations + + type (optional) - GW/destination + type to be checked; when omitting this parameter or specifying + a negative value i.e. "-1", matching will be done against all groups + (in a given partition if use_partition parameter is 1; if + use_partitions is 1 the partition being mandatory at this + point, it is not possible to do matching against all the partitions) + + + + + flags (optional) - what operations should be performed when a GW matches: + - 's' (Strip) - apply to the + + 's' (Strip) - apply to the username of RURI the strip defined by the GW + - 'p' (Prefix) - apply to the + + 'p' (Prefix) - apply to the username of RURI the prefix defined by the GW + - 'a' (Attributes) - return - the attributes string defined by the GW into gw_attrs_avp - AVP - - - 'i' (Gateway ID) - return the + + 'i' (Gateway ID) - return the gateway id into gw_id_avp AVP + - 'n' (Ignore port) - ignores port + + 'n' (Ignore port) - ignores port number during matching + + + + + 'c' (Carrier ID) - return the + carrier id into carrier_id_avp AVP + + + + gw_attrs_pvar (output, optional) + - a writable pseudo-variable which will be populated with + the attributes of the matched gateway. + + - <function>goes_to_gw</function> usage + <function>goes_to_gw</function> usage when <varname>use_partitions</varname> parameter is 0 + +... +if (goes_to_gw("1", , "$var(gw_attrs)")) { + sl_send_reply("403","Forbidden"); + exit; +} +... + + + + <function>goes_to_gw</function> usage, when <varname>use_partitions</varname> parameter is 1 ... -if (goes_to_gw("1")) { +if (goes_to_gw("my_partition", "1", , "$var(gw_attrs)")) { sl_send_reply("403","Forbidden"); exit; } @@ -1187,67 +1596,110 @@ if (goes_to_gw("1")) {
- <function moreinfo="none">is_from_gw( [type, [flag]])</function> + <function moreinfo="none">is_from_gw([partition','] [type], [flag], [gw_attrs_pvar])</function> - The function checks if the sender of the message is a gateway - from a certain group. + The function checks if the sender of the message (its source IP) + is a gateway from a certain group. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE and ONREPLY_ROUTE. - The function can take two optional parameters: + If you set use_partitions parameter to 1 you must supply + the partition (the partition becomes mandatory) in which the gateways have been defined. + + + If use_partitions parameter is 0 + all parameters are optional. Any of them may be ignored, provided + the necessary separation marks "," are properly placed. - type (optional) - GW/destination - type to be checked; a negative value (ex: -1) means - match any group; + + partition (mandatory if use_partitions + parameter is 1, otherwise it will be omitted altogether) - Partition + containing the destination/gw to be checked. + - flags (optional) - what operations + + type (optional) - GW/destination + type to be checked; when omitting this parameter or specifying + a negative value i.e. "-1", matching will be done against all groups + + + + + flags (optional) - what operations should be performed when a GW matches: + - 's' (Strip) - apply to the + + 's' (Strip) - apply to the username of RURI the strip defined by the GW + - 'p' (Prefix) - apply to the + + 'p' (Prefix) - apply to the username of RURI the prefix defined by the GW + - 'a' (Attributes) - return - the attributes string defined by the GW into gw_attrs_avp - AVP - - - 'i' (Gateway ID) - return the + + 'i' (Gateway ID) - return the gateway id into gw_id_avp AVP + - 'n' (Ignore port) - ignores port + + 'n' (Ignore port) - ignores port number during matching + + + + + 'c' (Carrier ID) - return the + carrier id into carrier_id_avp AVP + + + + gw_attrs_pvar (output, optional) + - a writable pseudo-variable which will be populated with + the attributes of the matched gateway. + + - <function>is_from_gw</function> usage + <function>is_from_gw</function> usage when <varname>use_partitions</varname> is 0 ... if (is_from_gw("3","1") { } ... + + + + + <function>is_from_gw</function> usage when <varname>use_partitions</varname> is 1 + +... +if (is_from_gw("my_partition","3","1") { +} +...
- <function moreinfo="none">dr_is_gw(src_pv, [type, [flag]])</function> + <function moreinfo="none">dr_is_gw([partition,] src_avp, [type], [flag], [gw_attrs_pvar])</function> The function checks if the ip address in pvar src_pv is a gateway @@ -1257,51 +1709,94 @@ if (is_from_gw("3","1") { This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE and EVENT_ROUTE. + + If you set use_partitions parameter to 1 you must supply + the partition (the partition becomes mandatory) in which the gateways have been defined. + Meaning of the parameters is as follows: - src_pv (mandatory) - pvar containing SIP URI. - May be a script var or avp. + + partition (mandatory if use_partitions + parameter is 1, otherwise it will be omitted altogether) - Partition + containing the destinations/gateways to be checked. + - type (optional) - GW/destination - type to be checked; a negative value (ex: -1) means - match any group; + + src_avp (mandatory) - avp containing a SIP URI. + Does not support other OpenSIPS pseudo-variables. + - flags (optional) - what operations + + type (optional) - GW/destination + type to be checked; when omitting this parameter or specifying + a negative value i.e. "-1", matching will be done against all groups + + + + + flags (optional) - what operations should be performed when a GW matches: + - 's' (Strip) - apply to the + + 's' (Strip) - apply to the username of RURI the strip defined by the GW + - 'p' (Prefix) - apply to the + + 'p' (Prefix) - apply to the username of RURI the prefix defined by the GW + - 'a' (Attributes) - return the attributes string - defined by the GW into gw_attrs_avp pvar + + 'i' (Gateway ID) - return the gateway id into gw_id_avp pvar + - 'i' (Gateway ID) - return the gateway id into gw_id_avp pvar + + 'n' (Ignore port) - ignores port number + - 'n' (Ignore port) - ignores port number + + 'c' (Carrier ID) - return the + carrier id into carrier_id_avp AVP + + + + gw_attrs_pvar (output, optional) + - a writable pseudo-variable which will be populated with + the attributes of the matched gateway. + + - <function>dr_is_gw</function> usage + <function>dr_is_gw</function> usage when <varname>use_partitions</varname> is 0 ... if (dr_is_gw("$avp(uac)","3") { } ... + + + + <function>dr_is_gw</function> usage when <varname>use_partitions</varname> is 1 + +... +if (dr_is_gw("my_partition","$avp(uac)","3") { +} +...
@@ -1319,13 +1814,39 @@ if (dr_is_gw("$avp(uac)","3") { This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. + + If you set use_partitions parameter to 1 you must supply + the partition (the partition becomes mandatory) in which the gateway to be + disabled is defined. + + + + + partition (mandatory if use_partitions + parameter is 1, otherwise it will be omitted altogether) - Partition + containing the destination/gateway to be disabled. + + + - <function>dr_disable()</function> usage + <function>dr_disable()</function> usage when <varname>use_partitions</varname> is 0 ... if (t_check_status("(408)|(5[0-9][0-9])")) { dr_disable(); - + +} + +... + + + + <function>dr_disable()</function> usage when <varname>use_partitions</varname> is 1 + +... +if (t_check_status("(408)|(5[0-9][0-9])")) { + dr_disable("my_partition"); + } ... @@ -1342,10 +1863,12 @@ if (t_check_status("(408)|(5[0-9][0-9])")) { dr_reload - Command to reload routing rules from database. + Command to reload routing rules from database. If use_partitions is set to 1 + you can reload just a partition given a parameter, if no parameter is supplied then all the + partitions will be reloaded. - It takes no parameter. + If use_partitions is 0 it takes no parameter. @@ -1353,6 +1876,7 @@ if (t_check_status("(408)|(5[0-9][0-9])")) { :dr_reload:fifo_reply + partition_name (optional) _empty_line_
@@ -1361,30 +1885,65 @@ if (t_check_status("(408)|(5[0-9][0-9])")) { <varname>dr_gw_status</varname> Gets or sets the status (enabled or disabled) of a gateway. The - function may take from 0 to 2 parameters. If none, it will list all - gateways along with their status. If one parameter is provided, that - must be the id of a gateway and the function will return the status - of that gateway. If 2 parameters are provided, first must be the ID of - the ID of a GW and the second must be the new status to be forced for - that GW (0 - disable, 1 - enable). + function may take from 0 to 3 parameters. + + + + if use_partitions is set to 0 - if no parameter + is provided, it will list all + gateways along with their status. If one parameter is provided, that + must be the id of a gateway and the function will return the status + of that gateway. If 2 parameters are provided, first must be the ID of + the ID of a GW and the second must be the new status to be forced for + that GW (0 - disable, 1 - enable). + + + + + if use_partitions is set to 1 - the first parameter + must be the partition (the partition is mandatory). If just one parameter + is provided it will the display the statuses of all the gateways in the + given partition. If two parameters are provided, + the first must be the partition, and the second must be the gateway Id. If three + parameters are provided, the first must be the partition, the second must be the gateway + and the third will be the new status to be forced for tat GW (0 - disable, 1 - enable) + + + MI FIFO Command Format: :dr_gw_status:_reply_fifo_file_ + partition_name (mandatory if use_partitions is 1, otherwise will be omitted altogether) GW_id status (optional) _empty_line_ - <function>dr_gw_status</function> usage + <function>dr_gw_status</function> usage when <varname>use_partitions</varname> is set to 0 $ ./opensipsctl fifo dr_gw_status 2 -Enabled:: no -$ ./opensipsctl fifo dr_gw_status 2 1 +State:: Active +$ ./opensipsctl fifo dr_gw_status 2 0 $ ./opensipsctl fifo dr_gw_status 2 -Enabled:: yes +Enabled:: Disabled MI +$ ./opensipsctl fifo dr_gw_status 3 +Enabled:: Inactive + + + + + <function>dr_gw_status</function> usage when <varname>use_partitions</varname>is set to 1 + +$ ./opensipsctl fifo dr_gw_status part_1 my_gw +State:: Active +$ ./opensipsctl fifo dr_gw_status my_partition 3 0 +$ ./opensipsctl fifo dr_gw_status partition7 dsbl_gw 2 +Enabled:: Disabled MI +$ ./opensipsctl fifo dr_gw_status partition8 gw3 +Enabled:: Inactive
@@ -1393,44 +1952,196 @@ Enabled:: yes <varname>dr_carrier_status</varname> Gets or sets the status (enabled or disabled) of a carrier. The - function may take from 0 to 2 parameters. If none, it will list all - carriers along with their status. If one parameter is provided, that - must be the id of a carrier and the function will return the status - of that carrier. If 2 parameters are provided, first must be the ID of - the ID of a carrier and the second must be the new status to be - forced for that carrier (0 - disable, 1 - enable). + function may take from 0 to 3 parameters. + + + + if use_partition is set to 0 - if no parameter + is provided it will list all the carriers along with their status. If + one parameter is provided, that must be the id of carrier and the function + will return the status of that carrier. If 2 parameters are provided, first + must be the Id of a carrier and the second must be the new status to be + forced for that carrier + + + + + if use_partition is set to 1 - the first parameter + must be the partition (the partition becomes mandatory). If one parameter + is supplied, it will be the partition, and it will display the statuses + of the carriers contained in that partition. If two parameters are supplied, + the second must be the carrierId, and the command will display the status + of the selected carrier. If three parameters are supplied, the first two + will be the partition name and the carrierId while the third parameter will be + the new status to be forced for that carrier. + + + MI FIFO Command Format: :dr_carrier_status:_reply_fifo_file_ + partition_name (mandatory if use_partition is 1, otherwise it will be omitted) carrier_id status (optional) _empty_line_ - <function>dr_carrier_status</function> usage + <function>dr_carrier_status</function> usage when <varname>use_partitions</varname> is 0 $ ./opensipsctl fifo dr_carrier_status CR1 Enabled:: no $ ./opensipsctl fifo dr_carrier_status CR1 1 $ ./opensipsctl fifo dr_carrier_status CR1 Enabled:: yes + + + + <function>dr_carrier_status</function> usage when <varname>use_partitions</varname> is 1 + +$ ./opensipsctl fifo dr_carrier_status my_partition CR1 +Enabled:: no +$ ./opensipsctl fifo dr_carrier_status partition_1 CR1 1 +$ ./opensipsctl fifo dr_carrier_status partition_3 CR1 +Enabled:: yes
+
+ <varname>dr_reload_status</varname> + + Gets the time of the last reload for any partition. The function + may take at most one parameter. + + + + + if use_partition is set to 0 - the function + doesn't receive any parameter. It will list the date of the + last reload for the default (and only) partition. + + + + + if use_partition is set to 1 - if no parameter + is supplied it will list the time of the last update for every + partition. If one parameter is supplied, then this must be the + partition name, and the function will list the time of the last + reload for that given partition. + + + + + MI FIFO Command Format: + + + :dr_reload_status:_reply_fifo_file_ + partition_name (if use_partition is 1 it may be omitted, but if use_partition +is 0 it must be omitted) + _empty_line_ + + + <function>dr_reload_status</function> usage when <varname>use_partitions</varname> is 0 + +$ ./opensipsctl fifo dr_reload_status +Date:: Tue Aug 12 12:26:00 2014 + + + + <function>dr_reload_status</function> usage when <varname>use_partitions</varname> is 1 + +$ ./opensipsctl fifo dr_reload_status +Partition:: part_test Date=Tue Aug 12 12:24:13 2014 +Partition:: part_2 Date=Tue Aug 12 12:24:13 2014 +$ ./opensipsctl fifo dr_reload_status part_test +Partition:: part_test Date=Tue Aug 12 12:24:13 2014 + + +
+ +
+ <varname>dr_number_routing</varname> + + Gets the matched prefix along with the list of the gateways / carriers to which a number + would be routed when using the do_routing function + + + + + if use_partition is set to 1 the function + will have 3 parameters: + + + partition name + + + group id - the group id of the rules to check against + + + number - the number to test against + + + + + + + if use_partition is set to 0 the function will have 2 parameters: + + + group id - the group id of the rules to check against + + + number - the number to test against + + + + + + Note: The group id may be omitted - just as with the do_routing function. +
+
+ Exported Events +
+ + <function moreinfo="none">E_DROUTING_STATUS</function> + + + This event is raised when the module changes the state of a gateway, + either through MI or probing. + + Parameters: + + + gwid - the gateway identifier. + + + address - the address of the gateway. + + + status - disabled MI if + the gateway was disabled using MI commands, + probing if the gateway is being pinged, + inactive if it was disabled from the script or + active if the gateway is enabled. + + +
+
+ +
Installation - The module requires 4 table in OpenSIPS database: dr_groups, + The module requires 4 tables in the OpenSIPS database: dr_groups, dr_gateways, dr_carriers, dr_rules. The SQL syntax to create them can be - found in drouting-create.sql script in the database directories - in the opensips/scripts folder. You can also find the complete + found in the drouting-create.sql script, located in the database directories + of the opensips/scripts folder. You can also find the complete database documentation on the project webpage, &osipsdbdocslink;.
diff --git a/modules/drouting/dr_bl.c b/modules/drouting/dr_bl.c index 16305842e84..830e4546400 100644 --- a/modules/drouting/dr_bl.c +++ b/modules/drouting/dr_bl.c @@ -39,51 +39,96 @@ #include "../../trim.h" #include "prefix_tree.h" #include "dr_bl.h" +#include "dr_partitions.h" -static struct dr_bl *drbl_lists = NULL; +/* + * link list for black_list definitions + * obtained via modparam + */ -static char **bl_lists=NULL; -static unsigned int bl_lists_size = 0; +//extern int use_partitions; +typedef struct blk_list_raw { + char * def; + struct blk_list_raw * next; +}blk_list_raw_t; +static blk_list_raw_t *bl_lists = NULL, *bl_lists_end=NULL; +static struct dr_bl *drbl_lists = NULL; + int set_dr_bl( modparam_t type, void* val) { - bl_lists = pkg_realloc( bl_lists, (bl_lists_size+1)*sizeof(char*)); - if (bl_lists==NULL) { - LM_ERR("failed to realloc\n"); + blk_list_raw_t * new_bl_def = pkg_malloc(sizeof(blk_list_raw_t)); + if (new_bl_def==NULL) { + LM_ERR("failed to alloc element for blacklist (linked-list)\n"); return -1; } - bl_lists[bl_lists_size] = (char*)val; - bl_lists_size++; + memset(new_bl_def, 0, sizeof(blk_list_raw_t)); + new_bl_def->def = (char*)val; + + if( bl_lists==NULL ) { /* first time functions is called */ + bl_lists = new_bl_def; + bl_lists_end = bl_lists; + } else { /* the list is not empty. the function was called before */ + bl_lists_end->next = new_bl_def; + bl_lists_end =new_bl_def; + } return 0; } -int init_dr_bls(void) +int init_dr_bls(struct head_db * head_db_start) { - unsigned int i; struct dr_bl *drbl; str name; str val; - char *p; + str part_name; + char *p = NULL; + blk_list_raw_t *it_blk, *to_clean; + struct head_db * current_partition; if (bl_lists==NULL) return 0; + it_blk = bl_lists; - for( i=0 ; i\n",bl_lists[i]); + while( it_blk!=NULL ) { + LM_DBG("processing bl definition <%s>\n",it_blk->def); /* get name */ - p = strchr( bl_lists[i], '='); - if (p==NULL || p== bl_lists[i]) { - LM_ERR("blaclist definition <%s> has no name",bl_lists[i]); + if( use_partitions ) { + p = strchr(it_blk->def, ':'); + part_name.s = it_blk->def; + part_name.len = p-part_name.s; + if( p==NULL || p==it_blk->def ) { + LM_ERR("blacklist definition <%s> has no partition name\n", + it_blk->def); + return -1; + } + trim(&part_name); + p = NULL; + if( (current_partition = get_partition(&part_name))==NULL ) { + LM_ERR("could not find partition name <%.*s> from blacklist " + "definition <%s>\n", part_name.len, part_name.s, + it_blk->def); + return -1; + } + + } else { + current_partition = head_db_start; + if( current_partition == 0 ) { + LM_CRIT("Default partition not registered\n"); + } + } + p = strchr( it_blk->def, '='); + if (p==NULL || p== it_blk->def) { + LM_ERR("blacklist definition <%s> has no name",it_blk->def); return -1; } - name.s = bl_lists[i]; + name.s = it_blk->def; name.len = p - name.s; trim(&name); if (name.len==0) { - LM_ERR("empty name in blacklist definition <%s>\n",bl_lists[i]); + LM_ERR("empty name in blacklist definition <%s>\n",it_blk->def); return -1; } LM_DBG("found list name <%.*s>\n",name.len,name.s); @@ -98,7 +143,7 @@ int init_dr_bls(void) p++; do { if (drbl->no_types==MAX_TYPES_PER_BL) { - LM_ERR("too many types per rule <%s>\n",bl_lists[i]); + LM_ERR("too many types per rule <%s>\n",it_blk->def); shm_free(drbl); return -1; } @@ -112,7 +157,7 @@ int init_dr_bls(void) } trim(&val); if (val.len==0) { - LM_ERR("invalid types listing in <%s>\n",bl_lists[i]); + LM_ERR("invalid types listing in <%s>\n",it_blk->def); shm_free(drbl); return -1; } @@ -125,24 +170,35 @@ int init_dr_bls(void) drbl->no_types++; }while(p!=NULL); - pkg_free(bl_lists[i]); - bl_lists[i] = NULL; /* create backlist for it */ drbl->bl = create_bl_head( 131313, 0/*flags*/, NULL, NULL, &name); + drbl->part = current_partition; + + to_clean = it_blk; + it_blk = it_blk->next; + if (drbl->bl==NULL) { LM_ERR("failed to create bl <%.*s>\n",name.len,name.s); shm_free(drbl); return -1; } + if( to_clean ) { + if( to_clean->def ) { + pkg_free(to_clean->def); + } + memset( to_clean, 0, sizeof(blk_list_raw_t)); + pkg_free(to_clean); + } + /* link it */ drbl->next = drbl_lists; drbl_lists = drbl; } - pkg_free(bl_lists); bl_lists = NULL; + bl_lists_end = NULL; return 0; } @@ -173,34 +229,41 @@ int populate_dr_bls(pgw_t *pgwa) /* each bl list at a time */ for( drbl=drbl_lists ; drbl ; drbl = drbl->next ) { - drbl_first = drbl_last = NULL; - /* each type at a time */ - for ( i=0 ; ino_types ; i++ ) { - /* search in the GW list all GWs of this type */ - for( gw=pgwa ; gw ; gw=gw->next ) { - if (gw->type==drbl->types[i]) { - for ( j=0 ; jips_no ; j++ ) { - gw_net = mk_net_bitlen( &gw->ips[j], gw->ips[j].len*8); - if (gw_net==NULL) { - LM_ERR("failed to build net mask\n"); - continue; + if( drbl->part && (*drbl->part->rdata) && (*drbl->part->rdata)->pgw_l == pgwa) { /* check if + list applies to current + partition */ + drbl_first = drbl_last = NULL; + /* each type at a time */ + for ( i=0 ; ino_types ; i++ ) { + /* search in the GW list all GWs of this type */ + for( gw=pgwa ; gw ; gw=gw->next ) { + if (gw->type==drbl->types[i]) { + for ( j=0 ; jips_no ; j++ ) { + gw_net = mk_net_bitlen( &gw->ips[j], gw->ips[j].len*8); + if (gw_net==NULL) { + LM_ERR("failed to build net mask\n"); + continue; + } + /* add this destination to the BL */ + if( add_rule_to_list( &drbl_first, &drbl_last, + gw_net, + NULL/*body*/, + 0/*port*/, + PROTO_NONE/*proto*/, + 0/*flags*/) != 0) { + LM_ERR("Something went wrong in add_rule_to_list\n"); + } else { + } + pkg_free(gw_net); } - /* add this destination to the BL */ - add_rule_to_list( &drbl_first, &drbl_last, - gw_net, - NULL/*body*/, - 0/*port*/, - PROTO_NONE/*proto*/, - 0/*flags*/); - pkg_free(gw_net); } } } - } - /* the new content for the BL */ - if (drbl->bl && add_list_to_head( drbl->bl, drbl_first, drbl_last, 1, 0)!=0) { - LM_ERR("failed to update bl\n"); - return -1; + /* the new content for the BL */ + if (drbl->bl!=NULL && add_list_to_head( drbl->bl, drbl_first, drbl_last, 1, 0)!=0) { + LM_ERR("failed to update bl\n"); + return -1; + } } } diff --git a/modules/drouting/dr_bl.h b/modules/drouting/dr_bl.h index 8e24f922199..f65f8c222a4 100644 --- a/modules/drouting/dr_bl.h +++ b/modules/drouting/dr_bl.h @@ -35,19 +35,21 @@ #include "../../sr_module.h" #include "../../blacklists.h" #include "prefix_tree.h" +#include "dr_partitions.h" #define MAX_TYPES_PER_BL 32 struct dr_bl { unsigned int no_types; unsigned int types[MAX_TYPES_PER_BL]; + struct head_db * part; struct bl_head *bl; struct dr_bl *next; }; int set_dr_bl( modparam_t type, void* val); -int init_dr_bls(void); +int init_dr_bls( struct head_db *); void destroy_dr_bls(void); diff --git a/modules/drouting/dr_db_def.c b/modules/drouting/dr_db_def.c new file mode 100644 index 00000000000..5850c5231e1 --- /dev/null +++ b/modules/drouting/dr_db_def.c @@ -0,0 +1,91 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of Open SIP Server (OpenSIPS). + * + * DROUTING OpenSIPS-module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * DROUTING OpenSIPS-module is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#include "../../ut.h" +#include "dr_db_def.h" + +/* DR group table related defs */ +str drg_table = str_init("dr_groups"); +str drg_user_col = str_init("username"); +str drg_domain_col = str_init("domain"); +str drg_grpid_col = str_init("groupid"); + +/* DR gateway table related defs */ +#define ID_DRD_COL "id" +#define GWID_DRD_COL "gwid" +#define ADDRESS_DRD_COL "address" +#define STRIP_DRD_COL "strip" +#define PREFIX_DRD_COL "pri_prefix" +#define TYPE_DRD_COL "type" +#define ATTRS_DRD_COL "attrs" +#define PROBE_DRD_COL "probe_mode" +#define SOCKET_DRD_COL "socket" +#define STATE_DRD_COL "state" +str drd_table = str_init("dr_gateways"); +str id_drd_col = str_init(ID_DRD_COL); +str gwid_drd_col = str_init(GWID_DRD_COL); +str address_drd_col = str_init(ADDRESS_DRD_COL); +str strip_drd_col = str_init(STRIP_DRD_COL); +str prefix_drd_col = str_init(PREFIX_DRD_COL); +str type_drd_col = str_init(TYPE_DRD_COL); +str attrs_drd_col = str_init(ATTRS_DRD_COL); +str probe_drd_col = str_init(PROBE_DRD_COL); +str sock_drd_col = str_init(SOCKET_DRD_COL); +str state_drd_col = str_init(STATE_DRD_COL); + +/* DR rule table related defs */ +#define RULE_ID_DRR_COL "ruleid" +#define GROUP_DRR_COL "groupid" +#define PREFIX_DRR_COL "prefix" +#define TIME_DRR_COL "timerec" +#define PRIORITY_DRR_COL "priority" +#define ROUTEID_DRR_COL "routeid" +#define DSTLIST_DRR_COL "gwlist" +#define ATTRS_DRR_COL "attrs" +str drr_table = str_init("dr_rules"); +str rule_id_drr_col = str_init(RULE_ID_DRR_COL); +str group_drr_col = str_init(GROUP_DRR_COL); +str prefix_drr_col = str_init(PREFIX_DRR_COL); +str time_drr_col = str_init(TIME_DRR_COL); +str priority_drr_col = str_init(PRIORITY_DRR_COL); +str routeid_drr_col = str_init(ROUTEID_DRR_COL); +str dstlist_drr_col = str_init(DSTLIST_DRR_COL); +str attrs_drr_col = str_init(ATTRS_DRR_COL); + +/* DR carrier table related defs */ +#define ID_DRC_COL "id" +#define CID_DRC_COL "carrierid" +#define FLAGS_DRC_COL "flags" +#define GWLIST_DRC_COL "gwlist" +#define ATTRS_DRC_COL "attrs" +#define STATE_DRC_COL "state" +str drc_table = str_init("dr_carriers"); +str id_drc_col = str_init(ID_DRC_COL); +str cid_drc_col = str_init(CID_DRC_COL); +str flags_drc_col = str_init(FLAGS_DRC_COL); +str gwlist_drc_col = str_init(GWLIST_DRC_COL); +str attrs_drc_col = str_init(ATTRS_DRC_COL); +str state_drc_col = str_init(STATE_DRC_COL); + + diff --git a/modules/drouting/dr_db_def.h b/modules/drouting/dr_db_def.h new file mode 100644 index 00000000000..740a0d93aa0 --- /dev/null +++ b/modules/drouting/dr_db_def.h @@ -0,0 +1,69 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of Open SIP Server (OpenSIPS). + * + * DROUTING OpenSIPS-module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * DROUTING OpenSIPS-module is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _DR_DB_DEFS +#define _DR_DB_DEFS + +#include "../../str.h" + +/* DR group table related defs */ +extern str drg_table; +extern str drg_user_col; +extern str drg_domain_col; +extern str drg_grpid_col; + +/* DR gateway table related defs */ +extern str drd_table; +extern str id_drd_col; +extern str gwid_drd_col; +extern str address_drd_col; +extern str strip_drd_col; +extern str prefix_drd_col; +extern str type_drd_col; +extern str attrs_drd_col; +extern str probe_drd_col; +extern str sock_drd_col; +extern str state_drd_col; + +/* DR rule table related defs */ +extern str drr_table; +extern str rule_id_drr_col; +extern str group_drr_col; +extern str prefix_drr_col; +extern str time_drr_col; +extern str priority_drr_col; +extern str routeid_drr_col; +extern str dstlist_drr_col; +extern str attrs_drr_col; + +/* DR carrier table related defs */ +extern str drc_table; +extern str id_drc_col; +extern str cid_drc_col; +extern str flags_drc_col; +extern str gwlist_drc_col; +extern str attrs_drc_col; +extern str state_drc_col; + +#endif + diff --git a/modules/drouting/dr_load.c b/modules/drouting/dr_load.c index b164c0d985f..b77dff1db9d 100644 --- a/modules/drouting/dr_load.c +++ b/modules/drouting/dr_load.c @@ -42,68 +42,27 @@ #include "../../db/db.h" #include "../../mem/shm_mem.h" #include "../../time_rec.h" +#include "../../socket_info.h" #include "dr_load.h" #include "routing.h" #include "prefix_tree.h" #include "parse.h" +#include "dr_db_def.h" -#define ID_DRD_COL "id" -#define GWID_DRD_COL "gwid" -#define ADDRESS_DRD_COL "address" -#define STRIP_DRD_COL "strip" -#define PREFIX_DRD_COL "pri_prefix" -#define TYPE_DRD_COL "type" -#define ATTRS_DRD_COL "attrs" -#define PROBE_DRD_COL "probe_mode" -static str id_drd_col = str_init(ID_DRD_COL); -static str gwid_drd_col = str_init(GWID_DRD_COL); -static str address_drd_col = str_init(ADDRESS_DRD_COL); -static str strip_drd_col = str_init(STRIP_DRD_COL); -static str prefix_drd_col = str_init(PREFIX_DRD_COL); -static str type_drd_col = str_init(TYPE_DRD_COL); -static str attrs_drd_col = str_init(ATTRS_DRD_COL); -static str probe_drd_col = str_init(PROBE_DRD_COL); - -#define RULE_ID_DRR_COL "ruleid" -#define GROUP_DRR_COL "groupid" -#define PREFIX_DRR_COL "prefix" -#define TIME_DRR_COL "timerec" -#define PRIORITY_DRR_COL "priority" -#define ROUTEID_DRR_COL "routeid" -#define DSTLIST_DRR_COL "gwlist" -static str rule_id_drr_col = str_init(RULE_ID_DRR_COL); -static str group_drr_col = str_init(GROUP_DRR_COL); -static str prefix_drr_col = str_init(PREFIX_DRR_COL); -static str time_drr_col = str_init(TIME_DRR_COL); -static str priority_drr_col = str_init(PRIORITY_DRR_COL); -static str routeid_drr_col = str_init(ROUTEID_DRR_COL); -static str dstlist_drr_col = str_init(DSTLIST_DRR_COL); - -#define ID_DRC_COL "id" -#define CID_DRC_COL "carrierid" -#define FLAGS_DRC_COL "flags" -#define GWLIST_DRC_COL "gwlist" -#define ATTRS_DRC_COL "attrs" -static str id_drc_col = str_init(ID_DRC_COL); -static str cid_drc_col = str_init(CID_DRC_COL); -static str flags_drc_col = str_init(FLAGS_DRC_COL); -static str gwlist_drc_col = str_init(GWLIST_DRC_COL); -static str attrs_drc_col = str_init(ATTRS_DRC_COL); - #define check_val( _col, _val, _type, _not_null, _is_empty_str) \ do{\ if ((_val)->type!=_type) { \ - LM_ERR("column %s has a bad type\n", _col); \ + LM_ERR("column %.*s has a bad type\n", _col.len, _col.s); \ goto error;\ } \ if (_not_null && (_val)->nul) { \ - LM_ERR("column %s is null\n", _col); \ + LM_ERR("column %.*s is null\n", _col.len, _col.s); \ goto error;\ } \ if (_is_empty_str && VAL_STRING(_val)==0) { \ - LM_ERR("column %s (str) is empty\n", _col); \ + LM_ERR("column %.*s (str) is empty\n", _col.len, _col.s); \ goto error;\ } \ }while(0) @@ -118,13 +77,13 @@ static inline tmrec_t* parse_time_def(char *time_str) p = time_str; time_rec = 0; -/* time_rec = (tmrec_t*)shm_malloc(sizeof(tmrec_t)); */ + /* time_rec = (tmrec_t*)shm_malloc(sizeof(tmrec_t)); */ time_rec = tmrec_new(SHM_ALLOC); if (time_rec==0) { LM_ERR("no more shm mem\n"); goto error; } -/* memset( time_rec, 0, sizeof(tmrec_t)); */ + /* memset( time_rec, 0, sizeof(tmrec_t)); */ /* empty definition? */ if ( time_str==0 || *time_str==0 ) @@ -146,7 +105,7 @@ static inline tmrec_t* parse_time_def(char *time_str) return time_rec; parse_error: LM_ERR("parse error in <%s> around position %i\n", - time_str, (int)(long)(p-time_str)); + time_str, (int)(long)(p-time_str)); error: if (time_rec) tmrec_free( time_rec ); @@ -169,7 +128,7 @@ static int add_rule(rt_data_t *rdata, char *grplst, str *prefix, rt_info_t *rule t = strtol(tmp, &ep, 10); if (ep == tmp) { LM_ERR("bad grp id '%c' (%d)[%s]\n", - *ep, (int)(ep-grplst), grplst); + *ep, (int)(ep-grplst), grplst); goto error; } if ((!IS_SPACE(*ep)) && (*ep != SEP) && (*ep != SEP1) && (*ep!=0)) { @@ -187,12 +146,12 @@ static int add_rule(rt_data_t *rdata, char *grplst, str *prefix, rt_info_t *rule /* add the routing rule */ if ( add_prefix(rdata->pt, prefix, rule, (unsigned int)t)!=0 ) { LM_ERR("failed to add prefix route\n"); - goto error; + goto error; } } else { if ( add_rt_info( &rdata->noprefix, rule, (unsigned int)t)!=0 ) { LM_ERR("failed to add prefixless route\n"); - goto error; + goto error; } } /* keep parsing */ @@ -205,7 +164,7 @@ static int add_rule(rt_data_t *rdata, char *grplst, str *prefix, rt_info_t *rule if(n==0) { LM_ERR("no id in grp list [%s]\n", - grplst); + grplst); goto error; } @@ -215,13 +174,53 @@ static int add_rule(rt_data_t *rdata, char *grplst, str *prefix, rt_info_t *rule } -rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, - str *drd_table, str *drc_table, str* drr_table ) +/* dr_gateways table */ +#define INT_VALS_STRIP_DRD_COL 0 +#define INT_VALS_TYPE_DRD_COL 1 +#define INT_VALS_PROBE_DRD_COL 2 +#define INT_VALS_STATE_DRD_COL 3 +#define STR_VALS_ADDRESS_DRD_COL 0 +#define STR_VALS_PREFIX_DRD_COL 1 +#define STR_VALS_ATTRS_DRD_COL 2 +#define STR_VALS_GWID_DRD_COL 3 +#define STR_VALS_ID_DRD_COL 4 + +/* dr_carriers table */ +#define INT_VALS_FLAGS_DRC_COL 0 +#define INT_VALS_STATE_DRC_COL 1 +#define STR_VALS_CID_DRC_COL 0 +#define STR_VALS_GWLIST_DRC_COL 1 +#define STR_VALS_ATTRS_DRC_COL 2 +#define STR_VALS_ID_DRC_COL 3 + +/* dr_rules table */ +#define INT_VALS_RULE_ID_DRR_COL 0 +#define INT_VALS_BLANK_1 1 +#define INT_VALS_PRIORITY_DRR_COL 2 +#define INT_VALS_SCRIPT_ROUTE_ID 3 +#define STR_VALS_GROUP_DRR_COL 0 +#define STR_VALS_PREFIX_DRR_COL 1 +#define STR_VALS_TIME_DRR_COL 2 +#define STR_VALS_ROUTEID_DRR_COL 3 +#define STR_VALS_DSTLIST_DRR_COL 4 +#define STR_VALS_ATTRS_DRR_COL 5 + +/* loads routing info for given partition; if partition_name is NULL + * loads all partitions + */ + +rt_data_t* dr_load_routing_info(struct head_db *current_partition + , int persistent_state) { - int int_vals[4]; + int int_vals[5]; char * str_vals[6]; str tmp; - db_key_t columns[8]; + db_func_t *dr_dbf = ¤t_partition->db_funcs; + db_con_t* db_hdl = *current_partition->db_con; + str *drd_table = ¤t_partition->drd_table; + str *drc_table = ¤t_partition->drc_table; + str *drr_table = ¤t_partition->drr_table; + db_key_t columns[10]; db_res_t* res; db_row_t* row; rt_info_t *ri; @@ -229,6 +228,11 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, tmrec_t *time_rec; int i,n; int no_rows = 10; + int db_cols; + struct socket_info *sock; + str s_sock, host; + int proto, port; + char id_buf[INT2STR_MAX_LEN]; res = 0; ri = 0; @@ -240,7 +244,7 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, goto error; } - if (db_check_table_version(dr_dbf, db_hdl, drd_table, 5 )!= 0) + if (db_check_table_version(dr_dbf, db_hdl, drd_table, 6/*version*/ )!= 0) goto error; /* read the destinations */ @@ -257,62 +261,118 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, columns[5] = &type_drd_col; columns[6] = &attrs_drd_col; columns[7] = &probe_drd_col; + columns[8] = &sock_drd_col; + if (persistent_state) { + columns[9] = &state_drd_col; + db_cols = 10; + } else { + db_cols = 9; + } if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) { - if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 8, 0, 0 ) < 0) { + if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, db_cols, 0, 0 ) < 0) { LM_ERR("DB query failed\n"); goto error; } - no_rows = estimate_available_rows( 4+32+15+4+32+4+128+4, 8); + no_rows = estimate_available_rows( 4+32+15+4+32+4+128+4+32+4, db_cols); if (no_rows==0) no_rows = 10; if(dr_dbf->fetch_result(db_hdl, &res, no_rows )<0) { LM_ERR("Error fetching rows\n"); goto error; } } else { - if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 8, 0, &res) < 0) { + if ( dr_dbf->query(db_hdl,0,0,0,columns,0,db_cols,0,&res) < 0) { LM_ERR("DB query failed\n"); goto error; } } LM_DBG("%d records found in %.*s\n", - RES_ROW_N(res), drd_table->len,drd_table->s); + RES_ROW_N(res), drd_table->len,drd_table->s); n = 0; do { for(i=0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; /* DB ID column */ - check_val(ID_DRD_COL, ROW_VALUES(row), DB_INT, 1, 0); - int_vals[0] = VAL_INT(ROW_VALUES(row)); + if ( VAL_TYPE( ROW_VALUES(row) ) == DB_INT ) { + /* if INT type, convert it to string */ + check_val( id_drd_col, ROW_VALUES(row), DB_INT, 1, 0); + /* int2bstr returns a null terminated string */ + str_vals[STR_VALS_ID_DRD_COL] = + int2bstr((unsigned long)VAL_INT(ROW_VALUES(row)), + id_buf, &int_vals[0]/*useless*/); + } else { + /* if not INT, accept only STRING type */ + check_val( id_drd_col, ROW_VALUES(row), DB_STRING, 1, 0); + str_vals[STR_VALS_ID_DRD_COL] = (char*)VAL_STRING(ROW_VALUES(row)); + } /* GW ID column */ - check_val(GWID_DRD_COL, ROW_VALUES(row)+1, DB_STRING, 1, 1); - str_vals[3] = (char*)VAL_STRING(ROW_VALUES(row)+1); + check_val( gwid_drd_col, ROW_VALUES(row)+1, DB_STRING, 1, 1); + str_vals[STR_VALS_GWID_DRD_COL] = (char*)VAL_STRING(ROW_VALUES(row)+1); /* ADDRESS column */ - check_val(ADDRESS_DRD_COL, ROW_VALUES(row)+2, DB_STRING, 1, 1); - str_vals[0] = (char*)VAL_STRING(ROW_VALUES(row)+2); + check_val( address_drd_col, ROW_VALUES(row)+2, DB_STRING, 1, 1); + str_vals[STR_VALS_ADDRESS_DRD_COL] = (char*)VAL_STRING(ROW_VALUES(row)+2); /* STRIP column */ - check_val(STRIP_DRD_COL, ROW_VALUES(row)+3, DB_INT, 1, 0); - int_vals[1] = VAL_INT (ROW_VALUES(row)+3); + check_val( strip_drd_col, ROW_VALUES(row)+3, DB_INT, 1, 0); + int_vals[INT_VALS_STRIP_DRD_COL] = VAL_INT (ROW_VALUES(row)+3); /* PREFIX column */ - check_val(PREFIX_DRD_COL, ROW_VALUES(row)+4, DB_STRING, 0, 0); - str_vals[1] = (char*)VAL_STRING(ROW_VALUES(row)+4); + check_val( prefix_drd_col, ROW_VALUES(row)+4, DB_STRING, 0, 0); + str_vals[STR_VALS_PREFIX_DRD_COL] = (char*)VAL_STRING(ROW_VALUES(row)+4); /* TYPE column */ - check_val(TYPE_DRD_COL, ROW_VALUES(row)+5, DB_INT, 1, 0); - int_vals[2] = VAL_INT(ROW_VALUES(row)+5); + check_val( type_drd_col, ROW_VALUES(row)+5, DB_INT, 1, 0); + int_vals[INT_VALS_TYPE_DRD_COL] = VAL_INT(ROW_VALUES(row)+5); /* ATTRS column */ - check_val(ATTRS_DRD_COL, ROW_VALUES(row)+6, DB_STRING, 0, 0); - str_vals[2] = (char*)VAL_STRING(ROW_VALUES(row)+6); + check_val( attrs_drd_col, ROW_VALUES(row)+6, DB_STRING, 0, 0); + str_vals[STR_VALS_ATTRS_DRD_COL] = (char*)VAL_STRING(ROW_VALUES(row)+6); /*PROBE_MODE column */ - check_val(PROBE_DRD_COL, ROW_VALUES(row)+7, DB_INT, 1, 0); - int_vals[3] = VAL_INT(ROW_VALUES(row)+7); + check_val( probe_drd_col, ROW_VALUES(row)+7, DB_INT, 1, 0); + int_vals[INT_VALS_PROBE_DRD_COL] = VAL_INT(ROW_VALUES(row)+7); + /*SOCKET column */ + check_val( sock_drd_col, ROW_VALUES(row)+8, DB_STRING, 0, 0); + if ( !VAL_NULL(ROW_VALUES(row)+8) && + (s_sock.s=(char*)VAL_STRING(ROW_VALUES(row)+8))[0]!=0 ) { + s_sock.len = strlen(s_sock.s); + if (parse_phostport( s_sock.s, s_sock.len, &host.s, &host.len, + &port, &proto)!=0){ + LM_ERR("GW <%s>(%s): socket description <%.*s> " + "is not valid -> ignoring socket\n", + str_vals[STR_VALS_GWID_DRD_COL], + str_vals[STR_VALS_ID_DRD_COL], s_sock.len,s_sock.s); + sock = NULL; + } else { + sock = grep_sock_info( &host, port, proto); + if (sock == NULL) { + LM_ERR("GW <%s>(%s): socket <%.*s> is not local to " + "OpenSIPS (we must listen on it) -> ignoring socket\n", + str_vals[STR_VALS_GWID_DRD_COL], + str_vals[STR_VALS_ID_DRD_COL], s_sock.len,s_sock.s); + } + } + } else { + sock = NULL; + } + /*STATE column */ + if (persistent_state) { + check_val( state_drd_col, ROW_VALUES(row)+9, DB_INT, 1, 0); + int_vals[INT_VALS_STATE_DRD_COL] = VAL_INT(ROW_VALUES(row)+9); + } else { + int_vals[INT_VALS_STATE_DRD_COL] = 0; /* by default enabled */ + } /* add the destinaton definition in */ - if ( add_dst( rdata, str_vals[3], str_vals[0], int_vals[1], - str_vals[1], int_vals[2], str_vals[2], int_vals[3])<0 ) { - LM_ERR("failed to add destination id %d -> skipping\n", - int_vals[0]); + if ( add_dst( rdata, str_vals[STR_VALS_GWID_DRD_COL], + str_vals[STR_VALS_ADDRESS_DRD_COL], + int_vals[INT_VALS_STRIP_DRD_COL], + str_vals[STR_VALS_PREFIX_DRD_COL], + int_vals[INT_VALS_TYPE_DRD_COL], + str_vals[STR_VALS_ATTRS_DRD_COL], + int_vals[INT_VALS_PROBE_DRD_COL], + sock, + int_vals[INT_VALS_STATE_DRD_COL] )<0 ) { + LM_ERR("failed to add destination <%s>(%s) -> skipping\n", + str_vals[STR_VALS_GWID_DRD_COL], + str_vals[STR_VALS_ID_DRD_COL]); continue; } n++; @@ -341,20 +401,26 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, columns[2] = &flags_drc_col; columns[3] = &gwlist_drc_col; columns[4] = &attrs_drc_col; + if (persistent_state) { + columns[5] = &state_drc_col; + db_cols = 6; + } else { + db_cols = 5; + } if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) { - if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 5, 0, 0 ) < 0) { + if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, db_cols, 0, 0 ) < 0) { LM_ERR("DB query failed\n"); goto error; } - no_rows = estimate_available_rows( 4+4+32+64+64, 5/*cols*/); + no_rows = estimate_available_rows( 4+4+32+64+64, db_cols); if (no_rows==0) no_rows = 10; if(dr_dbf->fetch_result(db_hdl, &res, no_rows)<0) { LM_ERR("Error fetching rows\n"); goto error; } } else { - if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 5, 0, &res) < 0) { + if ( dr_dbf->query(db_hdl,0,0,0,columns,0,db_cols,0,&res) < 0) { LM_ERR("DB query failed\n"); goto error; } @@ -364,31 +430,52 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, LM_DBG("table \"%.*s\" empty\n", drc_table->len,drc_table->s ); } else { LM_DBG("%d records found in %.*s\n", - RES_ROW_N(res), drc_table->len,drc_table->s); + RES_ROW_N(res), drc_table->len,drc_table->s); do { for(i=0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; - /* ID column */ - check_val(ID_DRC_COL, ROW_VALUES(row), DB_INT, 1, 0); - int_vals[0] = VAL_INT(ROW_VALUES(row)); + /* DB ID column */ + if ( VAL_TYPE( ROW_VALUES(row) ) == DB_INT ) { + /* if INT type, convert it to string */ + check_val( id_drc_col, ROW_VALUES(row), DB_INT, 1, 0); + /* int2bstr returns a null terminated string */ + str_vals[STR_VALS_ID_DRC_COL] = + int2bstr((unsigned long)VAL_INT(ROW_VALUES(row)), + id_buf, &int_vals[0]/*useless*/); + } else { + /* if not INT, accept only STRING type */ + check_val( id_drd_col, ROW_VALUES(row), DB_STRING, 1, 0); + str_vals[STR_VALS_ID_DRC_COL] = (char*)VAL_STRING(ROW_VALUES(row)); + } /* CARRIER_ID column */ - check_val(CID_DRC_COL, ROW_VALUES(row)+1, DB_STRING, 1, 1); - str_vals[0] = (char*)VAL_STRING(ROW_VALUES(row)+1); + check_val( cid_drc_col, ROW_VALUES(row)+1, DB_STRING, 1, 1); + str_vals[STR_VALS_CID_DRC_COL] = (char*)VAL_STRING(ROW_VALUES(row)+1); /* flags column */ - check_val(ID_DRC_COL, ROW_VALUES(row)+2, DB_INT, 1, 0); - int_vals[1] = VAL_INT(ROW_VALUES(row)+2); + check_val( flags_drc_col, ROW_VALUES(row)+2, DB_INT, 1, 0); + int_vals[INT_VALS_FLAGS_DRC_COL] = VAL_INT(ROW_VALUES(row)+2); /* GWLIST column */ - check_val(GWLIST_DRC_COL, ROW_VALUES(row)+3, DB_STRING, 1, 1); - str_vals[1] = (char*)VAL_STRING(ROW_VALUES(row)+3); + check_val( gwlist_drc_col, ROW_VALUES(row)+3, DB_STRING, 1, 1); + str_vals[STR_VALS_GWLIST_DRC_COL] = (char*)VAL_STRING(ROW_VALUES(row)+3); /* ATTRS column */ - check_val(ATTRS_DRC_COL, ROW_VALUES(row)+4, DB_STRING, 0, 0); - str_vals[2] = (char*)VAL_STRING(ROW_VALUES(row)+4); + check_val( attrs_drc_col, ROW_VALUES(row)+4, DB_STRING, 0, 0); + str_vals[STR_VALS_ATTRS_DRC_COL] = (char*)VAL_STRING(ROW_VALUES(row)+4); + /* STATE column */ + if (persistent_state) { + check_val( state_drc_col, ROW_VALUES(row)+5, DB_INT, 1, 0); + int_vals[INT_VALS_STATE_DRC_COL] = VAL_INT(ROW_VALUES(row)+5); + } else { + /* by default enabled */ + int_vals[INT_VALS_STATE_DRC_COL] = 0; + } /* add the new carrier */ - if ( add_carrier( int_vals[0], str_vals[0], int_vals[1], - str_vals[1], str_vals[2], rdata) != 0 ) { - LM_ERR("failed to add carrier db_id %d -> skipping\n", - int_vals[0]); + if ( add_carrier( str_vals[STR_VALS_CID_DRC_COL], + int_vals[INT_VALS_FLAGS_DRC_COL], + str_vals[STR_VALS_GWLIST_DRC_COL], + str_vals[STR_VALS_ATTRS_DRC_COL], + int_vals[INT_VALS_STATE_DRC_COL], rdata) != 0 ) { + LM_ERR("failed to add carrier db_id <%s> -> skipping\n", + str_vals[STR_VALS_ID_DRC_COL]); continue; } } @@ -419,7 +506,7 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, columns[4] = &priority_drr_col; columns[5] = &routeid_drr_col; columns[6] = &dstlist_drr_col; - columns[7] = &attrs_drd_col; + columns[7] = &attrs_drr_col; if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) { if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 8, 0, 0) < 0) { @@ -444,73 +531,78 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, } LM_DBG("initial %d records found in %.*s\n", RES_ROW_N(res), - drr_table->len, drr_table->s); + drr_table->len, drr_table->s); n = 0; do { for(i=0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; /* RULE_ID column */ - check_val(RULE_ID_DRR_COL, ROW_VALUES(row), DB_INT, 1, 0); - int_vals[0] = VAL_INT (ROW_VALUES(row)); + check_val( rule_id_drr_col, ROW_VALUES(row), DB_INT, 1, 0); + int_vals[INT_VALS_RULE_ID_DRR_COL] = VAL_INT (ROW_VALUES(row)); /* GROUP column */ - check_val(GROUP_DRR_COL, ROW_VALUES(row)+1, DB_STRING, 1, 1); - str_vals[0] = (char*)VAL_STRING(ROW_VALUES(row)+1); + check_val( group_drr_col, ROW_VALUES(row)+1, DB_STRING, 1, 1); + str_vals[STR_VALS_GROUP_DRR_COL] = (char*)VAL_STRING(ROW_VALUES(row)+1); /* PREFIX column - it may be null or empty */ - check_val(PREFIX_DRR_COL, ROW_VALUES(row)+2, DB_STRING, 0, 0); + check_val( prefix_drr_col, ROW_VALUES(row)+2, DB_STRING, 0, 0); if ((ROW_VALUES(row)+2)->nul || VAL_STRING(ROW_VALUES(row)+2)==0){ tmp.s = NULL; tmp.len = 0; } else { - str_vals[1] = (char*)VAL_STRING(ROW_VALUES(row)+2); - tmp.s = str_vals[1]; - tmp.len = strlen(str_vals[1]); + str_vals[STR_VALS_PREFIX_DRR_COL] = (char*)VAL_STRING(ROW_VALUES(row)+2); + tmp.s = str_vals[STR_VALS_PREFIX_DRR_COL]; + tmp.len = strlen(str_vals[STR_VALS_PREFIX_DRR_COL]); } /* TIME column */ - check_val(TIME_DRR_COL, ROW_VALUES(row)+3, DB_STRING, 0, 0); - str_vals[2] = (char*)VAL_STRING(ROW_VALUES(row)+3); + check_val( time_drr_col, ROW_VALUES(row)+3, DB_STRING, 0, 0); + str_vals[STR_VALS_TIME_DRR_COL] = (char*)VAL_STRING(ROW_VALUES(row)+3); /* PRIORITY column */ - check_val(PRIORITY_DRR_COL, ROW_VALUES(row)+4, DB_INT, 1, 0); - int_vals[2] = VAL_INT (ROW_VALUES(row)+4); + check_val( priority_drr_col, ROW_VALUES(row)+4, DB_INT, 1, 0); + int_vals[INT_VALS_PRIORITY_DRR_COL] = VAL_INT (ROW_VALUES(row)+4); /* ROUTE_ID column */ - check_val(ROUTEID_DRR_COL, ROW_VALUES(row)+5, DB_STRING, 0, 0); - str_vals[3] = (char*)VAL_STRING(ROW_VALUES(row)+5); + check_val( routeid_drr_col, ROW_VALUES(row)+5, DB_STRING, 0, 0); + str_vals[STR_VALS_ROUTEID_DRR_COL] = (char*)VAL_STRING(ROW_VALUES(row)+5); /* DSTLIST column */ - check_val(DSTLIST_DRR_COL, ROW_VALUES(row)+6, DB_STRING, 1, 1); - str_vals[4] = (char*)VAL_STRING(ROW_VALUES(row)+6); + check_val( dstlist_drr_col, ROW_VALUES(row)+6, DB_STRING, 1, 1); + str_vals[STR_VALS_DSTLIST_DRR_COL] = (char*)VAL_STRING(ROW_VALUES(row)+6); /* ATTRS column */ - check_val(ATTRS_DRD_COL, ROW_VALUES(row)+7, DB_STRING, 0, 0); - str_vals[5] = (char*)VAL_STRING(ROW_VALUES(row)+7); + check_val( attrs_drr_col, ROW_VALUES(row)+7, DB_STRING, 0, 0); + str_vals[STR_VALS_ATTRS_DRR_COL] = (char*)VAL_STRING(ROW_VALUES(row)+7); /* parse the time definition */ - if (str_vals[2] == NULL || *(str_vals[2]) == 0) + if (str_vals[STR_VALS_TIME_DRR_COL] == NULL || *(str_vals[STR_VALS_TIME_DRR_COL]) == 0) time_rec = NULL; - else if ((time_rec=parse_time_def(str_vals[2]))==0) { + else if ((time_rec=parse_time_def(str_vals[STR_VALS_TIME_DRR_COL]))==0) { LM_ERR("bad time definition <%s> for rule id %d -> skipping\n", - str_vals[2], int_vals[0]); + str_vals[STR_VALS_TIME_DRR_COL], int_vals[INT_VALS_RULE_ID_DRR_COL]); continue; } /* lookup for the script route ID */ - if (str_vals[3] && str_vals[3][0]) { - int_vals[3] = get_script_route_ID_by_name( str_vals[3], - rlist, RT_NO); - if (int_vals[3]==-1) { - LM_WARN("route <%s> does not exist\n",str_vals[3]); - int_vals[3] = 0; + if (str_vals[STR_VALS_ROUTEID_DRR_COL] && str_vals[STR_VALS_ROUTEID_DRR_COL][0]) { + int_vals[INT_VALS_SCRIPT_ROUTE_ID] = + get_script_route_ID_by_name( str_vals[STR_VALS_ROUTEID_DRR_COL], rlist, RT_NO); + if (int_vals[INT_VALS_SCRIPT_ROUTE_ID]==-1) { + LM_WARN("route <%s> does not exist\n", + str_vals[STR_VALS_ROUTEID_DRR_COL]); + int_vals[INT_VALS_SCRIPT_ROUTE_ID] = 0; } } else { - int_vals[3] = 0; + int_vals[INT_VALS_SCRIPT_ROUTE_ID] = 0; } /* build the routing rule */ - if ((ri = build_rt_info( int_vals[0], int_vals[2], time_rec, - int_vals[3], str_vals[4], str_vals[5], rdata))== 0 ) { + if ((ri = build_rt_info( int_vals[INT_VALS_RULE_ID_DRR_COL], + int_vals[INT_VALS_PRIORITY_DRR_COL], time_rec, + int_vals[INT_VALS_SCRIPT_ROUTE_ID], + str_vals[STR_VALS_DSTLIST_DRR_COL], + str_vals[STR_VALS_ATTRS_DRR_COL], rdata))== 0 ) { LM_ERR("failed to add routing info for rule id %d -> " - "skipping\n", int_vals[0]); + "skipping\n", int_vals[INT_VALS_RULE_ID_DRR_COL]); tmrec_free( time_rec ); continue; } /* add the rule */ - if (add_rule( rdata, str_vals[0], &tmp, ri)!=0) { - LM_ERR("failed to add rule id %d -> skipping\n", int_vals[0]); + if (add_rule( rdata, str_vals[STR_VALS_GROUP_DRR_COL], &tmp, ri)!=0) { + LM_ERR("failed to add rule id %d -> skipping\n", + int_vals[INT_VALS_RULE_ID_DRR_COL]); free_rt_info( ri ); continue; } @@ -522,7 +614,7 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, goto error; } LM_DBG("additional %d records found in %.*s\n", RES_ROW_N(res), - drr_table->len, drr_table->s); + drr_table->len, drr_table->s); } else { break; } @@ -532,12 +624,7 @@ rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, res = 0; LM_DBG("%d total records loaded from table %.*s\n", n, - drr_table->len, drr_table->s); - if (n==0) { - LM_WARN("no valid routing rules -> discarding all destinations\n"); - free_rt_data( rdata, 0 ); - } - + drr_table->len, drr_table->s); return rdata; error: if (res) diff --git a/modules/drouting/dr_load.h b/modules/drouting/dr_load.h index 55c37e01992..1f71ed7a017 100644 --- a/modules/drouting/dr_load.h +++ b/modules/drouting/dr_load.h @@ -35,9 +35,9 @@ #include "../../str.h" #include "../../db/db.h" +#include "dr_partitions.h" #include "routing.h" -rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db_con_t* db_hdl, - str *drd_table, str *drl_table, str* str_table); +rt_data_t* dr_load_routing_info(struct head_db * ,int persistent_state); #endif diff --git a/modules/drouting/dr_partitions.h b/modules/drouting/dr_partitions.h new file mode 100644 index 00000000000..87b4ab58394 --- /dev/null +++ b/modules/drouting/dr_partitions.h @@ -0,0 +1,88 @@ +/** + * + * dispatcher module fixup functions + * + * Copyright (C) 2004-2005 FhG Fokus + * Copyright (C) 2006-2010 Voice Sistem SRL + * Copyright (C) 2014 OpenSIPS Foundation + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History + * ------- + * 2014-07-23 initial version (Mihai Tiganus) + */ +#ifndef DR_DR_PARTITIONS_H +#define DR_DR_PARTITIONS_H + +#include "routing.h" +#include "../../sr_module.h" +#include "../../str.h" +#include "../../dprint.h" +#include "../../usr_avp.h" +#include "../../db/db.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../../rw_locking.h" +#include "../../action.h" +#include "../../error.h" +#include "../../ut.h" +#include "../../resolve.h" +#include "../../mod_fix.h" +#include "../../parser/parse_from.h" +#include "../../parser/parse_uri.h" +#include "../../mi/mi.h" +#include "../tm/tm_load.h" + +int use_partitions; + +struct head_db { + str db_url; + str partition; + db_func_t db_funcs; + db_con_t **db_con; + str drd_table; /* drd_table name extracted from database */ + str drr_table; /* drr_table name extracted from database */ + str drc_table; /* drc_table name extracted from database */ + str drg_table; /* drg_table name extracted from database */ + time_t time_last_update; + int avpID_store_ruri; /* from parse_avp_spec */ + int avpID_store_prefix; /* from parse_avp_spec */ + int avpID_store_index; /* from parse_avp_spec */ + int avpID_store_whitelist; /* from parse_avp_spec */ + int avpID_store_group; /* from parse_avp_spec */ + int avpID_store_flags; /* from parse_avp_spec */ + int gw_priprefix_avp; /* from parse_avp_spec */ + int rule_id_avp; /* from parse_avp_spec */ + int rule_prefix_avp; /* from parse_avp_spec */ + int carrier_id_avp; /* from parse_avp_spec */ + int ruri_avp; + int gw_id_avp; + int gw_sock_avp; + int gw_attrs_avp; + int rule_attrs_avp; + int carrier_attrs_avp; + rt_data_t **rdata; + rw_lock_t *ref_lock; + struct head_db *next; +}; + +struct head_db * get_partition(const str *); + + + +#endif diff --git a/modules/drouting/drouting.c b/modules/drouting/drouting.c index 78b2661c1d0..b4e447b44e6 100644 --- a/modules/drouting/drouting.c +++ b/modules/drouting/drouting.c @@ -34,28 +34,13 @@ #include #include -#include "../../sr_module.h" -#include "../../str.h" -#include "../../dprint.h" -#include "../../usr_avp.h" -#include "../../db/db.h" -#include "../../mem/mem.h" -#include "../../mem/shm_mem.h" -#include "../../rw_locking.h" -#include "../../action.h" -#include "../../error.h" -#include "../../ut.h" -#include "../../resolve.h" -#include "../../mod_fix.h" -#include "../../parser/parse_from.h" -#include "../../parser/parse_uri.h" -#include "../../mi/mi.h" -#include "../tm/tm_load.h" +#include "../../evi/evi.h" #include "dr_load.h" #include "prefix_tree.h" -#include "routing.h" #include "dr_bl.h" +#include "dr_db_def.h" +#include "dr_partitions.h" #define DR_PARAM_USE_WEIGTH (1<<0) @@ -64,6 +49,24 @@ #define DR_PARAM_ONLY_CHECK (1<<3) #define DR_PARAM_INTERNAL_TRIGGERED (1<<30) +#define DRD_TABLE_VER 6 +#define DRR_TABLE_VER 3 +#define DRG_TABLE_VER 2 +#define DRC_TABLE_VER 2 +#define PART_TABLE_VER 1 + +#define MAX_LEN_NAME_W_PART 510 /* max len of variable containing + avp_spec and partition name */ +#define MI_NO_PART_S "Too many arguments (use_partitions is 0 so no parameter"\ + " should be supplied to the MI function)" + +#define MI_NO_PART_LEN (strlen(MI_NO_PART_S)) + +#define MI_PART_NAME_S "Partition" +#define MI_PART_NAME_LEN (strlen(MI_PART_NAME_S)) + +#define MI_LAST_UPDATE_S "Date" +#define MI_LAST_UPDATE_LEN (strlen(MI_LAST_UPDATE_S)) /* probing related stuff */ static unsigned int dr_prob_interval = 30; @@ -74,80 +77,63 @@ str dr_probe_from = str_init("sip:prober@localhost"); static int* probing_reply_codes = NULL; static int probing_codes_no = 0; -static int dr_disable(struct sip_msg *req); /*** DB relatede stuff ***/ /* parameters */ static str db_url = {NULL,0}; -static str drg_table = str_init("dr_groups"); -static str drd_table = str_init("dr_gateways"); -static str drr_table = str_init("dr_rules"); -static str drc_table = str_init("dr_carriers"); +static int dr_persistent_state = 1; /* DRG use domain */ static int use_domain = 1; int dr_default_grp = -1; int dr_force_dns = 1; -/* DRG table columns */ -static str drg_user_col = str_init("username"); -static str drg_domain_col = str_init("domain"); -static str drg_grpid_col = str_init("groupid"); -/* variables */ -static db_con_t *db_hdl=0; /* DB handler */ -static db_func_t dr_dbf; /* DB functions */ +/* internal AVP used to store serial RURIs */ +static str ruri_avp_spec = str_init("$avp(___dr_ruri__)"); -/* current dr data - pointer to a pointer in shm */ -static rt_data_t **rdata = 0; +/* internal AVP used to store GW IDs */ +static str gw_id_avp_spec = str_init("$avp(___dr_gw_id__)"); -struct _dr_avp{ - unsigned short type; /* AVP ID */ - int name; /* AVP name*/ -}; - -/* AVP used to store serial RURIs */ -static struct _dr_avp ruri_avp = { 0, -1 }; -static str ruri_avp_spec = str_init("$avp(0xad346b2f)"); +/* internal AVP used to store GW socket */ +static str gw_sock_avp_spec = str_init("$avp(___dr_sock__)"); -/* AVP used to store GW IDs */ -static struct _dr_avp gw_id_avp = { 0, -1 }; -static str gw_id_avp_spec = str_init("$avp(0xad346b30)"); - -/* AVP used to store GW ATTRs */ -static struct _dr_avp gw_attrs_avp = { 0, -1 }; -static str gw_attrs_avp_spec = { NULL, 0}; +/* internal AVP used to store GW ATTRs */ +static str gw_attrs_avp_spec = str_init("$avp(___dr_gw_att__)"); /* AVP used to store GW Pri Prefix */ -static struct _dr_avp gw_priprefix_avp = { 0, -1 }; static str gw_priprefix_avp_spec = { NULL, 0}; /* AVP used to store RULE IDs */ -static struct _dr_avp rule_id_avp = { 0, -1 }; static str rule_id_avp_spec = {NULL, 0}; -/* AVP used to store RULE ATTRs */ -static struct _dr_avp rule_attrs_avp = { 0, -1 }; -static str rule_attrs_avp_spec = {NULL, 0}; +/* internal AVP used to store RULE ATTRs */ +static str rule_attrs_avp_spec = str_init("$avp(___dr_ru_att__)"); /* AVP used to store RULE prefix */ -static struct _dr_avp rule_prefix_avp = { 0, -1 }; static str rule_prefix_avp_spec = {NULL, 0}; /* AVP used to store CARRIER ID */ -static struct _dr_avp carrier_id_avp = { 0, -1 }; static str carrier_id_avp_spec = {NULL, 0}; -/* AVP used to store CARRIER ATTRs */ -static struct _dr_avp carrier_attrs_avp = { 0, -1 }; -static str carrier_attrs_avp_spec = {NULL, 0}; +/* internal AVP used to store CARRIER ATTRs */ +static str carrier_attrs_avp_spec = str_init("$avp(___dr_cr_att__)"); -/* internal AVPs used for fallback */ -static int avpID_store_ruri; -static int avpID_store_prefix; -static int avpID_store_index; -static int avpID_store_whitelist; -static int avpID_store_group; -static int avpID_store_flags; + +/* + * global pointers for faster parameter passing between functions + * meaning: current script pvar to dump attrs in (NULL to ignore) + */ +static pv_spec_p rule_attrs_spec; +static pv_spec_p gw_attrs_spec; +static pv_spec_p carrier_attrs_spec; + +/* + * if the attributes are not used at all in the script, + * do not store them in their internal AVPs at all --liviu + */ +static int populate_rule_attrs; +static int populate_gw_attrs; +static int populate_carrier_attrs; /* statistic data */ int tree_size = 0; @@ -155,33 +141,137 @@ int inode = 0; int unode = 0; static str attrs_empty = str_init(""); +/* configuration loader from db specific stuff */ +static str db_partitions_table = str_init("dr_partitions"); /* default url */ +static str db_partitions_url; + + +//static int use_partitions = 0; +// int use_partitions = 0; /* by default don't use db for config */ +static struct head_config { + str partition; /* partition name extracted from database */ + str db_url; + str drd_table; /* drd_table name extracted from database */ + str drr_table; /* drr_table name extracted from database */ + str drc_table; /* drc_table name extracted from database */ + str drg_table; /* drg_table name extracted from database */ + str gw_priprefix_avp_spec; /* extracted from database - it can be NULL */ + str rule_id_avp_spec; /* extracted from database - it can be NULL */ + str rule_prefix_avp_spec; /* extracted from database - it can be NULL */ + str carrier_id_avp_spec; /* extracted from database - it can be NULL */ + str ruri_avp_spec; /* extracted from database - has default value */ + str gw_id_avp_spec; /* extracted from database - has default value */ + str gw_sock_avp_spec; /* extracted from database - has default value */ + str gw_attrs_avp_spec; /* extracted from database - has default value */ + str rule_attrs_avp_spec; /* extracted from database - has default value */ + str carrier_attrs_avp_spec; /* extracted from database - has default value */ + struct head_config *next; +}* head_start = NULL,* head_end = NULL; + +struct head_db * head_db_start = NULL,* head_db_end = NULL; + + +typedef struct param_prob_callback { + struct head_db * current_partition; + unsigned int _id; +}param_prob_callback_t; + + +typedef struct dr_partition { + union { + struct head_db * part; + gparam_p part_name; + } v; + + enum dr_partition_type { DR_PTR_PART, DR_GPARAM_PART, DR_NO_PART } type; +} dr_partition_t; + +typedef struct dr_part_group { + dr_partition_t * dr_part; + dr_group_t * group; +} dr_part_group_t; + +static dr_part_group_t * default_part; /* for do_routing, used when + use_partitions = 0 */ + +typedef struct dr_part_old { + dr_partition_t *dr_part; + gparam_p gw_or_cr; /* gateway or carrier */ +} dr_part_old_t; + +typedef struct dr_part_cr { + gparam_p part; + gparam_p cr; +} dr_part_cr_t; + +typedef struct dr_part_gw { + gparam_p part; + gparam_p gw; +} dr_part_gw_t; + + +static int get_config_from_db(); +static int add_head_config(); +static int add_head_db(); +static int db_load_head(struct head_db*); /* used for populating head_db with + db connections and db funcs */ +static void trim_char(char**); +static int fixup_dr_disable(void **,int); +//static struct head_db * get_partition(const str *); +static int _is_dr_gw_w_part(struct sip_msg* , char * , char* , + int , struct ip_addr* , unsigned int); +static int use_next_gw_w_part( struct sip_msg*, struct head_db *, char *, char *, char *); +static int dr_disable(struct sip_msg *req, char * current_partition); +static int dr_disable_w_part(struct sip_msg *req, struct head_db *current_partition); +static int to_partition(struct sip_msg*, dr_partition_t *, + struct head_db **); +static inline int init_part_grp(dr_part_group_t **, struct head_db *, + dr_group_t*); + + /* reader-writers lock for reloading the data */ -static rw_lock_t *ref_lock = NULL; +static rw_lock_t *ref_lock = NULL; static int dr_init(void); static int dr_child_init(int rank); static int dr_exit(void); static int fixup_do_routing(void** param, int param_no); +static int fixup_next_gw(void** param, int param_no); static int fixup_from_gw(void** param, int param_no); static int fixup_is_gw(void** param, int param_no); +static int fixup_route2_carrier( void** param, int param_no); +static int fixup_route2_gw( void** param, int param_no); -static int do_routing(struct sip_msg* msg, dr_group_t *drg, int sort, gparam_t* wl); +static int do_routing(struct sip_msg* msg,dr_part_group_t*, int sort, gparam_t* wl); static int do_routing_0(struct sip_msg* msg); -static int do_routing_123(struct sip_msg* msg, char* str1, char* str2, char *str3); -static int use_next_gw(struct sip_msg* msg); -static int is_from_gw_0(struct sip_msg* msg, char* str1, char* str2); -static int is_from_gw_1(struct sip_msg* msg, char* str1, char* str2); -static int is_from_gw_2(struct sip_msg* msg, char* str1, char* str2); -static int goes_to_gw_0(struct sip_msg* msg, char* f1, char* f2); -static int goes_to_gw_1(struct sip_msg* msg, char* f1, char* f2); -static int dr_is_gw(struct sip_msg* msg, char* str1, char* str2, char* str3); -static int route2_carrier(struct sip_msg* msg, char* cr); -static int route2_gw(struct sip_msg* msg, char* gw); +static int do_routing_1(struct sip_msg* msg, char * , char* id, char* fl, char* wl, + char* rule_att, char* gw_att, char* carr_att); +static int use_next_gw(struct sip_msg* msg, + char* rule_or_part, char* rule_or_gw, char* gw_or_carr, char * carr); +static int is_from_gw_0(struct sip_msg* msg); +static int is_from_gw_1(struct sip_msg* msg, char * part); +static int is_from_gw_2(struct sip_msg* msg, char * part, char* str1); +static int is_from_gw_3(struct sip_msg* msg, char *, char*, char* ); +static int is_from_gw_4(struct sip_msg*, char*, char*, char*, char*); +static int goes_to_gw_0(struct sip_msg* msg); +static int goes_to_gw_1(struct sip_msg* msg, char * part, char* f1, char* f2, char* f3); +static int dr_is_gw(struct sip_msg* msg, char * part, char* str1, char* str2, char* str3, + char* str4); +static int route2_carrier(struct sip_msg* msg, char* cr_str, + char* gw_att_pv, char* carr_att_pv); +static int route2_gw(struct sip_msg* msg, char* gw, char* gw_att_pv); static struct mi_root* dr_reload_cmd(struct mi_root *cmd_tree, void *param); static struct mi_root* mi_dr_gw_status(struct mi_root *cmd, void *param); static struct mi_root* mi_dr_cr_status(struct mi_root *cmd, void *param); +static struct mi_root* mi_dr_number_routing(struct mi_root *cmd_tree, void *param); +static struct mi_root* mi_dr_reload_status(struct mi_root *cmd_tree, void *param); + + +/* event */ +static str dr_event = str_init("E_DROUTING_STATUS"); +static event_id_t dr_evi_id; /* @@ -190,39 +280,86 @@ static struct mi_root* mi_dr_cr_status(struct mi_root *cmd, void *param); static cmd_export_t cmds[] = { {"do_routing", (cmd_function)do_routing_0, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, - {"do_routing", (cmd_function)do_routing_123, 1, fixup_do_routing, 0, + {"do_routing", (cmd_function)do_routing_1, 1, fixup_do_routing, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"do_routing", (cmd_function)do_routing_1, 2, fixup_do_routing, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"do_routing", (cmd_function)do_routing_1, 3, fixup_do_routing, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, - {"do_routing", (cmd_function)do_routing_123, 2, fixup_do_routing, 0, + {"do_routing", (cmd_function)do_routing_1, 4, fixup_do_routing, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, - {"do_routing", (cmd_function)do_routing_123, 3, fixup_do_routing, 0, + {"do_routing", (cmd_function)do_routing_1, 5, fixup_do_routing, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"do_routing", (cmd_function)do_routing_1, 6, fixup_do_routing, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"do_routing", (cmd_function)do_routing_1, 7, fixup_do_routing, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, {"use_next_gw", (cmd_function)use_next_gw, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"use_next_gw", (cmd_function)use_next_gw, 1, fixup_next_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"use_next_gw", (cmd_function)use_next_gw, 2, fixup_next_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"use_next_gw", (cmd_function)use_next_gw, 3, fixup_next_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"use_next_gw", (cmd_function)use_next_gw, 4, fixup_next_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, {"next_routing", (cmd_function)use_next_gw, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"next_routing", (cmd_function)use_next_gw, 1, fixup_next_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"next_routing", (cmd_function)use_next_gw, 2, fixup_next_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"next_routing", (cmd_function)use_next_gw, 3, fixup_next_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, {"is_from_gw", (cmd_function)is_from_gw_0, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE}, {"is_from_gw", (cmd_function)is_from_gw_1, 1, fixup_from_gw, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE}, {"is_from_gw", (cmd_function)is_from_gw_2, 2, fixup_from_gw, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE}, + {"is_from_gw", (cmd_function)is_from_gw_3, 3, fixup_from_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE}, + {"is_from_gw", (cmd_function)is_from_gw_4, 4, fixup_from_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE}, {"goes_to_gw", (cmd_function)goes_to_gw_0, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"goes_to_gw", (cmd_function)goes_to_gw_1, 1, fixup_from_gw, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"goes_to_gw", (cmd_function)goes_to_gw_1, 2, fixup_from_gw, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"goes_to_gw", (cmd_function)goes_to_gw_1, 3, fixup_from_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"goes_to_gw", (cmd_function)goes_to_gw_1, 4, fixup_from_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"dr_is_gw", (cmd_function)dr_is_gw, 1, fixup_is_gw, 0, - REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"dr_is_gw", (cmd_function)dr_is_gw, 2, fixup_is_gw, 0, - REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"dr_is_gw", (cmd_function)dr_is_gw, 3, fixup_is_gw, 0, - REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, + {"dr_is_gw", (cmd_function)dr_is_gw, 4, fixup_is_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, + {"dr_is_gw", (cmd_function)dr_is_gw, 5, fixup_is_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"dr_disable", (cmd_function)dr_disable, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE}, - {"route_to_carrier",(cmd_function)route2_carrier,1,fixup_pvar_null, 0, + {"dr_disable", (cmd_function)dr_disable, 1, fixup_dr_disable, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE}, + {"route_to_carrier",(cmd_function)route2_carrier,1,fixup_route2_carrier, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, - {"route_to_gw", (cmd_function)route2_gw, 1,fixup_pvar_null, 0, + {"route_to_carrier",(cmd_function)route2_carrier,2,fixup_route2_carrier, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"route_to_carrier",(cmd_function)route2_carrier,3,fixup_route2_carrier, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"route_to_gw", (cmd_function)route2_gw, 1,fixup_route2_gw, 0, + REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, + {"route_to_gw", (cmd_function)route2_gw, 2,fixup_route2_gw, 0, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE}, {0, 0, 0, 0, 0, 0} }; @@ -232,31 +369,33 @@ static cmd_export_t cmds[] = { * Exported parameters */ static param_export_t params[] = { - {"db_url", STR_PARAM, &db_url.s }, - {"drd_table", STR_PARAM, &drd_table.s }, - {"drr_table", STR_PARAM, &drr_table.s }, - {"drg_table", STR_PARAM, &drg_table.s }, - {"drc_table", STR_PARAM, &drc_table.s }, - {"use_domain", INT_PARAM, &use_domain }, - {"drg_user_col", STR_PARAM, &drg_user_col.s }, - {"drg_domain_col", STR_PARAM, &drg_domain_col.s}, - {"drg_grpid_col", STR_PARAM, &drg_grpid_col.s }, - {"ruri_avp", STR_PARAM, &ruri_avp_spec.s }, - {"gw_id_avp", STR_PARAM, &gw_id_avp_spec.s }, - {"gw_attrs_avp", STR_PARAM, &gw_attrs_avp_spec.s }, - {"gw_priprefix_avp", STR_PARAM, &gw_priprefix_avp_spec.s }, - {"rule_id_avp", STR_PARAM, &rule_id_avp_spec.s }, - {"rule_attrs_avp", STR_PARAM, &rule_attrs_avp_spec.s }, - {"rule_prefix_avp", STR_PARAM, &rule_prefix_avp_spec.s }, - {"carrier_id_avp", STR_PARAM, &carrier_id_avp_spec.s }, - {"carrier_attrs_avp",STR_PARAM, &carrier_attrs_avp_spec.s}, - {"force_dns", INT_PARAM, &dr_force_dns }, - {"default_group", INT_PARAM, &dr_default_grp }, + {"use_partitions", INT_PARAM, &use_partitions }, + {"db_partitions_url", STR_PARAM, &db_partitions_url.s }, + {"db_partitions_table", STR_PARAM, &db_partitions_table.s }, + {"db_url", STR_PARAM, &db_url.s }, + {"drd_table", STR_PARAM, &drd_table.s }, + {"drr_table", STR_PARAM, &drr_table.s }, + {"drg_table", STR_PARAM, &drg_table.s }, + {"drc_table", STR_PARAM, &drc_table.s }, + {"use_domain", INT_PARAM, &use_domain }, + {"drg_user_col", STR_PARAM, &drg_user_col.s }, + {"drg_domain_col", STR_PARAM, &drg_domain_col.s }, + {"drg_grpid_col", STR_PARAM, &drg_grpid_col.s }, + {"ruri_avp", STR_PARAM, &ruri_avp_spec.s }, + {"gw_id_avp", STR_PARAM, &gw_id_avp_spec.s }, + {"gw_priprefix_avp", STR_PARAM, &gw_priprefix_avp_spec.s }, + {"gw_sock_avp", STR_PARAM, &gw_sock_avp_spec.s }, + {"rule_id_avp", STR_PARAM, &rule_id_avp_spec.s }, + {"rule_prefix_avp", STR_PARAM, &rule_prefix_avp_spec.s }, + {"carrier_id_avp", STR_PARAM, &carrier_id_avp_spec.s }, + {"force_dns", INT_PARAM, &dr_force_dns }, + {"default_group", INT_PARAM, &dr_default_grp }, {"define_blacklist", STR_PARAM|USE_FUNC_PARAM, (void*)set_dr_bl }, - { "probing_interval", INT_PARAM, &dr_prob_interval }, - { "probing_method", STR_PARAM, &dr_probe_method.s }, - { "probing_from", STR_PARAM, &dr_probe_from.s }, - { "probing_reply_codes", STR_PARAM, &dr_probe_replies.s }, + {"probing_interval", INT_PARAM, &dr_prob_interval }, + {"probing_method", STR_PARAM, &dr_probe_method.s }, + {"probing_from", STR_PARAM, &dr_probe_from.s }, + {"probing_reply_codes",STR_PARAM, &dr_probe_replies.s }, + {"persistent_state", INT_PARAM, &dr_persistent_state }, {0, 0, 0} }; @@ -268,23 +407,51 @@ static param_export_t params[] = { "into memory; A return string is returned only in case of error." #define HLP2 "Params: [ gw_id [ status ]] ; Sets/gets the status of a GW; "\ "If no gw_id is given, all gws will be listed; if a new status is give, "\ - "it will be pushed to the given GW." +"it will be pushed to the given GW." #define HLP3 "Params: [ carrier_id [ status ]] ; Sets/gets the status of a " \ "carrier; If no carrier_id is given, all carrier will be listed; if a " \ - "new status is give, it will be pushed to the given carrier." +"new status is give, it will be pushed to the given carrier." +#define HLP4 "Params: [partition] [group_id] number ; List the gateways a "\ + "number will match when searching through the rules from a specific group. "\ +"The partition parameter must be defined only if use_partitions = 1." +#define HLP5 "Params: [partition]; List the time of the last dr_reload"\ + " (load from database) for all partitions if no parameter is supplied, or"\ +" for a partition given as parameter. If use_partitions is 0, you should"\ +" not specify a partition." static mi_export_t mi_cmds[] = { - { "dr_reload", HLP1, dr_reload_cmd, MI_NO_INPUT_FLAG, 0, 0}, + { "dr_reload", HLP1, dr_reload_cmd, 0, 0, 0}, { "dr_gw_status", HLP2, mi_dr_gw_status, 0, 0, 0}, { "dr_carrier_status", HLP3, mi_dr_cr_status, 0, 0, 0}, + { "dr_number_routing", HLP4, mi_dr_number_routing, 0, 0, 0}, + { "dr_reload_status", HLP5, mi_dr_reload_status, 0, 0, 0}, { 0, 0, 0, 0, 0, 0} }; +static module_dependency_t *get_deps_probing_interval(param_export_t *param) +{ + if (*(int *)param->param_pointer <= 0) + return NULL; + return alloc_module_dep(MOD_TYPE_DEFAULT, "tm", DEP_ABORT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "probing_interval", get_deps_probing_interval }, + { NULL, NULL }, + }, +}; struct module_exports exports = { "drouting", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -312,28 +479,116 @@ static int check_options_rplcode(int code) return 0; } +static int dr_disable(struct sip_msg *req, char * param_part_name) { + str part_name; + struct head_db * current_partition = 0; + if( param_part_name!=NULL && fixup_get_svalue(req, + (gparam_p)param_part_name, + &part_name)==0 ) { + if( (current_partition = get_partition(&part_name))!= NULL) { + return dr_disable_w_part(req, current_partition); + } else { + LM_ERR("Given partition name <%*.s> was not found\n", part_name.len, part_name.s); + return -1; + } + } else { + if( use_partitions ) { + LM_ERR("Partition name is mandatory <%*.s>\n", part_name.len + ,part_name.s); + return -1; + } else { + if( head_db_start==NULL ) { + LM_ERR(" Error while loading default converation from .cfg" + " file\n"); + return -1; + } + return dr_disable_w_part(req, head_db_start); + } + } + return -1;/* unexpected ending */ +} -static int dr_disable(struct sip_msg *req) +static str dr_gwid_str = str_init("gwid"); +static str dr_address_str = str_init("address"); +static str dr_status_str = str_init("status"); +static str dr_inactive_str = str_init("inactive"); +static str dr_active_str = str_init("active"); +static str dr_disabled_str = str_init("disabled MI"); +static str dr_probing_str = str_init("probing"); + +static void dr_raise_event(pgw_t *gw) +{ + evi_params_p list = NULL; + str *txt; + if (dr_evi_id == EVI_ERROR || !evi_probe_event(dr_evi_id)) + return; + + list = evi_get_params(); + if (!list) { + LM_ERR("cannot create event params\n"); + return; + } + + if (evi_param_add_str(list, &dr_gwid_str, &gw->id) < 0) { + LM_ERR("cannot add gwid\n"); + goto error; + } + + if (evi_param_add_str(list, &dr_address_str, &gw->ip_str) < 0) { + LM_ERR("cannot add address\n"); + goto error; + } + + if (gw->flags&DR_DST_STAT_DSBL_FLAG) { + if (gw->flags&DR_DST_STAT_NOEN_FLAG) + txt = &dr_disabled_str; + else if (gw->flags&DR_DST_PING_DSBL_FLAG) + txt = &dr_probing_str; + else + txt = &dr_inactive_str; + } else { + txt = &dr_active_str; + } + + if (evi_param_add_str(list, &dr_status_str, txt) < 0) { + LM_ERR("cannot add state\n"); + goto error; + } + + if (evi_raise_event(dr_evi_id, list)) { + LM_ERR("unable to send dr event\n"); + } + return; + +error: + evi_free_params(list); +} + + +static int dr_disable_w_part(struct sip_msg *req, struct head_db *current_partition) { struct usr_avp *avp; int_str id_val; pgw_t *gw; - lock_start_read( ref_lock ); + lock_start_read( current_partition->ref_lock ); - avp = search_first_avp( AVP_VAL_STR|gw_id_avp.type, gw_id_avp.name, - &id_val,0); + avp = search_first_avp( AVP_VAL_STR, current_partition->gw_id_avp, &id_val,0); if (avp==NULL) { LM_DBG(" no AVP ID ->nothing to disable\n"); - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); return -1; } - gw = get_gw_by_id( (*rdata)->pgw_l, &id_val.s ); - if (gw!=NULL) - gw->flags |= DR_DST_STAT_DSBL_FLAG; + gw = get_gw_by_id( (*current_partition->rdata)->pgw_l, &id_val.s ); + if (gw!=NULL && (gw->flags&DR_DST_STAT_DSBL_FLAG)==0) { + LM_INFO(" partition : %.*s\n", current_partition->partition.len, + current_partition->partition.s); + gw->flags |= DR_DST_STAT_DSBL_FLAG|DR_DST_STAT_DIRT_FLAG; + dr_raise_event(gw); + } - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); return 1; } @@ -344,357 +599,908 @@ static void dr_probing_callback( struct cell *t, int type, { int code = ps->code; pgw_t *gw; + int _id ; + struct head_db * current_partition; - if (!*ps->param) { + if (!ps->param || !*ps->param) { LM_CRIT("BUG - reply to a DR probe with no ID (code=%d)\n", ps->code); return; } - lock_start_read( ref_lock ); + if( !((param_prob_callback_t*)*ps->param)->current_partition ) { + LM_CRIT("BUG - no partition supplied to callback function\n"); + return ; + } + + current_partition = ( (param_prob_callback_t*) *ps->param)->current_partition; - gw = get_gw_by_internal_id( (*rdata)->pgw_l, (int)(long)(*ps->param) ); + + + lock_start_read( current_partition->ref_lock ); + + _id = ((param_prob_callback_t*)*ps->param)->_id; + + gw = get_gw_by_internal_id( (*(current_partition->rdata))->pgw_l, _id); if (gw==NULL) goto end; if ((code == 200) || check_options_rplcode(code)) { /* re-enable to DST (if allowed) */ - if ( gw->flags&DR_DST_STAT_NOEN_FLAG ) + if ( (gw->flags&DR_DST_STAT_NOEN_FLAG)!=0 || /* permanently disabled */ + (gw->flags&DR_DST_STAT_DSBL_FLAG)==0) /* not disabled at all */ goto end; gw->flags &= ~DR_DST_STAT_DSBL_FLAG; + gw->flags |= DR_DST_STAT_DIRT_FLAG; + dr_raise_event(gw); goto end; } - if (code>=400) { - gw->flags |= DR_DST_STAT_DSBL_FLAG; + if (code>=400 && (gw->flags&DR_DST_STAT_DSBL_FLAG)==0) { + gw->flags |= DR_DST_STAT_DSBL_FLAG|DR_DST_STAT_DIRT_FLAG; + dr_raise_event(gw); + goto end; } end: - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); return; } +static void param_prob_callback_free(void *param) { + shm_free(param); +} + static void dr_prob_handler(unsigned int ticks, void* param) { static char buff[1000] = {"sip:"}; + /* do probing */ + pgw_t *dst; + param_prob_callback_t *params; + dlg_t *dlg; str uri; - if (rdata==NULL || *rdata==NULL) + struct head_db *it = head_db_start; + while( it!=NULL ) { + if (it->rdata==NULL || *(it->rdata)==NULL) + return; + + lock_start_read( it->ref_lock ); + + /* go through all destinations */ + for( dst = (*(it->rdata))->pgw_l ; dst ; dst=dst->next ) { + /* dst requires probing ? */ + if ( dst->flags&DR_DST_STAT_NOEN_FLAG + || !( (dst->flags&DR_DST_PING_PERM_FLAG) || /*permanent probing*/ + ( dst->flags&DR_DST_PING_DSBL_FLAG + && dst->flags&DR_DST_STAT_DSBL_FLAG /*probing on disable*/ + ) + ) + ) { + continue; + } + + memcpy(buff + 4, dst->ip_str.s, dst->ip_str.len); + uri.s = buff; + uri.len = dst->ip_str.len + 4; + + /* Execute the Dialog using the "request"-Method of the + * TM-Module.*/ + if (dr_tmb.new_auto_dlg_uac(&dr_probe_from, &uri, dst->sock, &dlg)!=0) { + LM_ERR("failed to create new TM dlg\n"); + continue; + } + dlg->state = DLG_CONFIRMED; + + params = shm_malloc(sizeof(param_prob_callback_t)); + if( params==0 ) { + LM_ERR("no more shm memory!\n"); + return; + } + params->_id = dst->_id; + params->current_partition = it; + + if (dr_tmb.t_request_within(&dr_probe_method, NULL, NULL, dlg, + dr_probing_callback, (void*)params, param_prob_callback_free) < 0) { + LM_ERR("unable to execute dialog\n"); + } + dr_tmb.free_dlg(dlg); + + } + + lock_stop_read( it->ref_lock ); + it = it->next; + } +} + + +static void dr_state_flusher(struct head_db* hd) +{ + static db_ps_t cr_ps=NULL, gw_ps=NULL; + pgw_t *gw; + pcr_t *cr; + db_key_t key_cmp; + db_val_t val_cmp; + db_key_t key_set; + db_val_t val_set; + + if(!hd) { + LM_ERR(" Bug - no head supplied to dr_state_flusher\n"); + } + + /* is data avaialable? */ + if (!hd || !(hd->rdata) || !(*hd->rdata)) return; - lock_start_read( ref_lock ); + val_cmp.type = DB_STR; + val_cmp.nul = 0; - /* do probing */ - pgw_t *dst; + val_set.type = DB_INT; + val_set.nul = 0; + + /* update the gateways */ + if ((hd->db_funcs).use_table( (*hd->db_con), &(hd->drd_table)) < 0) { + LM_ERR("cannot select table \"%.*s\"\n", hd->drd_table.len, hd->drd_table.s); + return; + } + key_cmp = &gwid_drd_col; + key_set = &state_drd_col; - /* go through all destinations */ - for( dst = (*rdata)->pgw_l ; dst ; dst=dst->next ) { - /* dst requires probing ? */ - if ( dst->flags&DR_DST_STAT_NOEN_FLAG - || !( (dst->flags&DR_DST_PING_PERM_FLAG) || /*permanent probing*/ - ( dst->flags&DR_DST_PING_DSBL_FLAG - && dst->flags&DR_DST_STAT_DSBL_FLAG /*probing on disable*/ - ) - ) - ) + /* iterate the gateways */ + for( gw=(*hd->rdata)->pgw_l ; gw ; gw=gw->next ) { + if ( (gw->flags & DR_DST_STAT_DIRT_FLAG)==0 ) + /* nothing to do for this gateway */ continue; - memcpy(buff + 4, dst->ip_str.s, dst->ip_str.len); - uri.s = buff; - uri.len = dst->ip_str.len + 4; - - if (dr_tmb.t_request( &dr_probe_method, &uri, &uri, - &dr_probe_from, NULL, NULL, NULL, dr_probing_callback, - (void*)(long)dst->_id, NULL) < 0) { - LM_ERR("probing failed\n"); + /* populate the update */ + val_cmp.val.str_val = gw->id; + val_set.val.int_val = (gw->flags&DR_DST_STAT_DSBL_FLAG) ? ((gw->flags&DR_DST_STAT_NOEN_FLAG)?1:2) : (0); + + /* update the state of this gateway */ + LM_DBG("updating the state of gw <%.*s> to %d\n", + gw->id.len, gw->id.s, val_set.val.int_val); + + CON_PS_REFERENCE(*hd->db_con) = gw_ps; + if ( (hd->db_funcs).update(*hd->db_con,&key_cmp,0,&val_cmp,&key_set,&val_set,1,1)<0 ) { + LM_ERR("DB update failed\n"); + } else { + gw->flags &= ~DR_DST_STAT_DIRT_FLAG; } + } + /* update the carriers */ + if ((hd->db_funcs).use_table( *hd->db_con, &(hd->drc_table)) < 0) { + LM_ERR("cannot select table \"%.*s\"\n", hd->drc_table.len, hd->drc_table.s); + return; } + key_cmp = &cid_drc_col; + key_set = &state_drc_col; + /* iterate the carriers */ + for( cr=(*hd->rdata)->carriers ; cr ; cr=cr->next ) { + if ( (cr->flags & DR_CR_FLAG_DIRTY)==0 ) + /* nothing to do for this carrier */ + continue; - lock_stop_read( ref_lock ); + /* populate the update */ + val_cmp.val.str_val = cr->id; + val_set.val.int_val = (cr->flags&DR_CR_FLAG_IS_OFF) ? 1 : 0; + + /* update the state of this carrier */ + LM_DBG("updating the state of cr <%.*s> to %d\n", + cr->id.len, cr->id.s, val_set.val.int_val); + + CON_PS_REFERENCE(*hd->db_con) = cr_ps; + if ( (hd->db_funcs).update(*hd->db_con,&key_cmp,0,&val_cmp,&key_set,&val_set,1,1)<0 ) { + LM_ERR("DB update failed\n"); + } else { + cr->flags &= ~DR_CR_FLAG_DIRTY; + } + } + + return; } -static inline int dr_reload_data( void ) +/* Flushes to DB the state of carriers and gateways (if modified) + * Locking is done to protect the data consistency */ +static void dr_state_timer(unsigned int ticks, void* param) +{ + struct head_db * it; + it = head_db_start; + while( it!=NULL ) { + lock_start_read( it->ref_lock ); + + dr_state_flusher(it); + + lock_stop_read( it->ref_lock ); + it = it->next; + } +} + +/* + * if none is succesfully loaded return + * -1, else return 0 + */ + +static inline int dr_reload_data_head( struct head_db *hd ) { rt_data_t *new_data; rt_data_t *old_data; + pgw_t *gw, *old_gw; + pcr_t *cr, *old_cr; + time_t rawtime; - new_data = dr_load_routing_info( &dr_dbf, db_hdl, - &drd_table, &drc_table, &drr_table); + new_data = dr_load_routing_info(hd, dr_persistent_state); if ( new_data==0 ) { LM_CRIT("failed to load routing info\n"); return -1; } - lock_start_write( ref_lock ); + lock_start_write( hd->ref_lock ); /* no more activ readers -> do the swapping */ - old_data = *rdata; - *rdata = new_data; + old_data = *(hd->rdata); + *(hd->rdata) = new_data; + /* update the time of the last reload for the current partition */ + time(&rawtime); + hd->time_last_update = rawtime; - lock_stop_write( ref_lock ); + lock_stop_write( (hd->ref_lock) ); /* destroy old data */ - if (old_data) + if (old_data) { + /* copy the state of gw/cr from old data */ + /* interate new gws and search them into old data */ + for( gw=new_data->pgw_l ; gw ; gw=gw->next ) { + old_gw = get_gw_by_id( old_data->pgw_l, &gw->id); + if (old_gw) { + gw->flags &= ~DR_DST_STAT_MASK; + gw->flags |= old_gw->flags&DR_DST_STAT_MASK; + } + } + /* interate new crs and search them into old data */ + for( cr=new_data->carriers ; cr ; cr=cr->next ) { + old_cr = get_carrier_by_id( old_data->carriers, &cr->id); + if (old_cr) { + cr->flags &= ~DR_CR_FLAG_IS_OFF; + cr->flags |= old_cr->flags&DR_CR_FLAG_IS_OFF; + } + } + + /* free old data */ free_rt_data( old_data, 1 ); + } /* generate new blacklist from the routing info */ - populate_dr_bls((*rdata)->pgw_l); + populate_dr_bls((*(hd->rdata))->pgw_l); return 0; } +static inline int dr_reload_data( void ) { + struct head_db * it_head_db; + int ret_val = 0; + + for( it_head_db=head_db_start; it_head_db!=NULL; + it_head_db=it_head_db->next ) { + if( dr_reload_data_head( it_head_db )!=0 ) + ret_val = -1; + } + return ret_val; +} + + +#define dr_fix_avp_def_w_default( _pv_spec, _avp_id, _default, _p_name, _name)\ + if(_pv_spec.s == NULL) { \ + if(use_partitions) {\ + _pv_spec.len = _default.len + _p_name.len;\ + _pv_spec.s = shm_malloc((_pv_spec.len)*sizeof(char));\ + memcpy(_pv_spec.s, _default.s, _default.len-1);\ + memcpy(_pv_spec.s + _default.len - 1, _p_name.s, _p_name.len);\ + _pv_spec.s[_pv_spec.len-1] = ')';\ + LM_DBG("name with partition:%.*s\n",_pv_spec.len, _pv_spec.s);\ + }\ + else { \ + shm_str_dup(&_pv_spec, &_default);\ + }\ + }\ +dr_fix_avp_definition(_pv_spec, _avp_id, _name); + +#define dr_fix_avp_definition( _pv_spec, _avp_id, _name) \ + do { \ + if (pv_parse_spec( &_pv_spec, &avp_spec)==0 \ + || avp_spec.type!=PVT_AVP) { \ + _pv_spec.len = strlen(_pv_spec.s); \ + LM_ERR("malformed or non AVP [%.*s] for %s AVP definition\n",\ + _pv_spec.len, _pv_spec.s, _name); \ + head_db_end->db_url.s = 0;\ + goto skip;\ + } \ + if( pv_get_avp_name(0, &(avp_spec.pvp), &_avp_id, &dummy )!=0) { \ + LM_ERR("[%.*s]- invalid AVP definition for %s AVP\n", \ + _pv_spec.len, _pv_spec.s, _name); \ + head_db_end->db_url.s = 0;\ + goto skip;\ + } \ + } while(0) + +#define add_partition_to_avp_name( _spec, _p_name, _name_w_part ) \ + _name_w_part.len = _spec.len + _p_name.len; \ +memcpy(_name_w_part.s, _spec.s, _spec.len);\ +memcpy(_name_w_part.s + _spec.len, _p_name.s, _p_name.len); + +static int cleanup_head_config( struct head_config *hd) { + LM_DBG("Cleanup started\n"); + if( hd==NULL ) { + LM_CRIT(" Cleanup head_config failed. Null pointer supplied\n"); + return -1; + } + + if( hd->db_url.s ) { + shm_free( hd->db_url.s ); + hd->db_url.s = 0; + } + + if( hd->drd_table.s && hd->drd_table.s != drd_table.s) { + shm_free( hd->drd_table.s ); + } + if( hd->drr_table.s && hd->drr_table.s != drr_table.s) { + shm_free( hd->drr_table.s ); + } + if( hd->drc_table.s && hd->drc_table.s != drc_table.s) { + shm_free( hd->drc_table.s ); + } + if( hd->drg_table.s && hd->drg_table.s != drg_table.s) { + shm_free( hd->drg_table.s ); + } + if(hd->gw_priprefix_avp_spec.s) + shm_free(hd->gw_priprefix_avp_spec.s); + if(hd->rule_id_avp_spec.s) + shm_free(hd->rule_id_avp_spec.s); + if(hd->rule_prefix_avp_spec.s) + shm_free(hd->rule_prefix_avp_spec.s); + if(hd->carrier_attrs_avp_spec.s) + shm_free(hd->carrier_attrs_avp_spec.s); + if(hd->ruri_avp_spec.s) + shm_free(hd->ruri_avp_spec.s); + if(hd->gw_id_avp_spec.s) + shm_free(hd->gw_id_avp_spec.s); + if(hd->gw_sock_avp_spec.s) + shm_free(hd->gw_sock_avp_spec.s); + if(hd->gw_attrs_avp_spec.s) + shm_free(hd->gw_attrs_avp_spec.s); + if(hd->rule_attrs_avp_spec.s) + shm_free(hd->rule_attrs_avp_spec.s); + if(hd->carrier_id_avp_spec.s) + shm_free(hd->carrier_id_avp_spec.s); + + return 0; +} + + +static int cleanup_head_db( struct head_db *hd) { + if(hd) { + if( hd->db_con && *(hd->db_con) ) { + hd->db_funcs.close(*(hd->db_con)); + } + if( hd->ref_lock ) { + lock_destroy_rw( ref_lock ); + } + if ( hd->rdata ) { + shm_free(hd->rdata); + hd->rdata = 0; + } + if ( hd->partition.s ) { + shm_free(hd->partition.s); + hd->partition.len = 0; + } + if( hd->db_url.s ) { + shm_free( hd->db_url.s ); + hd->db_url.len = 0; + } + if( hd->drd_table.s && hd->drd_table.s != drd_table.s) { + shm_free(hd->drd_table.s); + hd->drd_table.s = 0; + hd->drd_table.len = 0; + } + if( hd->drr_table.s && hd->drr_table.s != drr_table.s) { + shm_free(hd->drr_table.s); + hd->drr_table.s = 0; + hd->drr_table.len = 0; + } + if( hd->drc_table.s && hd->drc_table.s != drc_table.s) { + shm_free(hd->drc_table.s); + hd->drc_table.s = 0; + hd->drc_table.len = 0; + } + if( hd->drg_table.s && hd->drg_table.s != drg_table.s) { + shm_free(hd->drg_table.s); + hd->drg_table.s = 0; + hd->drg_table.len = 0; + } + + hd->avpID_store_ruri = -1; + hd->avpID_store_prefix = -1; + hd->avpID_store_index = -1; + hd->avpID_store_whitelist = -1; + hd->avpID_store_group = -1; + hd->avpID_store_flags = -1; + hd->gw_priprefix_avp = -1; + hd->rule_id_avp = -1; + hd->rule_prefix_avp = -1; + hd->carrier_id_avp = -1; + hd->ruri_avp = -1; + hd->gw_id_avp = -1; + hd->gw_sock_avp = -1; + hd->gw_attrs_avp = -1; + hd->rule_attrs_avp = -1; + hd->carrier_attrs_avp = -1; + } else { + LM_CRIT(" No head_db to clean supplied"); + return -1; + } + return 0; +} + +#define head_from_extern_param( dst, src, msg)\ + if( src.len != 0 ) \ +if( shm_str_dup( &dst, &src)!=0 ) {\ + LM_ERR(" Fail duplicating extern_param to head (%s)\n",msg); \ +} + +void init_head_w_extern_params(void) { + + head_from_extern_param( head_start->rule_id_avp_spec, + rule_id_avp_spec, "rule_id_avp_spec"); + + head_from_extern_param( head_start->rule_prefix_avp_spec, + rule_prefix_avp_spec, "rule_prefix_avp_spec"); + + head_from_extern_param( head_start->carrier_id_avp_spec, + carrier_id_avp_spec, "carrier_id_avp_spec"); + + head_from_extern_param( head_start->ruri_avp_spec, + ruri_avp_spec, "ruri_avp_spec"); + + head_from_extern_param( head_start->gw_id_avp_spec, + gw_id_avp_spec, "gw_id_avp_spec"); + + head_from_extern_param( head_start->gw_sock_avp_spec, + gw_sock_avp_spec, "gw_sock_avp_spec"); + + head_from_extern_param( head_start->gw_attrs_avp_spec, + gw_attrs_avp_spec, "gw_attrs_avp_spec"); + + head_from_extern_param( head_start->rule_attrs_avp_spec, + rule_attrs_avp_spec, "rule_attrs_avp_spec"); + + head_from_extern_param( head_start->carrier_attrs_avp_spec, + carrier_attrs_avp_spec, "carrier_attrs_avp_spec"); +} static int dr_init(void) { pv_spec_t avp_spec; - str name; + unsigned short dummy; + str name, name_w_part; + struct head_config * it_head_config = 0; + struct head_config * last_cleaned = 0; + struct head_db * it_head_db = 0, *to_clean = 0; + + head_start = NULL; //emtpy head list + head_end = NULL; LM_INFO("Dynamic-Routing - initializing\n"); - /* check the module params */ - init_db_url( db_url , 0 /*cannot be null*/); + name_w_part.s = shm_malloc( MAX_LEN_NAME_W_PART /* length of + fixed string */); + if( name_w_part.s == 0 ) { + LM_ERR(" No more shm memory [drouting:name_w_part.s]\n"); + goto error; + } - drd_table.len = strlen(drd_table.s); - if (drd_table.s[0]==0) { - LM_CRIT("mandatory parameter \"DRD_TABLE\" found empty\n"); - goto error; - } + if( use_partitions == 1 ) { /* loading configurations from db */ + if( get_config_from_db() == -1 ) { + LM_ERR("Failed to get configuration from db_config\n"); + goto error; + } + } else { + add_head_config(); - drr_table.len = strlen(drr_table.s); - if (drr_table.s[0]==0) { - LM_CRIT("mandatory parameter \"DRR_TABLE\" found empty\n"); - goto error; - } + /* if not empty save to head_config structure */ + drd_table.len = strlen(drd_table.s); + if (drd_table.s[0]==0) { + LM_CRIT("mandatory parameter \"DRD_TABLE\" found empty\n"); + goto error; + } else { + head_start->drd_table.s = shm_malloc( drd_table.len * sizeof(char) ); + if( head_start->drd_table.s == 0 ) { + LM_ERR(" no more shm memory [drouting:head_start->drd_table.s]\n"); + goto error; + } + memcpy( head_start->drd_table.s, drd_table.s, drd_table.len ); + head_start->drd_table.len = drd_table.len; + } - drg_table.len = strlen(drg_table.s); - if (drg_table.s[0]==0) { - LM_CRIT("mandatory parameter \"DRG_TABLE\" found empty\n"); - goto error; - } + drr_table.len = strlen(drr_table.s); + if (drr_table.s[0]==0) { + LM_CRIT("mandatory parameter \"DRR_TABLE\" found empty\n"); + goto error; + } else { + head_start->drr_table.s = shm_malloc( drr_table.len * sizeof(char) ); + if( head_start->drr_table.s == 0 ) { + LM_ERR(" no more shm memory [drouting:head_start->drr_table.s]\n"); + goto error; + } + memcpy( head_start->drr_table.s, drr_table.s, drr_table.len); + head_start->drr_table.len = drr_table.len; + } - drc_table.len = strlen(drc_table.s); - if (drc_table.s[0]==0) { - LM_CRIT("mandatory parameter \"DRC_TABLE\" found empty\n"); - goto error; + drg_table.len = strlen(drg_table.s); + if (drg_table.s[0]==0) { + LM_CRIT("mandatory parameter \"DRG_TABLE\" found empty\n"); + goto error; + } else { + head_start->drg_table.s = shm_malloc( drg_table.len * sizeof(char) ); + if( head_start->drg_table.s == 0 ) { + LM_ERR(" no more shm memory [drouting:head_start->drg_table.s]\n"); + goto error; + } + memcpy( head_start->drg_table.s, drg_table.s, drg_table.len); + head_start->drg_table.len = drg_table.len; + } + + drc_table.len = strlen(drc_table.s); + if ( drc_table.s[0]==0 ) { + LM_CRIT("mandatory parameter \"DRC_TABLE\" found empty\n"); + goto error; + } else { + head_start->drc_table.s = shm_malloc( drc_table.len * sizeof(char) ); + if( head_start->drc_table.s == 0 ) { + LM_ERR(" no more shm memory [drouting:head_start->drc_table.s]\n"); + goto error; + } + memcpy( head_start->drc_table.s, drc_table.s, drc_table.len); + head_start->drc_table.len = drc_table.len; + } + + db_url.len = strlen(db_url.s); + head_start->db_url.len = db_url.len; + head_start->db_url.s = shm_malloc( db_url.len * sizeof(char)); + if( head_start->db_url.s == 0 ) { + LM_ERR(" no more shm memory [drouting:head_start->db_url.s]\n"); + goto error; + } + memcpy( head_start->db_url.s, db_url.s, db_url.len ); + + init_head_w_extern_params(); + + head_start->partition.s = "Default"; + head_start->partition.len = strlen("Default\0"); } + it_head_config = head_start; + drg_user_col.len = strlen(drg_user_col.s); drg_domain_col.len = strlen(drg_domain_col.s); drg_grpid_col.len = strlen(drg_grpid_col.s); - /* fix specs for internal AVP (used for fallback) */ - name.s = "_dr_fb_ruri"; name.len=11; - if ( parse_avp_spec( &name, &avpID_store_ruri)!=0 ) { - LM_ERR("failed to init internal AVP for ruri\n"); - return E_UNSPEC; - } - name.s = "_dr_fb_prefix"; name.len=13; - if ( parse_avp_spec( &name, &avpID_store_prefix)!=0 ) { - LM_ERR("failed to init internal AVP for prefix\n"); - return E_UNSPEC; - } - name.s = "_dr_fb_index"; name.len=12; - if ( parse_avp_spec( &name, &avpID_store_index)!=0 ) { - LM_ERR("failed to init internal AVP for index\n"); - return E_UNSPEC; - } - name.s = "_dr_fb_whitelist"; name.len=16; - if ( parse_avp_spec( &name, &avpID_store_whitelist)!=0 ) { - LM_ERR("failed to init internal AVP for whitelist\n"); - return E_UNSPEC; - } - name.s = "_dr_fb_group"; name.len=12; - if ( parse_avp_spec( &name, &avpID_store_group)!=0 ) { - LM_ERR("failed to init internal AVP for group\n"); - return E_UNSPEC; - } - name.s = "_dr_fb_flags"; name.len=12; - if ( parse_avp_spec( &name, &avpID_store_flags)!=0 ) { - LM_ERR("failed to init internal AVP for flags\n"); - return E_UNSPEC; - } - - /* fix AVP specs for parameters */ - - ruri_avp_spec.len = strlen(ruri_avp_spec.s); - if (pv_parse_spec( &ruri_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP [%.*s] for RURI AVP definition\n", - ruri_avp_spec.len, ruri_avp_spec.s); - return E_CFG; - } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(ruri_avp.name), - &(ruri_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for RURI AVP\n", - ruri_avp_spec.len, ruri_avp_spec.s); - return E_CFG; - } + while(it_head_config != NULL) { + /* check if last head was ok, if not overwrite it */ + if( head_db_start==NULL || (head_db_start!=NULL && + head_db_end->db_url.s!=NULL) ) { + add_head_db(); + } - gw_id_avp_spec.len = strlen(gw_id_avp_spec.s); - if (pv_parse_spec( &gw_id_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP [%.*s] for ID AVP definition\n", - gw_id_avp_spec.len, gw_id_avp_spec.s); - return E_CFG; - } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(gw_id_avp.name), - &(gw_id_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for ID AVP\n", - gw_id_avp_spec.len, gw_id_avp_spec.s); - return E_CFG; - } + if( it_head_config->db_url.s==0 ) + continue; - if (gw_attrs_avp_spec.s) { - gw_attrs_avp_spec.len = strlen(gw_attrs_avp_spec.s); - if (pv_parse_spec( &gw_attrs_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP [%.*s] for ATTRS AVP definition\n", - gw_attrs_avp_spec.len, gw_attrs_avp_spec.s); - return E_CFG; + if( shm_str_dup( &( head_db_end->db_url ), + &(it_head_config->db_url))!=0 ) { + LM_CRIT("shm_str_dup failed for db_url"); + head_db_end->db_url.s = 0; + goto skip; } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(gw_attrs_avp.name), - &(gw_attrs_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for ATTRS AVP\n", - gw_attrs_avp_spec.len, gw_attrs_avp_spec.s); - return E_CFG; + + if( shm_str_dup( &( head_db_end->partition ), + &(it_head_config->partition))!=0 ) { + LM_CRIT("shm_str_dup failed for db_url"); + head_db_end->db_url.s = 0; + goto skip; } - } - if (gw_priprefix_avp_spec.s) { - gw_priprefix_avp_spec.len = strlen(gw_priprefix_avp_spec.s); - if (pv_parse_spec( &gw_priprefix_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP [%.*s] for PRI Prefix AVP definition\n", - gw_priprefix_avp_spec.len, gw_priprefix_avp_spec.s); - return E_CFG; + if(!it_head_config->drd_table.s) { + head_db_end->drd_table.s = drd_table.s; + head_db_end->drd_table.len = drd_table.len; + }else if( shm_str_dup( &( head_db_end->drd_table ), + &(it_head_config->drd_table))!=0 ) { + LM_CRIT("shm_str_dup failed for db_url"); + head_db_end->db_url.s = 0; + goto skip; } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(gw_priprefix_avp.name), - &(gw_priprefix_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for PRi Prefix AVP\n", - gw_priprefix_avp_spec.len, gw_priprefix_avp_spec.s); - return E_CFG; + + if(!it_head_config->drr_table.s) { + head_db_end->drr_table.s = drr_table.s; + head_db_end->drr_table.len = drr_table.len; + }else if( shm_str_dup( &( head_db_end->drr_table ), + &(it_head_config->drr_table))!=0 ) { + LM_CRIT("shm_str_dup failed for db_url"); + head_db_end->db_url.s = 0; + goto skip; } - } - if (rule_id_avp_spec.s) { - rule_id_avp_spec.len = strlen(rule_id_avp_spec.s); - if (pv_parse_spec( &rule_id_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP [%.*s] for ID AVP definition\n", - rule_id_avp_spec.len, rule_id_avp_spec.s); - return E_CFG; + if(!it_head_config->drc_table.s) { + head_db_end->drc_table.s = drc_table.s; + head_db_end->drc_table.len = drc_table.len; + } else if( shm_str_dup( &( head_db_end->drc_table ), + &(it_head_config->drc_table))!=0 ) { + LM_CRIT("shm_str_dup failed for db_url"); + head_db_end->db_url.s = 0; + goto skip; } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(rule_id_avp.name), - &(rule_id_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for ID AVP\n", - rule_id_avp_spec.len, rule_id_avp_spec.s); - return E_CFG; + if(!it_head_config->drg_table.s) { + head_db_end->drg_table.s = drg_table.s; + head_db_end->drg_table.len = drg_table.len; + } else if( shm_str_dup( &( head_db_end->drg_table ), + &(it_head_config->drg_table))!=0 ) { + LM_CRIT("shm_str_dup failed for db_url"); + head_db_end->db_url.s = 0; + goto skip; } - } - if (rule_attrs_avp_spec.s) { - rule_attrs_avp_spec.len = strlen(rule_attrs_avp_spec.s); - if (pv_parse_spec( &rule_attrs_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP [%.*s] for ATTRS AVP definition\n", - rule_attrs_avp_spec.len, rule_attrs_avp_spec.s); - return E_CFG; + + /* fix specs for internal AVP (used for fallback) */ + /* partition name is added to AVP name */ + + name.s = "_dr_fb_ruri_"; name.len=12; + add_partition_to_avp_name( name, it_head_config->partition, + name_w_part); + + if ( parse_avp_spec( &name_w_part, &(head_db_end->avpID_store_ruri))!=0 ) { + LM_ERR("failed to init internal AVP for ruri\n"); + head_db_end->db_url.s = 0; + goto skip; } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(rule_attrs_avp.name), - &(rule_attrs_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for ATTRS AVP\n", - rule_attrs_avp_spec.len, rule_attrs_avp_spec.s); - return E_CFG; + + name.s = "_dr_fb_prefix_"; name.len=14; + add_partition_to_avp_name( name, it_head_config->partition, + name_w_part); + if ( parse_avp_spec( &name_w_part, &(head_db_end->avpID_store_prefix))!=0 ) { + LM_ERR("failed to init internal AVP for prefix\n"); + head_db_end->db_url.s = 0; + goto skip; } - } - if (rule_prefix_avp_spec.s) { - rule_prefix_avp_spec.len = strlen(rule_prefix_avp_spec.s); - if (pv_parse_spec( &rule_prefix_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP [%.*s] for PREFIX AVP definition\n", - rule_prefix_avp_spec.len, rule_prefix_avp_spec.s); - return E_CFG; + name.s = "_dr_fb_index_"; name.len=13; + add_partition_to_avp_name( name, it_head_config->partition, + name_w_part); + if ( parse_avp_spec( &name_w_part, &(head_db_end->avpID_store_index))!=0 ) { + LM_ERR("failed to init internal AVP for index\n"); + head_db_end->db_url.s = 0; + goto skip; } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(rule_prefix_avp.name), - &(rule_prefix_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for PREFIX AVP\n", - rule_prefix_avp_spec.len, rule_prefix_avp_spec.s); - return E_CFG; + + name.s = "_dr_fb_whitelist_"; name.len=17; + add_partition_to_avp_name( name, it_head_config->partition, + name_w_part); + if ( parse_avp_spec( &name_w_part, &(head_db_end->avpID_store_whitelist))!=0 ) { + LM_ERR("failed to init internal AVP for whitelist\n"); + head_db_end->db_url.s = 0; + goto skip; } - } - if (carrier_id_avp_spec.s) { - carrier_id_avp_spec.len = strlen(carrier_id_avp_spec.s); - if (pv_parse_spec( &carrier_id_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("bad or non AVP [%.*s] for carrier id AVP definition\n", - carrier_id_avp_spec.len, carrier_id_avp_spec.s); - return E_CFG; + name.s = "_dr_fb_group_"; name.len=13; + add_partition_to_avp_name( name, it_head_config->partition, + name_w_part); + if ( parse_avp_spec( &name_w_part, &(head_db_end->avpID_store_group))!=0 ) { + LM_ERR("failed to init internal AVP for group\n"); + head_db_end->db_url.s = 0; + goto skip; } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(carrier_id_avp.name), - &(carrier_id_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for carrier id AVP\n", - carrier_id_avp_spec.len, carrier_id_avp_spec.s); - return E_CFG; + + name.s = "_dr_fb_flags_"; name.len=13; + add_partition_to_avp_name( name, it_head_config->partition, + name_w_part); + if ( parse_avp_spec( &name_w_part, &(head_db_end->avpID_store_flags))!=0 ) { + LM_ERR("failed to init internal AVP for flags\n"); + head_db_end->db_url.s = 0; + goto skip; + } + + /* fix AVP specs for parameters */ + dr_fix_avp_def_w_default( it_head_config->ruri_avp_spec, + head_db_end->ruri_avp, ruri_avp_spec, + it_head_config->partition, "RURI"); + + dr_fix_avp_def_w_default( it_head_config->gw_id_avp_spec, + head_db_end->gw_id_avp, gw_id_avp_spec, + it_head_config->partition, "GW ID"); + + dr_fix_avp_def_w_default( it_head_config->gw_sock_avp_spec, + head_db_end->gw_sock_avp, gw_sock_avp_spec, + it_head_config->partition, "GW SOCKET"); + + dr_fix_avp_def_w_default( it_head_config->gw_attrs_avp_spec, + head_db_end->gw_attrs_avp, gw_attrs_avp_spec, + it_head_config->partition, "GW ATTRS"); + + dr_fix_avp_def_w_default( it_head_config->rule_attrs_avp_spec, + head_db_end->rule_attrs_avp, rule_attrs_avp_spec, + it_head_config->partition, "RULE ATTRS"); + + dr_fix_avp_def_w_default( it_head_config->carrier_attrs_avp_spec, + head_db_end->carrier_attrs_avp, carrier_attrs_avp_spec, + it_head_config->partition, "CARRIER ATTRS"); + + if (it_head_config->gw_priprefix_avp_spec.s ) { + dr_fix_avp_definition( it_head_config->gw_priprefix_avp_spec, + head_db_end->gw_priprefix_avp, "GW PRI PREFIX"); } - } - if (carrier_attrs_avp_spec.s) { - carrier_attrs_avp_spec.len = strlen(carrier_attrs_avp_spec.s); - if (pv_parse_spec( &carrier_attrs_avp_spec, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("bad or non AVP [%.*s] for carrier attrs AVP definition\n", - carrier_attrs_avp_spec.len, carrier_attrs_avp_spec.s); - return E_CFG; + if (it_head_config->rule_id_avp_spec.s) { + dr_fix_avp_definition( it_head_config->rule_id_avp_spec, + head_db_end->rule_id_avp, "RULE ID"); } - if( pv_get_avp_name(0, &(avp_spec.pvp), &(carrier_attrs_avp.name), - &(carrier_attrs_avp.type) )!=0) { - LM_ERR("[%.*s]- invalid AVP definition for carrier attrs AVP\n", - carrier_attrs_avp_spec.len, carrier_attrs_avp_spec.s); - return E_CFG; + + if (it_head_config->rule_prefix_avp_spec.s) { + dr_fix_avp_definition( it_head_config->rule_prefix_avp_spec, + head_db_end->rule_prefix_avp, "RULE PREFIX"); } - } - if (init_dr_bls()!=0) { - LM_ERR("failed to init DR blacklists\n"); - return E_CFG; - } + if (it_head_config->carrier_id_avp_spec.s) { + dr_fix_avp_definition( it_head_config->carrier_id_avp_spec, + head_db_end->carrier_id_avp, "CARRIER ID"); + } - /* data pointer in shm */ - rdata = (rt_data_t**)shm_malloc( sizeof(rt_data_t*) ); - if (rdata==0) { - LM_CRIT("failed to get shm mem for data ptr\n"); - goto error; + + + + /* data pointer in shm */ + head_db_end->rdata = (rt_data_t**)shm_malloc( sizeof(rt_data_t*) ); + if ( head_db_end->rdata==0 ) { + LM_CRIT("failed to get shm mem for data ptr\n"); + head_db_end->db_url.s = 0; + goto skip; + } + + *(head_db_end->rdata) = 0; + + /* create & init lock */ + if ((head_db_end->ref_lock = lock_init_rw()) == NULL) { + LM_CRIT("failed to init lock\n"); + head_db_end->db_url.s = 0; + goto skip; + } + + head_db_end->db_con = pkg_malloc(sizeof(db_con_t **)); + (*(head_db_end->db_con)) = 0; + + /* bind to the mysql module */ + if (db_bind_mod( &(head_db_end->db_url), &( head_db_end->db_funcs ) )) { + LM_CRIT("cannot bind to database module! " + "Did you forget to load a database module ? (%.*s)\n", + db_url.len, db_url.s); + head_db_end->db_url.s = 0; + goto skip; + } + + if( (*head_db_end->db_con = + head_db_end->db_funcs.init(&head_db_end->db_url)) == 0) { + LM_ERR("Cand't load db ulr %.*s", head_db_end->db_url.len, + head_db_end->db_url.s); + return -1; + } + + if (!DB_CAPABILITY( head_db_end->db_funcs, DB_CAP_QUERY)) { + LM_CRIT( "database modules does not " + "provide QUERY functions needed by DRounting module\n"); + head_db_end->db_url.s = 0; + goto skip; + } + + if(db_check_table_version(&head_db_end->db_funcs, *head_db_end->db_con, + &head_db_end->drd_table, DRD_TABLE_VER) < 0) { + LM_ERR("error during table version check\n", head_db_end->drd_table.len, + head_db_end->drd_table.s, head_db_end->partition.len, + head_db_end->partition.s); + return -1; + } + + if(db_check_table_version(&head_db_end->db_funcs, *head_db_end->db_con, + &head_db_end->drr_table, DRR_TABLE_VER) < 0) { + LM_ERR("error during table version check\n", head_db_end->drr_table.len, + head_db_end->drr_table.s, head_db_end->partition.len, + head_db_end->partition.s); + return -1; + } + + if(db_check_table_version(&head_db_end->db_funcs, *head_db_end->db_con, + &head_db_end->drg_table, DRG_TABLE_VER) < 0) { + LM_ERR("error during table version check\n", head_db_end->drg_table.len, + head_db_end->drg_table.s, head_db_end->partition.len, + head_db_end->partition.s); + return -1; + } + + if(db_check_table_version(&head_db_end->db_funcs, *head_db_end->db_con, + &head_db_end->drc_table, DRC_TABLE_VER) < 0) { + LM_ERR("error during table version check\n", head_db_end->drc_table.len, + head_db_end->drc_table.s, head_db_end->partition.len, + head_db_end->partition.s); + return -1; + } + + (head_db_end->db_funcs).close(*head_db_end->db_con); + *head_db_end->db_con = 0; + + +skip: + it_head_config = it_head_config->next; + if(head_db_end->db_url.s == 0) { + cleanup_head_db(head_db_end); + memset( head_db_end, 0, sizeof(struct head_db) ); + } } - *rdata = 0; - /* create & init lock */ - if ((ref_lock = lock_init_rw()) == NULL) { - LM_CRIT("failed to init lock\n"); - goto error; + if( name_w_part.s ) { + shm_free(name_w_part.s); + name_w_part.s = 0; } - /* bind to the mysql module */ - if (db_bind_mod( &db_url, &dr_dbf )) { - LM_CRIT("cannot bind to database module! " - "Did you forget to load a database module ?\n"); - goto error; + /* free last head if left uninitialized */ + if( head_db_end!=NULL && head_db_end->db_url.s==NULL ) { + if( head_db_end==head_db_start ) { + cleanup_head_db( head_db_start ); + memset( head_db_start, 0, sizeof(struct head_db) ); + if( head_db_start ) { + shm_free( head_db_start ); + } + head_db_start=head_db_end = 0; + return -1; /* no valid head available */ + } else { + it_head_db = head_db_start; + while( it_head_db->next!=head_db_end ) + it_head_db = it_head_db->next; + to_clean = head_db_end; + head_db_end = it_head_db; + head_db_end->next = NULL; + cleanup_head_db( to_clean ); + memset( to_clean, 0, sizeof(struct head_db) ); + if( to_clean ) { + shm_free( to_clean ); + to_clean = 0; + } + + } } - if (!DB_CAPABILITY( dr_dbf, DB_CAP_QUERY)) { - LM_CRIT( "database modules does not " - "provide QUERY functions needed by DRounting module\n"); - return -1; + if (init_dr_bls(head_db_start)!=0) { + LM_ERR("failed to init DR blacklists\n"); + return E_CFG; } + it_head_config = head_start; + while( it_head_config ) { + cleanup_head_config( it_head_config ); + last_cleaned = it_head_config; + it_head_config = it_head_config->next; + + memset( last_cleaned, 0 , sizeof( struct head_config )); + if( last_cleaned ) { + shm_free( last_cleaned ); + last_cleaned = 0; + } + } + head_start = 0; + head_end = 0; - /* arm a function for probing */ if (dr_prob_interval) { /* load TM API */ if (load_tm_api(&dr_tmb)!=0) { @@ -710,7 +1516,7 @@ static int dr_init(void) /* register pinger function */ if (register_timer( "dr-pinger", dr_prob_handler, NULL, - dr_prob_interval)<0) { + dr_prob_interval)<0) { LM_ERR("failed to register probing handler\n"); return -1; } @@ -718,44 +1524,122 @@ static int dr_init(void) if (dr_probe_replies.s) { dr_probe_replies.len = strlen(dr_probe_replies.s); if(parse_reply_codes( &dr_probe_replies, &probing_reply_codes, - &probing_codes_no )< 0) { + &probing_codes_no )< 0) { LM_ERR("Bad format for options_reply_code parameter" - " - Need a code list separated by commas\n"); + " - Need a code list separated by commas\n"); return -1; } } } + if (dr_persistent_state) { + /* register function to flush changes in state */ + if (register_timer("dr-flush", dr_state_timer, NULL, 30)<0) { + LM_ERR("failed to register state flush handler\n"); + return -1; + } + } + LM_DBG("All in place in the init. Will return 0\n"); + + /* init the the default partition for do_routing */ + default_part = pkg_malloc(sizeof(dr_part_group_t)); + if(default_part == NULL) { + LM_ERR("No more pkg memory!\n"); + goto error; + } + memset(default_part, 0, sizeof(dr_part_group_t)); + default_part->dr_part = pkg_malloc(sizeof(dr_partition_t)); + if(default_part->dr_part == NULL) { + LM_ERR("No more pkg memory!\n"); + goto error; + } + memset(default_part->dr_part, 0, sizeof(dr_partition_t)); + default_part->dr_part->type = DR_PTR_PART; + default_part->dr_part->v.part = head_db_start; + + dr_evi_id = evi_publish_event(dr_event); + if (dr_evi_id == EVI_ERROR) { + LM_ERR("cannot register %.*s event\n", dr_event.len, dr_event.s); + goto error; + } + + + return 0; + error: - if (ref_lock) { - lock_destroy_rw( ref_lock ); - ref_lock = 0; + /* clean-up -> only when we used extern_params + * from the cfg*/ + if( head_db_end==head_db_start) { /* sanity check: should contain + only one head */ + cleanup_head_db( head_db_end ); + if( head_db_end!=0 ) { + shm_free( head_db_end ); + } + head_db_end=head_db_start = 0; + + cleanup_head_config( head_end ); + if( head_end!=0 ) { + shm_free( head_end ); + head_end = 0; + } + + + if (name_w_part.s) { + shm_free(name_w_part.s); + name_w_part.s = NULL; + } + } else { + LM_ERR(" Something went wrong: Head list should have only " + "one head\n"); + } + return -1; +} + + +static int db_load_head(struct head_db *x) { + + if( *(x->db_con) ) { + LM_ERR(" db_con already used\n"); + return -1; } - if (db_hdl) { - dr_dbf.close(db_hdl); - db_hdl = 0; + if( x->db_url.s && (*(x->db_con) = x->db_funcs.init(&(x->db_url)))==0 ) { + LM_ERR("cannot initialize database connection" + "(partition:%.*s, db_url:%.*s, len:%d)\n", x->partition.len, + x->partition.s, x->db_url.len, x->db_url.s, x->db_url.len); + return -1; } - if (rdata) { - shm_free(rdata); - rdata = 0; + if( x->db_con && *(x->db_con) && + x->db_funcs.use_table( *(x->db_con), &(x->drg_table)) <0 ) { + LM_ERR("cannot select table (partition:%.*s, drg_table:%.*s\n", + x->partition.len, x->partition.s, (x->drg_table).len, + (x->drg_table).s); + return -1; } - return -1; + return 0; } static int dr_child_init(int rank) { - /* only workers needs DB connection */ - if (rank==PROC_MAIN || rank==PROC_TCP_MAIN) + /* We need DB connection from: + * - attendant - for shutdown, flushingmstate + * - timer - may trigger routes with dr group + * - workers - execute routes with dr group + * - module's proc - ??? */ + LM_DBG("Child initialization\n"); + if (rank==PROC_TCP_MAIN || rank==PROC_BIN) return 0; - /* init DB connection */ - if ( (db_hdl=dr_dbf.init(&db_url))==0 ) { - LM_CRIT("cannot initialize database connection\n"); - return -1; + struct head_db *head_db_it = head_db_start; + + while( head_db_it!=NULL ) { + db_load_head( head_db_it ); + head_db_it = head_db_it->next; + + LM_DBG("Child iterates\n"); } /* child 1 load the routing info */ @@ -763,12 +1647,6 @@ static int dr_child_init(int rank) LM_CRIT("failed to load routing data\n"); return -1; } - - /* set GROUP table for workers */ - if (dr_dbf.use_table( db_hdl, &drg_table) < 0) { - LM_ERR("cannot select table \"%.*s\"\n", drg_table.len, drg_table.s); - return -1; - } srand(getpid()+time(0)+rank); return 0; } @@ -776,26 +1654,56 @@ static int dr_child_init(int rank) static int dr_exit(void) { - /* close DB connection */ - if (db_hdl) { - dr_dbf.close(db_hdl); - db_hdl = 0; - } + struct head_db * it = head_db_start, *to_clean; + + while( it!=NULL ) { + to_clean = it; + it = it->next; + if (dr_persistent_state && to_clean->db_con && *(to_clean->db_con)) + dr_state_flusher(to_clean); + + /* close DB connection */ + if (to_clean->db_con && *(to_clean->db_con)) { + (to_clean->db_funcs).close(*(to_clean->db_con)); + *(to_clean->db_con) = 0; + pkg_free(to_clean->db_con); + } - /* destroy data */ - if ( rdata) { - if (*rdata) - free_rt_data( *rdata, 1 ); - shm_free( rdata ); - rdata = 0; - } + /* destroy data */ + if ( to_clean->rdata) { + if (*(to_clean->rdata)) + free_rt_data( *(to_clean->rdata), 1 ); + shm_free( to_clean->rdata ); + to_clean->rdata = 0; + } + + /* destroy lock */ + if (to_clean->ref_lock) { + lock_destroy_rw( to_clean->ref_lock ); + to_clean->ref_lock = 0; + + } - /* destroy lock */ - if (ref_lock) { - lock_destroy_rw( ref_lock ); - ref_lock = 0; + /* free table names stored in head_db */ + if(to_clean->drd_table.s && to_clean->drd_table.s != drd_table.s) { + shm_free(to_clean->drd_table.s); + } + + if(to_clean->drr_table.s && to_clean->drr_table.s != drr_table.s) { + shm_free(to_clean->drr_table.s); + } + + if(to_clean->drc_table.s && to_clean->drc_table.s != drc_table.s) { + shm_free(to_clean->drc_table.s); + } + + if(to_clean->drg_table.s && to_clean->drg_table.s != drg_table.s) { + shm_free(to_clean->drg_table.s); + } + + shm_free(to_clean); } - + /* destroy blacklists */ destroy_dr_bls(); @@ -807,14 +1715,34 @@ static int dr_exit(void) static struct mi_root* dr_reload_cmd(struct mi_root *cmd_tree, void *param) { int n; + str * part_name; + struct head_db * part; + struct mi_node * node = NULL; LM_INFO("dr_reload MI command received!\n"); - if ( (n=dr_reload_data())!=0 ) { - LM_CRIT("failed to load routing data\n"); - goto error; + if(cmd_tree!=NULL) + node = cmd_tree->node.kids; + + if(node==NULL || use_partitions==0) { /* no parameter supplied */ + + if ( (n=dr_reload_data())!=0 ) { /* load the data for all the partitions */ + LM_CRIT("failed to load routing data\n"); + goto error; + } + } else { + part_name = &(node->value); + if( (part = get_partition(part_name))==NULL) { + LM_CRIT("Partition not found\n"); + goto error; + } + if( dr_reload_data_head(part)<0 ) { + LM_CRIT("Failed to load data head\n"); + goto error; + } } + return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); error: return init_mi_tree( 500, "Failed to reload",16); @@ -822,12 +1750,13 @@ static struct mi_root* dr_reload_cmd(struct mi_root *cmd_tree, void *param) -static inline int get_group_id(struct sip_uri *uri) +static inline int get_group_id(struct sip_uri *uri, struct head_db * + current_partition) { db_key_t keys_ret[1]; db_key_t keys_cmp[2]; db_val_t vals_cmp[2]; - db_res_t* res; + db_res_t* res = 0; int n; /* user */ @@ -848,7 +1777,16 @@ static inline int get_group_id(struct sip_uri *uri) keys_ret[0] = &drg_grpid_col; res = 0; - if ( dr_dbf.query(db_hdl,keys_cmp,0,vals_cmp,keys_ret,n,1,0,&res)<0 ) { + + if( (current_partition->db_funcs).use_table(*(current_partition->db_con), + &(current_partition->drg_table))<0 ) { + LM_ERR("cannot select table \"%.*s\"\n", + (current_partition->drg_table).len, + (current_partition->drg_table).s); + goto error; + } + if ( (current_partition->db_funcs).query(*(current_partition->db_con), + keys_cmp,0,vals_cmp,keys_ret,n,1,0,&res)<0 ) { LM_ERR("DB query failed\n"); goto error; } @@ -857,8 +1795,8 @@ static inline int get_group_id(struct sip_uri *uri) if (dr_default_grp!=-1) return dr_default_grp; LM_ERR("no group for user " - "\"%.*s\"@\"%.*s\"\n", uri->user.len, uri->user.s, - uri->host.len, uri->host.s); + "\"%.*s\"@\"%.*s\"\n", uri->user.len, uri->user.s, + uri->host.len, uri->host.s); goto error; } if (res->rows[0].values[0].nul || res->rows[0].values[0].type!=DB_INT) { @@ -867,25 +1805,26 @@ static inline int get_group_id(struct sip_uri *uri) } n = res->rows[0].values[0].val.int_val; - dr_dbf.free_result(db_hdl, res); + (current_partition->db_funcs).free_result(*(current_partition->db_con), res); return n; error: if (res) - dr_dbf.free_result(db_hdl, res); + (current_partition->db_funcs).free_result(*(current_partition->db_con) + , res); return -1; } static inline str* build_ruri(struct sip_uri *uri, int strip, str *pri, - str *hostport) + str *hostport) { static str uri_str; char *p; if (uri->user.len<=strip) { LM_ERR("stripping %d makes " - "username <%.*s> null\n",strip,uri->user.len,uri->user.s); + "username <%.*s> null\n",strip,uri->user.len,uri->user.s); return 0; } @@ -932,28 +1871,94 @@ static inline str* build_ruri(struct sip_uri *uri, int strip, str *pri, if (p-uri_str.s!=uri_str.len) { LM_CRIT("difference between allocated(%d)" - " and written(%d)\n",uri_str.len,(int)(long)(p-uri_str.s)); + " and written(%d)\n",uri_str.len,(int)(long)(p-uri_str.s)); return 0; } return &uri_str; } +static inline int init_part_grp(dr_part_group_t ** part_w_no_grp, + struct head_db * current_partition, dr_group_t * drg) { + dr_partition_t * part; + *part_w_no_grp = pkg_malloc(sizeof(dr_part_group_t)); + if(*part_w_no_grp == NULL) { + LM_ERR("No more pkg memory.\n"); + return -1; + } + + part = pkg_malloc(sizeof(dr_partition_t)); + if(part == NULL) { + LM_ERR("No more pkg memory.\n"); + return -1; + } + memset(part, 0, sizeof(dr_partition_t)); + part->type = DR_PTR_PART; + part->v.part = current_partition; + + (*part_w_no_grp)->group = drg; + (*part_w_no_grp)->dr_part = part; + return 0; +} + static int do_routing_0(struct sip_msg* msg) { - return do_routing(msg, NULL, 0, NULL); + rule_attrs_spec = gw_attrs_spec = carrier_attrs_spec = NULL; + dr_part_group_t * part_w_no_grp; + if(use_partitions == 0) { + if(head_db_start == NULL) { + LM_ERR("Error while loading configuration\n"); + return -1; + } + if(init_part_grp(&part_w_no_grp, head_db_start, 0) < 0) + return -1; + return do_routing(msg, part_w_no_grp, (int)0, NULL); + } else { + LM_ERR("Partition name is mandatory"); + return -1; + } + return -1; } -static int do_routing_123(struct sip_msg* msg, char* grp, char* param, - char* white_list) + +static int do_routing_1(struct sip_msg* msg, char *part_grp, char* grp_flags, + char* flags_wlst, char* wlst_rule, char* rule_gw, + char* gw_carr, char* carr) { str res = {0,0}; + dr_part_group_t * dr_part_group; int flags=0; char *p; + char * _flags, * wlst, * rule_att, * gw_att, * carr_att; + + if (use_partitions == 0) { + if(head_db_start == NULL) { + LM_CRIT("Can't load configuration.\n"); + return -1; + } + if(part_grp != NULL) { + default_part->group = ((dr_part_group_t*)part_grp)->group; + } else { + default_part->group = NULL; + } + dr_part_group = default_part; + _flags = grp_flags; + wlst = flags_wlst; + rule_att = wlst_rule; + gw_att = rule_gw; + carr_att = gw_carr; + } else { + dr_part_group = (dr_part_group_t*)part_grp; + _flags = grp_flags; + wlst = flags_wlst; + rule_att = wlst_rule; + gw_att = rule_gw; + carr_att = gw_carr; + } - if (param) { - if (fixup_get_svalue(msg, (gparam_p)param, &res) !=0){ - LM_ERR("falied to extract flags\n"); + if (_flags) { + if (fixup_get_svalue(msg, (gparam_p)_flags, &res) != 0) { + LM_ERR("failed to extract flags\n"); return -1; } @@ -983,103 +1988,201 @@ static int do_routing_123(struct sip_msg* msg, char* grp, char* param, } } - return do_routing(msg, (dr_group_t*)grp, flags, (gparam_t*)white_list); + rule_attrs_spec = (pv_spec_p)rule_att; + gw_attrs_spec = (pv_spec_p)gw_att; + carrier_attrs_spec = (pv_spec_p)carr_att; + + return do_routing(msg, (dr_part_group_t*)dr_part_group, flags, (gparam_t*)wlst); +} + +static int use_next_gw(struct sip_msg* msg, char* rule_or_part, + char * rule_or_gw, char *gw_carr, char * carr) { + dr_partition_t * part = 0; + struct head_db * current_partition = 0; + + if( use_partitions ) { /* first argument is partition name */ + part = (dr_partition_t*)rule_or_part; + if(part != NULL) { + if(part->type == DR_PTR_PART) { + current_partition = part->v.part; + } else if(part->type == DR_GPARAM_PART) { + if(to_partition(msg, part, ¤t_partition) < 0) { + return -1; + } + } + return use_next_gw_w_part(msg, current_partition, rule_or_gw, + gw_carr, carr); + } else { + LM_ERR("Partition is mandatory for use_next_gw.\n"); + return -1; + } + } else { /* setup from .cfg file => default partition */ + if(head_db_start == NULL) { + LM_ERR(" Error while loading default converation from .cfg" + " file\n"); + return -1; + } + return use_next_gw_w_part(msg, head_db_start, rule_or_part, + rule_or_gw, gw_carr); + } + return 0; } -static int use_next_gw(struct sip_msg* msg) +static int use_next_gw_w_part(struct sip_msg* msg, + struct head_db * current_partition, + char* rule_att, char* gw_att, char* carr_att) { - struct usr_avp *avp, *avp_ru; + struct usr_avp *avp, *avp_ru, *avp_sk; unsigned int flags; gparam_t wl_list; dr_group_t grp; int_str val; + pv_value_t pv_val; str ruri; + dr_part_group_t * part_grp; int ok; pgw_t * dst; + struct socket_info *sock; + rule_attrs_spec = (pv_spec_p)rule_att; + gw_attrs_spec = (pv_spec_p)gw_att; + carrier_attrs_spec = (pv_spec_p)carr_att; + + /* + * pop a value from each AVP + * (also remove all bogus non-STR top-most values) + */ while(1) { + if (rule_attrs_spec) { + avp = search_first_avp(0, current_partition->rule_attrs_avp, &val, NULL); + if (avp) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = val.s; + if (pv_set_value(msg, rule_attrs_spec, 0, &pv_val) != 0) + LM_ERR("failed to set value for rule attrs pvar\n"); + } + } + /* remove the old attrs */ - if (gw_attrs_avp.name!=-1) { + if (gw_attrs_spec) { avp = NULL; do { if (avp) destroy_avp(avp); - avp = search_first_avp( gw_attrs_avp.type, - gw_attrs_avp.name, NULL, 0); + avp = search_first_avp( 0, current_partition->gw_attrs_avp, NULL, NULL); }while (avp && (avp->flags&AVP_VAL_STR)==0 ); if (avp) destroy_avp(avp); + + avp = search_first_avp(0, current_partition->gw_attrs_avp, &val, NULL); + if (avp) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = val.s; + if (pv_set_value(msg, gw_attrs_spec, 0, &pv_val) != 0) + LM_ERR("failed to set value for gateway attrs pvar\n"); + } } - /* remove the old priprefix */ - if (gw_priprefix_avp.name!=-1) { + /* remove the old carrier attrs */ + if (carrier_attrs_spec) { avp = NULL; do { if (avp) destroy_avp(avp); - avp = search_first_avp( gw_priprefix_avp.type, - gw_priprefix_avp.name, NULL, 0); + avp = search_first_avp( 0, current_partition->carrier_attrs_avp, NULL, NULL); }while (avp && (avp->flags&AVP_VAL_STR)==0 ); if (avp) destroy_avp(avp); + + avp = search_first_avp(0, current_partition->carrier_attrs_avp, &val, NULL); + if (avp) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = val.s; + if (pv_set_value(msg, carrier_attrs_spec, 0, &pv_val) != 0) + LM_ERR("failed to set value for carrier attrs pvar\n"); + } } - /* remove the old carrier ID */ - if (carrier_id_avp.name!=-1) { + /* remove the old priprefix */ + if (current_partition->gw_priprefix_avp!=-1) { avp = NULL; do { if (avp) destroy_avp(avp); - avp = search_first_avp( carrier_id_avp.type, - carrier_id_avp.name, NULL, 0); + avp = search_first_avp( 0, current_partition->gw_priprefix_avp, NULL, NULL); }while (avp && (avp->flags&AVP_VAL_STR)==0 ); if (avp) destroy_avp(avp); } - /* remove the old carrier attrs */ - if (carrier_attrs_avp.name!=-1) { + /* remove the old carrier ID */ + if (current_partition->carrier_id_avp!=-1) { avp = NULL; do { if (avp) destroy_avp(avp); - avp = search_first_avp( carrier_attrs_avp.type, - carrier_attrs_avp.name, NULL, 0); + avp = search_first_avp( 0, current_partition->carrier_id_avp, NULL, NULL); }while (avp && (avp->flags&AVP_VAL_STR)==0 ); if (avp) destroy_avp(avp); } - /* remove old gw ID */ + /* remove old gw ID and search next one */ avp = NULL; do { if (avp) destroy_avp(avp); - avp = search_first_avp(gw_id_avp.type, gw_id_avp.name, NULL, 0); + avp = search_first_avp( 0, current_partition->gw_id_avp, + NULL, NULL); }while (avp && (avp->flags&AVP_VAL_STR)==0 ); - if (avp) destroy_avp(avp); + if (!avp) { + LM_WARN("no GWs found at all -> have you done do_routing in script ?? \n"); + return -1; + } + do { + if (avp) destroy_avp(avp); + avp = search_first_avp( 0, current_partition->gw_id_avp, + NULL, NULL); + }while (avp && (avp->flags&AVP_VAL_STR)==0 ); + /* any GW found ? */ + if (!avp) + goto rule_fallback; /* search for the first RURI AVP containing a string */ avp_ru = NULL; do { if (avp_ru) destroy_avp(avp_ru); - avp_ru = search_first_avp( ruri_avp.type, ruri_avp.name, &val, 0); + avp_ru = search_first_avp( 0, current_partition->ruri_avp, + &val, NULL); }while (avp_ru && (avp_ru->flags&AVP_VAL_STR)==0 ); if (!avp_ru) goto rule_fallback; - ruri = val.s; - LM_DBG("new RURI set to <%.*s>\n", val.s.len,val.s.s); - /* get value for next gw ID from avp */ - if (avp) { - get_avp_val(avp, &val); + /* search for the first SOCK AVP containing a string */ + avp_sk = NULL; + do { + if (avp_sk) destroy_avp(avp_sk); + avp_sk = search_first_avp( 0, current_partition->gw_sock_avp, + &val, NULL); + }while (avp_sk && (avp_sk->flags&AVP_VAL_STR)==0 ); + if (!avp_sk) { + /* this shuold not happen, it is a bogus state */ + sock = NULL; } else { - /* if no other ID found, simply use the GW as good */ - break; + if (sscanf( val.s.s, "%p", (void**)&sock ) != 1) + sock = NULL; + destroy_avp(avp_sk); } + LM_DBG("new RURI set to <%.*s> via socket <%.*s>\n", + val.s.len,val.s.s, + sock?sock->name.len:4, sock?sock->name.s:"none"); + + /* get value for next gw ID from avp */ + get_avp_val(avp, &val); + /* we have an ID, so we can check the GW state */ - lock_start_read( ref_lock ); - dst = get_gw_by_id( (*rdata)->pgw_l, &val.s); + lock_start_read( current_partition->ref_lock ); + dst = get_gw_by_id( (*current_partition->rdata)->pgw_l, &val.s); if (dst && (dst->flags & DR_DST_STAT_DSBL_FLAG) == 0) ok = 1; - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); if ( ok ) break; @@ -1092,6 +2195,8 @@ static int use_next_gw(struct sip_msg* msg) LM_ERR("failed to rewite RURI\n"); return -1; } + if (sock) + msg->force_send_socket = sock; destroy_avp(avp_ru); @@ -1099,23 +2204,27 @@ static int use_next_gw(struct sip_msg* msg) rule_fallback: + LM_DBG("using rule fallback\n"); /* check if a "flags" AVP is there and if fallback allowed */ - avp = search_first_avp( 0, avpID_store_flags, &val, 0); + avp = search_first_avp( 0, current_partition->avpID_store_flags, + &val, NULL); if (avp==NULL || !(val.n & DR_PARAM_RULE_FALLBACK) ) return -1; /* fallback allowed, fetch the rest of data from AVPs */ flags = val.n | DR_PARAM_INTERNAL_TRIGGERED; - if (search_first_avp( 0, avpID_store_group, &val, 0)==NULL) { + if (!search_first_avp( 0, current_partition->avpID_store_group, + &val, NULL)) { LM_ERR("Cannot find group AVP during a fallback\n"); goto fallback_failed; } grp.type = 0; grp.u.grp_id = val.n; - if (search_first_avp( AVP_VAL_STR, avpID_store_whitelist, &val, 0)==NULL) { + if (!search_first_avp( AVP_VAL_STR, current_partition->avpID_store_whitelist, + &val, NULL)) { wl_list.type = 0; } else { wl_list.type = GPARAM_TYPE_STR; @@ -1123,7 +2232,14 @@ static int use_next_gw(struct sip_msg* msg) wl_list.v.sval.s[--wl_list.v.sval.len] = 0; } - if (do_routing( msg, &grp, flags, wl_list.type?&wl_list:NULL)==1) { + part_grp = pkg_malloc(sizeof(dr_part_group_t)); + if(part_grp == NULL) { + LM_ERR("No more pkg memory!\n"); + return -1; + } + + init_part_grp(&part_grp, current_partition, &grp); + if (do_routing( msg, part_grp, flags, wl_list.type?&wl_list:NULL)==1) { return 1; } @@ -1137,7 +2253,7 @@ static int use_next_gw(struct sip_msg* msg) #define DR_MAX_GWLIST 64 static int sort_rt_dst(pgw_list_t *pgwl, unsigned short size, - int weight, unsigned short *idx) + int weight, unsigned short *idx) { unsigned short running_sum[DR_MAX_GWLIST]; unsigned int i, first, weight_sum, rand_no; @@ -1155,7 +2271,7 @@ static int sort_rt_dst(pgw_list_t *pgwl, unsigned short size, weight_sum += pgwl[ idx[i] ].weight ; running_sum[i] = weight_sum; LM_DBG("elen %d, weight=%d, sum=%d\n",i, - pgwl[ idx[i] ].weight, running_sum[i]); + pgwl[ idx[i] ].weight, running_sum[i]); } if (weight_sum) { /* randomly select number */ @@ -1163,18 +2279,18 @@ static int sort_rt_dst(pgw_list_t *pgwl, unsigned short size, LM_DBG("random number is %d\n",rand_no); /* select the element */ for( i=first ; i=rand_no) break; + if (running_sum[i]>rand_no) break; if (i==size) { LM_CRIT("bug in weight sort\n"); return -1; } } else { /* randomly select index */ - // i = (unsigned int)((size-first)*((float)rand()/RAND_MAX)); + // i = (unsigned int)((size-first)*((float)rand()/RAND_MAX)); i = first; } LM_DBG("selecting element %d with weight %d\n", - idx[i], pgwl[ idx[i] ].weight); + idx[i], pgwl[ idx[i] ].weight); /* "i" is the selected element : swap it with first position and retake alg without first elem */ rand_no = idx[i]; @@ -1187,11 +2303,15 @@ static int sort_rt_dst(pgw_list_t *pgwl, unsigned short size, } -inline static int push_gw_for_usage(struct sip_msg *msg, struct sip_uri *uri, - pgw_t *gw , str *c_id, str *c_attrs, int idx) +inline static int push_gw_for_usage(struct sip_msg *msg, struct head_db *current_partition, + struct sip_uri *uri, pgw_t *gw , str *c_id, str *c_attrs, int idx) { + char buf[2+16+1]; /* a hexa string */ str *ruri; int_str val; + if( current_partition==NULL ) { + return -1; + } /* build uri*/ ruri = build_ruri( uri, gw->strip, &gw->pri, &gw->ip_str); @@ -1205,67 +2325,80 @@ inline static int push_gw_for_usage(struct sip_msg *msg, struct sip_uri *uri, /* first GW to be added ? */ if (idx==0) { + /* add to RURI */ if (set_ruri( msg, ruri)!= 0 ) { LM_ERR("failed to set new RURI\n"); goto error; } + /* set socket to be used */ + if (gw->sock) + msg->force_send_socket = gw->sock; } else { /* add ruri as AVP */ val.s = *ruri; - if (add_avp_last( AVP_VAL_STR|(ruri_avp.type),ruri_avp.name, val)!=0 ) { + if (add_avp_last( AVP_VAL_STR, current_partition->ruri_avp, val)!=0 ) { LM_ERR("failed to insert ruri avp\n"); goto error; } + /* add GW sock avp */ + val.s.len = 1 + sprintf( buf, "%p", gw->sock ); + val.s.s = buf; + LM_DBG("setting GW sock [%.*s] as avp\n",val.s.len, val.s.s); + if (add_avp_last( AVP_VAL_STR, current_partition->gw_sock_avp, val)!=0 ) { + LM_ERR("failed to insert sock avp\n"); + goto error; + } + } /* add GW id avp */ val.s = gw->id; LM_DBG("setting GW id [%.*s] as avp\n",val.s.len, val.s.s); - if (add_avp_last( AVP_VAL_STR|(gw_id_avp.type),gw_id_avp.name, val)!=0 ) { + if (add_avp_last( AVP_VAL_STR, current_partition->gw_id_avp, val)!=0 ) { LM_ERR("failed to insert ids avp\n"); goto error; } - /* add GW attrs avp */ - if (gw_attrs_avp.name!=-1) { + /* add internal GW attrs avp if requested at least once in the script */ + if (populate_gw_attrs) { val.s = gw->attrs.s? gw->attrs : attrs_empty; - LM_DBG("setting GW attr [%.*s] as avp\n",val.s.len,val.s.s); - if (add_avp_last(AVP_VAL_STR|(gw_attrs_avp.type),gw_attrs_avp.name,val)!=0){ - LM_ERR("failed to insert attrs avp\n"); + LM_DBG("setting GW attr [%.*s] as avp\n", val.s.len, val.s.s); + if (add_avp_last(AVP_VAL_STR, current_partition->gw_attrs_avp, + val)!=0){ + LM_ERR("failed to insert gw attrs avp\n"); goto error; } } /* add GW priprefix avp */ - if (gw_priprefix_avp.name!=-1) { + if (current_partition->gw_priprefix_avp!=-1) { val.s = gw->pri.s? gw->pri : attrs_empty; LM_DBG("setting GW priprefix [%.*s] as avp\n",val.s.len,val.s.s); - if (add_avp_last(AVP_VAL_STR|(gw_priprefix_avp.type),gw_priprefix_avp.name,val)!=0){ + if (add_avp_last(AVP_VAL_STR, current_partition->gw_priprefix_avp, val)!=0){ LM_ERR("failed to insert priprefix avp\n"); goto error; } } - if (carrier_id_avp.name!=-1) { + if (current_partition->carrier_id_avp!=-1) { val.s = (c_id && c_id->s)? *c_id : attrs_empty ; LM_DBG("setting CR Id [%.*s] as avp\n",val.s.len,val.s.s); - if (add_avp_last(AVP_VAL_STR|(carrier_id_avp.type), - carrier_id_avp.name,val)!=0){ + if (add_avp_last(AVP_VAL_STR, current_partition->carrier_id_avp, val)!=0){ LM_ERR("failed to insert attrs avp\n"); goto error; } } - if (carrier_attrs_avp.name!=-1) { - val.s = (c_attrs && c_attrs->s)? *c_attrs : attrs_empty ; - LM_DBG("setting CR attr [%.*s] as avp\n",val.s.len,val.s.s); - if (add_avp_last(AVP_VAL_STR|(carrier_attrs_avp.type), - carrier_attrs_avp.name,val)!=0){ - LM_ERR("failed to insert attrs avp\n"); + /* add internal carrier attrs avp if requested at least once in the script */ + if (populate_carrier_attrs) { + val.s = (c_attrs && c_attrs->s)? *c_attrs : attrs_empty; + LM_DBG("setting CR attr [%.*s] as avp\n", val.s.len, val.s.s); + if (add_avp_last(AVP_VAL_STR, current_partition->carrier_attrs_avp, val)!=0) { + LM_ERR("failed to insert carrier attrs avp\n"); goto error; } } @@ -1288,30 +2421,49 @@ static inline int is_dst_in_list(void* dst, pgw_list_t *list, unsigned short len if (dst==(void*)list[i].dst.gw) return 1; } - return 0; + return 0; +} + +struct head_db * get_partition(const str *name) { + struct head_db * it = head_db_start; + + while( it!= NULL) { + if( it->partition.len==name->len && memcmp( it->partition.s, name->s, + name->len)==0 ) { + return it; + } + it = it->next; + } + + return NULL; /* partition was not found */ } -static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, - gparam_t* whitelist) +static int do_routing(struct sip_msg* msg, dr_part_group_t * part_group, + int flags, gparam_t* whitelist) { unsigned short dsts_idx[DR_MAX_GWLIST]; unsigned short carrier_idx[DR_MAX_GWLIST]; struct to_body *from; struct sip_uri uri; rt_info_t *rt_info; + pv_value_t pv_val; struct usr_avp *avp, *avp_prefix=NULL, *avp_index=NULL; str parsed_whitelist; pgw_list_t *dst, *cdst; pgw_list_t *wl_list; unsigned int prefix_len; unsigned int rule_idx; + struct head_db *current_partition=NULL; unsigned short wl_len; + dr_group_t * drg; str username; int grp_id; int i, j, n; int_str val; str ruri; + str next_carrier_attrs = {NULL, 0}; + str next_gw_attrs = {NULL, 0}; int ret; char tmp; char *ruri_buf; @@ -1321,44 +2473,70 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, wl_list = NULL; rt_info = NULL; - if ( (*rdata)==0 || (*rdata)->pgw_l==0 ) { + if(use_partitions) { + if(part_group == NULL || part_group->dr_part == NULL || part_group->dr_part->type == DR_NO_PART) { + LM_ERR("Partition name is mandatory for do_routing\n"); + return -1; + } + if(part_group->dr_part->type == DR_GPARAM_PART) { + if(to_partition(msg, part_group->dr_part, ¤t_partition) < 0) { + return -1; + } + } else if(part_group->dr_part->type == DR_PTR_PART) { + current_partition = part_group->dr_part->v.part; + } + } else { + if(part_group->dr_part->type == DR_PTR_PART) { + current_partition = part_group->dr_part->v.part; + } else { + LM_ERR("Error while loading configuration for do_routing\n"); + } + } + drg = part_group->group; + + + + /* allow no GWs if we're only trying to use DR for checking purposes */ + if ( *(current_partition->rdata)==0 || ((flags & DR_PARAM_ONLY_CHECK) == 0 + && (*(current_partition->rdata))->pgw_l==0 )) { LM_DBG("empty routing table\n"); goto error1; } + /* do some cleanup first */ - destroy_avps( ruri_avp.type, ruri_avp.name, 1); - destroy_avps( gw_id_avp.type, gw_id_avp.name, 1); - if (gw_attrs_avp.name!=-1) - destroy_avps( gw_attrs_avp.type, gw_attrs_avp.name, 1); - if (gw_priprefix_avp.name!=-1) - destroy_avps( gw_priprefix_avp.type, gw_priprefix_avp.name, 1); - if (rule_id_avp.name!=-1) - destroy_avps( rule_id_avp.type, rule_id_avp.name, 1); - if (rule_attrs_avp.name!=-1) - destroy_avps( rule_attrs_avp.type, rule_attrs_avp.name, 1); - if (rule_prefix_avp.name!=-1) - destroy_avps( rule_prefix_avp.type, rule_prefix_avp.name, 1); + destroy_avps( 0, current_partition->ruri_avp, 1); + destroy_avps( 0, current_partition->gw_id_avp, 1); + destroy_avps( 0, current_partition->gw_sock_avp, 1); + destroy_avps( 0, current_partition->rule_attrs_avp, 1); + destroy_avps( 0, current_partition->gw_attrs_avp, 1); + destroy_avps( 0, current_partition->carrier_attrs_avp, 1); - if ( !(flags & DR_PARAM_INTERNAL_TRIGGERED) ) { - /* not internally triggered, so get data from SIP msg */ + if ((current_partition->gw_priprefix_avp)!=-1) + destroy_avps( 0, current_partition->gw_priprefix_avp, 1); + if ((current_partition->rule_id_avp)!=-1) + destroy_avps( 0, current_partition->rule_id_avp, 1); + if ((current_partition->rule_prefix_avp)!=-1) + destroy_avps( 0, current_partition->rule_prefix_avp, 1); - /* get the username from FROM_HDR */ - if (parse_from_header(msg)!=0) { - LM_ERR("unable to parse from hdr\n"); - goto error1; - } - from = (struct to_body*)msg->from->parsed; - /* parse uri */ - if (parse_uri( from->uri.s, from->uri.len, &uri)!=0) { - LM_ERR("unable to parse from uri\n"); - goto error1; - } - /* get user's routing group */ + if ( !(flags & DR_PARAM_INTERNAL_TRIGGERED) ) { + /* not internally triggered, so get data from SIP msg */ if(drg==NULL) { - grp_id = get_group_id( &uri ); + /* get the username from FROM_HDR */ + if (parse_from_header(msg)!=0) { + LM_ERR("unable to parse from hdr\n"); + goto error1; + } + from = (struct to_body*)msg->from->parsed; + /* parse uri */ + if (parse_uri( from->uri.s, from->uri.len, &uri)!=0) { + LM_ERR("unable to parse from uri\n"); + goto error1; + } + + grp_id = get_group_id( &uri, current_partition); if (grp_id<0) { LM_ERR("failed to get group id\n"); goto error1; @@ -1368,14 +2546,14 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, grp_id = (int)drg->u.grp_id; else if(drg->type==1) { grp_id = 0; /* call get avp here */ - if((avp=search_first_avp( drg->u.avp_id.type, - drg->u.avp_id.name, &val, 0))==NULL||(avp->flags&AVP_VAL_STR)) { - LM_ERR( "failed to get group id\n"); + if((avp=search_first_avp( 0, drg->u.avp_name, &val, 0))==NULL || + (avp->flags&AVP_VAL_STR) ) { + LM_ERR( "failed to get group id from avp\n"); goto error1; } grp_id = val.n; } else - grp_id = 0; + grp_id = 0; } /* get the number/RURI and make a copy of it */ @@ -1400,7 +2578,8 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, } else { /* resume index on the rule under same prefix */ - avp_index = search_first_avp( 0, avpID_store_index, &val, 0); + avp_index = search_first_avp( 0, current_partition->avpID_store_index, + &val, 0); if (avp_index==NULL) { LM_ERR("Cannot find index AVP during a fallback\n"); goto error1; @@ -1408,7 +2587,8 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, rule_idx = val.n; /* prefix to resume with */ - avp_prefix = search_first_avp( AVP_VAL_STR, avpID_store_prefix, &val, 0); + avp_prefix = search_first_avp( AVP_VAL_STR, + current_partition->avpID_store_prefix, &val, 0); if (avp_prefix==NULL) { LM_ERR("Cannot find prefix AVP during a fallback\n"); goto error1; @@ -1418,7 +2598,7 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, if (username.len==0) return -1; /* original RURI to be used when building RURIs for new attempts */ - if (search_first_avp( AVP_VAL_STR, avpID_store_ruri, &val, 0)==NULL) { + if (search_first_avp( AVP_VAL_STR, current_partition->avpID_store_ruri, &val, 0)==NULL) { LM_ERR("Cannot find ruri AVP during a fallback\n"); goto error1; } @@ -1426,27 +2606,26 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, LM_ERR("unable to parse RURI from AVP\n"); goto error1; } - grp_id = (int)drg->u.grp_id; ruri.s = NULL; ruri.len = 0; } LM_DBG("using dr group %d, rule_idx %d, username %.*s\n", - grp_id,rule_idx,username.len,username.s); + grp_id,rule_idx,username.len,username.s); /* ref the data for reading */ - lock_start_read( ref_lock ); + lock_start_read( current_partition->ref_lock ); search_again: if (rt_info) { - /* we are here because of the "search_again", on a + /* we are here because of the "search_again", on a sequential retry based on rule FALL BACK */ /* => force fallback, either on next rule, either on shorter prefix */ username.len = prefix_len -(rule_idx?0:1); LM_DBG("doing internal fallback, prefix_len=%d,rule_idx=%d\n", - username.len, rule_idx); + username.len, rule_idx); if (username.len==0 && rule_idx==0) { /* disable failover as nothing left */ flags = flags & ~DR_PARAM_RULE_FALLBACK; @@ -1455,8 +2634,8 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, } /* search a prefix */ - rt_info = get_prefix( (*rdata)->pt, &username , (unsigned int)grp_id, - &prefix_len, &rule_idx); + rt_info = get_prefix( (*(current_partition->rdata))->pt, &username, + (unsigned int)grp_id,&prefix_len, &rule_idx); if (flags & DR_PARAM_STRICT_LEN) { if (rt_info==NULL || prefix_len!=username.len) @@ -1465,12 +2644,13 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, if (rt_info==0) { LM_DBG("no matching for prefix \"%.*s\"\n", - username.len, username.s); + username.len, username.s); /* try prefixless rules */ - rt_info = check_rt( &(*rdata)->noprefix, (unsigned int)grp_id); + rt_info = check_rt( &(*(current_partition->rdata))->noprefix, + (unsigned int)grp_id); if (rt_info==0) { LM_DBG("no prefixless matching for " - "grp %d\n", grp_id); + "grp %d\n", grp_id); goto error2; } prefix_len = 0; @@ -1481,7 +2661,7 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, if (ret&ACT_FL_DROP) { /* drop the action */ LM_DBG("script route %s drops routing " - "by %d\n", rlist[rt_info->route_idx].name, ret); + "by %d\n", rlist[rt_info->route_idx].name, ret); ret = -1; goto error2; } @@ -1501,7 +2681,7 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, if (rt_info->pgwl==NULL) { LM_INFO("no destination for dr group %d, rule_idx %d, username %.*s\n", - grp_id,rule_idx,username.len,username.s); + grp_id,rule_idx,username.len,username.s); if ( flags & DR_PARAM_RULE_FALLBACK ) goto search_again; goto error2; @@ -1509,7 +2689,7 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, /* sort the destination elements in the rule */ i = sort_rt_dst(rt_info->pgwl, rt_info->pgwa_len, - flags&DR_PARAM_USE_WEIGTH, dsts_idx); + flags&DR_PARAM_USE_WEIGTH, dsts_idx); if (i!=0) { LM_ERR("failed to sort destinations in rule\n"); goto error2; @@ -1523,8 +2703,8 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, } else { tmp = parsed_whitelist.s[parsed_whitelist.len]; parsed_whitelist.s[parsed_whitelist.len] = 0; - if (parse_destination_list( *rdata, parsed_whitelist.s, - &wl_list, &wl_len, 1)!=0) { + if (parse_destination_list( *(current_partition->rdata), + parsed_whitelist.s, &wl_list, &wl_len, 1)!=0) { LM_ERR("invalid format in whitelist-> ignoring...\n"); wl_list = NULL; } @@ -1542,7 +2722,8 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, /* is carrier turned off ? */ if( dst->dst.carrier->flags & DR_CR_FLAG_IS_OFF - || !is_dst_in_list( (void*)dst, wl_list, wl_len) ) + || !is_dst_in_list( (void*)dst->dst.carrier, + wl_list, wl_len) ) continue; /* any gws for this carrier ? */ @@ -1551,10 +2732,10 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, /* sort the gws of the carrier */ j = sort_rt_dst(dst->dst.carrier->pgwl, dst->dst.carrier->pgwa_len, - dst->dst.carrier->flags&DR_CR_FLAG_WEIGHT, carrier_idx); + dst->dst.carrier->flags&DR_CR_FLAG_WEIGHT, carrier_idx); if (j!=0) { LM_ERR("failed to sort gws for carrier <%.*s>, skipping\n", - dst->dst.carrier->id.len, dst->dst.carrier->id.s); + dst->dst.carrier->id.len, dst->dst.carrier->id.s); continue; } @@ -1568,14 +2749,22 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, /*ignore it*/ } else { /* add gateway to usage list */ - if ( push_gw_for_usage(msg, &uri, cdst->dst.gw , - &dst->dst.carrier->id, &dst->dst.carrier->attrs, n ) ) { + if ( push_gw_for_usage(msg, current_partition, &uri, cdst->dst.gw , + &dst->dst.carrier->id, &dst->dst.carrier->attrs, n ) ) { LM_ERR("failed to use gw <%.*s>, skipping\n", - cdst->dst.gw->id.len, cdst->dst.gw->id.s); + cdst->dst.gw->id.len, cdst->dst.gw->id.s); } else { n++; + + /* only export the top-most carrier/gw + * attributes in the script */ + if (n == 1) { + next_carrier_attrs = dst->dst.carrier->attrs; + next_gw_attrs = cdst->dst.gw->attrs; + } + + /* use only first valid GW */ if (dst->dst.carrier->flags&DR_CR_FLAG_FIRST) - /* use only first valid GW */ break; } } @@ -1586,15 +2775,21 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, /* is gateway disabled ? */ if (dst->dst.gw->flags & DR_DST_STAT_DSBL_FLAG - || !is_dst_in_list( (void*)dst, wl_list, wl_len) ) + || !is_dst_in_list( (void*)dst->dst.gw, wl_list, wl_len) ) continue; /* add gateway to usage list */ - if ( push_gw_for_usage(msg, &uri, dst->dst.gw, NULL, NULL, n) ) { + if ( push_gw_for_usage(msg, current_partition, &uri, + dst->dst.gw, NULL, NULL, n) ) { LM_ERR("failed to use gw <%.*s>, skipping\n", - dst->dst.gw->id.len, dst->dst.gw->id.s); + dst->dst.gw->id.len, dst->dst.gw->id.s); } else { n++; + /* only export the first gw attributes in the script */ + if (n == 1) { + next_carrier_attrs.s = NULL; + next_gw_attrs = dst->dst.gw->attrs; + } } } @@ -1608,50 +2803,80 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, goto error2; } + pv_val.flags = PV_VAL_STR; + + if (gw_attrs_spec) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = !next_gw_attrs.s ? attrs_empty : next_gw_attrs; + if (pv_set_value(msg, gw_attrs_spec, 0, &pv_val) != 0) { + LM_ERR("failed to set value for gateway attrs pvar - do_routing\n"); + goto error2; + } + } + + if (carrier_attrs_spec) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = !next_carrier_attrs.s ? attrs_empty : next_carrier_attrs; + if (pv_set_value(msg, carrier_attrs_spec, 0, &pv_val) + != 0) { + LM_ERR("failed to set value for carrier attrs pvar - do_routing\n"); + goto error2; + } + } + no_gws: /* add RULE prefix avp */ - if (rule_prefix_avp.name!=-1) { + if (current_partition->rule_prefix_avp!=-1) { val.s.s = username.s ; val.s.len = prefix_len; LM_DBG("setting RULE prefix [%.*s] \n",val.s.len,val.s.s); - if (add_avp( AVP_VAL_STR|(rule_prefix_avp.type), - rule_prefix_avp.name, val)!=0 ) { + if (add_avp( AVP_VAL_STR, current_partition->rule_prefix_avp, val)!=0 ) { LM_ERR("failed to insert rule prefix avp\n"); goto error2; } } - /* add RULE attrs avp */ - if (rule_attrs_avp.name!=-1) { - val.s = rt_info->attrs.s ? rt_info->attrs : attrs_empty; - LM_DBG("setting RULE attr [%.*s] \n",val.s.len,val.s.s); - if (add_avp( AVP_VAL_STR|(rule_attrs_avp.type), - rule_attrs_avp.name, val)!=0 ) { + + /* add internal RULE attrs avp if requested at least once in the script */ + if (populate_rule_attrs) { + val.s = !rt_info->attrs.s ? attrs_empty : rt_info->attrs; + LM_DBG("setting RULE attr [%.*s] \n", val.s.len, val.s.s); + if (add_avp( AVP_VAL_STR, current_partition->rule_attrs_avp, val) != 0) { LM_ERR("failed to insert rule attrs avp\n"); goto error2; } + + if (rule_attrs_spec) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = val.s; + if (pv_set_value(msg, rule_attrs_spec, 0, + &pv_val) != 0) { + LM_ERR("failed to set value for rule attrs pvar\n"); + goto error2; + } + } } /* add RULE id avp */ - if (rule_id_avp.name!=-1) { + if (current_partition->rule_id_avp!=-1) { val.n = (int) rt_info->id; LM_DBG("setting RULE id [%d] as avp\n",val.n); - if (add_avp( rule_id_avp.type,rule_id_avp.name, val)!=0 ) { + if (add_avp( 0, current_partition->rule_id_avp, val)!=0 ) { LM_ERR("failed to insert rule ids avp\n"); goto error2; } } /* we are done reading -> unref the data */ - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); if ( flags & DR_PARAM_RULE_FALLBACK ) { if ( !(flags & DR_PARAM_INTERNAL_TRIGGERED) ) { - /* first time ? we need to save some date, to be able to + /* first time ? we need to save some date, to be able to do the rule fallback later in "next_gw" */ LM_DBG("saving rule_idx %d, prefix %.*s\n",rule_idx, - prefix_len - (rule_idx?0:1), username.s); + prefix_len - (rule_idx?0:1), username.s); val.n = rule_idx; - if (add_avp( 0 , avpID_store_index, val) ) { + if (add_avp( 0 , current_partition->avpID_store_index, val) ) { LM_ERR("failed to insert index avp for fallback\n"); flags = flags & ~DR_PARAM_RULE_FALLBACK; } @@ -1660,33 +2885,35 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, prefix in the DR tree */ val.s.s = username.s ; val.s.len = prefix_len - (rule_idx?0:1); - if (add_avp( AVP_VAL_STR, avpID_store_prefix, val) ) { + if (add_avp( AVP_VAL_STR, current_partition->avpID_store_prefix, + val) ) { LM_ERR("failed to insert prefix avp for fallback\n"); flags = flags & ~DR_PARAM_RULE_FALLBACK; } /* also store current ruri as we will need it */ val.s = ruri; - if (add_avp( AVP_VAL_STR, avpID_store_ruri, val) ) { + if (add_avp( AVP_VAL_STR, current_partition->avpID_store_ruri, val) ) { LM_ERR("failed to insert ruri avp for fallback\n"); flags = flags & ~DR_PARAM_RULE_FALLBACK; } - /* we need to save a some date, to be able to do the rule + /* we need to save a some date, to be able to do the rule fallback later in "next_gw" (prefix/index already added) */ if (wl_list) { val.s = parsed_whitelist ; val.s.len++; /* we need extra space to place \0 when using */ - if (add_avp( AVP_VAL_STR, avpID_store_whitelist, val) ) { + if (add_avp( AVP_VAL_STR, + current_partition->avpID_store_whitelist, val) ) { LM_ERR("failed to insert whitelist avp for fallback\n"); flags = flags & ~DR_PARAM_RULE_FALLBACK; } } val.n = grp_id ; - if (add_avp( 0, avpID_store_group, val) ) { + if (add_avp( 0, current_partition->avpID_store_group, val) ) { LM_ERR("failed to insert group avp for fallback\n"); flags = flags & ~DR_PARAM_RULE_FALLBACK; } val.n = flags ; - if (add_avp( 0, avpID_store_flags, val) ) { + if (add_avp( 0, current_partition->avpID_store_flags, val) ) { LM_ERR("failed to insert flags avp for fallback\n"); } } else { @@ -1701,7 +2928,7 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, ((str*)data)->len = prefix_len-1; } LM_DBG("updating to %d, prefix %.*s \n",rule_idx, - prefix_len-(rule_idx?1:0),username.s); + prefix_len-(rule_idx?1:0),username.s); } } @@ -1709,48 +2936,73 @@ static int do_routing(struct sip_msg* msg, dr_group_t *drg, int flags, return 1; error2: /* we are done reading -> unref the data */ - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); error1: if (ruri_buf) pkg_free(ruri_buf); return ret; } -static int route2_carrier(struct sip_msg* msg, char *cr_str) +static int route2_carrier(struct sip_msg* msg, char* part_carrier, + char* gw_att_pv, char* carr_att_pv) { unsigned short carrier_idx[DR_MAX_GWLIST]; struct sip_uri uri; pgw_list_t *cdst; - pv_value_t val; pcr_t *cr; - str *ruri; + pv_value_t pv_val; + str *ruri, id; + str next_carrier_attrs = {NULL, 0}; + str next_gw_attrs = {NULL, 0}; int j,n; + dr_part_old_t * part_cr; + struct head_db * current_partition = 0; + + part_cr = (dr_part_old_t*)part_carrier; + if(use_partitions) { + if(part_cr == NULL) { + LM_ERR("Partition is mandatory for route2_carrier.\n"); + return -1; + } + if(part_cr->dr_part->type == DR_PTR_PART) { + current_partition = part_cr->dr_part->v.part; + } else if(part_cr->dr_part->type == DR_GPARAM_PART) { + if(to_partition(msg, part_cr->dr_part, ¤t_partition) < 0) + return -1; + } + } else { + current_partition = head_db_start; + } + - if ( (*rdata)==0 || (*rdata)->pgw_l==0 ) { + if ( (*current_partition->rdata)==0 || (*current_partition->rdata)->pgw_l==0 ) { LM_DBG("empty routing table\n"); return -1; } /* get the carrier ID */ - if ( pv_get_spec_value(msg, (pv_spec_p)cr_str, &val)!=0 || - (val.flags&PV_VAL_STR)==0 ) { + if (fixup_get_svalue(msg, (gparam_p)part_cr->gw_or_cr, &id) != 0) { LM_ERR("failed to get string value for carrier ID\n"); return -1; } + gw_attrs_spec = (pv_spec_p) gw_att_pv; + carrier_attrs_spec = (pv_spec_p) carr_att_pv; + /* do some cleanup first */ - destroy_avps( ruri_avp.type, ruri_avp.name, 1); - destroy_avps( gw_id_avp.type, gw_id_avp.name, 1); - if (gw_attrs_avp.name!=-1) - destroy_avps( gw_attrs_avp.type, gw_attrs_avp.name, 1); - if (gw_priprefix_avp.name!=-1) - destroy_avps( gw_priprefix_avp.type, gw_priprefix_avp.name, 1); - if (rule_id_avp.name!=-1) - destroy_avps( rule_id_avp.type, rule_id_avp.name, 1); - if (rule_attrs_avp.name!=-1) - destroy_avps( rule_attrs_avp.type, rule_attrs_avp.name, 1); - if (rule_prefix_avp.name!=-1) - destroy_avps( rule_prefix_avp.type, rule_prefix_avp.name, 1); + destroy_avps( 0, current_partition->ruri_avp, 1); + destroy_avps( 0, current_partition->gw_id_avp, 1); + destroy_avps( 0, current_partition->gw_sock_avp, 1); + destroy_avps( 0, current_partition->gw_attrs_avp, 1); + destroy_avps( 0, current_partition->rule_attrs_avp, 1); + destroy_avps( 0, current_partition->carrier_attrs_avp, 1); + + if (current_partition->gw_priprefix_avp!=-1) + destroy_avps( 0, current_partition->gw_priprefix_avp, 1); + if (current_partition->rule_id_avp!=-1) + destroy_avps( 0, current_partition->rule_id_avp, 1); + if (current_partition->rule_prefix_avp!=-1) + destroy_avps( 0, current_partition->rule_prefix_avp, 1); /* get the RURI */ ruri = GET_RURI(msg); @@ -1761,18 +3013,18 @@ static int route2_carrier(struct sip_msg* msg, char *cr_str) } /* ref the data for reading */ - lock_start_read( ref_lock ); + lock_start_read( current_partition->ref_lock ); - cr = get_carrier_by_id( (*rdata)->carriers, &val.rs ); + cr = get_carrier_by_id( (*current_partition->rdata)->carriers, &id ); if (cr==NULL) { - LM_ERR("carrier <%.*s> was not found\n",val.rs.len, val.rs.s ); + LM_ERR("carrier <%.*s> was not found\n", id.len, id.s ); goto error; } /* is carrier turned off ? */ if( cr->flags & DR_CR_FLAG_IS_OFF ) { LM_NOTICE("routing to disabled carrier <%.*s> failed\n", - cr->id.len, cr->id.s); + cr->id.len, cr->id.s); goto error; } @@ -1782,10 +3034,10 @@ static int route2_carrier(struct sip_msg* msg, char *cr_str) /* sort the gws of the carrier */ j = sort_rt_dst( cr->pgwl, cr->pgwa_len, cr->flags&DR_CR_FLAG_WEIGHT, - carrier_idx); + carrier_idx); if (j!=0) { LM_ERR("failed to sort gws for carrier <%.*s>, skipping\n", - cr->id.len, cr->id.s); + cr->id.len, cr->id.s); goto error; } @@ -1799,14 +3051,22 @@ static int route2_carrier(struct sip_msg* msg, char *cr_str) /*ignore it*/ } else { /* add gateway to usage list */ - if ( push_gw_for_usage(msg, &uri, cdst->dst.gw, - &cr->id, &cr->attrs, n ) ) { + if ( push_gw_for_usage(msg, current_partition, &uri, cdst->dst.gw, + &cr->id, &cr->attrs, n ) ) { LM_ERR("failed to use gw <%.*s>, skipping\n", - cdst->dst.gw->id.len, cdst->dst.gw->id.s); + cdst->dst.gw->id.len, cdst->dst.gw->id.s); } else { n++; + + /* only export the top-most carrier/gw + * attributes in the script */ + if (n == 1) { + next_carrier_attrs = cr->attrs; + next_gw_attrs = cdst->dst.gw->attrs; + } + + /* use only first valid GW */ if (cr->flags&DR_CR_FLAG_FIRST) - /* use only first valid GW */ break; } } @@ -1817,35 +3077,92 @@ static int route2_carrier(struct sip_msg* msg, char *cr_str) LM_ERR("All the gateways are disabled\n"); goto error; } + + pv_val.flags = PV_VAL_STR; + + if (gw_attrs_spec) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = !next_gw_attrs.s ? attrs_empty : next_gw_attrs; + if (pv_set_value(msg, gw_attrs_spec, 0, &pv_val) != 0) { + LM_ERR("failed to set value for gateway attrs pvar\n"); + goto error; + } + } + + if (carrier_attrs_spec) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = !next_carrier_attrs.s ? attrs_empty : next_carrier_attrs; + if (pv_set_value(msg, carrier_attrs_spec, 0, &pv_val) != 0) { + LM_ERR("failed to set value for carrier attrs pvar\n"); + goto error; + } + } + no_gws: /* we are done reading -> unref the data */ - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); return 1; error: /* we are done reading -> unref the data */ - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); return -1; } -static int route2_gw(struct sip_msg* msg, char *gw_str) +static int route2_gw(struct sip_msg* msg, char* ch_part_gw, char* gw_att_pv) { struct sip_uri uri; - pv_value_t val; pgw_t *gw; - str *ruri; + pv_value_t pv_val; + str *ruri, ids, id; + str next_gw_attrs = {NULL, 0}; + char *p; + int idx; + dr_part_old_t * part_gw = (dr_part_old_t*)ch_part_gw; + struct head_db * current_partition = 0; + + if( part_gw==NULL ) { + LM_ERR("No gateway to route to\n"); + return -1; + } + + if(use_partitions) { + if(part_gw == NULL) { + LM_ERR("Partition is mandatory for route2_gw.\n"); + return -1; + } + if(part_gw->dr_part->type == DR_PTR_PART) { + current_partition = part_gw->dr_part->v.part; + } else if(part_gw->dr_part->type == DR_GPARAM_PART) { + if(to_partition(msg, part_gw->dr_part, ¤t_partition) < 0) + return -1; + } + } else { + if(head_db_start == NULL) { + LM_ERR("Problem loading configuration for route_to_gw\n"); + return -1; + } + current_partition = head_db_start; + } - if ( (*rdata)==0 || (*rdata)->pgw_l==0 ) { + + if ( (*current_partition->rdata)==0 || (*current_partition->rdata)->pgw_l==0 ) { LM_DBG("empty routing table\n"); return -1; } + gw_attrs_spec = (pv_spec_p)gw_att_pv; + /* get the gw ID */ - if ( pv_get_spec_value(msg, (pv_spec_p)gw_str, &val)!=0 || - (val.flags&PV_VAL_STR)==0 ) { - LM_ERR("failed to get string value for gw ID\n"); + if (fixup_get_svalue(msg, (gparam_p)part_gw->gw_or_cr, &ids) != 0) { + LM_ERR("Invalid pseudo variable!\n"); + return -1; + } + str_trim_spaces_lr(ids); + if (ids.s[0] == ',' || ids.s[ids.len-1] == ',') { + LM_ERR("Empty slot\n"); return -1; } @@ -1858,131 +3175,592 @@ static int route2_gw(struct sip_msg* msg, char *gw_str) } /* ref the data for reading */ - lock_start_read( ref_lock ); + lock_start_read( current_partition->ref_lock ); - gw = get_gw_by_id( (*rdata)->pgw_l, &val.rs ); - if (gw==NULL) { - LM_ERR("no GW found with ID <%.*s> \n",val.rs.len,val.rs.s); - goto error; + + idx = 0; + do { + id.s = ids.s; + p = q_memchr( ids.s , ',' , ids.len); + id.len = (p==NULL)?ids.len:(p-ids.s); + + ids.len -= id.len + (p?1:0); + ids.s += id.len + (p?1:0); + + str_trim_spaces_lr(id); + if (id.len<=0) { + LM_ERR("empty slot\n"); + lock_stop_read( current_partition->ref_lock ); + return -1; + } else { + LM_DBG("found and looking for gw id <%.*s>,len=%d\n",id.len, id.s, id.len); + gw = get_gw_by_id( (*current_partition->rdata)->pgw_l, &id ); + if (gw==NULL) { + LM_ERR("no GW found with ID <%.*s> -> ignorring\n", id.len, id.s); + } else if ( push_gw_for_usage(msg, current_partition, &uri, gw, NULL, NULL, idx ) ) { + LM_ERR("failed to use gw <%.*s>, skipping\n", + gw->id.len, gw->id.s); + } else { + idx++; + + /* only export the top-most gw attributes in the script */ + if (idx == 1) + next_gw_attrs = gw->attrs; + } + } + } while(ids.len>0); + + /* we are done reading -> unref the data */ + lock_stop_read( current_partition->ref_lock ); + + if ( idx==0 ) { + LM_ERR("no GW added at all\n"); + return -1; + } + + if (gw_attrs_spec) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = !next_gw_attrs.s ? attrs_empty : next_gw_attrs; + if (pv_set_value(msg, gw_attrs_spec, 0, &pv_val) != 0) { + LM_ERR("failed to set value for gateway attrs pvar\n"); + return -1; + } + } + + return 1; +} + +int fxup_split_param(void ** fst_param, void ** scnd_param) { + char * ch_it ; + *scnd_param = 0; + + if(*fst_param == NULL || ((char*)*fst_param)[0] == 0) { /* NULL string */ + return -1; + } + + for(ch_it=*fst_param; (*ch_it)!=0 && (*ch_it)!=':'; ch_it++); + + if(*ch_it == 0) { + LM_CRIT("No partition specified. Missing ':'.\n"); + return -1; /* partition name was not specified */ + } + /* partition name exits */ + *ch_it = 0; + *scnd_param = ch_it+1; /* the second parameter */ + + return 0; +} + +int fxup_get_partition(void ** part_name, dr_partition_t ** x) { + str str_part_name; + struct head_db* part; + + trim_char((char**)part_name); + *x = (dr_partition_t*)pkg_malloc( sizeof(dr_partition_t) ); + if(*x == NULL) { + LM_ERR("no more pkg memory\n"); + return -1; + } + memset(*x, 0, sizeof(dr_partition_t)); + + if(part_name == 0 || *part_name == 0 || **(char**)part_name == 0) { + (*x)->type = DR_NO_PART; /* NO partition specified */ + LM_ERR("No partition\n"); + return 0; + } + + + if( fixup_sgp((void**)part_name)!=0 ) { + LM_CRIT("Failed to get partition name\n"); + return -1; + } + + if( ((gparam_p)(*part_name))->type==GPARAM_TYPE_STR ) { /* was + defined statically */ + str_part_name = (( (gparam_p) (*part_name))->v.sval); + if((part = get_partition(&str_part_name)) == NULL) { + LM_CRIT("Partition <%.*s> was not found.\n", str_part_name.len, + str_part_name.s); + return -1; /* partition was not found */ + } + (*x)->v.part = part; + (*x)->type = DR_PTR_PART; + } else { /* defined via avp/pv => will be evaluated at runtime*/ + (*x)->v.part_name = *part_name; + (*x)->type = DR_GPARAM_PART; + } + return 0; +} + +/* gets partition name from avp, and searches for that partition */ +static int to_partition(struct sip_msg* msg, dr_partition_t *part, + struct head_db ** current_partition) { + str part_name; + if(fixup_get_svalue(msg, part->v.part_name, + &part_name) < 0) { + LM_ERR("Failed to parse avp/pve.\n"); + return -1; + } + if((*current_partition = get_partition(&part_name)) == NULL) { + LM_ERR("Partition <%.*s> was not found.\n", part_name.len, part_name.s); + return -1; + } + return 0; +} +/* Returns a gparam_p to the containing partition if + * specified. If partition isn't specified return NULL + */ +gparam_t * fixup_get_partition(void** param) { + gparam_t *part_name = 0; + char *ch_it,*s = (char*)*param, *separator; + + if( s==NULL || s[0]==0 ) { + return NULL; + } + if( use_partitions==0 ) /* partition will be omitted */ + return NULL; + for( ch_it=s; (*ch_it)!=0 && (*ch_it)!=':'; ch_it++); + separator = ch_it; + + if( (*separator)==':' ) { /* partition was specified */ + part_name = pkg_malloc(sizeof(gparam_t)); + if( part_name==0 ) { + LM_ERR("No more pkg memory for part_name\n"); + } + memset( part_name, 0, sizeof(gparam_t)); + + while( (*s)==' ' ) s++; /* trim space left-of partition name */ + (*ch_it) = 0; + ch_it--; + while( (*ch_it)==' ' && ch_it!=s) { + (*ch_it) = 0; + ch_it--; + } + + if( fixup_sgp( (void**)&s )<0 ) /* get partition name */ + return NULL; + + part_name = (gparam_p)s; + *param = separator+1; /* go to group */ + } + return part_name; + +} + +static int fixup_dr_disable(void ** param, int param_no) { + if(use_partitions) { + switch(param_no) { + case 1: + trim_char((char**)param); + return fixup_sgp(param); + } + } + LM_ERR("Too many parameters. (if you don't use partitions)\n"); + return -1; +} + +static int fixup_do_routing(void** param, int param_no) +{ + char *s; + dr_group_t * drg = 0; + dr_part_group_t * part_param; + pv_spec_t avp_spec; + unsigned short dummy; + char * scnd_param; + str r; + + s = (char*)*param; + + switch (param_no) { + /* [partition name':']group ID */ + case 1: + part_param = pkg_malloc(sizeof(dr_part_group_t)); + if(part_param == NULL) { + LM_ERR("No more pkg memory.\n"); + return -1; + } + memset(part_param, 0, sizeof(dr_part_group_t)); + if(use_partitions == 1) { + if(fxup_split_param(param, (void **)&scnd_param) < 0) { + return -1; + } + if(fxup_get_partition(param, &(part_param->dr_part)) < 0) { + return -1; + } + + if(part_param->dr_part->type == DR_NO_PART) { + LM_ERR("Partition name is mandatory do_routing"); + } + } else { + scnd_param = s; + } + s = scnd_param; + trim_char(&s); + if ( s==NULL || s[0]==0 ) { + *param = (void*)part_param; + return 0; + } + + drg = pkg_malloc(sizeof(dr_group_t)); + if(drg == NULL) { + LM_ERR("No more pkg memory.\n"); + return -1; + } + memset(drg, 0, sizeof(dr_group_t)); + + if (s[0]=='$') { + /* param is a PV (AVP only supported) */ + r.s = s; + r.len = strlen(s); + if (pv_parse_spec( &r, &avp_spec)==0 + || avp_spec.type!=PVT_AVP) { + LM_ERR("malformed or non AVP %s AVP definition\n", s); + return E_CFG; + } + + if( pv_get_avp_name(0, &(avp_spec.pvp), + &drg->u.avp_name, &dummy )!=0) { + LM_ERR("[%s]- invalid AVP definition\n", s); + return E_CFG; + } + drg->type = 1; + /* do not free the param as the AVP spec may point inside + this string*/ + } else { + while(s && *s) { + if(*s<'0' || *s>'9') { + LM_ERR( "bad number\n"); + return E_UNSPEC; + } + drg->u.grp_id = (drg->u.grp_id)*10+(*s-'0'); + s++; + } + } + part_param->group = drg; + *param = (void*)part_param; + return 0; + + /* string with flags */ + case 2: + return fixup_sgp(param); + + /* white list of GWs/Carriers */ + case 3: + return fixup_spve(param); + + /* rule | gateway | carrier attributes output pvars */ + case 4: + populate_rule_attrs = 1; + return fixup_pvar(param); + case 5: + populate_gw_attrs = 1; + return fixup_pvar(param); + case 6: + populate_carrier_attrs = 1; + return fixup_pvar(param); } + return -1; +} + +static int fixup_next_gw( void** param, int param_no) +{ + dr_partition_t * part; + if( !use_partitions ) { /* partition not needed */ + switch (param_no) { + /* rule attrs pvar */ + case 1: /* first param can be partition name */ + populate_rule_attrs = 1; + return fixup_pvar(param); + /* gateway attrs pvar */ + case 2: + populate_gw_attrs = 1; + return fixup_pvar(param); + /* carrier attrs pvar */ + case 3: + populate_carrier_attrs = 1; + return fixup_pvar(param); + case 4: + LM_ERR("Too many arguments for use_next_gw()\n"); + return -1; + + } + } else { /* parition is mandatory => the first param */ + switch (param_no) { + case 1: + part = pkg_malloc(sizeof(dr_partition_t)); + if(part == NULL) { + LM_CRIT("No more pkg memory!\n"); + return -1; + } + memset(part, 0, sizeof(dr_partition_t)); + if(fxup_get_partition(param, &part) < 0) + return -1; + if(part->type == DR_NO_PART) { + LM_ERR("Partition name is mandatory for use_next_gw.\n"); + return -1; + } + *param = part; + return 0; + case 2: /* first param can be partition name */ + populate_rule_attrs = 1; + return fixup_pvar(param); + /* gateway attrs pvar */ + case 3: + populate_gw_attrs = 1; + return fixup_pvar(param); + /* carrier attrs pvar */ + case 4: + populate_carrier_attrs = 1; + return fixup_pvar(param); + } + } + + return -1; +} + + +static int fixup_from_gw( void** param, int param_no) +{ + dr_partition_t * part; + if(use_partitions == 0) { + switch (param_no) { + /* GW type*/ + case 1: + return fixup_sint(param); + /* GW ops */ + case 2: + + return fixup_spve(param); + /* ATTRS pseudo-var */ + case 3: + return fixup_pvar(param); + case 4: + LM_ERR("Too many parameters. (if you don't use partitions)\n"); + return -1; + } + } else { + switch (param_no) { + /* GW type*/ + case 1: + part = pkg_malloc(sizeof(dr_partition_t)); + if(part == NULL) { + LM_ERR("No more pkg memory.\n"); + return -1; + } + memset(part, 0, sizeof(dr_partition_t)); + + if(fxup_get_partition(param, &part) < 0) + return -1; + *param = part; + + return 0; + case 2: + return fixup_sint(param); + + /* GW ops */ + case 3: + return fixup_spve(param); + + /* ATTRS pseudo-var */ + case 4: + return fixup_pvar(param); + } + } + + return -1; +} + + +static int fixup_is_gw( void** param, int param_no) +{ + dr_partition_t * part; + if(use_partitions == 0) { + switch (param_no) { + /* SIP URI pseudo-var */ + case 1: + return fixup_pvar(param); + + /* GW type*/ + case 2: + return fixup_sint(param); + + /* GW ops */ + case 3: + return fixup_spve(param); + + /* ATTRS pseudo-var */ + case 4: + return fixup_pvar(param); + case 5: + LM_ERR("Too many parameters. (if you don't use partitions)\n"); + return -1; + } + } else { + switch (param_no) { + case 1: + part = pkg_malloc(sizeof(dr_partition_t)); + if(part == NULL) { + LM_CRIT("No more pkg memory!"); + return -1; + } + memset(part, 0, sizeof(dr_partition_t)); + + if(fxup_get_partition(param, &part) < 0) + return -1; + *param = part; + return 0; + /* SIP URI pseudo-var */ + case 2: + return fixup_pvar(param); + + /* GW type*/ + case 3: + return fixup_sint(param); + + /* GW ops */ + case 4: + return fixup_spve(param); + + /* ATTRS pseudo-var */ + case 5: + return fixup_pvar(param); + } + + } + return -1; +} + +static void trim_char(char ** param) { + char *trailing_sp; + if(*param!=NULL) { + while(**param==' ') (*param)++; + trailing_sp = *param; + while(*trailing_sp!=0) trailing_sp++; + trailing_sp--; + while(*trailing_sp==' ') *trailing_sp = 0, trailing_sp--; + } +} + +static int fixup_route2_carrier( void** param, int param_no) +{ + dr_part_old_t *part_param; + char * scnd_param; + + + int rc; + switch (param_no) { + + /* carrier name string - it has partition */ + case 1: + part_param = pkg_malloc(sizeof(dr_part_old_t)); + if(part_param == NULL) { + LM_ERR("No more pkg memory!"); + return -1; + } + memset(part_param, 0, sizeof(dr_part_old_t)); + if(use_partitions == 1) { + if(fxup_split_param(param, (void**)&scnd_param) < 0) { + return -1; + } + if(fxup_get_partition(param, &(part_param->dr_part)) < 0) { + return -1; + } + if(part_param->dr_part->type == DR_NO_PART) { + LM_ERR("Partition name is mandatory for route2_carrier\n"); + return -1; + } + } else { + scnd_param = *param; /* only carrier present */ + } + if(scnd_param == NULL) { + LM_CRIT("carrier_id mandatory for function route_to_carrier.\n"); + return -1; + } + trim_char(&scnd_param); + if(*scnd_param == 0) { /* carrier_id was formed only from spaces */ + LM_CRIT("carrier_id mandatory for function route_to_carrier.\n"); + return -1; + } + rc = fixup_sgp((void**)&scnd_param); + part_param->gw_or_cr = (gparam_p)scnd_param; + *param = (void*)part_param; + + return rc; - if ( push_gw_for_usage(msg, &uri, gw, NULL, NULL, 0 ) ) { - LM_ERR("failed to use gw <%.*s>, skipping\n", - gw->id.len, gw->id.s); - goto error; - } + /* gateway attrs pvar */ + case 2: + populate_gw_attrs = 1; + return fixup_pvar(param); - /* we are done reading -> unref the data */ - lock_stop_read( ref_lock ); + /* carrier attrs pvar */ + case 3: + populate_carrier_attrs = 1; + return fixup_pvar(param); + } - return 1; -error: - /* we are done reading -> unref the data */ - lock_stop_read( ref_lock ); return -1; } -static int fixup_do_routing(void** param, int param_no) +static int fixup_route2_gw( void** param, int param_no) { - char *s; - dr_group_t *drg; - pv_spec_t avp_spec; - str r; - - s = (char*)*param; - - if (param_no==1) { - /* group */ - drg = (dr_group_t*)pkg_malloc(sizeof(dr_group_t)); - if(drg==NULL) { - LM_ERR( "no more memory\n"); - return E_OUT_OF_MEM; - } - memset(drg, 0, sizeof(dr_group_t)); - - if ( s==NULL || s[0]==0 ) { - pkg_free(*param); - *param = NULL; - return 0; - } - - if (s[0]=='$') { - /* param is a PV (AVP only supported) */ - r.s = s; - r.len = strlen(s); - if (pv_parse_spec( &r, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP %s AVP definition\n", s); - return E_CFG; - } - - if( pv_get_avp_name(0, &(avp_spec.pvp), &(drg->u.avp_id.name), - &(drg->u.avp_id.type) )!=0) { - LM_ERR("[%s]- invalid AVP definition\n", s); - return E_CFG; + int rc; + char *gw = 0; + dr_part_old_t * part_param; /* partition and gateway */ + switch (param_no) { + /* gateway / gateways (csv) */ + case 1: + part_param = pkg_malloc(sizeof(dr_part_old_t)); + if(part_param == NULL) { + LM_ERR("No more pkg memory!"); + return -1; } - drg->type = 1; - /* do not free the param as the AVP spec may point inside - this string*/ - } else { - while(s && *s) { - if(*s<'0' || *s>'9') { - LM_ERR( "bad number\n"); - return E_UNSPEC; + memset(part_param, 0, sizeof(dr_part_old_t)); + if(use_partitions == 1) { + if(fxup_split_param(param, (void**)&gw) < 0) { + return -1; + } + if(fxup_get_partition(param, &(part_param->dr_part))<0) { + return -1; } - drg->u.grp_id = (drg->u.grp_id)*10+(*s-'0'); - s++; + if(part_param->dr_part->type == DR_NO_PART) { + LM_ERR("Partition name is mandatory for route2_gw\n"); + } + } else { + gw = *param; } - pkg_free(*param); - } - *param = (void*)drg; - } else - if (param_no==2) { - /* string of flags */ - return fixup_sgp(param); - } else - if (param_no==3) { - /* white_list of GWs/Carriers */ - return fixup_spve(param); - } - return 0; -} + if(gw == NULL) { + LM_CRIT("gateway mandatory for function route_to_gw.\n"); + return -1; + } + trim_char((char**)&gw); -static int fixup_from_gw( void** param, int param_no) -{ - if (param_no == 1) { - /* GW type*/ - return fixup_uint(param); - } else if (param_no == 2) { - /* GW ops */ - return fixup_spve(param); - } - return 0; -} + if(*gw == 0) { + LM_CRIT("gateway mandatory for function route_to_gw.\n"); + return -1; + } + rc = fixup_sgp((void**)&gw); + part_param->gw_or_cr = (gparam_p)gw; + *param = (void*)part_param; -static int fixup_is_gw( void** param, int param_no) -{ - if (param_no == 1) { - return fixup_pvar(param); - } else if (param_no == 2) { - /* GW type*/ - return fixup_uint(param); - } else if (param_no == 3) { - /* GW ops */ - return fixup_spve(param); + return rc; + + /* gateway attrs pvar */ + case 2: + populate_gw_attrs = 1; + return fixup_pvar(param); } - return 0; -} + return -1; +} static int strip_username(struct sip_msg* msg, int strip) { struct action act; - + act.type = STRIP_T; act.elem[0].type = NUMBER_ST; act.elem[0].u.number = strip; @@ -1999,7 +3777,7 @@ static int strip_username(struct sip_msg* msg, int strip) static int prefix_username(struct sip_msg* msg, str *pri) { struct action act; - + act.type = PREFIX_T; act.elem[0].type = STR_ST; act.elem[0].u.s = *pri; @@ -2017,35 +3795,69 @@ static int gw_matches_ip(pgw_t *pgwa, struct ip_addr *ip, unsigned short port) { unsigned short j; for ( j=0 ; jips_no ; j++) - if ( (pgwa->ports[j]==0 || pgwa->ports[j]==port) && - ip_addr_cmp( &pgwa->ips[j], ip) ) return 1; + if ( (pgwa->ports[j]==0 || port==0 || pgwa->ports[j]==port) && + ip_addr_cmp( &pgwa->ips[j], ip) ) return 1; return 0; } #define DR_IFG_STRIP_FLAG (1<<0) #define DR_IFG_PREFIX_FLAG (1<<1) -#define DR_IFG_ATTRS_FLAG (1<<2) #define DR_IFG_IDS_FLAG (1<<3) #define DR_IFG_IGNOREPORT_FLAG (1<<4) +#define DR_IFG_CARRIERID_FLAG (1<<5) + + +static int _is_dr_gw(struct sip_msg* msg, char * part, + char * flags_pv, int type, struct ip_addr *ip, + unsigned int port) { + struct head_db * it; + if(use_partitions) { + if(part == NULL || ((dr_partition_t*)part)->type == DR_NO_PART) { + LM_ERR("Partition is mandatory!\n"); + return -1; + } else if(((dr_partition_t*)part)->type == DR_PTR_PART) { + return _is_dr_gw_w_part(msg, (char*)((dr_partition_t*)part)->v.part, + flags_pv, type, ip, port); + } else if(((dr_partition_t*)part)->type == DR_GPARAM_PART) { + if(to_partition(msg, (dr_partition_t*)part, &it) < 0) { + return -1; + } + return _is_dr_gw_w_part(msg, (char*)it,flags_pv, type, ip, port); + } + } else { + if( head_db_start == NULL ) { + LM_ERR("Error loading config."); + return -1; + } + return _is_dr_gw_w_part(msg, (char*)head_db_start, flags_pv, (int)type, + (struct ip_addr *)ip, (unsigned int)port); + } + return -1; +} /* * Checks if a given IP + PORT is a GW; tests the TYPE too * INTERNAL FUNCTION */ -static int _is_dr_gw(struct sip_msg* msg, char* flags_pv, - int type, struct ip_addr *ip, unsigned int port) +static int _is_dr_gw_w_part(struct sip_msg* msg, char * part, char* flags_pv, + int type, struct ip_addr *ip, unsigned int port) { pgw_t *pgwa = NULL; + pcr_t *pcr = NULL; + pv_value_t pv_val; int flags = 0; str flags_s; int_str val; int i; + struct head_db *current_partition = (struct head_db *)part; - if(rdata==NULL || *rdata==NULL || msg==NULL) + if(current_partition == NULL || current_partition->rdata==NULL + || *current_partition->rdata==NULL || msg==NULL) return -1; + if (flags_pv && flags_pv[0]) { if (fixup_get_svalue( msg, (gparam_p)flags_pv, &flags_s)!=0) { LM_ERR("invalid flags parameter"); @@ -2055,80 +3867,138 @@ static int _is_dr_gw(struct sip_msg* msg, char* flags_pv, switch (flags_s.s[i]) { case 's': flags |= DR_IFG_STRIP_FLAG; break; case 'p': flags |= DR_IFG_PREFIX_FLAG; break; - case 'a': flags |= DR_IFG_ATTRS_FLAG; break; case 'i': flags |= DR_IFG_IDS_FLAG; break; case 'n': flags |= DR_IFG_IGNOREPORT_FLAG; break; + case 'c': flags |= DR_IFG_CARRIERID_FLAG; break; default: LM_WARN("unsuported flag %c \n",flags_s.s[i]); } } } - pgwa = (*rdata)->pgw_l; - while(pgwa) { - if( (type<0 || type==pgwa->type) && - gw_matches_ip( pgwa, ip, (flags&DR_IFG_IGNOREPORT_FLAG)?0:port ) ) { - /* strip ? */ - if ( (flags&DR_IFG_STRIP_FLAG) && pgwa->strip>0) - strip_username(msg, pgwa->strip); - /* prefix ? */ - if ( (flags&DR_IFG_PREFIX_FLAG) && pgwa->pri.len>0) { - /* pri prefix ? */ - if (gw_priprefix_avp.name!=-1) { - val.s = pgwa->pri.s ? pgwa->pri : attrs_empty ; - if (add_avp(AVP_VAL_STR|(gw_priprefix_avp.type), - gw_priprefix_avp.name,val)!=0) - LM_ERR("failed to insert GW pri prefix avp\n"); + if(current_partition->rdata!=NULL && *current_partition->rdata!=NULL) { + pgwa = (*current_partition->rdata)->pgw_l; + while(pgwa) { + if( (type<0 || type==pgwa->type) && + gw_matches_ip( pgwa, ip, (flags&DR_IFG_IGNOREPORT_FLAG)?0:port ) ) { + /* strip ? */ + if ( (flags&DR_IFG_STRIP_FLAG) && pgwa->strip>0) + strip_username(msg, pgwa->strip); + /* prefix ? */ + if ( (flags&DR_IFG_PREFIX_FLAG) && pgwa->pri.len>0) { + /* pri prefix ? */ + if (current_partition->gw_priprefix_avp!=-1) { + val.s = pgwa->pri.s ? pgwa->pri : attrs_empty ; + if (add_avp(AVP_VAL_STR, current_partition->gw_priprefix_avp, val)!=0) + LM_ERR("failed to insert GW pri prefix avp\n"); + } + prefix_username(msg, &pgwa->pri); } - prefix_username(msg, &pgwa->pri); - } - /* attrs ? */ - if (flags & DR_IFG_ATTRS_FLAG && gw_attrs_avp.name!=-1) { - val.s = pgwa->attrs.s ? pgwa->attrs : attrs_empty ; - if (add_avp(AVP_VAL_STR|(gw_attrs_avp.type), - gw_attrs_avp.name,val)!=0) - LM_ERR("failed to insert GW attrs avp\n"); - } - if ( flags & DR_IFG_IDS_FLAG ) { - val.s = pgwa->id; - if (add_avp(AVP_VAL_STR|(gw_id_avp.type), - gw_id_avp.name,val)!=0) - LM_ERR("failed to insert GW attrs avp\n"); + /* attrs ? */ + if (gw_attrs_spec) { + pv_val.flags = PV_VAL_STR; + pv_val.rs = pgwa->attrs.s ? pgwa->attrs : attrs_empty; + if (pv_set_value(msg, gw_attrs_spec, 0, &pv_val) != 0) + LM_ERR("failed to set value for GW attrs pvar\n"); + } + + if ( flags & DR_IFG_IDS_FLAG ) { + val.s = pgwa->id; + if (add_avp(AVP_VAL_STR, current_partition->gw_id_avp, val)!=0) + LM_ERR("failed to insert GW attrs avp\n"); + } + + if ( flags & DR_IFG_CARRIERID_FLAG ) { + /* lookup first carrier that contains this gw */ + for (pcr=(*current_partition->rdata)->carriers;pcr;pcr=pcr->next) { + for (i=0;ipgwa_len;i++) { + if (pcr->pgwl[i].is_carrier == 0 && + pcr->pgwl[i].dst.gw == pgwa ) { + /* found our carrier */ + if (current_partition->carrier_id_avp!=-1) { + val.s = pcr->id; + if (add_avp_last(AVP_VAL_STR, + current_partition->carrier_id_avp, val)!=0) { + LM_ERR("failed to add carrier id AVP\n"); + } + } + goto end; + } + } + } + } +end: + return 1; } - return 1; + pgwa = pgwa->next; } - pgwa = pgwa->next; } + return -1; } +static int is_from_gw_0(struct sip_msg* msg) { + return _is_dr_gw(msg, NULL, NULL, -1, &msg->rcv.src_ip, msg->rcv.src_port); +} /* * Checks if a given src IP and PORT is a GW; no TYPE, no FLAGS */ -static int is_from_gw_0(struct sip_msg* msg, char* str, char* str2) +static int is_from_gw_1(struct sip_msg* msg, char * part) { - return _is_dr_gw( msg, NULL, -1, &msg->rcv.src_ip , msg->rcv.src_port); + if(use_partitions) { + return _is_dr_gw( msg, part, NULL, -1, &msg->rcv.src_ip , msg->rcv.src_port); + } else { + return _is_dr_gw(msg, NULL, NULL, (!part? -1:(int)(long)part), &msg->rcv.src_ip, + msg->rcv.src_port); + } } /* * Checks if a given src IP and PORT is a GW; tests the TYPE too, no FLAGS */ -static int is_from_gw_1(struct sip_msg* msg, char* type_s, char* str2) +static int is_from_gw_2(struct sip_msg* msg, char * part, char* type_s) { - return _is_dr_gw( msg, NULL, (int)(long)type_s, &msg->rcv.src_ip , msg->rcv.src_port); + if(use_partitions) { + return _is_dr_gw(msg, part, NULL, (!type_s ? -1 : (int)(long)type_s), + &msg->rcv.src_ip , msg->rcv.src_port); + } else { + return _is_dr_gw(msg, NULL, type_s, (!part ? -1: (int)(long)part), + &msg->rcv.src_ip, msg->rcv.src_port); + } } +static int is_from_gw_3(struct sip_msg* msg, char * part,char* type_s, + char* flags_pv) { + if(use_partitions) { + return _is_dr_gw(msg, part, flags_pv, (!type_s ? -1:(int)(long)type_s), + &msg->rcv.src_ip, msg->rcv.src_port); + } else { + gw_attrs_spec = (pv_spec_p)flags_pv; + return _is_dr_gw(msg, NULL, type_s, (!part ? -1:(int)(long)part), + &msg->rcv.src_ip, msg->rcv.src_port); + } +} + /* * Checks if a given src IP and PORT is a GW; tests the TYPE too */ -static int is_from_gw_2(struct sip_msg* msg, char* type_s, char* flags_pv) +static int is_from_gw_4(struct sip_msg* msg, char * part,char* type_s, char* flags_pv, + char* gw_att) { - return _is_dr_gw( msg, flags_pv, - (int)(long)type_s, &msg->rcv.src_ip , msg->rcv.src_port); + gw_attrs_spec = (pv_spec_p)gw_att; + + if(use_partitions) { + return _is_dr_gw( msg, part, flags_pv, + (!type_s ? -1 : (int)(long)type_s), &msg->rcv.src_ip , + msg->rcv.src_port); + } else { + LM_ERR("Too many parameters\n"); + return -1; + } } @@ -2136,7 +4006,7 @@ static int is_from_gw_2(struct sip_msg* msg, char* type_s, char* flags_pv) * Checks if a given SIP URI is a GW; tests the TYPE too * INTERNAL FUNCTION */ -static int _is_dr_uri_gw(struct sip_msg* msg, char* flags_pv, int type, str *uri) +static int _is_dr_uri_gw(struct sip_msg* msg, char *part, char* flags_pv, int type, str *uri) { struct sip_uri puri; struct hostent* he; @@ -2149,7 +4019,7 @@ static int _is_dr_uri_gw(struct sip_msg* msg, char* flags_pv, int type, str *uri } he = sip_resolvehost(&puri.host, &puri.port_no, &puri.proto, - (puri.type==SIPS_URI_T), 0); + (puri.type==SIPS_URI_T), 0); if (he==0) { LM_DBG("resolve_host(%.*s) failure\n", puri.host.len, puri.host.s); return -1; @@ -2159,58 +4029,116 @@ static int _is_dr_uri_gw(struct sip_msg* msg, char* flags_pv, int type, str *uri memset(&ip,0,sizeof(struct ip_addr)); hostent2ip_addr( &ip, he, 0); - return _is_dr_gw( msg, flags_pv, type, &ip , puri.port_no); + return _is_dr_gw( msg, part, flags_pv, type, &ip , puri.port_no); } /* * Checks if RURI is a GW ; tests the TYPE too */ -static int goes_to_gw_1(struct sip_msg* msg, char* _type, char* flags_pv) +static int goes_to_gw_1(struct sip_msg* msg, char * part, char* _type, char* flags_pv, + char* gw_att) { - return _is_dr_uri_gw( msg, flags_pv, (int)(long)_type, GET_NEXT_HOP(msg)); + + if(use_partitions) { + gw_attrs_spec = (pv_spec_p)gw_att; + return _is_dr_uri_gw(msg, part, flags_pv, (!_type ? -1 : (int)(long)_type), + GET_NEXT_HOP(msg)); + } else { + gw_attrs_spec = (pv_spec_p)flags_pv; + return _is_dr_uri_gw(msg, NULL, _type, (!part ? -1 : (int)(long)part), + GET_NEXT_HOP(msg)); + } } /* * Checks if RURI is a GW; not TYPE check */ -static int goes_to_gw_0(struct sip_msg* msg, char* _type, char* _f2) +static int goes_to_gw_0(struct sip_msg* msg) { - return goes_to_gw_1(msg, (char*)(long)-1, _f2); + return goes_to_gw_1(msg, NULL, (char *)-1, NULL, NULL); } /* * Checks if a variable (containing a SIP URI) is a GW; tests the TYPE too */ -static int dr_is_gw(struct sip_msg* msg, char* src_pv, char* type_s, char* flags_pv) +static int dr_is_gw(struct sip_msg* msg, char * part, char* src_pv, char* type_s, + char* flags_pv, char* gw_att) { pv_value_t src; - if ( pv_get_spec_value(msg, (pv_spec_p)src_pv, &src)!=0 || (src.flags&PV_VAL_STR)==0 || src.rs.len<=0) { - LM_ERR("failed to get string value for src\n"); - return -1; + if(use_partitions) { + gw_attrs_spec = (pv_spec_p)gw_att; + if ( pv_get_spec_value(msg, (pv_spec_p)src_pv, &src)!=0 || + (src.flags&PV_VAL_STR)==0 || src.rs.len<=0) { + LM_ERR("failed to get string value for src\n"); + return -1; + } + return _is_dr_uri_gw(msg, part, flags_pv, !type_s ? -1:(int)(long)type_s, &src.rs); } + else { + if ( pv_get_spec_value(msg, (pv_spec_p)part, &src)!=0 || + (src.flags&PV_VAL_STR)==0 || src.rs.len<=0) { + LM_ERR("failed to get string value for src\n"); + return -1; + } + gw_attrs_spec = (pv_spec_p)flags_pv; + return _is_dr_uri_gw(msg, NULL, type_s ,!src_pv ? -1:(int)(long)src_pv + ,&src.rs); + } +} - return _is_dr_uri_gw( msg, flags_pv, (int)(long)type_s, &src.rs ); +static struct mi_root* mi_w_partition(struct mi_node **node, struct head_db ** + current_partition) { + struct mi_root *rpl_tree; + + if( use_partitions ) { + if( node!=NULL && (*node)!=NULL ) { + if( (*current_partition = get_partition(&((*node)->value))) == NULL) { + LM_ERR("Partition not found\n"); + rpl_tree = init_mi_tree( 404, MI_SSTR("Partition not found\n")); + return rpl_tree; + } + *node = (*node)->next; /* advance to next param */ + return NULL; /* everything is ok */ + } else { + LM_ERR("Partition name mandatory\n"); + rpl_tree = init_mi_tree(400, MI_SSTR("Partition mandatory\n")); + return rpl_tree; + } + } else { + *current_partition = head_db_start; + return NULL; /* everything is ok */ + } + rpl_tree = init_mi_tree( 400, + MI_SSTR("Unexpected outcome while parsing param for opensisctl\n")); + return rpl_tree; } static struct mi_root* mi_dr_gw_status(struct mi_root *cmd, void *param) { + struct mi_root *rpl_tree; struct mi_node *node; struct mi_attr *attr; unsigned int stat; + struct head_db * current_partition=0; pgw_t *gw; str *id; + int old_flags; node = cmd->node.kids; - lock_start_read( ref_lock ); - if (rdata==NULL || *rdata==NULL) { + if( (rpl_tree = mi_w_partition(&node, ¤t_partition))!=NULL ) + return rpl_tree; /* something went wrong: bad command format */ + + lock_start_read( current_partition->ref_lock ); + + if (current_partition->rdata==NULL || *current_partition->rdata==NULL) { rpl_tree = init_mi_tree( 404, MI_SSTR("No Data available yet")); goto done; } @@ -2220,16 +4148,29 @@ static struct mi_root* mi_dr_gw_status(struct mi_root *cmd, void *param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) goto error; + rpl_tree->node.flags |= MI_IS_ARRAY; - for( gw=(*rdata)->pgw_l ; gw ; gw=gw->next ) { + for( gw=(*current_partition->rdata)->pgw_l ; gw ; gw=gw->next ) { node = add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, - "ID", 2, gw->id.s, gw->id.len); + "ID", 2, gw->id.s, gw->id.len); if (node==NULL) goto error; attr = add_mi_attr( node, MI_DUP_VALUE, "IP" , 2, - gw->ip_str.s, gw->ip_str.len); + gw->ip_str.s, gw->ip_str.len); if (attr==NULL) goto error; - attr = add_mi_attr( node, 0, "Enabled", 7, - (gw->flags&DR_DST_STAT_DSBL_FLAG)?"no ":"yes", 3); + if (gw->flags&DR_DST_STAT_DSBL_FLAG) { + if (gw->flags&DR_DST_STAT_NOEN_FLAG) + attr = add_mi_attr( node, 0, "State", 5, + "Disabled MI", 11); + else if (gw->flags&DR_DST_PING_DSBL_FLAG) + attr = add_mi_attr( node, 0, "State", 5, + "Probing", 7); + else + attr = add_mi_attr( node, 0, "State", 5, + "Inactive", 8); + } else { + attr = add_mi_attr( node, 0, "State", 5, + "Active", 6); + } if (attr==NULL) goto error; } @@ -2240,7 +4181,7 @@ static struct mi_root* mi_dr_gw_status(struct mi_root *cmd, void *param) id = &node->value; /* search for the Gw */ - gw = get_gw_by_id( (*rdata)->pgw_l, id); + gw = get_gw_by_id( (*current_partition->rdata)->pgw_l, id); if (gw==NULL) { rpl_tree = init_mi_tree( 404, MI_SSTR("GW ID not found")); goto done; @@ -2254,8 +4195,20 @@ static struct mi_root* mi_dr_gw_status(struct mi_root *cmd, void *param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) goto error; - node = add_mi_node_child( &rpl_tree->node, 0, "Enabled", 7, - (gw->flags&DR_DST_STAT_DSBL_FLAG)?"no ":"yes", 3); + if (gw->flags&DR_DST_STAT_DSBL_FLAG) { + if (gw->flags&DR_DST_STAT_NOEN_FLAG) + node = add_mi_node_child( &rpl_tree->node, 0, "State", 5, + "Disabled MI", 11); + else if (gw->flags&DR_DST_PING_DSBL_FLAG) + node = add_mi_node_child( &rpl_tree->node, 0, "State", 5, + "Probing", 7); + else + node = add_mi_node_child( &rpl_tree->node, 0, "State", 5, + "Inactive", 8); + } else { + node = add_mi_node_child( &rpl_tree->node, 0, "State", 5, + "Active", 6); + } if (node==NULL) goto error; @@ -2266,7 +4219,7 @@ static struct mi_root* mi_dr_gw_status(struct mi_root *cmd, void *param) /* set the status */ if (node->next) { rpl_tree = init_mi_tree( 400, - MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); goto done; } if (str2int( &node->value, &stat) < 0) { @@ -2274,18 +4227,22 @@ static struct mi_root* mi_dr_gw_status(struct mi_root *cmd, void *param) goto done; } /* set the disable/enable */ + old_flags = gw->flags; if (stat) { gw->flags &= ~ (DR_DST_STAT_DSBL_FLAG|DR_DST_STAT_NOEN_FLAG); } else { gw->flags |= DR_DST_STAT_DSBL_FLAG|DR_DST_STAT_NOEN_FLAG; } - rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); + if (old_flags!=gw->flags) { + gw->flags |= DR_DST_STAT_DIRT_FLAG; + dr_raise_event(gw); + } done: - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); return rpl_tree; error: - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); if(rpl_tree) free_mi_tree(rpl_tree); return NULL; } @@ -2297,14 +4254,21 @@ static struct mi_root* mi_dr_cr_status(struct mi_root *cmd, void *param) struct mi_node *node; struct mi_attr *attr; unsigned int stat; + struct head_db * current_partition = 0; pcr_t *cr; str *id; + int old_flags; node = cmd->node.kids; - lock_start_read( ref_lock ); + if( (rpl_tree = mi_w_partition(&node, ¤t_partition)) + !=NULL ) { + return rpl_tree; + } + + lock_start_read( current_partition->ref_lock ); - if (rdata==NULL || *rdata==NULL) { + if (current_partition->rdata==NULL || *current_partition->rdata==NULL) { rpl_tree = init_mi_tree( 404, MI_SSTR("No Data available yet")); goto done; } @@ -2314,13 +4278,14 @@ static struct mi_root* mi_dr_cr_status(struct mi_root *cmd, void *param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) goto error; + rpl_tree->node.flags |= MI_IS_ARRAY; - for( cr=(*rdata)->carriers ; cr ; cr=cr->next ) { + for( cr=(*current_partition->rdata)->carriers ; cr ; cr=cr->next ) { node = add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, - "ID", 2, cr->id.s, cr->id.len); + "ID", 2, cr->id.s, cr->id.len); if (node==NULL) goto error; attr = add_mi_attr( node, 0, "Enabled", 7, - (cr->flags&DR_CR_FLAG_IS_OFF)?"no ":"yes", 3); + (cr->flags&DR_CR_FLAG_IS_OFF)?"no ":"yes", 3); if (attr==NULL) goto error; } @@ -2331,7 +4296,7 @@ static struct mi_root* mi_dr_cr_status(struct mi_root *cmd, void *param) id = &node->value; /* search for the Carrier */ - cr = get_carrier_by_id( (*rdata)->carriers, id); + cr = get_carrier_by_id( (*current_partition->rdata)->carriers, id); if (cr==NULL) { rpl_tree = init_mi_tree( 404, MI_SSTR("Carrier ID not found")); goto done; @@ -2346,7 +4311,7 @@ static struct mi_root* mi_dr_cr_status(struct mi_root *cmd, void *param) if (rpl_tree==NULL) goto error; node = add_mi_node_child( &rpl_tree->node, 0, "Enabled", 7, - (cr->flags&DR_CR_FLAG_IS_OFF)?"no ":"yes", 3); + (cr->flags&DR_CR_FLAG_IS_OFF)?"no ":"yes", 3); if (node==NULL) goto error; @@ -2357,7 +4322,7 @@ static struct mi_root* mi_dr_cr_status(struct mi_root *cmd, void *param) /* set the status */ if (node->next) { rpl_tree = init_mi_tree( 400, - MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); goto done; } if (str2int( &node->value, &stat) < 0) { @@ -2365,19 +4330,465 @@ static struct mi_root* mi_dr_cr_status(struct mi_root *cmd, void *param) goto done; } /* set the disable/enable */ + old_flags = cr->flags; if (stat) { cr->flags &= ~ (DR_CR_FLAG_IS_OFF); } else { cr->flags |= DR_CR_FLAG_IS_OFF; } + if (old_flags!=cr->flags) + cr->flags |= DR_CR_FLAG_DIRTY; + rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); done: - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); return rpl_tree; error: - lock_stop_read( ref_lock ); + lock_stop_read( current_partition->ref_lock ); if(rpl_tree) free_mi_tree(rpl_tree); return NULL; } +int add_head_db(void) { + struct head_db *new; + new = ( struct head_db* )shm_malloc(sizeof( struct head_db ) ); + if( new == NULL ) { + LM_ERR(" no more shm memory(add_head_db)\n"); + return -1; + } + memset( new, 0, sizeof( struct head_db ) ); + new->avpID_store_ruri = -1; + new->avpID_store_prefix = -1; + new->avpID_store_index = -1; + new->avpID_store_whitelist = -1; + new->avpID_store_group = -1; + new->avpID_store_flags = -1; + new->gw_priprefix_avp = -1; + new->rule_id_avp = -1; + new->rule_prefix_avp = -1; + new->carrier_id_avp = -1; + new->ruri_avp = -1; + new->gw_id_avp = -1; + new->gw_sock_avp = -1; + new->gw_attrs_avp = -1; + new->rule_attrs_avp = -1; + new->carrier_attrs_avp = -1; + if( head_db_start == NULL) { + head_db_start = new; + head_db_end = new; + } else { + head_db_end->next = new; + head_db_end = new; + } + return 0; +} + +/* use_partitions: use configurations from database */ +int add_head_config(void) { /* expand linked list */ + struct head_config *new; + new = ( struct head_config* )shm_malloc( sizeof( struct head_config ) ); + if( new == NULL ) { + LM_ERR("no more shm memory\n"); + return -1; + } + memset(new, 0, sizeof( struct head_config ) ); /* ->next will be null too */ + + if( head_start == NULL) { + head_start = new; + head_end = new; + } else { + head_end->next = new; + head_end = new; + } + return 0; +} + +#define init_head_config_value( from_head, external, default_val)\ + if( external.len!=0 ) {\ + shm_str_dup( &(from_head), &(external));\ + } else {\ + from_head = default_val;\ + }\ + +#define set_head_config_value(head_param, db_param)\ + if(db_param.len > 0) {\ + shm_str_dup(&(head_param), &(db_param));\ + }\ + + +static int populate_head_config(struct head_config *current, str attr, int index) { + switch(index) { + case 0: + if(shm_str_dup( &(current->partition), &attr) < 0) { + LM_ERR("no more shm memory for partition_name in head_config\n"); + } + break; + case 1: + if( shm_str_dup(&(current->db_url), &attr) < 0) { + LM_ERR("no more shm memory for db_url in head_config\n"); + } + break; + case 2: + init_head_config_value( current->drd_table, attr, drd_table); + break; + case 3: + init_head_config_value( current->drr_table, attr, drr_table); + break; + case 4: + init_head_config_value( current->drg_table, attr, drg_table); + break; + case 5: + init_head_config_value( current->drc_table, attr, drc_table); + break; + case 6: + set_head_config_value( current->ruri_avp_spec, attr); + break; + case 7: + set_head_config_value( current->gw_id_avp_spec, attr); + break; + case 8: + set_head_config_value( current->gw_priprefix_avp_spec, attr); + break; + case 9: + set_head_config_value( current->gw_sock_avp_spec, attr); + break; + case 10: + set_head_config_value( current->rule_id_avp_spec, attr); + break; + case 11: + set_head_config_value( current->rule_prefix_avp_spec, attr); + break; + case 12: + set_head_config_value( current->carrier_id_avp_spec, attr); + break; + default: + LM_DBG("Column from db_config not_known\n"); + return -1; + } + return 0; +} +static int get_config_from_db(void) { + + db_func_t db_funcs; + db_res_t * query_res; + db_con_t * db_con = 0; + /* columns needed from db_confgir_url for query */ + str partition_col = str_init("partition_name"); + str db_url_col = str_init("db_url"); + str drd_col = str_init("drd_table"); + str drr_col = str_init("drr_table"); + str drg_col = str_init("drg_table"); + str drc_col = str_init("drc_table"); + str ruri_avp_col = str_init("ruri_avp"); + str gw_id_avp_col = str_init("gw_id_avp"); + str gw_priprefix_avp_col = str_init("gw_priprefix_avp"); + str gw_sock_avp_col = str_init("gw_sock_avp"); + str rule_id_avp_col = str_init("rule_id_avp"); + str rule_prefix_avp_col = str_init("rule_prefix_avp"); + str carrier_id_avp_col = str_init("carrier_id_avp"); + int n_query_col = 13; + db_key_t query_cols[] = {&partition_col, &db_url_col, &drd_col, &drr_col, + &drg_col, &drc_col, &ruri_avp_col, &gw_id_avp_col, + &gw_priprefix_avp_col, &gw_sock_avp_col, + &rule_id_avp_col, &rule_prefix_avp_col, &carrier_id_avp_col}; + /* query result processing stuff */ + int nr_rows_db_config = 0 ; + int nr_cols_db_config = 0 ; + db_val_t * value; + db_row_t *rows_db_config = NULL; + int j; + int i; + str ans_col; + + + init_db_url(db_partitions_url, 0); + db_partitions_url.len = strlen(db_partitions_url.s); + db_partitions_table.len = strlen(db_partitions_table.s); + + + if(db_bind_mod( &db_partitions_url, &db_funcs) < 0) { + LM_ERR("Unable to bind to database driver (partition definitions) " + "\n", db_partitions_url.len, + db_partitions_url.s); + goto error; + } + + if( (db_con = db_funcs.init(&db_partitions_url)) == 0 ) { + LM_ERR("Cannot init connection to partitions table " + "\n", db_partitions_url.len, + db_partitions_url.s); + goto error; + } + + + if(db_check_table_version(&db_funcs, db_con, + &db_partitions_table, PART_TABLE_VER) < 0) { + LM_ERR("error during table version check .\n", + db_partitions_table.len, db_partitions_table.s); + return -1; + } + + if( db_funcs.use_table( db_con, &db_partitions_table) < 0) { + LM_ERR("Cannot use the partitions table " + "
\n", db_partitions_table.len, db_partitions_table.s, + db_partitions_url.len, db_partitions_url.s); + goto error; + } + + /* query for populating head_config structure */ + if( db_funcs.query( db_con, NULL, NULL, NULL, query_cols, 0, n_query_col, + NULL, &query_res) < 0 ) { + LM_ERR("Failed to query the table containing the partition definitions " + "\n", + db_partitions_url.len, db_partitions_url.s, + db_partitions_table.len, db_partitions_table.s); + goto error; + } + + nr_rows_db_config = RES_ROW_N(query_res); + nr_cols_db_config = RES_COL_N(query_res); + rows_db_config = RES_ROWS(query_res); + + for( i=0; irdata))->pt, + &prefix, (unsigned int)grp_id,matched_len, &rule_idx); + + if (rt_info==NULL) { + LM_DBG("no matching for prefix \"%.*s\"\n", + prefix.len, prefix.s); + + /* try prefixless rules */ + rt_info = check_rt( &(*(partition->rdata))->noprefix, + (unsigned int)grp_id); + if (rt_info == NULL) + LM_DBG("no prefixless matching for " + "grp %d\n", grp_id); + } + return rt_info; +} + +static struct mi_root* mi_dr_number_routing(struct mi_root *cmd_tree, void *param) +{ + struct mi_node *node = cmd_tree->node.kids; + struct head_db *partition; + str s; + int grp_id; + unsigned int matched_len; + struct mi_node *prefix_node; + rt_info_t *route; + + if (node == NULL) + return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + + if (use_partitions) { + s = node->value; + if((partition = get_partition(&s)) == NULL) { + LM_WARN("Partition <%.*s> was not found.\n", s.len, s.s); + return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + } + + node = node->next; + } + else partition = head_db_start; + + if (node == NULL) + return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + + if (node->next == NULL) { + grp_id = -1; + } else { + unsigned int ugrp_id; + if (str2int(&node->value, &ugrp_id) != 0) + return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + grp_id = ugrp_id; + node = node->next; + } + + lock_start_read( partition->ref_lock ); + route = find_rule_by_prefix_unsafe(partition, node->value, grp_id,&matched_len); + if (route == NULL){ + lock_stop_read( partition->ref_lock ); + return init_mi_tree(200, MI_OK_S, MI_OK_LEN); + } + + struct mi_root* rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN); + if (rpl_tree == NULL){ + lock_stop_read( partition->ref_lock ); + return 0; + } + + unsigned int i; + static const str gw_str = str_init("GATEWAY"); + static const str carrier_str = str_init("CARRIER"); + static const str matched_str = str_init("Matched Prefix"); + str chosen_desc; + str chosen_id; + if ((prefix_node = add_mi_node_child(&rpl_tree->node, 0, matched_str.s, + matched_str.len, node->value.s, matched_len)) == NULL) { + LM_ERR("failed to add node\n"); + lock_stop_read( partition->ref_lock ); + free_mi_tree(rpl_tree); + return 0; + } + + prefix_node->flags |= MI_IS_ARRAY; + + for (i = 0; i < route->pgwa_len; ++i){ + if (route->pgwl[i].is_carrier) { + chosen_desc = carrier_str; + chosen_id = route->pgwl[i].dst.carrier->id; + } + else { + chosen_desc = gw_str; + chosen_id = route->pgwl[i].dst.gw->id; + } + + if (add_mi_node_child(prefix_node, 0, chosen_desc.s, + chosen_desc.len, chosen_id.s, chosen_id.len) == NULL) { + + LM_ERR("failed to add node\n"); + lock_stop_read( partition->ref_lock ); + free_mi_tree(rpl_tree); + return 0; + } + } + lock_stop_read( partition->ref_lock ); + + return rpl_tree; +} + + +static struct mi_root* mi_dr_reload_status(struct mi_root *cmd_tree, void *param) { + struct mi_node *node = cmd_tree->node.kids; + struct mi_root *rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN); + struct mi_node *ans; + struct head_db * partition; + str part_name; + char * ch_time; + + if(node != NULL) { + if (use_partitions) { + part_name = node->value; + if((partition = get_partition(&part_name)) == NULL) { + LM_WARN("Partition <%.*s> was not found.\n", part_name.len, + part_name.s); + return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + } + /* display just for given partition */ + lock_start_read(partition->ref_lock); + ch_time = ctime(&partition->time_last_update); + if((ans = add_mi_node_child(&rpl_tree->node, MI_DUP_VALUE, + MI_PART_NAME_S, MI_PART_NAME_LEN, partition->partition.s, + partition->partition.len)) == NULL) { + LM_ERR("failed to add mi_node\n"); + goto error; + } + if(add_mi_attr(ans, 0, MI_LAST_UPDATE_S, MI_LAST_UPDATE_LEN, + ch_time, strlen(ch_time)) == NULL) { + LM_ERR("failed to add mi_attr\n"); + goto error; + } + lock_stop_read(partition->ref_lock); + } else { + return init_mi_tree(400, MI_NO_PART_S, MI_NO_PART_LEN); + } + } + else if(use_partitions){ + rpl_tree->node.flags |= MI_IS_ARRAY; + + /* display for all partitions */ + for(partition = head_db_start; partition; partition = partition->next) { + lock_start_read(partition->ref_lock); + ch_time = ctime(&partition->time_last_update); + LM_DBG("partition %.*s was last updated:%s\n", + partition->partition.len, partition->partition.s, + ch_time); + if((ans = add_mi_node_child(&rpl_tree->node, 0, MI_PART_NAME_S, + MI_PART_NAME_LEN, partition->partition.s, + partition->partition.len)) == NULL) { + LM_ERR("failed to add mi_node\n"); + goto error; + } + if(add_mi_attr(ans, 0, MI_LAST_UPDATE_S, MI_LAST_UPDATE_LEN, + ch_time, strlen(ch_time)) == NULL) { + LM_ERR("failed to add attr to mi_node\n"); + goto error; + } + lock_stop_read(partition->ref_lock); + } + } + else { + /* just one partition */ + partition = head_db_start; + + lock_start_read(partition->ref_lock); + ch_time = ctime(&partition->time_last_update); + if((ans = add_mi_node_child(&rpl_tree->node, 0, MI_LAST_UPDATE_S, + MI_LAST_UPDATE_LEN, ch_time, strlen(ch_time))) == NULL) { + LM_ERR("failed to add mi_node\n"); + goto error; + } + lock_stop_read(partition->ref_lock); + + } + return rpl_tree; +error: + lock_stop_read(partition->ref_lock); + free_mi_tree(rpl_tree); + return 0; + +} diff --git a/modules/drouting/prefix_tree.c b/modules/drouting/prefix_tree.c index f6c51884dec..40ff908c953 100644 --- a/modules/drouting/prefix_tree.c +++ b/modules/drouting/prefix_tree.c @@ -45,7 +45,7 @@ extern int unode; -static inline int +static inline int check_time( tmrec_t *time_rec ) @@ -88,7 +88,7 @@ internal_check_rt( rg=ptn->rg; for(i=0;(is; - /* go the tree down to the last digit in the + /* go the tree down to the last digit in the * prefix string or down to a leaf */ while(tmp< (prefix->s+prefix->len)) { if(NULL == tmp) @@ -184,7 +184,7 @@ get_prefix( return NULL; } -pgw_t* +pgw_t* get_gw_by_internal_id( pgw_t* gw, unsigned int id @@ -200,7 +200,7 @@ get_gw_by_internal_id( -pgw_t* +pgw_t* get_gw_by_id( pgw_t* gw, str *id @@ -217,7 +217,7 @@ get_gw_by_id( } -pcr_t* +pcr_t* get_carrier_by_id( pcr_t* carrier, str *id @@ -233,24 +233,29 @@ get_carrier_by_id( } -int +int add_prefix( ptree_t *ptree, str* prefix, rt_info_t *r, unsigned int rg -) +) { char* tmp=NULL; int res = 0; - if(NULL==ptree) + if(NULL==ptree) { + LM_ERR("ptree is null\n"); goto err_exit; + } tmp = prefix->s; while(tmp < (prefix->s+prefix->len)) { - if(NULL == tmp) + if(NULL == tmp) { + LM_ERR("prefix became null\n"); goto err_exit; + } if( !IS_DECIMAL_DIGIT(*tmp) ) { /* unknown character in the prefix string */ + LM_ERR("is not decimal digit\n"); goto err_exit; } if( tmp == (prefix->s+prefix->len-1) ) { @@ -258,8 +263,10 @@ add_prefix( LM_DBG("adding info %p, %d at: " "%p (%d)\n", r, rg, &(ptree->ptnode[*tmp-'0']), *tmp-'0'); res = add_rt_info(&(ptree->ptnode[*tmp-'0']), r,rg); - if(res < 0 ) + if(res < 0 ) { + LM_ERR("adding rt info doesn't work\n"); goto err_exit; + } unode++; res = 1; goto ok_exit; @@ -270,14 +277,14 @@ add_prefix( INIT_PTREE_NODE(ptree, ptree->ptnode[*tmp - '0'].next); inode+=10; #if 0 - printf("new tree node: %p (bp: %p)\n", + printf("new tree node: %p (bp: %p)\n", ptree->ptnode[*tmp - '0'].next, ptree->ptnode[*tmp - '0'].next->bp ); #endif } ptree = ptree->ptnode[*tmp-'0'].next; - tmp++; + tmp++; } ok_exit: @@ -287,7 +294,7 @@ add_prefix( return -1; } -int +int del_tree( ptree_t* t ) diff --git a/modules/drouting/prefix_tree.h b/modules/drouting/prefix_tree.h index 69e312806a9..b7fa589c0ea 100644 --- a/modules/drouting/prefix_tree.h +++ b/modules/drouting/prefix_tree.h @@ -59,18 +59,21 @@ do {\ #define DR_DST_PING_PERM_FLAG (1<<1) #define DR_DST_STAT_DSBL_FLAG (1<<2) #define DR_DST_STAT_NOEN_FLAG (1<<3) +#define DR_DST_STAT_DIRT_FLAG (1<<4) +#define DR_DST_STAT_MASK (DR_DST_STAT_DSBL_FLAG|DR_DST_STAT_NOEN_FLAG) #define DR_MAX_IPS 32 /* list of PSTN gw */ typedef struct pgw_ { - /* internal numerical ID */ + /* internal numerical ID, not DB related */ unsigned int _id; - /* GW ID*/ + /* GW ID from DB */ str id; /* type of gateway */ int type; str ip_str; + struct socket_info *sock; /* strip / pri and attrs */ str pri; int strip; @@ -98,12 +101,11 @@ typedef struct pgw_list_ { #define DR_CR_FLAG_WEIGHT (1<<0) #define DR_CR_FLAG_FIRST (1<<1) #define DR_CR_FLAG_IS_OFF (1<<2) +#define DR_CR_FLAG_DIRTY (1<<3) /* list of carriers */ struct pcr_ { - /* id matching the one in db */ - unsigned int db_id; - /* carrier ID/name */ + /* carrier ID/name from DB */ str id; /* flags */ unsigned int flags; @@ -161,7 +163,7 @@ typedef struct ptree_ { ptree_node_t ptnode[PTREE_CHILDREN]; } ptree_t; -void +void print_interim( int, int, @@ -193,7 +195,7 @@ get_prefix( int add_rt_info( - ptree_node_t*, + ptree_node_t*, rt_info_t*, unsigned int ); diff --git a/modules/drouting/routing.c b/modules/drouting/routing.c index a4d2e0a58fc..8aeea6e7628 100644 --- a/modules/drouting/routing.c +++ b/modules/drouting/routing.c @@ -120,7 +120,7 @@ int parse_destination_list(rt_data_t* rd, char *dstlist, /* eat the destination ID (alphanumerical) */ id.s = tmp; - while( *tmp && (isalpha(*tmp) || isdigit(*tmp) || (*tmp)=='_') ) + while( *tmp && (isalpha(*tmp) || isdigit(*tmp) || (*tmp)=='_' || (*tmp)=='-') ) tmp++; if (id.s == tmp) { LM_ERR("bad id '%c' (%d)[%s]\n", @@ -214,8 +214,8 @@ int parse_destination_list(rt_data_t* rd, char *dstlist, } -int add_carrier(int db_id, char *id, int flags, char *gwlist, char *attrs, - rt_data_t *rd) +int add_carrier(char *id, int flags, char *gwlist, char *attrs, + int state, rt_data_t *rd) { pcr_t *cr = NULL; unsigned int i; @@ -247,9 +247,16 @@ int add_carrier(int db_id, char *id, int flags, char *gwlist, char *attrs, } /* copy integer fields */ - cr->db_id = db_id; cr->flags = flags; + /* set state */ + if (state!=0) + /* disabled */ + cr->flags |= DR_CR_FLAG_IS_OFF; + else + /* enabled */ + cr->flags &= ~DR_CR_FLAG_IS_OFF; + /* copy id */ cr->id.s = (char*)(cr+1); cr->id.len = strlen(id); @@ -414,7 +421,7 @@ add_dst( rt_data_t *r, /* id */ char *id, - /* ip address */ + /* ip address */ char* ip, /* strip len */ int strip, @@ -425,8 +432,11 @@ add_dst( /* dst attrs*/ char* attrs, /* probe_mode */ - int probing - + int probing, + /* socket */ + struct socket_info *sock, + /* state */ + int state ) { static unsigned id_counter = 0; @@ -495,21 +505,37 @@ add_dst( } memset(pgw,0,sizeof(pgw_t)); - switch(probing) - { - case 0: - pgw->flags = 0; - break; - case 1: - pgw->flags = DR_DST_PING_DSBL_FLAG; - break; - case 2: - pgw->flags = DR_DST_PING_PERM_FLAG; - break; - default: - goto err_exit; + /* set probing related flags */ + switch(probing) { + case 0: + break; + case 1: + pgw->flags |= DR_DST_PING_DSBL_FLAG; + break; + case 2: + pgw->flags |= DR_DST_PING_PERM_FLAG; + break; + default: + goto err_exit; } + /* set state related flags */ + switch(state) { + case 0: + break; + case 1: + pgw->flags |= DR_DST_STAT_DSBL_FLAG|DR_DST_STAT_NOEN_FLAG; + break; + case 2: + pgw->flags |= DR_DST_STAT_DSBL_FLAG; + break; + default: + goto err_exit; + } + + /* set outbound socket */ + pgw->sock = sock; + pgw->_id = ++id_counter; pgw->id.len= l_id; @@ -607,7 +633,7 @@ void del_carriers_list( } } -void +void free_rt_data( rt_data_t* rt_data, int all diff --git a/modules/drouting/routing.h b/modules/drouting/routing.h index 09c8c94943a..0baac82aaaf 100644 --- a/modules/drouting/routing.h +++ b/modules/drouting/routing.h @@ -50,7 +50,7 @@ typedef struct hb_ { /* routing data is comprised of: - a list of PSTN gw - - a hash over routing groups containing + - a hash over routing groups containing pointers to the coresponding prefix trees */ typedef struct rt_data_ { @@ -69,10 +69,7 @@ typedef struct _dr_group { int type; union { unsigned int grp_id; - struct _avp_id{ - int name; - unsigned short type; - }avp_id; + int avp_name; }u; } dr_group_t; @@ -83,11 +80,11 @@ build_rt_data( void ); int add_carrier( - int db_id, char *id, int flags, char *gwlist, char *attrs, + int state, rt_data_t *rd ); @@ -97,7 +94,7 @@ add_dst( rt_data_t*, /* id */ char *, - /* ip address */ + /* ip address */ char*, /* strip len */ int, @@ -108,6 +105,10 @@ add_dst( /* dst attrs*/ char*, /* probe_mode */ + int, + /* socket */ + struct socket_info*, + /* state */ int ); diff --git a/modules/enum/README b/modules/enum/README index e983440f3bb..363e22896de 100644 --- a/modules/enum/README +++ b/modules/enum/README @@ -10,8 +10,7 @@ Otmar Lendl Copyright © 2002, 2003 Juha Heinanen Revision History - Revision $Revision$ $Date: 2010-01-18 10:45:05 +0100 - (Mon, 18 Jan 2010) $ + Revision $Revision: 5907 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/enum/enum.c b/modules/enum/enum.c index 4c3404aa47c..49028d15c4a 100644 --- a/modules/enum/enum.c +++ b/modules/enum/enum.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -59,8 +59,8 @@ static int cclen(const char *number) d1 = number[0]; d2 = number[1]; - - if (!isdigit((int)d2)) + + if (!isdigit((int)d2)) return(0); switch(d1) { @@ -90,7 +90,7 @@ static int cclen(const char *number) return(2); break; case '8': - if ((d2 == '1') || (d1 == '2') || (d1 == '4') || (d1 == '6')) + if ((d2 == '1') || (d1 == '2') || (d1 == '4') || (d1 == '6')) return(2); break; case '9': @@ -117,7 +117,7 @@ static inline int findchr(char* p, int c, unsigned int size) if (*p==(unsigned char)c) { return len; } - len++; + len++; } return len; } @@ -290,7 +290,7 @@ int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service) LM_ERR("Failed to parse From header\n"); return -1; } - + if(_msg->from==NULL || get_from(_msg)==NULL) { LM_DBG("No From header\n"); return -1; @@ -361,7 +361,7 @@ int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service) #ifdef LATER if ((pattern.len == 4) && (strncmp(pattern.s, "^.*$", 4) == 0)) { LM_DBG("Resulted in replacement: '%.*s'\n", - replacement.len, ZSW(replacement.s)); + replacement.len, ZSW(replacement.s)); retval = set_uri(_msg, replacement.s, replacement.len); free_rdata_list(head); /*clean up*/ return retval; @@ -373,7 +373,7 @@ int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service) pattern.s[pattern.len] = (char)0; replacement.s[replacement.len] = (char)0; /* We have already checked the size of - _msg->parsed_uri.user.s */ + _msg->parsed_uri.user.s */ memcpy(&(string[0]), user_s, user_len); string[user_len] = (char)0; if (reg_replace(pattern.s, replacement.s, &(string[0]), @@ -421,7 +421,7 @@ int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service) -/* +/* * Add parameter to URI. */ int add_uri_param(str *uri, str *param, str *new_uri) @@ -502,7 +502,7 @@ int add_uri_param(str *uri, str *param, str *new_uri) /* * Tests if one result record is "greater" that the other. Non-NAPTR records - * greater that NAPTR record. An invalid NAPTR record is greater than a + * greater that NAPTR record. An invalid NAPTR record is greater than a * valid one. Valid NAPTR records are compared based on their * (order,preference). */ @@ -532,34 +532,34 @@ static inline void naptr_sort(struct rdata** head) struct rdata *p, *q, *r, *s, *temp, *start; /* r precedes p and s points to the node up to which comparisons - are to be made */ + are to be made */ s = NULL; start = *head; - while ( s != start -> next ) { - r = p = start ; + while ( s != start -> next ) { + r = p = start ; q = p -> next ; - while ( p != s ) { - if ( naptr_greater(p, q) ) { - if ( p == start ) { - temp = q -> next ; - q -> next = p ; + while ( p != s ) { + if ( naptr_greater(p, q) ) { + if ( p == start ) { + temp = q -> next ; + q -> next = p ; p -> next = temp ; - start = q ; - r = q ; + start = q ; + r = q ; } else { - temp = q -> next ; - q -> next = p ; + temp = q -> next ; + q -> next = p ; p -> next = temp ; - r -> next = q ; - r = q ; - } + r -> next = q ; + r = q ; + } } else { - r = p ; - p = p -> next ; - } - q = p -> next ; - if ( q == s ) s = p ; + r = p ; + p = p -> next ; + } + q = p -> next ; + if ( q == s ) s = p ; } } *head = start; @@ -567,7 +567,7 @@ static inline void naptr_sort(struct rdata** head) /* - * Makes enum query on name. On success, rewrites user part and + * Makes enum query on name. On success, rewrites user part and * replaces Request-URI. */ int do_query(struct sip_msg* _msg, char *user, char *name, str *service) { @@ -582,12 +582,12 @@ int do_query(struct sip_msg* _msg, char *user, char *name, str *service) { str pattern, replacement, result, new_result; head = get_record(name, T_NAPTR); - + if (head == 0) { LM_DBG("No NAPTR record found for %s.\n", name); return -1; } - + naptr_sort(&head); q = MAX_Q - 10; @@ -610,9 +610,9 @@ int do_query(struct sip_msg* _msg, char *user, char *name, str *service) { naptr->services_len, (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, (int)(naptr->regexp_len), ZSW(naptr->regexp)); - + if (sip_match(naptr, service) == 0) continue; - + if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, &pattern, &replacement) < 0) { LM_ERR("Parsing of NAPTR regexp failed\n"); @@ -958,7 +958,7 @@ int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service) } memcpy(name + j, suffix->s, suffix->len + 1); - LM_DBG("Looking for EBL record for %s.\n", name); + LM_DBG("Looking for EBL record for %s.\n", name); head = get_record(name, T_EBL); if (head == 0) { LM_DBG("No EBL found for %s. Defaulting to user ENUM.\n",name); @@ -971,13 +971,13 @@ int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service) ebl->separator,(int)ebl->apex_len, ebl->apex); if ((ebl->apex_len > MAX_COMPONENT_SIZE) || (ebl->separator_len > MAX_COMPONENT_SIZE)) { - LM_ERR("EBL strings too long\n"); + LM_ERR("EBL strings too long\n"); return -1; } if (ebl->position > 15) { LM_ERR("EBL position too large (%d)\n", - ebl->position); + ebl->position); return -1; } @@ -1201,7 +1201,7 @@ int enum_pv_query_3(struct sip_msg* _msg, char* _sp, char* _suffix, result.len, ZSW(result.s)); pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; - + if (param.len > 0) { if (result.len + param.len > MAX_URI_SIZE - 1) { LM_ERR("URI is too long\n"); diff --git a/modules/enum/enum.h b/modules/enum/enum.h index 8ce1cdd7914..e7240358d5d 100644 --- a/modules/enum/enum.h +++ b/modules/enum/enum.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -32,7 +32,7 @@ #define MAX_DOMAIN_SIZE 256 #define MAX_COMPONENT_SIZE 32 /* separator, apex, ... This simplifies checks */ - + /* * Check if from user is an e164 number and has a naptr record diff --git a/modules/enum/enum_mod.c b/modules/enum/enum_mod.c index 2f8c0d2f55c..f32b401c60a 100644 --- a/modules/enum/enum_mod.c +++ b/modules/enum/enum_mod.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -79,7 +79,7 @@ static cmd_export_t cmds[] = { {"enum_query", (cmd_function)enum_query_0, 0, 0, 0, REQUEST_ROUTE}, {"enum_query", (cmd_function)enum_query_1, 1, fixup_sgp_null, fixup_free_str_null, REQUEST_ROUTE}, - {"enum_query", (cmd_function)enum_query_2, 2, fixup_sgp_sgp, + {"enum_query", (cmd_function)enum_query_2, 2, fixup_sgp_sgp, fixup_free_str_str, REQUEST_ROUTE}, {"enum_pv_query", (cmd_function)enum_pv_query_1, 1, fixup_pvar_null, fixup_free_pvar_null, REQUEST_ROUTE}, @@ -101,7 +101,7 @@ static cmd_export_t cmds[] = { {"isn_query", (cmd_function)isn_query_0, 0, 0, 0, REQUEST_ROUTE}, {"isn_query", (cmd_function)isn_query_1, 1, fixup_str_null, fixup_free_str_null, REQUEST_ROUTE}, - {"isn_query", (cmd_function)isn_query_2, 2, fixup_str_str, + {"isn_query", (cmd_function)isn_query_2, 2, fixup_str_str, fixup_free_str_str, REQUEST_ROUTE}, {0, 0, 0, 0, 0, 0} }; @@ -125,9 +125,11 @@ static param_export_t params[] = { * Module parameter variables */ struct module_exports exports = { - "enum", + "enum", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -144,7 +146,7 @@ struct module_exports exports = { static int mod_init(void) { LM_DBG("Initializing\n"); - + suffix.s = domain_suffix; suffix.len = strlen(suffix.s); diff --git a/modules/enum/enum_mod.h b/modules/enum/enum_mod.h index b8d77235f64..03d20388c64 100644 --- a/modules/enum/enum_mod.h +++ b/modules/enum/enum_mod.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/event_datagram/README b/modules/event_datagram/README index 8a92e021681..a90cc86cacc 100644 --- a/modules/event_datagram/README +++ b/modules/event_datagram/README @@ -153,4 +153,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/event_datagram/event_datagram.c b/modules/event_datagram/event_datagram.c index 2b7276a2ccf..ff062efcfeb 100644 --- a/modules/event_datagram/event_datagram.c +++ b/modules/event_datagram/event_datagram.c @@ -69,8 +69,10 @@ static str datagram_print(evi_reply_sock *sock); */ struct module_exports exports= { "event_datagram", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ 0, /* exported parameters */ 0, /* exported statistics */ @@ -85,7 +87,7 @@ struct module_exports exports= { /** - * exported functions for core event interface + * exported functions for core event interface */ static evi_export_t trans_export_udp = { UDP_STR, /* transport module name */ @@ -139,7 +141,7 @@ static int datagram_match(evi_reply_sock *sock1, evi_reply_sock *sock2) if (((sock1->flags & EVI_PORT) != (sock2->flags & EVI_PORT)) || ((sock1->flags & EVI_PORT) && (sock1->port != sock2->port))) return 0; - + if (sock1->flags & EVI_ADDRESS && sock2->flags & EVI_ADDRESS) { if (!memcmp(sock1->address.s, sock2->address.s, sock1->address.len)) { @@ -200,7 +202,7 @@ static evi_reply_sock* datagram_parse(str socket, int is_unix) if (port) { sock->flags = EVI_PORT; sock->port = port; - + /* also build sockaddr */ *p = 0; hentity = resolvehost(host, 0); @@ -277,12 +279,6 @@ static str datagram_print(evi_reply_sock *sock) goto end; } - if (sock->flags & DGRAM_UDP_FLAG) { - DO_PRINT("udp:", 4); - } else { - DO_PRINT("unix:", 5); - } - if (sock->flags & EVI_ADDRESS) DO_PRINT(sock->address.s, sock->address.len); @@ -291,7 +287,7 @@ static str datagram_print(evi_reply_sock *sock) aux.s = int2str(sock->port, &aux.len); DO_PRINT(aux.s, aux.len); } - + end: return datagram_print_s; } @@ -321,7 +317,7 @@ static int datagram_build_params(str* ev_name, evi_params_p ev_params) } dgram_buffer_len = 0; - + /* first is event name - cannot be larger than the buffer size */ memcpy(dgram_buffer, ev_name->s, ev_name->len); dgram_buffer[ev_name->len] = PARAM_SEP; diff --git a/modules/event_datagram/event_datagram.h b/modules/event_datagram/event_datagram.h index 8e9a9a2690b..d2145e3e3ea 100644 --- a/modules/event_datagram/event_datagram.h +++ b/modules/event_datagram/event_datagram.h @@ -45,7 +45,7 @@ #define PARAM_SEP '\n' #define QUOTE_C '"' #define ESC_C '\\' -#define ATTR_SEP_S "::" +#define ATTR_SEP_S "::" #define ATTR_SEP_LEN (sizeof(ATTR_SEP_S) - 1) struct dgram_socks { diff --git a/modules/event_rabbitmq/Makefile b/modules/event_rabbitmq/Makefile index a37aaf0b791..d799b1789ce 100644 --- a/modules/event_rabbitmq/Makefile +++ b/modules/event_rabbitmq/Makefile @@ -5,8 +5,22 @@ include ../../Makefile.defs auto_gen= NAME=event_rabbitmq.so -DEFS+=-I$(LOCALBASE)/include -LIBS=-L$(LOCALBASE)/lib -lrabbitmq + +ifeq ($(CROSS_COMPILE),) +RABBITMQ_BUILDER = $(shell \ + if pkg-config --exists librabbitmq; then \ + echo 'pkg-config librabbitmq'; \ + fi) +endif + +ifeq ($(RABBITMQ_BUILDER),) + DEFS+=-I$(LOCALBASE)/include + LIBS=-L$(LOCALBASE)/lib -lrabbitmq +else + DEFS += $(shell $(RABBITMQ_BUILDER) --cflags) + LIBS += $(shell $(RABBITMQ_BUILDER) --libs) +endif + include ../../Makefile.modules diff --git a/modules/event_rabbitmq/README b/modules/event_rabbitmq/README index 26cfd21e63c..82dbb2de594 100644 --- a/modules/event_rabbitmq/README +++ b/modules/event_rabbitmq/README @@ -24,6 +24,9 @@ Razvan Crainea 1.4.2. External Libraries or Applications 1.5. Exported Parameters + + 1.5.1. heartbeat (integer) + 1.6. Exported Functions 1.7. Example 1.8. Installation and Running @@ -34,9 +37,10 @@ Razvan Crainea List of Examples - 1.1. E_PIKE_BLOCKED event - 1.2. RabbitMQ socket - 1.3. OpenSIPS config script - sample event_rabbitmq usage + 1.1. Set heartbeat parameter + 1.2. E_PIKE_BLOCKED event + 1.3. RabbitMQ socket + 1.4. OpenSIPS config script - sample event_rabbitmq usage 2.1. Event subscription 2.2. Event subscription @@ -73,7 +77,8 @@ Chapter 1. Admin Guide 1.3. RabbitMQ socket syntax - 'rabbitmq:' [user[':'password] '@' host [':' port] '/' exchange + 'rabbitmq:' [user[':'password] '@' host [':' port] '/' + [exchange '?'] routing_key Meanings: * 'rabbitmq:' - informs the Event Interface that the events @@ -86,9 +91,11 @@ Chapter 1. Admin Guide * host - host name of the RabbitMQ server. * port - port of the RabbitMQ server. The default value is '5672'. - * exchange - this is the exchange routing information used by - the AMQP protocol. It is also used to identify the queue - where the event should be sent. + * exchange - exchange of the RabbitMQ server. The default + value is ''. + * routing_key - this is the routing key used by the AMQP + protocol and it is used to identify the queue where the + event should be sent. NOTE: if the queue does not exist, this module will not try to create it. @@ -107,7 +114,21 @@ Chapter 1. Admin Guide 1.5. Exported Parameters - No parameter exported by this module. +1.5.1. heartbeat (integer) + + Enables heartbeat support for the AMQP communication. If the + client does not receive a heartbeat from server within the + specified interval, the socket is automatically closed by the + rabbitmq-client. This prevents OpenSIPS from blocking while + waiting for a response from a dead rabbitmq-server. The value + represents the heartbit interval in seconds. + + Default value is “0 (disabled)”. + + Example 1.1. Set heartbeat parameter +... +modparam("event_rabbitmq", "heartbeat", 3) +... 1.6. Exported Functions @@ -118,13 +139,13 @@ Chapter 1. Admin Guide This is an example of an event raised by the pike module when it decides an ip should be blocked: - Example 1.1. E_PIKE_BLOCKED event + Example 1.2. E_PIKE_BLOCKED event E_PIKE_BLOCKED ip::192.168.2.11 - Example 1.2. RabbitMQ socket + Example 1.3. RabbitMQ socket rabbitmq:guest:guest@127.0.0.1:5672/pike @@ -142,7 +163,7 @@ Chapter 1. Admin Guide The parameters passed to the server are the R-URI username and the message body. - Example 1.3. OpenSIPS config script - sample event_rabbitmq + Example 1.4. OpenSIPS config script - sample event_rabbitmq usage ... loadmodule "signaling.so" @@ -376,4 +397,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/event_rabbitmq/doc/event_rabbitmq_admin.xml b/modules/event_rabbitmq/doc/event_rabbitmq_admin.xml index 770f5dd3b53..88463d03a22 100644 --- a/modules/event_rabbitmq/doc/event_rabbitmq_admin.xml +++ b/modules/event_rabbitmq/doc/event_rabbitmq_admin.xml @@ -60,7 +60,7 @@
RabbitMQ socket syntax - 'rabbitmq:' [user[':'password] '@' host [':' port] '/' exchange + 'rabbitmq:' [user[':'password] '@' host [':' port] '/' [exchange '?'] routing_key Meanings: @@ -86,9 +86,13 @@ default value is '5672'. - exchange - this is the exchange routing - information used by the AMQP protocol. It is also used to - identify the queue where the event should be sent. + exchange - exchange of the RabbitMQ server. The + default value is ''. + + + routing_key - this is the routing key + used by the AMQP protocol and it is used to identify the queue + where the event should be sent. NOTE: if the queue does not exist, this module will not try to create it. @@ -129,9 +133,30 @@
Exported Parameters +
+ <varname>heartbeat</varname> (integer) - No parameter exported by this module. + Enables heartbeat support for the AMQP communication. If the + client does not receive a heartbeat from server within the + specified interval, the socket is automatically closed by the + rabbitmq-client. This prevents OpenSIPS from blocking while + waiting for a response from a dead rabbitmq-server. The value + represents the heartbit interval in seconds. + + + Default value is 0 (disabled). + + + + Set <varname>heartbeat</varname> parameter + +... +modparam("event_rabbitmq", "heartbeat", 3) +... + + +
diff --git a/modules/event_rabbitmq/event_rabbitmq.c b/modules/event_rabbitmq/event_rabbitmq.c index b0adc4d2858..e1da4e105ad 100644 --- a/modules/event_rabbitmq/event_rabbitmq.c +++ b/modules/event_rabbitmq/event_rabbitmq.c @@ -43,6 +43,11 @@ static int mod_init(void); static int child_init(int); static void destroy(void); +/** + * module parameters + */ +static unsigned int heartbeat = 0; + /** * exported functions */ @@ -58,15 +63,24 @@ static proc_export_t procs[] = { {"RabbitMQ sender", 0, 0, rmq_process, 1, 0}, {0,0,0,0,0,0} }; + +/* module parameters */ +static param_export_t mod_params[] = { + {"heartbeat", INT_PARAM, &heartbeat}, + {0,0,0} +}; + /** * module exports */ struct module_exports exports= { "event_rabbitmq", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ - 0, /* exported parameters */ + mod_params, /* exported parameters */ 0, /* exported statistics */ 0, /* exported MI functions */ 0, /* exported pseudo-variables */ @@ -79,7 +93,7 @@ struct module_exports exports= { /** - * exported functions for core event interface + * exported functions for core event interface */ static evi_export_t trans_export_rmq = { RMQ_STR, /* transport module name */ @@ -96,7 +110,7 @@ static evi_export_t trans_export_rmq = { */ static int mod_init(void) { - LM_NOTICE("initializing module ...\n"); + LM_NOTICE("initializing module ......\n"); if (register_event_mod(&trans_export_rmq)) { LM_ERR("cannot register transport functions for RabbitMQ\n"); @@ -108,6 +122,13 @@ static int mod_init(void) return -1; } + if ( heartbeat <= 0 || heartbeat > 65535) { + LM_WARN("heartbeat is disabled according to the modparam configuration\n"); + heartbeat = 0; + } else { + LM_WARN("heartbeat is enabled for [%d] seconds\n", heartbeat); + } + return 0; } @@ -136,20 +157,20 @@ static int rmq_match(evi_reply_sock *sock1, evi_reply_sock *sock2) p1 = (rmq_params_t *)sock1->params; p2 = (rmq_params_t *)sock2->params; if (!p1 || !p2 || - !(p1->flags & RMQ_PARAM_EXCH) || !(p2->flags & RMQ_PARAM_EXCH) || - !(p1->flags & RMQ_PARAM_USER) || !(p2->flags & RMQ_PARAM_USER)) + !(p1->flags & RMQ_PARAM_RKEY) || !(p2->flags & RMQ_PARAM_RKEY)) return 0; if (sock1->port == sock2->port && sock1->address.len == sock2->address.len && - p1->exchange.len == p2->exchange.len && - p1->user.len == p2->user.len && + p1->routing_key.len == p2->routing_key.len && + p1->user.len == p2->user.len && p1->exchange.len == p2->exchange.len && (p1->user.s == p2->user.s || /* trying the static values */ - !memcmp(p1->user.s, p2->user.s, p1->user.len)) && + !memcmp(p1->user.s, p2->user.s, p1->user.len)) && !memcmp(sock1->address.s, sock2->address.s, sock1->address.len) && + !memcmp(p1->routing_key.s, p2->routing_key.s, p1->routing_key.len) && !memcmp(p1->exchange.s, p2->exchange.s, p1->exchange.len)) { LM_DBG("socket matched: %s@%s:%hu/%s\n", - p1->user.s, sock1->address.s, sock2->port, p1->exchange.s); + p1->user.s, sock1->address.s, sock2->port, p1->routing_key.s); return 1; } return 0; @@ -157,22 +178,33 @@ static int rmq_match(evi_reply_sock *sock1, evi_reply_sock *sock2) static inline int dupl_string(str* dst, const char* begin, const char* end) { + str tmp; + if (dst->s) + shm_free(dst->s); + + tmp.s = (char *)begin; + tmp.len = end - begin; + dst->s = shm_malloc(end - begin + 1); if (!dst->s) { LM_ERR("no more shm memory\n"); return -1; } - memcpy(dst->s, begin, end - begin); - dst->s[end - begin] = 0; - dst->len = end - begin + 1; + if (un_escape(&tmp, dst) < 0) + return -1; + + /* NULL-terminate the string */ + dst->s[dst->len] = 0; + dst->len++; + return 0; } /* * This is the parsing function * The socket grammar should be: - * [user [':' password] '@'] ip [':' port] '/' exchange + * [user [':' password] '@'] ip [':' port] '/' [ exchange ?] routing_key */ static evi_reply_sock* rmq_parse(str socket) { @@ -187,6 +219,7 @@ static evi_reply_sock* rmq_parse(str socket) ST_PASS_PORT, /* Password or port part */ ST_HOST, /* Hostname part */ ST_PORT, /* Port part */ + ST_ROUTE_OR_EXPORT /* Routing or export key */ } st; if (!socket.len || !socket.s) { @@ -231,11 +264,8 @@ static evi_reply_sock* rmq_parse(str socket) if (dupl_string(&sock->address, begin, socket.s + i) < 0) goto err; sock->flags |= EVI_ADDRESS; - if (dupl_string(¶m->exchange, socket.s + i + 1, - socket.s + len) < 0) - goto err; - param->flags |= RMQ_PARAM_EXCH; - goto success; + st = ST_ROUTE_OR_EXPORT; + begin = socket.s + i + 1; } break; @@ -266,11 +296,8 @@ static evi_reply_sock* rmq_parse(str socket) goto err; } sock->flags |= EVI_PORT; - if (dupl_string(¶m->exchange, socket.s + i + 1, - socket.s + len) < 0) - goto err; - param->flags |= RMQ_PARAM_EXCH; - goto success; + st = ST_ROUTE_OR_EXPORT; + begin = socket.s + i + 1; } break; @@ -289,11 +316,8 @@ static evi_reply_sock* rmq_parse(str socket) goto err; sock->flags |= EVI_ADDRESS; - if (dupl_string(¶m->exchange, socket.s + i + 1, - socket.s + len) < 0) - goto err; - param->flags |= RMQ_PARAM_EXCH; - goto success; + st = ST_ROUTE_OR_EXPORT; + begin = socket.s + i + 1; } break; @@ -308,16 +332,37 @@ static evi_reply_sock* rmq_parse(str socket) } sock->flags |= EVI_PORT; - if (dupl_string(¶m->exchange, socket.s + i + 1, - socket.s + len) < 0) + st = ST_ROUTE_OR_EXPORT; + begin = socket.s + i + 1; + } + break; + + case ST_ROUTE_OR_EXPORT: + switch(socket.s[i]) { + case '?': + + if (dupl_string(¶m->exchange, begin, socket.s + i) < 0) goto err; - param->flags |= RMQ_PARAM_EXCH; + param->flags |= RMQ_PARAM_EKEY; + + if (dupl_string(¶m->routing_key, socket.s + i + 1, socket.s + len) < 0) + goto err; + param->flags |= RMQ_PARAM_RKEY; + + goto success; + } + if(i == len - 1){ + if (dupl_string(¶m->routing_key, begin, socket.s + len) < 0) + goto err; + + param->flags |= RMQ_PARAM_RKEY; goto success; } break; + } } - LM_WARN("not implemented %.*s\n", socket.len, socket.s); + LM_WARN("not implemented %.*s\n", socket.len, socket.s); goto err; success: @@ -331,6 +376,7 @@ static evi_reply_sock* rmq_parse(str socket) param->flags |= RMQ_PARAM_USER|RMQ_PARAM_PASS; } + param->heartbeat = heartbeat; sock->params = param; sock->flags |= EVI_PARAMS | RMQ_FLAG; @@ -375,8 +421,6 @@ static str rmq_print(evi_reply_sock *sock) goto end; } - DO_PRINT(RMQ_NAME":", sizeof(RMQ_NAME)); - if (!(sock->flags & EVI_PARAMS)) goto end; @@ -388,9 +432,15 @@ static str rmq_print(evi_reply_sock *sock) if (sock->flags & EVI_ADDRESS) DO_PRINT(sock->address.s, sock->address.len - 1); - if (param->flags & RMQ_PARAM_EXCH) { - DO_PRINT("/", 1); + DO_PRINT("/", 1); /* needs to be changed if it can print a key without RMQ_PARAM_RKEY */ + + if (param->flags & RMQ_PARAM_EKEY) { DO_PRINT(param->exchange.s, param->exchange.len - 1); + DO_PRINT("?", 1); + } + + if (param->flags & RMQ_PARAM_RKEY) { + DO_PRINT(param->routing_key.s, param->routing_key.len - 1); } end: return rmq_print_s; @@ -423,7 +473,7 @@ static int rmq_build_params(str* ev_name, evi_params_p ev_params) } rmq_buffer_len = 0; - + /* first is event name - cannot be larger than the buffer size */ memcpy(rmq_buffer, ev_name->s, ev_name->len); rmq_buffer_len = ev_name->len; @@ -514,7 +564,7 @@ static int rmq_raise(struct sip_msg *msg, str* ev_name, LM_ERR("error while building parameters list\n"); return -1; } - rmqs = shm_malloc(sizeof(rmq_send_t *) + len); + rmqs = shm_malloc(sizeof(rmq_send_t) + len); if (!rmqs) { LM_ERR("no more shm memory\n"); return -1; @@ -543,7 +593,7 @@ static void destroy(void) static void rmq_free(evi_reply_sock *sock) { - rmq_send_t *rmqs = shm_malloc(sizeof(rmq_send_t *) + 1); + rmq_send_t *rmqs = shm_malloc(sizeof(rmq_send_t) + 1); if (!rmqs) { LM_ERR("no more shm memory\n"); goto destroy; @@ -557,6 +607,9 @@ static void rmq_free(evi_reply_sock *sock) } return; destroy: + if (rmqs) + shm_free(rmqs); rmq_destroy(sock); } + diff --git a/modules/event_rabbitmq/event_rabbitmq.h b/modules/event_rabbitmq/event_rabbitmq.h index 72d7c58a867..af9c9cd5090 100644 --- a/modules/event_rabbitmq/event_rabbitmq.h +++ b/modules/event_rabbitmq/event_rabbitmq.h @@ -29,6 +29,11 @@ #include #include +#if defined AMQP_VERSION && AMQP_VERSION >= 0x00040000 + #define AMQP_VERSION_v04 +#include +#endif + /* transport protocols name */ #define RMQ_NAME "rabbitmq" @@ -45,7 +50,7 @@ #define PARAM_SEP '\n' #define QUOTE_C '"' #define ESC_C '\\' -#define ATTR_SEP_S "::" +#define ATTR_SEP_S "::" #define ATTR_SEP_LEN (sizeof(ATTR_SEP_S) - 1) #define RMQ_DEFAULT_UP "guest" @@ -54,20 +59,23 @@ #define RMQ_DEFAULT_VHOST "/" #define RMQ_DEFAULT_PORT 5672 -#define RMQ_PARAM_EXCH (1 << 1) +#define RMQ_PARAM_RKEY (1 << 1) #define RMQ_PARAM_CONN (1 << 2) #define RMQ_PARAM_CHAN (1 << 3) #define RMQ_PARAM_USER (1 << 4) #define RMQ_PARAM_PASS (1 << 5) +#define RMQ_PARAM_EKEY (1 << 6) typedef struct _rmq_params { + str routing_key; str exchange; str user; str pass; amqp_connection_state_t conn; - int sock; int channel; int flags; + int heartbeat; } rmq_params_t; #endif + diff --git a/modules/event_rabbitmq/rabbitmq_send.c b/modules/event_rabbitmq/rabbitmq_send.c index 2f0daadb129..a2cd9a1ed95 100644 --- a/modules/event_rabbitmq/rabbitmq_send.c +++ b/modules/event_rabbitmq/rabbitmq_send.c @@ -33,6 +33,13 @@ #define RMQ_SIZE (sizeof(rmq_send_t *)) #define IS_ERR(_err) (errno == _err) +#ifdef HAVE_SCHED_YIELD +#include +#else +#include +/** Fake sched_yield if no unistd.h include is available */ + #define sched_yield() sleep(0) +#endif /* used to communicate with the sending process */ static int rmq_pipe[2]; @@ -70,8 +77,8 @@ int rmq_send(rmq_send_t* rmqs) do { rc = write(rmq_pipe[1], &rmqs, RMQ_SIZE); - } while ((rc < 0 && (IS_ERR(EINTR)||IS_ERR(EAGAIN)||IS_ERR(EWOULDBLOCK))) - || retries-- > 0); + } while (rc < 0 && ((IS_ERR(EINTR)||IS_ERR(EAGAIN)||IS_ERR(EWOULDBLOCK)) + || retries-- > 0)); if (rc < 0) { LM_ERR("unable to send rmq send struct to worker\n"); @@ -93,7 +100,7 @@ static rmq_send_t * rmq_receive(void) do { rc = read(rmq_pipe[0], &recv, RMQ_SIZE); - } while ((rc < 0 && IS_ERR(EINTR)) || retries-- > 0); + } while (rc < 0 && (IS_ERR(EINTR) || retries-- > 0)); if (rc < 0) { LM_ERR("cannot receive send param\n"); @@ -190,8 +197,8 @@ void rmq_free_param(rmq_params_t *rmqp) if ((rmqp->flags & RMQ_PARAM_PASS) && rmqp->pass.s && rmqp->pass.s != (char *)RMQ_DEFAULT_UP) shm_free(rmqp->pass.s); - if ((rmqp->flags & RMQ_PARAM_EXCH) && rmqp->exchange.s) - shm_free(rmqp->exchange.s); + if ((rmqp->flags & RMQ_PARAM_RKEY) && rmqp->routing_key.s) + shm_free(rmqp->routing_key.s); } @@ -231,12 +238,15 @@ void rmq_destroy(evi_reply_sock *sock) static int rmq_reconnect(evi_reply_sock *sock) { rmq_params_t * rmqp = (rmq_params_t *)sock->params; +#if defined AMQP_VERSION_v04 + amqp_socket_t *amqp_sock; +#endif + int socket; - if (!rmqp || !(rmqp->flags & RMQ_PARAM_EXCH)) { + if (!rmqp || !(rmqp->flags & RMQ_PARAM_RKEY)) { LM_ERR("not enough socket info\n"); return -1; } -// rmq_print(sock); if (!(rmqp->flags & RMQ_PARAM_CONN) || !rmqp->conn) { /* init new connection */ if (!(rmqp->conn = amqp_new_connection())) { @@ -244,18 +254,32 @@ static int rmq_reconnect(evi_reply_sock *sock) return -1; } rmqp->flags |= RMQ_PARAM_CONN; - rmqp->sock = amqp_open_socket(sock->address.s, sock->port); - if (rmqp->sock < 0) { - LM_ERR("cannot opens socket\n"); +#if defined AMQP_VERSION_v04 + amqp_sock = amqp_tcp_socket_new(rmqp->conn); + if (!amqp_sock) { + LM_ERR("cannot create AMQP socket\n"); + goto destroy_rmqp; + } + socket = amqp_socket_open(amqp_sock, sock->address.s, sock->port); + if (socket < 0) { + LM_ERR("cannot open AMQP socket\n"); + goto destroy_rmqp; + } +#else + socket = amqp_open_socket(sock->address.s, sock->port); + if (socket < 0) { + LM_ERR("cannot open AMQP socket\n"); goto destroy_rmqp; } - amqp_set_sockfd(rmqp->conn, rmqp->sock); + amqp_set_sockfd(rmqp->conn, socket); +#endif - if (rmq_error("Logging in", amqp_login(rmqp->conn, + if (rmq_error("Logging in", amqp_login( + rmqp->conn, RMQ_DEFAULT_VHOST, 0, RMQ_DEFAULT_MAX, - 0, + rmqp->heartbeat, AMQP_SASL_METHOD_PLAIN, rmqp->flags & RMQ_PARAM_USER ? rmqp->user.s : RMQ_DEFAULT_UP, rmqp->flags & RMQ_PARAM_PASS ? rmqp->pass.s : RMQ_DEFAULT_UP))) @@ -274,20 +298,82 @@ static int rmq_reconnect(evi_reply_sock *sock) return -1; } +#ifdef AMQP_VERSION_v04 +static inline int amqp_check_status(rmq_params_t *rmqp, int r) +{ + switch (r) { + case AMQP_STATUS_OK: + return 0; + + case AMQP_STATUS_NO_MEMORY: + LM_ERR("no more memory\n"); + goto no_close; + + case AMQP_STATUS_TABLE_TOO_BIG: + LM_ERR("A table in the properties was too large to fit in a single frame\n"); + goto no_close; + + case AMQP_STATUS_HEARTBEAT_TIMEOUT: + LM_ERR("heartbeat timeout\n"); + break; + + case AMQP_STATUS_CONNECTION_CLOSED: + LM_ERR("Connection closed\n"); + break; + + /* this should not happend since we do not use ssl */ + case AMQP_STATUS_SSL_ERROR: + LM_ERR("SSL error\n"); + break; + + case AMQP_STATUS_TCP_ERROR: + LM_ERR("TCP error: %s(%d)\n", strerror(errno), errno); + break; + + default: + LM_ERR("Unknown error: %s(%d)\n", strerror(errno), errno); + break; + } + /* we close the connection here to be able to re-connect later */ + rmq_destroy_param(rmqp); +no_close: + return r; +} +#else +static inline int amqp_check_status(rmq_params_t *rmqp, int r) +{ + if (r != 0) { + LM_ERR("Unknown error while sending\n"); + /* we close the connection here to be able to re-connect later */ + rmq_destroy_param(rmqp); + return -1; + } + return 0; +} +#endif + /* sends the buffer */ static int rmq_sendmsg(rmq_send_t *rmqs) { rmq_params_t * rmqp = (rmq_params_t *)rmqs->sock->params; + int ret; + if (!(rmqp->flags & RMQ_PARAM_CONN)) + return 0; + /* all checks should be already done */ - return amqp_basic_publish(rmqp->conn, + ret = amqp_basic_publish(rmqp->conn, rmqp->channel, - AMQP_EMPTY_BYTES, - amqp_cstring_bytes(rmqp->exchange.s), + rmqp->flags&RMQ_PARAM_EKEY? + amqp_cstring_bytes(rmqp->exchange.s) : + AMQP_EMPTY_BYTES , + amqp_cstring_bytes(rmqp->routing_key.s), 0, 0, 0, amqp_cstring_bytes(rmqs->msg)); + + return amqp_check_status(rmqp, ret); } void rmq_process(int rank) @@ -323,3 +409,4 @@ void rmq_process(int rank) shm_free(rmqs); } } + diff --git a/modules/event_rabbitmq/rabbitmq_send.h b/modules/event_rabbitmq/rabbitmq_send.h index b9f5abd11f2..a9ea898f350 100644 --- a/modules/event_rabbitmq/rabbitmq_send.h +++ b/modules/event_rabbitmq/rabbitmq_send.h @@ -45,3 +45,4 @@ void rmq_free_param(rmq_params_t *rmqp); void rmq_destroy(evi_reply_sock *sock); #endif + diff --git a/modules/event_route/README b/modules/event_route/README index 340a6f21552..b2eb8ff3c70 100644 --- a/modules/event_route/README +++ b/modules/event_route/README @@ -8,6 +8,10 @@ Edited by Razvan Crainea +Edited by + +Ovidiu Sas + Copyright © 2012 www.opensips-solutions.com __________________________________________________________ @@ -26,7 +30,7 @@ Razvan Crainea 1.6. Exported Parameters - 1.6.1. + 1.6.1. synch_mode (integer) 1.7. Exported Functions @@ -37,7 +41,8 @@ Razvan Crainea List of Examples 1.1. EVENT_ROUTE usage - 1.2. fetch_event_params usage + 1.2. Set synch_mode parameter + 1.3. fetch_event_params usage Chapter 1. Admin Guide @@ -62,10 +67,9 @@ Chapter 1. Admin Guide [ param_name= ] pvar [; [ param_name= ] pvar ]* Example: - - fetch_even_params("$avp(first_param)"); - fetch_even_params("ip=$avp(pike_ip)"); - fetch_even_params("source=$avp(src);destination=$avp(dst)"); +fetch_event_params("$avp(first_param)"); +fetch_event_params("ip=$avp(pike_ip)"); +fetch_event_params("source=$avp(src);destination=$avp(dst)"); If the name of the parameter is not specified, the avp will be populated according to the order of the parameters, as exported @@ -120,8 +124,18 @@ Chapter 1. Admin Guide 1.6. Exported Parameters - No parameter exported by this module. This module doesn't - export any parameter +1.6.1. synch_mode (integer) + + Sets the default event handling method: + * 0 : handle events in asynch mode (in a dedicated process) + * 1 : handle events in synch mode (in the same process) + + Default value is 1. + + Example 1.2. Set synch_mode parameter +... +modparam("event_route", "synch_mode", 0) +... 1.7. Exported Functions @@ -135,51 +149,51 @@ Chapter 1. Admin Guide This function can be used from REQUEST_ROUTE and EVENT_ROUTE. - Example 1.2. fetch_event_params usage + Example 1.3. fetch_event_params usage ... -fetch_even_params("$avp(first_param)"); # fetch the first parameter of a -n event -fetch_even_params("ip=$avp(pike_ip)"); # fetch the ip parameter -fetch_even_params("source=$avp(src);destination=$avp(dst)"); # fetch the - source and destination parameters +fetch_event_params("$avp(first_param)"); # fetch the first parameter of + an event +fetch_event_params("ip=$avp(pike_ip)"); # fetch the ip parameter +fetch_event_params("source=$avp(src);destination=$avp(dst)"); # fetch t +he source and destination parameters ... Chapter 2. Frequently Asked Questions 2.1. - Can I declare more routes for handling the same event? + Can I declare more routes for handling the same event? - No, only a single event_route can be used for a particular - event. + No, only a single event_route can be used for a particular + event. 2.2. - Where can I find more about OpenSIPS? + Where can I find more about OpenSIPS? - Take a look at http://www.opensips.org/. + Take a look at http://www.opensips.org/. 2.3. - Where can I post a question about this module? + Where can I post a question about this module? - First at all check if your question was already answered on one - of our mailing lists: - * User Mailing List - - http://lists.opensips.org/cgi-bin/mailman/listinfo/users - * Developer Mailing List - - http://lists.opensips.org/cgi-bin/mailman/listinfo/devel + First at all check if your question was already answered on one + of our mailing lists: + * User Mailing List - + http://lists.opensips.org/cgi-bin/mailman/listinfo/users + * Developer Mailing List - + http://lists.opensips.org/cgi-bin/mailman/listinfo/devel - E-mails regarding any stable OpenSIPS release should be sent to - and e-mails regarding development - versions should be sent to . + E-mails regarding any stable OpenSIPS release should be sent to + and e-mails regarding development + versions should be sent to . - If you want to keep the mail private, send it to - . + If you want to keep the mail private, send it to + . 2.4. - How can I report a bug? + How can I report a bug? - Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + Please follow the guidelines provided at: + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/event_route/doc/event_route.xml b/modules/event_route/doc/event_route.xml index 9cd0fdc6643..8e0eef0d73e 100644 --- a/modules/event_route/doc/event_route.xml +++ b/modules/event_route/doc/event_route.xml @@ -31,9 +31,12 @@ Razvan Crainea -
- razvancrainea@opensips.org -
+
razvancrainea@opensips.org
+
+ + Ovidiu + Sas +
osas@voipembedded.com
diff --git a/modules/event_route/doc/event_route_admin.xml b/modules/event_route/doc/event_route_admin.xml index be48367787f..50d3eacc337 100644 --- a/modules/event_route/doc/event_route_admin.xml +++ b/modules/event_route/doc/event_route_admin.xml @@ -30,15 +30,12 @@ Example: + +fetch_event_params("$avp(first_param)"); +fetch_event_params("ip=$avp(pike_ip)"); +fetch_event_params("source=$avp(src);destination=$avp(dst)"); + - - fetch_even_params("$avp(first_param)"); - - fetch_even_params("ip=$avp(pike_ip)"); - - fetch_even_params("source=$avp(src);destination=$avp(dst)"); - - If the name of the parameter is not specified, the avp will be populated according to the order of the parameters, as exported by the event. The following code will populate the $avp(first) avp @@ -128,10 +125,27 @@
Exported Parameters
+ <varname>synch_mode</varname> (integer) - No parameter exported by this module. - This module doesn't export any parameter + Sets the default event handling method: + + + 0 : handle events in asynch mode (in a dedicated process) + + + 1 : handle events in synch mode (in the same process) + + + Default value is 1. + + Set <varname>synch_mode</varname> parameter + +... +modparam("event_route", "synch_mode", 0) +... + +
@@ -156,9 +170,9 @@ <function>fetch_event_params</function> usage ... -fetch_even_params("$avp(first_param)"); # fetch the first parameter of an event -fetch_even_params("ip=$avp(pike_ip)"); # fetch the ip parameter -fetch_even_params("source=$avp(src);destination=$avp(dst)"); # fetch the source and destination parameters +fetch_event_params("$avp(first_param)"); # fetch the first parameter of an event +fetch_event_params("ip=$avp(pike_ip)"); # fetch the ip parameter +fetch_event_params("source=$avp(src);destination=$avp(dst)"); # fetch the source and destination parameters ... diff --git a/modules/event_route/event_route.c b/modules/event_route/event_route.c index a6ba673db55..6592736bb64 100644 --- a/modules/event_route/event_route.c +++ b/modules/event_route/event_route.c @@ -28,6 +28,7 @@ #include "../../evi/evi_modules.h" #include "../../ut.h" #include "event_route.h" +#include "route_send.h" #include #include #include @@ -38,10 +39,13 @@ * module functions */ static int mod_init(void); +static void destroy(void); static int child_init(int rank); static int scriptroute_fetch(struct sip_msg *msg, char *list); static int fixup_scriptroute_fetch(void **param, int param_no); +static int synch_mode = 1; + /** * exported functions */ @@ -53,6 +57,13 @@ static str scriptroute_print(evi_reply_sock *sock); #define SR_SOCK_ROUTE(_s) ((int)(unsigned long)(_s->params)) +/** + * * module process + * */ +static proc_export_t procs[] = { + {"event-route handler", 0, 0, event_route_handler, 1, 0}, + {0,0,0,0,0,0} +}; /** * module exported functions */ @@ -62,29 +73,35 @@ static cmd_export_t cmds[]={ {0,0,0,0,0,0} }; +static param_export_t params[] = { + {"synch_mode", INT_PARAM, &synch_mode}, + {0, 0, 0} +}; /** * module exports */ struct module_exports exports= { "event_route", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ - 0, /* exported parameters */ + params, /* exported parameters */ 0, /* exported statistics */ 0, /* exported MI functions */ 0, /* exported pseudo-variables */ - 0, /* extra processes */ + procs, /* extra processes */ mod_init, /* module initialization function */ 0, /* response handling function */ - 0, /* destroy function */ + destroy, /* destroy function */ child_init /* per-child init function */ }; /** - * exported functions for core event interface + * exported functions for core event interface */ static evi_export_t trans_export_scriptroute = { SCRIPTROUTE_NAME_STR, /* transport module name */ @@ -107,9 +124,29 @@ static int mod_init(void) LM_ERR("cannot register transport functions for SCRIPTROUTE\n"); return -1; } + + if (synch_mode) { + exports.procs = 0; + } else if (create_pipe() < 0) { + LM_ERR("cannot create communication pipe\n"); + return -1; + } + return 0; } +/* + * destroy function + */ +static void destroy(void) +{ + LM_NOTICE("destroy module ...\n"); + /* closing sockets */ + if (!synch_mode) + destroy_pipe(); +} + + static int child_init(int rank) { char buffer[EV_SCRIPTROUTE_MAX_SOCK]; @@ -117,6 +154,11 @@ static int child_init(int rank) str event_name; int idx; + if (!synch_mode && init_writer() < 0) { + LM_ERR("cannot init writing pipe\n"); + return -1; + } + /* * Only the first process registers the subscribers * @@ -153,7 +195,7 @@ static int child_init(int rank) } memcpy(buffer + sizeof(SCRIPTROUTE_NAME), event_name.s, event_name.len); sock_name.len = event_name.len + sizeof(SCRIPTROUTE_NAME); - + /* register the subscriber - does not expire */ if (evi_event_subscribe(event_name, sock_name, 0, 0) < 0) { LM_ERR("cannot subscribe to event %s\n", event_name.s); @@ -232,7 +274,7 @@ static str scriptroute_print(evi_reply_sock *sock) } /* static parameters list retrieved by the fetch_event_params */ -static evi_params_t *parameters = NULL; +evi_params_t *parameters = NULL; str *event_name = NULL; // mostly used for debugging static int scriptroute_raise(struct sip_msg *msg, str* ev_name, @@ -240,6 +282,7 @@ static int scriptroute_raise(struct sip_msg *msg, str* ev_name, { evi_params_t * backup_params; str * backup_name; + route_send_t *buf = NULL; if (!sock || !(sock->flags & EVI_PARAMS)) { LM_ERR("no socket found\n"); @@ -252,18 +295,25 @@ static int scriptroute_raise(struct sip_msg *msg, str* ev_name, return -1; } - /* save the previous parameters */ - backup_params = parameters; - backup_name = ev_name; + if (synch_mode) { + /* save the previous parameters */ + backup_params = parameters; + backup_name = event_name; - parameters = params; - event_name = ev_name; + parameters = params; + event_name = ev_name; - run_top_route(event_rlist[SR_SOCK_ROUTE(sock)].a, msg); + run_top_route(event_rlist[SR_SOCK_ROUTE(sock)].a, msg); - /* restore previous parameters */ - parameters = backup_params; - event_name = backup_name; + /* restore previous parameters */ + parameters = backup_params; + event_name = backup_name; + } else { + if (route_build_buffer(ev_name, sock, params, &buf) < 0) return -1; + buf->a = event_rlist[SR_SOCK_ROUTE(sock)].a; + + if (route_send(buf) < 0) return -1; + } return 0; } @@ -298,7 +348,7 @@ static int scriptroute_add_param(struct sip_msg *msg, break; } if (!it) { - LM_WARN("Parameter <%.*s> not found for event <%.*s>\n", + LM_WARN("Parameter <%.*s> not found for event <%.*s>\n", param->name.len, param->name.s, event_name->len, event_name->s); return 0; @@ -402,7 +452,7 @@ static int fixup_scriptroute_fetch(void **param, int param_no) name.len = e - s.s; trim_spaces_lr(name); if (name.len <= 0) { - LM_WARN("No name specified near <%.*s>\n", + LM_WARN("No name specified near <%.*s>\n", (int)(p - s.s), s.s); goto next; } @@ -410,7 +460,7 @@ static int fixup_scriptroute_fetch(void **param, int param_no) s.len = p - s.s; trim_spaces_lr(s); if (s.len <= 0) { - LM_WARN("No pvar specified near %.*s\n", + LM_WARN("No pvar specified near %.*s\n", (int)(p - s.s), s.s); goto next; } diff --git a/modules/event_route/event_route.h b/modules/event_route/event_route.h index 6815281f948..a172e0eaab1 100644 --- a/modules/event_route/event_route.h +++ b/modules/event_route/event_route.h @@ -27,6 +27,9 @@ #ifndef _EV_ROUTE_H_ #define _EV_ROUTE_H_ + +void event_route_handler(int rank); + /* transport protocol name */ #define SCRIPTROUTE_NAME "route" #define SCRIPTROUTE_NAME_STR { SCRIPTROUTE_NAME, sizeof(SCRIPTROUTE_NAME)-1} diff --git a/modules/event_route/route_send.c b/modules/event_route/route_send.c new file mode 100644 index 00000000000..03564f0f068 --- /dev/null +++ b/modules/event_route/route_send.c @@ -0,0 +1,275 @@ + +/* + * Copyright (C) 2014 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * history: + * --------- + * 2014-06-27 created (osas) + */ + +#include "../../evi/evi_transport.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../../ut.h" +#include "route_send.h" +#include "event_route.h" +#include +#include + +#define IS_ERR(_err) (errno == _err) + +extern evi_params_t *parameters; +extern str *event_name; + +/* used to communicate with the sending process */ +static int route_pipe[2]; + +/* creates communication pipe */ +int create_pipe(void) +{ + int rc; + + route_pipe[0] = route_pipe[1] = -1; + /* create pipe */ + do { + rc = pipe(route_pipe); + } while (rc < 0 && IS_ERR(EINTR)); + + if (rc < 0) { + LM_ERR("cannot create status pipe [%d:%s]\n", errno, strerror(errno)); + return -1; + } + return 0; +} + +void destroy_pipe(void) +{ + if (route_pipe[0] != -1) + close(route_pipe[0]); + if (route_pipe[1] != -1) + close(route_pipe[1]); +} + +int route_send(route_send_t *route_s) +{ + int rc, retries = ROUTE_SEND_RETRY; + + do { + rc = write(route_pipe[1], &route_s, sizeof(route_send_t *)); + if (rc == sizeof(route_send_t *)) + break; + } while ((rc < 0 && (IS_ERR(EINTR)||IS_ERR(EAGAIN)||IS_ERR(EWOULDBLOCK))) + || retries-- > 0); + + if (rc < 0) { + LM_ERR("unable to send route send struct to worker\n"); + return -1; + } else if (rc != sizeof(route_send_t *)){ + LM_ERR("Incomplete write [%d/%lu]\n", rc, sizeof(route_send_t *)); + return -1; + } + /* give a change to the writer :) */ + sched_yield(); + return 0; +} + +static union tmp_route_send_t { + route_send_t *ptr; + char buf[sizeof(route_send_t *)]; +} recv_buf; + +static route_send_t * route_receive(void) +{ + int rc; + int retries = ROUTE_SEND_RETRY; + int len = sizeof(route_send_t*); + int bytes_read = 0; + + if (route_pipe[0] == -1) + return NULL; + + do { + rc = read(route_pipe[0], recv_buf.buf + bytes_read, len); + if (rc > 0) { + bytes_read += rc; + len -= rc; + } else if (rc < 0 && IS_ERR(EINTR)) { + continue; + } else if (retries-- <= 0) { + break; + } + } while (len); + + if (rc < 0) { + LM_ERR("cannot receive send param\n"); + return NULL; + } + return recv_buf.ptr; +} + +int init_writer(void) +{ + int flags; + + if (route_pipe[0] != -1) { + close(route_pipe[0]); + route_pipe[0] = -1; + } + + /* Turn non-blocking mode on for sending*/ + flags = fcntl(route_pipe[1], F_GETFL); + if (flags == -1) { + LM_ERR("fcntl failed: %s\n", strerror(errno)); + goto error; + } + if (fcntl(route_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { + LM_ERR("fcntl: set non-blocking failed: %s\n", strerror(errno)); + goto error; + } + + return 0; +error: + close(route_pipe[1]); + route_pipe[1] = -1; + return -1; +} + +static void route_init_reader(void) +{ + if (route_pipe[1] != -1) { + close(route_pipe[1]); + route_pipe[1] = -1; + } +} + + +int route_build_buffer(str *event_name, evi_reply_sock *sock, + evi_params_t *params, route_send_t **msg) +{ + route_send_t *buf; + evi_param_p param, buf_param; + int len, params_len=0; + unsigned int param_no = 0; + char *s; + + len = sizeof(route_send_t) + event_name->len; + if (params) { + for (param = params->first; param; param = param->next) { + if (param->flags & EVI_INT_VAL) { + param_no++; + params_len += param->name.len; + } else if (param->flags & EVI_STR_VAL) { + param_no++; + params_len += param->name.len + param->val.s.len; + } else { + LM_ERR("FIXME: handle param=[%p]\n", param); + } + } + } + + len += sizeof(evi_params_t) + param_no*sizeof(evi_param_t) + params_len; + buf = shm_malloc(len); + if (!buf) { + LM_ERR("oom\n"); + return -1; + } + memset(buf, 0, len); + + /* First,is event */ + buf->event.s = (char*)(buf + 1); + buf->event.len = event_name->len; + memcpy(buf->event.s, event_name->s, event_name->len); + + if (params) { + buf_param = (evi_param_p)(buf->event.s + buf->event.len); + buf->params.first = buf_param; + s = (char*)(buf_param + param_no); + for (param = params->first; param; param = param->next) { + if (param->flags & EVI_INT_VAL) { + buf_param->flags = EVI_INT_VAL; + memcpy(s, param->name.s, param->name.len); + buf_param->name.s = s; + buf_param->name.len = param->name.len; + s += param->name.len; + buf_param->val.n = param->val.n; + buf_param->next = buf_param + 1; + buf_param++; + } else if (param->flags & EVI_STR_VAL) { + buf_param->flags = EVI_STR_VAL; + memcpy(s, param->name.s, param->name.len); + buf_param->name.s = s; + buf_param->name.len = param->name.len; + s += param->name.len; + memcpy(s, param->val.s.s, param->val.s.len); + buf_param->val.s.s = s; + buf_param->val.s.len = param->val.s.len; + s += param->val.s.len; + buf_param->next = buf_param + 1; + buf_param++; + } else { + LM_ERR("FIXME: handle param=[%p]\n", param); + } + } + buf_param--; + buf_param->next = NULL; + buf->params.last = buf_param; + } + + *msg = buf; + return 0; +} + + +void event_route_handler(int rank) +{ + /* init blocking reader */ + route_init_reader(); + route_send_t *route_s; + struct sip_msg* dummy_req; + + dummy_req = (struct sip_msg*)pkg_malloc(sizeof(struct sip_msg)); + if (dummy_req == NULL) { + LM_ERR("oom\n"); + return; + } + memset(dummy_req, 0, sizeof(struct sip_msg)); + dummy_req->first_line.type = SIP_REQUEST; + dummy_req->first_line.u.request.method.s= "DUMMY"; + dummy_req->first_line.u.request.method.len= 5; + dummy_req->first_line.u.request.uri.s= "sip:user@domain.com"; + dummy_req->first_line.u.request.uri.len= 19; + + + /* waiting for commands */ + for (;;) { + route_s = route_receive(); + if (!route_s) { + LM_ERR("invalid receive sock info\n"); + goto end; + } + + event_name = &route_s->event; + parameters = &route_s->params; + run_top_route(route_s->a, dummy_req); +end: + if (route_s) + shm_free(route_s); + } +} diff --git a/modules/event_route/route_send.h b/modules/event_route/route_send.h new file mode 100644 index 00000000000..5ba6bd2c9f4 --- /dev/null +++ b/modules/event_route/route_send.h @@ -0,0 +1,48 @@ + +/* + * Copyright (C) 2014 VoIP Embedded, Inc. + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * history: + * --------- + * 2014-06-27 created (osas) + */ + + +#ifndef _ROUTE_SEND_H_ +#define _ROUTE_SEND_H_ + + +#define ROUTE_SEND_RETRY 3 + +typedef struct _route_send { + struct action *a; + str event; + evi_params_t params; +} route_send_t; + +int create_pipe(void); +void destroy_pipe(void); +int init_writer(void); + +int route_build_buffer(str *event_name, evi_reply_sock *sock, + evi_params_t *params, route_send_t **msg); +int route_send(route_send_t *route_s); + +#endif diff --git a/modules/event_xmlrpc/README b/modules/event_xmlrpc/README index d855bb58558..a767bae5b2e 100644 --- a/modules/event_xmlrpc/README +++ b/modules/event_xmlrpc/README @@ -23,13 +23,17 @@ Razvan Crainea 1.3.2. External Libraries or Applications 1.4. Exported Parameters + + 1.4.1. use_struct_param (integer) + 1.5. Exported Functions 1.6. Example List of Examples - 1.1. E_PIKE_BLOCKED event - 1.2. XMLRPC socket + 1.1. Set use_struct_param parameter + 1.2. E_PIKE_BLOCKED event + 1.3. XMLRPC socket Chapter 1. Admin Guide @@ -78,7 +82,20 @@ Chapter 1. Admin Guide 1.4. Exported Parameters - No parameter exported by this module. +1.4.1. use_struct_param (integer) + + When raising an event, pack the name and value of the + parameters in a XMLRPC structure. This provides an easier way + for some XMLRPC server implementations to interpret the + parameters. Set it to zero to disable or to non-zero to enable + it. + + Default value is “0 (disabled)”. + + Example 1.1. Set use_struct_param parameter +... +modparam("event_xmlrpc", "use_struct_param", 1) +... 1.5. Exported Functions @@ -89,7 +106,7 @@ Chapter 1. Admin Guide This is an example of an event raised by the pike module when it decides an ip should be blocked: - Example 1.1. E_PIKE_BLOCKED event + Example 1.2. E_PIKE_BLOCKED event POST /RPC2 HTTP/1.1. @@ -114,7 +131,7 @@ Content-length: 240. - Example 1.2. XMLRPC socket + Example 1.3. XMLRPC socket # calls the 'block_ip' function xmlrpc:127.0.0.1:8080:block_ip diff --git a/modules/event_xmlrpc/doc/event_xmlrpc_admin.xml b/modules/event_xmlrpc/doc/event_xmlrpc_admin.xml index e00a274bcde..6bc857fb971 100644 --- a/modules/event_xmlrpc/doc/event_xmlrpc_admin.xml +++ b/modules/event_xmlrpc/doc/event_xmlrpc_admin.xml @@ -88,9 +88,29 @@
Exported Parameters +
+ <varname>use_struct_param</varname> (integer) + + When raising an event, pack the name and value of the + parameters in a XMLRPC structure. This provides an easier + way for some XMLRPC server implementations to interpret + the parameters. + Set it to zero to disable or to non-zero to enable it. + - No parameter exported by this module. + + Default value is 0 (disabled). + + + Set <varname>use_struct_param</varname> parameter + +... +modparam("event_xmlrpc", "use_struct_param", 1) +... + + +
diff --git a/modules/event_xmlrpc/event_xmlrpc.c b/modules/event_xmlrpc/event_xmlrpc.c index f577b530380..caa26f22988 100644 --- a/modules/event_xmlrpc/event_xmlrpc.c +++ b/modules/event_xmlrpc/event_xmlrpc.c @@ -1,3 +1,28 @@ +/* + * Copyright (C) 2012 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * history: + * --------- + * 2012-05-xx created (razvancrainea) + */ + #include "../../sr_module.h" #include "../../resolve.h" #include "../../evi/evi_transport.h" @@ -9,6 +34,8 @@ #include #include +extern unsigned xmlrpc_struct_on; + /** * module functions */ @@ -33,15 +60,24 @@ static proc_export_t procs[] = { {0,0,0,0,0,0} }; +/* module parameters */ +static param_export_t mod_params[] = { + {"use_struct_param", INT_PARAM, &xmlrpc_struct_on}, + {0,0,0} +}; + + /** * module exports */ struct module_exports exports= { "event_xmlrpc", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ - 0, /* exported parameters */ + mod_params, /* exported parameters */ 0, /* exported statistics */ 0, /* exported MI functions */ 0, /* exported pseudo-variables */ @@ -54,7 +90,7 @@ struct module_exports exports= { /** - * exported functions for core event interface + * exported functions for core event interface */ static evi_export_t trans_export_xmlrpc = { XMLRPC_STR, /* transport module name */ @@ -153,7 +189,7 @@ static evi_reply_sock* xmlrpc_parse(str socket) LM_DBG("host is %.*s - remains <%.*s>[%d]\n", host.len, host.s, socket.len, socket.s, socket.len); - + if (!socket.len || *socket.s == '\0') { LM_ERR("invalid port number\n"); return NULL; @@ -181,10 +217,10 @@ static evi_reply_sock* xmlrpc_parse(str socket) LM_ERR("invalid method name\n"); return NULL; } - + LM_DBG("method is %.*s[%d]\n", socket.len, socket.s, socket.len); - len = sizeof(evi_reply_sock) - sizeof(void*) + sizeof(str) + + len = sizeof(evi_reply_sock) - sizeof(void*) + sizeof(str) + host.len + socket.len; sock = shm_malloc(len); if (!sock) { @@ -262,8 +298,6 @@ static str xmlrpc_print(evi_reply_sock *sock) goto end; } - DO_PRINT("xmlrpc:", 7); - if (sock->flags & EVI_ADDRESS) DO_PRINT(sock->address.s, sock->address.len); @@ -272,7 +306,7 @@ static str xmlrpc_print(evi_reply_sock *sock) aux.s = int2str(sock->port, &aux.len); DO_PRINT(aux.s, aux.len); } - + if (sock->flags & EVI_PARAMS) { DO_PRINT(":", 1); method = (str *) &sock->params; diff --git a/modules/event_xmlrpc/event_xmlrpc.h b/modules/event_xmlrpc/event_xmlrpc.h index c488fb0562f..007116b375c 100644 --- a/modules/event_xmlrpc/event_xmlrpc.h +++ b/modules/event_xmlrpc/event_xmlrpc.h @@ -1,3 +1,27 @@ +/* + * Copyright (C) 2012 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * history: + * --------- + * 2012-05-xx created (razvancrainea) + */ #ifndef _EV_XMLRPC_H_ #define _EV_XMLRPC_H_ diff --git a/modules/event_xmlrpc/xmlrpc_send.c b/modules/event_xmlrpc/xmlrpc_send.c index c25096bcbc7..c652df76240 100644 --- a/modules/event_xmlrpc/xmlrpc_send.c +++ b/modules/event_xmlrpc/xmlrpc_send.c @@ -34,6 +34,7 @@ #define IS_ERR(_err) (errno == _err) +unsigned xmlrpc_struct_on = 0; static char * xmlrpc_body_buf = 0; static struct iovec xmlrpc_iov[XMLRPC_IOVEC_MAX_SIZE]; static unsigned xmlrpc_iov_len = 0; @@ -162,7 +163,7 @@ static int xmlrpc_sendmsg(xmlrpc_send_t *sock) { unsigned long i, len = 0; int fd, ret = -1; - int aux; + int *aux; /* host */ xmlrpc_iov[xmlrpc_host_index].iov_base = sock->host.s; @@ -182,10 +183,10 @@ static int xmlrpc_sendmsg(xmlrpc_send_t *sock) /* now compute content length */ for (i = xmlrpc_xmlbody_index; i < xmlrpc_iov_len; i++) - len += xmlrpc_iov[i].iov_len; + len += xmlrpc_iov[i].iov_len; - aux = (int)xmlrpc_iov[xmlrpc_ct_len_index].iov_len; - xmlrpc_iov[xmlrpc_ct_len_index].iov_base = int2str(len, &aux); + aux = (int *)&xmlrpc_iov[xmlrpc_ct_len_index].iov_len; + xmlrpc_iov[xmlrpc_ct_len_index].iov_base = int2str(len, aux); /* writing the iov on the network */ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { @@ -290,13 +291,21 @@ int xmlrpc_build_buffer(str *event_name, evi_reply_sock *sock, b += (_l); \ } while (0) - + if (params) { for (param = params->first; param; param = param->next) { /* '' */ COPY_STR(START_TAG(XMLRPC_PARAM), LENOF(START_TAG(XMLRPC_PARAM))); if (param->name.len && param->name.s) { + if (xmlrpc_struct_on) { + COPY_STR(START_TAG(XMLRPC_VALUE), + LENOF(START_TAG(XMLRPC_VALUE)) - 1); + COPY_STR(START_TAG(XMLRPC_STRUCT), + LENOF(START_TAG(XMLRPC_STRUCT)) - 1); + COPY_STR(START_TAG(XMLRPC_MEMBER), + LENOF(START_TAG(XMLRPC_MEMBER))); + } LM_DBG("adding parameter %.*s\n", param->name.len, param->name.s); /* */ @@ -339,6 +348,16 @@ int xmlrpc_build_buffer(str *event_name, evi_reply_sock *sock, } COPY_STR(END_TAG(XMLRPC_VALUE), LENOF(END_TAG(XMLRPC_VALUE))); + + if (param->name.len && param->name.s && + xmlrpc_struct_on) { + COPY_STR(END_TAG(XMLRPC_MEMBER), + LENOF(END_TAG(XMLRPC_MEMBER)) - 1); + COPY_STR(END_TAG(XMLRPC_STRUCT), + LENOF(END_TAG(XMLRPC_STRUCT)) - 1); + COPY_STR(END_TAG(XMLRPC_VALUE), + LENOF(END_TAG(XMLRPC_VALUE))); + } COPY_STR(END_TAG(XMLRPC_PARAM), LENOF(END_TAG(XMLRPC_PARAM))); } diff --git a/modules/event_xmlrpc/xmlrpc_send.h b/modules/event_xmlrpc/xmlrpc_send.h index 9e2c530497e..4231da2bac8 100644 --- a/modules/event_xmlrpc/xmlrpc_send.h +++ b/modules/event_xmlrpc/xmlrpc_send.h @@ -70,6 +70,8 @@ int xmlrpc_build_buffer(str *, #define XMLRPC_METHOD_CALL "methodCall" #define XMLRPC_METHOD_NAME "methodName" +#define XMLRPC_STRUCT "struct" +#define XMLRPC_MEMBER "member" #define XMLRPC_PARAMS "params" #define XMLRPC_PARAM "param" #define XMLRPC_ATTR "name" diff --git a/modules/exec/README b/modules/exec/README index 63f92263d12..48f73ae22d9 100644 --- a/modules/exec/README +++ b/modules/exec/README @@ -10,8 +10,7 @@ Jan Janak Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -34,8 +33,8 @@ Jan Janak 1.4.1. exec_dset(command) 1.4.2. exec_msg(command) - 1.4.3. exec_avp(command [, avplist]) - 1.4.4. exec_getenv(environment_variable [, avp]) + 1.4.3. exec_avp(command[, avplist]) + 1.4.4. exec_getenv(environment_variable[, avp]) 1.5. Known Issues @@ -53,11 +52,11 @@ Chapter 1. Admin Guide 1.1. Overview - Exec module allows to start an external command from a OpenSIPS - script. The commands may be any valid shell commands--the - command string is passed to shell using “popen” command. - OpenSIPS passes additionally lot of information about request - in environment variables: + The Exec module enables the execution of external commands from + the OpenSIPS script. Any valid shell commands are accepted. The + final input string is evaluated and executed using the + "/bin/sh" symlink/binary. OpenSIPS may additionally pass a lot + more information about the request using environment variables: * SIP_HF_ contains value of each header field in request. If a header field occurred multiple times, values are concatenated and comma-separated. is in @@ -75,10 +74,10 @@ Chapter 1. Admin Guide * SIP_USER is userpart of current request URI. * SIP_OUSER is userpart of original request URI. - NOTE: The envirnment variables must be specified with double $ - (e.g., $$SIP_OUSER) in the parameters given to exec functions. - Otherwise they will be evaluated as OpenSIPS pseudo-variables, - throwing errors. + NOTE: Any environment variables which are given to the exec + module functions must be specified using the '$$' delimiter + (e.g., $$SIP_OUSER), otherwise they will be evaluated as + OpenSIPS pseudo-variables, throwing scripting errors. 1.2. Dependencies @@ -112,7 +111,7 @@ modparam("exec", "setvars", 1) Specifies the longest time a program is allowed to execute. If the time is exceeded, the program is killed. - Default value is 0. + Default value is 0 (disabled). Example 1.2. Set “time_to_kill” parameter ... @@ -121,11 +120,11 @@ modparam("exec", "time_to_kill", 20) 1.3.3. async (integer) - Turns on the asynchronous mode for 'exec_msg' function. All + Turns on the asynchronous mode for the 'exec_msg' function. All commands will be executed by a different process and the caller - will continue it's flow, without waiting for a response. + will continue its flow, without waiting for a response. - Default value is 0. + Default value is 0 (disabled). Example 1.3. Set “async” parameter ... @@ -136,103 +135,119 @@ modparam("exec", "async", 1) 1.4.1. exec_dset(command) - Executes an external command. Current URI is passed to the - command as parameter. Output of the command is considered URI - set (separated by lines). + Executes an external command. The current R-URI is appended to + the command as its last parameter. The output of the command + will rewrite the current R-URI. Multiple lines of output lead + to multiple branches. Meaning of the parameters is as follows: - * command - Command to be executed. It can include pseudo- - variabes; + * command (string, pvar) - command to be executed. It can + include pseudo-variables or '$$' delimited UNIX environment + variables - WARNING: if the var you are passing out has a bash special - character in it, the var needs to be placed inside quotes, for - ex: exec_dset("print-contact.sh '$ct'"); + WARNING: most OpenSIPS scripting variables should be quoted + before being passed to external commands, as in: + exec_avp("log-call.sh '$ct'"). This may help avoid some + unexpected behaviour (e.g. unwanted extra parameters, errors + due to special bash characters, etc.) This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. Example 1.4. exec_dset usage ... -exec_dset("echo TEST > /tmp/test.txt"); -exec_dset("echo TEST > /tmp/$rU.txt"); +exec_dset("ruri-changer.sh"); +exec_dset("ruri-changer.sh '$ct'"); ... 1.4.2. exec_msg(command) - Executes an external command. The whole message is passed to it - in input, no command-line parameters are added, output of the - command is not processed. + Executes an external command. The current SIP message is passed + to it in the standard input, no command-line parameters are + added and the output of the command is ignored. See sip-server/modules/exec/etc/exec.cfg in the source tarball for information on usage. Meaning of the parameters is as follows: - * command - Command to be executed. It can include - pseudo-variables. + * command (string) - command to be executed. It can include + pseudo-variables or '$$' delimited UNIX environment + variables - WARNING: if the var you are passing out has a bash special - character in it, the var needs to be placed inside quotes, for - ex: exec_msg("print-contact.sh '$ct'"); + WARNING: most OpenSIPS scripting variables should be quoted + before being passed to external commands, as in: + exec_avp("log-call.sh '$ct'"). This may help avoid some + unexpected behaviour (e.g. unwanted extra parameters, errors + due to special bash characters, etc.) - This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, + LOCAL_ROUTE, TIMER_ROUTE, EVENT_ROUTE, ONREPLY_ROUTE. Example 1.5. exec_msg usage ... -exec_msg("echo TEST > /tmp/test.txt"); -exec_msg("echo TEST > /tmp/$rU.txt"); +exec_msg("call-logger.sh '$ct' >> /var/log/call-logger/'$rU'.calls"); ... -1.4.3. exec_avp(command [, avplist]) +1.4.3. exec_avp(command[, avplist]) - Executes an external command. Each line from output of the - command is saved in an AVP from 'avplist'. If 'avplist' is - missing, the AVP are named 1, 2, 3, ... + Executes an external command. Each output line of the command + is saved in its corresponding AVP from avplist. If avplist is + missing or is incomplete, the populated AVPs will be 1, 2, 3... + or N, N+1, N+2... Meaning of the parameters is as follows: - * command - Command to be executed. It can include pseudo- - variabes; - * avplist - comma separated list with AVP names to store the - result in; - - WARNING: if the var you are passing out has a bash special - character in it, the var needs to be placed inside quotes, for - ex: exec_avp("print-contact.sh '$ct'"); + * command (string) - command to be executed. It can include + pseudo-variables or '$$' delimited UNIX environment + variables + * avplist (string) - comma separated list with AVP names to + store the result in + + WARNING: most OpenSIPS scripting variables should be quoted + before being passed to external commands, as in: + exec_avp("log-call.sh '$ct'"). This may help avoid some + unexpected behaviour (e.g. unwanted extra parameters, errors + due to special bash characters, etc.) This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, - LOCAL_ROUTE, STARTUP_ROUTE. + LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE, EVENT_ROUTE, + ONREPLY_ROUTE. Example 1.6. exec_avp usage ... -exec_avp("echo TEST"); -exec_avp("echo TEST", "$avp(test)"); +exec_avp("get-subscriber-details.sh '$rU'", "$avp(credit) $avp(contract_ +model)"); ... -1.4.4. exec_getenv(environment_variable [, avp]) +1.4.4. exec_getenv(environment_variable[, avp]) - Get the value of an evironment_variable. The value is saved in - 'avp'. If 'avp' is missing, the AVP is named 1. If there is no - such environment variable no value is returned. + Obtains the value of a UNIX evironment_variable. The value is + saved in 'avp'. If 'avp' is missing, output will be stored in + $avp(1). If there is no such environment variable no value will + be returned. Meaning of the parameters is as follows: - * environment_variable - Environent variable name. It can - include pseudo- variabes; - * avp - an AVP names to store the result in; + * environment_variable (string) - environent variable name. + Can also be specified as a pseudo-variable + * avp - an AVP to store the result in - WARNING: if the var you are passing out has a bash special - character in it, the var needs to be placed inside quotes, for - ex: exec_getenv("'$ct'"); + WARNING: any OpenSIPS pseudo-vars which may contain special + bash characters should be placed inside quotes, e.g. + exec_getenv("'$ct'"); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, - LOCAL_ROUTE, STARTUP_ROUTE. + LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE, EVENT_ROUTE, + ONREPLY_ROUTE. Example 1.7. exec_getenv usage ... exec_getenv("HOSTNAME"); -exec_getenv("HOSTNAME", "$avp(test)"); +exec_getenv("HOSTNAME", "$avp(localhost)"); ... 1.5. Known Issues - There is currently no guarantee that scripts ever return and - stop blocking SIP server. (There is kill.c but it is not used - along with the current mechanisms based on popen. Besides that - kill.c is ugly). + When imposing an execution timeout using time_to_kill, make + sure your "/bin/sh" is a shell which does not fork when + executed, case in which the job itself will not be killed, but + rather its parent shell, while the job is silently inherited by + "init" and will continue to run. "/bin/dash" is one of these + troublesome shell environments. diff --git a/modules/exec/doc/exec_admin.xml b/modules/exec/doc/exec_admin.xml index 248ad63fa03..f35287e1a5a 100644 --- a/modules/exec/doc/exec_admin.xml +++ b/modules/exec/doc/exec_admin.xml @@ -7,11 +7,11 @@
Overview - Exec module allows to start an external command from a &osips; script. - The commands may be any valid shell commands--the command string is - passed to shell using popen command. &osips; passes - additionally lot of information about request in environment - variables: + The Exec module enables the execution of external commands from the + &osips; script. Any valid shell commands are accepted. The final input + string is evaluated and executed using the "/bin/sh" symlink/binary. + &osips; may additionally pass a lot more information about the request + using environment variables: @@ -64,10 +64,10 @@ - NOTE: The envirnment variables must be specified with double $ - (e.g., $$SIP_OUSER) in the parameters given to exec functions. - Otherwise they will be evaluated as &osips; pseudo-variables, - throwing errors. + NOTE: Any environment variables which are given to the exec module + functions must be specified using the '$$' delimiter (e.g., $$SIP_OUSER), + otherwise they will be evaluated as &osips; pseudo-variables, + throwing scripting errors.
@@ -123,17 +123,17 @@ modparam("exec", "setvars", 1)
-
+
<varname>time_to_kill</varname> (integer) - Specifies the longest time a program is allowed to execute. If the + Specifies the longest time a program is allowed to execute. If the time is exceeded, the program is killed. - Default value is 0. + Default value is 0 (disabled). @@ -148,13 +148,13 @@ modparam("exec", "time_to_kill", 20)
<varname>async</varname> (integer) - Turns on the asynchronous mode for 'exec_msg' function. All commands + Turns on the asynchronous mode for the 'exec_msg' function. All commands will be executed by a different process and the caller will continue - it's flow, without waiting for a response. + its flow, without waiting for a response. - Default value is 0. + Default value is 0 (disabled). @@ -175,22 +175,24 @@ modparam("exec", "async", 1) exec_dset(command) - Executes an external command. Current &uri; is passed to the command - as parameter. Output of the command is considered &uri; set - (separated by lines). + Executes an external command. The current &ruri; is appended to the command + as its last parameter. The output of the command will rewrite the current R-URI. + Multiple lines of output lead to multiple branches. Meaning of the parameters is as follows: - command - Command to be executed. It can - include pseudo- variabes; + command (string, pvar) - command to be + executed. It can include pseudo-variables or '$$' delimited UNIX + environment variables - WARNING: if the var you are passing out has a bash special - character in it, the var needs to be placed inside quotes, for ex: - exec_dset("print-contact.sh '$ct'"); + WARNING: most OpenSIPS scripting variables should be quoted before being + passed to external commands, as in: exec_avp("log-call.sh '$ct'"). + This may help avoid some unexpected behaviour + (e.g. unwanted extra parameters, errors due to special bash characters, etc.) This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. @@ -199,8 +201,8 @@ modparam("exec", "async", 1) <function moreinfo="none">exec_dset</function> usage ... -exec_dset("echo TEST > /tmp/test.txt"); -exec_dset("echo TEST > /tmp/$rU.txt"); +exec_dset("ruri-changer.sh"); +exec_dset("ruri-changer.sh '$ct'"); ... @@ -210,9 +212,9 @@ exec_dset("echo TEST > /tmp/$rU.txt"); exec_msg(command) - Executes an external command. The whole message is passed to it in - input, no command-line parameters are added, output of the command is - not processed. + Executes an external command. The current SIP message is passed to it in + the standard input, no command-line parameters are added and the output + of the command is ignored. See sip-server/modules/exec/etc/exec.cfg in the source tarball for @@ -221,65 +223,70 @@ exec_dset("echo TEST > /tmp/$rU.txt"); Meaning of the parameters is as follows: - command - Command to be executed. It - can include pseudo-variables. + command (string) - command to be executed. It + can include pseudo-variables or '$$' delimited UNIX + environment variables - WARNING: if the var you are passing out has a bash special - character in it, the var needs to be placed inside quotes, for ex: - exec_msg("print-contact.sh '$ct'"); + WARNING: most OpenSIPS scripting variables should be quoted before being + passed to external commands, as in: exec_avp("log-call.sh '$ct'"). + This may help avoid some unexpected behaviour + (e.g. unwanted extra parameters, errors due to special bash characters, etc.) - This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, LOCAL_ROUTE, + TIMER_ROUTE, EVENT_ROUTE, ONREPLY_ROUTE. <function moreinfo="none">exec_msg</function> usage ... -exec_msg("echo TEST > /tmp/test.txt"); -exec_msg("echo TEST > /tmp/$rU.txt"); +exec_msg("call-logger.sh '$ct' >> /var/log/call-logger/'$rU'.calls"); ...
- <function moreinfo="none">exec_avp(command [, avplist])</function> + <function moreinfo="none">exec_avp(command[, avplist])</function> - Executes an external command. Each line from output of the command - is saved in an AVP from 'avplist'. If 'avplist' is missing, the - AVP are named 1, 2, 3, ... + Executes an external command. Each output line of the command + is saved in its corresponding AVP from avplist. + If avplist is missing or is incomplete, the + populated AVPs will be 1, 2, 3... or N, N+1, N+2... Meaning of the parameters is as follows: - command - Command to be executed. It can - include pseudo- variabes; + command (string) - command to be + executed. It can include pseudo-variables or '$$' delimited UNIX + environment variables - avplist - comma separated list with AVP - names to store the result in; + avplist (string) - comma separated list with AVP + names to store the result in - WARNING: if the var you are passing out has a bash special - character in it, the var needs to be placed inside quotes, for ex: - exec_avp("print-contact.sh '$ct'"); + WARNING: most OpenSIPS scripting variables should be quoted before being + passed to external commands, as in: exec_avp("log-call.sh '$ct'"). + This may help avoid some unexpected behaviour + (e.g. unwanted extra parameters, errors due to special bash characters, etc.) - This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, LOCAL_ROUTE, STARTUP_ROUTE. + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, + LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE, EVENT_ROUTE, ONREPLY_ROUTE. <function moreinfo="none">exec_avp</function> usage ... -exec_avp("echo TEST"); -exec_avp("echo TEST", "$avp(test)"); +exec_avp("get-subscriber-details.sh '$rU'", "$avp(credit) $avp(contract_model)"); ... @@ -287,40 +294,39 @@ exec_avp("echo TEST", "$avp(test)");
- <function moreinfo="none">exec_getenv(environment_variable [, avp])</function> + <function moreinfo="none">exec_getenv(environment_variable[, avp])</function> - Get the value of an evironment_variable. The value is saved - in 'avp'. If 'avp' is missing, the AVP is named 1. If there - is no such environment variable no value is returned. + Obtains the value of a UNIX evironment_variable. The value is saved + in 'avp'. If 'avp' is missing, output will be stored in $avp(1). If there + is no such environment variable no value will be returned. Meaning of the parameters is as follows: - environment_variable - Environent - variable name. It can include pseudo- variabes; + environment_variable (string) - + environent variable name. Can also be specified as a pseudo-variable - avp - an AVP names to store the - result in; + avp - an AVP to store the result in - WARNING: if the var you are passing out has a bash special - character in it, the var needs to be placed inside quotes, for ex: - exec_getenv("'$ct'"); + WARNING: any OpenSIPS pseudo-vars which may contain special bash + characters should be placed inside quotes, e.g. exec_getenv("'$ct'"); - This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, LOCAL_ROUTE, STARTUP_ROUTE. + This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, + LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE, EVENT_ROUTE, ONREPLY_ROUTE. <function moreinfo="none">exec_getenv</function> usage ... exec_getenv("HOSTNAME"); -exec_getenv("HOSTNAME", "$avp(test)"); +exec_getenv("HOSTNAME", "$avp(localhost)"); ... @@ -333,9 +339,12 @@ exec_getenv("HOSTNAME", "$avp(test)");
Known Issues - There is currently no guarantee that scripts ever return and stop - blocking &sip; server. (There is kill.c but it is not used along with - the current mechanisms based on popen. Besides that kill.c is ugly). + When imposing an execution timeout using + , + make sure your "/bin/sh" is a shell which does not fork when executed, + case in which the job itself will not be killed, but rather its parent shell, + while the job is silently inherited by "init" and will continue to run. + "/bin/dash" is one of these troublesome shell environments.
diff --git a/modules/exec/exec.c b/modules/exec/exec.c index 8e2f83f51b2..abb6d4f6fe8 100644 --- a/modules/exec/exec.c +++ b/modules/exec/exec.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -35,7 +35,7 @@ #include #include #include -/* +/* #include */ #include @@ -48,8 +48,10 @@ #include "../../action.h" #include "../../usr_avp.h" #include "../../ut.h" +#include "../../trim.h" #include "exec.h" +#include "kill.h" #define SLEEP_INTERVAL 300 @@ -61,20 +63,27 @@ int exec_msg(struct sip_msg *msg, char *cmd ) FILE *pipe; int exit_status; int ret; + pid_t pid; ret=-1; /* pessimist: assume error */ - pipe=popen( cmd, "w" ); - if (pipe==NULL) { + pid = __popen(cmd, "w", &pipe); + if (pid < 0) { LM_ERR("cannot open pipe: %s\n", cmd); ser_error=E_EXEC; return -1; } + LM_DBG("Forked pid %d\n", pid); + if (fwrite(msg->buf, 1, msg->len, pipe)!=msg->len) { LM_ERR("failed to write to pipe\n"); ser_error=E_EXEC; goto error01; } + + schedule_to_kill(pid); + wait(&exit_status); + /* success */ ret=1; @@ -84,7 +93,8 @@ int exec_msg(struct sip_msg *msg, char *cmd ) ser_error=E_EXEC; ret=-1; } - exit_status=pclose(pipe); + + pclose(pipe); if (WIFEXITED(exit_status)) { /* exited properly .... */ /* return false if script exited with non-zero status */ if (WEXITSTATUS(exit_status)!=0) ret=-1; @@ -96,57 +106,6 @@ int exec_msg(struct sip_msg *msg, char *cmd ) return ret; } -#define MAX_EXEC_PARAMETERS 32 -static const char *exec_argv[MAX_EXEC_PARAMETERS]; - -/* modifies the string in order to execute the command using exec */ -void exec_build_params(char *cmd) -{ - char q, *p = cmd, *end = cmd + strlen(cmd); - int i = 1; - - exec_argv[0] = (const char *)cmd; - /* extract command */ - while (p < end && (*p != ' ' || *(p-1) == '\'')) - p++; - - /* check if no parameters were specified */ - if (p == end) - goto end; - - do { - /* terminate previous cmd/param */ - *p++ = '\0'; - /* skip spaces */ - while (p < end && *p == ' ') - p++; - if (p == end) - goto end; - - /* quoted? */ - if (*p == '\'') { - p++; - q = '\''; - } else { - q = ' '; - } - - exec_argv[i] = (const char *)p; - if (i == MAX_EXEC_PARAMETERS) { - LM_WARN("Too may parameters: %d - ignoring ...\n", i); - goto end; - } - i++; - /* skip parameter */ - while (p < end && (*p != q || *(p-1) == '\'')) - p++; - } while (p < end); - -end: - LM_DBG("XXX: reseting parameter %d\n", i); - exec_argv[i] = NULL; -} - void exec_async_proc(int rank) { int pid, status; @@ -167,12 +126,11 @@ void exec_async_proc(int rank) } else if (pid) { exec_async_list->active_childs++; cmd->pid = pid; + schedule_to_kill(pid); } else { LM_DBG("running command %s (%d)\n", cmd->cmd, getpid()); - /* build the argv vector */ - exec_build_params(cmd->cmd); - /* call command */ - execv(cmd->cmd, (char * const *)exec_argv); + execl("/bin/sh", "/bin/sh", "-c", cmd->cmd, NULL); + LM_ERR("failed to run command\n"); exit(0); } @@ -252,7 +210,7 @@ int exec_async(struct sip_msg *msg, char *cmd ) int exec_str(struct sip_msg *msg, char *cmd, char *param, int param_len) { int cmd_len; - FILE *pipe; + FILE *pipe; char *cmd_line; int ret; int l1; @@ -260,10 +218,11 @@ int exec_str(struct sip_msg *msg, char *cmd, char *param, int param_len) { int uri_cnt; str uri; int exit_status; + pid_t pid; /* pessimist: assume error by default */ ret=-1; - + l1=strlen(cmd); if(param_len>0) cmd_len=l1+param_len+4; @@ -277,7 +236,7 @@ int exec_str(struct sip_msg *msg, char *cmd, char *param, int param_len) { } /* 'command parameter \0' */ - memcpy(cmd_line, cmd, l1); + memcpy(cmd_line, cmd, l1); if(param_len>0) { cmd_line[l1]=' '; @@ -288,27 +247,25 @@ int exec_str(struct sip_msg *msg, char *cmd, char *param, int param_len) { } else { cmd_line[l1] = 0; } - - pipe=popen( cmd_line, "r" ); - if (pipe==NULL) { - LM_ERR("cannot open pipe: %s\n", cmd_line); + + pid = __popen(cmd_line, "r", &pipe); + if (pid < 0) { + LM_ERR("failed to run command: %s\n", cmd_line); ser_error=E_EXEC; goto error01; } + LM_DBG("Forked pid %d\n", pid); + schedule_to_kill(pid); + wait(&exit_status); + /* read now line by line */ uri_cnt=0; - while( fgets(uri_line, MAX_URI_SIZE, pipe)!=NULL){ + while (fgets(uri_line, MAX_URI_SIZE, pipe)) { uri.s = uri_line; uri.len=strlen(uri.s); - /* trim from right */ - while(uri.len && (uri.s[uri.len-1]=='\r' - || uri.s[uri.len-1]=='\n' - || uri.s[uri.len-1]=='\t' - || uri.s[uri.len-1]==' ' )) { - LM_DBG("rtrim\n"); - uri.len--; - } + trim_trailing(&uri); + /* skip empty line */ if (uri.len==0) continue; /* ZT */ @@ -340,7 +297,8 @@ int exec_str(struct sip_msg *msg, char *cmd, char *param, int param_len) { ser_error=E_EXEC; ret=-1; } - exit_status=pclose(pipe); + + pclose(pipe); if (WIFEXITED(exit_status)) { /* exited properly .... */ /* return false if script exited with non-zero status */ if (WEXITSTATUS(exit_status)!=0) ret=-1; @@ -361,37 +319,37 @@ int exec_avp(struct sip_msg *msg, char *cmd, pvname_list_p avpl) int_str avp_val; int_str avp_name; unsigned short avp_type; - FILE *pipe; + FILE *pipe; int ret; char res_line[MAX_URI_SIZE+1]; str res; int exit_status; int i; pvname_list_t* crt; + pid_t pid; /* pessimist: assume error by default */ ret=-1; - - pipe=popen( cmd, "r" ); - if (pipe==NULL) { - LM_ERR("cannot open pipe: %s\n", cmd); + + pid = __popen(cmd, "r", &pipe); + if (pid < 0) { + LM_ERR("failed to run command: %s\n", cmd); ser_error=E_EXEC; return ret; } + LM_DBG("Forked pid %d\n", pid); + schedule_to_kill(pid); + wait(&exit_status); + /* read now line by line */ i=0; crt = avpl; - while( fgets(res_line, MAX_URI_SIZE, pipe)!=NULL){ + while (fgets(res_line, MAX_URI_SIZE, pipe)) { res.s = res_line; res.len=strlen(res.s); - /* trim from right */ - while(res.len && (res.s[res.len-1]=='\r' - || res.s[res.len-1]=='\n' - || res.s[res.len-1]=='\t' - || res.s[res.len-1]==' ' )) { - res.len--; - } + trim_trailing(&res); + /* skip empty line */ if (res.len==0) continue; /* ZT */ @@ -420,13 +378,13 @@ int exec_avp(struct sip_msg *msg, char *cmd, pvname_list_p avpl) avp_type |= AVP_VAL_STR; avp_val.s = res; - + if(add_avp(avp_type, avp_name.n, avp_val)!=0) { LM_ERR("unable to add avp\n"); goto error; } - + if(crt) crt = crt->next; @@ -443,7 +401,8 @@ int exec_avp(struct sip_msg *msg, char *cmd, pvname_list_p avpl) ser_error=E_EXEC; ret=-1; } - exit_status=pclose(pipe); + + pclose(pipe); if (WIFEXITED(exit_status)) { /* exited properly .... */ /* return false if script exited with non-zero status */ if (WEXITSTATUS(exit_status)!=0) ret=-1; @@ -500,18 +459,16 @@ int exec_getenv(struct sip_msg *msg, char *cmd, pvname_list_p avpl) avp_type |= AVP_VAL_STR; avp_val.s = res; - + if(add_avp(avp_type, avp_name.n, avp_val)!=0) { LM_ERR("unable to add avp\n"); goto error; } - + /* success */ ret=1; error: return ret; } - - diff --git a/modules/exec/exec.h b/modules/exec/exec.h index 91598a556ca..72ad6e66f36 100644 --- a/modules/exec/exec.h +++ b/modules/exec/exec.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/exec/exec_hf.c b/modules/exec/exec_hf.c index 22480aa1003..aadaa87e7c6 100644 --- a/modules/exec/exec_hf.c +++ b/modules/exec/exec_hf.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * history @@ -32,9 +32,9 @@ * canonical form; multiple header field occurrences are merged * into a single variable * - * known limitations: - * - compact header field names unknown to parser will not be translated to - * canonical form. Thus, environment variables may have either name and + * known limitations: + * - compact header field names unknown to parser will not be translated to + * canonical form. Thus, environment variables may have either name and * users have to check for both of them. * - symbols in header field names will be translated to underscore * @@ -66,7 +66,7 @@ static int insert_hf( struct hf_wrapper **list, struct hdr_field *hf ) return 0; } memset(w, 0, sizeof(struct hf_wrapper)); - w->var_type=W_HF;w->u.hf=hf; + w->var_type=W_HF;w->u.hf=hf; w->prefix=HF_PREFIX; w->prefix_len=HF_PREFIX_LEN; /* is there another hf of the same type?... */ @@ -74,7 +74,7 @@ static int insert_hf( struct hf_wrapper **list, struct hdr_field *hf ) if (i->var_type==W_HF && i->u.hf->type==hf->type) { /* if it is OTHER, check name too */ if (hf->type==HDR_OTHER_T && (hf->name.len!=i->u.hf->name.len - || strncasecmp(i->u.hf->name.s, hf->name.s, + || strncasecmp(i->u.hf->name.s, hf->name.s, hf->name.len)!=0)) continue; /* yes, we found a hf of same type */ @@ -119,43 +119,43 @@ static int compacthdr_type2str(hdr_types_t type, char **hname, int *hlen ) switch(type) { /* HDR_CONTENT_ENCODING: 'e' -- unsupported by parser */ /* HDR_SUBJECT: 's' -- unsupported by parser */ - case HDR_VIA_T /* v */ : + case HDR_VIA_T /* v */ : *hname=VAR_VIA; *hlen=VAR_VIA_LEN; break; - case HDR_CONTENTTYPE_T /* c */ : + case HDR_CONTENTTYPE_T /* c */ : *hname=VAR_CTYPE; *hlen=VAR_CTYPE_LEN; break; - case HDR_FROM_T /* f */: + case HDR_FROM_T /* f */: *hname=VAR_FROM; *hlen=VAR_FROM_LEN; break; - case HDR_CALLID_T /* i */: + case HDR_CALLID_T /* i */: *hname=VAR_CALLID; *hlen=VAR_CALLID_LEN; break; - case HDR_SUPPORTED_T /* k */: + case HDR_SUPPORTED_T /* k */: *hname=VAR_SUPPORTED; *hlen=VAR_SUPPORTED_LEN; break; - case HDR_CONTENTLENGTH_T /* l */: + case HDR_CONTENTLENGTH_T /* l */: *hname=VAR_CLEN; *hlen=VAR_CLEN_LEN; break; - case HDR_CONTACT_T /* m */: + case HDR_CONTACT_T /* m */: *hname=VAR_CONTACT; *hlen=VAR_CONTACT_LEN; break; - case HDR_TO_T /* t */: + case HDR_TO_T /* t */: *hname=VAR_TO; *hlen=VAR_TO_LEN; break; - case HDR_EVENT_T /* o */: + case HDR_EVENT_T /* o */: *hname=VAR_EVENT; *hlen=VAR_EVENT_LEN; break; - default: + default: return 0; } return 1; @@ -175,17 +175,17 @@ static int canonize_headername(str *orig, char **hname, int *hlen ) } for (c=orig->s, i=0; i<*hlen; i++, c++) { /* lowercase to uppercase */ - if (*c>='a' && *c<='z') + if (*c>='a' && *c<='z') *((*hname)+i)=*c-('a'-'A'); /* uppercase and numbers stay "as is" */ - else if ((*c>='A' && *c<='Z')||(*c>='0' && *c<='9')) + else if ((*c>='A' && *c<='Z')||(*c>='0' && *c<='9')) *((*hname)+i)=*c; /* legal symbols will be translated to underscore */ else if (strchr(UNRESERVED_MARK HNV_UNRESERVED, *c) || (*c==ESCAPE)) *((*hname)+i)=HFN_SYMBOL; else { - LM_ERR("print_var unexpected char '%c' in hfname %.*s\n", + LM_ERR("print_var unexpected char '%c' in hfname %.*s\n", *c, *hlen, orig->s ); *((*hname)+i)=HFN_SYMBOL; } @@ -241,7 +241,7 @@ static int print_hf_var(struct hf_wrapper *w, int offset) LM_ERR("canonize_hn error\n"); return 0; } - } + } /* now we have a header name, let us generate the var */ envvar_len=w->u.hf->body.len; for(wi=w->next_same; wi; wi=wi->next_same) { /* other values, separated */ @@ -264,7 +264,7 @@ static int print_hf_var(struct hf_wrapper *w, int offset) } *c=0; /* zero termination */ LM_DBG("%s\n", envvar ); - + w->envvar=envvar; if (!canonical) pkg_free(hname); return 1; @@ -277,9 +277,9 @@ static int print_hf_var(struct hf_wrapper *w, int offset) static int print_var(struct hf_wrapper *w, int offset) { switch(w->var_type) { - case W_HF: + case W_HF: return print_hf_var(w, offset); - case W_AV: + case W_AV: return print_av_var(w); default: LM_CRIT("unknown type: %d\n", w->var_type ); @@ -287,7 +287,7 @@ static int print_var(struct hf_wrapper *w, int offset) } } -static void release_vars(struct hf_wrapper *list) +static void release_vars(struct hf_wrapper *list) { while(list) { if (list->envvar) { @@ -413,7 +413,7 @@ static int append_var(char *name, char *value, int len, struct hf_wrapper **list LM_ERR("ran out of pkg mem\n"); return 0; } - memset(w, 0, sizeof(struct hf_wrapper)); + memset(w, 0, sizeof(struct hf_wrapper)); w->var_type=W_AV; w->u.av.attr.s=name; w->u.av.attr.len=strlen(name); @@ -439,7 +439,7 @@ static int append_fixed_vars(struct sip_msg *msg, struct hf_wrapper **list) return 0; } /* request URI */ - uri=msg->new_uri.s && msg->new_uri.len ? + uri=msg->new_uri.s && msg->new_uri.len ? &msg->new_uri : &msg->first_line.u.request.uri; if (!append_var(EV_RURI, uri->s, uri->len, list )) { LM_ERR("append_var URI failed\n"); @@ -449,7 +449,7 @@ static int append_fixed_vars(struct sip_msg *msg, struct hf_wrapper **list) if (parse_uri(uri->s, uri->len, &parsed_uri)<0) { LM_WARN("uri not parsed\n"); } else { - if (!append_var(EV_USER, parsed_uri.user.s, + if (!append_var(EV_USER, parsed_uri.user.s, parsed_uri.user.len, list)) { LM_ERR("append_var USER failed\n"); goto error; @@ -462,12 +462,12 @@ static int append_fixed_vars(struct sip_msg *msg, struct hf_wrapper **list) goto error; } /* userpart of request URI */ - if (parse_uri(msg->first_line.u.request.uri.s, - msg->first_line.u.request.uri.len, + if (parse_uri(msg->first_line.u.request.uri.s, + msg->first_line.u.request.uri.len, &oparsed_uri)<0) { LM_WARN("orig URI not parsed\n"); } else { - if (!append_var(EV_OUSER, oparsed_uri.user.s, + if (!append_var(EV_OUSER, oparsed_uri.user.s, oparsed_uri.user.len, list)) { LM_ERR("ppend_var OUSER failed\n"); goto error; diff --git a/modules/exec/exec_hf.h b/modules/exec/exec_hf.h index 04bff45e60b..f68621bb32a 100644 --- a/modules/exec/exec_hf.h +++ b/modules/exec/exec_hf.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/exec/exec_mod.c b/modules/exec/exec_mod.c index 3975cdef5a7..523f0c8c7ee 100644 --- a/modules/exec/exec_mod.c +++ b/modules/exec/exec_mod.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -97,8 +97,10 @@ struct module_exports exec_exports = { struct module_exports exports= { #endif "exec", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS,/* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -120,7 +122,8 @@ void exec_shutdown(void) static int mod_init( void ) { LM_INFO("exec - initializing\n"); - if (time_to_kill) initialize_kill(); + if (time_to_kill) + initialize_kill(); if (async) { /* init exeternal structure if async enabled */ @@ -156,10 +159,10 @@ inline static int w_exec_dset(struct sip_msg* msg, char* cmd, char* foo) environment_t *backup; int ret; str command; - + if(msg==0 || cmd==0) return -1; - + backup=0; if (setvars) { backup=set_env(msg); @@ -173,13 +176,13 @@ inline static int w_exec_dset(struct sip_msg* msg, char* cmd, char* foo) uri=&msg->new_uri; else uri=&msg->first_line.u.request.uri; - + if(fixup_get_svalue(msg, (gparam_p)cmd, &command)!=0) { LM_ERR("invalid command parameter"); return -1; } - + LM_DBG("executing [%s]\n", command.s); ret=exec_str(msg, command.s, uri->s, uri->len); @@ -195,7 +198,7 @@ inline static int w_exec_msg(struct sip_msg* msg, char* cmd, char* foo) environment_t *backup; int ret; str command; - + if(msg==0 || cmd==0) return -1; @@ -207,15 +210,15 @@ inline static int w_exec_msg(struct sip_msg* msg, char* cmd, char* foo) return -1; } } - + if(fixup_get_svalue(msg, (gparam_p)cmd, &command)!=0) { LM_ERR("invalid command parameter"); return -1; } - + LM_DBG("executing [%s]\n", command.s); - + if(async) ret=exec_async(msg, command.s); else @@ -231,10 +234,10 @@ inline static int w_exec_avp(struct sip_msg* msg, char* cmd, char* avpl) environment_t *backup; int ret; str command; - + if(msg==0 || cmd==0) return -1; - + backup=0; if (setvars) { backup=set_env(msg); @@ -249,7 +252,7 @@ inline static int w_exec_avp(struct sip_msg* msg, char* cmd, char* avpl) LM_ERR("invalid command parameter"); return -1; } - + LM_DBG("executing [%s]\n", command.s); ret=exec_avp(msg, command.s, (pvname_list_p)avpl); diff --git a/modules/exec/kill.c b/modules/exec/kill.c index 82549a34c5e..3134c7e3fea 100644 --- a/modules/exec/kill.c +++ b/modules/exec/kill.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -40,11 +40,14 @@ */ +#include +#include #include #include #include +#include -#include "../../mem/shm_mem.h" +#include "../../mem/shm_mem.h" #include "../../dprint.h" #include "../../timer.h" #include "../../locking.h" @@ -55,7 +58,7 @@ static gen_lock_t *kill_lock=NULL; -static struct timer_list kill_list; +static struct timer_list *kill_list; @@ -74,29 +77,29 @@ static void timer_routine(unsigned int ticks , void * attr) int killr; /* check if it worth entering the lock */ - if (kill_list.first_tl.next_tl==&kill_list.last_tl - || kill_list.first_tl.next_tl->time_out > ticks ) + if (kill_list->first_tl.next_tl==&kill_list->last_tl + || kill_list->first_tl.next_tl->time_out > ticks ) return; lock(); - end = &kill_list.last_tl; - tl = kill_list.first_tl.next_tl; + end = &kill_list->last_tl; + tl = kill_list->first_tl.next_tl; while( tl!=end && tl->time_out <= ticks ) { tl=tl->next_tl; } /* nothing to delete found */ - if (tl->prev_tl==&kill_list.first_tl) { + if (tl->prev_tl==&kill_list->first_tl) { unlock(); return; } /* the detached list begins with current beginning */ - ret = kill_list.first_tl.next_tl; + ret = kill_list->first_tl.next_tl; /* and we mark the end of the split list */ tl->prev_tl->next_tl = 0; /* the shortened list starts from where we suspended */ - kill_list.first_tl.next_tl = tl; - tl->prev_tl = & kill_list.first_tl; + kill_list->first_tl.next_tl = tl; + tl->prev_tl=&kill_list->first_tl; unlock(); /* process the list now */ @@ -104,7 +107,8 @@ static void timer_routine(unsigned int ticks , void * attr) tmp_tl=ret->next_tl; ret->next_tl=ret->prev_tl=0; if (ret->time_out>0) { - killr=kill(ret->pid, SIGTERM ); + LM_INFO("exec timeout, pid %d -> sending SIGTERM\n", ret->pid); + killr=kill(ret->pid, SIGTERM); LM_DBG("child process (%d) kill status: %d\n", ret->pid, killr ); } shm_free(ret); @@ -112,58 +116,124 @@ static void timer_routine(unsigned int ticks , void * attr) } } +pid_t __popen(const char *cmd, const char *type, FILE **stream) +{ + #define READ 0 + #define WRITE 1 + + pid_t ret; + int fds[2]; + + if (*type != 'r' && *type != 'w') + return -1; + + if (pipe(fds) != 0) { + LM_ERR("failed to create pipe (%d: %s)\n", errno, strerror(errno)); + return -1; + } + + ret = fork(); + + if (ret == 0) { + + if (*type == 'r') { + close(fds[READ]); + dup2(fds[WRITE], 1); + close(fds[WRITE]); + } else { + close(fds[WRITE]); + dup2(fds[READ], 0); + close(fds[READ]); + } + + execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); + + exit(-1); + } + + if (*type == 'r') { + close(fds[WRITE]); + if (stream) + *stream = fdopen(fds[READ], "r"); + } else { + close(fds[READ]); + if (stream) + *stream = fdopen(fds[WRITE], "w"); + } + + return ret; +} + int schedule_to_kill( int pid ) { struct timer_link *tl; - tl=shm_malloc( sizeof(struct timer_link) ); - if (tl==0) { + + if (time_to_kill <= 0) + return 0; + + tl = shm_malloc(sizeof *tl); + if (!tl) { LM_ERR("no shmem\n"); return -1; } - memset(tl, 0, sizeof(struct timer_link) ); + memset(tl, 0, sizeof *tl); + lock(); tl->pid=pid; tl->time_out=get_ticks()+time_to_kill; - tl->prev_tl=kill_list.last_tl.prev_tl; - tl->next_tl=&kill_list.last_tl; - kill_list.last_tl.prev_tl=tl; + tl->prev_tl = kill_list->last_tl.prev_tl; + tl->next_tl = &kill_list->last_tl; + kill_list->last_tl.prev_tl=tl; tl->prev_tl->next_tl=tl; unlock(); - return 1; + + return 0; } int initialize_kill(void) { /* if disabled ... */ - if (time_to_kill==0) return 1; - if ((register_timer( "exec_kill", timer_routine, - 0 /* param */, 1 /* period */)<0)) { + if (time_to_kill == 0) + return 0; + + if (register_timer("exec_kill", timer_routine, NULL /* param */, + 1 /* period */) < 0) { LM_ERR("no exec timer registered\n"); return -1; } - kill_list.first_tl.next_tl=&kill_list.last_tl; - kill_list.last_tl.prev_tl=&kill_list.first_tl; - kill_list.first_tl.prev_tl= - kill_list.last_tl.next_tl = 0; - kill_list.last_tl.time_out=-1; - kill_lock=lock_alloc(); - if (kill_lock==0) { + + kill_list = shm_malloc(sizeof *kill_list); + if (!kill_list) { + LM_ERR("no more shm!\n"); + return -1; + } + + kill_list->first_tl.next_tl = &kill_list->last_tl; + kill_list->last_tl.prev_tl = &kill_list->first_tl; + kill_list->first_tl.prev_tl = + kill_list->last_tl.next_tl = NULL; + + kill_list->last_tl.time_out = -1; + + kill_lock = lock_alloc(); + if (!kill_lock) { LM_ERR("no shm mem for mutex\n"); return -1; } lock_init(kill_lock); + LM_DBG("kill initialized\n"); - return 1; + return 0; } void destroy_kill(void) { /* if disabled ... */ - if (time_to_kill==0) - return; + if (time_to_kill==0) + return; + if (kill_lock) { lock_destroy(kill_lock); lock_dealloc(kill_lock); } - return; } diff --git a/modules/exec/kill.h b/modules/exec/kill.h index 4996c34e565..e519d80ed98 100644 --- a/modules/exec/kill.h +++ b/modules/exec/kill.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -43,6 +43,15 @@ void destroy_kill(); int initialize_kill(); int schedule_to_kill( int pid ); +/** + * __popen - a wrapper function over execvp + * + * @cmd: the command string to be executed + * @type: denotes a read-only or write-only stream + * @stream: stream to be returned to the caller + */ +pid_t __popen(const char *cmd, const char *type, FILE **stream); + #endif diff --git a/modules/gflags/README b/modules/gflags/README index 224a90f997b..8682aae532f 100644 --- a/modules/gflags/README +++ b/modules/gflags/README @@ -16,8 +16,7 @@ Daniel-Constantin Mierla Copyright © 2004 FhG FOKUS Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/gflags/gflags.c b/modules/gflags/gflags.c index 9490a13b134..65700ca6986 100644 --- a/modules/gflags/gflags.c +++ b/modules/gflags/gflags.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -34,7 +34,7 @@ * * * gflags module: global flags; it keeps a bitmap of flags - * in shared memory and may be used to change behaviour + * in shared memory and may be used to change behaviour * of server based on value of the flags. E.g., * if (is_gflag("1")) { t_relay_to_udp("10.0.0.1","5060"); } * else { t_relay_to_udp("10.0.0.2","5060"); } @@ -95,7 +95,7 @@ static cmd_export_t cmds[]={ static param_export_t params[]={ {"initial", INT_PARAM, &initial}, - {0,0,0} + {0,0,0} }; static mi_export_t mi_cmds[] = { @@ -108,8 +108,10 @@ static mi_export_t mi_cmds[] = { struct module_exports exports = { "gflags", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -161,7 +163,7 @@ static int fixup_gflags( void** param, int param_no) /**************************** module functions ******************************/ -static int set_gflag(struct sip_msg *bar, char *flag, char *foo) +static int set_gflag(struct sip_msg *bar, char *flag, char *foo) { (*gflags) |= (unsigned int)(long)flag; return 1; diff --git a/modules/group/README b/modules/group/README index 19eb50d1629..c343c9bfb39 100644 --- a/modules/group/README +++ b/modules/group/README @@ -20,8 +20,7 @@ Irina-Maria Stanescu Copyright © 2009 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-08-17 19:03:14 +0300 - (Mon, 17 Aug 2009) $ + Revision $Revision: 5969 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/group/group.c b/modules/group/group.c index 18b23acb2e5..ab09d561368 100644 --- a/modules/group/group.c +++ b/modules/group/group.c @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -170,12 +170,12 @@ int db_is_user_in(struct sip_msg* _msg, char* _hf, char* _grp) } if (RES_ROW_N(res) == 0) { - LM_DBG("user is not in group '%.*s'\n", + LM_DBG("user is not in group '%.*s'\n", (grp_s.len), ZSW((grp_s.s))); group_dbf.free_result(group_dbh, res); return -6; } else { - LM_DBG("user is in group '%.*s'\n", + LM_DBG("user is in group '%.*s'\n", (grp_s.len), ZSW((grp_s.s))); group_dbf.free_result(group_dbh, res); return 1; @@ -225,7 +225,7 @@ void group_db_close(void) } /* - * * "Request-URI", "To", "From", "Credentials" + * * "Request-URI", "To", "From", "Credentials" */ static unsigned int hf_type( str *str1) { diff --git a/modules/group/group.h b/modules/group/group.h index d577c35a97c..bfdfcb64c89 100644 --- a/modules/group/group.h +++ b/modules/group/group.h @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/group/group_mod.c b/modules/group/group_mod.c index 243c93d5d67..a53e47865ec 100644 --- a/modules/group/group_mod.c +++ b/modules/group/group_mod.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id$ * * Group membership - module interface * @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -33,7 +33,7 @@ * 2004-06-07 updated to the new DB api: calls to group_db_* (andrei) * 2005-10-06 - added support for regexp-based groups (bogdan) * 2008-12-26 pseudovar argument for group parameter at is_user_in (saguti). - * 2009-08-07 - joined with group_radius module to support generic AAA group + * 2009-08-07 - joined with group_radius module to support generic AAA group * requests (Irina Stanescu) */ @@ -108,7 +108,7 @@ static str db_url = {NULL, 0}; static str aaa_proto_url = {NULL, 0}; /* Table name where group definitions are stored */ -str table = {TABLE, TABLE_LEN}; +str table = {TABLE, TABLE_LEN}; str user_column = {USER_COL, USER_COL_LEN}; str domain_column = {DOMAIN_COL, DOMAIN_COL_LEN}; str group_column = {GROUP_COL, GROUP_COL_LEN}; @@ -166,14 +166,26 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_AAA, NULL, DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_url", get_deps_sqldb_url }, + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "group", + "group", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ diff --git a/modules/group/group_mod.h b/modules/group/group_mod.h index 1f45a9188a8..b463838b75a 100644 --- a/modules/group/group_mod.h +++ b/modules/group/group_mod.h @@ -1,7 +1,7 @@ /* * $Id$ * - * Group membership + * Group membership * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2009 Irina Stanescu @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/group/re_group.c b/modules/group/re_group.c index b2b96825682..a66473a1ef5 100644 --- a/modules/group/re_group.c +++ b/modules/group/re_group.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id$ * * Copyright (C) 2005-2007 Voice Sistem SRL * @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/group/re_group.h b/modules/group/re_group.h index 12029e55b64..6fc47cfe1d8 100644 --- a/modules/group/re_group.h +++ b/modules/group/re_group.h @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id$ * * Copyright (C) 2005-2007 Voice Sistem SRL * @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/h350/h350_exp_fn.c b/modules/h350/h350_exp_fn.c index 12b19602fce..bdc3b543b62 100644 --- a/modules/h350/h350_exp_fn.c +++ b/modules/h350/h350_exp_fn.c @@ -79,7 +79,7 @@ int h350_sipuri_lookup(struct sip_msg* _msg, pv_elem_t* _sip_uri) LM_ERR("ldap_rfc4515_escape failed\n"); return E_H350_INTERNAL; } - + /* * do ldap search */ @@ -95,7 +95,7 @@ int h350_sipuri_lookup(struct sip_msg* _msg, pv_elem_t* _sip_uri) LM_ERR("ldap search failed\n"); return E_H350_INTERNAL; } - + if (ld_result_count < 1) { return E_H350_NO_SUCCESS; @@ -122,9 +122,9 @@ int h350_auth_lookup( /* * get digest_username str */ - if (_digest_username) + if (_digest_username) { - if (pv_printf_s(_msg, _digest_username, &digest_username) != 0) + if (pv_printf_s(_msg, _digest_username, &digest_username) != 0) { LM_ERR("pv_printf_s failed\n"); return E_H350_INTERNAL; @@ -159,16 +159,16 @@ int h350_auth_lookup( return E_H350_INTERNAL; } - /* + /* * search for sip digest username in H.350, store digest password */ - + /* ldap filter escape digest username */ digest_username_escaped.s = digest_username_buf; digest_username_escaped.len = DIGEST_USERNAME_BUF_SIZE - 1; if (ldap_api.ldap_rfc4515_escape( - &digest_username, - &digest_username_escaped, + &digest_username, + &digest_username_escaped, 0) ) { @@ -205,13 +205,13 @@ int h350_auth_lookup( /* get ldap result values */ rc = ldap_api.ldap_result_attr_vals(&h350_sip_pwd_name, &attr_vals); - if (rc < 0) + if (rc < 0) { LM_ERR("getting LDAP attribute values failed\n"); ldap_api.ldap_value_free_len(attr_vals); return E_H350_INTERNAL; } - if ((rc > 0) || (attr_vals == NULL)) + if ((rc > 0) || (attr_vals == NULL)) { LM_INFO("no values found in LDAP entry for username [%s]\n", digest_username_escaped.s); @@ -225,11 +225,11 @@ int h350_auth_lookup( /* * write AVPs */ - + avp_val.s = digest_username; - if (add_avp( username_avp_type | AVP_VAL_STR, - username_avp_name, - avp_val) + if (add_avp( username_avp_type | AVP_VAL_STR, + username_avp_name, + avp_val) < 0) { LM_ERR("failed to create new AVP\n"); @@ -260,7 +260,7 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) regmatch_t pmatch[5]; int avp_name; int_str avp_val; - str avp_val_str, avp_name_str, + str avp_val_str, avp_name_str, avp_name_prefix_str, call_pref_timeout_str; int call_pref_timeout; static char call_pref_avp_name[AVP_NAME_STR_BUF_LEN]; @@ -274,7 +274,7 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) return E_H350_INTERNAL; } - + /* * get LDAP attribute values */ @@ -301,8 +301,8 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) memcpy(call_pref_avp_name, avp_name_prefix_str.s, avp_name_prefix_str.len); } else { - LM_ERR("AVP name prefix too long [%d] (max [%d])", - avp_name_prefix_str.len, + LM_ERR("AVP name prefix too long [%d] (max [%d])", + avp_name_prefix_str.len, AVP_NAME_STR_BUF_LEN); return E_H350_INTERNAL; } @@ -314,7 +314,7 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) switch (rc) { case REG_NOMATCH: - LM_INFO("no h350 call preference regex match for [%s]\n", + LM_INFO("no h350 call preference regex match for [%s]\n", attr_vals[i]->bv_val); continue; case REG_ESPACE: @@ -327,7 +327,7 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) } /* calculate call preference sip uri */ - if (avp_name_prefix_str.len + pmatch[2].rm_eo - pmatch[2].rm_so + if (avp_name_prefix_str.len + pmatch[2].rm_eo - pmatch[2].rm_so >= AVP_NAME_STR_BUF_LEN) { LM_ERR("AVP name too long for [%s]", attr_vals[i]->bv_val); @@ -337,9 +337,9 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) avp_val_str.len = pmatch[1].rm_eo - pmatch[1].rm_so; avp_val.s = avp_val_str; - + /* calculate call preference avp name */ - memcpy( call_pref_avp_name + avp_name_prefix_str.len, + memcpy( call_pref_avp_name + avp_name_prefix_str.len, attr_vals[i]->bv_val + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so); @@ -351,7 +351,7 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) LM_ERR("cannot get avp id\n"); continue; } - + /* add avp */ if (add_avp(AVP_NAME_STR | AVP_VAL_STR, avp_name, avp_val) < 0) { @@ -361,13 +361,13 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) } avp_count++; - + /* check for call preference timeout */ if ((pmatch[4].rm_eo - pmatch[4].rm_so) == 0) { continue; } - + /* calculate call preference timeout avp name */ memcpy( avp_name_str.s + avp_name_str.len, "_t", 2); avp_name_str.len += 2; @@ -376,7 +376,7 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) LM_ERR("cannot get avp id\n"); continue; } - + /* calculate timeout avp value */ call_pref_timeout_str.s = attr_vals[i]->bv_val + pmatch[4].rm_so; call_pref_timeout_str.len = pmatch[4].rm_eo - pmatch[4].rm_so; @@ -395,14 +395,14 @@ int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) LM_ERR("failed to create new AVP\n"); ldap_api.ldap_value_free_len(attr_vals); return E_H350_INTERNAL; - } + } } ldap_api.ldap_value_free_len(attr_vals); if (avp_count > 0) { return avp_count; - } else + } else { return E_H350_NO_SUCCESS; } @@ -451,8 +451,8 @@ int h350_service_level(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) AVP_NAME_STR_BUF_LEN); ldap_api.ldap_value_free_len(attr_vals); return E_H350_INTERNAL; - } - + } + /* * loop through service level values and add AVP(s) @@ -466,12 +466,12 @@ int h350_service_level(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix) LM_ERR("AVP name too long for [%s]\n", attr_vals[i]->bv_val); continue; } - memcpy( service_level_avp_name + avp_name_prefix.len, + memcpy( service_level_avp_name + avp_name_prefix.len, attr_vals[i]->bv_val, attr_vals[i]->bv_len); avp_name.s.s = service_level_avp_name; avp_name.s.len = avp_name_prefix.len + attr_vals[i]->bv_len; - + avp_name.n = get_avp_id(&avp_name.s); if (avp_name.n <= 0) { LM_ERR("cannot get avp id\n"); diff --git a/modules/h350/h350_exp_fn.h b/modules/h350/h350_exp_fn.h index 59adf0010a4..f8903609daf 100644 --- a/modules/h350/h350_exp_fn.h +++ b/modules/h350/h350_exp_fn.h @@ -51,8 +51,8 @@ int h350_exp_fn_init(); int h350_sipuri_lookup(struct sip_msg* _msg, pv_elem_t* _sip_uri); int h350_auth_lookup( - struct sip_msg* _msg, - pv_elem_t* _digest_username, + struct sip_msg* _msg, + pv_elem_t* _digest_username, struct h350_auth_lookup_avp_params* _avp_specs); int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix); diff --git a/modules/h350/h350_mod.c b/modules/h350/h350_mod.c index 02ca0de1e7b..498cbe1dcd6 100644 --- a/modules/h350/h350_mod.c +++ b/modules/h350/h350_mod.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * OpenSIPS H.350 Module @@ -6,7 +6,7 @@ * Copyright (C) 2007 University of North Carolina * * Original author: Christian Schlatter, cs@unc.edu - * + * * * This file is part of opensips, a free SIP server. * @@ -20,8 +20,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -103,14 +103,25 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "ldap", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "h350", + "h350", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -125,7 +136,7 @@ struct module_exports exports = { static int child_init(int rank) { - + /* don't do anything for non-worker process */ if (rank == PROC_MAIN || rank == PROC_TCP_MAIN) { return 0; @@ -169,7 +180,7 @@ static int mod_init(void) LM_ERR("Invalid search_scope [%s]\n", h350_search_scope.s); return -1; } - + } @@ -189,8 +200,8 @@ static int w_h350_sipuri_lookup(struct sip_msg* msg, char* sip_uri, char* s2) static int w_h350_auth_lookup(struct sip_msg* msg, char* digest_username, char* avp_specs) { return h350_auth_lookup( - msg, - (pv_elem_t*)digest_username, + msg, + (pv_elem_t*)digest_username, (struct h350_auth_lookup_avp_params*)avp_specs); } @@ -237,7 +248,7 @@ static int h350_auth_lookup_fixup(void** param, int param_no) str s; struct h350_auth_lookup_avp_params *params; - if (param_no == 1) + if (param_no == 1) { s.s = (char*)*param; s.len = strlen(s.s); @@ -254,7 +265,7 @@ static int h350_auth_lookup_fixup(void** param, int param_no) /* * parse *param into username_avp_spec_str and pwd_avp_spec_str */ - + username_avp_spec_str = (char*)*param; if ((pwd_avp_spec_str = strchr(username_avp_spec_str, '/')) == 0) { diff --git a/modules/httpd/README b/modules/httpd/README index cfe05aee72e..e4bf893b5ce 100644 --- a/modules/httpd/README +++ b/modules/httpd/README @@ -8,10 +8,9 @@ Edited by Ovidiu Sas - Copyright © 2012 VoIP Embedded, Inc. + Copyright © 2012-2013 VoIP Embedded, Inc. Revision History - Revision $Rev: 8580 $ $Date: 2011-11-21 14:51:00 -0500 (Mon, 21 - Nov 2011) $ + Revision $Rev: 8580 $ $Date$ __________________________________________________________ Table of Contents @@ -29,6 +28,7 @@ Ovidiu Sas 1.3.1. ip(string) 1.3.2. port(integer) 1.3.3. buf_size (integer) + 1.3.4. post_buf_size (integer) 1.4. Exported MI Functions @@ -50,6 +50,7 @@ Ovidiu Sas 1.1. Set ip parameter 1.2. Set port parameter 1.3. Set buf_size parameter + 1.4. Set post_buf_size parameter Chapter 1. Admin Guide @@ -103,8 +104,8 @@ modparam("httpd", "port", 8000) 1.3.3. buf_size (integer) - It specifies the maximum length of the buffer used to write in - the html response. + It specifies the maximum length (in bytes) of the buffer used + to write in the html response. If the size of the buffer is set to zero, it will be automatically set to a quarter of the size of the pkg memory. @@ -116,6 +117,19 @@ modparam("httpd", "port", 8000) modparam("httpd", "buf_size", 524288) ... +1.3.4. post_buf_size (integer) + + It specifies the length (in bytes) of the POST HTTP requests + processing buffer. For large POST request, the default value + might require to be increased. + + The default value is 1024. The minumal value is 256. + + Example 1.4. Set post_buf_size parameter +... +modparam("httpd", "post_buf_size", 4096) +... + 1.4. Exported MI Functions 1.4.1. httpd_list_root_path diff --git a/modules/httpd/doc/httpd.xml b/modules/httpd/doc/httpd.xml index 4c5578f6765..5a915a4cb77 100644 --- a/modules/httpd/doc/httpd.xml +++ b/modules/httpd/doc/httpd.xml @@ -29,7 +29,7 @@ - 2012 + 2012-2013 VoIP Embedded, Inc. diff --git a/modules/httpd/doc/httpd_admin.xml b/modules/httpd/doc/httpd_admin.xml index 103461dcb35..420a34bfeca 100644 --- a/modules/httpd/doc/httpd_admin.xml +++ b/modules/httpd/doc/httpd_admin.xml @@ -91,8 +91,8 @@ modparam("httpd", "port", 8000)
<varname>buf_size</varname> (integer) - It specifies the maximum length of the buffer used to write - in the html response. + It specifies the maximum length (in bytes) of the buffer + used to write in the html response. If the size of the buffer is set to zero, it will be automatically @@ -107,6 +107,25 @@ modparam("httpd", "port", 8000) ... modparam("httpd", "buf_size", 524288) ... + + +
+
+ <varname>post_buf_size</varname> (integer) + + It specifies the length (in bytes) of the POST HTTP requests + processing buffer. For large POST request, the default value + might require to be increased. + + + The default value is 1024. The minumal value is 256. + + + Set <varname>post_buf_size</varname> parameter + +... +modparam("httpd", "post_buf_size", 4096) +...
diff --git a/modules/httpd/httpd.c b/modules/httpd/httpd.c index 6f4568380e7..c0f45ddbe7b 100644 --- a/modules/httpd/httpd.c +++ b/modules/httpd/httpd.c @@ -46,6 +46,10 @@ #include "httpd_load.h" #include "httpd_proc.h" + +#define MIN_POST_BUF_SIZE 256 +#define DEFAULT_POST_BUF_SIZE 1024 + /* module functions */ static int mod_init(); static int destroy(void); @@ -54,6 +58,7 @@ static struct mi_root* mi_list_root_path(struct mi_root* cmd, void* param); int port = 8888; str ip = {NULL, 0}; str buffer = {NULL, 0}; +int post_buf_size = DEFAULT_POST_BUF_SIZE; struct httpd_cb *httpd_cb_list = NULL; @@ -65,9 +70,10 @@ static proc_export_t mi_procs[] = { /** Module parameters */ static param_export_t params[] = { - {"port", INT_PARAM, &port}, - {"ip", STR_PARAM, &ip.s}, - {"buf_size", INT_PARAM, &buffer.len}, + {"port", INT_PARAM, &port}, + {"ip", STR_PARAM, &ip.s}, + {"buf_size", INT_PARAM, &buffer.len}, + {"post_buf_size", INT_PARAM, &post_buf_size}, {NULL, 0, NULL} }; @@ -87,8 +93,10 @@ static mi_export_t mi_cmds[] = { /** Module exports */ struct module_exports exports = { "httpd", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ NULL, /* exported statistics */ @@ -114,6 +122,11 @@ static int mod_init(void) } } + if (post_buf_size < MIN_POST_BUF_SIZE) { + LM_ERR("post_buf_size should be bigger then %d\n", + MIN_POST_BUF_SIZE); + return -1; + } if (buffer.len == 0) buffer.len = (pkg_mem_size/4)*3; LM_DBG("buf_size=[%d]\n", buffer.len); @@ -137,12 +150,6 @@ int destroy(void) } -const char *httpd_lookup_arg(void *connection, const char *key) -{ - return MHD_lookup_connection_value((struct MHD_Connection *)connection, - MHD_GET_ARGUMENT_KIND, key); -} - int httpd_register_httpdcb(const char *module, str *http_root, httpd_acces_handler_cb f1, httpd_flush_data_cb f2, @@ -219,6 +226,7 @@ static struct mi_root* mi_list_root_path(struct mi_root* cmd, void* param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return NULL; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; while(cb) { node = add_mi_node_child(rpl, 0, "http_root", 9, cb->http_root->s, cb->http_root->len); diff --git a/modules/httpd/httpd_load.h b/modules/httpd/httpd_load.h index af0a4d79eac..1f8e1ae1d75 100644 --- a/modules/httpd/httpd_load.h +++ b/modules/httpd/httpd_load.h @@ -25,8 +25,18 @@ */ -#ifndef _MI_HTTP_HTTPD_LOAD_H -#define _MI_HTTP_HTTPD_LOAD_H +#ifndef HTTPD_HTTPD_LOAD_H +#define HTTPD_HTTPD_LOAD_H + + +#define HTTPD_UNKNOWN_CONTENT_LEN -1 + +enum HTTPD_CONTENT_TYPE { + HTTPD_UNKNOWN_CNT_TYPE = -1, + HTTPD_STD_CNT_TYPE = 0, + HTTPD_TEXT_XML_CNT_TYPE, + HTTPD_APPLICATION_JSON_CNT_TYPE +}; /** * A client has requested the given url using the given method ("GET", @@ -110,8 +120,10 @@ struct httpd_cb { -const char *lookup_arg(void *connection, const char *key); -typedef const char *(*lookup_arg_f)(void *connection, const char *key); +void lookup_arg(void *connection, const char *key, + void *con_cls, str *val); +typedef void (*lookup_arg_f)(void *connection, const char *key, + void *con_cls, str *val); int register_httpdcb(const char *mod, str *root_path, httpd_acces_handler_cb f1, @@ -128,6 +140,8 @@ typedef struct httpd_api { }httpd_api_t; +void httpd_lookup_arg(void *connection, const char *key, + void *con_cls, str *val); typedef int(*load_httpd_f)(httpd_api_t *api); int httpd_bind(httpd_api_t *api); diff --git a/modules/httpd/httpd_proc.c b/modules/httpd/httpd_proc.c index bb32ee086e9..e6c89d96867 100644 --- a/modules/httpd/httpd_proc.c +++ b/modules/httpd/httpd_proc.c @@ -47,21 +47,114 @@ #include "../../sr_module.h" #include "../../str.h" #include "../../ut.h" +#include "../../sliblist.h" #include "httpd_load.h" extern int port; extern str ip; extern str buffer; +extern int post_buf_size; extern struct httpd_cb *httpd_cb_list; static const str MI_HTTP_U_URL = str_init("" "Unable to parse URL!"); +static const str MI_HTTP_U_METHOD = str_init("" +"Unsupported HTTP request!"); +static const str MI_HTTP_U_CNT_TYPE = str_init("" +"Unsupported Content-Type!"); + +/** + * Data structure to store inside elents of slinkedl_list list. + */ +typedef struct str_str { + str key; + str val; +} str_str_t; + #ifdef LIBMICROHTTPD struct MHD_Daemon *dmn; + +struct post_request { + struct MHD_PostProcessor *pp; + int status; + enum HTTPD_CONTENT_TYPE content_type; + enum HTTPD_CONTENT_TYPE accept_type; + int content_len; + slinkedl_list_t *p_list; +}; #endif + +/** + * Allocator for the slinkedl_list list. + */ +void *httpd_alloc(size_t size) { return pkg_malloc(size); } + +/** + * De-allocator for the slinkedl_list list. + * + * @param ptr The pointer to memory that we want to free up. + */ +void httpd_free(void *ptr) { pkg_free(ptr); return; } + +/** + * Function to extract data from an element of a slinkedl_list list. + * + * @param e_data Pointer to the data stored by the current + * element being processed (a str_str_t type). + * @param data Pointer to the key idetifier. + * @param r_data Pointer where the value that we are looking for + */ +int httpd_get_val(void *e_data, void *data, void *r_data) +{ + str_str_t *kv = (str_str_t*)e_data; + str *val = (str*)r_data; + if (kv==NULL) { + LM_ERR("null data\n"); + } else { + if (strncmp(kv->key.s, data, kv->key.len)==0) { + val->s = kv->val.s; + val->len = kv->val.len; + LM_DBG("DATA=[%p] [%p][%p] [%.*s]->[%.*s]\n", + kv, kv->key.s, kv->val.s, + kv->key.len, kv->key.s, + kv->val.len, kv->val.s); + return 1; + } + } + return 0; +} + +/** + * Function to print data stored in slinkedl_list list elemnts. + * For debugging purposes only. + */ +/* +int httpd_print_data(void *e_data, void *data, void *r_data) +{ + str_str_t *kv = (str_str_t*)e_data; + if (kv==NULL) { + LM_ERR("null data\n"); + } else { + LM_DBG("data=[%p] [%p][%p] [%.*s]->[%.*s]\n", + kv, kv->key.s, kv->val.s, + kv->key.len, kv->key.s, + kv->val.len, kv->val.s); + } + return 0; +} +*/ + + +/** + * Function that retrieves the callback function that should + * handle the current request. + * + * @param url Pointer to the root part of the HTTP URL. + * @return The callback function to handle the HTTP request. + */ struct httpd_cb *get_httpd_cb(const char *url) { int url_len; @@ -96,8 +189,201 @@ struct httpd_cb *get_httpd_cb(const char *url) return NULL; } - #ifdef LIBMICROHTTPD +/** + * Handle regular POST data. + * + */ +static int post_iterator (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *value, uint64_t off, size_t size) +{ + int key_len; + struct post_request *pr; + str_str_t *kv; + char *p; + + LM_DBG("post_iterator: cls=%p, kind=%d key=[%p]->'%s'" + " filename='%s' content_type='%s' transfer_encoding='%s'" + " value=[%p]->'%s' off=%llu size=%zu\n", + cls, kind, key, key, + filename, content_type, transfer_encoding, + value, value, (long long unsigned int)off, size); + + + pr = (struct post_request*)cls; + if (pr==NULL) { + LM_CRIT("corrupted data: null cls\n"); + pr->status = -1; return MHD_NO; + } + + if (off!=0) { + if (size==0) { + /* This is the last call post_iterator call + * before destroying the post_processor. */ + return MHD_YES; + } else { + LM_ERR("Trunkated data: post_iterator buffer to small!" + " Increase post_buf_size value\n"); + pr->status = -1; return MHD_NO; + } + } + + if (key) { + key_len = strlen(key); + if (key_len==0) { + LM_ERR("empty key\n"); + pr->status = -1; return MHD_NO; + } + } else { + LM_ERR("NULL key\n"); + pr->status = -1; return MHD_NO; + } + + if (filename) { + LM_ERR("we don't support file uploading\n"); + pr->status = -1; return MHD_NO; + } + if (content_type) { + LM_ERR("we don't support content_type\n"); + pr->status = -1; return MHD_NO; + } + if (transfer_encoding) { + LM_ERR("we don't support transfer_encoding\n"); + pr->status = -1; return MHD_NO; + } + + LM_DBG("[%.*s]->[%.*s]\n", key_len, key, (int)size, value); + + kv = (str_str_t*)slinkedl_append(pr->p_list, + sizeof(str_str_t) + key_len + size); + p = (char*)(kv + 1); + kv->key.len = key_len; kv->key.s = p; + memcpy(p, key, key_len); + p += key_len; + kv->val.len = size; kv->val.s = p; + memcpy(p, value, size); + LM_DBG("inserting element pr=[%p] pp=[%p] p_list=[%p]\n", + pr, pr->pp, pr->p_list); + + return MHD_YES; +} + +/** + * Lookup for HTTP headers. + * + * @param cls Pointer to store return data. + * @param kind Specifies the source of the key-value pairs that + * we are looking for in the HTTP protocol. + * @param key The key. + * @param value The value. + * + * @return MHD_YES to continue iterating, + * MHD_NO to abort the iteration. + */ +int getConnectionHeader(void *cls, enum MHD_ValueKind kind, + const char *key, const char *value) +{ + struct post_request *pr = (struct post_request*)cls; + str content_length; + unsigned int len; + + if (cls == NULL) { + LM_ERR("Unable to store return data\n"); + return MHD_NO; + } + if (kind != MHD_HEADER_KIND) { + LM_ERR("Got kind != MHD_HEADER_KIND\n"); + return MHD_NO; + } + + if (strcasecmp("Accept", key) == 0) { + LM_DBG("Accept=%s\n", value); + if (strcasecmp("text/xml", value) == 0) + pr->accept_type = HTTPD_TEXT_XML_CNT_TYPE; + else if (strcasecmp("application/json", value) == 0) + pr->accept_type = HTTPD_APPLICATION_JSON_CNT_TYPE; + else + pr->accept_type = HTTPD_UNKNOWN_CNT_TYPE; + return MHD_YES; + } + if (strcasecmp("Content-Type", key) == 0) { + LM_DBG("Content-Type=%s\n", value); + if (strcasecmp("text/xml", value) == 0) + pr->content_type = HTTPD_TEXT_XML_CNT_TYPE; + else if (strcasecmp("application/json", value) == 0) + pr->content_type = HTTPD_APPLICATION_JSON_CNT_TYPE; + else + pr->content_type = HTTPD_UNKNOWN_CNT_TYPE; + goto done; + } + if (strcasecmp("Content-Length", key) == 0) { + LM_DBG("Content-Length=%s\n", value); + content_length.s = (char*)value; + content_length.len = strlen(value); + if (str2int(&content_length, &len)<0) { + LM_ERR("got bogus Content-Length=%s\n", value); + pr->content_len = HTTPD_UNKNOWN_CONTENT_LEN; + } else + pr->content_len = len; + goto done; + } + + return MHD_YES; + +done: + if (pr->content_type && pr->content_len) + return MHD_NO; + else + return MHD_YES; +} + + +/** + * Performs lookup values for given keys. + * For GET requests, we will use the libmicrohttpd's + * internal API: MHD_lookup_connection_value(). + * For POST requests, we will retrieve the value from + * the slinkedl_list that was created and populated by + * the post_iterator(). + * + * @param connection Pointer to the MHD_Connection + * @param key The key for which we need to retrieve + * the value. + * @param con_cls This is a pointer to the slinkedl_list + * that was passed back and forth via + * several callback between the application + * and the libmicrohttpd library. + * @param val Pointer to the value that we are looking + * for. + */ +void httpd_lookup_arg(void *connection, const char *key, + void *con_cls, str *val) +{ + slinkedl_list_t *list = (slinkedl_list_t*)con_cls; + + if (val) { + if (list==NULL) { + val->s = (char *)MHD_lookup_connection_value( + (struct MHD_Connection *)connection, + MHD_GET_ARGUMENT_KIND, key); + if (val->s) val->len = strlen(val->s); + else val->len = 0; + } else { + slinkedl_traverse(list, &httpd_get_val, (void *)key, val); + } + } else { + LM_ERR("NULL holder for requested val\n"); + } + + return; +} + + int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, @@ -105,29 +391,230 @@ int answer_to_connection (void *cls, struct MHD_Connection *connection, { str page = {NULL, 0}; struct MHD_Response *response; - int ret = 0; + int ret; void *async_data = NULL; struct httpd_cb *cb; const char *normalised_url; + struct post_request *pr; + str_str_t *kv; + char *p; + int cnt_type = HTTPD_STD_CNT_TYPE; + int accept_type = HTTPD_STD_CNT_TYPE; LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, " - "versio=%s, upload_data[%d]=%p, con_cls=%p\n", + "versio=%s, upload_data[%zu]=%p, *con_cls=%p\n", cls, connection, url, method, version, - (int)*upload_data_size, upload_data, con_cls); - - cb = get_httpd_cb(url); - if (cb) { - normalised_url = &url[cb->http_root->len+1]; - LM_DBG("normalised_url=[%s]\n", normalised_url); - cb->callback(cls, (void*)connection, - normalised_url, - method, version, - upload_data, upload_data_size, con_cls, - &buffer, &page); - } else { - page = MI_HTTP_U_URL; + *upload_data_size, upload_data, *con_cls); + + pr = *con_cls; + if(pr == NULL){ + pr = pkg_malloc(sizeof(struct post_request)); + if(pr==NULL) { + LM_ERR("oom while allocating post_request structure\n"); + return MHD_NO; + } + memset(pr, 0, sizeof(struct post_request)); + pr->p_list = slinkedl_init(&httpd_alloc, &httpd_free); + if (pr->p_list==NULL) { + LM_ERR("oom while allocating list\n"); + return MHD_NO; + } + *con_cls = pr; + pr = NULL; + } + + if(strncmp(method, "POST", 4)==0) { + if(pr == NULL){ + pr = *con_cls; + LM_DBG("running MHD_create_post_processor\n"); + pr->pp = MHD_create_post_processor(connection, + post_buf_size, + &post_iterator, + pr); + if(pr->pp==NULL) { + if (*upload_data_size == 0) { + /* We need to wait for morte data before + * handling the POST request */ + return MHD_YES; + } + LM_DBG("NOT a regular POST :o)\n"); + if (pr->content_type==0 && pr->content_len==0) + MHD_get_connection_values(connection, MHD_HEADER_KIND, + &getConnectionHeader, pr); + if (pr->content_type<=0 || pr->content_len<=0) { + LM_ERR("got a bogus request\n"); + return MHD_NO; + } + if (*upload_data_size != pr->content_len) { + /* For now, we don't support large POST with truncated data */ + LM_ERR("got a truncated POST request\n"); + return MHD_NO; + } + LM_DBG("got ContentType [%d] with len [%d]: %.*s\\n", + pr->content_type, pr->content_len, + (int)*upload_data_size, upload_data); + /* Here we save data. */ + switch (pr->content_type) { + case HTTPD_TEXT_XML_CNT_TYPE: + case HTTPD_APPLICATION_JSON_CNT_TYPE: + /* Save the entire body as 'body' */ + kv = (str_str_t*)slinkedl_append(pr->p_list, + sizeof(str_str_t) + 1 + + *upload_data_size); + p = (char*)(kv + 1); + kv->key.len = 1; kv->key.s = p; + memcpy(p, "1", 1); + p += 1; + kv->val.len = *upload_data_size; + kv->val.s = p; + memcpy(p, upload_data, *upload_data_size); + break; + default: + LM_ERR("Unhandled data for ContentType [%d]\n", + pr->content_type); + return MHD_NO; + } + /* Mark the fact that we consumed all data */ + *upload_data_size = 0; + return MHD_YES; + } + + LM_DBG("pr=[%p] pp=[%p] p_list=[%p]\n", + pr, pr->pp, pr->p_list); + return MHD_YES; + } else { + if (pr->pp==NULL) { + if (*upload_data_size == 0) { + if (pr->content_type==HTTPD_TEXT_XML_CNT_TYPE) + cnt_type = HTTPD_TEXT_XML_CNT_TYPE; + if (pr->content_type==HTTPD_APPLICATION_JSON_CNT_TYPE) + cnt_type = HTTPD_APPLICATION_JSON_CNT_TYPE; + *con_cls = pr->p_list; + cb = get_httpd_cb(url); + if (cb) { + normalised_url = &url[cb->http_root->len+1]; + LM_DBG("normalised_url=[%s]\n", normalised_url); + cb->callback(cls, (void*)connection, + normalised_url, + method, version, + upload_data, upload_data_size, con_cls, + &buffer, &page); + } else { + page = MI_HTTP_U_URL; + } + /* slinkedl_traverse(pr->p_list, + &httpd_print_data, NULL, NULL); */ + slinkedl_list_destroy(*con_cls); + pkg_free(pr); *con_cls = pr = NULL; + goto send_response; + } + LM_DBG("NOT a regular POST :o)\n"); + if (pr->content_type==0 && pr->content_len==0) + MHD_get_connection_values(connection, MHD_HEADER_KIND, + &getConnectionHeader, pr); + if (pr->content_type<=0 || pr->content_len<=0) { + LM_ERR("got a bogus request\n"); + return MHD_NO; + } + if (*upload_data_size != pr->content_len) { + /* For now, we don't support large POST with truncated data */ + LM_ERR("got a truncated POST request\n"); + return MHD_NO; + } + LM_DBG("got ContentType [%d] with len [%d]: %.*s\\n", + pr->content_type, pr->content_len, + (int)*upload_data_size, upload_data); + /* Here we save data. */ + switch (pr->content_type) { + case HTTPD_TEXT_XML_CNT_TYPE: + case HTTPD_APPLICATION_JSON_CNT_TYPE: + /* Save the entire body as 'body' */ + kv = (str_str_t*)slinkedl_append(pr->p_list, + sizeof(str_str_t) + 1 + + *upload_data_size); + p = (char*)(kv + 1); + kv->key.len = 1; kv->key.s = p; + memcpy(p, "1", 1); + p += 1; + kv->val.len = *upload_data_size; + kv->val.s = p; + memcpy(p, upload_data, *upload_data_size); + break; + default: + LM_ERR("Unhandled data for ContentType [%d]\n", + pr->content_type); + return MHD_NO; + } + /* Mark the fact that we consumed all data */ + *upload_data_size = 0; + return MHD_YES; + } + LM_DBG("running MHD_post_process: " + "pp=%p status=%d upload_data_size=%zu\n", + pr->pp, pr->status, *upload_data_size); + if (pr->status<0) { + slinkedl_list_destroy(pr->p_list); + pr->p_list = NULL; + /* FIXME: + * It might be better to reply with an error + * instead of resetting the connection via MHD_NO */ + return MHD_NO; + } + ret =MHD_post_process(pr->pp, upload_data, *upload_data_size); + LM_DBG("ret=%d upload_data_size=%zu\n", ret, *upload_data_size); + if(*upload_data_size != 0) { + *upload_data_size = 0; + return MHD_YES; + } + + LM_DBG("running MHD_destroy_post_processor: " + "pr=[%p] pp=[%p] p_list=[%p]\n", + pr, pr->pp, pr->p_list); + MHD_destroy_post_processor(pr->pp); + LM_DBG("done MHD_destroy_post_processor\n"); + /* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */ + *con_cls = pr->p_list; + + cb = get_httpd_cb(url); + if (cb) { + normalised_url = &url[cb->http_root->len+1]; + LM_DBG("normalised_url=[%s]\n", normalised_url); + cb->callback(cls, (void*)connection, + normalised_url, + method, version, + upload_data, upload_data_size, con_cls, + &buffer, &page); + } else { + page = MI_HTTP_U_URL; + } + /* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */ + slinkedl_list_destroy(*con_cls); + pkg_free(pr); *con_cls = pr = NULL; + } + }else if(strncmp(method, "GET", 3)==0) { + pr = *con_cls; + MHD_get_connection_values(connection, MHD_HEADER_KIND, + &getConnectionHeader, pr); + accept_type = pr->accept_type; + pkg_free(pr); *con_cls = pr = NULL; + LM_DBG("accept_type=[%d]\n", accept_type); + cb = get_httpd_cb(url); + if (cb) { + normalised_url = &url[cb->http_root->len+1]; + LM_DBG("normalised_url=[%s]\n", normalised_url); + cb->callback(cls, (void*)connection, + normalised_url, + method, version, + upload_data, upload_data_size, con_cls, + &buffer, &page); + } else { + page = MI_HTTP_U_URL; + } + }else{ + page = MI_HTTP_U_METHOD; } +send_response: if (page.s) { LM_DBG("MHD_create_response_from_data [%p:%d]\n", page.s, page.len); @@ -142,9 +629,19 @@ int answer_to_connection (void *cls, struct MHD_Connection *connection, (void*)async_data, NULL); } + if (cnt_type==HTTPD_TEXT_XML_CNT_TYPE || accept_type==HTTPD_TEXT_XML_CNT_TYPE) + MHD_add_response_header(response, + MHD_HTTP_HEADER_CONTENT_TYPE, + "text/xml; charset=utf-8"); + if (cnt_type==HTTPD_APPLICATION_JSON_CNT_TYPE || accept_type==HTTPD_APPLICATION_JSON_CNT_TYPE) + MHD_add_response_header(response, + MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json"); ret = MHD_queue_response (connection, MHD_HTTP_OK, response); MHD_destroy_response (response); + + return ret; } #endif @@ -162,7 +659,7 @@ void httpd_proc(int rank) /*child's initial settings*/ if (init_mi_child()!=0) { - LM_ERR("failed to init the mi process\n"); + LM_ERR("failed to init the mi child process\n"); return; } @@ -224,7 +721,7 @@ void httpd_proc(int rank) return; break; case EINTR: - LM_WARN("error returned by select: EINTR [%d] " + LM_DBG("failure returned by select: EINTR [%d] " "(Non blocked signal caught)\n", status); break; case EINVAL: diff --git a/modules/identity/README b/modules/identity/README index 3b9473e9448..8c9418f5875 100644 --- a/modules/identity/README +++ b/modules/identity/README @@ -11,7 +11,7 @@ Alexander Christ Copyright © 2007 Alexander Christ, Cologne University of Applied Sciences Revision History - Revision $Revision$ $Date: 2007-03-29$ + Revision $Revision: 5901 $ $Date: 2007-03-29$ __________________________________________________________ Table of Contents diff --git a/modules/identity/identity.c b/modules/identity/identity.c index e78c1db92b3..d5e1dbc8b4d 100644 --- a/modules/identity/identity.c +++ b/modules/identity/identity.c @@ -1,7 +1,7 @@ /* *$Id$ * - * Copyright (C) 2007 Alexander Christ, + * Copyright (C) 2007 Alexander Christ, * Cologne University of Applied Sciences * Copyright (C) 2009 Voice Sistem SRL * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -31,15 +31,15 @@ */ -/* Some functions are based on examples of [VIE-02]. +/* Some functions are based on examples of [VIE-02]. * You can download these examples at * http://www.opensslbook.com/code.html. * - * [VIE-02] Viega, John; Messier, Matt; Chandra Pravir: Network Security + * [VIE-02] Viega, John; Messier, Matt; Chandra Pravir: Network Security * with OpenSSL. * First Edition, Beijing, ... : O'Reilly, 2002 * - * The function "static STACK_OF(X509) * load_untrusted(char * certfile)" is + * The function "static STACK_OF(X509) * load_untrusted(char * certfile)" is * based on the function"static STACK_OF(X509) *load_untrusted(char *certfile)" * of the openssl sources. (apps/verify.c, version 0.9.7e, line 290) * @@ -54,7 +54,7 @@ -#include +#include #define _XOPEN_SOURCE 600 /* glibc2 on linux, bsd */ #define _XOPEN_SOURCE_EXTENDED 1 /* solaris */ @@ -73,26 +73,26 @@ #include #include -#include +#include #include #include #include #include #include #include -#include +#include #include #include #include "../../sr_module.h" -#include "../../pvar.h" -#include "../../data_lump.h" -#include "../../mem/mem.h" -#include "../../parser/parse_hname2.h" -#include "../../parser/contact/contact.h" -#include "../../parser/contact/parse_contact.h" -#include "../../parser/parse_from.h" -#include "../../parser/parse_uri.h" +#include "../../pvar.h" +#include "../../data_lump.h" +#include "../../mem/mem.h" +#include "../../parser/parse_hname2.h" +#include "../../parser/contact/contact.h" +#include "../../parser/contact/parse_contact.h" +#include "../../parser/parse_from.h" +#include "../../parser/parse_uri.h" #include "identity.h" @@ -103,7 +103,7 @@ static char * authCert = NULL; /* private key of authentication service */ static char * privKey = NULL; -/* uri of Identity-Info header field, for authentication +/* uri of Identity-Info header field, for authentication * service NOT for verifier */ static char * certUri = NULL; /* path where the verifier can find the certificates */ @@ -153,12 +153,14 @@ static param_export_t params[]={ /** module exports */ struct module_exports exports= { - "identity", /* name */ + "identity", /* name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* parameters to be exportet */ - 0, /* exported statistics */ + 0, /* exported statistics */ 0, /* exported MI functions */ 0, /* exported pseudo-variables */ 0, /* local processes */ @@ -258,7 +260,7 @@ static void mod_destroy(void) if(store) { - X509_STORE_free(store); + X509_STORE_free(store); } if(verify_ctx) @@ -283,7 +285,7 @@ static void mod_destroy(void) */ static int authservice_(struct sip_msg* msg, char* str1, char* str2) { - time_t dateHFValue = -1; + time_t dateHFValue = -1; int retval = 0; char dateHF[MAX_TIME] = "\0"; long dateDelta = -1; @@ -336,7 +338,7 @@ static int authservice_(struct sip_msg* msg, char* str1, char* str2) } }*/ - + if(!addIdentity(dateHF, msg)) { LM_ERR("addIdentity failed\n"); @@ -354,19 +356,19 @@ static int authservice_(struct sip_msg* msg, char* str1, char* str2) /* verifier -return value: -438: You should send a 438-reply. +return value: -438: You should send a 438-reply. -437: You should send a 437-reply. -436: You should send a 436-reply. -428: You should send a 428-reply. -3: Error verifying Date header field. -2: Authentication service is not authoritative. -1: An error occured. - 1: verification OK + 1: verification OK */ static int verifier_(struct sip_msg* msg, char* str1, char* str2) { char identityHF[MAX_IDENTITY] = "\0"; - X509 * cert = NULL; + X509 * cert = NULL; int retval = -1; STACK_OF(X509) * certchain = NULL; @@ -387,12 +389,12 @@ static int verifier_(struct sip_msg* msg, char* str1, char* str2) return -1; } - if(!getCert(&cert, &certchain, msg)) + if(!getCert(&cert, &certchain, msg)) { return -436; } - if(!validateCert(cert, certchain)) + if(!validateCert(cert, certchain)) { X509_free(cert); sk_X509_pop_free(certchain, X509_free); @@ -400,25 +402,25 @@ static int verifier_(struct sip_msg* msg, char* str1, char* str2) } sk_X509_pop_free(certchain, X509_free); - if(!checkAuthority(cert, msg)) + if(!checkAuthority(cert, msg)) { X509_free(cert); return -2; } - if(!checkSign(cert, identityHF, msg)) + if(!checkSign(cert, identityHF, msg)) { X509_free(cert); return -438; } - if(!checkDate(cert, msg)) + if(!checkDate(cert, msg)) { X509_free(cert); return -3; } - X509_free(cert); + X509_free(cert); return 1; } @@ -444,9 +446,9 @@ static time_t my_timegm(struct tm *tm) /* reads the Date header field of msg return value: -1: error 0: Date header field does not exist - 1: success + 1: success - dateHF must point to an array with at least MAX_TIME bytes + dateHF must point to an array with at least MAX_TIME bytes */ static int getDate(char * dateHF, time_t * dateHFValue, struct sip_msg * msg) { @@ -494,7 +496,7 @@ static int getDate(char * dateHF, time_t * dateHFValue, struct sip_msg * msg) } -/* adds a Date header field to msg +/* adds a Date header field to msg return value: 0: error 1: success */ @@ -502,9 +504,9 @@ static int addDate(char * dateHF, time_t * dateHFValue, struct sip_msg * msg) { #define DATE_HDR_S "Date: " #define DATE_HDR_L (sizeof(DATE_HDR_S)-1) - char* buf; + char* buf; size_t len = 0; - struct tm * bd_time = NULL; + struct tm * bd_time = NULL; if(!dateHF || !dateHFValue || !msg) { @@ -515,13 +517,13 @@ static int addDate(char * dateHF, time_t * dateHFValue, struct sip_msg * msg) *dateHFValue = time(0); bd_time = gmtime(dateHFValue); - if(!bd_time) + if(!bd_time) { LM_ERR("gmtime failed\n"); return 0; } - len=strftime(dateHF, MAX_TIME, DATE_FORMAT, bd_time); + len=strftime(dateHF, MAX_TIME, DATE_FORMAT, bd_time); if (len>MAX_TIME-1 || len==0) { LM_ERR("unexpected time length\n"); @@ -549,7 +551,7 @@ static int addDate(char * dateHF, time_t * dateHFValue, struct sip_msg * msg) /* calculates | now - dateHFValue | return value: result, - -1: if an error occured + -1: if an error occured */ static long getDateDelta(time_t dateHFValue) { @@ -586,16 +588,16 @@ static int authCertMatchesDate(time_t dateHFValue) return value: 1: success 0: else -annotation: This function is based on the function search_body_f of the +annotation: This function is based on the function search_body_f of the Textops module. static int addContentLength(struct sip_msg * msg) { str body; char * tmp = NULL; char buf[MAX_CONTENT_LENGTH] = "\0"; - + body.s = get_body(msg); - if (body.s == 0) + if (body.s == 0) { //body does not exist body.len = 0; @@ -605,20 +607,20 @@ static int addContentLength(struct sip_msg * msg) //body exists body.len = msg->len -(int)(body.s-msg->buf); } - - + + snprintf(buf, MAX_CONTENT_LENGTH, "Content-Length: %i\r\n", body.len); buf[MAX_CONTENT_LENGTH - 1] = '\0'; - + tmp = buf; //we need a char * for &-operation - + if(add_header_fixup( (void**) &tmp, 1) != 0) { LOG(L_ERR, "idenity: addContentLength: ERROR: add_header_fixup failed\n"); return 0; } - - if(append_hf_1(msg, tmp, 0) != 1) + + if(append_hf_1(msg, tmp, 0) != 1) { pkg_free(tmp); LOG(L_ERR, "identity: addContentLength: ERROR: append_hf_1 failed\n"); @@ -626,14 +628,14 @@ static int addContentLength(struct sip_msg * msg) } pkg_free(tmp); return 1; - + }*/ /* builds digest string of msg Return value: 1: success 0: else - digestString must point to an array with at least MAX_DIGEST bytes + digestString must point to an array with at least MAX_DIGEST bytes */ static int makeDigestString(char * digestString, char * dateHF, struct sip_msg * msg) @@ -804,7 +806,7 @@ static int makeDigestString(char * digestString, char * dateHF, *(digestString+(l++)) = 0; } - LM_DBG("Digest-String=>%s<\n", digestString); + LM_DBG("Digest-String=>%s<\n", digestString); return 1; } @@ -817,10 +819,10 @@ static int addIdentity(char * dateHF, struct sip_msg * msg) { #define IDENTITY_HDR_S "Identity: \"" #define IDENTITY_HDR_L (sizeof(IDENTITY_HDR_S)-1) - EVP_MD_CTX ctx; + EVP_MD_CTX ctx; unsigned int siglen = 0; int b64len = 0; - unsigned char * sig = NULL; + unsigned char * sig = NULL; char digestString[MAX_DIGEST]; str buf; @@ -910,7 +912,7 @@ static int addIdentityInfo(struct sip_msg * msg) LM_ERR("failed to add Identity-Info header\n"); return 0; } - + return 1; } @@ -930,7 +932,7 @@ static int getIdentityHF(char * identityHF, struct sip_msg * msg) LM_ERR("identityHF or msg not set\n"); return -1; } - + identity = get_header_by_static_name(msg, "Identity"); if (!identity) { @@ -961,7 +963,7 @@ static int getCert(X509 ** certp, STACK_OF(X509) ** certchainp, struct sip_msg * msg) { struct hdr_field * identityInfo = NULL; - int uriLen = 0; + int uriLen = 0; char * end = NULL; char * begin = NULL; char uri[MAX_IDENTITY_INFO] = "\0"; @@ -976,7 +978,7 @@ static int getCert(X509 ** certp, STACK_OF(X509) ** certchainp, } identityInfo = get_header_by_static_name(msg, "Identity-Info"); - if (!identityInfo) + if (!identityInfo) { /* Identity-Info header field does not exist */ return 0; @@ -1068,7 +1070,7 @@ static int getCert(X509 ** certp, STACK_OF(X509) ** certchainp, Return value: 1: success, cert is valid 0: else - Annotation: This function is based on example 10-7 of [VIE-02]. + Annotation: This function is based on example 10-7 of [VIE-02]. */ static int validateCert(X509 * cert, STACK_OF(X509) * certchain) { @@ -1080,12 +1082,12 @@ static int validateCert(X509 * cert, STACK_OF(X509) * certchain) return 0; } - /* X509_STORE_CTX_init did not return an error condition + /* X509_STORE_CTX_init did not return an error condition in prior versions */ #if (OPENSSL_VERSION_NUMBER > 0x00907000L) if(X509_STORE_CTX_init(verify_ctx, store, cert, certchain) != 1) { - X509_STORE_CTX_cleanup(verify_ctx); + X509_STORE_CTX_cleanup(verify_ctx); LM_ERR("Error initializing verification context\n"); return 0; } @@ -1093,8 +1095,8 @@ static int validateCert(X509 * cert, STACK_OF(X509) * certchain) X509_STORE_CTX_init(verify_ctx, store, cert, certchain); #endif - result = X509_verify_cert(verify_ctx); - X509_STORE_CTX_cleanup(verify_ctx); + result = X509_verify_cert(verify_ctx); + X509_STORE_CTX_cleanup(verify_ctx); if(result != 1) { @@ -1106,8 +1108,8 @@ static int validateCert(X509 * cert, STACK_OF(X509) * certchain) } -/* checks whether the signing authentication service is authoritative - for the URI in the From header field. +/* checks whether the signing authentication service is authoritative + for the URI in the From header field. Return value: 1: authentication service is authoritative 0: else Annotation: This function is based on example 5-8 of [VIE-02]. @@ -1168,7 +1170,7 @@ static int checkAuthority(X509 * cert, struct sip_msg * msg) hostname[fromUri.host.len] = '\0'; /* first, check subjectAltName extensions */ - num = X509_get_ext_count(cert); + num = X509_get_ext_count(cert); for(i = 0; i < num; i++) { @@ -1179,7 +1181,7 @@ static int checkAuthority(X509 * cert, struct sip_msg * msg) if(!strcmp(extstr, "subjectAltName")) { - if(!(meth = X509V3_EXT_get(cext))) + if(!(meth = (X509V3_EXT_METHOD*)X509V3_EXT_get(cext))) { LM_ERR("X509V3_EXT_get failed\n"); return 0; @@ -1204,7 +1206,7 @@ static int checkAuthority(X509 * cert, struct sip_msg * msg) for (j = 0; j < sk_CONF_VALUE_num(val); j++) { nval = sk_CONF_VALUE_value(val, j); - + if(!strcmp(nval->name, "DNS")) { /* entry of type dNSName found */ @@ -1220,11 +1222,11 @@ static int checkAuthority(X509 * cert, struct sip_msg * msg) } } - /* if no subjectAltName extension is found, Common Name of subject + /* if no subjectAltName extension is found, Common Name of subject will be checked */ if(foundDNSName == 0) { - X509_NAME_get_text_by_NID(X509_get_subject_name(cert), + X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, tmp, MAX_HOSTNAME); tmp[MAX_HOSTNAME - 1] = '\0'; @@ -1244,16 +1246,16 @@ static int checkAuthority(X509 * cert, struct sip_msg * msg) */ static int checkSign(X509 * cert, char * identityHF, struct sip_msg * msg) { - EVP_PKEY * pubkey = NULL; + EVP_PKEY * pubkey = NULL; char digestString[MAX_DIGEST] = "\0"; - int siglen = -1; - unsigned char * sigbuf = NULL; - int b64len = 0; + int siglen = -1; + unsigned char * sigbuf = NULL; + int b64len = 0; EVP_MD_CTX ctx; int result = 0; char *p; unsigned long err; - + if(!cert || !identityHF || !msg) { LM_ERR("cert or identityHF or msg not set\n"); @@ -1293,8 +1295,8 @@ static int checkSign(X509 * cert, char * identityHF, struct sip_msg * msg) p=strstr(identityHF , "="); siglen-=strspn(p , "="); - EVP_VerifyInit(&ctx, EVP_sha1()); - EVP_VerifyUpdate(&ctx, digestString, strlen(digestString)); + EVP_VerifyInit(&ctx, EVP_sha1()); + EVP_VerifyUpdate(&ctx, digestString, strlen(digestString)); pubkey = X509_get_pubkey(cert); if(!pubkey) @@ -1305,7 +1307,7 @@ static int checkSign(X509 * cert, char * identityHF, struct sip_msg * msg) return 0; } - result = EVP_VerifyFinal(&ctx, sigbuf, siglen, pubkey); + result = EVP_VerifyFinal(&ctx, sigbuf, siglen, pubkey); EVP_PKEY_free(pubkey); EVP_MD_CTX_cleanup(&ctx); @@ -1330,8 +1332,8 @@ static int checkSign(X509 * cert, char * identityHF, struct sip_msg * msg) /* checks the Date header field: - - difference between now and Date header field must be smaller - than +-MAXDATEDELTA_VER + - difference between now and Date header field must be smaller + than +-MAXDATEDELTA_VER - Date header field and validity period of cert must match Return value: 1: OK 0: else @@ -1446,7 +1448,7 @@ static time_t parseX509Date(ASN1_STRING * dateString) } -/* sets authCert_notBefore and authCert_notAfter, checks whether +/* sets authCert_notBefore and authCert_notAfter, checks whether cert is valid now return value: 1: success 0: else @@ -1464,7 +1466,7 @@ static int setAuthCertPeriod(void) return 0; } - authCertX509 = PEM_read_X509(fp, NULL, NULL, NULL); + authCertX509 = PEM_read_X509(fp, NULL, NULL, NULL); if(!authCertX509) { fclose(fp); @@ -1483,7 +1485,7 @@ static int setAuthCertPeriod(void) X509_free(authCertX509); - now = time(0); + now = time(0); if(now == -1) { LM_ERR("time failed\n"); @@ -1566,7 +1568,7 @@ static int readPrivKey(void) /* replaces every forbidden char with a '-'. Only alphanumeric characters, - '_' and '.' are allowed. If the first char is a '.', 0 is returned also. + '_' and '.' are allowed. If the first char is a '.', 0 is returned also. Return value: 1: success 0: else */ @@ -1577,7 +1579,7 @@ static int uri2filename(char * name) return 0; } - if(name[0] == '.') + if(name[0] == '.') { LM_ERR("uri starts with '.'\n"); return 0; @@ -1587,7 +1589,7 @@ static int uri2filename(char * name) { if(!isalnum(*name) && (*name != '_') && (*name != '.')) { - *name = '-'; + *name = '-'; } name++; } @@ -1596,7 +1598,7 @@ static int uri2filename(char * name) } -/* sets verCertWithSlash, verCert is used, If necessary, a '/' is +/* sets verCertWithSlash, verCert is used, If necessary, a '/' is added at the end. Return value: 1: success 0: else @@ -1681,18 +1683,18 @@ static int prepareCertValidation(void) { if(X509_load_crl_file(lookup, crlList, X509_FILETYPE_PEM) < 1) { - /* changed from !=1 to < 1 + /* changed from !=1 to < 1 return value = number of loaded crls */ LM_ERR("Error reading the crlList file\n"); return 0; } - /* enabling verification against CRLs is + /* enabling verification against CRLs is not possible in prior versions */ #if (OPENSSL_VERSION_NUMBER > 0x00907000L) /* set the flags of the store so that CRLs are consulted */ - X509_STORE_set_flags(store, - X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + X509_STORE_set_flags(store, + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); #endif } @@ -1735,8 +1737,8 @@ void seed_prng(void) /* loads a certificate chain return value: STACK_OF(X509) *: on success NULL: else - annotation: This function is based on the function - "static STACK_OF(X509) *load_untrusted(char *certfile)" of the openssl + annotation: This function is based on the function + "static STACK_OF(X509) *load_untrusted(char *certfile)" of the openssl sources. (apps/verify.c, version 0.9.7e, line 290) */ static STACK_OF(X509) * load_untrusted(char * certfile) @@ -1780,7 +1782,7 @@ static STACK_OF(X509) * load_untrusted(char * certfile) X509_INFO_free(xi); } - if(!sk_X509_num(stack)) + if(!sk_X509_num(stack)) { LM_ERR("no certificates in file, %s\n",certfile); sk_X509_free(stack); @@ -1790,7 +1792,7 @@ static STACK_OF(X509) * load_untrusted(char * certfile) end: BIO_free(in); - sk_X509_INFO_free(sk); + sk_X509_INFO_free(sk); return(ret); } @@ -1868,12 +1870,12 @@ static int id_add_header(struct sip_msg* msg, char* s, int len) { struct lump* anchor; - anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0); + anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0); if (!anchor) { LM_ERR("can't get anchor\n"); return -1; } - + if (!insert_new_lump_before(anchor, s, len, 0)) { LM_ERR("can't insert lump\n"); diff --git a/modules/identity/identity.h b/modules/identity/identity.h index 5c55df67e03..d6fbfba3984 100644 --- a/modules/identity/identity.h +++ b/modules/identity/identity.h @@ -1,7 +1,7 @@ /* *$Id$ * - *Copyright (C) 2007 Alexander Christ, + *Copyright (C) 2007 Alexander Christ, * Cologne University of Applied Sciences * * This file is part of openser, a free SIP server. @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -25,9 +25,9 @@ * ------- * 2007-03-29 initial version * 2007-04-06 added GPL copyright, #ifndef ... ; changed MIN macro - * + * */ - + #ifndef _IDENTITY_H_ #define _IDENTITY_H_ @@ -49,7 +49,7 @@ #define HOSTNAME_ILLCHAR "?[" //forbidden characters in certHostname -#define MIN(a, b) ((a < b) ? a : b) +#define MIN(a, b) ((a < b) ? a : b) static int mod_init(void); static void mod_destroy(void); @@ -57,13 +57,13 @@ static void mod_destroy(void); static int authservice_(struct sip_msg* msg, char* str1, char* str2); static int verifier_(struct sip_msg* msg, char* str1, char* str2); static int getDate(char * dateHF, time_t * dateHFValue, struct sip_msg * msg); -static int addDate(char * dateHF, time_t * dateHFValue, struct sip_msg * msg); +static int addDate(char * dateHF, time_t * dateHFValue, struct sip_msg * msg); static long getDateDelta(time_t dateHFValue); static int authCertMatchesDate(time_t dateHFValue); static int makeDigestString(char * digestString, char * dateHF, struct sip_msg * msg); -static int addIdentity(char * dateHF, struct sip_msg * msg); +static int addIdentity(char * dateHF, struct sip_msg * msg); static int addIdentityInfo(struct sip_msg * msg); -static int getIdentityHF(char * identityHF, struct sip_msg * msg); +static int getIdentityHF(char * identityHF, struct sip_msg * msg); static int getCert(X509 ** certp, STACK_OF(X509) ** certchainp, struct sip_msg * msg); static int validateCert(X509 * cert, STACK_OF(X509) * certchain); static int checkAuthority(X509 * cert, struct sip_msg * msg); diff --git a/modules/imc/README b/modules/imc/README index 3e1fd5eec45..fc0a9d62aca 100644 --- a/modules/imc/README +++ b/modules/imc/README @@ -12,8 +12,7 @@ Anca-Maria Vamanu Copyright © 2006-2008 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/imc/imc.c b/modules/imc/imc.c index 5dc47a8e19e..16319246503 100644 --- a/modules/imc/imc.c +++ b/modules/imc/imc.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -129,13 +129,23 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; - +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /** module exports */ struct module_exports exports= { "imc", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported commands */ params, /* exported parameters */ #ifdef STATISTICS @@ -164,12 +174,12 @@ int add_from_db(void) db_val_t mquery_vals[2]; db_res_t *r_res= NULL; db_res_t *m_res= NULL; - db_row_t *m_row = NULL, *r_row = NULL; + db_row_t *m_row = NULL, *r_row = NULL; db_val_t *m_row_vals, *r_row_vals = NULL; str name, domain; imc_room_p room = NULL; int er_ret = -1; - + rq_result_cols[0] = &imc_col_name; rq_result_cols[1] = &imc_col_domain; rq_result_cols[2] = &imc_col_flag; @@ -181,7 +191,7 @@ int add_from_db(void) mquery_cols[0] = &imc_col_room; mquery_vals[0].type = DB_STR; mquery_vals[0].nul = 0; - + if(imc_dbf.use_table(imc_db, &rooms_table)< 0) { LM_ERR("use_table failed\n"); @@ -208,22 +218,22 @@ int add_from_db(void) /*add rooms*/ r_row = &r_res->rows[i]; r_row_vals = ROW_VALUES(r_row); - + name.s = r_row_vals[0].val.str_val.s; name.len = strlen(name.s); - + domain.s = r_row_vals[1].val.str_val.s; domain.len = strlen(domain.s); - + flag = r_row_vals[2].val.int_val; - + room = imc_add_room(&name, &domain, flag); if(room == NULL) { LM_ERR("failed to add room\n "); goto error; - } - + } + /* add members */ if(imc_dbf.use_table(imc_db, &members_table)< 0) { @@ -232,8 +242,8 @@ int add_from_db(void) } mquery_vals[0].val.str_val= room->uri; - - if(imc_dbf.query(imc_db, mquery_cols, 0, mquery_vals, mq_result_cols, + + if(imc_dbf.query(imc_db, mquery_cols, 0, mquery_vals, mq_result_cols, 1, 3, 0, &m_res)< 0) { LM_ERR("failed to querry table\n"); @@ -250,15 +260,15 @@ int add_from_db(void) { m_row = &m_res->rows[j]; m_row_vals = ROW_VALUES(m_row); - + name.s = m_row_vals[0].val.str_val.s; name.len = strlen(name.s); - + domain.s = m_row_vals[1].val.str_val.s; domain.len = strlen(domain.s); - + flag = m_row_vals[2].val.int_val; - + LM_DBG("adding memeber: [name]=%.*s [domain]=%.*s" " in [room]= %.*s\n",name.len, name.s, domain.len,domain.s, room->uri.len, room->uri.s); @@ -269,7 +279,7 @@ int add_from_db(void) LM_ERR("failed to adding member\n "); goto error; } - imc_release_room(room); + imc_release_room(room); } if(m_res) @@ -290,7 +300,7 @@ int add_from_db(void) LM_ERR("failed to delete information from db\n"); goto error; } - + if(imc_dbf.use_table(imc_db, &rooms_table)< 0) { LM_ERR("use table failed\n "); @@ -304,12 +314,12 @@ int add_from_db(void) } if(r_res) - { + { imc_dbf.free_result(imc_db, r_res); r_res = NULL; } if(m_res) - { + { imc_dbf.free_result(imc_db, m_res); m_res = NULL; } @@ -331,7 +341,7 @@ int add_from_db(void) imc_release_room(room); return er_ret; -} +} static int mod_init(void) @@ -364,7 +374,7 @@ static int mod_init(void) /* binding to mysql module */ init_db_url( db_url , 0 /*cannot be null*/); LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len, db_url.s); - + if (db_bind_mod(&db_url, &imc_dbf)) { LM_DBG("database module not found\n"); @@ -383,7 +393,7 @@ static int mod_init(void) LM_ERR("failed to get information from db\n"); return -1; } - + /* load TM API */ if (load_tm_api(&tmb)!=0) { LM_ERR("unable to load tm api\n"); @@ -391,11 +401,11 @@ static int mod_init(void) } imc_cmd_start_char = imc_cmd_start_str.s[0]; - + if(imc_db) imc_dbf.close(imc_db); imc_db = NULL; - + return 0; } @@ -403,7 +413,7 @@ static int mod_init(void) * child init */ static int child_init(int rank) -{ +{ if (imc_dbf.init==0) { LM_ERR("database not bound\n"); @@ -453,15 +463,15 @@ static int imc_manager(struct sip_msg* msg, char *str1, char *str2) LM_ERR("failed to parse r-uri\n"); goto error; } - + pto_uri=&msg->parsed_uri; - + if(parse_from_header(msg)<0) { - LM_ERR("failed to parse From header\n"); + LM_ERR("failed to parse From header\n"); goto error; } - pfrom = (struct to_body*)msg->from->parsed; + pfrom = (struct to_body*)msg->from->parsed; if(parse_uri(pfrom->uri.s, pfrom->uri.len, &from_uri)<0){ LM_ERR("failed to parse From URI\n"); goto error; @@ -558,7 +568,7 @@ static int imc_manager(struct sip_msg* msg, char *str1, char *str2) goto error; } } - + goto done; } @@ -573,7 +583,7 @@ static int imc_manager(struct sip_msg* msg, char *str1, char *str2) error: - return -1; + return -1; } /** @@ -588,20 +598,20 @@ void destroy(void) db_val_t mq_vals[4]; db_key_t rq_cols[4]; db_val_t rq_vals[4]; - + LM_DBG("destroy module ...\n"); - + if(imc_db==NULL) goto done; mq_cols[0] = &imc_col_username; mq_vals[0].type = DB_STR; mq_vals[0].nul = 0; - + mq_cols[1] = &imc_col_domain; mq_vals[1].type = DB_STR; mq_vals[1].nul = 0; - + mq_cols[2] = &imc_col_flag; mq_vals[2].type = DB_INT; mq_vals[2].nul = 0; @@ -614,7 +624,7 @@ void destroy(void) rq_cols[0] = &imc_col_name; rq_vals[0].type = DB_STR; rq_vals[0].nul = 0; - + rq_cols[1] = &imc_col_domain; rq_vals[1].type = DB_STR; rq_vals[1].nul = 0; @@ -623,10 +633,10 @@ void destroy(void) rq_vals[2].type = DB_INT; rq_vals[2].nul = 0; - for(i=0; iname; @@ -661,7 +671,7 @@ void destroy(void) if(imc_dbf.insert(imc_db, mq_cols, mq_vals, 4)<0) { - LM_ERR("failed to insert into table imc_rooms\n"); + LM_ERR("failed to insert into table imc_rooms\n"); return; } member = member->next; @@ -690,8 +700,9 @@ static struct mi_root* imc_mi_list_rooms(struct mi_root* cmd_tree, void* param) if(rpl_tree == NULL) return 0; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; - for(i=0; imembers->uri.s, irp->members->uri.len); if(attr == NULL) goto error; - + irp = irp->next; } lock_release(&_imc_htable[i].lock); @@ -748,7 +759,7 @@ static struct mi_root* imc_mi_list_members(struct mi_root* cmd_tree, node= cmd_tree->node.kids; if(node == NULL|| node->next!=NULL) return 0; - + /* room name */ room_name.s = rnbuf; room_name.len= node->value.len; @@ -780,11 +791,11 @@ static struct mi_root* imc_mi_list_members(struct mi_root* cmd_tree, if(rpl_tree == NULL) return 0; - node_r = add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, "ROOM", 4, - room_name.s, room_name.len); + node_r = add_mi_node_child( &rpl_tree->node, MI_IS_ARRAY|MI_DUP_VALUE, + "ROOM", 4, room_name.s, room_name.len); if(node_r == NULL) goto error; - + imp = room->members; i=0; @@ -797,7 +808,7 @@ static struct mi_root* imc_mi_list_members(struct mi_root* cmd_tree, goto error; imp = imp->next; } - + p = int2str(i, &len); attr= add_mi_attr(node_r, MI_DUP_VALUE, "NR_OF_MEMBERS", 13, p, len); if(attr == 0) diff --git a/modules/imc/imc.h b/modules/imc/imc.h index 0cdbd229272..356290b903c 100644 --- a/modules/imc/imc.h +++ b/modules/imc/imc.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/imc/imc_cmd.c b/modules/imc/imc_cmd.c index bb7a6a1a541..43efd58984e 100644 --- a/modules/imc/imc_cmd.c +++ b/modules/imc/imc_cmd.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -123,7 +123,7 @@ int imc_parse_cmd(char *buf, int len, imc_cmd_p cmd) if(*p=='\0' || p>=buf+len) goto done; - + i=0; do { while(p=IMC_CMD_MAX_PARAM) break; } while(1); - + done: LM_ERR("command: [%.*s]\n", cmd->name.len, cmd->name.s); for(i=0; iparam[1].s, IMC_ROOM_PRIVATE, cmd->param[1].len)) { - flag_room |= IMC_ROOM_PRIV; + flag_room |= IMC_ROOM_PRIV; LM_DBG("room with private flag on\n"); } - + room= imc_add_room(&cmd->param[0], &dst->host, flag_room); if(room == NULL) { LM_ERR("failed to add new room\n"); goto error; - } + } LM_DBG("added room uri= %.*s\n", room->uri.len, room->uri.s); flag_member |= IMC_MEMBER_OWNER; /* adding the owner as the forst member*/ @@ -195,24 +195,24 @@ int imc_handle_create(struct sip_msg* msg, imc_cmd_t *cmd, } LM_DBG("added the owner as the first member " "[%.*s]\n",member->uri.len, member->uri.s); - + /* send info message */ body.s = "*** room was created"; body.len = sizeof("*** room was created")-1; imc_send_message(&room->uri, &member->uri, &imc_hdr_ctype, &body); goto done; } - + /* room already exists */ LM_DBG("room [%.*s] already created\n", cmd->param[0].len, cmd->param[0].s); - if(!(room->flags & IMC_ROOM_PRIV)) + if(!(room->flags & IMC_ROOM_PRIV)) { LM_DBG("checking if the user [%.*s] is a member\n", src->user.len, src->user.s); member= imc_get_member(room, &src->user, &src->host); if(member== NULL) - { + { member= imc_add_member(room, &src->user, &src->host, flag_member); if(member == NULL) { @@ -229,7 +229,7 @@ int imc_handle_create(struct sip_msg* msg, imc_cmd_t *cmd, if(body.len>0) imc_room_broadcast(room, &imc_hdr_ctype, &body); - } + } } done: @@ -260,8 +260,8 @@ int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd, room_name = cmd->param[0].s?cmd->param[0]:dst->user; room=imc_get_room(&room_name, &dst->host); if(room== NULL || (room->flags&IMC_ROOM_DELETED)) - { - LM_DBG("could not find room [%.*s]- adding\n", + { + LM_DBG("could not find room [%.*s]- adding\n", room_name.len, room_name.s); room= imc_add_room(&room_name, &dst->host, flag_room); if(room == NULL) @@ -295,17 +295,17 @@ int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd, { LM_DBG("room [%.*s] is public\n", room_name.len, room_name.s); if(member== NULL) - { + { LM_DBG("adding new member [%.*s]\n", src->user.len, src->user.s); member= imc_add_member(room, &src->user, - &src->host, flag_member); + &src->host, flag_member); if(member == NULL) { LM_ERR("adding new user [%.*s]\n", src->user.len, src->user.s); goto error; - } + } goto build_inform; - } else { + } else { LM_DBG("member [%.*s] is in room already\n", member->uri.len,member->uri.s ); } @@ -318,7 +318,7 @@ int imc_handle_join(struct sip_msg* msg, imc_cmd_t *cmd, } - if(member->flags & IMC_MEMBER_INVITED) + if(member->flags & IMC_MEMBER_INVITED) member->flags &= ~IMC_MEMBER_INVITED; } @@ -362,13 +362,13 @@ int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd, int result; - size = cmd->param[0].len+2 ; + size = cmd->param[0].len+2 ; add_domain = 1; add_sip = 0; while (iparam[0].s[i]== '@') - { + { add_domain = 0; break; } @@ -383,7 +383,7 @@ int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd, size += 4; add_sip = 1; } - + uri.s = (char*)pkg_malloc(size *sizeof(char)); if(uri.s == NULL) { @@ -392,16 +392,16 @@ int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd, } size= 0; if(add_sip) - { + { strcpy(uri.s, "sip:"); size=4; } - + memcpy(uri.s+size, cmd->param[0].s, cmd->param[0].len); size += cmd->param[0].len; if(add_domain) - { + { uri.s[size] = '@'; size++; memcpy(uri.s+ size, dst->host.s, dst->host.len); @@ -414,15 +414,15 @@ int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd, LM_ERR("bad uri [%.*s]!\n", uri.len, uri.s); goto error; } - + room_name = (cmd->param[1].s)?cmd->param[1]:dst->user; - room = imc_get_room(&room_name, &dst->host); + room = imc_get_room(&room_name, &dst->host); if(room== NULL || (room->flags&IMC_ROOM_DELETED)) { LM_ERR("the room does not exist [%.*s]!\n", room_name.len, room_name.s); goto error; - } + } member= imc_get_member(room, &src->user, &src->host); if(member==NULL) @@ -438,7 +438,7 @@ int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd, " other users!\n", src->user.len, src->user.s); goto error; } - + member= imc_get_member(room, &inv_uri.user, &inv_uri.host); if(member!=NULL) { @@ -446,39 +446,39 @@ int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd, " of the room!\n", inv_uri.user.len, inv_uri.user.s); goto error; } - - flag_member |= IMC_MEMBER_INVITED; + + flag_member |= IMC_MEMBER_INVITED; member=imc_add_member(room, &inv_uri.user, &inv_uri.host, flag_member); if(member == NULL) { LM_ERR("adding member [%.*s]\n", inv_uri.user.len, inv_uri.user.s); - goto error; + goto error; } - - body.len = 13 + member->uri.len - 4/* sip: */ + 28; + + body.len = 13 + member->uri.len - 4/* sip: */ + 28; if(body.len>=IMC_BUF_SIZE || member->uri.len>=IMC_BUF_SIZE || room->uri.len>=IMC_BUF_SIZE) { LM_ERR("buffer size overflow\n"); - goto error; + goto error; } body.s = imc_body_buf; memcpy(body.s, "INVITE from: ", 13); memcpy(body.s+13, member->uri.s + 4, member->uri.len - 4); - memcpy(body.s+ 9 + member->uri.len, "(Type: '#accept' or '#deny')", 28); - body.s[body.len] = '\0'; + memcpy(body.s+ 9 + member->uri.len, "(Type: '#accept' or '#deny')", 28); + body.s[body.len] = '\0'; - LM_DBG("to=[%.*s]\nfrom=[%.*s]\nbody=[%.*s]\n", + LM_DBG("to=[%.*s]\nfrom=[%.*s]\nbody=[%.*s]\n", member->uri.len,member->uri.s,room->uri.len, room->uri.s, body.len, body.s); - + cback_param = (del_member_t*)shm_malloc(sizeof(del_member_t)); if(cback_param==NULL) { LM_ERR("no more shm\n"); - goto error; + goto error; } memset(cback_param, 0, sizeof(del_member_t)); cback_param->room_name = room->name; @@ -497,7 +497,7 @@ int imc_handle_invite(struct sip_msg* msg, imc_cmd_t *cmd, imc_inv_callback, /* callback function*/ (void*)(cback_param), /* callback param*/ NULL - ); + ); if(result< 0) { LM_ERR("in tm send request\n"); @@ -531,7 +531,7 @@ int imc_handle_accept(struct sip_msg* msg, imc_cmd_t *cmd, imc_member_p member = 0; str room_name; str body; - + /* accepting the invitation */ room_name = cmd->param[0].s?cmd->param[0]:dst->user; room=imc_get_room(&room_name, &dst->host); @@ -539,7 +539,7 @@ int imc_handle_accept(struct sip_msg* msg, imc_cmd_t *cmd, { LM_ERR("room [%.*s] is not created!\n", room_name.len, room_name.s); goto error; - } + } /* if aready invited add as a member */ member=imc_get_member(room, &src->user, &src->host); if(member==NULL || !(member->flags & IMC_MEMBER_INVITED)) @@ -548,9 +548,9 @@ int imc_handle_accept(struct sip_msg* msg, imc_cmd_t *cmd, src->user.len, src->user.s); goto error; } - + member->flags &= ~IMC_MEMBER_INVITED; - + /* send info message */ body.s = imc_body_buf; body.len = snprintf(body.s, IMC_BUF_SIZE, "*** <%.*s> has joined the room", @@ -589,7 +589,7 @@ int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd, while (iparam[0].s[i]== '@') - { + { add_domain =0; break; } @@ -613,16 +613,16 @@ int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd, size= 0; if(add_sip) - { + { strcpy(uri.s, "sip:"); size = 4; } - + memcpy(uri.s+size, cmd->param[0].s, cmd->param[0].len); size+= cmd->param[0].len; if(add_domain) - { + { uri.s[size] = '@'; size++; memcpy(uri.s+size, dst->host.s, dst->host.len); @@ -635,14 +635,14 @@ int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd, LM_ERR("invalid uri [%.*s]\n", uri.len, uri.s); goto error; } - + room_name = cmd->param[1].s?cmd->param[1]:dst->user; room= imc_get_room(&room_name, &dst->host); if(room==NULL || (room->flags&IMC_ROOM_DELETED)) { LM_ERR("room [%.*s]does not exist!\n", room_name.len, room_name.s); goto error; - } + } /* verify if the user who sent the request is a member in the room * and has the right to remove other users */ @@ -650,11 +650,11 @@ int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd, if(member== NULL) { - LM_ERR("user [%.*s] is not member of room [%.*s]!\n", + LM_ERR("user [%.*s] is not member of room [%.*s]!\n", src->user.len, src->user.s, room_name.len, room_name.s); goto error; } - + if(!(member->flags & IMC_MEMBER_OWNER) && !(member->flags & IMC_MEMBER_ADMIN)) { @@ -667,18 +667,18 @@ int imc_handle_remove(struct sip_msg* msg, imc_cmd_t *cmd, member= imc_get_member(room, &inv_uri.user, &inv_uri.host); if(member== NULL) { - LM_ERR("user [%.*s] is not member of room [%.*s]!\n", + LM_ERR("user [%.*s] is not member of room [%.*s]!\n", inv_uri.user.len, inv_uri.user.s, room_name.len, room_name.s); goto error; } - + if(member->flags & IMC_MEMBER_OWNER) { LM_ERR("user [%.*s] is owner of room [%.*s]" " -- cannot be removed!\n", inv_uri.user.len, inv_uri.user.s, room_name.len, room_name.s); goto error; - } + } /* send message to the removed person */ body.s = "You have been removed from this room"; @@ -731,30 +731,30 @@ int imc_handle_deny(struct sip_msg* msg, imc_cmd_t *cmd, { LM_ERR("room [%.*s] does not exist!\n", room_name.len, room_name.s); goto error; - } + } /* If the user is an invited member, delete it froim the list */ member= imc_get_member(room, &src->user, &src->host); if(member==NULL || !(member->flags & IMC_MEMBER_INVITED)) { - LM_ERR("user [%.*s] was not invited in room [%.*s]!\n", + LM_ERR("user [%.*s] was not invited in room [%.*s]!\n", src->user.len, src->user.s, room_name.len, room_name.s); goto error; - } - + } + #if 0 /* send info message */ body.s = imc_body_buf; - body.len = snprintf(body.s, IMC_BUF_SIZE, + body.len = snprintf(body.s, IMC_BUF_SIZE, "The user [%.*s] has denied the invitation", src->user.len, src->user.s); if(body.len>0) imc_send_message(&room->uri, &memeber->uri, &imc_hdr_ctype, &body); #endif - LM_ERR("user [%.*s] declined invitation in room [%.*s]!\n", + LM_ERR("user [%.*s] declined invitation in room [%.*s]!\n", src->user.len, src->user.s, room_name.len, room_name.s); imc_del_member(room, &src->user, &src->host); - + imc_release_room(room); return 0; @@ -776,7 +776,7 @@ int imc_handle_list(struct sip_msg* msg, imc_cmd_t *cmd, str room_name; str body; char *p; - + /* the user wants to leave the room */ room_name = cmd->param[0].s?cmd->param[0]:dst->user; @@ -785,14 +785,14 @@ int imc_handle_list(struct sip_msg* msg, imc_cmd_t *cmd, { LM_ERR("room [%.*s] does not exist!\n", room_name.len, room_name.s); goto error; - } + } /* verify if the user is a member of the room */ member = imc_get_member(room, &src->user, &src->host); if(member == NULL) { - LM_ERR("user [%.*s] is not member of room [%.*s]!\n", + LM_ERR("user [%.*s] is not member of room [%.*s]!\n", src->user.len, src->user.s, room_name.len, room_name.s); goto error; } @@ -818,7 +818,7 @@ int imc_handle_list(struct sip_msg* msg, imc_cmd_t *cmd, *p++ = '\n'; imp = imp->next; } - + imc_release_room(room); /* write over last '\n' */ @@ -846,7 +846,7 @@ int imc_handle_exit(struct sip_msg* msg, imc_cmd_t *cmd, imc_member_p member = 0; str room_name; str body; - + /* the user wants to leave the room */ room_name = cmd->param[0].s?cmd->param[0]:dst->user; @@ -855,18 +855,18 @@ int imc_handle_exit(struct sip_msg* msg, imc_cmd_t *cmd, { LM_ERR("room [%.*s] does not exist!\n", room_name.len, room_name.s); goto error; - } + } /* verify if the user is a member of the room */ member= imc_get_member(room, &src->user, &src->host); if(member== NULL) { - LM_ERR("user [%.*s] is not member of room [%.*s]!\n", + LM_ERR("user [%.*s] is not member of room [%.*s]!\n", src->user.len, src->user.s, room_name.len, room_name.s); goto error; } - + if(member->flags & IMC_MEMBER_OWNER) { /*If the user is the owner of the room, the room is distroyed */ @@ -878,7 +878,7 @@ int imc_handle_exit(struct sip_msg* msg, imc_cmd_t *cmd, imc_room_broadcast(room, &imc_hdr_ctype, &body); imc_release_room(room); - + imc_del_room(&room_name, &dst->host); room = NULL; goto done; @@ -887,7 +887,7 @@ int imc_handle_exit(struct sip_msg* msg, imc_cmd_t *cmd, member->flags |= IMC_MEMBER_DELETED; imc_del_member(room, &src->user, &src->host); body.s = imc_body_buf; - body.len = snprintf(body.s, IMC_BUF_SIZE, + body.len = snprintf(body.s, IMC_BUF_SIZE, "The user [%.*s] has left the room", src->user.len, src->user.s); if(body.len>0) @@ -915,7 +915,7 @@ int imc_handle_destroy(struct sip_msg* msg, imc_cmd_t *cmd, imc_member_p member = 0; str room_name; str body; - + /* distrugere camera */ room_name = cmd->param[0].s?cmd->param[0]:dst->user; @@ -924,18 +924,18 @@ int imc_handle_destroy(struct sip_msg* msg, imc_cmd_t *cmd, { LM_ERR("room [%.*s] does not exist!\n", room_name.len, room_name.s); goto error; - } + } /* verify is the user is a member of the room*/ member= imc_get_member(room, &src->user, &src->host); if(member== NULL) { - LM_ERR("user [%.*s] is not a member of room [%.*s]!\n", + LM_ERR("user [%.*s] is not a member of room [%.*s]!\n", src->user.len, src->user.s, room_name.len, room_name.s); goto error; } - + if(!(member->flags & IMC_MEMBER_OWNER)) { LM_ERR("user [%.*s] is not owner of room [%.*s] -- cannot destroy it" @@ -1032,7 +1032,7 @@ int imc_handle_message(struct sip_msg* msg, str *msgbody, imc_member_p member = 0; str body; - room = imc_get_room(&dst->user, &dst->host); + room = imc_get_room(&dst->user, &dst->host); if(room==NULL || (room->flags&IMC_ROOM_DELETED)) { LM_ERR("room [%.*s] does not exist!\n", dst->user.len, dst->user.s); @@ -1046,7 +1046,7 @@ int imc_handle_message(struct sip_msg* msg, str *msgbody, src->user.len, src->user.s, dst->user.len, dst->user.s); goto error; } - + LM_DBG("broadcast to room [%.*s]\n", room->uri.len, room->uri.s); body.s = imc_body_buf; @@ -1058,7 +1058,7 @@ int imc_handle_message(struct sip_msg* msg, str *msgbody, } body.s[0] = '<'; memcpy(body.s + 1, member->uri.s + 4, member->uri.len - 4); - memcpy(body.s + 1 + member->uri.len - 4, ">: ", 3); + memcpy(body.s + 1 + member->uri.len - 4, ">: ", 3); memcpy(body.s + 1 + member->uri.len - 4 +3, msgbody->s, msgbody->len); body.s[body.len] = '\0'; @@ -1098,10 +1098,10 @@ int imc_room_broadcast(imc_room_p room, str *ctype, str *body) imp = imp->next; continue; } - + /* to-do: callbac to remove user fi delivery fails */ imc_send_message(&room->uri, &imp->uri, ctype, body); - + imp = imp->next; } return 0; @@ -1142,18 +1142,18 @@ void imc_inv_callback( struct cell *t, int type, struct tmcb_params *ps) imc_member_p member= NULL; imc_room_p room = NULL; - if(ps->param==NULL || *ps->param==NULL || + if(ps->param==NULL || *ps->param==NULL || (del_member_t*)(*ps->param) == NULL) { LM_DBG("member not received\n"); return; } - + LM_DBG("completed with status %d [member name domain:" - "%p/%.*s/%.*s]\n",ps->code, ps->param, + "%p/%.*s/%.*s]\n",ps->code, ps->param, ((del_member_t *)(*ps->param))->member_name.len, ((del_member_t *)(*ps->param))->member_name.s, - ((del_member_t *)(*ps->param))->member_domain.len, + ((del_member_t *)(*ps->param))->member_domain.len, ((del_member_t *)(*ps->param))->member_domain.s); if(ps->code < 300) return; @@ -1165,7 +1165,7 @@ void imc_inv_callback( struct cell *t, int type, struct tmcb_params *ps) { LM_ERR("the room does not exist!\n"); goto error; - } + } /*verify if the user who sent the request is a member in the room * and has the right to remove other users */ member= imc_get_member(room, @@ -1183,25 +1183,25 @@ void imc_inv_callback( struct cell *t, int type, struct tmcb_params *ps) goto build_inform; } - + build_inform: - + body_final.s = body_buf; body_final.len = member->uri.len - 4 /* sip: part of URI */ + 20; memcpy(body_final.s, member->uri.s + 4, member->uri.len - 4); memcpy(body_final.s+member->uri.len-4," is not registered. ",21); - + goto send_message; send_message: - + from_uri_s.s = from_uri_buf; from_uri_s.len = room->uri.len; strncpy(from_uri_s.s, room->uri.s, room->uri.len); LM_DBG("sending message\n"); - + to_uri_s.s = to_uri_buf; to_uri_s.len = ((del_member_t *)(*ps->param))->inv_uri.len; strncpy(to_uri_s.s,((del_member_t *)(*ps->param))->inv_uri.s , @@ -1237,6 +1237,6 @@ void imc_inv_callback( struct cell *t, int type, struct tmcb_params *ps) } if((del_member_t *)(*ps->param)) shm_free(*ps->param); - return; + return; } diff --git a/modules/imc/imc_cmd.h b/modules/imc/imc_cmd.h index 33f75f99189..0283ed5cfbe 100644 --- a/modules/imc/imc_cmd.h +++ b/modules/imc/imc_cmd.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/imc/imc_mng.c b/modules/imc/imc_mng.c index 86b6eb1d1f6..bd13081503e 100644 --- a/modules/imc/imc_mng.c +++ b/modules/imc/imc_mng.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -69,7 +69,7 @@ int imc_htable_init(void) goto error; } } - + return 0; error: @@ -91,7 +91,7 @@ int imc_htable_destroy(void) imc_room_p irp = NULL, irp_temp=NULL; if(_imc_htable==NULL) return -1; - + for(i=0; is==NULL || name->len<=0 || domain == NULL || domain->s==NULL || domain->len<=0) { @@ -134,7 +134,7 @@ imc_room_p imc_add_room(str* name, str* domain, int flags) return NULL; } memset(irp, 0, size); - + irp->uri.len = 4 /*sip:*/ + name->len + 1 /*@*/ + domain->len; irp->uri.s = (char*)(((char*)irp)+sizeof(imc_room_t)); memcpy(irp->uri.s, "sip:", 4); @@ -147,14 +147,14 @@ imc_room_p imc_add_room(str* name, str* domain, int flags) irp->name.s = irp->uri.s+4; irp->domain.len = domain->len; irp->domain.s = irp->uri.s+5+name->len; - + irp->flags = flags; irp->hashid = core_case_hash(&irp->name, &irp->domain, 0); - + hidx = imc_get_hentry(irp->hashid, imc_hash_size); lock_get(&_imc_htable[hidx].lock); - + if(_imc_htable[hidx].rooms!=NULL) { irp->next = _imc_htable[hidx].rooms; @@ -162,8 +162,8 @@ imc_room_p imc_add_room(str* name, str* domain, int flags) _imc_htable[hidx].rooms = irp; } else { _imc_htable[hidx].rooms = irp; - } - + } + return irp; } @@ -173,13 +173,13 @@ imc_room_p imc_add_room(str* name, str* domain, int flags) int imc_release_room(imc_room_p room) { unsigned int hidx; - + if(room==NULL) { LM_ERR("invalid parameters\n"); return -1; } - + hidx = imc_get_hentry(room->hashid, imc_hash_size); lock_release(&_imc_htable[hidx].lock); @@ -194,16 +194,16 @@ imc_room_p imc_get_room(str* name, str* domain) imc_room_p irp = NULL; unsigned int hashid; int hidx; - + if(name == NULL || name->s==NULL || name->len<=0 || domain == NULL || domain->s==NULL || domain->len<=0) { LM_ERR("invalid parameters\n"); return NULL; } - + hashid = core_case_hash(name, domain, 0); - + hidx = imc_get_hentry(hashid, imc_hash_size); lock_get(&_imc_htable[hidx].lock); @@ -235,19 +235,19 @@ int imc_del_room(str* name, str* domain) imc_room_p irp = NULL; imc_member_p imp=NULL, imp_temp=NULL; unsigned int hashid; - int hidx; - + int hidx; + if(name == NULL || name->s==NULL || name->len<=0 || domain == NULL || domain->s==NULL || domain->len<=0) { LM_ERR("invalid parameters\n"); return -1; } - + hashid = core_case_hash(name, domain, 0); - + hidx = imc_get_hentry(hashid, imc_hash_size); - + lock_get(&_imc_htable[hidx].lock); irp = _imc_htable[hidx].rooms; while(irp) @@ -270,7 +270,7 @@ int imc_del_room(str* name, str* domain) imp_temp = imp->next; shm_free(imp); imp = imp_temp; - } + } shm_free(irp); @@ -279,7 +279,7 @@ int imc_del_room(str* name, str* domain) irp = irp->next; } -done: +done: lock_release(&_imc_htable[hidx].lock); return 0; @@ -292,14 +292,14 @@ imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags) { imc_member_p imp = NULL; int size; - + if(room==NULL || user == NULL || user->s==NULL || user->len<=0 || domain == NULL || domain->s==NULL || domain->len<=0) { LM_ERR("invalid parameters\n"); return NULL; } - + /* struct size + "sip:" + user name len + "@" + domain len + '\0' */ size = sizeof(imc_member_t) + (user->len+domain->len+6)*sizeof(char); imp = (imc_member_p)shm_malloc(size); @@ -309,7 +309,7 @@ imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags) return NULL; } memset(imp, 0, size); - + imp->uri.len = 4 /*sip:*/ + user->len + 1 /*@*/ + domain->len; imp->uri.s = (char*)(((char*)imp)+sizeof(imc_member_t)); memcpy(imp->uri.s, "sip:", 4); @@ -317,11 +317,11 @@ imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags) imp->uri.s[4+user->len] = '@'; memcpy(imp->uri.s+5+user->len, domain->s, domain->len); imp->uri.s[imp->uri.len] = '\0'; - + LM_DBG("[uri]= %.*s\n", imp->uri.len, imp->uri.s); imp->user.len = user->len; imp->user.s = imp->uri.s+4; - + LM_DBG("[user]= %.*s\n", imp->user.len, imp->user.s); imp->domain.len = domain->len; imp->domain.s = imp->uri.s+5+user->len; @@ -330,7 +330,7 @@ imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags) imp->hashid = core_case_hash(&imp->user, &imp->domain, 0); room->nr_of_members++; - + if(room->members==NULL) room->members = imp; else { @@ -338,7 +338,7 @@ imc_member_p imc_add_member(imc_room_p room, str* user, str* domain, int flags) if((room->members)->next!=NULL) ((room->members)->next)->prev = imp; imp->prev = room->members; - + room->members->next=imp; } @@ -359,7 +359,7 @@ imc_member_p imc_get_member(imc_room_p room, str* user, str* domain) LM_ERR("invalid parameters\n"); return NULL; } - + hashid = core_case_hash(user, domain, 0); imp = room->members; while(imp) @@ -385,14 +385,14 @@ int imc_del_member(imc_room_p room, str* user, str* domain) { imc_member_p imp = NULL; unsigned int hashid; - + if(room==NULL || user == NULL || user->s==NULL || user->len<=0 || domain == NULL || domain->s==NULL || domain->len<=0) { LM_ERR("invalid parameters\n"); return -1; } - + hashid = core_case_hash(user, domain, 0); imp = room->members; while(imp) @@ -414,6 +414,6 @@ int imc_del_member(imc_room_p room, str* user, str* domain) } imp = imp->next; } - + return 0; } diff --git a/modules/imc/imc_mng.h b/modules/imc/imc_mng.h index 123d1d42b71..f981b5b04ef 100644 --- a/modules/imc/imc_mng.h +++ b/modules/imc/imc_mng.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/jabber/README b/modules/jabber/README index 2b1395037fa..3525e12f253 100644 --- a/modules/jabber/README +++ b/modules/jabber/README @@ -12,8 +12,7 @@ Daniel-Constantin Mierla Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/jabber/jabber.c b/modules/jabber/jabber.c index 6ce66c2dd7c..c5786ad3746 100644 --- a/modules/jabber/jabber.c +++ b/modules/jabber/jabber.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * --- @@ -79,9 +79,9 @@ struct tm_binds tmb; /** iHTTP bind */ struct ih_binds ihb; /** iHTTP callback functions */ -int xjab_mod_info(ih_req_p _irp, void *_p, char *_bb, int *_bl, +int xjab_mod_info(ih_req_p _irp, void *_p, char *_bb, int *_bl, char *_hb, int *_hl); -int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, +int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, char *_hb, int *_hl); #endif @@ -156,7 +156,7 @@ static cmd_export_t cmds[] = { /* - * Exported parameters + * Exported parameters */ static param_export_t params[] = { {"db_url", STR_PARAM, &db_url.s }, @@ -176,11 +176,23 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; struct module_exports exports= { "jabber", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -246,14 +258,14 @@ static int mod_init(void) if (load_ih( &ihb )==-1) return -1; #endif - + pipes = (int**)pkg_malloc(nrw*sizeof(int*)); if (pipes == NULL) { LM_ERR("no more pkg memory (pipes)\n"); return -1; } - + for(i=0; i-<%d>\n", i, pipes[i][0], pipes[i][1]); } - + if((jwl = xj_wlist_init(pipes,nrw,max_jobs,cache_time,sleep_time, delay_time)) == NULL) { LM_ERR("failed to initialize workers list\n"); return -1; } - + if(xj_wlist_set_aliases(jwl, jaliases, jdomain, proxy) < 0) { LM_ERR("failed to set aliases and outbound proxy\n"); return -1; } - LM_DBG("initialized ...\n"); + LM_DBG("initialized ...\n"); return 0; } @@ -318,7 +330,7 @@ static int mod_init(void) static int child_init(int rank) { int i, j, mpid, cpid; - + LM_DBG("initializing child <%d>\n", rank); /* Rank 0 is main process now - 1 is the first child (janakj) */ if(rank == 1) @@ -355,7 +367,7 @@ static int child_init(int rank) LM_ERR("failed to set worker's pid\n"); return -1; } - xj_worker_process(jwl,jaddress,jport, priority, i, + xj_worker_process(jwl,jaddress,jport, priority, i, db_con[i], &jabber_dbf); exit(0); } @@ -369,7 +381,7 @@ static int child_init(int rank) } } } - + //if(pipes) //{ // for(i=0;ito || !msg->from) { LM_ERR("cannot find TO or FROM HEADERS!\n"); goto error; } - + /* parsing from header */ - if ( parse_from_header( msg )<0 || msg->from->parsed==NULL) + if ( parse_from_header( msg )<0 || msg->from->parsed==NULL) { LM_DBG("cannot get FROM header\n"); goto error; @@ -516,7 +528,7 @@ int xjab_manage_sipmsg(struct sip_msg *msg, int type) // if is for going ONLINE/OFFLINE we do not need the destination if(type==XJ_GO_ONLINE || type==XJ_GO_OFFLINE) goto prepare_job; - + // determination of destination // - try to get it from new_uri, r-uri or to hdr, but check it against // jdomain and aliases @@ -532,7 +544,7 @@ int xjab_manage_sipmsg(struct sip_msg *msg, int type) LM_DBG("using NEW URI for destination\n"); #endif } - + if (dst.len == 0 && msg->first_line.u.request.uri.s != NULL && msg->first_line.u.request.uri.len > 0 ) { @@ -557,13 +569,13 @@ int xjab_manage_sipmsg(struct sip_msg *msg, int type) LM_DBG("using TO-URI for destination\n"); #endif } - + if(dst.len == 0) { LM_DBG("destination not found in SIP message\n"); goto error; } - + /** skip 'sip:' and parameters in destination address */ if(xj_extract_aor(&dst, 1)) { @@ -573,14 +585,14 @@ int xjab_manage_sipmsg(struct sip_msg *msg, int type) #ifdef XJ_EXTRA_DEBUG LM_DBG("destination after correction [%.*s].\n", dst.len, dst.s); #endif - + prepare_job: //putting the SIP message parts in share memory to be accessible by workers jsmsg = (xj_sipmsg)shm_malloc(sizeof(t_xj_sipmsg)); memset(jsmsg, 0, sizeof(t_xj_sipmsg)); if(jsmsg == NULL) return -1; - + switch(type) { case XJ_SEND_MESSAGE: @@ -640,7 +652,7 @@ int xjab_manage_sipmsg(struct sip_msg *msg, int type) shm_free(jsmsg); goto error; } - + return 1; error: return -1; @@ -675,7 +687,7 @@ void destroy(void) jabber_dbf.close(db_con[i]); shm_free(db_con); } - + xj_wlist_free(jwl); LM_DBG("unloaded ...\n"); } @@ -713,16 +725,16 @@ void xj_register_watcher(str *from, str *to, void *cbf, void *pp) LM_DBG("cannot find pipe of the worker!\n"); goto error; } - + //putting the SIP message parts in share memory to be accessible by workers jsmsg = (xj_sipmsg)shm_malloc(sizeof(t_xj_sipmsg)); memset(jsmsg, 0, sizeof(t_xj_sipmsg)); if(jsmsg == NULL) goto error; - + jsmsg->msg.len = 0; jsmsg->msg.s = NULL; - + to_uri.s = to->s; to_uri.len = to->len; /** skip 'sip:' and parameters in destination address */ @@ -749,7 +761,7 @@ void xj_register_watcher(str *from, str *to, void *cbf, void *pp) jsmsg->jkey = jp; jsmsg->type = XJ_REG_WATCHER; //jsmsg->jkey->hash = jkey.hash; - + jsmsg->cbf = (pa_callback_f)cbf; jsmsg->p = pp; @@ -767,7 +779,7 @@ void xj_register_watcher(str *from, str *to, void *cbf, void *pp) shm_free(jsmsg); goto error; } - + error: return; } @@ -799,13 +811,13 @@ void xjab_check_workers(int mpid) n = waitpid(jwl->workers[i].pid, &stat, WNOHANG); if(n == 0 || n!=jwl->workers[i].pid) continue; - + LM_ERR("worker[%d][pid=%d] has exited - status=%d err=%d" "errno=%d\n", i, jwl->workers[i].pid, stat, n, errno); xj_wlist_clean_jobs(jwl, i, 1); xj_wlist_set_pid(jwl, -1, i); } - + #ifdef XJ_EXTRA_DEBUG LM_DBG("create a new worker[%d]\n", i); #endif @@ -828,22 +840,22 @@ void xjab_check_workers(int mpid) db_con[i], &jabber_dbf); exit(0); } - } + } } #ifdef HAVE_IHTTP /** * Module's information retrieval - function to use with iHttp module * - */ -int xjab_mod_info(ih_req_p _irp, void *_p, char *_bb, int *_bl, + */ +int xjab_mod_info(ih_req_p _irp, void *_p, char *_bb, int *_bl, char *_hb, int *_hl) { if(!_irp || !_bb || !_bl || *_bl <= 0 || !_hb || !_hl || *_hl <= 0) return -1; *_hl = 0; *_hb = 0; - + strcpy(_bb, "

SER2Jabber Gateway

"); strcat(_bb, "
Module parameters:
"); strcat(_bb, "
-- db table = "); @@ -873,7 +885,7 @@ int xjab_mod_info(ih_req_p _irp, void *_p, char *_bb, int *_bl, strcat(_bb, int2str(cache_time, NULL)); strcat(_bb, "
-- check time = "); strcat(_bb, int2str(check_time, NULL)); - + *_bl = strlen(_bb); return 0; @@ -881,10 +893,10 @@ int xjab_mod_info(ih_req_p _irp, void *_p, char *_bb, int *_bl, /** * SER2Jab connection management - function to use with iHttp module - * - be aware of who is able to use the ihttp because he can close any + * - be aware of who is able to use the ihttp because he can close any * open connection between SER and Jabber server - */ -int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, + */ +int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, char *_hb, int *_hl) { t_xj_jkey jkey, *p; @@ -895,12 +907,12 @@ int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, if(!_irp || !_bb || !_bl || *_bl <= 0 || !_hb || !_hl || *_hl <= 0) return -1; - + *_hl = 0; *_hb = 0; idx = -1; strcpy(_bb, "

Active XMPP connections

"); - + if(_irp->params) { strcat(_bb, "
Close action is alpha release!
"); @@ -936,7 +948,7 @@ int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, } i++; break; - + } _ipp = _ipp->next; } @@ -958,7 +970,7 @@ int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, return 0; } - + if(jwl!=NULL && jwl->len > 0 && jwl->workers!=NULL) { for(idx=0; idxlen; idx++) @@ -973,7 +985,7 @@ int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, continue; lock_set_get(jwl->sems, idx); maxcount = count234(jwl->workers[idx].sip_ids); - for (i = 0; i < maxcount; i++) + for (i = 0; i < maxcount; i++) { p = (xj_jkey)index234(jwl->workers[idx].sip_ids, i); if(p == NULL) @@ -996,7 +1008,7 @@ int xjab_connections(ih_req_p _irp, void *_p, char *_bb, int *_bl, lock_set_release(jwl->sems, idx); } } - + *_bl = strlen(_bb); return 0; diff --git a/modules/jabber/mdefines.h b/modules/jabber/mdefines.h index 410ab39df3a..9aff94e7b63 100644 --- a/modules/jabber/mdefines.h +++ b/modules/jabber/mdefines.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/jabber/sha.c b/modules/jabber/sha.c index 23494c2a90c..9202e9e327d 100644 --- a/modules/jabber/sha.c +++ b/modules/jabber/sha.c @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * + * * Gabber * Copyright (C) 1999-2000 Dave Smith & Julian Missig * @@ -22,7 +22,7 @@ -/* +/* Implements the Secure Hash Algorithm (SHA1) Copyright (C) 1999 Scott G. Miller @@ -30,12 +30,12 @@ Released under the terms of the GNU General Public License v2 see file COPYING for details - Credits: - Robert Klep -- Expansion function fix + Credits: + Robert Klep -- Expansion function fix Thomas "temas" Muldowney : -- shahash() for string fun -- Will add the int32 stuff in a few - + --- FIXME: This source takes int to be a 32 bit integer. This may vary from system to system. I'd use autoconf if I was familiar @@ -67,7 +67,7 @@ (x>>24 & 0x000000ff) /* Initial hash values */ -#define Ai 0x67452301 +#define Ai 0x67452301 #define Bi 0xefcdab89 #define Ci 0x98badcfe #define Di 0x10325476 @@ -76,7 +76,7 @@ /* SHA1 round constants */ #define K1 0x5a827999 #define K2 0x6ed9eba1 -#define K3 0x8f1bbcdc +#define K3 0x8f1bbcdc #define K4 0xca62c1d6 /* Round functions. Note that f2() is used in both rounds 2 and 4 */ @@ -94,34 +94,34 @@ 32 bit ints), into the ongoing 160 bit hash value (five 32 bit ints) 'hash' */ -int -sha_hash(int *data, int *hash) +int +sha_hash(int *data, int *hash) { int W[80]; unsigned int A=hash[0], B=hash[1], C=hash[2], D=hash[3], E=hash[4]; unsigned int t, x, TEMP; - for (t=0; t<16; t++) + for (t=0; t<16; t++) { #ifndef WORDS_BIGENDIAN W[t]=switch_endianness(data[t]); -#else +#else W[t]=data[t]; #endif } /* SHA1 Data expansion */ - for (t=16; t<80; t++) + for (t=16; t<80; t++) { x=W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]; W[t]=rol1(x); } - /* SHA1 main loop (t=0 to 79) + /* SHA1 main loop (t=0 to 79) This is broken down into four subloops in order to use the correct round function and constant */ - for (t=0; t<20; t++) + for (t=0; t<20; t++) { TEMP=rol5(A) + f1(B,C,D) + E + W[t] + K1; E=D; @@ -130,7 +130,7 @@ sha_hash(int *data, int *hash) B=A; A=TEMP; } - for (; t<40; t++) + for (; t<40; t++) { TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K2; E=D; @@ -139,7 +139,7 @@ sha_hash(int *data, int *hash) B=A; A=TEMP; } - for (; t<60; t++) + for (; t<60; t++) { TEMP=rol5(A) + f3(B,C,D) + E + W[t] + K3; E=D; @@ -148,7 +148,7 @@ sha_hash(int *data, int *hash) B=A; A=TEMP; } - for (; t<80; t++) + for (; t<80; t++) { TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K4; E=D; @@ -157,7 +157,7 @@ sha_hash(int *data, int *hash) B=A; A=TEMP; } - hash[0]+=A; + hash[0]+=A; hash[1]+=B; hash[2]+=C; hash[3]+=D; @@ -170,8 +170,8 @@ sha_hash(int *data, int *hash) initializes it to the start constants of the SHA1 algorithm. This must be called before using hash in the call to sha_hash */ -int -sha_init(int *hash) +int +sha_init(int *hash) { hash[0]=Ai; hash[1]=Bi; @@ -181,11 +181,11 @@ sha_init(int *hash) return 0; } -int strprintsha(char *dest, int *hashval) +int strprintsha(char *dest, int *hashval) { int x; char *hashstr = dest; - for (x=0; x<5; x++) + for (x=0; x<5; x++) { snprintf(hashstr, 9, "%08x", hashval[x]); hashstr+=8; @@ -198,12 +198,12 @@ int strprintsha(char *dest, int *hashval) return 0; } -char *shahash(const char *str) +char *shahash(const char *str) { char read_buffer[65]; //int read_buffer[64]; int c=1, i; - + INT64 length=0; int strsz; @@ -216,43 +216,43 @@ char *shahash(const char *str) strsz = strlen(str); - if(strsz == 0) + if(strsz == 0) { memset(read_buffer, 0, 65); read_buffer[0] = 0x80; sha_hash((int *)read_buffer, hashval); } - while (strsz>0) + while (strsz>0) { memset(read_buffer, 0, 65); strncpy((char*)read_buffer, str, 64); c = strlen((char *)read_buffer); length+=c; strsz-=c; - if (strsz<=0) + if (strsz<=0) { - length<<=3; + length<<=3; read_buffer[c]=(char)0x80; - for (i=c+1; i<64; i++) + for (i=c+1; i<64; i++) read_buffer[i]=0; - if (c>55) + if (c>55) { /* we need to do an entire new block */ sha_hash((int *)read_buffer, hashval); - for (i=0; i<14; i++) + for (i=0; i<14; i++) ((int*)read_buffer)[i]=0; - } + } #ifndef WORDS_BIGENDIAN - for (i=0; i<8; i++) + for (i=0; i<8; i++) { read_buffer[56+i]=(char)(length>>(56-(i*8))) & 0xff; } -#else +#else memcpy(read_buffer+56, &length, 8); #endif } - + sha_hash((int *)read_buffer, hashval); str+=64; } diff --git a/modules/jabber/tree234.c b/modules/jabber/tree234.c index 59ab667d3c3..43596fa18bb 100644 --- a/modules/jabber/tree234.c +++ b/modules/jabber/tree234.c @@ -2,9 +2,9 @@ * $Id$ * * tree234.c: reasonably generic counted 2-3-4 tree routines. - * + * * This file is copyright 1999-2001 Simon Tatham. - * + * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without @@ -13,10 +13,10 @@ * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -185,7 +185,7 @@ static void *add234_internal(tree234 *t, void *e, int index) { /* * Leaf node. We want to insert at kid position * equal to the index: - * + * * 0 A 1 B 2 C 3 */ childnum = index; @@ -313,7 +313,7 @@ static void *add234_internal(tree234 *t, void *e, int index) { /* * Insert in a 4-node; split into a 2-node and a * 3-node, and move focus up a level. - * + * * I don't think it matters which way round we put the * 2 and the 3. For simplicity, we'll put the 3 first * always. @@ -451,7 +451,7 @@ void *index234(tree234 *t, int index) { return NULL; /* out of range */ n = t->root; - + while (n) { if (index < n->counts[0]) n = n->kids[0]; @@ -558,7 +558,7 @@ void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp, * know where we would insert this node if we wanted to: * we'd put it in in place of the (empty) subtree * n->kids[kcount], and it would have index idx - * + * * But the actual element isn't there. So if our search * relation is EQ, we're doomed. */ @@ -648,7 +648,7 @@ static void *delpos234_internal(tree234 *t, int index) { * only one element, but child ki-1 has two or * more. So we need to move a subtree from ki-1 * to ki. - * + * * . C . . B . * / \ -> / \ * [more] a A b B c d D e [more] a A b c C d D e @@ -684,7 +684,7 @@ static void *delpos234_internal(tree234 *t, int index) { * Case 3a, right-handed variant. ki has only * one element but ki+1 has two or more. Move a * subtree from ki+1 to ki. - * + * * . B . . C . * / \ -> / \ * a A b c C d D e [more] a A b B c d D e [more] @@ -719,7 +719,7 @@ static void *delpos234_internal(tree234 *t, int index) { * . B . . * / \ -> | * a A b c C d a A b B c C d - * + * * (Since at all points we have avoided * descending to a node with only one element, * we can be sure that n is not reduced to @@ -848,7 +848,7 @@ static void *delpos234_internal(tree234 *t, int index) { while (m->kids[0]) { m = (m->kids[3] ? m->kids[3] : m->kids[2] ? m->kids[2] : - m->kids[1] ? m->kids[1] : m->kids[0]); + m->kids[1] ? m->kids[1] : m->kids[0]); } target = (m->elems[2] ? m->elems[2] : m->elems[1] ? m->elems[1] : m->elems[0]); diff --git a/modules/jabber/tree234.h b/modules/jabber/tree234.h index 20e26e3c701..f04351786a3 100644 --- a/modules/jabber/tree234.h +++ b/modules/jabber/tree234.h @@ -2,9 +2,9 @@ * $Id$ * * tree234.h: header defining functions in tree234.c. - * + * * This file is copyright 1999-2001 Simon Tatham. - * + * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without @@ -13,10 +13,10 @@ * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -71,7 +71,7 @@ void *add234(tree234 *t, void *e); * Add an element e to an unsorted 2-3-4 tree t. Returns e on * success, NULL on failure. (Failure should only occur if the * index is out of range or the tree is sorted.) - * + * * Index range can be from 0 to the tree's current element count, * inclusive. */ @@ -80,14 +80,14 @@ void *addpos234(tree234 *t, void *e, int index); /* * Look up the element at a given numeric index in a 2-3-4 tree. * Returns NULL if the index is out of range. - * + * * One obvious use for this function is in iterating over the whole * of a tree (sorted or unsorted): - * + * * for (i = 0; (p = index234(tree, i)) != NULL; i++) consume(p); - * + * * or - * + * * int maxcount = count234(tree); * for (i = 0; i < maxcount; i++) { * p = index234(tree, i); @@ -103,36 +103,36 @@ void *index234(tree234 *t, int index); * can be an asymmetric function if desired. cmp can also be passed * as NULL, in which case the compare function from the tree proper * will be used. - * + * * Three of these functions are special cases of findrelpos234. The * non-`pos' variants lack the `index' parameter: if the parameter * is present and non-NULL, it must point to an integer variable * which will be filled with the numeric index of the returned * element. - * + * * The non-`rel' variants lack the `relation' parameter. This * parameter allows you to specify what relation the element you * provide has to the element you're looking for. This parameter * can be: - * + * * REL234_EQ - find only an element that compares equal to e * REL234_LT - find the greatest element that compares < e * REL234_LE - find the greatest element that compares <= e * REL234_GT - find the smallest element that compares > e * REL234_GE - find the smallest element that compares >= e - * + * * Non-`rel' variants assume REL234_EQ. - * + * * If `rel' is REL234_GT or REL234_LT, the `e' parameter may be * NULL. In this case, REL234_GT will return the smallest element * in the tree, and REL234_LT will return the greatest. This gives * an alternative means of iterating over a sorted tree, instead of * using index234: - * + * * // to loop forwards * for (p = NULL; (p = findrel234(tree, p, NULL, REL234_GT)) != NULL ;) * consume(p); - * + * * // to loop backwards * for (p = NULL; (p = findrel234(tree, p, NULL, REL234_LT)) != NULL ;) * consume(p); @@ -149,15 +149,15 @@ void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp, int relation, /* * Delete an element e in a 2-3-4 tree. Does not free the element, * merely removes all links to it from the tree nodes. - * + * * delpos234 deletes the element at a particular tree index: it * works on both sorted and unsorted trees. - * + * * del234 deletes the element passed to it, so it only works on * sorted trees. (It's equivalent to using findpos234 to determine * the index of an element, and then passing that index to * delpos234.) - * + * * Both functions return a pointer to the element they delete, for * the user to free or pass on elsewhere or whatever. If the index * is out of range (delpos234) or the element is already not in the diff --git a/modules/jabber/xjab_base.c b/modules/jabber/xjab_base.c index 7a26c3086a7..d253d114b5f 100644 --- a/modules/jabber/xjab_base.c +++ b/modules/jabber/xjab_base.c @@ -17,7 +17,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -39,7 +39,7 @@ /** * get the hash code - based on Andrei's function - * + * */ int xj_get_hash(str *x, str *y) { @@ -59,8 +59,8 @@ int xj_get_hash(str *x, str *y) } v=0; for (;p<(x->s+x->len); p++) - { - v<<=8; + { + v<<=8; v+=*p; } h+=v^(v>>3); @@ -72,17 +72,17 @@ int xj_get_hash(str *x, str *y) v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; h+=v^(v>>3); } - + v=0; for (;p<(y->s+y->len); p++) - { - v<<=8; + { + v<<=8; v+=*p; } h+=v^(v>>3); } h=((h)+(h>>11))+((h>>13)+(h>>23)); - + return (h)?h:1; } @@ -103,15 +103,15 @@ int xj_jkey_cmp(void *x, void *y) // ((str *)a)->s, ((str *)b)->len, ((str *)b)->s); if(a->hash != b->hash) return (a->hash < b->hash)?-1:1; - + if(a->id->len != b->id->len) return (a->id->len < b->id->len)?-1:1; - + n=strncmp(a->id->s,b->id->s,a->id->len); - + if(n!=0) return (n<0)?-1:1; - + return 0; } /** @@ -159,7 +159,7 @@ int xj_extract_aor(str* u, int t) LM_ERR("failed to parse URI\n"); return -1; } - + if(t == 1) u->s = puri.user.s; u->len = puri.host.s + puri.host.len - u->s; diff --git a/modules/jabber/xjab_base.h b/modules/jabber/xjab_base.h index 8da71d7fd83..cfa0aca817b 100644 --- a/modules/jabber/xjab_base.h +++ b/modules/jabber/xjab_base.h @@ -20,7 +20,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ + */ /*** * --- diff --git a/modules/jabber/xjab_jcon.c b/modules/jabber/xjab_jcon.c index e5f82a586ac..44eb35d3190 100644 --- a/modules/jabber/xjab_jcon.c +++ b/modules/jabber/xjab_jcon.c @@ -17,7 +17,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -63,7 +63,7 @@ xj_jcon xj_jcon_init(char *hostname, int port) xj_jcon jbc = NULL; if(hostname==NULL || strlen(hostname)<=0) return NULL; - + jbc = (xj_jcon)_M_MALLOC(sizeof(struct _xj_jcon)); if(jbc == NULL) return NULL; @@ -88,7 +88,7 @@ xj_jcon xj_jcon_init(char *hostname, int port) _M_FREE(jbc); return NULL; } - + return jbc; } @@ -191,12 +191,12 @@ int xj_jcon_user_auth(xj_jcon jbc, char *username, char *passwd, sprintf(msg_buff, JB_CLIENT_OPEN_STREAM, jbc->hostname); if(send(jbc->sock, msg_buff, strlen(msg_buff), 0) != strlen(msg_buff)) goto error; - + n = recv(jbc->sock, msg_buff, 4096, 0); msg_buff[n] = 0; if(strncasecmp(msg_buff, JB_START_STREAM, JB_START_STREAM_LEN)) goto error; - + p0 = strstr(msg_buff + JB_START_STREAM_LEN, "id='"); if(p0 == NULL) goto error; @@ -211,7 +211,7 @@ int xj_jcon_user_auth(xj_jcon jbc, char *username, char *passwd, jbc->stream_id[p1-p0] = 0; sprintf(msg_buff, "%08X", jbc->seq_nr); - + x = xode_new_tag("iq"); if(!x) return -1; @@ -228,9 +228,9 @@ int xj_jcon_user_auth(xj_jcon jbc, char *username, char *passwd, i = send(jbc->sock, p0, n, 0); if(i != n) goto errorx; - + xode_free(x); - + // receive response // try 10 times i = 10; @@ -250,24 +250,24 @@ int xj_jcon_user_auth(xj_jcon jbc, char *username, char *passwd, x = xode_from_strx(msg_buff, n, &err, &i); p0 = msg_buff; if(err) - p0 += i; - + p0 += i; + if(strncasecmp(xode_get_name(x), "iq", 2)) goto errorx; - + if((x = xode_get_tag(x, "query?xmlns=jabber:iq:auth")) == NULL) goto errorx; - + y = xode_new_tag("query"); xode_put_attrib(y, "xmlns", "jabber:iq:auth"); z = xode_insert_tag(y, "username"); xode_insert_cdata(z, username, -1); z = xode_insert_tag(y, "resource"); xode_insert_cdata(z, resource, -1); - + if(xode_get_tag(x, "digest") != NULL) { // digest authentication - + //sprintf(msg_buff, "%s%s", jbc->stream_id, passwd); strcpy(msg_buff, jbc->stream_id); strcat(msg_buff, passwd); @@ -284,16 +284,16 @@ int xj_jcon_user_auth(xj_jcon jbc, char *username, char *passwd, } y = xode_wrap(y, "iq"); - + jbc->seq_nr++; sprintf(msg_buff, "%08X", jbc->seq_nr); - + xode_put_attrib(y, "id", msg_buff); xode_put_attrib(y, "type", "set"); - + p1 = xode_to_str(y); n = strlen(p1); - + i = send(jbc->sock, p1, n, 0); if(i != n) { @@ -302,7 +302,7 @@ int xj_jcon_user_auth(xj_jcon jbc, char *username, char *passwd, } xode_free(x); xode_free(y); - + // receive response // try 10 times i = 10; @@ -322,19 +322,19 @@ int xj_jcon_user_auth(xj_jcon jbc, char *username, char *passwd, x = xode_from_strx(msg_buff, n, &err, &i); p0 = msg_buff; if(err) - p0 += i; - - if(strncasecmp(xode_get_name(x), "iq", 2) || + p0 += i; + + if(strncasecmp(xode_get_name(x), "iq", 2) || strncasecmp(xode_get_attrib(x, "type"), "result", 6)) goto errorx; - + jbc->resource = (char*)_M_MALLOC(strlen(resource)+1); strcpy(jbc->resource, resource); jbc->allowed = XJ_NET_ALL; - jbc->ready = XJ_NET_JAB; + jbc->ready = XJ_NET_JAB; return 0; - + errorx: xode_free(x); error: @@ -361,22 +361,22 @@ int xj_jcon_set_roster(xj_jcon jbc, char* jid, char *type) char *p; int n; char buff[16]; - + if(!jbc || !jid) return -1; - + x = xode_new_tag("item"); if(!x) return -1; xode_put_attrib(x, "jid", jid); if(type != NULL) xode_put_attrib(x, "subscription", type); - + x = xode_wrap(x, "query"); xode_put_attrib(x, "xmlns", "jabber:iq:roster"); x = xode_wrap(x, "iq"); - + xode_put_attrib(x, "type", "set"); jbc->seq_nr++; sprintf(buff, "%08X", jbc->seq_nr); @@ -384,7 +384,7 @@ int xj_jcon_set_roster(xj_jcon jbc, char* jid, char *type) p = xode_to_str(x); n = strlen(p); - + if(send(jbc->sock, p, n, 0) != n) { LM_DBG("item not sent\n"); @@ -401,20 +401,20 @@ int xj_jcon_set_roster(xj_jcon jbc, char* jid, char *type) * send a message through a JABBER connection * params are pairs (buffer, len) */ -int xj_jcon_send_msg(xj_jcon jbc, char *to, int tol, char *msg, +int xj_jcon_send_msg(xj_jcon jbc, char *to, int tol, char *msg, int msgl, int type) { char msg_buff[4096], *p; int n; xode x; - + if(jbc == NULL) return -1; - + x = xode_new_tag("body"); if(!x) return -1; - + xode_insert_cdata(x, msg, msgl); x = xode_wrap(x, "message"); strncpy(msg_buff, to, tol); @@ -436,7 +436,7 @@ int xj_jcon_send_msg(xj_jcon jbc, char *to, int tol, char *msg, n = strlen(p); #ifdef XJ_EXTRA_DEBUG LM_DBG("jabber msg:\n%s\n", p); -#endif +#endif if(send(jbc->sock, p, n, 0) != n) { LM_DBG(" message not sent\n"); @@ -474,16 +474,16 @@ int xj_jcon_send_presence(xj_jcon jbc, char *sto, char *type, char *status, char *p; int n; xode x, y; - + if(jbc == NULL) return -1; #ifdef XJ_EXTRA_DEBUG LM_DBG("-----START-----\n"); -#endif +#endif x = xode_new_tag("presence"); if(!x) return -1; - + if(sto != NULL) xode_put_attrib(x, "to", sto); if(type != NULL) @@ -497,11 +497,11 @@ int xj_jcon_send_presence(xj_jcon jbc, char *sto, char *type, char *status, { y = xode_insert_tag(x, "priority"); xode_insert_cdata(y, priority, strlen(priority)); - } - + } + p = xode_to_str(x); n = strlen(p); - + if(send(jbc->sock, p, n, 0) != n) { LM_DBG("presence not sent\n"); @@ -525,10 +525,10 @@ int xj_jcon_send_subscribe(xj_jcon jbc, char *to, char *from, char *type) char *p; int n; xode x; - + if(!jbc || !to) return -1; - + x = xode_new_tag("presence"); if(!x) return -1; @@ -541,7 +541,7 @@ int xj_jcon_send_subscribe(xj_jcon jbc, char *to, char *from, char *type) p = xode_to_str(x); n = strlen(p); - + if(send(jbc->sock, p, n, 0) != n) { LM_DBG("subscribe not sent\n"); @@ -561,7 +561,7 @@ int xj_jcon_send_subscribe(xj_jcon jbc, char *to, char *from, char *type) int xj_jcon_free(xj_jcon jbc) { xj_jconf jcf; - + if(jbc == NULL) return -1; @@ -575,7 +575,7 @@ int xj_jcon_free(xj_jcon jbc) _M_FREE(jbc->hostname); if(jbc->stream_id != NULL) _M_FREE(jbc->stream_id); - + if(jbc->resource != NULL) _M_FREE(jbc->resource); #ifdef XJ_EXTRA_DEBUG @@ -603,7 +603,7 @@ int xj_jcon_free(xj_jcon jbc) * - delay_time : time needed to became an active connection * return : pointer to the structure or NULL on error */ -int xj_jcon_set_attrs(xj_jcon jbc, xj_jkey jkey, int cache_time, +int xj_jcon_set_attrs(xj_jcon jbc, xj_jkey jkey, int cache_time, int delay_time) { int t; @@ -627,11 +627,11 @@ int xj_jcon_update(xj_jcon jbc, int cache_time) if(jbc == NULL) return -1; #ifdef XJ_EXTRA_DEBUG - LM_DBG("params [%.*s] %d\n", + LM_DBG("params [%.*s] %d\n", jbc->jkey->id->len, jbc->jkey->id->s, cache_time); #endif jbc->expire = get_ticks() + cache_time; - return 0; + return 0; } int xj_jcon_is_ready(xj_jcon jbc, char *to, int tol, char dl) @@ -641,14 +641,14 @@ int xj_jcon_is_ready(xj_jcon jbc, char *to, int tol, char dl) xj_jconf jcf = NULL; if(!jbc || !to || tol <= 0) return -1; - + sto.s = to; sto.len = tol; if(!xj_jconf_check_addr(&sto, dl)) { #ifdef XJ_EXTRA_DEBUG LM_DBG("destination=conference\n"); -#endif +#endif if((jcf=xj_jcon_get_jconf(jbc, &sto, dl))!=NULL) return (jcf->status & XJ_JCONF_READY)?0:3; #ifdef XJ_EXTRA_DEBUG @@ -656,19 +656,19 @@ int xj_jcon_is_ready(xj_jcon jbc, char *to, int tol, char dl) #endif return -1; } - + p = to; - while(p < to+tol && *p!='@') + while(p < to+tol && *p!='@') p++; if(p>=to+tol) return -1; p++; if(!strncasecmp(p, XJ_AIM_NAME, XJ_AIM_LEN)) return (jbc->ready & XJ_NET_AIM)?0:((jbc->allowed & XJ_NET_AIM)?1:2); - + if(!strncasecmp(p, XJ_ICQ_NAME, XJ_ICQ_LEN)) return (jbc->ready & XJ_NET_ICQ)?0:((jbc->allowed & XJ_NET_ICQ)?1:2); - + if(!strncasecmp(p, XJ_MSN_NAME, XJ_MSN_LEN)) return (jbc->ready & XJ_NET_MSN)?0:((jbc->allowed & XJ_NET_MSN)?1:2); @@ -687,8 +687,8 @@ xj_jconf xj_jcon_get_jconf(xj_jcon jbc, str* sid, char dl) if(!jbc || !sid || !sid->s || sid->len <= 0) return NULL; #ifdef XJ_EXTRA_DEBUG - LM_DBG("looking for conference\n"); -#endif + LM_DBG("looking for conference\n"); +#endif if((jcf = xj_jconf_new(sid))==NULL) return NULL; if(xj_jconf_init_sip(jcf, jbc->jkey->id, dl)) @@ -701,7 +701,7 @@ xj_jconf xj_jcon_get_jconf(xj_jcon jbc, str* sid, char dl) xj_jconf_free(jcf); return p; } - + if(jbc->nrjconf >= XJ_MAX_JCONF) goto clean; @@ -734,7 +734,7 @@ xj_jconf xj_jcon_check_jconf(xj_jcon jbc, char* id) return NULL; #ifdef XJ_EXTRA_DEBUG LM_DBG("conference not found\n"); -#endif +#endif sid.s = id; sid.len = strlen(id); if((jcf = xj_jconf_new(&sid))==NULL) @@ -754,15 +754,15 @@ xj_jconf xj_jcon_check_jconf(xj_jcon jbc, char* id) LM_DBG("conference not found\n"); #endif xj_jconf_free(jcf); - return NULL; + return NULL; } -int xj_jcon_jconf_presence(xj_jcon jbc, xj_jconf jcf, char* type, +int xj_jcon_jconf_presence(xj_jcon jbc, xj_jconf jcf, char* type, char* status) { char buff[256]; - - strncpy(buff, jcf->room.s, + + strncpy(buff, jcf->room.s, jcf->room.len + jcf->server.len +1); buff[jcf->room.len + jcf->server.len +1] = '/'; buff[jcf->room.len + jcf->server.len +2] = 0; @@ -775,12 +775,12 @@ int xj_jcon_jconf_presence(xj_jcon jbc, xj_jconf jcf, char* type, int xj_jcon_del_jconf(xj_jcon jbc, str *sid, char dl, int flag) { xj_jconf jcf = NULL, p = NULL; - + if(!jbc || !sid || !sid->s || sid->len <= 0) return -1; #ifdef XJ_EXTRA_DEBUG LM_DBG("deleting conference of <%.*s>\n", sid->len, sid->s); -#endif +#endif if((jcf = xj_jconf_new(sid))==NULL) return -1; if(xj_jconf_init_sip(jcf, jbc->jkey->id, dl)) @@ -788,7 +788,7 @@ int xj_jcon_del_jconf(xj_jcon jbc, str *sid, char dl, int flag) xj_jconf_free(jcf); return -1; } - + p = del234(jbc->jconf, (void*)jcf); if(p != NULL) diff --git a/modules/jabber/xjab_jcon.h b/modules/jabber/xjab_jcon.h index effc22f6796..9a3af89a137 100644 --- a/modules/jabber/xjab_jcon.h +++ b/modules/jabber/xjab_jcon.h @@ -17,7 +17,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/jabber/xjab_jconf.c b/modules/jabber/xjab_jconf.c index ce2f5a4d8af..b9eb6bd0c7d 100644 --- a/modules/jabber/xjab_jconf.c +++ b/modules/jabber/xjab_jconf.c @@ -40,7 +40,7 @@ xj_jconf xj_jconf_new(str *u) { xj_jconf jcf = NULL; - + if(!u || !u->s || u->len<=0) return NULL; jcf = (xj_jconf)pkg_malloc(sizeof(t_xj_jconf)); @@ -64,14 +64,14 @@ xj_jconf xj_jconf_new(str *u) jcf->jcid = 0; jcf->status = XJ_JCONF_NULL; - + jcf->room.s = NULL; jcf->room.len = 0; jcf->server.s = NULL; jcf->server.len = 0; jcf->nick.s = NULL; jcf->nick.len = 0; - + return jcf; } @@ -82,19 +82,19 @@ int xj_jconf_init_sip(xj_jconf jcf, str *sid, char dl) { char *p, *p0; int n = 0; - if(!jcf || !jcf->uri.s || jcf->uri.len <= 0 + if(!jcf || !jcf->uri.s || jcf->uri.len <= 0 || !sid || !sid->s || sid->len <= 0) return -1; #ifdef XJ_EXTRA_DEBUG LM_DBG("parsing uri\n"); -#endif +#endif p = jcf->uri.s; - while(p<(jcf->uri.s + jcf->uri.len) && *p != '@') + while(p<(jcf->uri.s + jcf->uri.len) && *p != '@') p++; if(*p != '@') goto bad_format; p0 = p; - + while(p0 > jcf->uri.s) { p0--; @@ -142,9 +142,9 @@ int xj_jconf_init_sip(xj_jconf jcf, str *sid, char dl) jcf->jcid = xj_get_hash(&jcf->room, &jcf->server); #ifdef XJ_EXTRA_DEBUG LM_DBG("conference id=%d\n", jcf->jcid); -#endif +#endif return 0; - + bad_format: LM_ERR("failed to parse uri - bad format\n"); return -2; @@ -160,18 +160,18 @@ int xj_jconf_init_jab(xj_jconf jcf) return -1; #ifdef XJ_EXTRA_DEBUG LM_DBG("parsing uri\n"); -#endif +#endif p = jcf->uri.s; - while(p<(jcf->uri.s + jcf->uri.len) && *p != '@') + while(p<(jcf->uri.s + jcf->uri.len) && *p != '@') p++; if(*p != '@' || p==jcf->uri.s) goto bad_format; - + p0 = p+1; - + while(p0 < ((jcf->uri.s + jcf->uri.len)) && *p0 != '/') p0++; - + jcf->server.s = p+1; jcf->server.len = p0 - jcf->server.s; jcf->room.s = jcf->uri.s; @@ -186,7 +186,7 @@ int xj_jconf_init_jab(xj_jconf jcf) LM_DBG("conference id=%d\n", jcf->jcid); #endif return 0; - + bad_format: LM_ERR("failed to parse uri - bad format\n"); return -2; @@ -214,38 +214,38 @@ int xj_jconf_cmp(void *a, void *b) return -1; if(b == NULL) return 1; - + // LM_DBG("comparing <%.*s> / <%.*s>\n",((str *)a)->len, // ((str *)a)->s, ((str *)b)->len, ((str *)b)->s); if(((xj_jconf)a)->jcid < ((xj_jconf)b)->jcid) return -1; if(((xj_jconf)a)->jcid > ((xj_jconf)b)->jcid) return 1; - + if(((xj_jconf)a)->room.len < ((xj_jconf)b)->room.len) return -1; if(((xj_jconf)a)->room.len > ((xj_jconf)b)->room.len) return 1; - + if(((xj_jconf)a)->server.len < ((xj_jconf)b)->server.len) return -1; if(((xj_jconf)a)->server.len > ((xj_jconf)b)->server.len) return 1; - n = strncmp(((xj_jconf)a)->room.s, ((xj_jconf)b)->room.s, + n = strncmp(((xj_jconf)a)->room.s, ((xj_jconf)b)->room.s, ((xj_jconf)a)->room.len); if(n<0) return -1; if(n>0) return 1; - - n = strncmp(((xj_jconf)a)->server.s, ((xj_jconf)b)->server.s, + + n = strncmp(((xj_jconf)a)->server.s, ((xj_jconf)b)->server.s, ((xj_jconf)a)->server.len); if(n<0) return -1; if(n>0) return 1; - + return 0; } @@ -256,12 +256,12 @@ int xj_jconf_free(xj_jconf jcf) { if(!jcf) return 0; - + if(jcf->uri.s != NULL) pkg_free(jcf->uri.s); pkg_free(jcf); jcf = NULL; - + return 0; } diff --git a/modules/jabber/xjab_load.c b/modules/jabber/xjab_load.c index 25c4ee62d3a..590a0873a48 100644 --- a/modules/jabber/xjab_load.c +++ b/modules/jabber/xjab_load.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -26,13 +26,13 @@ int load_xjab(struct xjab_binds *xjb) { if(!( xjb->register_watcher=(pa_register_watcher_f) - find_export("jab_register_watcher", XJ_NO_SCRIPT_F, 0)) ) + find_export("jab_register_watcher", XJ_NO_SCRIPT_F, 0)) ) { LM_ERR("'jab_register_watcher' not found!\n"); return -1; } if(!( xjb->unregister_watcher=(pa_unregister_watcher_f) - find_export("jab_unregister_watcher", XJ_NO_SCRIPT_F, 0)) ) + find_export("jab_unregister_watcher", XJ_NO_SCRIPT_F, 0)) ) { LM_ERR("'jab_unregister_watcher' not found!\n"); return -1; diff --git a/modules/jabber/xjab_load.h b/modules/jabber/xjab_load.h index 7d5a15b3ec4..a2ee40e2a57 100644 --- a/modules/jabber/xjab_load.h +++ b/modules/jabber/xjab_load.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/jabber/xjab_presence.c b/modules/jabber/xjab_presence.c index ad34cca4e1b..fdf4488171f 100644 --- a/modules/jabber/xjab_presence.c +++ b/modules/jabber/xjab_presence.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -121,7 +121,7 @@ int xj_pres_cell_update(xj_pres_cell prc, pa_callback_f f, void *p) xj_pres_list xj_pres_list_init(void) { xj_pres_list prl = NULL; - + prl = (xj_pres_list)pkg_malloc(sizeof(t_xj_pres_list)); if(!prl) return NULL; @@ -202,7 +202,7 @@ int xj_pres_list_del(xj_pres_list prl, str *uid) return -1; if(prl->nr<=0 || prl->clist==NULL) return 0; - + lkey = xj_get_hash(uid, NULL); p = prl->clist; diff --git a/modules/jabber/xjab_presence.h b/modules/jabber/xjab_presence.h index 64a4ba781ed..539d90d5661 100644 --- a/modules/jabber/xjab_presence.h +++ b/modules/jabber/xjab_presence.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/jabber/xjab_util.c b/modules/jabber/xjab_util.c index b359156dd33..b0eb5fc9064 100644 --- a/modules/jabber/xjab_util.c +++ b/modules/jabber/xjab_util.c @@ -17,7 +17,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -101,7 +101,7 @@ xj_jcon_pool xj_jcon_pool_init(int size, int jlen, int ch) int xj_jcon_pool_add_jmsg(xj_jcon_pool jcp, xj_sipmsg _jsm, xj_jcon _ojc) { int i; - + if(jcp == NULL) return -1; if(jcp->jmqueue.size == jcp->jmqueue.len) @@ -137,7 +137,7 @@ int xj_jcon_pool_del_jmsg(xj_jcon_pool jcp, int idx) jcp->jmqueue.size--; jcp->jmqueue.jsm[idx] = NULL; jcp->jmqueue.ojc[idx] = NULL; - + return 0; } @@ -149,18 +149,18 @@ int xj_jcon_pool_del_jmsg(xj_jcon_pool jcp, int idx) int xj_jcon_pool_add(xj_jcon_pool jcp, xj_jcon jc) { int i = 0; - + if(jcp == NULL) return -1; #ifdef XJ_EXTRA_DEBUG LM_DBG("add connection into the pool\n"); -#endif +#endif while(i < jcp->len && jcp->ojc[i] != NULL) i++; if(i >= jcp->len) return -1; jcp->ojc[i] = jc; - + return 0; } @@ -174,7 +174,7 @@ xj_jcon xj_jcon_pool_get(xj_jcon_pool jcp, xj_jkey jkey) { int i = 0; xj_jcon _ojc; - + if(jcp==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL) return NULL; #ifdef XJ_EXTRA_DEBUG @@ -183,7 +183,7 @@ xj_jcon xj_jcon_pool_get(xj_jcon_pool jcp, xj_jkey jkey) #endif while(i < jcp->len) { - if((jcp->ojc[i]!=NULL) && jcp->ojc[i]->jkey->hash==jkey->hash && + if((jcp->ojc[i]!=NULL) && jcp->ojc[i]->jkey->hash==jkey->hash && (!strncmp(jcp->ojc[i]->jkey->id->s, jkey->id->s, jkey->id->len))) { _ojc = jcp->ojc[i]; @@ -205,7 +205,7 @@ xj_jcon xj_jcon_pool_get(xj_jcon_pool jcp, xj_jkey jkey) int xj_jcon_pool_del(xj_jcon_pool jcp, xj_jkey jkey) { int i = 0; - + if(jcp==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL) return -1; #ifdef XJ_EXTRA_DEBUG @@ -213,7 +213,7 @@ int xj_jcon_pool_del(xj_jcon_pool jcp, xj_jkey jkey) #endif while(i < jcp->len) { - if((jcp->ojc[i]!=NULL) && jcp->ojc[i]->jkey->hash==jkey->hash && + if((jcp->ojc[i]!=NULL) && jcp->ojc[i]->jkey->hash==jkey->hash && (!strncmp(jcp->ojc[i]->jkey->id->s,jkey->id->s,jkey->id->len))) { xj_jcon_free(jcp->ojc[i]); @@ -253,7 +253,7 @@ void xj_jcon_pool_free(xj_jcon_pool jcp) _M_FREE(jcp->jmqueue.ojc); if(jcp->jmqueue.expire != NULL) _M_FREE(jcp->jmqueue.expire); - + _M_FREE(jcp); } diff --git a/modules/jabber/xjab_wlist.c b/modules/jabber/xjab_wlist.c index 22a0aa88a74..bcc2699ec91 100644 --- a/modules/jabber/xjab_wlist.c +++ b/modules/jabber/xjab_wlist.c @@ -17,7 +17,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * @@ -61,13 +61,13 @@ xj_wlist xj_wlist_init(int **pipes, int size, int max, int cache_time, return NULL; #ifdef XJ_EXTRA_DEBUG LM_DBG("-----START-----\n"); -#endif +#endif jwl = (xj_wlist)_M_SHM_MALLOC(sizeof(t_xj_wlist)); if(jwl == NULL) return NULL; jwl->len = size; jwl->maxj = max; - + jwl->cachet = cache_time; jwl->delayt = delay_time; jwl->sleept = sleep_time; @@ -101,7 +101,7 @@ xj_wlist xj_wlist_init(int **pipes, int size, int max, int cache_time, lock_set_destroy(jwl->sems); goto clean; } - } + } return jwl; @@ -185,12 +185,12 @@ void xj_wlist_free(xj_wlist jwl) _M_SHM_FREE(jwl->aliases); jwl->aliases = NULL; } - + if(jwl->sems != NULL){ lock_set_destroy(jwl->sems); lock_set_dealloc(jwl->sems); } - + _M_SHM_FREE(jwl); } @@ -207,7 +207,7 @@ int xj_wlist_check(xj_wlist jwl, xj_jkey jkey, xj_jkey *p) int i; if(jwl==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL) return -1; - + i = 0; *p = NULL; while(i < jwl->len) @@ -251,7 +251,7 @@ int xj_wlist_get(xj_wlist jwl, xj_jkey jkey, xj_jkey *p) { int i = 0, pos = -1, min = 100000; xj_jkey msid = NULL; - + if(jwl==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL) return -1; @@ -301,7 +301,7 @@ int xj_wlist_get(xj_wlist jwl, xj_jkey jkey, xj_jkey *p) _M_SHM_FREE(msid); goto error; } - + msid->id->s = (char*)_M_SHM_MALLOC(jkey->id->len); if(msid->id == NULL) { @@ -309,7 +309,7 @@ int xj_wlist_get(xj_wlist jwl, xj_jkey jkey, xj_jkey *p) _M_SHM_FREE(msid); goto error; } - + if((*p = add234(jwl->workers[pos].sip_ids, msid)) != NULL) { msid->id->len = jkey->id->len; @@ -347,12 +347,12 @@ int xj_wlist_set_flag(xj_wlist jwl, xj_jkey jkey, int fl) xj_jkey p = NULL; if(jwl==NULL || jkey==NULL || jkey->id==NULL || jkey->id->s==NULL) return -1; - + #ifdef XJ_EXTRA_DEBUG LM_DBG("looking for <%.*s>" " having id=%d\n", jkey->id->len, jkey->id->s, jkey->hash); #endif - + i = 0; while(i < jwl->len) { @@ -393,18 +393,18 @@ int xj_wlist_set_aliases(xj_wlist jwl, char *als, char *jd, char *pa) { char *p, *p0, *p1; int i, n; - + if(jwl == NULL) return -1; if(!jd) // || !als || strlen(als)<2) return 0; - + if((jwl->aliases = (xj_jalias)_M_SHM_MALLOC(sizeof(t_xj_jalias)))==NULL) { LM_DBG("not enough SHMemory.\n"); return -1; } - + jwl->aliases->jdm = NULL; jwl->aliases->proxy = NULL; jwl->aliases->dlm = XJ_DEF_JDELIM; // default user part delimiter @@ -428,7 +428,7 @@ int xj_wlist_set_aliases(xj_wlist jwl, char *als, char *jd, char *pa) LM_DBG("not enough SHMemory!?\n"); _M_SHM_FREE(jwl->aliases); jwl->aliases = NULL; - return -1; + return -1; } jwl->aliases->jdm->len = n; if((jwl->aliases->jdm->s=(char*)_M_SHM_MALLOC(jwl->aliases->jdm->len)) @@ -445,14 +445,14 @@ int xj_wlist_set_aliases(xj_wlist jwl, char *als, char *jd, char *pa) jwl->aliases->jdm->len, jwl->aliases->jdm->s, jwl->aliases->dlm); #endif } - + // set the proxy address if(pa && strlen(pa)>0) { if((jwl->aliases->proxy = (str*)_M_SHM_MALLOC(sizeof(str)))==NULL) { LM_DBG(" not enough SHMemory!!\n"); - goto clean3; + goto clean3; } i = jwl->aliases->proxy->len = strlen(pa); // check if proxy address has sip: prefix @@ -478,23 +478,23 @@ int xj_wlist_set_aliases(xj_wlist jwl, char *als, char *jd, char *pa) jwl->aliases->proxy->len, jwl->aliases->proxy->s); #endif } - + // set the IM aliases if(!als || strlen(als)<2) return 0; - + if((p = strchr(als, ';')) == NULL) { LM_DBG("bad parameter value\n"); return -1; } - + if((jwl->aliases->size = atoi(als)) <= 0) { LM_DBG("wrong number of aliases\n"); return 0; } - + jwl->aliases->d = (char*)_M_SHM_MALLOC(jwl->aliases->size*sizeof(char)); if(jwl->aliases->d == NULL) { @@ -502,14 +502,14 @@ int xj_wlist_set_aliases(xj_wlist jwl, char *als, char *jd, char *pa) goto clean2; } memset(jwl->aliases->d, 0, jwl->aliases->size); - + jwl->aliases->a = (str*)_M_SHM_MALLOC(jwl->aliases->size*sizeof(str)); if(jwl->aliases->a == NULL) { LM_DBG("not enough SHMemory..\n"); goto clean1; } - + p++; for(i=0; ialiases->size; i++) { @@ -532,11 +532,11 @@ int xj_wlist_set_aliases(xj_wlist jwl, char *als, char *jd, char *pa) LM_DBG("not enough SHMemory!\n"); goto clean; } - + strncpy(jwl->aliases->a[i].s, p, jwl->aliases->a[i].len); #ifdef XJ_EXTRA_DEBUG - LM_DBG("alias[%d/%d]=%.*s delim=%c\n", - i+1, jwl->aliases->size, jwl->aliases->a[i].len, + LM_DBG("alias[%d/%d]=%.*s delim=%c\n", + i+1, jwl->aliases->size, jwl->aliases->a[i].len, jwl->aliases->a[i].s, jwl->aliases->d[i]?jwl->aliases->d[i]:'X'); #endif p = p0 + 1; @@ -592,27 +592,27 @@ int xj_wlist_check_aliases(xj_wlist jwl, str *addr) p++; if(p >= addr->s + addr->len) return -1; - + p++; ll = addr->s + addr->len - p; - + // check parameters p0 = p; while(p0 < p + ll && *p0 != ';') p0++; if(p0 < p + ll) ll = p0 - p; - + ll = addr->s + addr->len - p; - if(jwl->aliases->jdm && jwl->aliases->jdm->len == ll && + if(jwl->aliases->jdm && jwl->aliases->jdm->len == ll && !strncasecmp(jwl->aliases->jdm->s, p, ll)) return 0; if(jwl->aliases->size <= 0) return 1; - + for(i = 0; i < jwl->aliases->size; i++) - if(jwl->aliases->a[i].len == ll && + if(jwl->aliases->a[i].len == ll && !strncasecmp(p, jwl->aliases->a[i].s, ll)) return 0; return 1; diff --git a/modules/jabber/xjab_worker.c b/modules/jabber/xjab_worker.c index 9b4003221e9..056f5eedebb 100644 --- a/modules/jabber/xjab_worker.c +++ b/modules/jabber/xjab_worker.c @@ -17,7 +17,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * @@ -93,20 +93,20 @@ int xj_address_translation(str *src, str *dst, xj_jalias als, int flag) { char *p, *p0; int i, ll; - + if(!src || !dst || !src->s || !dst->s ) - return -1; - + return -1; + if(!als || !als->jdm || !als->jdm->s || als->jdm->len <= 0) goto done; - + dst->len = 0; #ifdef XJ_EXTRA_DEBUG LM_DBG("%d: - checking aliases\n", _xj_pid); #endif p = src->s; - while(p<(src->s + src->len) && *p != '@') + while(p<(src->s + src->len) && *p != '@') p++; if(*p != '@') goto done; @@ -117,12 +117,12 @@ int xj_address_translation(str *src, str *dst, xj_jalias als, int flag) #ifdef XJ_EXTRA_DEBUG LM_DBG("%d: - domain is [%.*s]\n",_xj_pid,ll,p); #endif - + /*** checking aliases */ if(als->size > 0) { for(i=0; isize; i++) - if(als->a[i].len == ll && + if(als->a[i].len == ll && !strncasecmp(p, als->a[i].s, als->a[i].len)) { if(als->d[i]) @@ -131,7 +131,7 @@ int xj_address_translation(str *src, str *dst, xj_jalias als, int flag) { strncpy(dst->s, src->s, src->len); p0 = dst->s; - while(p0 < dst->s + (p-src->s)) + while(p0 < dst->s + (p-src->s)) { if(*p0 == als->dlm) *p0 = als->d[i]; @@ -143,12 +143,12 @@ int xj_address_translation(str *src, str *dst, xj_jalias als, int flag) { strncpy(dst->s, src->s, src->len); p0 = dst->s; - while(p0 < dst->s + (p-src->s)) + while(p0 < dst->s + (p-src->s)) { if(*p0 == als->d[i]) *p0 = als->dlm; p0++; - } + } return 0; } } @@ -158,9 +158,9 @@ int xj_address_translation(str *src, str *dst, xj_jalias als, int flag) #ifdef XJ_EXTRA_DEBUG LM_DBG("%d: - doing address correction\n", - _xj_pid); + _xj_pid); #endif - + if(flag & XJ_ADDRTR_S2J) { if(als->jdm->len != ll || strncasecmp(p, als->jdm->s, als->jdm->len)) @@ -235,11 +235,11 @@ int xj_address_translation(str *src, str *dst, xj_jalias als, int flag) done: dst->s = src->s; dst->len = src->len; - return 0; + return 0; } /** - * worker implementation + * worker implementation * - jwl : pointer to the workers list * - jaddress : address of the jabber server * - jport : port of the jabber server @@ -267,7 +267,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, static str tmp2 = str_init("type"); static str tmp3 = str_init("jab_id"); static str tmp4 = str_init("jab_passwd"); - + db_key_t keys[] = {&tmp1, &tmp2}; db_val_t vals[2]; db_key_t col[] = {&tmp3, &tmp4}; @@ -279,9 +279,9 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, vals[1].type=DB_INT; vals[1].nul=0; vals[1].val.int_val=0; - + _xj_pid = getpid(); - + //signal(SIGTERM, xj_sig_handler); //signal(SIGINT, xj_sig_handler); //signal(SIGQUIT, xj_sig_handler); @@ -299,7 +299,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, } } - if(!jwl || !jwl->aliases || !jwl->aliases->jdm + if(!jwl || !jwl->aliases || !jwl->aliases->jdm || !jaddress || rank >= jwl->len) { LM_DBG("[%d]:%d: exiting - wrong parameters\n", rank, _xj_pid); @@ -333,10 +333,10 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, tmv.tv_usec = 0; ret = select(maxfd+1, &mset, NULL, NULL, &tmv); - + // check the msg queue xj_worker_check_qmsg(jwl, jcp); - + if(ret <= 0) goto step_x; @@ -345,7 +345,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, #endif if(!FD_ISSET(pipe, &mset)) goto step_y; - + if(read(pipe, &jsmsg, sizeof(jsmsg)) < (int)sizeof(jsmsg)) { LM_DBG("%d: BROKEN PIPE - exiting\n", _xj_pid); @@ -363,7 +363,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, buff[jsmsg->jkey->id->len] = 0; jbc = xj_jcon_pool_get(jcp, jsmsg->jkey); - + switch(jsmsg->type) { case XJ_SEND_MESSAGE: @@ -399,7 +399,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, default: goto step_w; } - + if(jbc != NULL) { #ifdef XJ_EXTRA_DEBUG @@ -409,11 +409,11 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, xj_jcon_update(jbc, jwl->cachet); goto step_z; } - + // NO OPEN CONNECTION FOR THIS SIP ID #ifdef XJ_EXTRA_DEBUG LM_DBG("%d: new connection for <%s>.\n", _xj_pid, buff); -#endif +#endif if(dbf->query(db_con, keys, 0, vals, col, 2, 2, NULL, &res) != 0 || RES_ROW_N(res) <= 0) { @@ -421,29 +421,29 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, LM_DBG("%d: no database result when looking" " for associated Jabber account\n", _xj_pid); #endif - xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, + xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, XJ_DMSG_ERR_JGWFORB, NULL); - + goto step_v; } - + jbc = xj_jcon_init(jaddress, jport); - + if(xj_jcon_connect(jbc)) { LM_DBG("%d: Cannot connect" " to the Jabber server ...\n", _xj_pid); - xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, + xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, XJ_DMSG_ERR_NOJSRV, NULL); goto step_v; } - + #ifdef XJ_EXTRA_DEBUG LM_DBG("auth to jabber as: [%s] / [xxx]\n", (char*)(ROW_VALUES(RES_ROWS(res))[0].val.string_val)); // (char*)(ROW_VALUES(RES_ROWS(res))[1].val.string_val)); -#endif +#endif if(xj_jcon_user_auth(jbc, (char*)(ROW_VALUES(RES_ROWS(res))[0].val.string_val), (char*)(ROW_VALUES(RES_ROWS(res))[1].val.string_val), @@ -451,26 +451,26 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, { LM_DBG("athentication to the Jabber server failed ...\n"); xj_jcon_disconnect(jbc); - - xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, + + xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, XJ_DMSG_ERR_JAUTH, NULL); - + xj_jcon_free(jbc); goto step_v; } - + if(xj_jcon_set_attrs(jbc, jsmsg->jkey, jwl->cachet, jwl->delayt) || xj_jcon_pool_add(jcp, jbc)) { LM_DBG("keeping connection to Jabber server" " failed! Not enough memory ...\n"); xj_jcon_disconnect(jbc); - xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, + xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, XJ_DMSG_ERR_JGWFULL, NULL); xj_jcon_free(jbc); goto step_v; } - + /** add socket descriptor to select */ #ifdef XJ_EXTRA_DEBUG LM_DBG("add connection on <%d> \n",jbc->sock); @@ -478,13 +478,13 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, if(jbc->sock > maxfd) maxfd = jbc->sock; FD_SET(jbc->sock, &set); - + xj_jcon_get_roster(jbc); xj_jcon_send_presence(jbc, NULL, NULL, "Online", priority); - + /** wait for a while - the worker is tired */ //sleep(3); - + if ((res != NULL) && (dbf->free_result(db_con,res) < 0)) { LM_DBG("failed to free SQL result - worker terminated\n"); @@ -496,13 +496,13 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, step_z: if(jsmsg->type == XJ_GO_ONLINE) goto step_w; - + if(jsmsg->type == XJ_REG_WATCHER) { // update or register a presence watcher xj_worker_check_watcher(jwl, jcp, jbc, jsmsg); goto step_w; } - + flag = 0; if(!xj_jconf_check_addr(&jsmsg->to, jwl->aliases->dlm)) { @@ -510,14 +510,14 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, != NULL) { if((jsmsg->type == XJ_JOIN_JCONF) && - !(jcf->status & XJ_JCONF_READY || + !(jcf->status & XJ_JCONF_READY || jcf->status & XJ_JCONF_WAITING)) { if(!xj_jcon_jconf_presence(jbc,jcf,NULL,"online")) jcf->status = XJ_JCONF_WAITING; else { - // unable to join the conference + // unable to join the conference // --- send back to SIP user a msg xj_send_sip_msgz(_PADDR(jwl),jsmsg->jkey->id,&jsmsg->to, XJ_DMSG_ERR_JOINJCONF, &jbc->jkey->flag); @@ -528,7 +528,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, } else { - // unable to get the conference + // unable to get the conference // --- send back to SIP user a msg xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, XJ_DMSG_ERR_NEWJCONF, &jbc->jkey->flag); @@ -537,7 +537,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, } if(jsmsg->type != XJ_SEND_MESSAGE) goto step_w; - + // here will come only XJ_SEND_MESSAGE switch(xj_jcon_is_ready(jbc,jsmsg->to.s,jsmsg->to.len,jwl->aliases->dlm)) { @@ -546,24 +546,24 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, LM_DBG("sending the message to Jabber network ...\n"); #endif /*** address correction ***/ - sto.s = buff; + sto.s = buff; sto.len = 0; flag |= XJ_ADDRTR_S2J; - if(xj_address_translation(&jsmsg->to, &sto, jwl->aliases, + if(xj_address_translation(&jsmsg->to, &sto, jwl->aliases, flag) == 0) { if(xj_jcon_send_msg(jbc, sto.s, sto.len, jsmsg->msg.s, jsmsg->msg.len, (flag&XJ_ADDRTR_CON)?XJ_JMSG_GROUPCHAT:XJ_JMSG_CHAT)<0) - + xj_send_sip_msgz(_PADDR(jwl),jsmsg->jkey->id,&jsmsg->to, XJ_DMSG_ERR_SENDJMSG, &jbc->jkey->flag); } else LM_ERR("sending as Jabber message ...\n"); - + goto step_w; - + case 1: #ifdef XJ_EXTRA_DEBUG LM_DBG("scheduling the message.\n"); @@ -578,7 +578,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, } else // skip freeing the SIP message - now is in queue goto step_y; - + case 2: xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, XJ_DMSG_ERR_NOREGIM, &jbc->jkey->flag); @@ -587,7 +587,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, XJ_DMSG_ERR_NOTJCONF, &jbc->jkey->flag); goto step_w; - + default: xj_send_sip_msgz(_PADDR(jwl), jsmsg->jkey->id, &jsmsg->to, XJ_DMSG_ERR_SENDJMSG, &jbc->jkey->flag); @@ -595,7 +595,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, } step_v: // error connecting to Jabber server - + // cleaning jab_wlist xj_wlist_del(jwl, jsmsg->jkey, _xj_pid); @@ -613,9 +613,9 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, { xj_sipmsg_free(jsmsg); jsmsg = NULL; - } + } -step_y: +step_y: // check for new message from ... JABBER for(i = 0; i < jcp->len && main_loop; i++) { @@ -640,7 +640,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, } *p = 0; /** - * flush out the socket - set it to nonblocking + * flush out the socket - set it to nonblocking */ flags = fcntl(jcp->ojc[i]->sock, F_GETFL, 0); if(flags!=-1 && !(flags & O_NONBLOCK)) @@ -649,8 +649,8 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, fcntl(jcp->ojc[i]->sock, F_SETFL, flags|O_NONBLOCK); } } - - if((nr = read(jcp->ojc[i]->sock, p, + + if((nr = read(jcp->ojc[i]->sock, p, sizeof(recv_buff)-(p-recv_buff))) == 0 ||(nr < 0 && errno != EAGAIN)) { @@ -678,9 +678,9 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, #endif } while(xj_manage_jab(recv_buff, nr, &pos, jwl->aliases, jcp->ojc[i]) == 9 && main_loop); - + /** - * flush out the socket - set it back to blocking + * flush out the socket - set it back to blocking */ flags = fcntl(jcp->ojc[i]->sock, F_GETFL, 0); if(flags!=-1 && (flags & O_NONBLOCK)) @@ -689,7 +689,7 @@ int xj_worker_process(xj_wlist jwl, char* jaddress, int jport, char* priority, fcntl(jcp->ojc[i]->sock, F_SETFL, flags & ~O_NONBLOCK); } #ifdef XJ_EXTRA_DEBUG - LM_DBG("msgs from socket <%d> parsed ...\n", jcp->ojc[i]->sock); + LM_DBG("msgs from socket <%d> parsed ...\n", jcp->ojc[i]->sock); #endif } // end FOR(i = 0; i < jcp->len; i++) @@ -744,11 +744,11 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) if(!jbc) return -1; - sid = jbc->jkey->id; + sid = jbc->jkey->id; x = xode_from_strx(buf, len, &err, &j); #ifdef XJ_EXTRA_DEBUG LM_DBG("xode ret:%d pos:%d\n", err, j); -#endif +#endif if(err && pos != NULL) *pos= j; if(x == NULL) @@ -757,7 +757,7 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) ecode = NULL; /******************** XMPP 'MESSAGE' HANDLING **********************/ - + if(!strncasecmp(xode_get_name(x), "message", 7)) { #ifdef XJ_EXTRA_DEBUG @@ -819,7 +819,7 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) p--; if(*p == '/') { - if(jcf->nick.len>0 + if(jcf->nick.len>0 && strlen(p+1) == jcf->nick.len && !strncasecmp(p+1, jcf->nick.s, jcf->nick.len)) { @@ -842,7 +842,7 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) strcat(lbuf, msg); ts.s = lbuf; ts.len = strlen(lbuf); - + if(xj_send_sip_msg(als->proxy, sid, &jcf->uri, &ts, &jbc->jkey->flag)<0) LM_ERR("sip message was not sent!\n"); @@ -862,7 +862,7 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) { ts.s = lbuf; ts.len = strlen(lbuf); - + if(xj_send_sip_msg(als->proxy, sid, &tf, &ts, &jbc->jkey->flag)<0) LM_ERR("sip message was not sent!\n"); #ifdef XJ_EXTRA_DEBUG @@ -873,7 +873,7 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) goto ready; } /*------------------- END 'MESSAGE' HANDLING ----------------------*/ - + /******************** XMPP 'PRESENCE' HANDLING *********************/ if(!strncasecmp(xode_get_name(x), "presence", 8)) { @@ -978,11 +978,11 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) } goto ready; } - + if(strchr(from, '@') == NULL) goto ready; - - + + if(!strncasecmp(type, "error", 5)) { if((jcf=xj_jcon_check_jconf(jbc, from))!=NULL) @@ -1025,7 +1025,7 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) } goto ready; } - + if(!strncasecmp(type, "unsubscribed", 12)) { #ifdef XJ_EXTRA_DEBUG @@ -1038,12 +1038,12 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) goto call_pa_cbf; } } - + // ignoring unknown types goto ready; } /*------------------- END XMPP 'PRESENCE' HANDLING ----------------*/ - + /******************** XMPP 'IQ' HANDLING ***************************/ if(!strncasecmp(xode_get_name(x), "iq", 2)) { @@ -1097,7 +1097,7 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) z = xode_get_nextsibling(z); } } - + goto ready; } /*------------------- END XMPP 'IQ' HANDLING ----------------------*/ @@ -1124,7 +1124,7 @@ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) /** * */ -void xj_sig_handler(int s) +void xj_sig_handler(int s) { //signal(SIGTERM, xj_sig_handler); //signal(SIGINT, xj_sig_handler); @@ -1152,8 +1152,8 @@ int xj_send_sip_msg(str *proxy, str *to, str *from, str *msg, int *cbp) str str_hdr; char buf1[1024]; - if( !to || !to->s || to->len <= 0 - || !from || !from->s || from->len <= 0 + if( !to || !to->s || to->len <= 0 + || !from || !from->s || from->len <= 0 || !msg || !msg->s || msg->len <= 0 || (cbp && *cbp!=0) ) return -1; @@ -1165,16 +1165,16 @@ int xj_send_sip_msg(str *proxy, str *to, str *from, str *msg, int *cbp) strncpy(buf+tfrom.len, from->s, from->len); tfrom.len += from->len; buf[tfrom.len++] = '>'; - + tfrom.s = buf; - + // building Contact and Content-Type strcpy(buf1,"Content-Type: text/plain"CRLF"Contact: "); str_hdr.len = 24 + CRLF_LEN + 9; - + strncat(buf1,tfrom.s,tfrom.len); str_hdr.len += tfrom.len; - + strcat(buf1, CRLF); str_hdr.len += CRLF_LEN; str_hdr.s = buf1; @@ -1183,7 +1183,7 @@ int xj_send_sip_msg(str *proxy, str *to, str *from, str *msg, int *cbp) #ifdef XJ_EXTRA_DEBUG LM_DBG("uac callback parameter [%p==%d]\n", cbp, *cbp); #endif - return tmb.t_request(&msg_type, 0, to, &tfrom, &str_hdr, msg, + return tmb.t_request(&msg_type, 0, to, &tfrom, &str_hdr, msg, 0, xj_tuac_callback, (void*)cbp, 0); } else @@ -1278,7 +1278,7 @@ void xj_worker_check_jcons(xj_wlist jwl, xj_jcon_pool jcp, int ltime, fd_set *ps { int i; xj_jconf jcf; - + for(i = 0; i < jcp->len && main_loop; i++) { if(jcp->ojc[i] == NULL) @@ -1286,7 +1286,7 @@ void xj_worker_check_jcons(xj_wlist jwl, xj_jcon_pool jcp, int ltime, fd_set *ps if(jcp->ojc[i]->jkey->flag==XJ_FLAG_OPEN && jcp->ojc[i]->expire > ltime) continue; - + #ifdef XJ_EXTRA_DEBUG LM_DBG("connection expired for <%.*s> \n", jcp->ojc[i]->jkey->id->len, jcp->ojc[i]->jkey->id->s); @@ -1302,7 +1302,7 @@ void xj_worker_check_jcons(xj_wlist jwl, xj_jcon_pool jcp, int ltime, fd_set *ps // looking for open conference rooms #ifdef XJ_EXTRA_DEBUG - LM_DBG("having %d open conferences\n", + LM_DBG("having %d open conferences\n", jcp->ojc[i]->nrjconf); #endif while(jcp->ojc[i]->nrjconf > 0) @@ -1363,10 +1363,10 @@ void xj_worker_check_qmsg(xj_wlist jwl, xj_jcon_pool jcp) { #ifdef XJ_EXTRA_DEBUG LM_DBG("message to %.*s is expired\n", - jcp->jmqueue.jsm[i]->to.len, + jcp->jmqueue.jsm[i]->to.len, jcp->jmqueue.jsm[i]->to.s); #endif - xj_send_sip_msgz(_PADDR(jwl), jcp->jmqueue.jsm[i]->jkey->id, + xj_send_sip_msgz(_PADDR(jwl), jcp->jmqueue.jsm[i]->jkey->id, &jcp->jmqueue.jsm[i]->to, XJ_DMSG_ERR_SENDIM, &jcp->jmqueue.ojc[i]->jkey->flag); if(jcp->jmqueue.jsm[i]!=NULL) @@ -1381,7 +1381,7 @@ void xj_worker_check_qmsg(xj_wlist jwl, xj_jcon_pool jcp) #ifdef XJ_EXTRA_DEBUG LM_DBG("%d: QUEUE: message[%d] from [%.*s]" "/to [%.*s]/body[%.*s] expires at %d\n", - get_ticks(), i, + get_ticks(), i, jcp->jmqueue.jsm[i]->jkey->id->len, jcp->jmqueue.jsm[i]->jkey->id->s, jcp->jmqueue.jsm[i]->to.len,jcp->jmqueue.jsm[i]->to.s, @@ -1391,13 +1391,13 @@ void xj_worker_check_qmsg(xj_wlist jwl, xj_jcon_pool jcp) if(xj_jcon_is_ready(jcp->jmqueue.ojc[i], jcp->jmqueue.jsm[i]->to.s, jcp->jmqueue.jsm[i]->to.len, jwl->aliases->dlm)) continue; - + /*** address correction ***/ flag = XJ_ADDRTR_S2J; if(!xj_jconf_check_addr(&jcp->jmqueue.jsm[i]->to,jwl->aliases->dlm)) flag |= XJ_ADDRTR_CON; - - sto.s = buff; + + sto.s = buff; sto.len = 0; if(xj_address_translation(&jcp->jmqueue.jsm[i]->to, &sto, jwl->aliases, flag) == 0) @@ -1416,7 +1416,7 @@ void xj_worker_check_qmsg(xj_wlist jwl, xj_jcon_pool jcp) else LM_ERR("sending the message from" " local queue to Jabber network ...\n"); - + if(jcp->jmqueue.jsm[i]!=NULL) { xj_sipmsg_free(jcp->jmqueue.jsm[i]); @@ -1458,11 +1458,11 @@ void xj_worker_check_watcher(xj_wlist jwl, xj_jcon_pool jcp, (*(jsmsg->cbf))(&jsmsg->to, &jsmsg->to, XJ_PS_OFFLINE, jsmsg->p); return; } - - sto.s = buff; + + sto.s = buff; sto.len = 0; - if(xj_address_translation(&jsmsg->to, &sto, jwl->aliases, + if(xj_address_translation(&jsmsg->to, &sto, jwl->aliases, XJ_ADDRTR_S2J) == 0) { prc = xj_pres_list_check(jbc->plist, &sto); @@ -1492,7 +1492,7 @@ void xj_worker_check_watcher(xj_wlist jwl, xj_jcon_pool jcp, } sto.s[sto.len] = 0; if(!xj_jcon_send_subscribe(jbc, sto.s, NULL, "subscribe")) - prc->status = XJ_PRES_STATUS_WAIT; + prc->status = XJ_PRES_STATUS_WAIT; } else { diff --git a/modules/jabber/xjab_worker.h b/modules/jabber/xjab_worker.h index 4a04dbd8e5b..2a349149c9b 100644 --- a/modules/jabber/xjab_worker.h +++ b/modules/jabber/xjab_worker.h @@ -83,7 +83,7 @@ void xj_wlist_del(xj_wlist, xj_jkey, int); void xj_wlist_free(xj_wlist); int xj_wlist_set_aliases(xj_wlist, char *, char *, char *); int xj_wlist_check_aliases(xj_wlist, str*); -int xj_wlist_clean_jobs(xj_wlist, int, int); +int xj_wlist_clean_jobs(xj_wlist, int, int); int xj_worker_process(xj_wlist, char*, int, char*, int, db_con_t*, db_func_t*); diff --git a/modules/jabber/xode.c b/modules/jabber/xode.c index 025d129a21e..d7a37054539 100644 --- a/modules/jabber/xode.c +++ b/modules/jabber/xode.c @@ -561,14 +561,14 @@ char* xode_get_data(xode node) int xode_get_datasz(xode node) { - + if( node == NULL ) { - return (int)(long)NULL; - } + return (int)(long)NULL; + } else if(xode_get_type(node) == XODE_TYPE_TAG) /* loop till we find a CDATA */ { - xode cur; + xode cur; for(cur = xode_get_firstchild(node); cur != NULL; cur = xode_get_nextsibling(cur)) if(xode_get_type(cur) == XODE_TYPE_CDATA) return cur->data_sz; @@ -814,8 +814,8 @@ _xode_to_prettystr( xode_spool s, xode x, int deep ) xode y; if(xode_get_type(x) != XODE_TYPE_TAG) return; - - for(i=0; i"); xode_spool_add(s,"\n"); - + if( xode_get_data(x)) { - for(i=0; i<=deep; i++) xode_spool_add(s, "\t"); - xode_spool_add( s , xode_get_data(x)); + for(i=0; i<=deep; i++) xode_spool_add(s, "\t"); + xode_spool_add( s , xode_get_data(x)); } - + y = xode_get_firstchild(x); while( y ) { @@ -842,20 +842,20 @@ _xode_to_prettystr( xode_spool s, xode x, int deep ) y = xode_get_nextsibling(y); xode_spool_add(s,"\n"); } - - for(i=0; i" , s ); return; } -char * +char * xode_to_prettystr( xode x ) { xode_spool s; if( !x) return NULL; - + s = xode_spool_newfrompool( xode_get_pool(x)); _xode_to_prettystr( s , x, 0 ); diff --git a/modules/jabber/xode.h b/modules/jabber/xode.h index 22bef98a90d..ad141a01e35 100644 --- a/modules/jabber/xode.h +++ b/modules/jabber/xode.h @@ -85,7 +85,7 @@ extern int ap_vsnprintf(char *, size_t, const char *, va_list ap); /* xode_pool_cleaner - callback type which is associated - with a pool entry; invoked when the pool entry is + with a pool entry; invoked when the pool entry is free'd */ typedef void (*xode_pool_cleaner)(void *arg); @@ -112,20 +112,20 @@ xode_pool xode_pool_new(void); /* pool wrappers for malloc */ void *xode_pool_malloc (xode_pool p, int size); -void *xode_pool_mallocx (xode_pool p, int size, char c); -void *xode_pool_malloco (xode_pool p, int size); +void *xode_pool_mallocx (xode_pool p, int size, char c); +void *xode_pool_malloco (xode_pool p, int size); /* wrapper around strdup, gains mem from pool */ -char *xode_pool_strdup (xode_pool p, const char *src); +char *xode_pool_strdup (xode_pool p, const char *src); /* calls f(arg) before the pool is freed during cleanup */ -void xode_pool_cleanup (xode_pool p, xode_pool_cleaner f, void *arg); +void xode_pool_cleanup (xode_pool p, xode_pool_cleaner f, void *arg); /* pool wrapper for free, called on a pool */ -void xode_pool_free (xode_pool p); +void xode_pool_free (xode_pool p); /* returns total bytes allocated in this pool */ -int xode_pool_size (xode_pool p); +int xode_pool_size (xode_pool p); /* --------------------------------------------------------- */ /* */ @@ -178,8 +178,8 @@ void xode_spool_free ( xode_spool s ); /* Free's t #define XODE_TYPE_LAST 2 #define XODE_TYPE_UNDEF -1 -/* -------------------------------------------------------------------------- - Node structure. Do not use directly! Always use accessors macros +/* -------------------------------------------------------------------------- + Node structure. Do not use directly! Always use accessors macros and methods! -------------------------------------------------------------------------- */ typedef struct xode_struct @@ -191,9 +191,9 @@ typedef struct xode_struct int complete; xode_pool p; struct xode_struct* parent; - struct xode_struct* firstchild; + struct xode_struct* firstchild; struct xode_struct* lastchild; - struct xode_struct* prev; + struct xode_struct* prev; struct xode_struct* next; struct xode_struct* firstattrib; struct xode_struct* lastattrib; @@ -204,7 +204,7 @@ xode xode_wrap(xode x,const char* wrapper); xode xode_new(const char* name); xode xode_new_tag(const char* name); xode xode_new_frompool(xode_pool p, const char* name); -xode xode_insert_tag(xode parent, const char* name); +xode xode_insert_tag(xode parent, const char* name); xode xode_insert_cdata(xode parent, const char* CDATA, unsigned int size); xode xode_insert_tagnode(xode parent, xode node); void xode_insert_node(xode parent, xode node); diff --git a/modules/jabber/xode_from.c b/modules/jabber/xode_from.c index 019148d8727..ff24070df93 100644 --- a/modules/jabber/xode_from.c +++ b/modules/jabber/xode_from.c @@ -130,11 +130,11 @@ xode xode_from_strx(char *str, int len, int *err, int *pos) if(err != NULL) *err = XML_GetErrorCode(p); if(pos != NULL) - *pos = XML_GetCurrentByteIndex(p); + *pos = XML_GetCurrentByteIndex(p); node = *x; free(x); XML_ParserFree(p); - + return node; /* return the xmlnode x points to */ } diff --git a/modules/jabber/xode_str.c b/modules/jabber/xode_str.c index bbc3604b309..10e5e740b7d 100644 --- a/modules/jabber/xode_str.c +++ b/modules/jabber/xode_str.c @@ -34,7 +34,7 @@ int xode_spool_getlen(const xode_spool s) if(s == NULL) return 0; - return s->len; + return s->len; } void xode_spool_free(xode_spool s) diff --git a/modules/jabber/xpool.c b/modules/jabber/xpool.c index 884e8ec58e9..246d35b99d5 100644 --- a/modules/jabber/xpool.c +++ b/modules/jabber/xpool.c @@ -17,26 +17,26 @@ * * Jabber * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ - * + * * 2/27/00:3am, random plans by jer - * + * * ok based on gprof, we really need some innovation here... my thoughs are this: - * + * * most things are strings, so have a string-based true-blue garbage collector * one big global hash containing all the strings created by any pstrdup, returning const char * * a refcount on each string block * when a pool is freed, it moves down the refcount * garbage collector collects pools on the free stack, and runs through the hash for unused strings * j_strcmp can check for == (if they are both from a pstrdup) - * + * * let's see... this would change: * pstrdup: do a hash lookup, success=return, fail=pmalloc & hash put - * pool_free: - * - * - * - * - * + * pool_free: + * + * + * + * + * */ #include "xode.h" @@ -175,7 +175,7 @@ void *xode_pool_mallocx(xode_pool p, int size, char c) if (result != NULL) memset(result, c, size); return result; -} +} /* easy safety utility (for creating blank mem for structs, etc) */ void *xode_pool_malloco(xode_pool p, int size) @@ -183,7 +183,7 @@ void *xode_pool_malloco(xode_pool p, int size) void *block = xode_pool_malloc(p, size); memset(block, 0, size); return block; -} +} /* XXX efficient: move this to const char * and then loop through the existing heaps to see if src is within a block in this pool */ char *xode_pool_strdup(xode_pool p, const char *src) diff --git a/modules/jabber/xsnprintf.c b/modules/jabber/xsnprintf.c index 0db801797cd..a47c31cdacd 100644 --- a/modules/jabber/xsnprintf.c +++ b/modules/jabber/xsnprintf.c @@ -8,7 +8,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -366,7 +366,7 @@ conv_10(register wide_int num, register bool_int is_unsigned, *is_negative = (num < 0); /* - * On a 2's complement machine, negating the most negative integer + * On a 2's complement machine, negating the most negative integer * results in a number that cannot be represented as a signed integer. * Here is what we do to obtain the number's magnitude: * a. add 1 to the number @@ -383,7 +383,7 @@ conv_10(register wide_int num, register bool_int is_unsigned, } /* - * We use a do-while loop so that we write at least 1 digit + * We use a do-while loop so that we write at least 1 digit */ do { register u_wide_int new_magnitude = magnitude / 10; @@ -806,11 +806,11 @@ static int format_converter(register buffy * odp, const char *fmt, break; /* - * Always extract the argument as a "char *" pointer. We - * should be using "void *" but there are still machines + * Always extract the argument as a "char *" pointer. We + * should be using "void *" but there are still machines * that don't understand it. * If the pointer size is equal to the size of an unsigned - * integer we convert the pointer to a hex number, otherwise + * integer we convert the pointer to a hex number, otherwise * we print "%p" to indicate that we don't handle "%p". */ case 'p': @@ -868,7 +868,7 @@ static int format_converter(register buffy * odp, const char *fmt, PAD(min_width, s_len, pad_char); } /* - * Print the string s. + * Print the string s. */ for (i = s_len; i != 0; i--) { INS_CHAR(*s, sp, bep, cc); diff --git a/modules/jabber/xstream.c b/modules/jabber/xstream.c index 0f98cc92bda..ec59e1dab17 100644 --- a/modules/jabber/xstream.c +++ b/modules/jabber/xstream.c @@ -138,7 +138,7 @@ xode_stream xode_stream_new(xode_pool p, xode_stream_onNode f, void *arg) XML_SetElementHandler(newx->parser, (void (*)(void*, const char*, const char**))_xode_stream_startElement, (void (*)(void*, const char*))_xode_stream_endElement); - XML_SetCharacterDataHandler(newx->parser, + XML_SetCharacterDataHandler(newx->parser, (void (*)(void*, const char*, int))_xode_stream_charData); xode_pool_cleanup(p, _xode_stream_cleanup, (void *)newx); diff --git a/modules/json/Makefile b/modules/json/Makefile index ef5bd87a15c..5c514655bec 100644 --- a/modules/json/Makefile +++ b/modules/json/Makefile @@ -8,7 +8,24 @@ include ../../Makefile.defs auto_gen= NAME=json.so -DEFS+=-I$(LOCALBASE)/include -LIBS=-L$(LOCALBASE)/lib -ljson + +ifeq ($(CROSS_COMPILE),) +JSON_BUILDER = $(shell \ + if pkg-config --exists json; then \ + echo 'pkg-config json'; \ + elif pkg-config --exists json-c; then\ + echo 'pkg-config json-c'; \ + fi) + +endif + +ifeq ($(JSON_BUILDER),) + DEFS += -I$(LOCALBASE)/include -I$(SYSBASE)/include + LIBS += -L$(LOCALBASE)/lib -ljson +else + JSON_LIB_VER = $(shell $(JSON_BUILDER) --modversion | sed "s/\.\([0-9]\)\./.0\1./g" | sed "s/\.\([0-9]\)\$$/.0\1/g" | tr -d "." | sed -e "s/^0*//" ) + DEFS += $(shell $(JSON_BUILDER) --cflags) -DJSON_LIB_VERSION=$(JSON_LIB_VER) + LIBS += $(shell $(JSON_BUILDER) --libs) +endif include ../../Makefile.modules diff --git a/modules/json/README b/modules/json/README index 80443f8ad90..934744ada85 100644 --- a/modules/json/README +++ b/modules/json/README @@ -2,7 +2,7 @@ JSON Module Andrei Dragus - Voice Sistem SRL + OpenSIPS Solutions Edited by @@ -10,8 +10,7 @@ Andrei Dragus Copyright © 2009 Voice Sistem SRL Revision History - Revision $Revision: 6078 $ $Date: 2009-09-04 15:16:18 +0300 - (Fri, 04 Sep 2009) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -77,7 +76,7 @@ Chapter 1. Admin Guide 1.2.2. External Libraries or Applications - * libjson The libjson library can be downloaded from: + * libjson The libjson C library can be downloaded from: http://oss.metaparadigm.com/json-c/ 1.3. Exported Parameters @@ -89,7 +88,7 @@ Chapter 1. Admin Guide This module exports the $json(id) variable. The json variable provides methods to access fields in json - objects and to access indexes in json arrays. + objects and indexes in json arrays. 1.4.1. Variable lifetime diff --git a/modules/json/array_del.c b/modules/json/array_del.c index b0380591d88..d5ee2dfdf70 100644 --- a/modules/json/array_del.c +++ b/modules/json/array_del.c @@ -26,8 +26,8 @@ * 2009-09-04 first version (andreidragus) */ -#include -#include +#include +#include void array_list_del_idx( struct array_list * arr, int idx) { @@ -47,4 +47,4 @@ void array_list_del_idx( struct array_list * arr, int idx) void json_object_array_del(struct json_object* obj, int idx) { array_list_del_idx(obj->o.c_array, idx); -}; \ No newline at end of file +}; diff --git a/modules/json/doc/json_admin.xml b/modules/json/doc/json_admin.xml index dddc41a0080..e1df0465d3a 100644 --- a/modules/json/doc/json_admin.xml +++ b/modules/json/doc/json_admin.xml @@ -44,7 +44,7 @@ libjson - The libjson library can be downloaded from: + The libjson C library can be downloaded from: http://oss.metaparadigm.com/json-c/ @@ -72,7 +72,7 @@ The json variable provides methods to access fields - in json objects and to access indexes in json arrays. + in json objects and indexes in json arrays.
diff --git a/modules/json/json.c b/modules/json/json.c index 3b33f9091a3..cdf159b145c 100644 --- a/modules/json/json.c +++ b/modules/json/json.c @@ -47,8 +47,8 @@ #include "../rr/api.h" -#include -#include +#include +#include @@ -94,7 +94,7 @@ typedef struct _json_name str name; json_tag * tags; json_tag ** end; - + }json_name; @@ -135,8 +135,10 @@ static pv_export_t mod_items[] = { struct module_exports exports= { "json", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ 0, /* param exports */ 0, /* exported statistics */ @@ -225,7 +227,7 @@ int fixup_json_bind(void** param, int param_no) -struct json_object* json_parse(const char *str,int len) +struct json_object* json_parse(const char *str,int len,enum json_tokener_error *status) { struct json_tokener* tok; struct json_object* obj; @@ -235,10 +237,13 @@ struct json_object* json_parse(const char *str,int len) if( tok-> err == json_tokener_continue ) obj = json_tokener_parse_ex(tok, "", -1); - - if(tok->err != json_tokener_success) - obj = (struct json_object*)error_ptr(-tok->err); - + + if(tok->err != json_tokener_success) { + obj = NULL; + if (status) + *status = tok->err; + } + json_tokener_free(tok); return obj; } @@ -261,7 +266,7 @@ pv_json_t * get_pv_json (pv_param_t* pvp) } return cur; - + } @@ -278,10 +283,10 @@ json_t * get_object(pv_json_t * var, pv_param_t* pvp , json_tag ** tag, int poz; - + cur_tag = id->tags; cur_obj = var->data; - + while( cur_tag ) { @@ -297,13 +302,19 @@ json_t * get_object(pv_json_t * var, pv_param_t* pvp , json_tag ** tag, !json_object_is_type( cur_obj, json_type_object ) ) goto error; +#if JSON_LIB_VERSION < 10 cur_obj = json_object_object_get( cur_obj, buff ); if( cur_obj == NULL && tag == NULL) goto error; +#else + if (!json_object_object_get_ex( cur_obj,buff, &cur_obj ) && + tag == NULL) + goto error; +#endif + - } if( cur_tag->type & TAG_IDX ) @@ -336,7 +347,7 @@ json_t * get_object(pv_json_t * var, pv_param_t* pvp , json_tag ** tag, goto error; } - + cur_tag = cur_tag->next; } @@ -387,7 +398,7 @@ int pv_get_json (struct sip_msg* msg, pv_param_t* pvp, pv_value_t* val) if( var == NULL ) { - /* this is not an error - we simply came across a json spec + /* this is not an error - we simply came across a json spec * pointing a json var which was never set/init */ LM_DBG("Variable named:%.*s not found\n",id->name.len,id->name.s); return pv_get_null( msg, pvp, val); @@ -404,12 +415,20 @@ int pv_get_json (struct sip_msg* msg, pv_param_t* pvp, pv_value_t* val) val->rs.s = int2str(json_object_get_int(obj), &val->rs.len); val->ri = json_object_get_int(obj);; val->flags |= PV_VAL_INT|PV_TYPE_INT; - + } - else + else if( json_object_is_type(obj, json_type_string)) { val->flags = PV_VAL_STR; val->rs.s = (char*)json_object_get_string( obj ); +#if JSON_LIB_VERSION >= 10 + val->rs.len = json_object_get_string_len( obj ); +#else + val->rs.len = strlen(val->rs.s); +#endif + } else { + val->flags = PV_VAL_STR; + val->rs.s = (char*)json_object_to_json_string( obj ); val->rs.len = strlen(val->rs.s); } @@ -439,7 +458,7 @@ int pv_add_json ( pv_param_t* pvp, json_t * obj ) LM_ERR("Object is not initialized yet\n"); return -1; } - + var = (pv_json_t *) pkg_malloc(sizeof(pv_json_t)); if( var == NULL ) @@ -500,7 +519,7 @@ int pv_add_json ( pv_param_t* pvp, json_t * obj ) LM_ERR("Invalid parameter for deletion\n"); return -1; } - + json_object_array_add(dest,obj); return 0; @@ -508,7 +527,7 @@ int pv_add_json ( pv_param_t* pvp, json_t * obj ) if( poz < 0 ) poz += json_object_array_length(dest); - + @@ -543,6 +562,7 @@ int pv_set_json (struct sip_msg* msg, pv_param_t* pvp, int flag , { json_t * obj; + enum json_tokener_error parse_status; if( expand_tag_list( msg, ((json_name *)pvp->pvn.u.dname)->tags ) < 0) @@ -561,19 +581,24 @@ int pv_set_json (struct sip_msg* msg, pv_param_t* pvp, int flag , /* If we want the value to be interpreted prepare the object */ if( flag == COLONEQ_T ) { - + if( ! (val->flags & PV_VAL_STR) ) { LM_ERR("Trying to interpret a non-string value\n"); return -1; } - obj = json_parse( val->rs.s, val->rs.len); + obj = json_parse( val->rs.s, val->rs.len,&parse_status); - if (is_error(obj)) + if (obj == NULL) { LM_ERR("Error parsing json: %s\n", - json_tokener_errors[-(unsigned long)obj]); +#if JSON_LIB_VERSION >= 10 + json_tokener_error_desc(parse_status) +#else + json_tokener_errors[(unsigned long)obj] +#endif + ); return -1; } @@ -589,11 +614,11 @@ int pv_set_json (struct sip_msg* msg, pv_param_t* pvp, int flag , { obj = json_object_new_string_len( val->rs.s, val->rs.len); } - + } - + return pv_add_json(pvp,obj); } @@ -707,7 +732,7 @@ void print_tag_list( json_tag * start, json_tag * end, int err) cur = cur->next; } - + } } @@ -724,7 +749,7 @@ int get_value(int state, json_name * id, char *start, char * cur) if( state != ST_TEST ) LM_DBG("JSON tag type=%d value=%.*s\n",state,(int)(cur-start),start); - + switch(state) { case ST_NAME: @@ -758,7 +783,7 @@ int get_value(int state, json_name * id, char *start, char * cur) return 0; } - + node->key = in; break; @@ -770,7 +795,7 @@ int get_value(int state, json_name * id, char *start, char * cur) LM_ERR("Out of memory\n"); return -1; } - + memset(node,0,sizeof(json_tag)); node->type = TAG_IDX; *id->end = node; @@ -785,13 +810,13 @@ int get_value(int state, json_name * id, char *start, char * cur) empty = 0; break; } - + if( empty) { node->type |= TAG_END; return 0; } - + if( *i == '$' ) { @@ -811,7 +836,7 @@ int get_value(int state, json_name * id, char *start, char * cur) (int)(cur-start), start ); return -1; } - + break; @@ -906,7 +931,7 @@ int pv_parse_json_name (pv_spec_p sp, str *in) if ( get_value(state, id, start, cur) ) return -1; - + if( ignore[state][(unsigned int)*cur]) { cur --; @@ -914,7 +939,7 @@ int pv_parse_json_name (pv_spec_p sp, str *in) prev_state = state; state = next_state; - + } if( state == ST_IDX) @@ -944,7 +969,7 @@ int pv_parse_json_name (pv_spec_p sp, str *in) int mod_init(void) { - + return 0; } @@ -955,6 +980,6 @@ int child_init(int rank) void mod_destroy(void) { - + } diff --git a/modules/ldap/api.h b/modules/ldap/api.h index 8d604eecd42..e7bd34ef3fb 100644 --- a/modules/ldap/api.h +++ b/modules/ldap/api.h @@ -49,7 +49,7 @@ typedef int (*ldap_params_search_t)( int _scope, char** _attrs, char* _filter, - ...); + ...); typedef int (*ldap_url_search_t)( char* _ldap_url, @@ -68,7 +68,7 @@ typedef int (*ldap_str2scope_t)(char* scope_str); typedef int (*get_ldap_handle_t)(char* _lds_name, LDAP** _ldap_handle); typedef void (*get_last_ldap_result_t)( - LDAP** _last_ldap_handle, + LDAP** _last_ldap_handle, LDAPMessage** _last_ldap_result); typedef int (*ldap_rfc4515_escape_t)(str *sin, str *sout, int url_encode); diff --git a/modules/ldap/ld_session.c b/modules/ldap/ld_session.c index e394551db36..6fc484db288 100644 --- a/modules/ldap/ld_session.c +++ b/modules/ldap/ld_session.c @@ -45,7 +45,7 @@ int add_ld_session(char* _name, LDAP* _ldh, dictionary* _d) struct ld_session* new_lds = NULL; char *host_name, *bind_dn, *bind_pwd; int client_search_timeout_ms, client_bind_timeout_ms, network_timeout_ms; - + new_lds = (struct ld_session*)pkg_malloc(sizeof(struct ld_session)); if (new_lds == NULL) { @@ -58,7 +58,7 @@ int add_ld_session(char* _name, LDAP* _ldh, dictionary* _d) strncpy(new_lds->name, _name, 255); /* handle */ new_lds->handle = _ldh; - + /* host_name */ host_name = iniparser_getstring( _d, @@ -76,7 +76,7 @@ int add_ld_session(char* _name, LDAP* _ldh, dictionary* _d) _d, get_ini_key_name(_name, CFG_N_LDAP_VERSION), CFG_DEF_LDAP_VERSION); - + /* client_search_timeout */ client_search_timeout_ms = iniparser_getint( _d, @@ -103,9 +103,9 @@ int add_ld_session(char* _name, LDAP* _ldh, dictionary* _d) get_ini_key_name(_name, CFG_N_LDAP_CLIENT_BIND_TIMEOUT), CFG_DEF_LDAP_CLIENT_BIND_TIMEOUT); new_lds->client_bind_timeout.tv_sec = client_bind_timeout_ms / 1000; - new_lds->client_bind_timeout.tv_usec = + new_lds->client_bind_timeout.tv_usec = (client_bind_timeout_ms % 1000) * 1000; - + /* network_timeout */ network_timeout_ms = iniparser_getint( _d, @@ -141,11 +141,11 @@ int add_ld_session(char* _name, LDAP* _ldh, dictionary* _d) /* calculate_ha1 */ new_lds->calculate_ha1 = iniparser_getboolean( - _d, - get_ini_key_name(_name, CFG_N_CALCULATE_HA1), + _d, + get_ini_key_name(_name, CFG_N_CALCULATE_HA1), CFG_DEF_CALCULATE_HA1); - - + + if (current == NULL) { ld_sessions = new_lds; @@ -162,7 +162,7 @@ int add_ld_session(char* _name, LDAP* _ldh, dictionary* _d) struct ld_session* get_ld_session(char* _name) { struct ld_session* current = ld_sessions; - + if (_name == NULL) { LM_ERR("lds_name == NULL\n"); @@ -206,11 +206,11 @@ int free_ld_sessions(void) { pkg_free(current->bind_pwd); } - + pkg_free(current); current = tmp; } - + ld_sessions = NULL; return 0; diff --git a/modules/ldap/ldap_api_fn.c b/modules/ldap/ldap_api_fn.c index 48e7798874f..b2e9806328d 100644 --- a/modules/ldap/ldap_api_fn.c +++ b/modules/ldap/ldap_api_fn.c @@ -47,7 +47,7 @@ static LDAP* last_ldap_handle = NULL; static LDAPMessage* last_ldap_result = NULL; int get_connected_ldap_session( - char* _lds_name, + char* _lds_name, struct ld_session** _lds); int lds_search(char* _lds_name, char* _dn, @@ -93,7 +93,7 @@ int get_ldap_handle(char* _lds_name, LDAP** _ldap_handle) } int get_connected_ldap_session(char* _lds_name, struct ld_session** _lds) -{ +{ /* * get ld session */ @@ -137,7 +137,7 @@ int get_connected_ldap_session(char* _lds_name, struct ld_session** _lds) last_ldap_result = NULL; } */ - + return 0; } @@ -184,7 +184,7 @@ int ldap_params_search( { LM_ERR( "[%s]: filter string too long (len [%d], max len [%d])\n", _lds_name, - rc, + rc, LDAP_MAX_FILTER_LEN); return -1; } @@ -208,7 +208,7 @@ int ldap_params_search( != 0) { /* try again if LDAP API ERROR */ - if (LDAP_API_ERROR(rc) && + if (LDAP_API_ERROR(rc) && (lds_search(_lds_name, _dn, _scope, @@ -228,11 +228,11 @@ int ldap_params_search( return -1; } } - - LM_DBG( "[%s]: [%d] LDAP entries found\n", + + LM_DBG( "[%s]: [%d] LDAP entries found\n", _lds_name, *_ld_result_count); - + return 0; } @@ -417,16 +417,16 @@ int lds_search( last_ldap_result = NULL; } - + LM_DBG( "[%s]: performing LDAP search: dn [%s]," " scope [%d], filter [%s], client_timeout [%d] usecs\n", _lds_name, _dn, _scope, _filter, - (int)(lds->client_search_timeout.tv_sec * 1000000 + (int)(lds->client_search_timeout.tv_sec * 1000000 + lds->client_search_timeout.tv_usec)); - + #ifdef LDAP_PERF gettimeofday(&before_search, NULL); #endif @@ -468,7 +468,7 @@ int lds_search( { ldap_disconnect(_lds_name); } - + LM_DBG( "[%s]: ldap_search_ext_st failed: %s\n", _lds_name, ldap_err2string(*_ld_error)); diff --git a/modules/ldap/ldap_api_fn.h b/modules/ldap/ldap_api_fn.h index d4af4846d11..5cc1071a95e 100644 --- a/modules/ldap/ldap_api_fn.h +++ b/modules/ldap/ldap_api_fn.h @@ -66,7 +66,7 @@ int ldap_str2scope(char* scope_str); int get_ldap_handle(char* _lds_name, LDAP** _ldap_handle); -void get_last_ldap_result(LDAP** _last_ldap_handle, +void get_last_ldap_result(LDAP** _last_ldap_handle, LDAPMessage** _last_ldap_result); #endif /* LDAP_API_FN_H */ diff --git a/modules/ldap/ldap_connect.c b/modules/ldap/ldap_connect.c index 3e17c709ec5..55bb6eebb0b 100644 --- a/modules/ldap/ldap_connect.c +++ b/modules/ldap/ldap_connect.c @@ -61,13 +61,13 @@ int ldap_connect(char* _ld_name) /* * get ld session and session config parameters */ - + if ((lds = get_ld_session(_ld_name)) == NULL) { LM_ERR("ld_session [%s] not found\n", _ld_name); return -1; } - + /* * ldap_initialize */ @@ -81,7 +81,7 @@ int ldap_connect(char* _ld_name) ldap_err2string(rc)); return -1; } - + /* * set LDAP OPTIONS */ @@ -96,17 +96,17 @@ int ldap_connect(char* _ld_name) break; default: LM_ERR( "[%s]: Invalid LDAP protocol version [%d]\n", - _ld_name, + _ld_name, lds->version); return -1; } if (ldap_set_option(lds->handle, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto_version) - != LDAP_OPT_SUCCESS) + != LDAP_OPT_SUCCESS) { LM_ERR( "[%s]: Could not set LDAP_OPT_PROTOCOL_VERSION [%d]\n", - _ld_name, + _ld_name, ldap_proto_version); return -1; } @@ -133,7 +133,7 @@ int ldap_connect(char* _ld_name) } } */ - + /* LDAP_OPT_NETWORK_TIMEOUT */ if ((lds->network_timeout.tv_sec > 0) || (lds->network_timeout.tv_usec > 0)) { @@ -144,13 +144,13 @@ int ldap_connect(char* _ld_name) { LM_ERR( "[%s]: Could not set" " LDAP_NETWORK_TIMEOUT to [%d.%d]\n", - _ld_name, + _ld_name, (int)lds->network_timeout.tv_sec, (int)lds->network_timeout.tv_usec); } } - - + + /* if timeout == 0 then use default */ if ((lds->client_bind_timeout.tv_sec == 0) && (lds->client_bind_timeout.tv_usec == 0)) @@ -199,7 +199,7 @@ int ldap_connect(char* _ld_name) } LM_DBG( "[%s]: LDAP bind successful (ldap_host [%s])\n", - _ld_name, + _ld_name, lds->host_name); return 0; @@ -232,7 +232,7 @@ int ldap_disconnect(char* _ld_name) int ldap_reconnect(char* _ld_name) { int rc; - + if (ldap_disconnect(_ld_name) != 0) { LM_ERR("[%s]: disconnect failed\n", _ld_name); @@ -263,7 +263,7 @@ int ldap_get_vendor_version(char** _version) #else api.ldapai_info_version = 1; #endif - + if (ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) != LDAP_SUCCESS) { LM_ERR("ldap_get_option(API_INFO) failed\n"); diff --git a/modules/ldap/ldap_escape.c b/modules/ldap/ldap_escape.c index 17ab3b56243..67ac8b950e5 100644 --- a/modules/ldap/ldap_escape.c +++ b/modules/ldap/ldap_escape.c @@ -53,8 +53,8 @@ static const char hex[] = "0123456789ABCDEF"; int ldap_rfc4515_escape(str *sin, str *sout, int url_encode) { char *src, *dst; - - if (sin == NULL || sout == NULL || sin->s == NULL || sout->s == NULL + + if (sin == NULL || sout == NULL || sin->s == NULL || sout->s == NULL || sin->len <= 0 || sout->len < 3*sin->len+1) { return -1; diff --git a/modules/ldap/ldap_exp_fn.c b/modules/ldap/ldap_exp_fn.c index 074c9caba90..1d29091459e 100644 --- a/modules/ldap/ldap_exp_fn.c +++ b/modules/ldap/ldap_exp_fn.c @@ -54,7 +54,7 @@ static char esc_buf[ESC_BUF_SIZE]; /* * exported functions -*/ +*/ int ldap_search_impl( struct sip_msg* _msg, @@ -62,7 +62,7 @@ int ldap_search_impl( { str ldap_url; int ld_result_count = 0; - + /* * do variable substitution for _ldap_url (pv_printf_s) */ @@ -108,16 +108,16 @@ int ldap_write_result( struct berval **attr_vals; str avp_val_str, *subst_result = NULL; int avp_val_int; - + /* * get dst AVP name (dst_avp_name) */ - + if (pv_get_avp_name( _msg, - &(_lrp->dst_avp_spec.pvp), - &dst_avp_name, + &(_lrp->dst_avp_spec.pvp), + &dst_avp_name, &dst_avp_type) - != 0) + != 0) { LM_ERR("error getting dst AVP name\n"); return -2; @@ -159,7 +159,7 @@ int ldap_write_result( if (_lrp->dst_avp_val_type == 1) { /* try to convert ldap value to integer */ - if (!str2sint(&avp_val_str, &avp_val_int)) + if (!str2sint(&avp_val_str, &avp_val_int)) { dst_avp_val.n = avp_val_int; rc = add_avp(dst_avp_type, dst_avp_name, dst_avp_val); @@ -173,7 +173,7 @@ int ldap_write_result( dst_avp_val.s = avp_val_str; rc = add_avp(dst_avp_type|AVP_VAL_STR, dst_avp_name, dst_avp_val); } - + if (subst_result != NULL) { if (subst_result->s != 0) { pkg_free(subst_result->s); @@ -181,8 +181,8 @@ int ldap_write_result( pkg_free(subst_result); subst_result = NULL; } - - if (rc < 0) + + if (rc < 0) { LM_ERR("failed to create new AVP\n"); ldap_value_free_len(attr_vals); @@ -191,7 +191,7 @@ int ldap_write_result( added_avp_count++; } ldap_value_free_len(attr_vals); - + if (added_avp_count > 0) { return added_avp_count; @@ -229,9 +229,9 @@ int ldap_result_check( struct berval **attr_vals; /* - * do variable substitution for check_str + * do variable substitution for check_str */ - + if (_lrp->check_str_elem_p) { if (pv_printf_s(_msg, _lrp->check_str_elem_p, &check_str) != 0) @@ -239,18 +239,18 @@ int ldap_result_check( LM_ERR("pv_printf_s failed\n"); return -2; } - } else + } else { LM_ERR("empty check string\n"); return -2; } LM_DBG("check_str [%s]\n", check_str.s); - + /* * get LDAP attr values */ - + if ((rc = ldap_get_attr_vals(&_lrp->ldap_attr_name, &attr_vals)) != 0) { if (rc > 0) { @@ -263,14 +263,14 @@ int ldap_result_check( /* * loop through attribute values */ - + for (i = 0; attr_vals[i] != NULL; i++) { if (_se == NULL) { attr_val = attr_vals[i]->bv_val; } else - { + { subst_result = subst_str(attr_vals[i]->bv_val, _msg, _se, &nmatches); if ((subst_result == NULL) || (nmatches < 1)) @@ -279,10 +279,10 @@ int ldap_result_check( } attr_val = subst_result->s; } - + LM_DBG("attr_val [%s]\n", attr_val); rc = strncmp(check_str.s, attr_val, check_str.len); - if (_se != NULL) + if (_se != NULL) { pkg_free(subst_result->s); } @@ -302,7 +302,7 @@ int ldap_filter_url_encode( pv_elem_t* _filter_component, pv_spec_t* _dst_avp_spec) { - str filter_component_str, esc_str; + str filter_component_str, esc_str; int dst_avp_name; unsigned short dst_avp_type; diff --git a/modules/ldap/ldap_exp_fn.h b/modules/ldap/ldap_exp_fn.h index e97d8c63d44..5bc05d3f10e 100644 --- a/modules/ldap/ldap_exp_fn.h +++ b/modules/ldap/ldap_exp_fn.h @@ -53,7 +53,7 @@ struct ldap_result_check_params }; int ldap_search_impl( - struct sip_msg* _msg, + struct sip_msg* _msg, pv_elem_t* _ldap_url); int ldap_write_result( diff --git a/modules/ldap/ldap_mod.c b/modules/ldap/ldap_mod.c index 3254b181b3e..9761279fc6c 100644 --- a/modules/ldap/ldap_mod.c +++ b/modules/ldap/ldap_mod.c @@ -72,16 +72,16 @@ static int w_ldap_search(struct sip_msg* msg, char* ldap_url, char* param); static int w_ldap_result1(struct sip_msg* msg, char* src, char* param); static int w_ldap_result2(struct sip_msg* msg, char* src, char* subst); static int w_ldap_result_next(struct sip_msg* msg, char* foo, char *bar); -static int w_ldap_filter_url_encode(struct sip_msg* msg, +static int w_ldap_filter_url_encode(struct sip_msg* msg, char* filter_component, char* dst_avp_name); -static int w_ldap_result_check_1(struct sip_msg* msg, +static int w_ldap_result_check_1(struct sip_msg* msg, char* attr_name_check_str, char* param); static int w_ldap_result_check_2(struct sip_msg* msg, char* attr_name_check_str, char* attr_val_re); -/* -* Default module parameter values +/* +* Default module parameter values */ #define DEF_LDAP_CONFIG "/usr/local/etc/opensips/ldap.cfg" @@ -95,25 +95,25 @@ static dictionary* config_vals = NULL; * Exported functions */ static cmd_export_t cmds[] = { - {"ldap_search", (cmd_function)w_ldap_search, 1, + {"ldap_search", (cmd_function)w_ldap_search, 1, ldap_search_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| ONREPLY_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, - {"ldap_result", (cmd_function)w_ldap_result1, 1, + {"ldap_result", (cmd_function)w_ldap_result1, 1, ldap_result_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| ONREPLY_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, - {"ldap_result", (cmd_function)w_ldap_result2, 2, + {"ldap_result", (cmd_function)w_ldap_result2, 2, ldap_result_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| ONREPLY_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, - {"ldap_result_next", (cmd_function)w_ldap_result_next, 0, + {"ldap_result_next", (cmd_function)w_ldap_result_next, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE| LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, - {"ldap_result_check", (cmd_function)w_ldap_result_check_1, 1, + {"ldap_result_check", (cmd_function)w_ldap_result_check_1, 1, ldap_result_check_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE| BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, - {"ldap_result_check", (cmd_function)w_ldap_result_check_2, 2, + {"ldap_result_check", (cmd_function)w_ldap_result_check_2, 2, ldap_result_check_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE| BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, - {"ldap_filter_url_encode", (cmd_function)w_ldap_filter_url_encode, 2, + {"ldap_filter_url_encode", (cmd_function)w_ldap_filter_url_encode, 2, ldap_filter_url_encode_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE| BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"load_ldap", (cmd_function)load_ldap, 0, @@ -137,9 +137,11 @@ static param_export_t params[] = { * Module interface */ struct module_exports exports = { - "ldap", + "ldap", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -157,7 +159,7 @@ static int child_init(int rank) { int i = 0, ld_count = 0; char* ld_name; - + /* don't do anything for non-worker process */ if (rank==PROC_MAIN || rank==PROC_TCP_MAIN) { return 0; @@ -185,9 +187,9 @@ static int child_init(int rank) ldap_disconnect(ld_name); return -1; } - + } - + return 0; } @@ -197,7 +199,7 @@ static int mod_init(void) int ld_count = 0, i = 0; char* section_name; char* ldap_version; - + LM_INFO("LDAP_H350 module - initializing\n"); /* @@ -232,13 +234,13 @@ static int mod_init(void) if (!iniparser_find_entry(config_vals, get_ini_key_name(section_name, CFG_N_LDAP_HOST))) { - LM_ERR( "mandatory %s not defined in [%s]\n", - CFG_N_LDAP_HOST, + LM_ERR( "mandatory %s not defined in [%s]\n", + CFG_N_LDAP_HOST, section_name); return -2; } - } - + } + /* * print ldap version string */ @@ -305,8 +307,8 @@ static int w_ldap_result_check_1(struct sip_msg* msg, static int w_ldap_result_check_2(struct sip_msg* msg, char* attr_name_check_str, char* attr_val_re) { - return ldap_result_check( msg, - (struct ldap_result_check_params*)attr_name_check_str, + return ldap_result_check( msg, + (struct ldap_result_check_params*)attr_name_check_str, (struct subst_expr*)attr_val_re); } @@ -345,10 +347,10 @@ static int ldap_result_fixup(void** param, int param_no) char *p; str s; int dst_avp_val_type = 0; - + if (param_no == 1) { arg_str = (char*)*param; - if ((dst_avp_str = strchr(arg_str, '/')) == 0) + if ((dst_avp_str = strchr(arg_str, '/')) == 0) { /* no / found in arg_str */ LM_ERR("invalid first argument [%s]\n", arg_str); @@ -377,7 +379,7 @@ static int ldap_result_fixup(void** param, int param_no) return E_OUT_OF_MEM; } memset(lp, 0, sizeof(struct ldap_result_params)); - + lp->ldap_attr_name.s = arg_str; lp->ldap_attr_name.len = strlen(arg_str); @@ -397,7 +399,7 @@ static int ldap_result_fixup(void** param, int param_no) return E_UNSPEC; } *param = (void*)lp; - + } else if (param_no == 2) { subst.s = *param; subst.len = strlen(*param); @@ -421,7 +423,7 @@ static int ldap_result_check_fixup(void** param, int param_no) str s; char *arg_str, *check_str; int arg_str_len; - + if (param_no == 1) { arg_str = (char*)*param; @@ -434,7 +436,7 @@ static int ldap_result_check_fixup(void** param, int param_no) return E_UNSPEC; } *(check_str++) = 0; - + lp = (struct ldap_result_check_params*)pkg_malloc(sizeof(struct ldap_result_check_params)); if (lp == NULL) { LM_ERR("no memory\n"); @@ -458,7 +460,7 @@ static int ldap_result_check_fixup(void** param, int param_no) LM_ERR("pv_parse_format failed\n"); return E_OUT_OF_MEM; } - } + } *param = (void*)lp; } else if (param_no == 2) @@ -474,7 +476,7 @@ static int ldap_result_check_fixup(void** param, int param_no) *param = (void*)se; } - return 0; + return 0; } static int ldap_filter_url_encode_fixup(void** param, int param_no) diff --git a/modules/load_balancer/README b/modules/load_balancer/README index c5cd0b33b97..9900088881b 100644 --- a/modules/load_balancer/README +++ b/modules/load_balancer/README @@ -8,8 +8,7 @@ Bogdan-Andrei Iancu Copyright © 2009 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -49,7 +48,9 @@ Bogdan-Andrei Iancu 1.8.3. lb_list 1.8.4. lb_status - 1.9. Exported pseudo-variables + 1.9. Exported Events + + 1.9.1. E_LOAD_BALANCER_STATUS 2. Developer Guide @@ -253,8 +254,8 @@ modparam("load_balancer", "lb_define_blacklist", "blist2= 2,10,6") grouped in several groups you can you for differnet scenarios; this can be a number or a variable containing a numerical value. - * resources - string containing a semi-colon list of - resources required by the current call. + * resources - string containing a semi-colon separated list + of resources required by the current call. * algorithm - algorithm used for computing the available load on the system: + 0 - Absolute value - the effective available load ( @@ -319,8 +320,8 @@ if (t_check_status("(408)|(5[0-9][0-9])")) { Meaning of the parameters is as follows: * ip and port - IP and PORT to be checked (any kind of variables are allowed, but take care as the PORT variables - should have an interger value); A value 0 for the port - means "any" - will match any port. + should have an integer value); A value 0 for the port means + "any" - will match any port. * group - in what LB group the destination should be looked for; If not specified, the search will be in all groups. * active - if "1", the search will be performed only over @@ -329,7 +330,7 @@ if (t_check_status("(408)|(5[0-9][0-9])")) { Example 1.10. lb_is_destination usage ... -if (is_destination("$si","$sp") ) { +if (lb_is_destination("$si","$sp") ) { # request from a LB destination } ... @@ -347,8 +348,8 @@ if (is_destination("$si","$sp") ) { call has to be counted for. * grp - group id for the destinations; if no knows, "-1" will mean all groups. - * resources - string containing a semi-colon list of - resources required by the current call. + * resources - string containing a semi-colon separated list + of resources required by the current call. Function returns true if the call was properly taken into consideration for estimating the load on the destination. @@ -445,9 +446,18 @@ $ ./opensipsctl fifo lb_status 2 1 $ ./opensipsctl fifo lb_status 2 enable:: yes -1.9. Exported pseudo-variables +1.9. Exported Events - NONE +1.9.1. E_LOAD_BALANCER_STATUS + + This event is raised when the module changes the state of a + destination, either through MI or probing. + + Parameters: + * group - the group of the destination. + * uri - the URI of the destination. + * status - disabled if the destination was disabled or + enabled if the destination is being used. Chapter 2. Developer Guide @@ -486,4 +496,4 @@ Chapter 3. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/load_balancer/doc/load_balancer_admin.xml b/modules/load_balancer/doc/load_balancer_admin.xml index 85b6969a2c0..1ba935ae771 100644 --- a/modules/load_balancer/doc/load_balancer_admin.xml +++ b/modules/load_balancer/doc/load_balancer_admin.xml @@ -304,7 +304,7 @@ modparam("load_balancer", "lb_define_blacklist", "blist2= 2,10,6") resources - string containing a - semi-colon list of resources required by the current call. + semi-colon separated list of resources required by the current call. @@ -405,7 +405,7 @@ if (t_check_status("(408)|(5[0-9][0-9])")) { ip and port - IP and PORT to be checked (any kind of variables are allowed, but - take care as the PORT variables should have an interger value); + take care as the PORT variables should have an integer value); A value 0 for the port means "any" - will match any port. @@ -428,7 +428,7 @@ if (t_check_status("(408)|(5[0-9][0-9])")) { <function>lb_is_destination</function> usage ... -if (is_destination("$si","$sp") ) { +if (lb_is_destination("$si","$sp") ) { # request from a LB destination } ... @@ -461,7 +461,7 @@ if (is_destination("$si","$sp") ) { resources - string containing a - semi-colon list of resources required by the current call. + semi-colon separated list of resources required by the current call. @@ -608,12 +608,31 @@ enable:: yes
- Exported pseudo-variables - - NONE - + Exported Events +
+ + <function moreinfo="none">E_LOAD_BALANCER_STATUS</function> + + + This event is raised when the module changes the state of a destination, + either through MI or probing. + + Parameters: + + + group - the group of the destination. + + + uri - the URI of the destination. + + + status - disabled if + the destination was disabled or enabled if + the destination is being used. + + +
- diff --git a/modules/load_balancer/lb_bl.c b/modules/load_balancer/lb_bl.c index b925f3ca335..97ba000b6db 100644 --- a/modules/load_balancer/lb_bl.c +++ b/modules/load_balancer/lb_bl.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History diff --git a/modules/load_balancer/lb_bl.h b/modules/load_balancer/lb_bl.h index fdcb0fdbecf..d112867fb05 100644 --- a/modules/load_balancer/lb_bl.h +++ b/modules/load_balancer/lb_bl.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index 011d74efe43..44bc5a1a434 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -33,6 +33,7 @@ #include "../../proxy.h" #include "../../parser/parse_uri.h" #include "../../mem/shm_mem.h" +#include "../../evi/evi.h" #include "lb_parser.h" #include "lb_data.h" #include "lb_db.h" @@ -68,7 +69,7 @@ struct lb_resource *get_resource_by_name(struct lb_data *data, str *name) struct lb_resource *res; for( res=data->resources ; res ; res=res->next ) { - if (name->len==res->name.len && + if (name->len==res->name.len && memcmp( name->s, res->name.s, name->len)==0) { LM_DBG("found resource [%.*s]\n",name->len,name->s); return res; @@ -130,7 +131,7 @@ static struct lb_resource *add_lb_resource(struct lb_data *data, str *name) } new_res->profile = lb_dlg_binds.search_profile( &profile_name ); if (new_res->profile==NULL) { - LM_CRIT("bug - cannot find just added profile\n"); + LM_CRIT("bug - cannot find just added profile\n"); goto error; } } else { @@ -262,7 +263,7 @@ int add_lb_dsturi( struct lb_data *data, int id, int group, char *uri, memcpy( dst->uri.s , uri, len); dst->profile_id.s = dst->uri.s + len; - dst->profile_id.len = snprintf(dst->profile_id.s, + dst->profile_id.len = snprintf(dst->profile_id.s, 2+2*sizeof(struct lb_dst*), "%X", id); dst->id = id; @@ -470,8 +471,9 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, for(last_dst=data->dsts,i=0,j=0 ; last_dst ; last_dst=last_dst->next) { if (last_dst->id==id_val.n) {used_dst_bitmap[i] &= ~(1<n ; i++) - get_lock( call_res[i]->lock ); + lock_get( call_res[i]->lock ); /* do the load-balancing */ load = 0; @@ -524,6 +526,11 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, } LM_DBG("destination <%.*s> selected for LB set with free=%d " "(max=%d)\n",it->uri.len, it->uri.s,ld, load); + } else { + if (it->group==grp) + LM_DBG("skipping destination <%.*s> (used=%d , disabled=%d)\n", + it->uri.len, it->uri.s, + (used_dst_bitmap[i] & (1<flags&LB_DST_STAT_DSBL_FLAG)?1:0 ); } j++; if (j==8*sizeof(unsigned int)) {i++;j=0;} @@ -544,16 +551,18 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, /* add to the profiles */ for( i=0 ; in ; i++) { if (lb_dlg_binds.set_profile( req, &dst->profile_id, - call_res[i]->profile)!=0) + call_res[i]->profile, 0)!=0) LM_ERR("failed to add to profile\n"); } } /* unlock the resources*/ for( i=0 ; in ; i++) - release_lock( call_res[i]->lock ); + lock_release( call_res[i]->lock ); if (dst) { + LM_DBG("winning destination <%.*s> selected for LB set with free=%d\n", + dst->uri.len, dst->uri.s,load); /* change (add/edit) the AVPs for the next iteration */ if (grp_avp==NULL && mask_avp==NULL) { grp_val.n = grp; @@ -585,12 +594,71 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, return dst?0:-2; } +/* events */ +static event_id_t lb_evi_id; +static str lb_event = str_init("E_LOAD_BALANCER_STATUS"); +static str lb_group_str = str_init("group"); +static str lb_uri_str = str_init("uri"); +static str lb_state_str = str_init("status"); +static str lb_disabled_str = str_init("disabled"); +static str lb_enabled_str = str_init("enabled"); + +int lb_init_event(void) +{ + lb_evi_id = evi_publish_event(lb_event); + if (lb_evi_id == EVI_ERROR) { + LM_ERR("cannot register %.*s event\n", lb_event.len, lb_event.s); + return -1; + } + return 0; +} + +void lb_raise_event(struct lb_dst *dst) +{ + evi_params_p list = NULL; + + if (lb_evi_id == EVI_ERROR || !evi_probe_event(lb_evi_id)) + return; + + list = evi_get_params(); + if (!list) { + LM_ERR("cannot create event params\n"); + return; + } + + if (evi_param_add_int(list, &lb_group_str, &dst->group) < 0) { + LM_ERR("cannot add destination group\n"); + goto error; + } + + if (evi_param_add_str(list, &lb_uri_str, &dst->uri) < 0) { + LM_ERR("cannot add destination uri\n"); + goto error; + } + + if (evi_param_add_str(list, &lb_state_str, + dst->flags&LB_DST_STAT_DSBL_FLAG ? &lb_disabled_str : &lb_enabled_str) < 0) { + LM_ERR("cannot add destination state\n"); + goto error; + } + + if (evi_raise_event(lb_evi_id, list)) { + LM_ERR("unable to send %.*s event\n", lb_event.len, lb_event.s); + } + return; + +error: + evi_free_params(list); +} + + int do_lb_disable(struct sip_msg *req, struct lb_data *data) { struct usr_avp *id_avp; int_str id_val; struct lb_dst *dst; + unsigned int old_flags; id_avp = search_first_avp( 0, id_avp_name, &id_val, 0); if (id_avp==NULL) { @@ -600,7 +668,10 @@ int do_lb_disable(struct sip_msg *req, struct lb_data *data) for( dst=data->dsts ; dst ; dst=dst->next) { if (dst->id==id_val.n) { + old_flags = dst->flags; dst->flags |= LB_DST_STAT_DSBL_FLAG; + if (dst->flags != old_flags) + lb_raise_event(dst); } } @@ -685,11 +756,13 @@ int lb_count_call(struct lb_data *data, struct sip_msg *req, if ( (dst->ports[k]==0 || port==0 || port==dst->ports[k]) && ip_addr_cmp( ip, &dst->ips[k]) ) { /* found */ - break; + goto end_search; } } } } + +end_search: if (dst==NULL) { LM_ERR("no destination to match the given IP and port (%s:%d)\n", ip_addr2a(ip), port); @@ -726,18 +799,18 @@ int lb_count_call(struct lb_data *data, struct sip_msg *req, /* lock the resources */ for( i=0 ; in ; i++) - get_lock( call_res[i]->lock ); + lock_get( call_res[i]->lock ); /* add to the profiles */ for( i=0 ; in ; i++) { if (lb_dlg_binds.set_profile( req, &dst->profile_id, - call_res[i]->profile)!=0) + call_res[i]->profile, 0)!=0) LM_ERR("failed to add to profile\n"); } /* unlock the resources*/ for( i=0 ; in ; i++) - release_lock( call_res[i]->lock ); + lock_release( call_res[i]->lock ); return 0; } diff --git a/modules/load_balancer/lb_data.h b/modules/load_balancer/lb_data.h index 931c218b70b..6e3870bd519 100644 --- a/modules/load_balancer/lb_data.h +++ b/modules/load_balancer/lb_data.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -30,7 +30,6 @@ #ifndef LB_LB_DATA_H_ #define LB_LB_DATA_H_ - #include "../../str.h" #include "../../locking.h" #include "../../parser/msg_parser.h" @@ -102,6 +101,9 @@ int lb_is_dst(struct lb_data *data, struct sip_msg *_m, int lb_count_call(struct lb_data *data, struct sip_msg *req, struct ip_addr *ip, int port, int grp, struct lb_res_str_list *rl); +int lb_init_event(void); +void lb_raise_event(struct lb_dst *dst); + /* failover stuff */ extern int grp_avp_name; extern int mask_avp_name; diff --git a/modules/load_balancer/lb_db.c b/modules/load_balancer/lb_db.c index 1a938b995e7..2b6e4b33cda 100644 --- a/modules/load_balancer/lb_db.c +++ b/modules/load_balancer/lb_db.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/load_balancer/lb_db.h b/modules/load_balancer/lb_db.h index f92dc34b210..ea7db262775 100644 --- a/modules/load_balancer/lb_db.h +++ b/modules/load_balancer/lb_db.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/load_balancer/lb_parser.c b/modules/load_balancer/lb_parser.c index 69c73adb1ec..8edfa1df25f 100644 --- a/modules/load_balancer/lb_parser.c +++ b/modules/load_balancer/lb_parser.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -110,7 +110,7 @@ struct lb_res_str_list *parse_resources_list(char *r_list, int has_val) } LM_DBG("discovered %d resources\n",n); - /* alocate stuff*/ + /* allocate stuff*/ lb_rl = (struct lb_res_str_list *)pkg_malloc (sizeof(struct lb_res_str_list) + n*sizeof(struct lb_res_str) + len); if (lb_rl==NULL) { diff --git a/modules/load_balancer/lb_parser.h b/modules/load_balancer/lb_parser.h index 5db44c11af3..cee755fb63b 100644 --- a/modules/load_balancer/lb_parser.h +++ b/modules/load_balancer/lb_parser.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/load_balancer/lb_prober.c b/modules/load_balancer/lb_prober.c index c54b7b89ef8..00e6c7f1c4a 100644 --- a/modules/load_balancer/lb_prober.c +++ b/modules/load_balancer/lb_prober.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/load_balancer/lb_prober.h b/modules/load_balancer/lb_prober.h index dea094cfd49..2bd953c5f42 100644 --- a/modules/load_balancer/lb_prober.h +++ b/modules/load_balancer/lb_prober.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/load_balancer/load_balancer.c b/modules/load_balancer/load_balancer.c index 8c58d4d2e60..92d11b7f427 100644 --- a/modules/load_balancer/load_balancer.c +++ b/modules/load_balancer/load_balancer.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -54,7 +54,7 @@ static char *table_name = NULL; struct dlg_binds lb_dlg_binds; /* reader-writers lock for data reloading */ -static rw_lock_t *ref_lock = NULL; +static rw_lock_t *ref_lock = NULL; struct lb_data **curr_data = NULL; /* probing related stuff */ @@ -144,12 +144,32 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static module_dependency_t *get_deps_probing_interval(param_export_t *param) +{ + if (*(int *)param->param_pointer <= 0) + return NULL; + return alloc_module_dep(MOD_TYPE_DEFAULT, "tm", DEP_ABORT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "dialog", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "probing_interval", get_deps_probing_interval }, + { NULL, NULL }, + }, +}; struct module_exports exports= { "load_balancer", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ mod_params, /* param exports */ 0, /* exported statistics */ @@ -198,7 +218,7 @@ static int fixup_resources(void** param, int param_no) } if (pv_parse_spec(&s, lbgp->grp_pv)==0 || lbgp->grp_pv->type==PVT_NULL) { - LM_ERR("%s is not interger nor PV !\n", (char*)*param); + LM_ERR("%s is not integer nor PV !\n", (char*)*param); return E_UNSPEC; } } @@ -207,7 +227,7 @@ static int fixup_resources(void** param, int param_no) } else if (param_no==2) { - /* parameter is string (semi-colon separated list) + /* parameter is string (semi-colon separated list) * of needed resources */ lbp = (struct lb_res_parse *)pkg_malloc(sizeof(struct lb_res_parse)); if (!lbp) { @@ -267,7 +287,7 @@ static int fixup_is_dst(void** param, int param_no) return fixup_pvar(param); } else if (param_no==3) { /* the group to check in */ - return fixup_uint(param); + return fixup_igp(param); } else if (param_no==4) { /* active only check ? */ return fixup_uint(param); @@ -420,6 +440,11 @@ static int mod_init(void) return -1; } + if (lb_init_event() < 0) { + LM_ERR("cannot init event\n"); + return -1; + } + return 0; } @@ -555,30 +580,24 @@ static int w_lb_is_dst2(struct sip_msg *msg, char *ip, char *port) static int w_lb_is_dst3(struct sip_msg *msg,char *ip,char *port,char *grp) { - int ret; - - lock_start_read( ref_lock ); - - ret = lb_is_dst(*curr_data, msg,(pv_spec_t*)ip, (pv_spec_t*)port, - (int)(long)grp,0); - - lock_stop_read( ref_lock ); - - if (ret<0) - return ret; - return 1; + return w_lb_is_dst4(msg, ip, port, grp, 0); } static int w_lb_is_dst4(struct sip_msg *msg,char *ip,char *port,char *grp, char *active) { - int ret; + int ret, group; + + if (fixup_get_ivalue(msg, (gparam_p)grp, &group) != 0) { + LM_ERR("Invalid lb group pseudo variable!\n"); + return -1; + } lock_start_read( ref_lock ); ret = lb_is_dst(*curr_data, msg, (pv_spec_t*)ip, (pv_spec_t*)port, - (int)(long)grp, (int)(long)active); + group, (int)(long)active); lock_stop_read( ref_lock ); @@ -697,6 +716,7 @@ static int check_options_rplcode(int code) void set_dst_state_from_rplcode( int id, int code) { struct lb_dst *dst; + int old_flags; lock_start_read( ref_lock ); @@ -712,13 +732,19 @@ void set_dst_state_from_rplcode( int id, int code) lock_stop_read( ref_lock ); return; } + old_flags = dst->flags; dst->flags &= ~LB_DST_STAT_DSBL_FLAG; + if (dst->flags != old_flags) + lb_raise_event(dst); lock_stop_read( ref_lock ); return; } if (code>=400) { + old_flags = dst->flags; dst->flags |= LB_DST_STAT_DSBL_FLAG; + if (dst->flags != old_flags) + lb_raise_event(dst); } lock_stop_read( ref_lock ); @@ -754,7 +780,7 @@ static struct mi_root* mi_lb_reload(struct mi_root *cmd_tree, void *param) } /*! \brief - * Expects 3 nodes: + * Expects 3 nodes: * destination ID (number) * resource name (string) * size (number) @@ -801,7 +827,7 @@ static struct mi_root* mi_lb_resize(struct mi_root *cmd, void *param) memcmp( dst->rmap[n].resource->name.s, name->s, name->len)==0) break; if (n==dst->rmap_no) { - rpl_tree = init_mi_tree( 404, + rpl_tree = init_mi_tree( 404, MI_SSTR("Destination has no such resource")); } else { dst->rmap[n].max_load = size; @@ -819,7 +845,7 @@ static struct mi_root* mi_lb_resize(struct mi_root *cmd, void *param) /*! \brief - * Expects 2 nodes: + * Expects 2 nodes: * destination ID (number) * status (number) */ @@ -830,6 +856,7 @@ static struct mi_root* mi_lb_status(struct mi_root *cmd, void *param) struct lb_dst *dst; struct mi_node *node; unsigned int id, stat; + unsigned int old_flags; node = cmd->node.kids; if (node==NULL) @@ -877,13 +904,16 @@ static struct mi_root* mi_lb_status(struct mi_root *cmd, void *param) MI_SSTR("Destination ID not found")); } else { /* set the disable/enable */ + old_flags = dst->flags; if (stat) { dst->flags &= ~ (LB_DST_STAT_DSBL_FLAG|LB_DST_STAT_NOEN_FLAG); } else { - dst->flags |= + dst->flags |= LB_DST_STAT_DSBL_FLAG|LB_DST_STAT_NOEN_FLAG; } + if (old_flags != dst->flags) + lb_raise_event(dst); lock_stop_read( ref_lock ); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); } @@ -902,7 +932,7 @@ static struct mi_root* mi_lb_list(struct mi_root *cmd_tree, void *param) { struct mi_root *rpl_tree; struct mi_node *dst_node; - struct mi_node *node; + struct mi_node *node, *node1; struct mi_attr *attr; struct lb_dst *dst; char *p; @@ -912,6 +942,7 @@ static struct mi_root* mi_lb_list(struct mi_root *cmd_tree, void *param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return NULL; + rpl_tree->node.flags |= MI_IS_ARRAY; lock_start_read( ref_lock ); @@ -950,23 +981,27 @@ static struct mi_root* mi_lb_list(struct mi_root *cmd_tree, void *param) if (attr==0) goto error; + node = add_mi_node_child( dst_node, MI_IS_ARRAY, "Resources", 9, NULL, 0); + if (node==0) + goto error; + /* go through all resources */ for( i=0 ; irmap_no ; i++) { /* add a resource node */ - node = add_mi_node_child( dst_node, 0, "Resource", 8, + node1 = add_mi_node_child( node, 0, "Resource", 8, dst->rmap[i].resource->name.s,dst->rmap[i].resource->name.len); - if (dst_node==0) + if (node1==0) goto error; /* add some attributes to the destination node */ p= int2str((unsigned long)dst->rmap[i].max_load, &len); - attr = add_mi_attr( node, MI_DUP_VALUE, "max", 3, p, len); + attr = add_mi_attr( node1, MI_DUP_VALUE, "max", 3, p, len); if (attr==0) goto error; p= int2str((unsigned long)lb_dlg_binds.get_profile_size (dst->rmap[i].resource->profile, &dst->profile_id), &len); - attr = add_mi_attr( node, MI_DUP_VALUE, "load", 4, p, len); + attr = add_mi_attr( node1, MI_DUP_VALUE, "load", 4, p, len); if (attr==0) goto error; } diff --git a/modules/lua/sipapi.c b/modules/lua/sipapi.c index d28279b3ecc..e11b18fc29b 100644 --- a/modules/lua/sipapi.c +++ b/modules/lua/sipapi.c @@ -800,7 +800,7 @@ static int l_siplua_moduleFunc(lua_State *L) elems[i + 1].type = STRING_ST; elems[i + 1].u.data = str; /* elems[].u.string */ } - act = mk_action(MODULE_T, n - 2 + 1, elems, 0); + act = mk_action(MODULE_T, n - 2 + 1, elems, 0, NULL); if (!act) { siplua_moduleFunc_free(func, exp_func_struct, elems, nargs); @@ -912,7 +912,7 @@ void siplua_register_api_cclosures(lua_State *L) /* LM_ERR("Invalid URI reference\n"); */ /* ret = NULL; */ /* } else { */ - + /* switch (what) { */ /* case XS_URI_USER: ret = &(myuri->user); */ /* break; */ diff --git a/modules/lua/siplua.c b/modules/lua/siplua.c index 7ebb635f393..3a86a135fe2 100644 --- a/modules/lua/siplua.c +++ b/modules/lua/siplua.c @@ -78,8 +78,10 @@ static mi_export_t mi_cmds[] = { */ struct module_exports exports = { "lua", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, RTLD_NOW | RTLD_GLOBAL, + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ diff --git a/modules/lua/sipluami.c b/modules/lua/sipluami.c index 09082d640d5..7f3b94bc5a1 100644 --- a/modules/lua/sipluami.c +++ b/modules/lua/sipluami.c @@ -74,6 +74,7 @@ struct mi_root *siplua_mi_watch(struct mi_root *cmd_tree, void *param) int i; answer = init_mi_tree(200, "xOK", 3); + answer->node.flags |= MI_IS_ARRAY; sipwatch_lock(); for (i = 0; i < siplua_watch->nb; ++i) addf_mi_node_child(&answer->node, 0, "extension", 9, "%s", diff --git a/modules/lua/sipmemcache.c b/modules/lua/sipmemcache.c index 98a5955adc6..097ebf9f4b8 100644 --- a/modules/lua/sipmemcache.c +++ b/modules/lua/sipmemcache.c @@ -145,7 +145,7 @@ static int sipmemcache_atomic_opts(lua_State *L, u_int32_t (*f)(struct memcache const char *key; size_t keylen; int nb; - + o = luaL_checkudata(L, 1, "siplua.memcache"); key = luaL_checklstring(L, 2, &keylen); nb = luaL_checkinteger(L, 3); @@ -177,7 +177,7 @@ static int l_sipmemcache_delete(lua_State *L) const char *key; size_t keylen; int ret; - + o = luaL_checkudata(L, 1, "siplua.memcache"); key = luaL_checklstring(L, 2, &keylen); if (o->finalized || !o->mc) @@ -200,7 +200,7 @@ static int l_sipmemcache_get(lua_State *L) size_t keylen; void *blah; size_t retlen; - + o = luaL_checkudata(L, 1, "siplua.memcache"); key = luaL_checklstring(L, 2, &keylen); if (o->finalized || !o->mc) diff --git a/modules/lua/sipstate.c b/modules/lua/sipstate.c index b96b45c571f..a234fc73a33 100644 --- a/modules/lua/sipstate.c +++ b/modules/lua/sipstate.c @@ -149,7 +149,7 @@ static int l_sipstate_xlog(lua_State *L) } str = luaL_checklstring(L, 2, &len); } - siplua_log(lev, "%.*s", (int)len, str); + siplua_log(lev, "%.*s", (int)len, str); return 0; } @@ -312,11 +312,8 @@ static int l_sipstate_setCoreDebug(lua_State *L) int n; n = luaL_checkinteger(L, 1); -#ifdef CHANGEABLE_DEBUG_LEVEL - *debug = n; -#else - debug = n; -#endif + set_global_debug_level(n); + return 0; } diff --git a/modules/mangler/README b/modules/mangler/README index b8150245c2f..7ae57bee799 100644 --- a/modules/mangler/README +++ b/modules/mangler/README @@ -10,8 +10,7 @@ Gabriel Vasile Copyright © 2003 Fill in here Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/mangler/common.h b/modules/mangler/common.h index 545acb12785..239505c7d92 100644 --- a/modules/mangler/common.h +++ b/modules/mangler/common.h @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ #ifndef COMMON_H @@ -31,6 +31,6 @@ #define STRICT_CHECK 1 //#define DEBUG 1 -//#define DEMO 1 /* for mangler.c */ +//#define DEMO 1 /* for mangler.c */ #endif diff --git a/modules/mangler/contact_ops.c b/modules/mangler/contact_ops.c index fa8b456043a..516d258e937 100644 --- a/modules/mangler/contact_ops.c +++ b/modules/mangler/contact_ops.c @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ @@ -56,14 +56,14 @@ encode_contact (struct sip_msg *msg, char *encoding_prefix,char *public_ip) /* - * I have a list of contacts in contact->parsed which is of type - * contact_body_t inside i have a contact->parsed->contact which is the - * head of the list of contacts inside it is a + * I have a list of contacts in contact->parsed which is of type + * contact_body_t inside i have a contact->parsed->contact which is the + * head of the list of contacts inside it is a * str uri; * struct contact *next; * I just have to visit each uri and encode each uri according to a scheme */ - + if ((msg->contact == NULL)&&((parse_headers(msg,HDR_CONTACT_F,0) == -1) || (msg->contact == NULL) )) { @@ -107,14 +107,14 @@ encode_contact (struct sip_msg *msg, char *encoding_prefix,char *public_ip) LM_ERR("lumping failed in mangling port \n"); return -2; } - + /* encoding next contacts too?*/ #ifdef ENCODE_ALL_CONTACTS while (c->next != NULL) { c = c->next; uri = c->uri; - + res = encode_uri (uri, encoding_prefix,public_ip,separator,&newUri); if (res != 0) { @@ -163,15 +163,15 @@ decode_contact (struct sip_msg *msg,char *unused1,char *unused2) if (contact_flds_separator != NULL) if (strlen(contact_flds_separator)>=1) separator = contact_flds_separator[0]; - + if ((msg->new_uri.s == NULL) || (msg->new_uri.len == 0)) { uri = msg->first_line.u.request.uri; if (uri.s == NULL) return -1; } - + res = decode_uri (uri, separator, &newUri); - + #ifdef DEBUG if (res == 0) fprintf (stdout, "newuri.s=[%.*s]\n", newUri.len, newUri.s); #endif @@ -190,8 +190,8 @@ decode_contact (struct sip_msg *msg,char *unused1,char *unused2) pkg_free(msg->new_uri.s); msg->new_uri = newUri; } - - + + /* if (patch (msg, uri.s, uri.len, newUri.s, newUri.len) < 0) { @@ -212,8 +212,8 @@ decode_contact_header (struct sip_msg *msg,char *unused1,char *unused2) str newUri; char separator; int res; - - + + #ifdef DEBUG fprintf (stdout,"---START--------DECODE CONTACT HEADER-----------------\n"); #endif @@ -238,13 +238,13 @@ decode_contact_header (struct sip_msg *msg,char *unused1,char *unused2) ruri = &msg->first_line.u.request.uri; fprintf (stdout, "INITIAL.s=[%.*s]\n", ruri->len, ruri->s); #endif - + if (msg->contact->parsed == NULL) parse_contact (msg->contact); if (msg->contact->parsed != NULL) { cb = (contact_body_t *) msg->contact->parsed; c = cb->contacts; - // we visit each contact + // we visit each contact if (c != NULL) { uri = c->uri; @@ -287,11 +287,11 @@ decode_contact_header (struct sip_msg *msg,char *unused1,char *unused2) LM_ERR("lumping failed in mangling port \n"); return -3; } - } // end while + } // end while #endif - } // if c!= NULL - } // end if - else // after parsing still NULL + } // if c!= NULL + } // end if + else // after parsing still NULL { LM_ERR("unable to parse Contact header\n"); return -4; @@ -354,18 +354,18 @@ encode2format (str uri, struct uri_format *format) return foo-10; } - + format->username = sipUri.user; format->password = sipUri.passwd; format->ip = sipUri.host; format->port = sipUri.port; format->protocol = sipUri.transport_val; - -#ifdef DEBUG + +#ifdef DEBUG fprintf (stdout, "transport=[%.*s] transportval=[%.*s]\n", sipUri.transport.len,sipUri.transport.s,sipUri.transport_val.len,sipUri.transport_val.s); fprintf(stdout,"First %d,second %d\n",format->first,format->second); #endif - + return 0; } @@ -378,12 +378,12 @@ encode_uri (str uri, char *encoding_prefix, char *public_ip,char separator, str char *pos; int foo,res; - + result->s = NULL; result->len = 0; if (uri.len <= 1) return -1; /* no contact or an invalid one */ - if (public_ip == NULL) + if (public_ip == NULL) { LM_ERR("invalid NULL value for public_ip parameter\n"); return -2; @@ -400,7 +400,7 @@ encode_uri (str uri, char *encoding_prefix, char *public_ip,char separator, str } #ifdef DEBUG fprintf(stdout,"user=%.*s ip=%.*s port=%.*s protocol=%.*s\n",format.username.len,format.username.s,format.ip.len,format.ip.s, - format.port.len,format.port.s,format.protocol.len,format.protocol.s); + format.port.len,format.port.s,format.protocol.len,format.protocol.s); #endif /* a complete uri would be sip:username@ip:port;transport=protocol goes to @@ -428,12 +428,12 @@ encode_uri (str uri, char *encoding_prefix, char *public_ip,char separator, str #ifdef DEBUG fprintf (stdout, "[pass=%d][Allocated %d bytes][first=%d][lengthsec=%d]\nAdding [%d] ->%.*s\n",format.password.len,result->len,format.first,uri.len-format.second,format.first, format.first,uri.s);fflush (stdout); #endif - + res = snprintf(pos,result->len,"%.*s%s%c%.*s%c%.*s%c%.*s%c%.*s%c%.*s@",format.first,uri.s,encoding_prefix,separator, format.username.len,format.username.s,separator,format.password.len,format.password.s, separator,format.ip.len,format.ip.s,separator,format.port.len,format.port.s,separator,format.protocol.len,format.protocol.s); - if ((res < 0 )||(res>result->len)) + if ((res < 0 )||(res>result->len)) { LM_ERR("unable to construct new uri.\n"); if (result->s != NULL) pkg_free(result->s); @@ -447,7 +447,7 @@ encode_uri (str uri, char *encoding_prefix, char *public_ip,char separator, str pos = pos + strlen (public_ip); memcpy (pos, uri.s + format.second, uri.len - format.second); -#ifdef DEBUG +#ifdef DEBUG fprintf (stdout, "Adding2 [%d] ->%.*s\n", uri.len - format.second,uri.len - format.second, uri.s + format.second); fprintf (stdout, "NEW NEW uri is->[%.*s]\n", result->len, result->s); #endif @@ -473,7 +473,7 @@ decode2format (str uri, char separator, struct uri_format *format) return -1; } /* sip:enc_pref*username*password*ip*port*protocol@public_ip */ - + start = q_memchr (uri.s, ':', uri.len); if (start == NULL) { @@ -482,11 +482,11 @@ decode2format (str uri, char separator, struct uri_format *format) } /* invalid uri */ start = start + 1; /* jumping over sip: ATENTIE LA BUFFER OVERFLOW DACA E DOAR sip: */ format->first = start - uri.s; - + /* start */ end = q_memchr(start,'@',uri.len-(start-uri.s)); - if (end == NULL) + if (end == NULL) { LM_ERR("invalid SIP uri.Missing @\n"); return -3;/* no host address found */ @@ -495,10 +495,10 @@ decode2format (str uri, char separator, struct uri_format *format) #ifdef DEBUG fprintf (stdout, "Decoding %.*s\n",end-start,start); #endif - + state = EX_PREFIX; lastpos = start; - + for (pos = start;pos')||(*pos == ';')) @@ -532,15 +532,15 @@ decode2format (str uri, char separator, struct uri_format *format) return -5; } } - - + + /* we must be in state EX_PROT and protocol is between lastpos and end@ */ if (state != EX_PROT) return -6; format->protocol.len = end - lastpos; if (format->protocol.len>0) format->protocol.s = lastpos; else format->protocol.s = NULL; /* I should check perhaps that after @ there is something */ - + #ifdef DEBUG fprintf (stdout, "username=%.*s\n", format->username.len,format->username.s); fprintf (stdout, "password=%.*s\n", format->password.len,format->password.s); @@ -562,8 +562,8 @@ decode2format (str uri, char separator, struct uri_format *format) } /* if we are here we did not find > or ; */ format->second = uri.len; - return 0; - + return 0; + } @@ -594,29 +594,29 @@ decode_uri (str uri, char separator, str * result) { LM_ERR("unable to decode host address \n"); return -2;/* should I quit or ignore ? */ - } + } if ((format.password.len > 0) && (format.username.len <= 0)) { LM_ERR("password decoded but no username available\n"); return -3; } - + /* a complete uri would be sip:username:password@ip:port;transport=protocol goes to * sip:enc_pref#username#password#ip#port#protocol@public_ip */ result->len = format.first + (uri.len - format.second); /* not NULL terminated */ if (format.username.len > 0) result->len += format.username.len + 1; //: or @ if (format.password.len > 0) result->len += format.password.len + 1; //@ - + /* if (format.ip.len > 0) */ result->len += format.ip.len; - + if (format.port.len > 0) result->len += 1 + format.port.len; //: if (format.protocol.len > 0) result->len += 1 + 10 + format.protocol.len; //;transport= #ifdef DEBUG fprintf (stdout, "Result size is %d.Original Uri size is %d\n",result->len, uri.len); #endif - + /* adding one comes from * */ result->s = pkg_malloc (result->len); if (result->s == NULL) @@ -630,7 +630,7 @@ decode_uri (str uri, char separator, str * result) #endif memcpy (pos, uri.s, format.first); /* till sip: */ pos = pos + format.first; - + if (format.username.len > 0) { memcpy (pos, format.username.s, format.username.len); @@ -652,7 +652,7 @@ decode_uri (str uri, char separator, str * result) memcpy (pos, format.ip.s, format.ip.len); pos = pos + format.ip.len; - + if (format.port.len > 0) { memcpy (pos, ":", 1); diff --git a/modules/mangler/contact_ops.h b/modules/mangler/contact_ops.h index e92fa9f4472..cd4e8933060 100644 --- a/modules/mangler/contact_ops.h +++ b/modules/mangler/contact_ops.h @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ /* TODO :decode2format unpleasant */ @@ -64,7 +64,7 @@ typedef struct uri_format contact_fields_t; int encode_contact (struct sip_msg *msg, char *encoding_prefix,char *public_ip); int decode_contact (struct sip_msg *msg, char *unused1,char *unused2); int decode_contact_header (struct sip_msg *msg, char *unused1,char *unused2); - + int encode2format (str uri, struct uri_format *format); int decode2format (str uri, char separator, struct uri_format *format); diff --git a/modules/mangler/ip_helper.c b/modules/mangler/ip_helper.c index 243ab3b0216..a9ecd850352 100644 --- a/modules/mangler/ip_helper.c +++ b/modules/mangler/ip_helper.c @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ #include "ip_helper.h" @@ -193,7 +193,7 @@ make_mask (unsigned int length) netmask is specified and inserts the netmask into mask. Cuts of the netmask of the string, if it founds a netmask !!! Returns 0 if no netmask found, -1 if netmask isn't valid, and - 1 if successful. + 1 if successful. According to this function a mask is in form of 255.255.192.0 so an ip/mask looks like 10.0.0.0/255.255.192.0 we will extend it to 10.0.0.0/18 which will be also valid diff --git a/modules/mangler/ip_helper.h b/modules/mangler/ip_helper.h index c9e6634dae7..2b75847b669 100644 --- a/modules/mangler/ip_helper.h +++ b/modules/mangler/ip_helper.h @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ diff --git a/modules/mangler/mangler.c b/modules/mangler/mangler.c index ae4b6b9a381..c485e73b6af 100644 --- a/modules/mangler/mangler.c +++ b/modules/mangler/mangler.c @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ @@ -50,8 +50,8 @@ #include "../tm/t_hooks.h" #include "../tm/tm_load.h" #include "../tm/h_table.h" -struct tm_binds tmb; - +struct tm_binds tmb; + #endif @@ -75,9 +75,9 @@ char *contact_flds_separator = DEFAULT_SEPARATOR; -static param_export_t params[] = { +static param_export_t params[] = { {"contact_flds_separator",STR_PARAM,&contact_flds_separator}, - {0, 0, 0} + {0, 0, 0} }; /* perhaps I should add pre-compiled expressions */ @@ -85,7 +85,7 @@ static param_export_t params[] = { /* * Exported functions */ -static cmd_export_t cmds[] = +static cmd_export_t cmds[] = { {"sdp_mangle_ip", (cmd_function)sdp_mangle_ip, 2,0, 0, REQUEST_ROUTE|ONREPLY_ROUTE}, {"sdp_mangle_port", (cmd_function)sdp_mangle_port, 1,0, 0, REQUEST_ROUTE|ONREPLY_ROUTE}, @@ -101,8 +101,10 @@ static cmd_export_t cmds[] = */ struct module_exports exports = { "mangler", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -130,7 +132,7 @@ static void func_invite(struct cell *t,struct sip_msg *msg,int code,void *param) } i = encode_contact(msg,"enc_prefix","193.175.135.38"); fprintf(stdout,"decode/encode = returned %d\n",i);fflush(stdout); - + if (t->is_invite) { if (msg->buf != NULL) @@ -140,16 +142,16 @@ static void func_invite(struct cell *t,struct sip_msg *msg,int code,void *param) fprintf(stdout,"sdp_mangle_port returned %d\n",i);fflush(stdout); i = sdp_mangle_ip(msg,"10.0.0.0/16","123.124.125.126"); fprintf(stdout,"sdp_mangle_ip returned %d\n",i);fflush(stdout); - + } else fprintf(stdout,"INVITE:received NULL\n");fflush(stdout); } else { fprintf(stdout,"NOT INVITE(REGISTER?) received \n%s\n",msg->buf);fflush(stdout); - //i = decode_contact(msg,NULL,NULL); + //i = decode_contact(msg,NULL,NULL); //fprintf(stdout,"decode/encode = returned %d\n",i);fflush(stdout); - } + } fflush(stdout); } @@ -161,7 +163,7 @@ int prepare (void) /* using pre-compiled expressions to speed things up*/ compile_expresions(PORT_REGEX,IP_REGEX); - + #ifdef DEMO fprintf(stdout,"===============NEW RUN================\n"); @@ -171,9 +173,9 @@ int prepare (void) return -1; } - //register callbacks + //register callbacks if (tmb.register_tmcb(TMCB_REQUEST_OUT,func_invite,0) <= 0) return -1; -#endif +#endif return 0; } @@ -195,7 +197,7 @@ static int mod_init (void) static void destroy (void) { /*free some compiled regex expressions */ - free_compiled_expresions(); + free_compiled_expresions(); #ifdef DEMO fprintf(stdout,"Freeing pre-compiled expressions\n"); #endif diff --git a/modules/mangler/mangler.h b/modules/mangler/mangler.h index f8e81111b25..1ddd0fa6ca6 100644 --- a/modules/mangler/mangler.h +++ b/modules/mangler/mangler.h @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ diff --git a/modules/mangler/sdp_mangler.c b/modules/mangler/sdp_mangler.c index ed927b24596..aa098e2775a 100644 --- a/modules/mangler/sdp_mangler.c +++ b/modules/mangler/sdp_mangler.c @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ #include @@ -50,16 +50,16 @@ int sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) { - int oldContentLength, newContentLength, oldlen, err, oldPort, newPort, - diff, offsetValue,len,off,ret,needToDealocate; + int old_content_length, new_content_length, oldlen, err, oldPort, newPort, + diff, offsetValue,len,off,ret,need_to_deallocate; struct lump *l; regmatch_t pmatch; regex_t *re; char *s, *pos,*begin,*key; char buf[6]; str body; - - + + key = PORT_REGEX; /* * Checking if msg has a payload @@ -76,8 +76,8 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) return -2; } - oldContentLength = get_content_length(msg); - + old_content_length = get_content_length(msg); + if (offset == NULL) return -14; if (sscanf (offset, "%d", &offsetValue) != 1) @@ -85,13 +85,13 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) LM_ERR("invalid value for offset \n"); return -13; } - + //offsetValue = (int)offset; #ifdef DEBUG fprintf (stdout,"---START--------MANGLE PORT-----------------\n"); fprintf(stdout,"===============OFFSET = %d\n",offsetValue); #endif - + if ((offsetValue < MIN_OFFSET_VALUE) || (offsetValue > MAX_OFFSET_VALUE)) { LM_ERR("invalid value %d for offset \n",offsetValue); @@ -102,8 +102,8 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) ret = -1; /* try to use pre-compiled expressions */ - needToDealocate = 0; - if (portExpression != NULL) + need_to_deallocate = 0; + if (portExpression != NULL) { re = portExpression; #ifdef DEBUG @@ -118,7 +118,7 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) LM_ERR("unable to allocate re\n"); return -4; } - needToDealocate = 1; + need_to_deallocate = 1; if ((regcomp (re, key, REG_EXTENDED)) != 0) { LM_ERR("unable to compile %s \n",key); @@ -129,7 +129,7 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) #endif } - + diff = 0; while ((begin < msg->buf + msg->len) && (regexec (re, begin, 1, &pmatch, 0) == 0)) { @@ -139,21 +139,21 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) LM_ERR("offset unknown\n"); return -6; } - + #ifdef STRICT_CHECK pmatch.rm_eo --; /* return with one space */ #endif - - /* + + /* for BSD and Solaris we avoid memrchr - pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so); + pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so); */ pos = begin+pmatch.rm_eo; #ifdef DEBUG printf("begin=%c pos=%c rm_so=%d rm_eo=%d\n",*begin,*pos,pmatch.rm_so,pmatch.rm_eo); #endif do pos--; while (*pos != ' '); /* we should find ' ' because we matched m=audio port */ - + pos++; /* jumping over space */ oldlen = (pmatch.rm_eo - pmatch.rm_so) - (pos - (begin + pmatch.rm_so)); /* port length */ @@ -192,7 +192,7 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) #ifdef DEBUG printf("WARNING: sdp_mangle_port: Silent fail for not matching new port %d\n",newPort); #endif - + LM_WARN("silent fail for not matching new port %d\n",newPort); #ifdef STRICT_CHECK return -9; @@ -219,10 +219,10 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) if (newPort >= 10) len = 2; else len = 1; - /* replaced five div's + 1 add with most probably 1 comparison or 2 */ - + /* replaced five div's + 1 add with most probably 1 comparison or 2 */ + /* deleting old port */ - if ((l = del_lump (msg, pmatch.rm_so + off + + if ((l = del_lump (msg, pmatch.rm_so + off + (pos -(begin + pmatch.rm_so)),oldlen, 0)) == 0) { LM_ERR("del_lump failed\n"); @@ -252,7 +252,7 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) begin = begin + pmatch.rm_eo; } /* while */ - if (needToDealocate) + if (need_to_deallocate) { regfree (re); pkg_free(re); @@ -260,11 +260,11 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) fprintf(stdout,"Deallocating expression for port ...\n"); #endif } - + if (diff != 0) { - newContentLength = oldContentLength + diff; - patch_content_length (msg, newContentLength); + new_content_length = old_content_length + diff; + patch_content_length (msg, new_content_length); } #ifdef DEBUG @@ -278,12 +278,13 @@ sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused) int sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) { - int i, oldContentLength, newContentLength, diff, oldlen,len,off,ret,needToDealocate; + int i, old_content_length, new_content_length; + int diff, oldlen, len, off, ret, need_to_deallocate; unsigned int mask, address, locatedIp; struct lump *l; regmatch_t pmatch; regex_t *re; - char *s, *pos,*begin,*key; + char *s, *pos, *begin, *key; char buffer[16]; /* 123.456.789.123\0 */ str body; @@ -291,7 +292,7 @@ sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) fprintf (stdout,"---START--------MANGLE IP-----------------\n"); #endif - + key = IP_REGEX; /* @@ -309,7 +310,7 @@ sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) return -2; } - oldContentLength = get_content_length(msg); + old_content_length = get_content_length(msg); /* checking oldip */ if (oldip == NULL) @@ -349,8 +350,8 @@ sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) len = strlen (newip); /* try to use pre-compiled expressions */ - needToDealocate = 0; - if (ipExpression != NULL) + need_to_deallocate = 0; + if (ipExpression != NULL) { re = ipExpression; #ifdef DEBUG @@ -366,7 +367,7 @@ sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) LM_ERR("unable to allocate re in pkg mem\n"); return -7; } - needToDealocate = 1; + need_to_deallocate = 1; if ((regcomp (re, key, REG_EXTENDED)) != 0) { LM_ERR("unable to compile %s \n",key); @@ -386,14 +387,14 @@ sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) LM_ERR("offset unknown\n"); return -9; } - + #ifdef STRICT_CHECK pmatch.rm_eo --; /* return with one space,\n,\r */ #endif - - /* + + /* for BSD and Solaris we avoid memrchr - pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so); + pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so); */ pos = begin+pmatch.rm_eo; do pos--; while (*pos != ' '); /* we should find ' ' because we matched c=IN IP4 ip */ @@ -405,24 +406,24 @@ sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) LM_WARN("silent fail because oldlen > 15\n"); #ifdef STRICT_CHECK return -10; -#else +#else goto continue2; /* silent fail return -10; invalid ip format ,probably like 1000.3.12341.2 */ #endif - + } buffer[0] = '\0'; - strncat ((char *) buffer, pos, oldlen); + strncat ((char *) buffer, pos, oldlen); buffer[oldlen] = '\0'; i = parse_ip_address (buffer, &locatedIp); if (i == 0) { LM_WARN("silent fail on parsing matched address \n"); - + #ifdef STRICT_CHECK return -11; -#else - goto continue2; +#else + goto continue2; #endif } if (same_net (locatedIp, address, mask) == 0) @@ -441,7 +442,7 @@ sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) /* replacing ip */ /* deleting old ip */ - if ((l = del_lump (msg,pmatch.rm_so + off + + if ((l = del_lump (msg,pmatch.rm_so + off + (pos - (begin + pmatch.rm_so)),oldlen, 0)) == 0) { LM_ERR("del_lump failed\n"); @@ -468,19 +469,19 @@ sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip) begin = begin + pmatch.rm_eo; } /* while */ - if (needToDealocate) + if (need_to_deallocate) { - regfree (re); /* if I am going to use pre-compiled expressions to be removed */ - pkg_free(re); + regfree (re); /* if I am going to use pre-compiled expressions to be removed */ + pkg_free(re); #ifdef DEBUG fprintf(stdout,"Deallocating expression for ip ...\n"); #endif } - + if (diff != 0) { - newContentLength = oldContentLength + diff; - patch_content_length (msg, newContentLength); + new_content_length = old_content_length + diff; + patch_content_length (msg, new_content_length); } #ifdef DEBUG @@ -508,7 +509,7 @@ int compile_expresions(char *port,char *ip) { LM_ERR("unable to alloc portExpression in pkg mem\n"); } - + ipExpression = NULL; ipExpression = pkg_malloc(sizeof(regex_t)); if (ipExpression != NULL) @@ -524,19 +525,19 @@ int compile_expresions(char *port,char *ip) { LM_ERR("unable to alloc ipExpression in pkg mem\n"); } - + return 0; } int free_compiled_expresions(void) { - if (portExpression != NULL) + if (portExpression != NULL) { regfree(portExpression); pkg_free(portExpression); portExpression = NULL; } - if (ipExpression != NULL) + if (ipExpression != NULL) { regfree(ipExpression); pkg_free(ipExpression); diff --git a/modules/mangler/sdp_mangler.h b/modules/mangler/sdp_mangler.h index 2842018cfff..8c38465b117 100644 --- a/modules/mangler/sdp_mangler.h +++ b/modules/mangler/sdp_mangler.h @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ /* TO DO: precompiled expresions */ @@ -38,10 +38,10 @@ /* With STRICT_CHECK off: -If you define a port like 41231311 and BEST_EFFORT is defined it will +If you define a port like 41231311 and BEST_EFFORT is defined it will consider a port the first 5 digits Similarly an ip like 12.31.12.313131132131 will be mangled with only 3 digits -from the last group +from the last group */ #ifdef STRICT_CHECK @@ -71,7 +71,7 @@ regex_t *ipExpression; /* replaces all appearances of a port in lines like m=audio port with - a new value for port which is oldvalue+offset + a new value for port which is oldvalue+offset @param msg a pointer to a sip message @param offset value of an offset.Must be a numeric format like "-12345" @param unused unused parameter diff --git a/modules/mangler/utils.c b/modules/mangler/utils.c index 3049e7a6135..90d3c83bbff 100644 --- a/modules/mangler/utils.c +++ b/modules/mangler/utils.c @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ #include "utils.h" diff --git a/modules/mangler/utils.h b/modules/mangler/utils.h index 52a3576c56f..81ebfb73b3e 100644 --- a/modules/mangler/utils.h +++ b/modules/mangler/utils.h @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-04-07 first version. + * 2003-04-07 first version. */ #ifndef UTILS_H @@ -31,13 +31,13 @@ #include "../../parser/msg_parser.h" /* struct sip_msg */ -/* replace a part of a sip message identified by (start address,length) with a new part +/* replace a part of a sip message identified by (start address,length) with a new part @param msg a pointer to a sip message @param oldstr the start address of the part to be modified @param oldlen the length of the part being modified @param newstr the start address of the part to be added @param oldlen the length of the part being added - @return 0 in case of success, negative on error + @return 0 in case of success, negative on error */ int patch (struct sip_msg *msg, char *oldstr, unsigned int oldlen, @@ -46,7 +46,7 @@ int patch (struct sip_msg *msg, char *oldstr, unsigned int oldlen, modify the Content-Length header of a sip message @param msg a pointer to a sip message @param newValue the new value of Content-Length - @return 0 in case of success, negative on error + @return 0 in case of success, negative on error */ int patch_content_length (struct sip_msg *msg, unsigned int newValue); diff --git a/modules/mathops/Makefile b/modules/mathops/Makefile new file mode 100644 index 00000000000..40d89f8c9fb --- /dev/null +++ b/modules/mathops/Makefile @@ -0,0 +1,13 @@ +# Makefile v 1.0 2002/12/27 +# +# Mathops module makefile +# +# +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=mathops.so +LIBS=-lm + +include ../../Makefile.modules diff --git a/modules/mathops/README b/modules/mathops/README new file mode 100644 index 00000000000..5c8c57c3312 --- /dev/null +++ b/modules/mathops/README @@ -0,0 +1,352 @@ +mathops Module + +Liviu Chircu + + OpenSIPS Solutions + + +Edited by + +Liviu Chircu + +Edited by + +Stephane Alnet + + Copyright © 2013 www.opensips-solutions.com + Revision History + Revision $Revision$ $Date$ + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. Dependencies + + 1.2.1. OpenSIPS Modules + 1.2.2. External Libraries or Applications + + 1.3. Exported Parameters + + 1.3.1. decimal_digits (integer) + + 1.4. Exported Functions + + 1.4.1. math_eval(expression, result_pvar) + 1.4.2. math_rpn(expression, result_pvar) + 1.4.3. math_trunc(number, result_pvar) + 1.4.4. math_floor(number, result_pvar) + 1.4.5. math_ceil(number, result_pvar) + 1.4.6. math_round(number, result_pvar[, decimals]) + 1.4.7. math_round_sf(number, result_pvar, figures) + + List of Examples + + 1.1. Setting the decimal_digits module parameter + 1.2. math_eval usage + 1.3. math_rpn usage + 1.4. math_trunc usage + 1.5. math_floor usage + 1.6. math_ceil usage + 1.7. math_round usage + 1.8. math_round_sf usage + +Chapter 1. Admin Guide + +1.1. Overview + + The mathops module provides a series of functions which enable + various floating point operations at OpenSIPS script level. + +1.2. Dependencies + +1.2.1. OpenSIPS Modules + + The following modules must be loaded before this module: + * No dependencies on other OpenSIPS modules.. + +1.2.2. External Libraries or Applications + + The following libraries or applications must be installed + before running OpenSIPS with this module loaded: + * None. + +1.3. Exported Parameters + +1.3.1. decimal_digits (integer) + + The precision of the results returned by all the module + functions. The higher the “decimal_digits” value, the more + decimal digits the results will have. + + Default value is “6”. + + Example 1.1. Setting the decimal_digits module parameter +modparam("mathops", "decimal_digits", 10) + +1.4. Exported Functions + +1.4.1. math_eval(expression, result_pvar) + + The function evaluates a given expression and writes the + results in the output pseudo-variable. The expression may + contain any number of pseudo variables. + + Currently allowed syntax for specifying an expression: + * Nested parantheses + * binary + - / * operators + + Meaning of the parameters is as follows: + * expression - String containing a mathematical expression. + It can also include pseudo variables. The expression + parameter can only be given as a string. + * result_pvar - pseudo-variable which will hold the result of + the evaluation. Specified as a quoted string. + + This function can be used from any route. + + Example 1.2. math_eval usage +... +# Compute some random math expression + +$avp(1) = "3.141592"; +$avp(2) = "2.71828"; +$avp(3) = "123.45678"; + +if (math_eval("$avp(1) * ($avp(3) - ($avp(1) - $avp(2))) / $avp(3)", "$a +vp(result)")) { + xlog("Result of expression: $avp(result)\n"); +} else { + xlog("Math eval failed!\n"); +} + +... + +1.4.2. math_rpn(expression, result_pvar) + + The function evaluates a given RPN expression and writes the + results in the output pseudo-variable. The expression may + contain any number of pseudo variables. + + The expression is specified as a Reverse Polish Notation + script. Values are pushed onto a stack, while operations are + executed on that stack. The following operations are supported: + * binary operators: + - / * mod pow + * unary functions: neg exp ln log10 abs sqrt cbrt floor ceil + round nearbyint trunc + neg will change the sign of the top of the stack + ln is natural logarithm; abs is absolute value; other + functions are standard C functions + * constants: e pi + * stack manipulations commands: drop dup swap + + Meaning of the parameters is as follows: + * expression - String containing a RPN expression. It can + also include pseudo variables. The expression parameter can + only be given as a string. + * result_pvar - pseudo-variable which will hold the result of + the evaluation. Specified as a quoted string. + + This function can be used from any route. + + Example 1.3. math_rpn usage +$avp(1) = "3"; + +if (math_rpn("1 $avp(1) swap swap dup drop / exp ln 1 swap /", "$avp(res +ult)")) { + xlog("Result of expression: $avp(result)\n"); +} else { + xlog("RPN eval failed!\n"); +} + +/* This example RPN script will push 1 then 3 onto the stack, then do a +couple no-ops +(exchange the two values twice, duplicate one of them then drop the dupl +icate), +compute the division of 1 by 3, then do another no-op (exponentiation th +en logarithm), and +finally compute 1 divided by the result, giving 3 as the result. */ + +1.4.3. math_trunc(number, result_pvar) + + Truncation of a number towards zero. This means that trunc(3.7) + = 3.0 and trunc(-2.9) = -2.0. + + Meaning of the parameters is as follows: + * number - Number to be truncated. The number parameter can + have the following types: + + string - statically given + + pvar - value of an existing pseudo-variable (as string + value - it makes no sense to truncate integers) + * result_pvar - pseudo-variable which will hold the result of + the evaluation. Specified as a quoted string. + + This function can be used from any route. + + Example 1.4. math_trunc usage +... +# Truncate a random number + +$avp(1) = "3.141492"; + +if (math_trunc("$avp(1)", "$avp(result)")) { + xlog("Truncate result: $avp(result)\n"); +} else { + xlog("Truncate failed!\n"); +} +... + +1.4.4. math_floor(number, result_pvar) + + Truncates a number, always towards -infinity. This means that + floor(3.7) = 3.0 and floor(-2.9) = -3.0 + + Meaning of the parameters is as follows: + * number - Number to be truncated. The number parameter can + have the following types: + + string - statically given + + pvar - value of an existing pseudo-variable (as string + value - it makes no sense to truncate integers) + * result_pvar - pseudo-variable which will hold the result of + the evaluation. Specified as a quoted string. + + This function can be used from any route. + + Example 1.5. math_floor usage +... +# Truncate a random number + +$avp(1) = "3.141492"; + +if (math_floor("$avp(1)", "$avp(result)")) { + xlog("Floor result: $avp(result)\n"); +} else { + xlog("Floor operation failed!\n"); +} +... + +1.4.5. math_ceil(number, result_pvar) + + Truncates a number, always towards +infinity. This means that + ceil(3.2) = 4.0 and ceil(-2.9) = -2.0 + + Meaning of the parameters is as follows: + * number - Number to be truncated. The number parameter can + have the following types: + + string - statically given + + pvar - value of an existing pseudo-variable (as string + value - it makes no sense to truncate integers) + * result_pvar - pseudo-variable which will hold the result of + the evaluation. Specified as a quoted string. + + This function can be used from any route. + + Example 1.6. math_ceil usage +... +# Truncate a random number + +$avp(1) = "3.141492"; + +if (math_ceil("$avp(1)", "$avp(result)")) { + xlog("Ceil result: $avp(result)\n"); +} else { + xlog("Ceil operation failed!\n"); +} +... + +1.4.6. math_round(number, result_pvar[, decimals]) + + The round function returns the nearest integer, and + tie-breaking is done away from zero. Examples: round(1.2) = + 1.0, round(0.5) = 1.0, round(-0.5) = -1.0 + + By default, the function returns an integer. An additional + parameter controls the number of decimal digits of the initial + number which will be kept. The rounding will then be done using + the remaining decimal digits, and the result will be a float + value, represented as a string. + + Meaning of the parameters is as follows: + * number - Number to be rounded. The number parameter can + have the following types: + + string - statically given + + pvar - value of an existing pseudo-variable (as string + value - it makes no sense to truncate integers) + * result_pvar - pseudo-variable which will hold the result of + the evaluation. Specified as a quoted string. + * decimals - (pvar / integer as a string) which further + improves the precision of the rounding. + + This function can be used from any route. + + Example 1.7. math_round usage +... +# Rounding PI + +$avp(1) = "3.141492"; + +if (math_round("$avp(1)", "$avp(result)")) { + + # result should be: 3 + xlog("Round result: $avp(result)\n"); +} else { + xlog("Round operation failed!\n"); +} + +... + +if (math_round("$avp(1)", "$avp(result)", "4")) { + + # result should be: "3.1415" + xlog("Round result: $avp(result)\n"); +} else { + xlog("Round operation failed!\n"); +} +... + +1.4.7. math_round_sf(number, result_pvar, figures) + + To give a simple explanation, rounding to N significant figures + is done by first obtaining the number resulted from keeping N + significant figures (0 padded if necessary), then adjusting it + if the N+1'th digit is greater or equal to 5. + + Some examples: + * round_sf(17892.987, 1) = 20000 + round_sf(17892.987, 2) = 18000 + round_sf(17892.987, 3) = 17900 + round_sf(17892.987, 4) = 17890 + round_sf(17892.987, 5) = 17893 + round_sf(17892.987, 6) = 17893.0 + round_sf(17892.987, 7) = 17892.99 + + Meaning of the parameters is as follows: + * number - Number to be rounded. The number parameter can + have the following types: + + string - statically given + + pvar - value of an existing pseudo-variable (as string + value - it makes no sense to truncate integers) + * result_pvar - pseudo-variable which will hold the result of + the evaluation. Specified as a quoted string. + * figures - (pvar / integer as a string) which further + improves the precision of the rounding. + + This function can be used from any route. + + Example 1.8. math_round_sf usage +... +# Rounding PI + +$avp(1) = "3.141492"; + +if (math_round_sf("$avp(1)", "$avp(result)", "4")) { + + # result should be: "3.141" + xlog("Round result: $avp(result)\n"); +} else { + xlog("Round operation failed!\n"); +} + +... diff --git a/modules/mathops/doc/mathops.xml b/modules/mathops/doc/mathops.xml new file mode 100644 index 00000000000..822c21adc7d --- /dev/null +++ b/modules/mathops/doc/mathops.xml @@ -0,0 +1,54 @@ + + + + + +%docentities; + +]> + + + + mathops Module + + + Liviu + Chircu + OpenSIPS Solutions + liviu@opensips.org + + + Liviu + Chircu +
+ liviu@opensips.org +
+
+ + Stephane + Alnet +
+ stephane@shimaore.net +
+
+
+ + 2013 + &osipssol; + + + + $Revision$ + $Date$ + + +
+ + + &admin; + +
diff --git a/modules/mathops/doc/mathops_admin.xml b/modules/mathops/doc/mathops_admin.xml new file mode 100644 index 00000000000..515835e6501 --- /dev/null +++ b/modules/mathops/doc/mathops_admin.xml @@ -0,0 +1,508 @@ + + + + + &adminguide; + +
+ Overview + + The mathops module provides a series of functions which enable various + floating point operations at &osips; script level. + +
+ +
+ Dependencies +
+ &osips; Modules + + The following modules must be loaded before this module: + + + + No dependencies on other &osips; modules.. + + + + +
+ +
+ External Libraries or Applications + + The following libraries or applications must be installed before + running &osips; with this module loaded: + + + + None. + + + + +
+
+ +
+ Exported Parameters +
+ <varname>decimal_digits</varname> (integer) + + The precision of the results returned by all the module functions. + The higher the decimal_digits value, the more decimal + digits the results will have. + + + Default value is 6. + + + Setting the decimal_digits module parameter + +modparam("mathops", "decimal_digits", 10) + + +
+
+ +
+ Exported Functions +
+ + <function moreinfo="none">math_eval(expression, result_pvar)</function> + + + The function evaluates a given expression and writes the results in the + output pseudo-variable. The expression may contain any number of pseudo + variables. + + + Currently allowed syntax for specifying an expression: + + + Nested parantheses + + + binary + - / * operators + + + + Meaning of the parameters is as follows: + + + expression - String containing a + mathematical expression. It can also include pseudo variables. The + expression parameter can only be given as a string. + + + + result_pvar - pseudo-variable which will + hold the result of the evaluation. Specified as a quoted string. + + + + + This function can be used from any route. + + + <function moreinfo="none">math_eval</function> usage + +... +# Compute some random math expression + +$avp(1) = "3.141592"; +$avp(2) = "2.71828"; +$avp(3) = "123.45678"; + +if (math_eval("$avp(1) * ($avp(3) - ($avp(1) - $avp(2))) / $avp(3)", "$avp(result)")) { + xlog("Result of expression: $avp(result)\n"); +} else { + xlog("Math eval failed!\n"); +} + +... + + +
+ +
+ + <function moreinfo="none">math_rpn(expression, result_pvar)</function> + + + The function evaluates a given RPN expression and writes the results in the + output pseudo-variable. The expression may contain any number of pseudo + variables. + + + The expression is specified as a Reverse Polish Notation script. Values are pushed + onto a stack, while operations are executed on that stack. The following operations + are supported: + + + binary operators: + - / * mod pow + + + unary functions: neg exp ln log10 abs sqrt cbrt floor ceil round nearbyint trunc + neg will change the sign of the top of the stack + ln is natural logarithm; abs is absolute value; other functions are standard C functions + + + constants: e pi + + + stack manipulations commands: drop dup swap + + + + Meaning of the parameters is as follows: + + + expression - String containing a + RPN expression. It can also include pseudo variables. The + expression parameter can only be given as a string. + + + + result_pvar - pseudo-variable which will + hold the result of the evaluation. Specified as a quoted string. + + + + + This function can be used from any route. + + + <function moreinfo="none">math_rpn</function> usage + +$avp(1) = "3"; + +if (math_rpn("1 $avp(1) swap swap dup drop / exp ln 1 swap /", "$avp(result)")) { + xlog("Result of expression: $avp(result)\n"); +} else { + xlog("RPN eval failed!\n"); +} + +/* This example RPN script will push 1 then 3 onto the stack, then do a couple no-ops +(exchange the two values twice, duplicate one of them then drop the duplicate), +compute the division of 1 by 3, then do another no-op (exponentiation then logarithm), and +finally compute 1 divided by the result, giving 3 as the result. */ + + +
+ + +
+ + <function moreinfo="none">math_trunc(number, result_pvar)</function> + + + Truncation of a number towards zero. This means that trunc(3.7) = 3.0 and + trunc(-2.9) = -2.0. + + Meaning of the parameters is as follows: + + + number - Number to be truncated. The + number parameter can have the following types: + + + + string - statically given + + + + pvar - value of an existing pseudo-variable + (as string value - it makes no sense to truncate integers) + + + + + + result_pvar - pseudo-variable which will + hold the result of the evaluation. Specified as a quoted string. + + + + + This function can be used from any route. + + + <function moreinfo="none">math_trunc</function> usage + +... +# Truncate a random number + +$avp(1) = "3.141492"; + +if (math_trunc("$avp(1)", "$avp(result)")) { + xlog("Truncate result: $avp(result)\n"); +} else { + xlog("Truncate failed!\n"); +} +... + + +
+ +
+ + <function moreinfo="none">math_floor(number, result_pvar)</function> + + + Truncates a number, always towards -infinity. This means that floor(3.7) = 3.0 + and floor(-2.9) = -3.0 + + Meaning of the parameters is as follows: + + + number - Number to be truncated. The + number parameter can have the following types: + + + + string - statically given + + + + pvar - value of an existing pseudo-variable + (as string value - it makes no sense to truncate integers) + + + + + + result_pvar - pseudo-variable which will + hold the result of the evaluation. Specified as a quoted string. + + + + + This function can be used from any route. + + + <function moreinfo="none">math_floor</function> usage + +... +# Truncate a random number + +$avp(1) = "3.141492"; + +if (math_floor("$avp(1)", "$avp(result)")) { + xlog("Floor result: $avp(result)\n"); +} else { + xlog("Floor operation failed!\n"); +} +... + + +
+ +
+ + <function moreinfo="none">math_ceil(number, result_pvar)</function> + + + Truncates a number, always towards +infinity. This means that ceil(3.2) = 4.0 + and ceil(-2.9) = -2.0 + + Meaning of the parameters is as follows: + + + number - Number to be truncated. The + number parameter can have the following types: + + + + string - statically given + + + + pvar - value of an existing pseudo-variable + (as string value - it makes no sense to truncate integers) + + + + + + result_pvar - pseudo-variable which will + hold the result of the evaluation. Specified as a quoted string. + + + + + This function can be used from any route. + + + <function moreinfo="none">math_ceil</function> usage + +... +# Truncate a random number + +$avp(1) = "3.141492"; + +if (math_ceil("$avp(1)", "$avp(result)")) { + xlog("Ceil result: $avp(result)\n"); +} else { + xlog("Ceil operation failed!\n"); +} +... + + +
+ +
+ + <function moreinfo="none">math_round(number, result_pvar[, decimals])</function> + + + The round function returns the nearest integer, and tie-breaking is done away + from zero. Examples: round(1.2) = 1.0, round(0.5) = 1.0, round(-0.5) = -1.0 + + + By default, the function returns an integer. An additional parameter controls + the number of decimal digits of the initial number which will be kept. The + rounding will then be done using the remaining decimal digits, and the result + will be a float value, represented as a string. + + Meaning of the parameters is as follows: + + + number - Number to be rounded. The + number parameter can have the following types: + + + + string - statically given + + + + pvar - value of an existing pseudo-variable + (as string value - it makes no sense to truncate integers) + + + + + + result_pvar - pseudo-variable which will + hold the result of the evaluation. Specified as a quoted string. + + + + decimals - (pvar / integer as a string) which + further improves the precision of the rounding. + + + + + This function can be used from any route. + + + <function moreinfo="none">math_round</function> usage + +... +# Rounding PI + +$avp(1) = "3.141492"; + +if (math_round("$avp(1)", "$avp(result)")) { + + # result should be: 3 + xlog("Round result: $avp(result)\n"); +} else { + xlog("Round operation failed!\n"); +} + +... + +if (math_round("$avp(1)", "$avp(result)", "4")) { + + # result should be: "3.1415" + xlog("Round result: $avp(result)\n"); +} else { + xlog("Round operation failed!\n"); +} +... + + +
+ +
+ + <function moreinfo="none">math_round_sf(number, result_pvar, figures)</function> + + + To give a simple explanation, rounding to N significant figures is done by + first obtaining the number resulted from keeping N significant figures + (0 padded if necessary), then adjusting it if the N+1'th digit is greater + or equal to 5. + + + Some examples: + + + round_sf(17892.987, 1) = 20000 + round_sf(17892.987, 2) = 18000 + round_sf(17892.987, 3) = 17900 + round_sf(17892.987, 4) = 17890 + round_sf(17892.987, 5) = 17893 + round_sf(17892.987, 6) = 17893.0 + round_sf(17892.987, 7) = 17892.99 + + + + Meaning of the parameters is as follows: + + + number - Number to be rounded. The + number parameter can have the following types: + + + + string - statically given + + + + pvar - value of an existing pseudo-variable + (as string value - it makes no sense to truncate integers) + + + + + + result_pvar - pseudo-variable which will + hold the result of the evaluation. Specified as a quoted string. + + + + figures - (pvar / integer as a string) which + further improves the precision of the rounding. + + + + + This function can be used from any route. + + + <function moreinfo="none">math_round_sf</function> usage + +... +# Rounding PI + +$avp(1) = "3.141492"; + +if (math_round_sf("$avp(1)", "$avp(result)", "4")) { + + # result should be: "3.141" + xlog("Round result: $avp(result)\n"); +} else { + xlog("Round operation failed!\n"); +} + +... + + +
+
+
+ diff --git a/modules/mathops/math_funcs.c b/modules/mathops/math_funcs.c new file mode 100644 index 00000000000..8a6c9cb8253 --- /dev/null +++ b/modules/mathops/math_funcs.c @@ -0,0 +1,609 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-02-13: Created (Liviu) + */ + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#define _ADDED_XOPEN +#define _GNU_SOURCE +#endif + +#include +#include + +#ifdef _ADDED_XOPEN +#undef _ADDED_XOPEN +#undef _XOPEN_SOURCE +#undef _GNU_SOURCE +#endif + +#include + +#include "../../pvar.h" +#include "../../dprint.h" +#include "../../error.h" +#include "../../mem/mem.h" +#include "../../trim.h" + +#include "math_funcs.h" + +static char print_buffer[MATHOP_REAL_DIGITS + MATHOP_DECIMAL_DIGITS]; + +static token stack[MAX_STACK_SIZE]; +static token output[MAX_STACK_SIZE]; + +int top = 0; +int pos = 0; + +static int precedence(int op) +{ + switch (op) { + + case MATHOP_ADD: + case MATHOP_SUB: + return 1; + + case MATHOP_MUL: + case MATHOP_DIV: + return 2; + + default: + return 3; + } +} + +static int get_op(char symbol) +{ + switch (symbol) { + case MATHOP_PLUS: + return MATHOP_ADD; + + case MATHOP_MINUS: + return MATHOP_SUB; + + case MATHOP_MULT: + return MATHOP_MUL; + + case MATHOP_SLASH: + return MATHOP_DIV; + + default: + return -1; + } +} + +static int push_op(int type) +{ + if(top >= MAX_STACK_SIZE) { + LM_ERR("RPN Stack Full\n"); + return -1; + } + + stack[top].type = type; + top++; + return 0; +} + +static int push_number(double value) +{ + if(top >= MAX_STACK_SIZE) { + LM_ERR("RPN Stack Full\n"); + return -1; + } + + LM_DBG("push %f\n",value); + stack[top].type = MATHOP_NUMBER; + stack[top].value = value; + top++; + return 0; +} + +static int pop_number(double *value) +{ + if(top <= 0) { + LM_ERR("RPN Stack Empty\n"); + return -1; + } + + top--; + + if(stack[top].type != MATHOP_NUMBER) { + LM_ERR("RPN Stack Top is not a number\n"); + return -1; + } + + *value = stack[top].value; + LM_DBG("pop = %f\n",*value); + return 0; +} + +static void pop_to_output(void) +{ + output[pos++] = stack[--top]; +} + +static void pop_while_higher(int op_type) +{ + while (top > 0 && stack[top-1].type != MATHOP_LPAREN && + precedence(stack[top-1].type) >= precedence(op_type)) + { + pop_to_output(); + } +} + +static int rpn_eval(const token* t) +{ + double o1, o2; + + switch (t->type) { + case MATHOP_NUMBER: + return push_number(t->value); + + case MATHOP_ADD: + return pop_number(&o2) || pop_number(&o1) || push_number(o1 + o2); + + case MATHOP_SUB: + return pop_number(&o2) || pop_number(&o1) || push_number(o1 - o2); + + case MATHOP_MUL: + return pop_number(&o2) || pop_number(&o1) || push_number(o1 * o2); + + case MATHOP_DIV: + return pop_number(&o2) || pop_number(&o1) || push_number(o1 / o2); + + case MATHOP_NEG: + return pop_number(&o1) || push_number(-o1); + + case MATHOP_DROP: + return pop_number(&o1); + + case MATHOP_DUP: + if(pop_number(&o1)) return -1; + return push_number(o1) || push_number(o1); + + case MATHOP_SWAP: + return pop_number(&o2) || pop_number(&o1) || push_number(o2) || push_number(o1); + + case MATHOP_MOD: + return pop_number(&o2) || pop_number(&o1) || push_number(fmod(o1,o2)); + + case MATHOP_POW: + return pop_number(&o2) || pop_number(&o1) || push_number(pow(o1,o2)); + + case MATHOP_EXP: + return pop_number(&o1) || push_number(exp(o1)); + + case MATHOP_LOG10: + return pop_number(&o1) || push_number(log10(o1)); + + case MATHOP_LN: + return pop_number(&o1) || push_number(log(o1)); + + case MATHOP_ABS: + return pop_number(&o1) || push_number(fabs(o1)); + + case MATHOP_SQRT: + return pop_number(&o1) || push_number(sqrt(o1)); + + case MATHOP_CBRT: + return pop_number(&o1) || push_number(cbrt(o1)); + + case MATHOP_FLOOR: + return pop_number(&o1) || push_number(floor(o1)); + + case MATHOP_CEIL: + return pop_number(&o1) || push_number(ceil(o1)); + + case MATHOP_ROUND: + return pop_number(&o1) || push_number(round(o1)); + + case MATHOP_NEARBYINT: + return pop_number(&o1) || push_number(nearbyint(o1)); + + case MATHOP_TRUNC: + return pop_number(&o1) || push_number(trunc(o1)); + + case MATHOP_E: + return push_number(M_E); + + case MATHOP_PI: + return push_number(M_PI); + + default: + LM_WARN("Invalid RPN token type\n"); + return -1; + } +} + +#define inc_and_trim(s) \ + do { \ + s.s++; \ + s.len--; \ + trim_leading(&s); \ + } while (0) + +static inline void parse_word(str* _s, str* word) +{ + trim_leading(_s); + word->len = 0; + word->s = _s->s; + for(; _s->len > 0; _s->len--, _s->s++) { + switch(*(_s->s)) { + case ' ': + case '\t': + case '\r': + case '\n': + return; + + default: + word->len++; + break; + } + } +} + +struct mathop_entry { + str s; + int op; +}; + +const struct mathop_entry word_to_mathop[] = { + {s:{ len:1, s:"+" }, op:MATHOP_ADD}, + {s:{ len:1, s:"-" }, op:MATHOP_SUB}, + {s:{ len:1, s:"*" }, op:MATHOP_MUL}, + {s:{ len:1, s:"/" }, op:MATHOP_DIV}, + {s:{ len:4, s:"drop" }, op:MATHOP_DROP}, + {s:{ len:3, s:"dup" }, op:MATHOP_DUP}, + {s:{ len:4, s:"swap" }, op:MATHOP_SWAP}, + {s:{ len:3, s:"mod" }, op:MATHOP_MOD}, + {s:{ len:3, s:"pow" }, op:MATHOP_POW}, + {s:{ len:3, s:"exp" }, op:MATHOP_EXP}, + {s:{ len:2, s:"ln" }, op:MATHOP_LN}, + {s:{ len:3, s:"log10" }, op:MATHOP_LOG10}, + {s:{ len:3, s:"abs" }, op:MATHOP_ABS}, + {s:{ len:3, s:"neg" }, op:MATHOP_NEG}, + {s:{ len:4, s:"sqrt" }, op:MATHOP_SQRT}, + {s:{ len:4, s:"cbrt" }, op:MATHOP_CBRT}, + {s:{ len:5, s:"floor" }, op:MATHOP_FLOOR}, + {s:{ len:4, s:"ceil" }, op:MATHOP_CEIL}, + {s:{ len:5, s:"round" }, op:MATHOP_ROUND}, + {s:{ len:9, s:"nearbyint" }, op:MATHOP_NEARBYINT}, + {s:{ len:5, s:"trunc" }, op:MATHOP_TRUNC}, + {s:{ len:1, s:"e" }, op:MATHOP_E}, + {s:{ len:2, s:"pi" }, op:MATHOP_PI}, + {s:{ len:0, s:NULL}, op:-1} +}; + +static int get_rpn_op(str *_s) +{ + str word; + const struct mathop_entry* j; + + trim_leading(_s); + parse_word(_s,&word); + if(word.len == 0) { + return -1; + } + + for( j = word_to_mathop; j->s.len > 0; j++ ) { + if(j->s.len == word.len && !strncmp(j->s.s,word.s,j->s.len)) { + return j->op; + } + } + + LM_WARN("Parse expr error: Invalid operator! <%.*s>\n", word.len, word.s); + return -1; +} + +/** + * Shunting-yard algorithm + * + * Converts an expression to Reverse Polish Notation + * Result is written to the 'output' buffer + */ +static int convert_to_rpn(str *exp) +{ + double d; + char *p; + int op; + str s; + + p = exp->s; + s.s = exp->s; + s.len = exp->len; + + while (s.len) { + + if (*s.s >= '0' && *s.s <= '9') { + errno = 0; + d = strtod(s.s, &p); + + s.len -= p - s.s; + s.s = p; + + if (errno == ERANGE) { + LM_WARN("Overflow in parsing a numeric value!\n"); + } + + output[pos].type = MATHOP_NUMBER; + output[pos].value = d; + pos++; + + trim_leading(&s); + continue; + } + + switch (*s.s) { + + case MATHOP_L_PAREN: + + push_op(MATHOP_LPAREN); + inc_and_trim(s); + break; + + case MATHOP_R_PAREN: + + while (top > 0 && stack[top-1].type != MATHOP_LPAREN) { + pop_to_output(); + } + + if (top == 0) { + LM_ERR("Parse expr error: mismatched parantheses!\n"); + return -1; + } + + /* just pop the left paranthesis off the stack */ + top--; + + inc_and_trim(s); + + break; + + default: + + op = get_op(*s.s); + if (op < 0) { + LM_WARN("Parse expr error: Invalid operator! <%c>\n", *s.s); + return -1; + } + + pop_while_higher(op); + push_op(op); + + inc_and_trim(s); + } + } + + /* since ADD has lowest precedence, this will pop all remaining operators */ + pop_while_higher(MATHOP_ADD); + + return 0; +} + +static int parse_rpn(str *exp) +{ + double d; + char *p; + int op; + str s; + + p = exp->s; + s.s = exp->s; + s.len = exp->len; + + while (s.len) { + + if (*s.s >= '0' && *s.s <= '9') { + errno = 0; + d = strtod(s.s, &p); + + s.len -= p - s.s; + s.s = p; + + if (errno == ERANGE) { + LM_WARN("Overflow in parsing a numeric value!\n"); + return -1; + } + + output[pos].type = MATHOP_NUMBER; + output[pos].value = d; + pos++; + } else { + op = get_rpn_op(&s); + if (op < 0) { + return -1; + } + + output[pos].type = op; + pos++; + } + trim_leading(&s); + } + + return 0; +} + +/** + * The function assumes that the 'output' buffer is properly written and + * the 'pos' variable holds the size of the buffer + */ +static int evaluate_rpn_output(double *result) +{ + int i; + + for (i = 0; i < pos; i++) { + if(rpn_eval(output+i) < 0) { + return -1; + } + } + + if (top != 1) { + LM_ERR("Parse expr error: stack has %d elements\n",top); + return -1; + } + + return pop_number(result); +} + + +/** + * Computes the result of a given expression + */ +int evaluate_exp(struct sip_msg *msg, str *exp, pv_spec_p result_var, short is_rpn) +{ + double result; + pv_value_t pv_val; + + trim(exp); + + /* reset stack and output markers */ + top = 0; + pos = 0; + + if(is_rpn) { + if (parse_rpn(exp) != 0) { + LM_ERR("Failed to parse RPN!\n"); + return -1; + } + } else { + if (convert_to_rpn(exp) != 0) { + LM_ERR("Failed to convert expression to RPN form!\n"); + return -1; + } + } + + if (evaluate_rpn_output(&result) != 0) { + LM_ERR("Mismatched tokens in expression: <%.*s>\n", exp->len, exp->s); + return -1; + } + + sprintf(print_buffer, "%.*lf", decimal_digits, result); + + pv_val.flags = PV_VAL_STR; + pv_val.rs.s = print_buffer; + pv_val.rs.len = strlen(print_buffer); + + if (pv_set_value(msg, result_var, 0, &pv_val) != 0) + { + LM_ERR("SET output value failed.\n"); + return -1; + } + + return 1; +} + + +/** + * Basic rounding to nearest integer functions: floor, ceil, trunc + */ +int basic_round_op(struct sip_msg *msg, str *n, pv_spec_p result_var, + double (*math_op)(double)) +{ + double d; + pv_value_t pv_val; + + errno = 0; + d = strtod(n->s, NULL); + + if (errno == ERANGE) { + LM_WARN("Overflow in parsing a numeric value!\n"); + } + + pv_val.flags = PV_VAL_INT|PV_TYPE_INT; + pv_val.ri = (int)math_op(d); + + if (pv_set_value(msg, result_var, 0, &pv_val) != 0) + { + LM_ERR("SET output value failed.\n"); + return -1; + } + + return 1; +} + + +/** + * Rounds a number away from zero [ to the specified number of decimal digits ] + */ +int round_dp_op(struct sip_msg *msg, str *n, pv_spec_p result_var, int digits) +{ + double d; + pv_value_t pv_val; + + errno = 0; + d = strtod(n->s, NULL); + + if (errno == ERANGE) { + LM_WARN("Overflow in parsing a numeric value!\n"); + } + + if (digits == 0) { + pv_val.flags = PV_TYPE_INT|PV_VAL_INT; + pv_val.ri = (int)round(d); + } else { + sprintf(print_buffer, "%.*lf", digits, d); + + pv_val.flags = PV_VAL_STR; + pv_val.rs.s = print_buffer; + pv_val.rs.len = strlen(print_buffer); + } + + if (pv_set_value(msg, result_var, 0, &pv_val) != 0) + { + LM_ERR("SET output value failed.\n"); + return -1; + } + + return 1; +} + + +/** + * Rounds a number to the given number of significant digits + */ +int round_sf_op(struct sip_msg *msg, str *n, pv_spec_p result_var, int digits) +{ + double d, factor; + pv_value_t pv_val; + + d = strtod(n->s, NULL); + factor = pow(10.0, digits - ceil(log10(fabs(d)))); + d = round(d * factor) / factor; + + sprintf(print_buffer, "%.*f", decimal_digits, d); + + pv_val.flags = PV_VAL_STR; + pv_val.rs.s = print_buffer; + pv_val.rs.len = strlen(print_buffer); + + if (pv_set_value(msg, result_var, 0, &pv_val) != 0) + { + LM_ERR("SET output value failed.\n"); + return -1; + } + + return 1; +} + diff --git a/modules/mathops/math_funcs.h b/modules/mathops/math_funcs.h new file mode 100644 index 00000000000..11754baa951 --- /dev/null +++ b/modules/mathops/math_funcs.h @@ -0,0 +1,67 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-02-13: Created (Liviu) + */ + +#ifndef __MATHOPS_H__ +#define __MATHOPS_H__ + +#include + +#define MAX_STACK_SIZE 100 + +#define MATHOP_PLUS '+' +#define MATHOP_MINUS '-' +#define MATHOP_MULT '*' +#define MATHOP_SLASH '/' +#define MATHOP_L_PAREN '(' +#define MATHOP_R_PAREN ')' + +#define MATHOP_REAL_DIGITS 128 +#define MATHOP_DECIMAL_DIGITS 128 + +extern int decimal_digits; + +enum { MATHOP_NUMBER = 0, MATHOP_LPAREN, MATHOP_ADD, MATHOP_SUB, MATHOP_MUL, + MATHOP_DIV, MATHOP_DROP, MATHOP_DUP, MATHOP_SWAP, MATHOP_MOD, MATHOP_NEG, + MATHOP_POW, MATHOP_EXP, MATHOP_LN, MATHOP_LOG10, MATHOP_ABS, MATHOP_SQRT, + MATHOP_CBRT, MATHOP_FLOOR, MATHOP_CEIL, MATHOP_ROUND, MATHOP_NEARBYINT, + MATHOP_TRUNC, MATHOP_E, MATHOP_PI }; + +typedef struct _token { + int type; + double value; +} token; + +/** + * Exported function headers + */ +int basic_round_op(struct sip_msg *msg, str *n, pv_spec_p result_var, + double (*math_op)(double)); +int round_dp_op(struct sip_msg *msg, str *n, pv_spec_p result_var, int digits); +int round_sf_op(struct sip_msg *msg, str *n, pv_spec_p result_var, int digits); + +int evaluate_exp(struct sip_msg *msg, str *exp, pv_spec_p result, short is_rpn); + +#endif /* __MATHOPS_H__ */ diff --git a/modules/mathops/mathops.c b/modules/mathops/mathops.c new file mode 100644 index 00000000000..a394d9f8fca --- /dev/null +++ b/modules/mathops/mathops.c @@ -0,0 +1,361 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-02-13: Created (Liviu) + */ + + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#define _ADDED_XOPEN +#define _GNU_SOURCE +#endif + +#include +#include + +#ifdef _ADDED_XOPEN +#undef _ADDED_XOPEN +#undef _XOPEN_SOURCE +#undef _GNU_SOURCE +#endif + +#include "../../sr_module.h" +#include "../../dprint.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../../mod_fix.h" + +#include "math_funcs.h" + +/** + * Module initialization function prototype + */ +static int mod_init(void); + +/** + * Module parameter variables + */ +int decimal_digits = 6; /* default number of decimal digits written into pvs */ + +/** + * Fixup functions + */ +static int fixup_evaluate_exp(void **param, int param_no); +static int fixup_binary_op(void **param, int param_no); +static int fixup_round_op(void **param, int param_no); + +/** + * Function headers + */ +static int w_evaluate_exp(struct sip_msg *msg, char *exp, char *result); +static int w_evaluate_rpn(struct sip_msg *msg, char *exp, char *result); +static int w_basic_round_op(struct sip_msg *msg, char *number, char *result, + double (*math_op)(double)); +static int w_floor_op(struct sip_msg *msg, char *number, char *result); +static int w_ceil_op(struct sip_msg *msg, char *number, char *result); +static int w_trunc_op(struct sip_msg *msg, char *number, char *result); +static int w_round_dp_op(struct sip_msg *msg, char *number, char *result, + char *digits); +static int w_round_sf_op(struct sip_msg *msg, char *number, char *result, + char *digits); + + +/** + * Exported functions + */ +static cmd_export_t cmds[] = { + {"math_eval",(cmd_function)w_evaluate_exp, 2, fixup_evaluate_exp, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE}, + {"math_rpn",(cmd_function)w_evaluate_rpn, 2, fixup_evaluate_exp, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE}, + {"math_floor",(cmd_function)w_floor_op, 2, fixup_binary_op, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE}, + {"math_ceil",(cmd_function)w_ceil_op, 2, fixup_binary_op, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE}, + {"math_trunc",(cmd_function)w_trunc_op, 2, fixup_binary_op, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE}, + {"math_round",(cmd_function)w_round_dp_op, 2, fixup_binary_op, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE}, + {"math_round",(cmd_function)w_round_dp_op, 3, fixup_round_op, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE}, + {"math_round_sf",(cmd_function)w_round_sf_op, 3, fixup_round_op, 0, + REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE| + STARTUP_ROUTE|TIMER_ROUTE}, + {0, 0, 0, 0, 0, 0} +}; + + +/** + * Exported parameters + */ +static param_export_t params[] = { + {"decimal_digits", INT_PARAM, &decimal_digits}, + {0, 0, 0} +}; + + +/** + * Module parameter variables + */ +struct module_exports exports = { + "mathops", + MOD_TYPE_DEFAULT,/* class of this module */ + MODULE_VERSION, /* module version */ + DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ + cmds, /* Exported functions */ + params, /* Exported parameters */ + 0, /* exported statistics */ + 0, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + 0, /* response function*/ + 0, /* destroy function */ + 0 /* per-child init function */ +}; + + +static int mod_init(void) +{ + LM_DBG("Initializing...\n"); + + LM_INFO("Module initialized!\n"); + + return 0; +} + +/**************************** Fixup functions ********************************/ + + +static int fixup_binary_op(void **param, int param_no) +{ + pv_spec_p sp; + str s; + + switch (param_no) { + case 1: + return fixup_sgp(param); + + case 2: + if (!(sp = pkg_malloc(sizeof(*sp)))) { + LM_ERR("No more pkg memory!\n"); + return -1; + } + + memset(sp, 0, sizeof(*sp)); + + s.s = (char *)*param; s.len = strlen(s.s); + if (!pv_parse_spec(&s, sp)) { + LM_ERR("Parameter 2 only accepts pvars! Given: <%.*s>\n", s.len, s.s); + return -1; + } + + *param = (void *)sp; + return 0; + + default: + LM_ERR("Invalid parameter number: %d\n", param_no); + return E_UNSPEC; + } +} + + +static int fixup_round_op(void **param, int param_no) +{ + switch (param_no) { + case 1: + case 2: + return fixup_binary_op(param, param_no); + case 3: + return fixup_igp(param); + + default: + LM_ERR("Invalid parameter number: %d\n", param_no); + return E_UNSPEC; + } +} + + +static int fixup_evaluate_exp(void **param, int param_no) +{ + pv_elem_p ep; + pv_spec_p sp; + str s; + + if (param_no != 1 && param_no != 2) { + LM_ERR("Invalid parameter number: %d\n", param_no); + return E_UNSPEC; + } + + if (param_no == 1) { + + s.s = (char*)(*param); s.len = strlen(s.s); + + if (pv_parse_format(&s, &ep) < 0) { + LM_ERR("wrong format[%.*s]\n", s.len, s.s); + return E_UNSPEC; + } + + *param = (void *)ep; + return 0; + + } else { + if (!(sp = pkg_malloc(sizeof(*sp)))) { + LM_ERR("No more pkg memory!\n"); + return -1; + } + + memset(sp, 0, sizeof(*sp)); + + s.s = (char *)*param; s.len = strlen(s.s); + if (!pv_parse_spec(&s, sp)) { + LM_ERR("Parameter 2 only accepts pvars! Given: <%.*s>\n", s.len, s.s); + return -1; + } + + *param = (void *)sp; + return 0; + } +} + + +/**************************** Module functions *******************************/ + + +static int w_evaluate_exp(struct sip_msg *msg, char *exp, char *result) +{ + pv_elem_p exp_fmt = (pv_elem_p)exp; + str s; + + if (pv_printf_s(msg, exp_fmt, &s) != 0) { + LM_ERR("Failed to print the pv format string!\n"); + return -1; + } + + LM_DBG("Evaluating expression: %.*s\n", s.len, s.s); + + return evaluate_exp(msg, &s, (pv_spec_p)result, 0); +} + +static int w_evaluate_rpn(struct sip_msg *msg, char *exp, char *result) +{ + pv_elem_p exp_fmt = (pv_elem_p)exp; + str s; + + if (pv_printf_s(msg, exp_fmt, &s) != 0) { + LM_ERR("Failed to print the pv format string!\n"); + return -1; + } + + LM_DBG("Evaluating expression: %.*s\n", s.len, s.s); + + return evaluate_exp(msg, &s, (pv_spec_p)result, 1); +} + + +static int w_floor_op(struct sip_msg *msg, char *number, char *result) +{ + return w_basic_round_op(msg, number, result, floor); +} + + +static int w_ceil_op(struct sip_msg *msg, char *number, char *result) +{ + return w_basic_round_op(msg, number, result, ceil); +} + + +static int w_trunc_op(struct sip_msg *msg, char *number, char *result) +{ + return w_basic_round_op(msg, number, result, trunc); +} + + +static int w_basic_round_op(struct sip_msg *msg, char *number, char *result, + double (*round_func)(double)) +{ + str n; + + if (fixup_get_svalue(msg, (gparam_p)number, &n) != 0) { + LM_ERR("Invalid number pseudo variable!\n"); + return -1; + } + + return basic_round_op(msg, &n, (pv_spec_p)result, round_func); +} + + +static int w_round_dp_op(struct sip_msg *msg, char *number, char *result, + char *digits) +{ + int d; + str n; + + if (fixup_get_svalue(msg, (gparam_p)number, &n) != 0) { + LM_ERR("Invalid number pseudo variable!\n"); + return -1; + } + + if (!digits) + return round_dp_op(msg, &n, (pv_spec_p)result, 0); + + if (fixup_get_ivalue(msg, (gparam_p)digits, &d) != 0) { + LM_ERR("Invalid digits pseudo variable!\n"); + return -1; + } + + return round_dp_op(msg, &n, (pv_spec_p)result, d); +} + + +static int w_round_sf_op(struct sip_msg *msg, char *number, char *result, + char *digits) +{ + int d; + str n; + + if (fixup_get_svalue(msg, (gparam_p)number, &n) != 0) { + LM_ERR("Invalid number pseudo variable!\n"); + return -1; + } + + if (!digits) + return round_dp_op(msg, &n, (pv_spec_p)result, 0); + + if (fixup_get_ivalue(msg, (gparam_p)digits, &d) != 0) { + LM_ERR("Invalid digits pseudo variable!\n"); + return -1; + } + + return round_sf_op(msg, &n, (pv_spec_p)result, d); +} + diff --git a/modules/maxfwd/README b/modules/maxfwd/README index 283f459f7df..314f8806fe2 100644 --- a/modules/maxfwd/README +++ b/modules/maxfwd/README @@ -8,8 +8,7 @@ Bogdan-Andrei Iancu Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/maxfwd/maxfwd.c b/modules/maxfwd/maxfwd.c index 395fe3559d5..ad6a94f62c0 100644 --- a/modules/maxfwd/maxfwd.c +++ b/modules/maxfwd/maxfwd.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -30,7 +30,7 @@ * module param (bogdan) * 2005-09-15 max_limit param cannot be disabled anymore (according to RFC) * (bogdan) - * 2005-11-03 is_maxfwd_lt() function added; MF value saved in + * 2005-11-03 is_maxfwd_lt() function added; MF value saved in * msg->maxforwards->parsed (bogdan) */ @@ -78,8 +78,10 @@ struct module_exports maxfwd_exports = { struct module_exports exports= { #endif "maxfwd", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, params, 0, /* exported statistics */ @@ -129,7 +131,7 @@ static int fixup_maxfwd_header(void** param, int param_no) *param=(void*)code; return 0; }else{ - LM_ERR("bad number <%s>\n",(char*)(*param)); + LM_ERR("bad number <%s>\n",(char*)(*param)); return E_UNSPEC; } } @@ -152,7 +154,7 @@ static int w_process_maxfwd_header(struct sip_msg* msg, char* str1,char* str2) return 2; /* error */ case -2: - break; + goto error; /* found */ case 0: return -1; diff --git a/modules/maxfwd/mf_funcs.c b/modules/maxfwd/mf_funcs.c index daeb86a7f84..6aec7bcdea6 100644 --- a/modules/maxfwd/mf_funcs.c +++ b/modules/maxfwd/mf_funcs.c @@ -15,10 +15,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * ---------- * 2003-02-28 scratchpad compatibility abandoned (jiri) @@ -40,7 +40,7 @@ #define MF_HDR "Max-Forwards: " #define MF_HDR_LEN (sizeof(MF_HDR) - 1) -/* do a tricky thing and keep the parsed value of MAXFWD hdr incremented +/* do a tricky thing and keep the parsed value of MAXFWD hdr incremented * by one in order to make difference between 0 (not set) * and 0 (zero value) - bogdan */ #define IS_MAXWD_STORED(_msg_) \ @@ -135,7 +135,7 @@ int add_maxfwd_header( struct sip_msg* msg , unsigned int val ) len +=CRLF_LEN; /*inserts the header at the beginning of the message*/ - anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0 , 0); + anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0); if (anchor == 0) { LM_ERR("add_maxfwd_header: failed to get anchor\n"); goto error1; diff --git a/modules/maxfwd/mf_funcs.h b/modules/maxfwd/mf_funcs.h index 491266636ef..1465b44d9cc 100644 --- a/modules/maxfwd/mf_funcs.h +++ b/modules/maxfwd/mf_funcs.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/mediaproxy/README b/modules/mediaproxy/README index 4b4e77eb2c3..418510e10b0 100644 --- a/modules/mediaproxy/README +++ b/modules/mediaproxy/README @@ -12,8 +12,7 @@ Dan Pascu Copyright © 2004 Dan Pascu Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/mediaproxy/mediaproxy.c b/modules/mediaproxy/mediaproxy.c index 56e4c50fcbe..36ff599556e 100644 --- a/modules/mediaproxy/mediaproxy.c +++ b/modules/mediaproxy/mediaproxy.c @@ -217,10 +217,23 @@ static param_export_t parameters[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_SILENT }, + { MOD_TYPE_DEFAULT, "dialog", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports = { "mediaproxy", // module name + MOD_TYPE_DEFAULT,// class of this module MODULE_VERSION, // module name DEFAULT_DLFLAGS, // dlopen flags + &deps, // OpenSIPS module dependencies commands, // exported functions parameters, // exported parameters NULL, // exported statistics @@ -448,9 +461,9 @@ get_cseq_number(struct sip_msg *msg, str *cseq) { struct cell *trans = tm_api.t_gett(); - if (msg->first_line.type == SIP_REPLY && trans != NULL && trans != T_UNDEFINED) { - cseq->s = trans->cseq_n.s+CSEQ_LEN; - cseq->len = trans->cseq_n.len-CSEQ_LEN; + if (msg->first_line.type == SIP_REPLY && trans != NULL && trans != T_UNDEFINED && + trans->uas.request!=NULL ) { + *cseq = get_cseq(trans->uas.request)->number; } else { if (msg->cseq == NULL) { if (parse_headers(msg, HDR_CSEQ_F, 0)==-1) { @@ -465,11 +478,6 @@ get_cseq_number(struct sip_msg *msg, str *cseq) *cseq = get_cseq(msg)->number; } - if (cseq->s==NULL || cseq->len==0) { - LM_ERR("missing CSeq number\n"); - return False; - } - return True; } @@ -510,6 +518,11 @@ get_to_uri(struct sip_msg *msg) str uri; char *ptr; + if (parse_headers(msg, HDR_TO_F, 0) == -1) { + LM_ERR("failed to parse To header\n"); + return unknown; + } + if (!msg->to) { LM_ERR("missing To header\n"); return unknown; @@ -564,6 +577,11 @@ get_to_tag(struct sip_msg *msg) return undefined; } + if (parse_headers(msg, HDR_TO_F, 0) == -1) { + LM_ERR("failed to parse To header\n"); + return undefined; + } + if (!msg->to) { LM_ERR("missing To header\n"); return undefined; @@ -680,8 +698,8 @@ check_content_type(struct sip_msg *msg) static int get_sdp_message(struct sip_msg *msg, str *sdp) { - if ( get_body(msg, sdp)!=0 || sdp->len==0) - return -1; + if (get_body(msg, sdp)!=0 || sdp->len==0) + return -2; if (!check_content_type(msg)) return -1; @@ -856,7 +874,7 @@ has_ice_candidates(str *block) } -// will return true if given block contains an ICE +// will return true if given block contains an ICE // candidate with the given component ID static Bool has_ice_candidate_component(str *block, int id) @@ -881,7 +899,7 @@ has_ice_candidate_component(str *block, int id) return True; } } - + chunk.s = zone.s + zone.len; chunk.len = block_end - chunk.s; } @@ -1221,7 +1239,7 @@ insert_element(struct sip_msg *msg, char *position, char *element) return False; } - anchor = anchor_lump(msg, position - msg->buf, 0, 0); + anchor = anchor_lump(msg, position - msg->buf, 0); if (!anchor) { LM_ERR("failed to get anchor for new element\n"); pkg_free(buf); @@ -1440,7 +1458,7 @@ send_command(char *command) // ice_candidate_data: it carries data across the dialog when using engage_media_proxy: // - priority: the priority that should be used for the ICE candidate // * -1: no candidate should be added. -// * other: the specified type preference should be used for calculating +// * other: the specified type preference should be used for calculating // - skip_next_reply: flag for knowing the fact that the next reply with SDP must be skipped // because it is a reply to a re-INVITE or UPDATE *after* the ICE negotiation static int @@ -1462,7 +1480,7 @@ use_media_proxy(struct sip_msg *msg, char *dialog_id, ice_candidate_data *ice_da type = "request"; } else if (msg->first_line.type == SIP_REPLY) { if (ice_data != NULL && ice_data->skip_next_reply) { - // we don't process replies to ICE negotiation end requests + // we don't process replies to ICE negotiation end requests // (those containing a=remote-candidates) ice_data->skip_next_reply = False; return -1; @@ -1500,7 +1518,7 @@ use_media_proxy(struct sip_msg *msg, char *dialog_id, ice_candidate_data *ice_da } return -1; } - + status = get_session_info(&sdp, &session); if (status < 0) { LM_ERR("can't extract media streams from the SDP message\n"); @@ -1637,7 +1655,7 @@ use_media_proxy(struct sip_msg *msg, char *dialog_id, ice_candidate_data *ice_da if (j >= len) { break; } - + if (!isnullport(stream.port)) { if (!replace_element(msg, &stream.port, &tokens[j])) { LM_ERR("failed to replace port in media stream number %d\n", i+1); @@ -1699,7 +1717,7 @@ use_media_proxy(struct sip_msg *msg, char *dialog_id, ice_candidate_data *ice_da candidate.len = sprintf(candidate.s, "a=candidate:R%x 1 UDP %u %.*s %i typ relay%.*s", hexip.s_addr, priority, - tokens[0].len, tokens[0].s, + tokens[0].len, tokens[0].s, port, session.separator.len, session.separator.s); @@ -1713,7 +1731,7 @@ use_media_proxy(struct sip_msg *msg, char *dialog_id, ice_candidate_data *ice_da candidate.len = sprintf(candidate.s, "a=candidate:R%x 2 UDP %u %.*s %i typ relay%.*s", hexip.s_addr, priority-1, - tokens[0].len, tokens[0].s, + tokens[0].len, tokens[0].s, port+1, session.separator.len, session.separator.s); diff --git a/modules/mi_datagram/README b/modules/mi_datagram/README index bce91a03d6b..df2a79f39fb 100644 --- a/modules/mi_datagram/README +++ b/modules/mi_datagram/README @@ -8,8 +8,7 @@ Andreea-Ancuta Onofrei Copyright © 2007 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -237,4 +236,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/mi_datagram/datagram_fnc.c b/modules/mi_datagram/datagram_fnc.c index 2379de7e60d..6846952b2cd 100644 --- a/modules/mi_datagram/datagram_fnc.c +++ b/modules/mi_datagram/datagram_fnc.c @@ -102,7 +102,7 @@ int mi_init_datagram_server(sockaddr_dtgram *addr, unsigned int socket_domain, case AF_LOCAL: LM_DBG("we have a unix socket: %s\n", addr->unix_addr.sun_path); socket_name = addr->unix_addr.sun_path; - if(bind(socks->rx_sock,(struct sockaddr*)&addr->unix_addr, + if(bind(socks->rx_sock,(struct sockaddr*)&addr->unix_addr, SUN_LEN(&addr->unix_addr))< 0) { LM_ERR("bind: %s\n", strerror(errno)); goto err_rx; @@ -120,7 +120,7 @@ int mi_init_datagram_server(sockaddr_dtgram *addr, unsigned int socket_domain, /* change ownership */ if ((uid!=-1) || (gid!=-1)){ if (chown(socket_name, uid, gid)<0){ - LM_ERR("failed to change the owner/group for %s to %d.%d;" + LM_ERR("failed to change the owner/group for %s to %d.%d;" "%s[%d]\n",socket_name, uid, gid, strerror(errno), errno); goto err_rx; } @@ -152,7 +152,7 @@ int mi_init_datagram_server(sockaddr_dtgram *addr, unsigned int socket_domain, socks->tx_sock = socks->rx_sock; break; #ifdef USE_IPV6 - case AF_INET6: + case AF_INET6: if(bind(socks->rx_sock, (struct sockaddr*)&addr->udp_addr.sin6, sizeof(addr->udp_addr)) < 0) { LM_ERR("bind: %s\n", strerror(errno)); @@ -197,7 +197,7 @@ int mi_sock_check(int fd, char* fname) struct stat lst; if (fstat(fd, &fst)<0){ - LM_ERR("fstat failed: %s\n", + LM_ERR("fstat failed: %s\n", strerror(errno)); return -1; } @@ -208,7 +208,7 @@ int mi_sock_check(int fd, char* fname) } /* check if hard-linked */ if (fst.st_nlink>1){ - LM_ERR("security: sock_check: %s is hard-linked %d times\n", + LM_ERR("security: sock_check: %s is hard-linked %d times\n", fname, (unsigned)fst.st_nlink); return -1; } @@ -239,7 +239,7 @@ int mi_sock_check(int fd, char* fname) /* this function sends the reply over the reply socket */ -static int mi_send_dgram(int fd, char* buf, unsigned int len, +static int mi_send_dgram(int fd, char* buf, unsigned int len, const struct sockaddr* to, int tolen, int timeout) { int n; @@ -251,7 +251,7 @@ static int mi_send_dgram(int fd, char* buf, unsigned int len, if(total_len == 0 || tolen ==0) return -1; - + if (total_len>DATAGRAM_SOCK_BUF_SIZE) { LM_DBG("datagram too big, " @@ -265,7 +265,7 @@ static int mi_send_dgram(int fd, char* buf, unsigned int len, -/*function that verifyes that the function from the datagram's first +/*function that verifyes that the function from the datagram's first * line is correct and exists*/ static int identify_command(datagram_stream * dtgram, struct mi_cmd * *f) { @@ -274,17 +274,17 @@ static int identify_command(datagram_stream * dtgram, struct mi_cmd * *f) /* default offset for the command: 0 */ p= dtgram->start; if (!p){ - LM_ERR("null pointer \n"); + LM_ERR("null pointer\n"); return -1; } - + /*if no command*/ if ( dtgram->len ==0 ){ - LM_DBG("command empty case1 \n"); + LM_DBG("command empty case1\n"); goto error; } if (*p != MI_CMD_SEPARATOR){ - LM_ERR("command must begin with: %c \n", MI_CMD_SEPARATOR); + LM_ERR("command must begin with: %c\n", MI_CMD_SEPARATOR); goto error; } command = p+1; @@ -348,18 +348,18 @@ static void datagram_close_async(struct mi_root *mi_rpl,struct mi_handler *hdl, } /*build the response*/ if(mi_datagram_write_tree(&dtgram , mi_rpl) != 0){ - LM_ERR("failed to build the response \n"); + LM_ERR("failed to build the response\n"); goto err1; } LM_DBG("the response is %s", dtgram.start); - + /*send the response*/ ret = mi_send_dgram(p->tx_sock, dtgram.start, - dtgram.current - dtgram.start, - (struct sockaddr *)&p->address, + dtgram.current - dtgram.start, + (struct sockaddr *)&p->address, p->address_len, mi_socket_timeout); if (ret>0){ - LM_DBG("the response: %s has been sent in %i octets\n", + LM_DBG("the response: %s has been sent in %i octets\n", dtgram.start, ret); }else{ LM_ERR("failed to send the response, ret is %i\n",ret); @@ -368,7 +368,7 @@ static void datagram_close_async(struct mi_root *mi_rpl,struct mi_handler *hdl, pkg_free(dtgram.start); } else { mi_send_dgram(p->tx_sock, MI_COMMAND_FAILED, MI_COMMAND_FAILED_LEN, - (struct sockaddr*)&reply_addr, reply_addr_len, + (struct sockaddr*)&reply_addr, reply_addr_len, mi_socket_timeout); } } @@ -436,7 +436,7 @@ void mi_datagram_server(int rx_sock, int tx_sock) reply_addr_len = sizeof(reply_addr); /* get the client's address */ - ret = recvfrom(rx_sock, mi_buf, DATAGRAM_SOCK_BUF_SIZE, 0, + ret = recvfrom(rx_sock, mi_buf, DATAGRAM_SOCK_BUF_SIZE, 0, (struct sockaddr*)&reply_addr, &reply_addr_len); if (ret == -1) { @@ -472,9 +472,9 @@ void mi_datagram_server(int rx_sock, int tx_sock) if(ret != 0) { LM_ERR("command not available\n"); - mi_send_dgram(tx_sock, MI_COMMAND_NOT_AVAILABLE, - MI_COMMAND_AVAILABLE_LEN, - (struct sockaddr* )&reply_addr, reply_addr_len, + mi_send_dgram(tx_sock, MI_COMMAND_NOT_AVAILABLE, + MI_COMMAND_AVAILABLE_LEN, + (struct sockaddr* )&reply_addr, reply_addr_len, mi_socket_timeout); continue; } @@ -495,7 +495,7 @@ void mi_datagram_server(int rx_sock, int tx_sock) hdl = 0; } - LM_DBG("after identifing the command, the received datagram is %s\n", + LM_DBG("after identifing the command, the received datagram is %s\n", dtgram.current); /*if no params required*/ @@ -522,26 +522,26 @@ void mi_datagram_server(int rx_sock, int tx_sock) /*error while running the command*/ LM_ERR("failed to process the command\n"); mi_send_dgram(tx_sock, MI_COMMAND_FAILED, MI_COMMAND_FAILED_LEN, - (struct sockaddr* )&reply_addr, reply_addr_len, + (struct sockaddr* )&reply_addr, reply_addr_len, mi_socket_timeout); goto failure; } /*the command exited well*/ - LM_DBG("command process (%s)succeded\n",f->name.s); + LM_DBG("command process (%s)succeded\n",f->name.s); if (mi_rpl!=MI_ROOT_ASYNC_RPL) { if(mi_datagram_write_tree(&dtgram , mi_rpl) != 0){ - LM_ERR("failed to build the response \n"); + LM_ERR("failed to build the response \n"); goto failure; } len = dtgram.current - dtgram.start; - ret = mi_send_dgram(tx_sock, dtgram.start,len, - (struct sockaddr* )&reply_addr, + ret = mi_send_dgram(tx_sock, dtgram.start,len, + (struct sockaddr* )&reply_addr, reply_addr_len, mi_socket_timeout); if (ret>0){ - LM_DBG("the response: %s has been sent in %i octets\n", + LM_DBG("the response: %s has been sent in %i octets\n", dtgram.start, ret); }else{ LM_ERR("failed to send the response: %s (%d)\n", @@ -550,7 +550,7 @@ void mi_datagram_server(int rx_sock, int tx_sock) free_mi_tree( mi_rpl ); free_async_handler(hdl); if (mi_cmd) free_mi_tree( mi_cmd ); - }else { + }else { if (mi_cmd) free_mi_tree( mi_cmd ); } diff --git a/modules/mi_datagram/datagram_fnc.h b/modules/mi_datagram/datagram_fnc.h index 3158c1f16f9..79d9b60f3ca 100644 --- a/modules/mi_datagram/datagram_fnc.h +++ b/modules/mi_datagram/datagram_fnc.h @@ -53,7 +53,7 @@ typedef struct datagram_str{ - char * start, * current; + char * start, * current; int len; }datagram_stream; @@ -63,7 +63,7 @@ typedef struct rx_tx{ int mi_init_datagram_server(sockaddr_dtgram * address, unsigned int domain, - rx_tx_sockets * socks,int mode, + rx_tx_sockets * socks,int mode, int uid, int gid ); int mi_init_datagram_buffer(); void mi_datagram_server(int rx_sock, int tx_sock); diff --git a/modules/mi_datagram/mi_datagram.c b/modules/mi_datagram/mi_datagram.c index a4251fb43af..6643afc326b 100644 --- a/modules/mi_datagram/mi_datagram.c +++ b/modules/mi_datagram/mi_datagram.c @@ -124,8 +124,10 @@ static param_export_t mi_params[] = { struct module_exports exports = { "mi_datagram", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ mi_params, /* exported parameters */ 0, /* exported statistics */ @@ -195,7 +197,7 @@ static int mi_mod_init(void) LM_ERR("invalid port number; must be in [1024,%d]\n",MAX_NB_PORT); return -1; } - + if(! (host = resolvehost(host_s, 0)) ){ LM_ERR("failed to resolve %s\n", host_s); return -1; @@ -211,7 +213,7 @@ static int mi_mod_init(void) { /*in case of a Unix socket*/ LM_DBG("we have an UNIX socket\n"); - + n=stat(mi_socket, &filestat); if( n==0){ LM_INFO("the socket %s already exists, trying to delete it...\n", @@ -231,15 +233,15 @@ static int mi_mod_init(void) "forcing it to rw-------\n"); mi_unix_socket_mode = S_IRUSR| S_IWUSR; } - + if (mi_unix_socket_uid_s){ - if (user2uid(&mi_unix_socket_uid, &mi_unix_socket_gid, + if (user2uid(&mi_unix_socket_uid, &mi_unix_socket_gid, mi_unix_socket_uid_s)<0){ LM_ERR("bad user name %s\n", mi_unix_socket_uid_s); return -1; } } - + if (mi_unix_socket_gid_s){ if (group2gid(&mi_unix_socket_gid, mi_unix_socket_gid_s)<0){ LM_ERR("bad group name %s\n", mi_unix_socket_gid_s); @@ -276,7 +278,7 @@ static int pre_datagram_process(void) /*create the sockets*/ res = mi_init_datagram_server(&mi_dtgram_addr, mi_socket_domain, &sockets, - mi_unix_socket_mode, mi_unix_socket_uid, + mi_unix_socket_mode, mi_unix_socket_uid, mi_unix_socket_gid); if ( res ) { @@ -333,7 +335,7 @@ static int mi_destroy(void) n=stat(mi_socket, &filestat); if (n==0){ if (unlink(mi_socket)<0){ - LM_ERR("cannot delete the socket (%s): %s\n", + LM_ERR("cannot delete the socket (%s): %s\n", mi_socket, strerror(errno)); goto error; } diff --git a/modules/mi_datagram/mi_datagram.h b/modules/mi_datagram/mi_datagram.h index 58c1e20831c..aa19e1e727e 100644 --- a/modules/mi_datagram/mi_datagram.h +++ b/modules/mi_datagram/mi_datagram.h @@ -42,7 +42,7 @@ #define MAX_MI_FILENAME 128 /* size of buffer used by parser to read and build the MI tree */ -#define MI_CHILD_NO 1 +#define MI_CHILD_NO 1 #include #include "../../ip_addr.h" diff --git a/modules/mi_datagram/mi_datagram_parser.c b/modules/mi_datagram/mi_datagram_parser.c index 0bb9ced029a..84b1a3fd93c 100644 --- a/modules/mi_datagram/mi_datagram_parser.c +++ b/modules/mi_datagram/mi_datagram_parser.c @@ -55,7 +55,7 @@ int mi_datagram_parser_init( unsigned int size ) * 1 = end of input */ /*example: mi_parse_node(datagram, &buf, &name, &value)*/ -static inline int mi_datagram_parse_node(datagram_stream * data, str *name, +static inline int mi_datagram_parse_node(datagram_stream * data, str *name, str *value) { char *p, *pmax; @@ -92,7 +92,7 @@ static inline int mi_datagram_parse_node(datagram_stream * data, str *name, /* look for the atribute name */ p = mark_nsp = start; - while ( p!=pmax && (( *p!=MI_ATTR_VAL_SEP1) || p+1==pmax + while ( p!=pmax && (( *p!=MI_ATTR_VAL_SEP1) || p+1==pmax ||*(p+1)!=MI_ATTR_VAL_SEP2) ) { if (!isspace((int)*p)) { if (*p=='"') @@ -128,7 +128,7 @@ static inline int mi_datagram_parse_node(datagram_stream * data, str *name, } p += 2; /* for separator */ - + /* consume the trailing spaces */ for( ; p!=pmax && isspace((int)*p) ; p++) { @@ -165,7 +165,7 @@ static inline int mi_datagram_parse_node(datagram_stream * data, str *name, break; } } - + value->s = start; value->len = mark_nsp - start+1; LM_DBG("*start is %c and start is %p\n",*start, start); @@ -200,13 +200,13 @@ static inline int mi_datagram_parse_node(datagram_stream * data, str *name, LM_DBG("skipping %c",*p); /* skip current char */ memmove( p-1, p, pmax-p); - pmax--; + pmax--; } else { LM_DBG("we have reached the end of attr value, p is %s\n", p); /* end of value */ value->len = p - value->s; LM_DBG("attr value <%.*s> found\n",value->len, value->s); - + /* is the line ending propely (only spaces) ? */ p++; for(; p!=pmax && isspace((int)*p) ; p++) @@ -278,7 +278,7 @@ struct mi_root * mi_datagram_parse_tree(datagram_stream * datagram) { /* every tree for a command ends with a \n that is alone on its line */ while ((ret=mi_datagram_parse_node(datagram, &name, &value))>=0 ) { - + if(ret == 1) return root; LM_DBG("adding node <%.*s> ; val <%.*s>\n", diff --git a/modules/mi_datagram/mi_datagram_writer.c b/modules/mi_datagram/mi_datagram_writer.c index 545252d6652..c48af5a6f8f 100644 --- a/modules/mi_datagram/mi_datagram_writer.c +++ b/modules/mi_datagram/mi_datagram_writer.c @@ -59,13 +59,13 @@ int mi_datagram_writer_init( unsigned int size , char *indent) } -static inline int mi_datagram_write_node(datagram_stream * dtgram, +static inline int mi_datagram_write_node(datagram_stream * dtgram, struct mi_node *node, int level) { struct mi_attr *attr; char *start, *end, *p; - + start = p = dtgram->current; end = dtgram->start + dtgram->len; LM_DBG("writing the name <%.*s> and value <%.*s> \n", @@ -95,7 +95,7 @@ static inline int mi_datagram_write_node(datagram_stream * dtgram, *(p++) = MI_ATTR_VAL_SEP2; *(p++) = ' '; } - + /*LM_DBG("after adding the " "name, the datagram is %s\n ", dtgram->datagram.s);*/ if (node->value.s!=NULL) { @@ -143,17 +143,17 @@ static inline int mi_datagram_write_node(datagram_stream * dtgram, dtgram->len -= p-start; dtgram->current = p; - + return 0; } -static int datagram_recur_write_tree(datagram_stream *dtgram, +static int datagram_recur_write_tree(datagram_stream *dtgram, struct mi_node *tree, int level) { for( ; tree ; tree=tree->next ) { - if (!(tree->flags & MI_WRITTEN)) { + if (!(tree->flags & MI_WRITTEN)) { if (mi_datagram_write_node( dtgram, tree, level)!=0) { LM_ERR("failed to write -line too long!!!\n"); return -1; @@ -183,7 +183,7 @@ int mi_datagram_write_tree(datagram_stream * dtgram, struct mi_root *tree) LM_ERR("failed to write - reason too long!\n"); return -1; } - + memcpy( dtgram->start, code.s, code.len); dtgram->current += code.len; *(dtgram->current) = ' '; @@ -217,27 +217,27 @@ int mi_datagram_write_tree(datagram_stream * dtgram, struct mi_root *tree) static int mi_datagram_recur_flush_tree(datagram_stream * dtgram, struct mi_node *tree, int level) { - struct mi_node *kid, *tmp; + struct mi_node *kid, *tmp; int ret; - for(kid = tree->kids ; kid ; ){ + for(kid = tree->kids ; kid ; ){ /* write the current kid */ if (!(kid->flags & MI_WRITTEN)){ if (mi_datagram_write_node( dtgram, kid, level)<0) { LM_ERR("failed to write -line too long!!!\n"); return -1; } - /* we are sure that this node has been written + /* we are sure that this node has been written * => avoid writing it again */ kid->flags |= MI_WRITTEN; } - + /* write the current kid's children */ if ((ret = mi_datagram_recur_flush_tree(dtgram, kid, level+1))<0) return -1; else if (ret > 0) return ret; - + if (!(kid->flags & MI_NOT_COMPLETED)){ tmp = kid; kid = kid->next; @@ -245,7 +245,7 @@ static int mi_datagram_recur_flush_tree(datagram_stream * dtgram, if(!tmp->kids){ /* this node does not have any kids */ - free_mi_node(tmp); + free_mi_node(tmp); } } else{ @@ -281,12 +281,12 @@ int mi_datagram_flush_tree(datagram_stream * dtgram, struct mi_root *tree) memcpy(dtgram->current, tree->reason.s, tree->reason.len); dtgram->current += tree->reason.len; } - + *(dtgram->current) = '\n'; dtgram->current++; dtgram->len -= code.len + 1 + tree->reason.len+1; - - /* we are sure that this node has been written + + /* we are sure that this node has been written * => avoid writing it again */ tree->node.flags |= MI_WRITTEN; } @@ -298,7 +298,7 @@ int mi_datagram_flush_tree(datagram_stream * dtgram, struct mi_root *tree) LM_ERR("failed to write - EOC does not fit in!\n"); return -1; } - + *(dtgram->current) = '\n'; dtgram->len--; *(dtgram->current) = '\0'; diff --git a/modules/mi_fifo/README b/modules/mi_fifo/README index 0e653d5d6aa..6b3b98a8a07 100644 --- a/modules/mi_fifo/README +++ b/modules/mi_fifo/README @@ -2,7 +2,7 @@ mi_fifo Module Bogdan-Andrei Iancu - OpenSIPS Solutions> + OpenSIPS Solutions Edited by @@ -10,8 +10,7 @@ Bogdan-Andrei Iancu Copyright © 2006 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -52,7 +51,14 @@ Chapter 1. Admin Guide 1.1. Overview This is a module which provides a FIFO transport layer - implementation for Management Interface. + implementation for Management Interface. It receives the + command over a FIFO file and returns the output through the + reply_fifo specified. + + The module checks every 30 seconds if the FIFO files exists, + and if it was deleted, it recreates it. If one wants to force + the fifo file recreation, it should send a SIGHUP signal to the + MI process PID. 1.2. FIFO command syntax diff --git a/modules/mi_fifo/doc/mi_fifo_admin.xml b/modules/mi_fifo/doc/mi_fifo_admin.xml index 82d7b9de9bf..b8ef33e2485 100644 --- a/modules/mi_fifo/doc/mi_fifo_admin.xml +++ b/modules/mi_fifo/doc/mi_fifo_admin.xml @@ -8,7 +8,15 @@ Overview This is a module which provides a FIFO transport layer - implementation for Management Interface. + implementation for Management Interface. It receives the + command over a FIFO file and returns the output through the + reply_fifo specified. + + + The module checks every 30 seconds if the FIFO files exists, + and if it was deleted, it recreates it. If one wants to force + the fifo file recreation, it should send a SIGHUP signal to + the MI process PID.
diff --git a/modules/mi_fifo/fifo_fnc.c b/modules/mi_fifo/fifo_fnc.c index fbb5a86d93c..b5524e74bca 100644 --- a/modules/mi_fifo/fifo_fnc.c +++ b/modules/mi_fifo/fifo_fnc.c @@ -47,45 +47,49 @@ #include "mi_parser.h" #include "mi_writer.h" -static int mi_fifo_read = 0; -static int mi_fifo_write = 0; static char *mi_buf = 0; static char *reply_fifo_s = 0; static int reply_fifo_len = 0; +static char *mi_fifo_name = NULL; +static int mi_fifo_mode; +static int mi_fifo_uid; +static int mi_fifo_gid; +static int volatile mi_reload_fifo = 0; -FILE* mi_init_fifo_server(char *fifo_name, int mi_fifo_mode, - int mi_fifo_uid, int mi_fifo_gid, char* fifo_reply_dir) +FILE* mi_create_fifo(void) { - FILE *fifo_stream; + static int mi_fifo_read = 0; + static int mi_fifo_write = 0; + FILE *fifo_stream = 0; long opt; /* create FIFO ... */ - if ((mkfifo(fifo_name, mi_fifo_mode)<0)) { + if ((mkfifo(mi_fifo_name, mi_fifo_mode)<0)) { LM_ERR("can't create FIFO: %s (mode=%d)\n", strerror(errno), mi_fifo_mode); return 0; } - LM_DBG("FIFO created @ %s\n", fifo_name ); + LM_DBG("FIFO created @ %s\n", mi_fifo_name ); - if ((chmod(fifo_name, mi_fifo_mode)<0)) { + if ((chmod(mi_fifo_name, mi_fifo_mode)<0)) { LM_ERR("can't chmod FIFO: %s (mode=%d)\n", strerror(errno), mi_fifo_mode); return 0; } if ((mi_fifo_uid!=-1) || (mi_fifo_gid!=-1)){ - if (chown(fifo_name, mi_fifo_uid, mi_fifo_gid)<0){ - LM_ERR("failed to change the owner/group for %s to %d.%d; %s[%d]\n", - fifo_name, mi_fifo_uid, mi_fifo_gid, strerror(errno), errno); + if (chown(mi_fifo_name, mi_fifo_uid, mi_fifo_gid)<0){ + LM_ERR("failed to change the owner/group for %s to %d.%d; %s[%d]\n", + mi_fifo_name, mi_fifo_uid, mi_fifo_gid, strerror(errno), errno); return 0; } } - LM_DBG("fifo %s opened, mode=%o\n", fifo_name, mi_fifo_mode ); + LM_DBG("fifo %s opened, mode=%o\n", mi_fifo_name, mi_fifo_mode ); /* open it non-blocking or else wait here until someone * opens it for writing */ - mi_fifo_read=open(fifo_name, O_RDONLY|O_NONBLOCK, 0); + mi_fifo_read=open(mi_fifo_name, O_RDONLY|O_NONBLOCK, 0); if (mi_fifo_read<0) { LM_ERR("mi_fifo_read did not open: %s\n", strerror(errno)); return 0; @@ -98,7 +102,7 @@ FILE* mi_init_fifo_server(char *fifo_name, int mi_fifo_mode, } /* make sure the read fifo will not close */ - mi_fifo_write=open( fifo_name, O_WRONLY|O_NONBLOCK, 0); + mi_fifo_write=open(mi_fifo_name, O_WRONLY|O_NONBLOCK, 0); if (mi_fifo_write<0) { LM_ERR("fifo_write did not open: %s\n", strerror(errno)); return 0; @@ -112,6 +116,19 @@ FILE* mi_init_fifo_server(char *fifo_name, int mi_fifo_mode, LM_ERR("cntl(F_SETFL) failed: %s [%d]\n", strerror(errno), errno); return 0; } + return fifo_stream; +} + +static void mi_sig_hup(int signo) +{ + mi_reload_fifo = 1; +} + +FILE* mi_init_fifo_server(char *fifo_name, int fifo_mode, + int fifo_uid, int fifo_gid, char* fifo_reply_dir) +{ + FILE *fifo_stream; + /* allocate all static buffers */ mi_buf = pkg_malloc(MAX_MI_FIFO_BUFFER); @@ -120,11 +137,27 @@ FILE* mi_init_fifo_server(char *fifo_name, int mi_fifo_mode, LM_ERR("no more private memory\n"); return 0; } + mi_fifo_name = fifo_name; + mi_fifo_mode = fifo_mode; + mi_fifo_uid = fifo_uid; + mi_fifo_gid = fifo_gid; + + fifo_stream = mi_create_fifo(); + if (!fifo_stream) { + LM_ERR("cannot create fifo\n"); + return 0; + } /* init fifo reply dir buffer */ reply_fifo_len = strlen(fifo_reply_dir); memcpy( reply_fifo_s, fifo_reply_dir, reply_fifo_len); + if (signal(SIGHUP, mi_sig_hup) == SIG_ERR ) { + LM_ERR("cannot install SIGHUP signal\n"); + pkg_free(reply_fifo_s); + return 0; + } + return fifo_stream; } @@ -138,7 +171,7 @@ static int mi_fifo_check(int fd, char* fname) { struct stat fst; struct stat lst; - + if (fstat(fd, &fst)<0){ LM_ERR("fstat failed: %s\n", strerror(errno)); return -1; @@ -176,6 +209,35 @@ static int mi_fifo_check(int fd, char* fname) } +static inline FILE* get_fifo_stream(FILE *old_stream) +{ + int fd, n; + struct stat fst; + + if (mi_reload_fifo == 0) { + fd = fileno(old_stream); + if (!mi_fifo_check(fd, mi_fifo_name)) + return old_stream; + LM_INFO("invalid FIFO file: creating a new one (%s)\n", mi_fifo_name); + } else { + LM_INFO("Forcefully replacing FIFO file (%s)\n", mi_fifo_name); + } + /* here we are either forced to reload or the check did not pass */ + n = stat(mi_fifo_name, &fst); + if (n == 0) { + if (unlink(mi_fifo_name) < 0) { + LM_ERR("cannot delete fifo file %s\n", mi_fifo_name); + return NULL; + } + LM_INFO("deleted FIFO file (%s)\n", mi_fifo_name); + } else if (n < 0 && errno != ENOENT) { + LM_ERR("stat failed: %s\n", strerror(errno)); + return NULL; + } + mi_reload_fifo = 0; + return mi_create_fifo(); +} + static FILE *mi_open_reply_pipe( char *pipe_name ) { @@ -191,7 +253,7 @@ static FILE *mi_open_reply_pipe( char *pipe_name ) } tryagain: - /* open non-blocking to make sure that a broken client will not + /* open non-blocking to make sure that a broken client will not * block the FIFO server forever */ fifofd=open( pipe_name, O_WRONLY | O_NONBLOCK ); if (fifofd==-1) { @@ -215,7 +277,7 @@ static FILE *mi_open_reply_pipe( char *pipe_name ) LM_ERR("open error (%s): %s\n", pipe_name, strerror(errno)); return 0; } - /* security checks: is this really a fifo?, is + /* security checks: is this really a fifo?, is * it hardlinked? is it a soft link? */ if (mi_fifo_check(fifofd, pipe_name)<0) goto error; @@ -243,39 +305,66 @@ static FILE *mi_open_reply_pipe( char *pipe_name ) return 0; } +static FILE *mi_init_read(FILE *stream, int *fd, fd_set *fds) +{ + FILE *new_stream = get_fifo_stream(stream); + if (!new_stream) + return NULL; + *fd = fileno(new_stream); + FD_ZERO(fds); + FD_SET(*fd, fds); + return new_stream; +} -int mi_read_line( char *b, int max, FILE *stream, int *read) +int mi_read_line( char *b, int max, FILE **stream, int *read_len) { - int retry_cnt; - int len; - retry_cnt=0; + int ret = 0; + int done, i, fd; + struct timeval tv; + fd_set fds, init_fds; + FILE *new_stream; + + /* first check if we need to update our fifo file */ + if (!(new_stream = mi_init_read(*stream, &fd, &init_fds))) + return -1; + done = 0; + for (i = 0; !done && i < max; i++) { + fds = init_fds; + tv.tv_sec = FIFO_CHECK_WAIT; + tv.tv_usec = 0; retry: - if (fgets(b, max, stream)==NULL) { - LM_ERR("fifo_server fgets failed: %s\n", strerror(errno)); - /* on Linux, fgets sometimes returns ESPIPE -- give - it few more chances - */ - if (errno==ESPIPE) { - retry_cnt++; - if (retry_cnt<4) goto retry; + ret = select(fd + 1, &fds, NULL, NULL, &tv); + if (ret < 0) { + if (errno == EAGAIN) + goto retry; + /* interrupted by signal or ... */ + if (errno == EINTR) { + if (!(new_stream = mi_init_read(new_stream, &fd, &init_fds))) + return -1; + } else { + kill(0, SIGTERM); + } + } else if (ret == 0) { + if (!(new_stream = mi_init_read(new_stream, &fd, &init_fds))) + return -1; + --i; + continue; } - /* interrupted by signal or ... */ - if ((errno==EINTR)||(errno==EAGAIN)) goto retry; - kill(0, SIGTERM); + ret = read(fd, &b[i], 1); + if (ret < 0) + return ret; + else if (ret == 0 || b[i] == '\n') + done = 1; } - /* if we did not read whole line, our buffer is too small - and we cannot process the request; consume the remainder of - request - */ - - len=strlen(b); - if (len && !(b[len-1]=='\n' || b[len-1]=='\r')) { - LM_ERR("request line too long\n"); + + if (!done) { + LM_ERR("request line too long\n"); return -1; } - *read = len; + *read_len = i; + *stream = new_stream; return 0; } @@ -297,6 +386,7 @@ static inline char *get_reply_filename( char * file, int len ) memcpy( reply_fifo_s+reply_fifo_len, file, len ); reply_fifo_s[reply_fifo_len+len]=0; + return reply_fifo_s; } @@ -366,7 +456,7 @@ static inline struct mi_handler* build_async_handler( char *name, int len) LM_DBG("entered consume\n"); \ /* consume the rest of the fifo request */ \ do { \ - mi_read_line(mi_buf,MAX_MI_FIFO_BUFFER,fifo_stream,&line_len); \ + mi_read_line(mi_buf,MAX_MI_FIFO_BUFFER,&fifo_stream,&line_len); \ } while(line_len>1); \ LM_DBG("**** done consume\n"); \ } while(0) @@ -397,7 +487,7 @@ void mi_fifo_server(FILE *fifo_stream) reply_stream = NULL; /* commands must look this way '::[filename]' */ - if (mi_read_line(mi_buf,MAX_MI_FIFO_BUFFER,fifo_stream, &line_len)) { + if (mi_read_line(mi_buf,MAX_MI_FIFO_BUFFER,&fifo_stream, &line_len)) { LM_ERR("failed to read command\n"); continue; } @@ -409,7 +499,7 @@ void mi_fifo_server(FILE *fifo_stream) line_len--; mi_buf[line_len]=0; } else break; - } + } if (line_len==0) { LM_DBG("command empty\n"); diff --git a/modules/mi_fifo/fifo_fnc.h b/modules/mi_fifo/fifo_fnc.h index c1bcfaa3c8e..8d567bc5b38 100644 --- a/modules/mi_fifo/fifo_fnc.h +++ b/modules/mi_fifo/fifo_fnc.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2006 Voice Sistem SRL @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -34,7 +34,7 @@ #include -/* how patient is opensips with FIFO clients not awaiting a reply? +/* how patient is opensips with FIFO clients not awaiting a reply? default = 4 x 80ms = 0.32 sec */ #define FIFO_REPLY_RETRIES 4 @@ -47,7 +47,7 @@ FILE* mi_init_fifo_server(char *fifo_name, int mode, int uid, int gid, void mi_fifo_server(FILE *fifostream); -int mi_read_line( char *b, int max, FILE *stream, int *read); +int mi_read_line( char *b, int max, FILE **stream, int *read); static inline int mi_fifo_reply( FILE *stream, char *reply_fmt, ... ) { diff --git a/modules/mi_fifo/mi_fifo.c b/modules/mi_fifo/mi_fifo.c index 1dbf4ed364c..c3b1a7f4e9d 100644 --- a/modules/mi_fifo/mi_fifo.c +++ b/modules/mi_fifo/mi_fifo.c @@ -87,8 +87,10 @@ static proc_export_t mi_procs[] = { struct module_exports exports = { "mi_fifo", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ mi_params, /* exported parameters */ 0, /* exported statistics */ diff --git a/modules/mi_fifo/mi_fifo.h b/modules/mi_fifo/mi_fifo.h index 3d996f6745a..34c7df4614e 100644 --- a/modules/mi_fifo/mi_fifo.h +++ b/modules/mi_fifo/mi_fifo.h @@ -42,7 +42,7 @@ /* maximum length of a FIFO line */ #define MAX_MI_FIFO_BUFFER 1024 -/* how patient is ser with FIFO clients not awaiting a reply? +/* how patient is ser with FIFO clients not awaiting a reply? 4 x 80ms = 0.32 sec */ #define FIFO_REPLY_RETRIES 4 @@ -52,4 +52,7 @@ /* size of buffer used by parser to read and build the MI tree */ #define MAX_MI_FIFO_READ 8192 +/* we are waiting for a while between fifo file checks */ +#define FIFO_CHECK_WAIT 30 + #endif /* _MI_FIFO */ diff --git a/modules/mi_fifo/mi_parser.c b/modules/mi_fifo/mi_parser.c index c7ef8bab351..1c6b3352c70 100644 --- a/modules/mi_fifo/mi_parser.c +++ b/modules/mi_fifo/mi_parser.c @@ -70,7 +70,7 @@ static inline int mi_parse_node( FILE *stream, str *buf, str *name, str *value) /* read one line */ do { - if (mi_read_line( buf->s, buf->len, stream, &line_len)<0) { + if (mi_read_line( buf->s, buf->len, &stream, &line_len)<0) { LM_ERR("failed to read from fifo\n"); return -1; } @@ -185,7 +185,7 @@ static inline int mi_parse_node( FILE *stream, str *buf, str *name, str *value) buf->s = p; /*read one more line */ - if (mi_read_line( buf->s, buf->len, stream, &line_len)<0) { + if (mi_read_line( buf->s, buf->len, &stream, &line_len)<0) { LM_ERR("failed to re-read from fifo\n"); return -1; } @@ -248,7 +248,7 @@ struct mi_root * mi_parse_tree(FILE *stream) { if (ret==-1) { /* consume the rest of the fifo request */ do { - mi_read_line(mi_parse_buffer,mi_parse_buffer_len,stream,&ret); + mi_read_line(mi_parse_buffer,mi_parse_buffer_len,&stream,&ret); }while(ret>1); } diff --git a/modules/mi_fifo/mi_writer.c b/modules/mi_fifo/mi_writer.c index 1be4a4e5f06..ba4d4b3390d 100644 --- a/modules/mi_fifo/mi_writer.c +++ b/modules/mi_fifo/mi_writer.c @@ -141,7 +141,7 @@ static inline int mi_write_node(str *buf, struct mi_node *node, int level) static int recur_write_tree(FILE *stream, struct mi_node *tree, str *buf, int level) { - for( ; tree ; tree=tree->next ) { + for( ; tree ; tree=tree->next ) { if (!(tree->flags & MI_WRITTEN)) { if (mi_write_node( buf, tree, level)!=0) { /* buffer is full -> write it and reset buffer */ @@ -213,7 +213,7 @@ int mi_write_tree(FILE *stream, struct mi_root *tree) static int recur_flush_tree(FILE *stream, struct mi_node *tree, str *buf, int level) { - struct mi_node *kid, *tmp; + struct mi_node *kid, *tmp; int ret; for(kid = tree->kids ; kid ; ){ @@ -232,7 +232,7 @@ static int recur_flush_tree(FILE *stream, struct mi_node *tree, str *buf, } } - /* we are sure that this node has been written + /* we are sure that this node has been written * => avoid writing it again */ kid->flags |= MI_WRITTEN; } @@ -250,7 +250,7 @@ static int recur_flush_tree(FILE *stream, struct mi_node *tree, str *buf, if(!tmp->kids){ /* this node does not have any kids */ - free_mi_node(tmp); + free_mi_node(tmp); } } else{ @@ -289,8 +289,8 @@ int mi_flush_tree(FILE *stream, struct mi_root *tree) } *(buf.s++) = '\n'; buf.len -= code.len + 1 + tree->reason.len+1; - - /* we are sure that this node has been written + + /* we are sure that this node has been written * => avoid writing it again */ tree->node.flags |= MI_WRITTEN; } diff --git a/modules/mi_http/README b/modules/mi_http/README index 9e70d1643b8..a426705b5bf 100644 --- a/modules/mi_http/README +++ b/modules/mi_http/README @@ -8,10 +8,9 @@ Edited by Ovidiu Sas - Copyright © 2011-2012 VoIP Embedded, Inc. + Copyright © 2011-2013 VoIP Embedded, Inc. Revision History - Revision $Rev: 8580 $ $Date: 2011-11-21 14:51:00 -0500 (Mon, 21 - Nov 2011) $ + Revision $Rev: 8688 $ $Date$ __________________________________________________________ Table of Contents @@ -27,6 +26,7 @@ Ovidiu Sas 1.4. Exported Parameters 1.4.1. mi_http_root(string) + 1.4.2. mi_http_method(integer) 1.5. Exported Functions 1.6. Known issues @@ -34,6 +34,7 @@ Ovidiu Sas List of Examples 1.1. Set mi_http_root parameter + 1.2. Set mi_http_method parameter Chapter 1. Admin Guide @@ -58,8 +59,8 @@ Chapter 1. Admin Guide 1.4.1. mi_http_root(string) - It specifies the root path for mi http requests. The link to - the mi web interface must be constructed using the following + Specifies the root path for mi http requests. The link to the + mi web interface must be constructed using the following patern: http://[opensips_IP]:[opensips_mi_port]/[mi_http_root] The default value is "mi". @@ -69,6 +70,19 @@ Chapter 1. Admin Guide modparam("mi_http", "mi_http_root", "opensips_mi") ... +1.4.2. mi_http_method(integer) + + Specifies the HTTP request method to be used: + * 0 - use GET HTTP request + * 1 - use POST HTTP request + + The default value is 0. + + Example 1.2. Set mi_http_method parameter +... +modparam("mi_http", "mi_http_method", 1) +... + 1.5. Exported Functions No function exported to be used from configuration file. diff --git a/modules/mi_http/doc/mi_http.xml b/modules/mi_http/doc/mi_http.xml index a11ee416c7b..7e1c40c06e6 100644 --- a/modules/mi_http/doc/mi_http.xml +++ b/modules/mi_http/doc/mi_http.xml @@ -28,7 +28,7 @@ - 2011-2012 + 2011-2013 VoIP Embedded, Inc. diff --git a/modules/mi_http/doc/mi_http_admin.xml b/modules/mi_http/doc/mi_http_admin.xml index 1334e1ccf6c..b0d2e551ca6 100644 --- a/modules/mi_http/doc/mi_http_admin.xml +++ b/modules/mi_http/doc/mi_http_admin.xml @@ -46,7 +46,7 @@
<varname>mi_http_root</varname>(string) - It specifies the root path for mi http requests. + Specifies the root path for mi http requests. The link to the mi web interface must be constructed using the following patern: http://[opensips_IP]:[opensips_mi_port]/[mi_http_root] @@ -60,6 +60,27 @@ ... modparam("mi_http", "mi_http_root", "opensips_mi") ... + + +
+
+ <varname>mi_http_method</varname>(integer) + + Specifies the HTTP request method to be used: + + 0 - use GET HTTP request + 1 - use POST HTTP request + + + + The default value is 0. + + + Set <varname>mi_http_method</varname> parameter + +... +modparam("mi_http", "mi_http_method", 1) +...
diff --git a/modules/mi_http/http_fnc.c b/modules/mi_http/http_fnc.c index 2880d928e02..aa86de8723b 100644 --- a/modules/mi_http/http_fnc.c +++ b/modules/mi_http/http_fnc.c @@ -1,7 +1,7 @@ /* * $Id$ * - * Copyright (C) 2011 VoIP Embedded Inc. + * Copyright (C) 2011-2013 VoIP Embedded, Inc. * * This file is part of Open SIP Server (opensips). * @@ -38,6 +38,7 @@ extern str http_root; +extern int http_method; str upSinceCTime; http_mi_cmd_t* http_mi_cmds; @@ -109,6 +110,20 @@ do{ \ memcpy((p), (s6).s, (s6).len); (p) += (s6).len; \ }while(0) +#define MI_HTTP_COPY_7(p,s1,s2,s3,s4,s5,s6,s7) \ +do{ \ + if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len+(s6).len+(s7).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (s1).s, (s1).len); (p) += (s1).len; \ + memcpy((p), (s2).s, (s2).len); (p) += (s2).len; \ + memcpy((p), (s3).s, (s3).len); (p) += (s3).len; \ + memcpy((p), (s4).s, (s4).len); (p) += (s4).len; \ + memcpy((p), (s5).s, (s5).len); (p) += (s5).len; \ + memcpy((p), (s6).s, (s6).len); (p) += (s6).len; \ + memcpy((p), (s7).s, (s7).len); (p) += (s7).len; \ +}while(0) + #define MI_HTTP_COPY_10(p,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10) \ do{ \ if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len+(s6).len+(s7).len+(s8).len+(s9).len+(s10).len>max_page_len) { \ @@ -144,6 +159,73 @@ do{ \ memcpy((p), (s11).s, (s11).len); (p) += (s11).len; \ }while(0) +#define MI_HTTP_COPY_12(p,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12) \ +do{ \ + if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len+(s6).len+(s7).len+(s8).len+(s9).len+(s10).len+(s11).len+(s12).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (s1).s, (s1).len); (p) += (s1).len; \ + memcpy((p), (s2).s, (s2).len); (p) += (s2).len; \ + memcpy((p), (s3).s, (s3).len); (p) += (s3).len; \ + memcpy((p), (s4).s, (s4).len); (p) += (s4).len; \ + memcpy((p), (s5).s, (s5).len); (p) += (s5).len; \ + memcpy((p), (s6).s, (s6).len); (p) += (s6).len; \ + memcpy((p), (s7).s, (s7).len); (p) += (s7).len; \ + memcpy((p), (s8).s, (s8).len); (p) += (s8).len; \ + memcpy((p), (s9).s, (s9).len); (p) += (s9).len; \ + memcpy((p), (s10).s, (s10).len); (p) += (s10).len; \ + memcpy((p), (s11).s, (s11).len); (p) += (s11).len; \ + memcpy((p), (s12).s, (s12).len); (p) += (s12).len; \ +}while(0) + + +#define MI_HTTP_ESC_COPY(p,str,temp_holder,temp_counter) \ +do{ \ + (temp_holder).s = (str).s; \ + (temp_holder).len = 0; \ + for((temp_counter)=0;(temp_counter)<(str).len;(temp_counter)++) { \ + switch((str).s[(temp_counter)]) { \ + case '<': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_HTTP_COPY_2(p, (temp_holder), MI_HTTP_ESC_LT); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '>': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_HTTP_COPY_2(p, (temp_holder), MI_HTTP_ESC_GT); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '&': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_HTTP_COPY_2(p, (temp_holder), MI_HTTP_ESC_AMP); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '"': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_HTTP_COPY_2(p, (temp_holder), MI_HTTP_ESC_QUOT); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '\'': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_HTTP_COPY_2(p, (temp_holder), MI_HTTP_ESC_SQUOT); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + } \ + } \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_HTTP_COPY(p, (temp_holder)); \ +}while(0) + +static const str MI_HTTP_METHOD[] = { + str_init("GET"), + str_init("POST") +}; + static const str MI_HTTP_Response_Head_1 = str_init(""\ "OpenSIPS Management Interface"\ ""\ ""\ ""); static const str MI_HTTP_Response_Head_2 = str_init(\ -""\ +""\ +"\n"\ ""); static const str MI_HTTP_Response_Title_Table_1 = str_init(\ @@ -208,14 +291,10 @@ static const str MI_HTTP_CODE_1 = str_init("
");
 static const str MI_HTTP_CODE_2 = str_init("
"); static const str MI_HTTP_Post_1 = str_init("\n"\ -"
\n"\ -" \n"\ -" \n"\ -" \n"); +"
\n"\ -" \n"\ +static const str MI_HTTP_Post_2 = str_init("\">\n"\ +" \n"\ " \n"\ " \n"); @@ -223,13 +302,18 @@ static const str MI_HTTP_Response_Foot = str_init(\ "\n\n
"\ ""\ "OpenSIPS web site
"\ - "Copyright © 2011-2012 VoIP Embedded"\ + "Copyright © 2011-2013 VoIP Embedded, Inc."\ ". All rights reserved."\ "
"); #define MI_HTTP_ROWSPAN 5 static const str MI_HTTP_CMD_ROWSPAN = str_init("5"); +static const str MI_HTTP_ESC_LT = str_init("<"); /* < */ +static const str MI_HTTP_ESC_GT = str_init(">"); /* > */ +static const str MI_HTTP_ESC_AMP = str_init("&"); /* & */ +static const str MI_HTTP_ESC_QUOT = str_init("""); /* " */ +static const str MI_HTTP_ESC_SQUOT = str_init("'"); /* ' */ int mi_http_init_async_lock(void) @@ -328,9 +412,14 @@ int mi_http_parse_url(const char* url, int* mod, int* cmd) } -int mi_http_build_content(str *page, int max_page_len, +static int mi_http_recur_flush_tree(char** pointer, char *buf, int max_page_len, + struct mi_node *tree, int level); + +int mi_http_flush_content(str *page, int max_page_len, int mod, int cmd, struct mi_root* tree); + + int mi_http_flush_tree(void* param, struct mi_root *tree) { if (param==NULL) { @@ -338,7 +427,7 @@ int mi_http_flush_tree(void* param, struct mi_root *tree) return 0; } mi_http_html_page_data_t* html_p_data = (mi_http_html_page_data_t*)param; - mi_http_build_content(&html_p_data->page, + mi_http_flush_content(&html_p_data->page, html_p_data->buffer.len, html_p_data->mod, html_p_data->cmd, @@ -465,7 +554,7 @@ static inline struct mi_handler* mi_http_build_async_handler(int mod, int cmd) return hdl; } -struct mi_root* mi_http_run_mi_cmd(int mod, int cmd, const char* arg, +struct mi_root* mi_http_run_mi_cmd(int mod, int cmd, const str* arg, str *page, str *buffer, struct mi_handler **async_hdl) { struct mi_cmd *f; @@ -501,9 +590,9 @@ struct mi_root* mi_http_run_mi_cmd(int mod, int cmd, const char* arg, if (f->flags&MI_NO_INPUT_FLAG) { mi_cmd = NULL; } else { - if (arg) { - buf.s = (char*)arg; - buf.len = strlen(arg); + if (arg->s) { + buf.s = arg->s; + buf.len = arg->len; LM_DBG("start parsing [%d][%s]\n", buf.len, buf.s); mi_cmd = mi_http_parse_tree(&buf); if (mi_cmd==NULL) @@ -606,6 +695,8 @@ static inline int mi_http_write_node(char** pointer, char* buf, int max_page_len struct mi_node *node, int level) { struct mi_attr *attr; + int temp_counter; + str temp_holder; /* name and value */ if (node->name.s!=NULL) { @@ -615,16 +706,21 @@ static inline int mi_http_write_node(char** pointer, char* buf, int max_page_len MI_HTTP_COPY(*pointer,node->name); } if (node->value.s!=NULL) { - MI_HTTP_COPY_2(*pointer,MI_HTTP_NODE_SEPARATOR,node->value); + MI_HTTP_COPY(*pointer,MI_HTTP_NODE_SEPARATOR); + MI_HTTP_ESC_COPY(*pointer, node->value, + temp_holder, temp_counter); } /* attributes */ for(attr=node->attributes;attr!=NULL;attr=attr->next) { if (attr->name.s!=NULL) { - MI_HTTP_COPY_2(*pointer,MI_HTTP_ATTR_SEPARATOR,attr->name); - } - if (attr->value.s!=NULL) { - MI_HTTP_COPY_2(*pointer,MI_HTTP_ATTR_VAL_SEPARATOR, - attr->value); + MI_HTTP_COPY_3(*pointer, + MI_HTTP_ATTR_SEPARATOR, + attr->name, + MI_HTTP_ATTR_VAL_SEPARATOR); + if(attr->value.len) { + MI_HTTP_ESC_COPY(*pointer, attr->value, + temp_holder, temp_counter); + } } } MI_HTTP_COPY(*pointer,MI_HTTP_BREAK); @@ -636,7 +732,7 @@ static inline int mi_http_write_node(char** pointer, char* buf, int max_page_len } -static int mi_http_recur_write_tree(char** pointer, char *buf, int max_page_len, +static int mi_http_recur_flush_tree(char** pointer, char *buf, int max_page_len, struct mi_node *tree, int level) { struct mi_node *kid, *tmp; @@ -649,7 +745,7 @@ static int mi_http_recur_write_tree(char** pointer, char *buf, int max_page_len, return -1; kid->flags |= MI_WRITTEN; } - if ((ret = mi_http_recur_write_tree(pointer, buf, max_page_len, + if ((ret = mi_http_recur_flush_tree(pointer, buf, max_page_len, tree->kids, level+1))<0){ return -1; } else if (ret > 0) { @@ -675,8 +771,29 @@ static int mi_http_recur_write_tree(char** pointer, char *buf, int max_page_len, } +static int mi_http_recur_write_tree(char** pointer, char *buf, int max_page_len, + struct mi_node *tree, int level) +{ + for( ; tree ; tree=tree->next ) { + if (!(tree->flags & MI_WRITTEN)) { + if (mi_http_write_node(pointer, buf, max_page_len, + tree, level)!=0){ + return -1; + } + } + if (tree->kids) { + if (mi_http_recur_write_tree(pointer, buf, max_page_len, + tree->kids, level+1)<0){ + return -1; + } + } + } + return 0; +} + + int mi_http_build_header(str *page, int max_page_len, - int mod, int cmd, struct mi_root *tree) + int mod, int cmd, struct mi_root *tree, int flush) { int i, j; char *p, *buf; @@ -754,9 +871,15 @@ int mi_http_build_header(str *page, int max_page_len, MI_HTTP_CODE_1); tree->node.flags |= MI_WRITTEN; } - if (mi_http_recur_write_tree(&p, buf, max_page_len, - &tree->node, 0)<0) - return -1; + if (flush) { + if (mi_http_recur_flush_tree(&p, buf, max_page_len, + &tree->node, 0)<0) + return -1; + } else { + if (mi_http_recur_write_tree(&p, buf, max_page_len, + tree->node.kids, 0)<0) + return -1; + } } else if (mod>=0) { /* Building command menu */ /* Build the list of comands for the selected module */ MI_HTTP_COPY_4(p,MI_HTTP_Response_Menu_Cmd_Table_1, @@ -793,11 +916,13 @@ int mi_http_build_header(str *page, int max_page_len, MI_HTTP_Response_Menu_Cmd_td_4a); if (cmd>=0){ if (j==1) { - MI_HTTP_COPY_5(p, + MI_HTTP_COPY_7(p, MI_HTTP_Response_Menu_Cmd_td_1c, MI_HTTP_CMD_ROWSPAN, MI_HTTP_Response_Menu_Cmd_td_3c, MI_HTTP_Post_1, + MI_HTTP_METHOD[http_method], + MI_HTTP_Post_2, MI_HTTP_Response_Menu_Cmd_td_4c); } else if (j>MI_HTTP_ROWSPAN) { MI_HTTP_COPY_3(p, @@ -810,7 +935,7 @@ int mi_http_build_header(str *page, int max_page_len, } if (cmd>=0){ if (j==1) { - MI_HTTP_COPY_10(p,MI_HTTP_Response_Menu_Cmd_tr_1, + MI_HTTP_COPY_12(p,MI_HTTP_Response_Menu_Cmd_tr_1, MI_HTTP_Response_Menu_Cmd_td_1d, MI_HTTP_NBSP, MI_HTTP_Response_Menu_Cmd_td_4d, @@ -818,6 +943,8 @@ int mi_http_build_header(str *page, int max_page_len, MI_HTTP_CMD_ROWSPAN, MI_HTTP_Response_Menu_Cmd_td_3c, MI_HTTP_Post_1, + MI_HTTP_METHOD[http_method], + MI_HTTP_Post_2, MI_HTTP_Response_Menu_Cmd_td_4c, MI_HTTP_Response_Menu_Cmd_tr_2); j++; @@ -850,17 +977,19 @@ int mi_http_build_content(str *page, int max_page_len, { char *p, *buf; - if (page->len==0) - if (0!=mi_http_build_header(page, max_page_len, mod, cmd, tree)) + if (page->len==0) { + if (0!=mi_http_build_header(page, max_page_len, mod, cmd, tree, 0)) return -1; - buf = page->s; - p = page->s + page->len; + } else { + buf = page->s; + p = page->s + page->len; - if (tree) { /* Build mi reply */ - if (mi_http_recur_write_tree(&p, buf, max_page_len, - &tree->node, 0)<0) - return -1; - page->len = p - page->s; + if (tree) { /* Build mi reply */ + if (mi_http_recur_write_tree(&p, buf, max_page_len, + tree->node.kids, 0)<0) + return -1; + page->len = p - page->s; + } } return 0; } @@ -871,13 +1000,12 @@ int mi_http_build_page(str *page, int max_page_len, { char *p, *buf; - if (page->len==0) - if (0!=mi_http_build_content(page, max_page_len, mod, cmd, tree)) - return -1; + if (0!=mi_http_build_content(page, max_page_len, mod, cmd, tree)) + return -1; buf = page->s; p = page->s + page->len; - if (tree) { /* Build mi reply */ + if (tree) { /* Build foot reply */ MI_HTTP_COPY_5(p,MI_HTTP_CODE_2, MI_HTTP_Response_Menu_Cmd_td_4d, MI_HTTP_Response_Menu_Cmd_tr_2, @@ -893,3 +1021,23 @@ int mi_http_build_page(str *page, int max_page_len, return -1; } + +int mi_http_flush_content(str *page, int max_page_len, + int mod, int cmd, struct mi_root* tree) +{ + char *p, *buf; + + if (page->len==0) + if (0!=mi_http_build_header(page, max_page_len, mod, cmd, tree, 1)) + return -1; + buf = page->s; + p = page->s + page->len; + + if (tree) { /* Build mi reply */ + if (mi_http_recur_flush_tree(&p, buf, max_page_len, + &tree->node, 0)<0) + return -1; + page->len = p - page->s; + } + return 0; +} diff --git a/modules/mi_http/http_fnc.h b/modules/mi_http/http_fnc.h index f86a542e657..494be5075db 100644 --- a/modules/mi_http/http_fnc.h +++ b/modules/mi_http/http_fnc.h @@ -53,7 +53,7 @@ void mi_http_destroy_async_lock(void); int mi_http_init_cmds(void); int mi_http_parse_url(const char* url, int* mod, int* cmd); -struct mi_root* mi_http_run_mi_cmd(int mod, int cmd, const char* arg, +struct mi_root* mi_http_run_mi_cmd(int mod, int cmd, const str* arg, str *page, str *buffer, struct mi_handler **async_hdl); int mi_http_build_page(str* page, int max_page_len, int mod, int cmd, struct mi_root* tree); diff --git a/modules/mi_http/mi_http.c b/modules/mi_http/mi_http.c index 62b56a40552..32a099b8ce3 100644 --- a/modules/mi_http/mi_http.c +++ b/modules/mi_http/mi_http.c @@ -1,7 +1,7 @@ /* * $Id$ * - * Copyright (C) 2011-2012 VoIP Embedded Inc. + * Copyright (C) 2011-2013 VoIP Embedded Inc. * * This file is part of Open SIP Server (opensips). * @@ -47,6 +47,7 @@ void mi_http_answer_to_connection (void *cls, void *connection, static ssize_t mi_http_flush_data(void *cls, uint64_t pos, char *buf, size_t max); str http_root = str_init("mi"); +int http_method = 0; httpd_api_t httpd_api; @@ -61,15 +62,28 @@ static const str MI_HTTP_U_METHOD = str_init("" /* module parameters */ static param_export_t mi_params[] = { - {"mi_http_root", STR_PARAM, &http_root.s}, + {"mi_http_root", STR_PARAM, &http_root.s}, + {"mi_http_method", INT_PARAM, &http_method}, {0,0,0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "httpd", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /* module exports */ struct module_exports exports = { "mi_http", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ 0, /* exported functions */ mi_params, /* exported parameters */ 0, /* exported statistics */ @@ -100,6 +114,10 @@ static int mod_init(void) { http_root.len = strlen(http_root.s); + if (http_method<0 || http_method>1) { + LM_ERR("mi_http_method can be between [0,1]\n"); + return -1; + } /* Load httpd api */ if(load_httpd_api(&httpd_api)<0) { LM_ERR("Failed to load httpd api\n"); @@ -193,20 +211,20 @@ void mi_http_answer_to_connection (void *cls, void *connection, { int mod = -1; int cmd = -1; - const char *url_args; + str arg = {NULL, 0}; struct mi_root *tree = NULL; struct mi_handler *async_hdl; LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, " - "versio=%s, upload_data[%d]=%p, con_cls=%p\n", + "versio=%s, upload_data[%d]=%p, *con_cls=%p\n", cls, connection, url, method, version, - (int)*upload_data_size, upload_data, con_cls); - if (strncmp(method, "GET", 3)==0) { + (int)*upload_data_size, upload_data, *con_cls); + if (strncmp(method, "GET", 3)==0 || strncmp(method, "POST", 4)==0) { if(0 == mi_http_parse_url(url, &mod, &cmd)) { - url_args = httpd_api.lookup_arg(connection, "arg"); - LM_DBG("url_args [%p]->[%s]\n", url_args, url_args); - if (mod>=0 && cmd>=0 && url_args) { - tree = mi_http_run_mi_cmd(mod, cmd, url_args, + httpd_api.lookup_arg(connection, "arg", *con_cls, &arg); + if (mod>=0 && cmd>=0 && arg.s) { + LM_DBG("arg [%p]->[%.*s]\n", arg.s, arg.len, arg.s); + tree = mi_http_run_mi_cmd(mod, cmd, &arg, page, buffer, &async_hdl); if (tree == NULL) { LM_ERR("no reply\n"); @@ -220,9 +238,9 @@ void mi_http_answer_to_connection (void *cls, void *connection, if(0!=mi_http_build_page(page, buffer->len, mod, cmd, tree)){ LM_ERR("unable to build response " - "for cmd [%d] w/ args [%s]\n", + "for cmd [%d] w/ args [%.*s]\n", cmd, - url_args); + arg.len, arg.s); *page = MI_HTTP_U_ERROR; } } diff --git a/modules/mi_json/Makefile b/modules/mi_json/Makefile new file mode 100644 index 00000000000..cb8bc39a4f5 --- /dev/null +++ b/modules/mi_json/Makefile @@ -0,0 +1,8 @@ +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=mi_json.so +LIBS= + +include ../../Makefile.modules diff --git a/modules/mi_json/README b/modules/mi_json/README new file mode 100644 index 00000000000..2228d361724 --- /dev/null +++ b/modules/mi_json/README @@ -0,0 +1,125 @@ +mi_json Module + +Stephane Alnet + + + +Edited by + +Stephane Alnet + + Copyright © 2013 shimaore.net + Revision History + Revision $Rev$ $Date$ + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. Dependencies + + 1.2.1. External Libraries or Applications + 1.2.2. OpenSIPS Modules + + 1.3. Exported Parameters + + 1.3.1. mi_json_root(string) + + 1.4. Exported Functions + 1.5. Known issues + 1.6. Examples + + List of Examples + + 1.1. Set mi_json_root parameter + 1.2. JSON request + 1.3. JSON request + +Chapter 1. Admin Guide + +1.1. Overview + + This module implements a JSON server that handles GET requests + and generates JSON responses. + +1.2. Dependencies + +1.2.1. External Libraries or Applications + + None + +1.2.2. OpenSIPS Modules + + The following modules must be loaded before this module: + * httpd module. + +1.3. Exported Parameters + +1.3.1. mi_json_root(string) + + Specifies the root path for JSON requests: + http://[opensips_IP]:[opensips_httpd_port]/[mi_json_root] + + The default value is "json". + + Example 1.1. Set mi_json_root parameter +... +modparam("mi_json", "mi_json_root", "opensips_mi_json") +... + +1.4. Exported Functions + + No function exported to be used from configuration file. + +1.5. Known issues + + Commands with large responses (like ul_dump) will fail if the + configured size of the httpd buffer is to small (or if there + isn't enough pkg memory configured). + + Future realeases of the httpd and mi_json modules will address + this issue. + +1.6. Examples + + This is an example showing the JSON format for the + “get_statistics net: uri:” MI command. Notice how the + paramaters are comma-separated then URI-encoded. + + Example 1.2. JSON request + +GET /json/get_statistics?params=net%3A%2Curi%3A HTTP/1.1 +Accept: application/json +Host: example.net + +HTTP/1.1 200 OK +Content-Length: 49 +Content-Type: application/json +Date: Fri, 01 Nov 2013 12:00:00 GMT + +["net:waiting_udp = 0", "net:waiting_tcp = 0", "uri:positive checks = 0" +, "uri:negative_checks = 0"] + + + Here is another example showing the JSON format for the “ps” MI + command. + + Example 1.3. JSON request + +GET /json/ps HTTP/1.1 +Accept: application/json +Host: example.net + +HTTP/1.1 200 OK +Content-Length: 428 +Content-Type: application/json +Date: Fri, 01 Nov 2013 12:00:00 GMT + +[{"name":"Process", "value":null, "attributes":{"ID": "0", "PID": "7400" +, "Type": "stand-alone SIP receiver udp:127.0.0.1:5060"}}, {"name":"Proc +ess", "value":null, "attributes":{"ID": "1", "PID": "7402", "Type": "HTT +PD INADDR_ANY:8888"}}, {"name":"Process", "value":null, "attributes":{"I +D": "2", "PID": "7403", "Type": "time_keeper"}}, {"name":"Process", "val +ue":null, "attributes":{"ID": "3", "PID": "7404", "Type": "timer"}}] diff --git a/modules/mi_json/doc/mi_json.xml b/modules/mi_json/doc/mi_json.xml new file mode 100644 index 00000000000..ffe1842491d --- /dev/null +++ b/modules/mi_json/doc/mi_json.xml @@ -0,0 +1,49 @@ + + + + + + +%docentities; + +]> + + + + mi_json Module + &osipsname; + + + Stephane + Alnet + stephane@shimaore.net + + + Stephane + Alnet + + + + 2013 + + shimaore.net + + + + + $Rev$ + $Date$ + + + + + + &admin; + &faq; + + + + diff --git a/modules/mi_json/doc/mi_json_admin.xml b/modules/mi_json/doc/mi_json_admin.xml new file mode 100644 index 00000000000..4d1d3e32fbb --- /dev/null +++ b/modules/mi_json/doc/mi_json_admin.xml @@ -0,0 +1,125 @@ + + + + + &adminguide; + +
+ Overview + + This module implements a JSON server that handles GET + requests and generates JSON responses. + +
+ +
+ Dependencies +
+ External Libraries or Applications + None + +
+
+ &osips; Modules + + The following modules must be loaded before this module: + + + httpd module. + + + +
+
+ +
+ Exported Parameters +
+ <varname>mi_json_root</varname>(string) + + Specifies the root path for JSON requests: + http://[opensips_IP]:[opensips_httpd_port]/[mi_json_root] + + + The default value is "json". + + + Set <varname>mi_json_root</varname> parameter + +... +modparam("mi_json", "mi_json_root", "opensips_mi_json") +... + + +
+
+ +
+ Exported Functions + + No function exported to be used from configuration file. + +
+ +
+ Known issues + + Commands with large responses (like ul_dump) will fail if the + configured size of the httpd buffer is to small (or if there + isn't enough pkg memory configured). + + + Future realeases of the httpd and mi_json modules + will address this issue. + +
+ +
+ Examples + + This is an example showing the JSON format for the + get_statistics net: uri: MI command. + Notice how the paramaters are comma-separated then URI-encoded. + + + JSON request + + + + + + Here is another example showing the JSON format for the + ps MI command. + + + JSON request + + + + +
+ +
+ diff --git a/modules/mi_json/http_fnc.c b/modules/mi_json/http_fnc.c new file mode 100644 index 00000000000..49e59ed5afb --- /dev/null +++ b/modules/mi_json/http_fnc.c @@ -0,0 +1,696 @@ +/* + * This file is part of Open SIP Server (opensips). + * + * opensips is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * History: + * --------- + * 2013-10-31 first version (shimaore) + */ + + +#include "../../str.h" +#include "../../ut.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../../mi/mi.h" +#include "../../config.h" +#include "../../globals.h" +#include "../../locking.h" + +#include "http_fnc.h" + +extern str http_root; + +mi_json_page_data_t html_page_data; + +gen_lock_t* mi_json_lock; + +struct page_buf { + char *current; + char *buf; + int max_page_len; + short status; +}; + +static inline void MI_JSON_COPY(struct page_buf* pb, const str s) { + if ( pb->status ) { + return; + } + if ( s.s == NULL || s.len == 0 ) { + return; + } + if ( (int)(pb->current - pb->buf) + s.len > pb->max_page_len) { + pb->status = -1; + } else { + memcpy(pb->current, s.s, s.len); + pb->current += s.len; + } +} + +static const str MI_JSON_ESC = str_init("\\"); + +static inline void MI_JSON_ESC_COPY(struct page_buf* pb, const str s) { + str temp_holder; + int temp_counter; + if( pb->status ) { + return; + } + if( s.s == NULL || s.len == 0 ) { + return; + } + temp_holder.s = s.s; + temp_holder.len = 0; + for(temp_counter=0;temp_counterpage, + html_p_data->buffer.len, + tree); + return 0; +} + + +static void mi_json_close_async(struct mi_root *mi_rpl, struct mi_handler *hdl, int done) +{ + struct mi_root *shm_rpl = NULL; + gen_lock_t* lock; + mi_json_async_resp_data_t *async_resp_data; + + if (hdl==NULL) { + LM_CRIT("null mi handler\n"); + return; + } + + LM_DBG("mi_root [%p], hdl [%p], hdl->param [%p], " + "*hdl->param [%p] and done [%u]\n", + mi_rpl, hdl, hdl->param, *(struct mi_root **)hdl->param, done); + + if (!done) { + /* we do not pass provisional stuff (yet) */ + if (mi_rpl) free_mi_tree( mi_rpl ); + return; + } + + async_resp_data = + (mi_json_async_resp_data_t*)((char*)hdl+sizeof(struct mi_handler)); + lock = async_resp_data->lock; + lock_get(lock); + if (mi_rpl!=NULL && (shm_rpl=clone_mi_tree( mi_rpl, 1))!=NULL) { + *(struct mi_root **)hdl->param = shm_rpl; + } else { + LM_WARN("Unable to process async reply [%p]\n", mi_rpl); + /* mark it as invalid */ + hdl->param = NULL; + } + LM_DBG("shm_rpl [%p], hdl [%p], hdl->param [%p], *hdl->param [%p]\n", + shm_rpl, hdl, hdl->param, + (hdl->param)?*(struct mi_root **)hdl->param:NULL); + lock_release(lock); + + if (mi_rpl) free_mi_tree(mi_rpl); + + return; +} + +static inline struct mi_handler* mi_json_build_async_handler(void) +{ + struct mi_handler *hdl; + mi_json_async_resp_data_t *async_resp_data; + unsigned int len; + + len = sizeof(struct mi_handler)+sizeof(mi_json_async_resp_data_t); + hdl = (struct mi_handler*)shm_malloc(len); + if (hdl==NULL) { + LM_ERR("oom\n"); + return NULL; + } + + memset(hdl, 0, len); + async_resp_data = + (mi_json_async_resp_data_t*)((char*)hdl+sizeof(struct mi_handler)); + + hdl->handler_f = mi_json_close_async; + hdl->param = (void*)&async_resp_data->tree; + + async_resp_data->lock = mi_json_lock; + + LM_DBG("hdl [%p], hdl->param [%p], *hdl->param [%p] mi_json_lock=[%p]\n", + hdl, hdl->param, (hdl->param)?*(struct mi_root **)hdl->param:NULL, + async_resp_data->lock); + + return hdl; +} + +struct mi_root* mi_json_run_mi_cmd(struct mi_cmd *f, const str* miCmd, + const str* params, str *page, str *buffer, struct mi_handler **async_hdl) +{ + struct mi_node *node; + struct mi_root *mi_cmd; + struct mi_root *mi_rpl; + struct mi_handler *hdl; + str val; + int i, j; + + LM_DBG("got command=%.*s\n", miCmd->len, miCmd->s); + + if (f->flags&MI_ASYNC_RPL_FLAG) { + LM_DBG("command=%.*s is async\n", miCmd->len, miCmd->s); + /* We need to build an async handler */ + hdl = mi_json_build_async_handler(); + if (hdl==NULL) { + LM_ERR("failed to build async handler\n"); + goto error; + } + } else { + hdl = NULL; + } + *async_hdl = hdl; + + if (f->flags&MI_NO_INPUT_FLAG) { + LM_DBG("command=%.*s requires no parameters\n", miCmd->len, miCmd->s); + mi_cmd = NULL; + } else { + LM_DBG("command=%.*s accepts parameters\n", miCmd->len, miCmd->s); + if (params->s) { + mi_cmd = init_mi_tree(0,0,0); + if (mi_cmd==NULL) { + LM_ERR("the MI tree cannot be initialized!\n"); + goto error; + } + i = 0; + j = 0; + for( i = 0; i < params->len; i++ ) { + if (params->s[i] == ',') { + val.s = params->s + j; + val.len = i-j; + LM_DBG("got string param [%.*s]\n", val.len, val.s); + node = &mi_cmd->node; + if(!add_mi_node_child(node,0,NULL,0,val.s,val.len)){ + LM_ERR("cannot add the child node to the tree\n"); + free_mi_tree(mi_cmd); + goto error; + } + j = i+1; + } + } + if( j < params->len ) { + val.s = params->s + j; + val.len = params->len-j; + LM_DBG("got string param [%.*s]\n", val.len, val.s); + node = &mi_cmd->node; + if(!add_mi_node_child(node,0,NULL,0,val.s,val.len)){ + LM_ERR("cannot add the child node to the tree\n"); + free_mi_tree(mi_cmd); + goto error; + } + } + mi_cmd->async_hdl = hdl; + } else { + LM_DBG("but no parameters were found\n"); + mi_cmd = init_mi_tree(0,0,0); + if (mi_cmd==NULL) { + LM_ERR("the MI tree cannot be initialized!\n"); + goto error; + } + } + } + + html_page_data.page.s = buffer->s; + html_page_data.page.len = 0; + html_page_data.buffer.s = buffer->s; + html_page_data.buffer.len = buffer->len; + + /* FIXME: find a proper way for handling flushing */ + mi_rpl = run_mi_cmd(f, mi_cmd, + NULL, &html_page_data); + if (mi_rpl == NULL) { + LM_ERR("failed to process the command\n"); + if (mi_cmd) free_mi_tree(mi_cmd); + goto error; + } else if (mi_rpl != MI_ROOT_ASYNC_RPL) { + *page = html_page_data.page; + } + LM_DBG("got mi_rpl=[%p]\n",mi_rpl); + + if (mi_cmd) free_mi_tree(mi_cmd); + return mi_rpl; + +error: + return NULL; +} + + +static inline int mi_json_write_node_array(struct page_buf* pb, + struct mi_node *node) +{ + LM_DBG("start\n"); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, node->value); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + + node->flags |= MI_WRITTEN; + return pb->status; +} +static inline int mi_json_write_node_hash(struct page_buf* pb, + struct mi_node *node) +{ + LM_DBG("start\n"); + + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, node->name); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_COPY(pb, MI_JSON_COLON); + if (node->value.s!=NULL) { + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, node->value); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + } else { + MI_JSON_COPY(pb, MI_JSON_NULL); + } + + node->flags |= MI_WRITTEN; + return pb->status; +} + +static inline int mi_json_write_node(struct page_buf* pb, + struct mi_node *node) +{ + struct mi_attr *attr; + LM_DBG("start\n"); + + /* name */ + MI_JSON_COPY(pb, MI_JSON_KEY_NAME); + if (node->name.s!=NULL) { + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, node->name); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + } else { + MI_JSON_COPY(pb, MI_JSON_NULL); + } + MI_JSON_COPY(pb, MI_JSON_COMMA); + + /* value */ + MI_JSON_COPY(pb, MI_JSON_KEY_VALUE); + if (node->value.s!=NULL) { + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, node->value); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + } else { + MI_JSON_COPY(pb, MI_JSON_NULL); + } + MI_JSON_COPY(pb, MI_JSON_COMMA); + + /* attributes */ + MI_JSON_COPY(pb, MI_JSON_KEY_ATTRIBUTES); + MI_JSON_COPY(pb, MI_JSON_OBJECT_START); + for(attr=node->attributes;attr!=NULL;attr=attr->next) { + if (attr->name.s!=NULL) { + /* attribute name */ + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, attr->name); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_COPY(pb, MI_JSON_COLON); + + /* attribute value */ + if (attr->value.s!=NULL) { + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, attr->value); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + } else { + MI_JSON_COPY(pb, MI_JSON_NULL); + } + } + if (attr->next!=NULL) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + } + } + MI_JSON_COPY(pb, MI_JSON_OBJECT_STOP); + + return pb->status; +} + +/* sync case */ +#if 0 +static int mi_json_recur_write_tree(struct page_buf* pb, + struct mi_node *tree, unsigned int flags) +{ + int names = 0; + int values = 0; + int attributes = 0; + int kids = 0; + struct mi_node* t; + LM_DBG("start\n"); + for( t = tree; t ; t=t->next ) { + if(t->name.s) { + names++; + } + if(t->value.s) { + values++; + } + if(t->attributes) { + attributes++; + } + if(t->kids) { + kids++; + } + } + + if(names == 0 && values > 0 && attributes == 0 && kids == 0) { + LM_DBG("Treat as an array\n"); + /* Treat as an array */ + MI_JSON_COPY(pb, MI_JSON_ARRAY_START); + for( t = tree; t; t=t->next ) { + mi_json_write_node_array(pb,t); + t->flags |= MI_WRITTEN; + if(t->next) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + } + } + MI_JSON_COPY(pb, MI_JSON_ARRAY_STOP); + LM_DBG("done\n"); + return 0; + } + if(names >= values && attributes == 0 && kids == 0) { + LM_DBG("Treat as a hash\n"); + /* Treat as a hash */ + MI_JSON_COPY(pb, MI_JSON_OBJECT_START); + for( t = tree; t; t=t->next ) { + LM_DBG("t = %p\n",t); + mi_json_write_node_hash(pb,t); + t->flags |= MI_WRITTEN; + if(t->next) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + } + } + MI_JSON_COPY(pb, MI_JSON_OBJECT_STOP); + LM_DBG("done\n"); + return 0; + } + if(names == 0 && values == 0 && attributes == 0 && kids > 0) { + LM_DBG("Treat as an array of objects\n"); + /* Treat as an array of objects */ + MI_JSON_COPY(pb, MI_JSON_ARRAY_START); + for( t = tree; t; t=t->next ) { + mi_json_recur_write_tree(pb,t->kids, t->flags); + t->flags |= MI_WRITTEN; + if(t->next) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + } + } + MI_JSON_COPY(pb, MI_JSON_ARRAY_STOP); + LM_DBG("done\n"); + return 0; + } + + /* Otherwise */ + LM_DBG("Treat as a complex array of hashes\n"); + /* Treat as a complex array of hashes */ + MI_JSON_COPY(pb, MI_JSON_ARRAY_START); + for( t = tree; t; t=t->next ) { + MI_JSON_COPY(pb, MI_JSON_OBJECT_START); + mi_json_write_node(pb,t); + if (t->kids) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + MI_JSON_COPY(pb, MI_JSON_KEY_CHILDREN); + mi_json_recur_write_tree(pb, t->kids, t->flags); + } + MI_JSON_COPY(pb, MI_JSON_OBJECT_STOP); + if(t->next) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + } + } + MI_JSON_COPY(pb, MI_JSON_ARRAY_STOP); + LM_DBG("done\n"); + return pb->status; +} +#endif + +static void mi_json_recur_write_node(struct page_buf* pb, struct mi_node *node, + int dump_name) +{ + struct mi_attr *attr; + int first = 1; + + /* if we only have name and value, then dump it like hash */ + if (dump_name && node->name.s && node->value.s && !node->attributes && !node->kids) { + mi_json_write_node_hash(pb, node); + return; + } + + if (dump_name && node->name.s) { + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, node->name); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_COPY(pb, MI_JSON_COLON); + MI_JSON_COPY(pb, MI_JSON_OBJECT_START); + } + + /* value */ + if (node->value.s) { + MI_JSON_COPY(pb, MI_JSON_KEY_VALUE); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, node->value); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + first = 0; + } + + /* attributes */ + if (node->attributes) { + if (!first) + MI_JSON_COPY(pb, MI_JSON_COMMA); + + MI_JSON_COPY(pb, MI_JSON_KEY_ATTRIBUTES); + MI_JSON_COPY(pb, MI_JSON_OBJECT_START); + for(attr=node->attributes;attr!=NULL;attr=attr->next) { + if (attr->name.s!=NULL) { + /* attribute name */ + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, attr->name); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_COPY(pb, MI_JSON_COLON); + + /* attribute value */ + if (attr->value.s!=NULL) { + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_ESC_COPY(pb, attr->value); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + } else { + MI_JSON_COPY(pb, MI_JSON_NULL); + } + } + if (attr->next!=NULL) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + } + } + MI_JSON_COPY(pb, MI_JSON_OBJECT_STOP); + first = 0; + } + + /* kids */ + if (node->kids) { + if (!first) + MI_JSON_COPY(pb, MI_JSON_COMMA); + MI_JSON_COPY(pb, MI_JSON_KEY_CHILDREN); + mi_json_recur_write_tree(pb, node->kids, node->flags); + } + + if (dump_name && node->name.s) { + MI_JSON_COPY(pb, MI_JSON_OBJECT_STOP); + } +} + +static int mi_json_recur_write_tree(struct page_buf* pb, + struct mi_node *tree, unsigned int flags) +{ + struct mi_node* t; + if (!tree) + return pb->status; + + + if (flags & MI_IS_ARRAY) { + LM_DBG("Treat as an array\n"); + MI_JSON_COPY(pb, MI_JSON_OBJECT_START); + MI_JSON_COPY(pb, MI_JSON_SQUOT); + if (tree->name.s) { + MI_JSON_ESC_COPY(pb, tree->name); + } + MI_JSON_COPY(pb, MI_JSON_SQUOT); + MI_JSON_COPY(pb, MI_JSON_COLON); + MI_JSON_COPY(pb, MI_JSON_ARRAY_START); + for( t = tree; t; t=t->next ) { + MI_JSON_COPY(pb, MI_JSON_OBJECT_START); + mi_json_recur_write_node(pb,t,0); + MI_JSON_COPY(pb, MI_JSON_OBJECT_STOP); + t->flags |= MI_WRITTEN; + if(t->next) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + } + } + MI_JSON_COPY(pb, MI_JSON_ARRAY_STOP); + MI_JSON_COPY(pb, MI_JSON_OBJECT_STOP); + } else { + LM_DBG("Treat as a hash\n"); + MI_JSON_COPY(pb, MI_JSON_OBJECT_START); + for( t = tree; t; t=t->next ) { + mi_json_recur_write_node(pb,t,1); + t->flags |= MI_WRITTEN; + if(t->next) { + MI_JSON_COPY(pb, MI_JSON_COMMA); + } + } + MI_JSON_COPY(pb, MI_JSON_OBJECT_STOP); + } + LM_DBG("done\n"); + return pb->status; +} + + +int mi_json_build_content(str *page, int max_page_len, + struct mi_root* tree) +{ + struct page_buf pb; + LM_DBG("start\n"); + + pb.buf = page->s; + pb.current = page->s + page->len; + pb.max_page_len = max_page_len; + pb.status = 0; + + if (tree) { /* Build mi reply */ + mi_json_recur_write_tree(&pb, tree->node.kids, tree->node.flags); + page->len = pb.current - page->s; + } + LM_DBG("done\n"); + return pb.status; +} + + +int mi_json_build_page(str *page, int max_page_len, + struct mi_root *tree) +{ + LM_DBG("start\n"); + return mi_json_build_content(page, max_page_len, tree); +} + + +/* async case */ +static int mi_json_recur_flush_tree(struct page_buf* pb, + struct mi_node *tree) +{ + struct mi_node *kid; + LM_DBG("start\n"); + + for(kid = tree->kids ; kid ; ){ + if (kid->flags & MI_NOT_COMPLETED) { + return 1; + } + } + + mi_json_recur_write_tree(pb,tree,0); + LM_DBG("done\n"); + return pb->status; +} + +int mi_json_flush_content(str *page, int max_page_len, + struct mi_root* tree) +{ + struct page_buf pb; + LM_DBG("start\n"); + pb.buf = page->s; + pb.current = page->s + page->len; + pb.max_page_len = max_page_len; + pb.status = 0; + + if (tree) { /* Build mi reply */ + mi_json_recur_flush_tree(&pb, &tree->node); + page->len = pb.current - page->s; + } + LM_DBG("done\n"); + return pb.status; +} diff --git a/modules/mi_json/http_fnc.h b/modules/mi_json/http_fnc.h new file mode 100644 index 00000000000..44e5b297d6c --- /dev/null +++ b/modules/mi_json/http_fnc.h @@ -0,0 +1,47 @@ +/* + * This file is part of Open SIP Server (opensips). + * + * opensips is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * History: + * --------- + * 2013-03-04 first version (osas) + */ + + +#ifndef _MI_JSON_HTTP_FNC_H +#define _MI_JSON_HTTP_FNC_H + + +typedef struct mi_json_html_page_data_ { + str page; + str buffer; +}mi_json_page_data_t; + +typedef struct mi_json_async_resp_data_ { + gen_lock_t* lock; + struct mi_root* tree; +}mi_json_async_resp_data_t; + + +int mi_json_init_async_lock(void); +void mi_json_destroy_async_lock(void); + +struct mi_root* mi_json_run_mi_cmd(struct mi_cmd *f, const str* command, + const str* params, str *page, str *buffer, struct mi_handler **async_hdl); +int mi_json_build_page(str* page, int max_page_len, + struct mi_root* tree); + +#endif diff --git a/modules/mi_json/mi_json.c b/modules/mi_json/mi_json.c new file mode 100644 index 00000000000..3dc73dcc93b --- /dev/null +++ b/modules/mi_json/mi_json.c @@ -0,0 +1,251 @@ +/* + * This file is part of Open SIP Server (opensips). + * + * opensips is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * History: + * --------- + * 2013-03-04 first version (osas) + */ + +#include + +#include "../../globals.h" +#include "../../sr_module.h" +#include "../../str.h" +#include "../../ut.h" +#include "../../resolve.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../httpd/httpd_load.h" +#include "http_fnc.h" + +/* module functions */ +static int mod_init(); +static int destroy(void); +void mi_json_answer_to_connection (void *cls, void *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **con_cls, + str *buffer, str *page); +static ssize_t mi_json_flush_data(void *cls, uint64_t pos, char *buf, size_t max); + +str http_root = str_init("json"); +httpd_api_t httpd_api; + + +static const str MI_HTTP_U_ERROR = str_init("{\"error\":" +"\"Internal server error\"}"); +static const str MI_HTTP_U_METHOD = str_init("{\"error\":" +"\"Unexpected method\"}"); +static const str MI_HTTP_U_NOT_FOUND = str_init("{\"error\":" +"\"Command not found\"}"); + + +/* module parameters */ +static param_export_t mi_params[] = { + {"mi_json_root", STR_PARAM, &http_root.s}, + {0,0,0} +}; + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "httpd", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + +/* module exports */ +struct module_exports exports = { + "mi_json", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ + MODULE_VERSION, + DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ + NULL, /* exported functions */ + mi_params, /* exported parameters */ + NULL, /* exported statistics */ + NULL, /* exported MI functions */ + NULL, /* exported PV */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + (response_function) 0, /* response handling function */ + (destroy_function) destroy, /* destroy function */ + NULL /* per-child init function */ +}; + + +void proc_init(void) +{ + /* Build async lock */ + if (mi_json_init_async_lock() != 0) + exit(-1); + + return; +} + +static int mod_init(void) +{ + http_root.len = strlen(http_root.s); + + /* Load httpd api */ + if(load_httpd_api(&httpd_api)<0) { + LM_ERR("Failed to load httpd api\n"); + return -1; + } + /* Load httpd hooks */ + httpd_api.register_httpdcb(exports.name, &http_root, + &mi_json_answer_to_connection, + &mi_json_flush_data, + &proc_init); + + return 0; +} + + +int destroy(void) +{ + mi_json_destroy_async_lock(); + return 0; +} + + + +static ssize_t mi_json_flush_data(void *cls, uint64_t pos, char *buf, size_t max) +{ + struct mi_handler *hdl = (struct mi_handler*)cls; + gen_lock_t *lock; + mi_json_async_resp_data_t *async_resp_data; + str page = {NULL, 0}; + + if (hdl==NULL) { + LM_ERR("Unexpected NULL mi handler!\n"); + return -1; + } + LM_DBG("hdl=[%p], hdl->param=[%p], pos=[%d], buf=[%p], max=[%d]\n", + hdl, hdl->param, (int)pos, buf, (int)max); + + if (pos){ + LM_DBG("freeing hdl=[%p]: hdl->param=[%p], " + " pos=[%d], buf=[%p], max=[%d]\n", + hdl, hdl->param, (int)pos, buf, (int)max); + shm_free(hdl); + return -1; + } + async_resp_data = + (mi_json_async_resp_data_t*)((char*)hdl+sizeof(struct mi_handler)); + lock = async_resp_data->lock; + lock_get(lock); + if (hdl->param) { + if (*(struct mi_root**)hdl->param) { + page.s = buf; + LM_DBG("tree=[%p]\n", *(struct mi_root**)hdl->param); + if (mi_json_build_page(&page, max, + *(struct mi_root**)hdl->param)!=0){ + LM_ERR("Unable to build response\n"); + shm_free(*(void**)hdl->param); + *(void**)hdl->param = NULL; + lock_release(lock); + memcpy(buf, MI_HTTP_U_ERROR.s, MI_HTTP_U_ERROR.len); + return MI_HTTP_U_ERROR.len; + } else { + shm_free(*(void**)hdl->param); + *(void**)hdl->param = NULL; + lock_release(lock); + return page.len; + } + } else { + LM_DBG("data not ready yet\n"); + lock_release(lock); + return 0; + } + } else { + lock_release(lock); + LM_ERR("Invalid async reply\n"); + memcpy(buf, MI_HTTP_U_ERROR.s, MI_HTTP_U_ERROR.len); + return MI_HTTP_U_ERROR.len; + } + lock_release(lock); + LM_CRIT("done?\n"); + shm_free(hdl); + return -1; +} + +void mi_json_answer_to_connection (void *cls, void *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **con_cls, + str *buffer, str *page) +{ + str command = {NULL, 0}; + str params = {NULL, 0}; + struct mi_cmd *f = NULL; + struct mi_root *tree = NULL; + struct mi_handler *async_hdl; + + LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, " + "versio=%s, upload_data[%d]=%p, *con_cls=%p\n", + cls, connection, url, method, version, + (int)*upload_data_size, upload_data, *con_cls); + if (strncmp(method, "GET", 3)==0) { + if(url && url[0] == '/' && url[1] != '\0') { + command.s = (char*)url+1; + command.len = strlen(command.s); + } + httpd_api.lookup_arg(connection, "params", *con_cls, ¶ms); + if (command.s) { + + f = lookup_mi_cmd(command.s, command.len); + if (f == NULL) { + LM_ERR("unable to find mi command [%.*s]\n", command.len, command.s); + *page = MI_HTTP_U_NOT_FOUND; + } else { + + tree = mi_json_run_mi_cmd(f, &command,¶ms, + page, buffer, &async_hdl); + if (tree == NULL) { + LM_ERR("no reply\n"); + *page = MI_HTTP_U_ERROR; + } else if (tree == MI_ROOT_ASYNC_RPL) { + LM_DBG("got an async reply\n"); + tree = NULL; + } else { + LM_DBG("building on page [%p:%d]\n", + page->s, page->len); + if(0!=mi_json_build_page(page, buffer->len, tree)){ + LM_ERR("unable to build response\n"); + *page = MI_HTTP_U_ERROR; + } + } + } + } else { + page->s = buffer->s; + LM_ERR("unable to build response for empty request\n"); + *page = MI_HTTP_U_ERROR; + } + if (tree) { + free_mi_tree(tree); + tree = NULL; + } + } else { + LM_ERR("unexpected method [%s]\n", method); + *page = MI_HTTP_U_METHOD; + } + + return; +} diff --git a/modules/mi_xmlrpc/README b/modules/mi_xmlrpc/README index 6b859f6ce1a..3b1ed29ad25 100644 --- a/modules/mi_xmlrpc/README +++ b/modules/mi_xmlrpc/README @@ -2,8 +2,6 @@ mi_xmlrpc Module Lavinia-Andreea Andrei - Voice Sistem SRL - Edited by Lavinia-Andreea Andrei @@ -14,8 +12,7 @@ Juha Heinanen Copyright © 2006 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/mi_xmlrpc/abyss.h b/modules/mi_xmlrpc/abyss.h index 87fc405511e..275c65f7168 100644 --- a/modules/mi_xmlrpc/abyss.h +++ b/modules/mi_xmlrpc/abyss.h @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -198,7 +198,7 @@ bool ListFindString(TList *sl,char *str,uint16 *index); ** Table *********************************************************************/ -typedef struct +typedef struct { char *name,*value; uint16 hash; @@ -371,10 +371,10 @@ uint32 SocketAvailableReadBytes(TSocket *s); #ifdef ABYSS_WIN32 #ifndef __BORLANDC__ #define O_APPEND _O_APPEND -#define O_CREAT _O_CREAT +#define O_CREAT _O_CREAT #define O_EXCL _O_EXCL #define O_RDONLY _O_RDONLY -#define O_RDWR _O_RDWR +#define O_RDWR _O_RDWR #define O_TRUNC _O_TRUNC #define O_WRONLY _O_WRONLY #define O_TEXT _O_TEXT @@ -427,7 +427,7 @@ typedef struct finddata_t time_t time_write; } TFileInfo; -typedef struct +typedef struct { char path[NAME_MAX+1]; DIR *handle; @@ -474,7 +474,7 @@ typedef struct uid_t uid; gid_t gid; TFile pidfile; -#endif +#endif } TServer; @@ -482,13 +482,13 @@ typedef struct ** Conn *********************************************************************/ -#define BUFFER_SIZE 4096 +#define BUFFER_SIZE 4096 typedef struct _TConn { TServer *server; uint32 buffersize,bufferpos; - uint32 inbytes,outbytes; + uint32 inbytes,outbytes; TSocket socket; TIPAddr peerip; TThread thread; diff --git a/modules/mi_xmlrpc/abyss_conf.c b/modules/mi_xmlrpc/abyss_conf.c index 667079e8580..b3830ef340c 100644 --- a/modules/mi_xmlrpc/abyss_conf.c +++ b/modules/mi_xmlrpc/abyss_conf.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -197,7 +197,7 @@ readMIMETypesFile(const char * const filename, while (ConfReadLine(&file, z, 512)) { char * p; p = &z[0]; - + if (ConfNextToken(&p)) { const char * mimetype = ConfGetToken(&p); if (mimetype) { @@ -233,7 +233,7 @@ readMIMETypesFile(const char * const filename, static void chdirx(const char * const newdir, abyss_bool * const successP) { - + #if defined(WIN32) && !defined(__BORLANDC__) *successP = _chdir(newdir) == 0; #else @@ -244,12 +244,12 @@ chdirx(const char * const newdir, static void -parseUser(const char * const p, +parseUser(const char * const p, struct _TServer * const srvP) { #ifdef _UNIX if (p[0] == '#') { int32_t n; - + if (!ConfReadInt(&p[1], &n, 0, 0)) TraceExit("Bad user number '%s'", p); else @@ -259,14 +259,14 @@ parseUser(const char * const p, if (!(pwd = getpwnam(p))) TraceExit("Unknown user '%s'", p); - + srvP->uid = pwd->pw_uid; if ((int)srvP->gid==(-1)) srvP->gid = pwd->pw_gid; }; #else TraceMsg("User option ignored"); -#endif /* _UNIX */ +#endif /* _UNIX */ } @@ -281,7 +281,7 @@ parsePidfile(const char * const p, }; #else TraceMsg("PidFile option ignored"); -#endif /* _UNIX */ +#endif /* _UNIX */ } @@ -333,7 +333,7 @@ ConfReadServerFile(const char * const filename, TraceExit("Invalid path '%s'", p); } else if (strcasecmp(option, "default") == 0) { const char * filename; - + while ((filename = ConfGetToken(&p))) { ListAdd(&srvP->defaultfilenames, strdup(filename)); if (!ConfNextToken(&p)) diff --git a/modules/mi_xmlrpc/abyss_conn.c b/modules/mi_xmlrpc/abyss_conn.c index 7afaca06d61..d2ff13170c0 100644 --- a/modules/mi_xmlrpc/abyss_conn.c +++ b/modules/mi_xmlrpc/abyss_conn.c @@ -65,7 +65,7 @@ static void threadDone(void * const userHandle) { TConn * const connectionP = userHandle; - + connDone(connectionP); } @@ -76,7 +76,7 @@ makeThread(TConn * const connectionP, enum abyss_foreback const foregroundBackground, abyss_bool const useSigchld, const char ** const errorP) { - + switch (foregroundBackground) { case ABYSS_FOREGROUND: connectionP->hasOwnThread = FALSE; @@ -98,7 +98,7 @@ makeThread(TConn * const connectionP, } /* switch */ } - + void ConnCreate(TConn ** const connectionPP, @@ -202,7 +202,7 @@ void ConnWaitAndRelease(TConn * const connectionP) { if (connectionP->hasOwnThread) ThreadWaitAndRelease(connectionP->threadP); - + free(connectionP); } @@ -239,17 +239,17 @@ traceBuffer(const char * const label, unsigned int nonPrintableCount; unsigned int i; - + nonPrintableCount = 0; /* Initial value */ - + for (i = 0; i < size; ++i) { if (!isprint(buffer[i]) && buffer[i] != '\n' && buffer[i] != '\r') ++nonPrintableCount; } if (nonPrintableCount > 0) - fprintf(stderr, "%s contains %u nonprintable characters.\n", + fprintf(stderr, "%s contains %u nonprintable characters.\n", label, nonPrintableCount); - + fprintf(stderr, "%s:\n", label); fprintf(stderr, "%.*s\n", (int)size, buffer); } @@ -284,10 +284,10 @@ traceSocketWrite(TConn * const connectionP, static uint32_t bufferSpace(TConn * const connectionP) { - + return BUFFER_SIZE - connectionP->buffersize; } - + abyss_bool @@ -306,7 +306,7 @@ ConnRead(TConn * const connectionP, cantGetData = FALSE; gotData = FALSE; - + while (!gotData && !cantGetData) { int const timeLeft = deadline - time(NULL); @@ -314,17 +314,17 @@ ConnRead(TConn * const connectionP, cantGetData = TRUE; else { int rc; - + rc = SocketWait(connectionP->socketP, TRUE, FALSE, timeLeft * 1000); - + if (rc != 1) cantGetData = TRUE; else { uint32_t bytesAvail; - + bytesAvail = SocketAvailableReadBytes(connectionP->socketP); - + if (bytesAvail <= 0) cantGetData = TRUE; else { @@ -355,7 +355,7 @@ ConnRead(TConn * const connectionP, } - + abyss_bool ConnWrite(TConn * const connectionP, const void * const buffer, @@ -421,12 +421,12 @@ ConnWriteFromFile(TConn * const connectionP, bytesReadThisTime = FileRead(fileP, buffer, bytesToRead); bytesread += bytesReadThisTime; - + if (bytesReadThisTime > 0) ConnWrite(connectionP, buffer, bytesReadThisTime); else break; - + if (waittime > 0) xmlrpc_millisecond_sleep(waittime); } @@ -440,7 +440,7 @@ ConnWriteFromFile(TConn * const connectionP, static void processHeaderLine(char * const start, const char * const headerStart, - TConn * const connectionP, + TConn * const connectionP, time_t const deadline, abyss_bool * const gotHeaderP, char ** const nextP, @@ -473,12 +473,12 @@ processHeaderLine(char * const start, Must read more. */ int const timeLeft = deadline - time(NULL); - + *errorP = !ConnRead(connectionP, timeLeft); } if (!*errorP) { p = lfPos; /* Point to LF */ - + /* If the next line starts with whitespace, it's a continuation line, so blank out the line delimiter (LF or CRLF) so as to join the next @@ -614,7 +614,7 @@ ConnServer(TConn * const connectionP) { ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE diff --git a/modules/mi_xmlrpc/abyss_conn.h b/modules/mi_xmlrpc/abyss_conn.h index 4be150fc7c6..adf8cf138d8 100644 --- a/modules/mi_xmlrpc/abyss_conn.h +++ b/modules/mi_xmlrpc/abyss_conn.h @@ -5,7 +5,7 @@ #include "abyss_socket.h" #include "abyss_file.h" -#define BUFFER_SIZE 4096 +#define BUFFER_SIZE 4096 struct _TConn { struct _TConn * nextOutstandingP; @@ -21,7 +21,7 @@ struct _TConn { /* Index into the connection buffer (buffer[], below) where the next byte to be delivered to the user is. */ - uint32_t inbytes,outbytes; + uint32_t inbytes,outbytes; TSocket * socketP; TIPAddr peerip; abyss_bool hasOwnThread; diff --git a/modules/mi_xmlrpc/abyss_data.c b/modules/mi_xmlrpc/abyss_data.c index 397345f5df8..3f2ede71b2f 100644 --- a/modules/mi_xmlrpc/abyss_data.c +++ b/modules/mi_xmlrpc/abyss_data.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -73,7 +73,7 @@ ListFree(TList * const sl) { unsigned int i; for (i = sl->size; i > 0; --i) free(sl->item[i-1]); - + } free(sl->item); } @@ -107,7 +107,7 @@ ListAdd(TList * const sl, if (sl->size >= sl->maxsize) { uint16_t newSize = sl->maxsize + 16; void **newitem; - + newitem = realloc(sl->item, newSize * sizeof(void *)); if (newitem) { sl->item = newitem; @@ -144,12 +144,12 @@ ListAddFromString(TList * const list, const char * const stringArg) { abyss_bool retval; - + if (!stringArg) retval = TRUE; else { char * buffer; - + buffer = strdup(stringArg); if (!buffer) retval = FALSE; @@ -163,10 +163,10 @@ ListAddFromString(TList * const list, ) { const char * t; NextToken((const char **)&c); - + while (*c == ',') ++c; - + t = GetToken(&c); if (!t) endOfString = TRUE; @@ -175,11 +175,11 @@ ListAddFromString(TList * const list, for (p = c - 2; *p == ','; --p) *p = '\0'; - + if (t[0] != '\0') { abyss_bool added; added = ListAdd(list, (void*)t); - + if (!added) error = TRUE; } @@ -266,7 +266,7 @@ abyss_bool BufferRealloc(TBuffer *buf,uint32_t memsize) else { void *d; - + d=realloc(buf->data,memsize); if (d) { @@ -303,7 +303,7 @@ abyss_bool StringConcat(TString *s,char *s2) if (len+s->size+1>s->buffer.size) if (!BufferRealloc(&(s->buffer),((len+s->size+1+256)/256)*256)) return FALSE; - + strcat((char *)(s->buffer.data),s2); s->size+=len; return TRUE; @@ -316,7 +316,7 @@ abyss_bool StringBlockConcat(TString *s,char *s2,char **ref) if (len+s->size>s->buffer.size) if (!BufferRealloc(&(s->buffer),((len+s->size+1+256)/256)*256)) return FALSE; - + *ref=(char *)(s->buffer.data)+s->size; memcpy(*ref,s2,len); s->size+=len; @@ -342,9 +342,9 @@ static uint16_t Hash16(const char * const start) { const char * s; - + uint16_t i; - + s = start; i = 0; @@ -376,7 +376,7 @@ void TableFree(TTable *t) free(t->item[i-1].name); free(t->item[i-1].value); }; - + free(t->item); } @@ -442,7 +442,7 @@ TableAdd(TTable * const t, if (t->size>=t->maxsize) { TTableItem *newitem; - + t->maxsize+=16; newitem=(TTableItem *)realloc(t->item,(t->maxsize)*sizeof(TTableItem)); @@ -485,7 +485,7 @@ static TPoolZone * PoolZoneAlloc(uint32_t const zonesize) { TPoolZone * poolZoneP; - + MALLOCARRAY(poolZoneP, zonesize); if (poolZoneP) { poolZoneP->pos = &poolZoneP->data[0]; @@ -613,7 +613,7 @@ PoolFree(TPool * const poolP) { TPoolZone * poolZoneP; TPoolZone * nextPoolZoneP; - + for (poolZoneP = poolP->firstzone; poolZoneP; poolZoneP = nextPoolZoneP) { nextPoolZoneP = poolZoneP->next; free(poolZoneP); diff --git a/modules/mi_xmlrpc/abyss_data.h b/modules/mi_xmlrpc/abyss_data.h index c8a874c139e..6bd81887c62 100644 --- a/modules/mi_xmlrpc/abyss_data.h +++ b/modules/mi_xmlrpc/abyss_data.h @@ -43,7 +43,7 @@ ListFindString(TList * const listP, uint16_t * const indexP); -typedef struct +typedef struct { char *name,*value; uint16_t hash; diff --git a/modules/mi_xmlrpc/abyss_date.c b/modules/mi_xmlrpc/abyss_date.c index c11962d291a..247f620a52c 100644 --- a/modules/mi_xmlrpc/abyss_date.c +++ b/modules/mi_xmlrpc/abyss_date.c @@ -15,7 +15,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -133,7 +133,7 @@ DateDecode(const char * const dateString, if (rc != 5) return FALSE; } - } + } /* s points now to the month string */ s += n; for (n = 0; n < 12; ++n) { diff --git a/modules/mi_xmlrpc/abyss_file.c b/modules/mi_xmlrpc/abyss_file.c index 657c8f30f70..e9cc57c21d6 100644 --- a/modules/mi_xmlrpc/abyss_file.c +++ b/modules/mi_xmlrpc/abyss_file.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -106,7 +106,7 @@ uint64_t FileSize(TFile *f) fstat(*f,&fs); return (fs.st_size); -#endif +#endif } abyss_bool FileClose(TFile *f) @@ -210,7 +210,7 @@ abyss_bool FileFindNext(TFileFind *filefind,TFileInfo *fileinfo) strncat(z,"/",NAME_MAX); strncat(z,fileinfo->name,NAME_MAX); z[NAME_MAX]='\0'; - + stat(z,&fs); if (fs.st_mode & S_IFDIR) @@ -220,7 +220,7 @@ abyss_bool FileFindNext(TFileFind *filefind,TFileInfo *fileinfo) fileinfo->size=fs.st_size; fileinfo->time_write=fs.st_mtime; - + return TRUE; }; diff --git a/modules/mi_xmlrpc/abyss_file.h b/modules/mi_xmlrpc/abyss_file.h index 00b8ffa60a5..502d231d7fc 100644 --- a/modules/mi_xmlrpc/abyss_file.h +++ b/modules/mi_xmlrpc/abyss_file.h @@ -15,10 +15,10 @@ #ifdef WIN32 #ifndef __BORLANDC__ #define O_APPEND _O_APPEND -#define O_CREAT _O_CREAT +#define O_CREAT _O_CREAT #define O_EXCL _O_EXCL #define O_RDONLY _O_RDONLY -#define O_RDWR _O_RDWR +#define O_RDWR _O_RDWR #define O_TRUNC _O_TRUNC #define O_WRONLY _O_WRONLY #define O_TEXT _O_TEXT diff --git a/modules/mi_xmlrpc/abyss_http.c b/modules/mi_xmlrpc/abyss_http.c index c8b75938988..56784695bd9 100644 --- a/modules/mi_xmlrpc/abyss_http.c +++ b/modules/mi_xmlrpc/abyss_http.c @@ -148,7 +148,7 @@ unescapeUri(char * const uri, char * y; x = y = uri; - + *errorP = FALSE; while (*x && !*errorP) { @@ -194,7 +194,7 @@ parseHostPort(char * const hostport, const char ** const hostP, unsigned short * const portP, uint16_t * const httpErrorCodeP) { - + char * colonPos; colonPos = strchr(hostport, ':'); @@ -209,7 +209,7 @@ parseHostPort(char * const hostport, for (p = colonPos + 1, port = 0; isdigit(*p) && port < 65535; (port = port * 10 + (*p - '0')), ++p); - + *portP = port; if (*p || port == 0) @@ -245,7 +245,7 @@ parseRequestUri(char * const requestUri, abyss_bool error; unescapeUri(requestUri, &error); - + if (error) *httpErrorCodeP = 400; /* Bad Request */ else { @@ -256,14 +256,14 @@ parseRequestUri(char * const requestUri, { /* Split requestUri at the question mark */ char * const qmark = strchr(requestUri, '?'); - + if (qmark) { *qmark = '\0'; *queryP = qmark + 1; } else *queryP = NULL; } - + requestUriNoQuery = requestUri; if (requestUriNoQuery[0] == '/') { @@ -277,11 +277,11 @@ parseRequestUri(char * const requestUri, char * const hostportpath = &requestUriNoQuery[7]; char * const slashPos = strchr(hostportpath, '/'); char * hostport; - + if (slashPos) { char * p; *pathP = slashPos; - + /* Nul-terminate the host name. To make space for it, slide the whole name back one character. This moves it into the space now occupied by @@ -290,7 +290,7 @@ parseRequestUri(char * const requestUri, for (p = hostportpath; *p != '/'; ++p) *(p-1) = *p; *(p-1) = '\0'; - + hostport = hostportpath - 1; *httpErrorCodeP = 0; } else { @@ -350,11 +350,11 @@ parseRequestLine(char * const requestLine, *httpMethodP = m_head; else *httpMethodP = m_unknown; - + /* URI and Query Decoding */ NextToken((const char **)&p); - + requestUri = GetToken(&p); if (!requestUri) *httpErrorCodeP = 400; /* Bad Request */ @@ -366,9 +366,9 @@ parseRequestLine(char * const requestLine, const char * httpVersion; NextToken((const char **)&p); - + /* HTTP Version Decoding */ - + httpVersion = GetToken(&p); if (httpVersion) { uint32_t vmin, vmaj; @@ -412,11 +412,11 @@ static void getFieldNameToken(char ** const pP, char ** const fieldNameP, uint16_t * const httpErrorCodeP) { - + char * fieldName; NextToken((const char **)pP); - + fieldName = GetToken(pP); if (!fieldName) *httpErrorCodeP = 400; /* Bad Request */ @@ -428,7 +428,7 @@ getFieldNameToken(char ** const pP, fieldName[strlen(fieldName)-1] = '\0'; /* remove trailing colon */ strtolower(fieldName); - + *httpErrorCodeP = 0; /* no error */ *fieldNameP = fieldName; } @@ -522,12 +522,12 @@ RequestRead(TSession * const sessionP) { char * fieldValue; NextToken((const char **)&p); - + fieldValue = p; - + TableAdd(&sessionP->request_headers, fieldName, fieldValue); - + processHeader(fieldName, fieldValue, sessionP, &httpErrorCode); } @@ -557,7 +557,7 @@ RequestValidURI(TSession * const sessionP) { if (!sessionP->request_info.uri) return FALSE; - + if (xmlrpc_streq(sessionP->request_info.uri, "*")) return (sessionP->request_info.method != m_options); @@ -687,42 +687,42 @@ HTTPReasonByStatus(uint16_t const code) { }; static struct _HTTPReasons const reasons[] = { - { 100,"Continue" }, - { 101,"Switching Protocols" }, - { 200,"OK" }, - { 201,"Created" }, - { 202,"Accepted" }, - { 203,"Non-Authoritative Information" }, - { 204,"No Content" }, - { 205,"Reset Content" }, - { 206,"Partial Content" }, - { 300,"Multiple Choices" }, - { 301,"Moved Permanently" }, - { 302,"Moved Temporarily" }, - { 303,"See Other" }, - { 304,"Not Modified" }, - { 305,"Use Proxy" }, - { 400,"Bad Request" }, - { 401,"Unauthorized" }, - { 402,"Payment Required" }, - { 403,"Forbidden" }, - { 404,"Not Found" }, - { 405,"Method Not Allowed" }, - { 406,"Not Acceptable" }, - { 407,"Proxy Authentication Required" }, - { 408,"Request Timeout" }, - { 409,"Conflict" }, - { 410,"Gone" }, - { 411,"Length Required" }, - { 412,"Precondition Failed" }, - { 413,"Request Entity Too Large" }, - { 414,"Request-URI Too Long" }, - { 415,"Unsupported Media Type" }, - { 500,"Internal Server Error" }, - { 501,"Not Implemented" }, - { 502,"Bad Gateway" }, - { 503,"Service Unavailable" }, - { 504,"Gateway Timeout" }, + { 100,"Continue" }, + { 101,"Switching Protocols" }, + { 200,"OK" }, + { 201,"Created" }, + { 202,"Accepted" }, + { 203,"Non-Authoritative Information" }, + { 204,"No Content" }, + { 205,"Reset Content" }, + { 206,"Partial Content" }, + { 300,"Multiple Choices" }, + { 301,"Moved Permanently" }, + { 302,"Moved Temporarily" }, + { 303,"See Other" }, + { 304,"Not Modified" }, + { 305,"Use Proxy" }, + { 400,"Bad Request" }, + { 401,"Unauthorized" }, + { 402,"Payment Required" }, + { 403,"Forbidden" }, + { 404,"Not Found" }, + { 405,"Method Not Allowed" }, + { 406,"Not Acceptable" }, + { 407,"Proxy Authentication Required" }, + { 408,"Request Timeout" }, + { 409,"Conflict" }, + { 410,"Gone" }, + { 411,"Length Required" }, + { 412,"Precondition Failed" }, + { 413,"Request Entity Too Large" }, + { 414,"Request-URI Too Long" }, + { 415,"Unsupported Media Type" }, + { 500,"Internal Server Error" }, + { 501,"Not Implemented" }, + { 502,"Bad Gateway" }, + { 503,"Service Unavailable" }, + { 504,"Gateway Timeout" }, { 505,"HTTP Version Not Supported" }, { 000, NULL } }; @@ -825,7 +825,7 @@ HTTPKeepalive(TSession * const sessionP) { ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE diff --git a/modules/mi_xmlrpc/abyss_mallocvar.h b/modules/mi_xmlrpc/abyss_mallocvar.h index bdaccb41fe1..62d67788a43 100644 --- a/modules/mi_xmlrpc/abyss_mallocvar.h +++ b/modules/mi_xmlrpc/abyss_mallocvar.h @@ -1,5 +1,5 @@ /* These are some dynamic memory allocation facilities. They are essentially - an extension to C, as they do allocations with a cognizance of C + an extension to C, as they do allocations with a cognizance of C variables. You can use them to make C read more like a high level language. @@ -16,7 +16,7 @@ #include static __inline__ void -mallocProduct(void ** const resultP, +mallocProduct(void ** const resultP, unsigned int const factor1, unsigned int const factor2) { /*---------------------------------------------------------------------------- @@ -37,10 +37,10 @@ mallocProduct(void ** const resultP, if (factor1 == 0 || factor2 == 0) *resultP = malloc(1); else { - if (UINT_MAX / factor2 < factor1) + if (UINT_MAX / factor2 < factor1) *resultP = NULL; - else - *resultP = malloc(factor1 * factor2); + else + *resultP = malloc(factor1 * factor2); } } @@ -50,11 +50,11 @@ static __inline__ void reallocProduct(void ** const blockP, unsigned int const factor1, unsigned int const factor2) { - - if (UINT_MAX / factor2 < factor1) + + if (UINT_MAX / factor2 < factor1) *blockP = NULL; - else - *blockP = realloc(*blockP, factor1 * factor2); + else + *blockP = realloc(*blockP, factor1 * factor2); } diff --git a/modules/mi_xmlrpc/abyss_response.c b/modules/mi_xmlrpc/abyss_response.c index 77850e044a5..309693cf62e 100644 --- a/modules/mi_xmlrpc/abyss_response.c +++ b/modules/mi_xmlrpc/abyss_response.c @@ -39,14 +39,14 @@ ResponseError(TSession * const sessionP) { ResponseAddField(sessionP, "Content-type", "text/html"); ResponseWriteStart(sessionP); - + xmlrpc_asprintf(&errorDocument, "Error %d" - "

Error %d

%s

" SERVER_HTML_INFO + "

Error %d

%s

" SERVER_HTML_INFO "", sessionP->status, sessionP->status, reason); - - ConnWrite(sessionP->conn, errorDocument, strlen(errorDocument)); + + ConnWrite(sessionP->conn, errorDocument, strlen(errorDocument)); xmlrpc_strfree(errorDocument); } @@ -158,7 +158,7 @@ ResponseWriteStart(TSession * const sessionP) { if (HTTPKeepalive(sessionP)) { const char * keepaliveValue; - + ResponseAddField(sessionP, "Connection", "Keep-Alive"); xmlrpc_asprintf(&keepaliveValue, "timeout=%u, max=%u", @@ -169,7 +169,7 @@ ResponseWriteStart(TSession * const sessionP) { xmlrpc_strfree(keepaliveValue); } else ResponseAddField(sessionP, "Connection", "close"); - + if (sessionP->chunkedwrite && sessionP->chunkedwritemode) ResponseAddField(sessionP, "Transfer-Encoding", "chunked"); @@ -188,7 +188,7 @@ ResponseWriteStart(TSession * const sessionP) { xmlrpc_strfree(line); } - ConnWrite(sessionP->conn, "\r\n", 2); + ConnWrite(sessionP->conn, "\r\n", 2); } @@ -224,7 +224,7 @@ abyss_bool ResponseContentLength(TSession * const sessionP, uint64_t const len) { char contentLengthValue[32]; - + sprintf(contentLengthValue, "%llu", (long long unsigned int)len); return ResponseAddField(sessionP, "Content-length", contentLengthValue); @@ -248,7 +248,7 @@ static MIMEType * globalMimeTypeP = NULL; MIMEType * MIMETypeCreate(void) { - + MIMEType * MIMETypeP; MALLOCVAR(MIMETypeP); @@ -300,7 +300,7 @@ mimeTypeAdd(MIMEType * const MIMETypeP, const char * const type, const char * const ext, abyss_bool * const successP) { - + uint16_t index; void * mimeTypesItem; abyss_bool typeIsInList; @@ -328,7 +328,7 @@ mimeTypeAdd(MIMEType * const MIMETypeP, ListAdd(&MIMETypeP->typeList, mimeTypesItem); if (addedToMimeTypes) { abyss_bool addedToExt; - + addedToExt = ListAdd(&MIMETypeP->extList, extItem); *successP = addedToExt; if (!*successP) @@ -358,7 +358,7 @@ MIMETypeAdd2(MIMEType * const MIMETypeArg, if (MIMETypeP == NULL) success = FALSE; - else + else mimeTypeAdd(MIMETypeP, type, ext, &success); return success; @@ -390,7 +390,7 @@ mimeTypeFromExt(MIMEType * const MIMETypeP, retval = NULL; else retval = MIMETypeP->typeList.item[extindex]; - + return retval; } @@ -434,7 +434,7 @@ findExtension(const char * const fileName, /* We're looking for the last dot after the last slash */ for (i = 0, extFound = FALSE; fileName[i]; ++i) { char const c = fileName[i]; - + if (c == '.') { extFound = TRUE; extPos = i + 1; @@ -459,7 +459,7 @@ mimeTypeFromFileName(MIMEType * const MIMETypeP, const char * ext; assert(MIMETypeP != NULL); - + findExtension(fileName, &ext); if (ext) @@ -477,7 +477,7 @@ MIMETypeFromFileName2(MIMEType * const MIMETypeArg, const char * const fileName) { const char * retval; - + MIMEType * MIMETypeP = MIMETypeArg ? MIMETypeArg : globalMimeTypeP; if (MIMETypeP == NULL) @@ -516,13 +516,13 @@ fileContainsText(const char * const fileName) { unsigned int i; readRc = FileRead(&file, buffer, sizeof(buffer)); - + if (readRc >= 0) { unsigned int bytesRead = readRc; abyss_bool nonTextFound; nonTextFound = FALSE; /* initial value */ - + for (i = 0; i < bytesRead; ++i) { char const c = buffer[i]; if (c < ' ' && !isspace(c) && c != ctlZ) @@ -539,7 +539,7 @@ fileContainsText(const char * const fileName) { } - + static const char * mimeTypeGuessFromFile(MIMEType * const MIMETypeP, const char * const fileName) { @@ -553,12 +553,12 @@ mimeTypeGuessFromFile(MIMEType * const MIMETypeP, if (ext && MIMETypeP) retval = MIMETypeFromExt2(MIMETypeP, ext); - + if (!retval) { if (fileContainsText(fileName)) retval = "text/plain"; else - retval = "application/octet-stream"; + retval = "application/octet-stream"; } return retval; } @@ -581,7 +581,7 @@ MIMETypeGuessFromFile(const char * const fileName) { return mimeTypeGuessFromFile(globalMimeTypeP, fileName); } - + /********************************************************************* ** Base64 @@ -603,7 +603,7 @@ void Base64Encode(char *s,char *d) uint32_t i,length=strlen(s); char *p=d; - + /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ for (i = 0; i < length; i += 3) { @@ -613,13 +613,13 @@ void Base64Encode(char *s,char *d) *p++ = tbl[s[2] & 0x3f]; s += 3; } - + /* Pad the result if necessary... */ if (i == length + 1) *(p - 1) = '='; else if (i == length + 2) *(p - 1) = *(p - 2) = '='; - + /* ...and zero-terminate it. */ *p = '\0'; } @@ -641,7 +641,7 @@ void Base64Encode(char *s,char *d) ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE diff --git a/modules/mi_xmlrpc/abyss_server.c b/modules/mi_xmlrpc/abyss_server.c index 2a5403a8ed5..7eb737797c6 100644 --- a/modules/mi_xmlrpc/abyss_server.c +++ b/modules/mi_xmlrpc/abyss_server.c @@ -90,7 +90,7 @@ determineSortType(const char * const query, *sortP = 1; *textP = FALSE; *errorP = NULL; - + if (query) { if (xmlrpc_streq(query, "plain")) *textP = TRUE; @@ -121,7 +121,7 @@ generateListing(TList * const listP, TPool * const poolP, const char ** const errorP, uint16_t * const responseStatusP) { - + TFileInfo fileinfo; TFileFind findhandle; @@ -158,7 +158,7 @@ generateListing(TList * const listP, if (*errorP) { *responseStatusP = 500; ListFree(listP); - } + } FileFindClose(&findhandle); } } @@ -209,7 +209,7 @@ sendDirectoryDocument(TList * const listP, /* Sort the files */ qsort(listP->item, listP->size, sizeof(void *), (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates)); - + /* Write the listing */ if (ascending) i = 0; @@ -226,7 +226,7 @@ sendDirectoryDocument(TList * const listP, ++i; else --i; - + strcpy(z, fi->name); k = strlen(z); @@ -245,12 +245,12 @@ sendDirectoryDocument(TList * const listP, p = z1 + 24; } else { strcpy(z1, z); - + ++k; p = z1 + k; while (k < 25) z1[k++] = ' '; - + z1[25] = '\0'; } @@ -276,9 +276,9 @@ sendDirectoryDocument(TList * const listP, u = 'G'; } } - + sprintf(z3, "%5llu %c", (long long unsigned int)fi->size, u); - + if (xmlrpc_streq(fi->name, "..")) z4 = ""; else @@ -297,13 +297,13 @@ sendDirectoryDocument(TList * const listP, HTTPWriteBodyChunk(sessionP, z, strlen(z)); } - + /* Write the tail of the file */ if (text) strcpy(z, SERVER_PLAIN_INFO); else strcpy(z, "" SERVER_HTML_INFO "" CRLF CRLF); - + HTTPWriteBodyChunk(sessionP, z, strlen(z)); } @@ -346,7 +346,7 @@ ServerDirectoryHandler(TSession * const r, uint16_t responseStatus=0; TDate dirdate; const char * imsHdr; - + determineSortType(r->request_info.query, &ascending, &sort, &text, &error); if (error) { @@ -388,7 +388,7 @@ ServerDirectoryHandler(TSession * const r, if (DateToString(&dirdate, z)) ResponseAddField(r, "Last-Modified", z); - + ResponseChunked(r); ResponseWrite(r); @@ -433,7 +433,7 @@ sendBody(TSession * const sessionP, uint64_t start; uint64_t end; abyss_bool decoded; - + decoded = RangeDecode((char *)(sessionP->ranges.item[i]), filesize, &start, &end); @@ -473,7 +473,7 @@ ServerFileHandler(TSession * const r, TDate date; char * p; TDate filedate; - + mediatype = MIMETypeGuessFromFile2(mimeTypeP, z); if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) { @@ -510,7 +510,7 @@ ServerFileHandler(TSession * const r, ResponseStatus(r, 200); break; } - + sprintf(z, "bytes %llu-%llu/%llu", (long long unsigned int)start, (long long unsigned int)end, (long long unsigned int)filesize); @@ -524,12 +524,12 @@ ServerFileHandler(TSession * const r, ResponseStatus(r, 206); break; } - + if (r->ranges.size == 0) { ResponseContentLength(r, filesize); ResponseContentType(r, mediatype); } - + if (DateToString(&filedate, z)) ResponseAddField(r, "Last-Modified", z); @@ -620,7 +620,7 @@ ServerDefaultHandlerFunc(TSession * const sessionP) { i = srvP->defaultfilenames.size; while (i-- > 0) { - *p = '\0'; + *p = '\0'; strcat(z, (srvP->defaultfilenames.item[i])); if (FileStat(z, &fs)) { if (!(fs.st_mode & S_IFDIR)) @@ -630,7 +630,7 @@ ServerDefaultHandlerFunc(TSession * const sessionP) { } *(p-1) = '\0'; - + if (!FileStat(z, &fs)) { ResponseStatusErrno(sessionP); return TRUE; @@ -721,7 +721,7 @@ static void createServer(struct _TServer ** const srvPP, abyss_bool const noAccept, TSocket * const userSocketP, - uint16_t const portNumber, + uint16_t const portNumber, const char ** const errorP) { struct _TServer * srvP; @@ -748,7 +748,7 @@ createServer(struct _TServer ** const srvPP, srvP->advertise = TRUE; srvP->mimeTypeP = NULL; srvP->useSigchld = FALSE; - + initUnixStuff(srvP); ListInitAutoFree(&srvP->handlers); @@ -757,7 +757,7 @@ createServer(struct _TServer ** const srvPP, srvP->logfileisopen = FALSE; *errorP = NULL; - } + } if (*errorP) free(srvP); } @@ -808,7 +808,7 @@ ServerCreate(TServer * const serverP, success = FALSE; } else { success = TRUE; - + setNamePathLog(serverP, name, filesPath, logFileName); } @@ -855,7 +855,7 @@ ServerCreateSocket(TServer * const serverP, xmlrpc_strfree(error); } else { success = TRUE; - + setNamePathLog(serverP, name, filesPath, logFileName); } } else @@ -885,7 +885,7 @@ ServerCreateNoAccept(TServer * const serverP, xmlrpc_strfree(error); } else { success = TRUE; - + setNamePathLog(serverP, name, filesPath, logFileName); } return success; @@ -897,7 +897,7 @@ void ServerCreateSocket2(TServer * const serverP, TSocket * const socketP, const char ** const errorP) { - + abyss_bool const noAcceptFalse = FALSE; assert(socketP); @@ -937,7 +937,7 @@ ServerFree(TServer * const serverP) { xmlrpc_strfree(srvP->name); xmlrpc_strfree(srvP->filespath); - + ListFree(&srvP->defaultfilenames); terminateHandlers(&srvP->handlers); @@ -959,7 +959,7 @@ ServerSetName(TServer * const serverP, const char * const name) { xmlrpc_strfree(serverP->srvP->name); - + serverP->srvP->name = strdup(name); } @@ -970,7 +970,7 @@ ServerSetFilesPath(TServer * const serverP, const char * const filesPath) { xmlrpc_strfree(serverP->srvP->filespath); - + serverP->srvP->filespath = strdup(filesPath); } @@ -979,12 +979,12 @@ ServerSetFilesPath(TServer * const serverP, void ServerSetLogFileName(TServer * const serverP, const char * const logFileName) { - + struct _TServer * const srvP = serverP->srvP; if (srvP->logfilename) xmlrpc_strfree(srvP->logfilename); - + srvP->logfilename = strdup(logFileName); } @@ -1041,18 +1041,18 @@ runUserHandler(TSession * const sessionP, abyss_bool handled; int i; - + for (i = srvP->handlers.size-1, handled = FALSE; i >= 0 && !handled; --i) { URIHandler2 * const handlerP = srvP->handlers.item[i]; - + if (handlerP->handleReq2) handlerP->handleReq2(handlerP, sessionP, &handled); else if (handlerP->handleReq1) handled = handlerP->handleReq1(sessionP); } - + if (!handled) ((URIHandler)(srvP->defaulthandler))(sessionP); } @@ -1069,7 +1069,7 @@ processDataFromClient(TConn * const connectionP, RequestInit(&session, connectionP); session.serverDeniesKeepalive = lastReqOnConn; - + RequestRead(&session); if (session.status == 0) { if (session.version.major >= 2) @@ -1080,14 +1080,14 @@ processDataFromClient(TConn * const connectionP, runUserHandler(&session, connectionP->server->srvP); } assert(session.status != 0); - + if (session.responseStarted) HTTPWriteEndChunk(&session); else ResponseError(&session); *keepAliveP = HTTPKeepalive(&session); - + SessionLog(&session); RequestFree(&session); @@ -1115,7 +1115,7 @@ serverFunc(void * const userHandle) { while (!connectionDone) { abyss_bool success; - + /* Wait to read until timeout */ success = ConnRead(connectionP, srvP->keepalivetimeout); @@ -1126,14 +1126,14 @@ serverFunc(void * const userHandle) { requestCount + 1 >= srvP->keepalivemaxconn; abyss_bool keepalive; - + processDataFromClient(connectionP, lastReqOnConn, &keepalive); - + ++requestCount; if (!keepalive) connectionDone = TRUE; - + /**************** Must adjust the read buffer *****************/ ConnReadInit(connectionP); } @@ -1152,16 +1152,16 @@ createAndBindSocket(struct _TServer * const srvP) { TraceMsg("Can't initialize TCP sockets"); else { TSocket * socketP; - + SocketUnixCreate(&socketP); - + if (!socketP) TraceMsg("Can't create a socket"); else { abyss_bool success; - + success = SocketBind(socketP, NULL, srvP->port); - + if (!success) TraceMsg("Failed to bind listening socket to port number %u", srvP->port); @@ -1190,7 +1190,7 @@ ServerInit(TServer * const serverP) { -----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; abyss_bool success; - + if (!srvP->serverAcceptsConnections) { TraceMsg("ServerInit() is not valid on a server that doesn't " "accept connections " @@ -1214,7 +1214,7 @@ ServerInit(TServer * const serverP) { -/* We don't do any locking on the outstanding connections list, so +/* We don't do any locking on the outstanding connections list, so we must make sure that only the master thread (the one that listens for connections) ever accesses it. @@ -1285,12 +1285,12 @@ freeFinishedConns(outstandingConnList * const listP) { TConn * const connectionP = (*pp); ThreadUpdateStatus(connectionP->threadP); - + if (connectionP->finished) { /* Take it out of the list */ *pp = connectionP->nextOutstandingP; --listP->count; - + ConnWaitAndRelease(connectionP); } else { /* Move to next connection in list */ @@ -1326,7 +1326,7 @@ waitForNoConnections(outstandingConnList * const outstandingConnListP) { while (outstandingConnListP->firstP) { freeFinishedConns(outstandingConnListP); - + if (outstandingConnListP->firstP) waitForConnectionFreed(outstandingConnListP); } @@ -1363,7 +1363,7 @@ void ServerUseSigchld(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; - + srvP->useSigchld = TRUE; } @@ -1389,7 +1389,7 @@ destroyConnSocket(void * const userHandle) { } -static void +static void serverRun2(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; @@ -1408,7 +1408,7 @@ serverRun2(TServer * const serverP) { SocketAccept(srvP->listenSocketP, &connected, &failed, &connectedSocketP, &peerIpAddr); - + if (connected) { const char * error; @@ -1424,7 +1424,7 @@ serverRun2(TServer * const serverP) { addToOutstandingConnList(outstandingConnListP, connectionP); ConnProcess(connectionP); SocketClose(connectedSocketP); - + /* When connection is done (which could be later, courtesy of a background thread), destroyConnSocket() will destroy *connectedSocketP. @@ -1443,7 +1443,7 @@ serverRun2(TServer * const serverP) { -void +void ServerRun(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; @@ -1474,7 +1474,7 @@ serverRunConn(TServer * const serverP, srvP->keepalivemaxconn = 1; - ConnCreate(&connectionP, + ConnCreate(&connectionP, serverP, connectedSocketP, &serverFunc, NULL, ABYSS_FOREGROUND, srvP->useSigchld, &error); @@ -1561,7 +1561,7 @@ ServerRunOnce(TServer * const serverP) { abyss_bool failed; TSocket * connectedSocketP; TIPAddr remoteAddr; - + srvP->keepalivemaxconn = 1; SocketAccept(srvP->listenSocketP, @@ -1598,7 +1598,7 @@ ServerRunOnce2(TServer * const serverP, static void setGroups(void) { -#ifdef HAVE_SETGROUPS +#ifdef HAVE_SETGROUPS if (setgroups(0, NULL) == (-1)) TraceExit("Failed to setup the group."); #endif @@ -1632,7 +1632,7 @@ ServerDaemonize(TServer * const serverP) { /* We are the parent */ exit(0); } - + setsid(); /* Change the current user if we are root */ @@ -1647,14 +1647,14 @@ ServerDaemonize(TServer * const serverP) { if (srvP->gid != (gid_t)-1) if (setgid(srvP->gid)==(-1)) TraceExit("Failed to change the group."); - + if (setuid(srvP->uid) == -1) TraceExit("Failed to change the user."); } - + if (srvP->pidfile != -1) { char z[16]; - + sprintf(z, "%d", getpid()); FileWrite(&srvP->pidfile, z, strlen(z)); FileClose(&srvP->pidfile); @@ -1758,7 +1758,7 @@ LogWrite(TServer * const serverP, const char * const lbr = "\n"; FileWrite(&srvP->logfile, msg, strlen(msg)); FileWrite(&srvP->logfile, lbr, strlen(lbr)); - + MutexUnlock(&srvP->logmutex); } } @@ -1782,7 +1782,7 @@ LogWrite(TServer * const serverP, ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE diff --git a/modules/mi_xmlrpc/abyss_session.c b/modules/mi_xmlrpc/abyss_session.c index 06e699122c8..f3844f25c44 100644 --- a/modules/mi_xmlrpc/abyss_session.c +++ b/modules/mi_xmlrpc/abyss_session.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -55,10 +55,10 @@ SessionRefillBuffer(TSession * const sessionP) { -----------------------------------------------------------------------------*/ struct _TServer * const srvP = sessionP->conn->server->srvP; abyss_bool succeeded; - + /* Reset our read buffer & flush data from previous reads. */ ConnReadInit(sessionP->conn); - + /* Read more network data into our buffer. If we encounter a timeout, exit immediately. We're very forgiving about the timeout here. We allow a full timeout per network read, which @@ -83,9 +83,9 @@ SessionReadDataAvail(TSession * const sessionP) { void -SessionGetReadData(TSession * const sessionP, - size_t const max, - const char ** const outStartP, +SessionGetReadData(TSession * const sessionP, + size_t const max, + const char ** const outStartP, size_t * const outLenP) { /*---------------------------------------------------------------------------- Extract some data which the server has read and buffered for the @@ -114,7 +114,7 @@ SessionGetReadData(TSession * const sessionP, void SessionGetRequestInfo(TSession * const sessionP, const TRequestInfo ** const requestInfoPP) { - + *requestInfoPP = &sessionP->request_info; } @@ -141,7 +141,7 @@ SessionLog(TSession * const sessionP) { IPB3(sessionP->conn->peerip), IPB4(sessionP->conn->peerip), user ? user : "", - date, + date, sessionP->request_info.requestline, sessionP->status, sessionP->conn->outbytes diff --git a/modules/mi_xmlrpc/abyss_socket.c b/modules/mi_xmlrpc/abyss_socket.c index 7a367f0ce8d..16eec7a1b65 100644 --- a/modules/mi_xmlrpc/abyss_socket.c +++ b/modules/mi_xmlrpc/abyss_socket.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -87,7 +87,7 @@ socketOsTerm(void) { SocketUnixTerm(); #endif } - + abyss_bool SocketTraceIsActive; @@ -179,10 +179,10 @@ SocketWrite(TSocket * const socketP, uint32_t -SocketRead(TSocket * const socketP, - unsigned char * const buffer, +SocketRead(TSocket * const socketP, + unsigned char * const buffer, uint32_t const len) { - + return (*socketP->vtbl.read)(socketP, (char*)buffer, len); } diff --git a/modules/mi_xmlrpc/abyss_socket.h b/modules/mi_xmlrpc/abyss_socket.h index 90b429ed9f9..b0a46e14b44 100644 --- a/modules/mi_xmlrpc/abyss_socket.h +++ b/modules/mi_xmlrpc/abyss_socket.h @@ -109,8 +109,8 @@ SocketWrite(TSocket * const socketP, abyss_bool * const failedP); uint32_t -SocketRead(TSocket * const socketP, - unsigned char * const buffer, +SocketRead(TSocket * const socketP, + unsigned char * const buffer, uint32_t const len); abyss_bool diff --git a/modules/mi_xmlrpc/abyss_socket_unix.c b/modules/mi_xmlrpc/abyss_socket_unix.c index c5bdccda601..29a68ee6ed5 100644 --- a/modules/mi_xmlrpc/abyss_socket_unix.c +++ b/modules/mi_xmlrpc/abyss_socket_unix.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -148,7 +148,7 @@ SocketUnixCreate(TSocket ** const socketPP) { else { socketUnixP->fd = rc; socketUnixP->userSuppliedFd = FALSE; - + { int32_t n = 1; int rc; @@ -234,7 +234,7 @@ socketWrite(TSocket * const socketP, size_t const maxSend = (size_t)(-1) >> 1; ssize_t rc; - + rc = send(socketUnixP->fd, &buffer[len-bytesLeft], MIN(maxSend, bytesLeft), 0); @@ -261,8 +261,8 @@ socketWrite(TSocket * const socketP, static uint32_t -socketRead(TSocket * const socketP, - char * const buffer, +socketRead(TSocket * const socketP, + char * const buffer, uint32_t const len) { struct socketUnix * const socketUnixP = socketP->implP; @@ -273,7 +273,7 @@ socketRead(TSocket * const socketP, if (rc < 0) fprintf(stderr, "Abyss socket: recv() failed. errno=%d (%s)", errno, strerror(errno)); - else + else fprintf(stderr, "Abyss socket: read %u bytes: '%.*s'\n", len, (int)len, buffer); } @@ -390,7 +390,7 @@ socketAccept(TSocket * const listenSocketP, if (acceptedSocketUnixP) { acceptedSocketUnixP->fd = acceptedFd; acceptedSocketUnixP->userSuppliedFd = FALSE; - + SocketCreate(&vtbl, acceptedSocketUnixP, acceptedSocketPP); if (!*acceptedSocketPP) failed = TRUE; @@ -408,7 +408,7 @@ socketAccept(TSocket * const listenSocketP, interrupted = TRUE; else failed = TRUE; - } + } *failedP = failed; *connectedP = connected; } @@ -444,16 +444,16 @@ socketWait(TSocket * const socketP, rc = select(socketUnixP->fd + 1, &rfds, &wfds, NULL, (timems == TIME_INFINITE ? NULL : &tv)); - switch(rc) { + switch(rc) { case 0: /* time out */ return 0; case -1: /* socket error */ if (errno == EINTR) break; - + return 0; - + default: if (FD_ISSET(socketUnixP->fd, &rfds)) return 1; @@ -494,7 +494,7 @@ socketGetPeerName(TSocket * const socketP, struct sockaddr sockAddr; addrlen = sizeof(sockAddr); - + rc = getpeername(socketUnixP->fd, &sockAddr, &addrlen); if (rc < 0) { diff --git a/modules/mi_xmlrpc/abyss_thread_fork.c b/modules/mi_xmlrpc/abyss_thread_fork.c index a18575377c7..ba15b735d27 100644 --- a/modules/mi_xmlrpc/abyss_thread_fork.c +++ b/modules/mi_xmlrpc/abyss_thread_fork.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -90,7 +90,7 @@ struct abyss_thread { static struct { struct abyss_thread * firstP; } ThreadPool; - + void @@ -107,7 +107,7 @@ findThread(pid_t const pid) { struct abyss_thread * p; for (p = ThreadPool.firstP; p && p->pid != pid; p = p->nextInPoolP); - + return p; } @@ -142,7 +142,7 @@ removeFromPool(struct abyss_thread * const threadP) { for (p = ThreadPool.firstP; p && p->nextInPoolP != threadP; p = p->nextInPoolP); - + if (p) /* p points to thread right before the one we want to remove */ p->nextInPoolP = threadP->nextInPoolP; @@ -191,7 +191,7 @@ ThreadCreate(TThread ** const threadPP, TThreadDoneFn * const threadDone, abyss_bool const useSigchld, const char ** const errorP) { - + TThread * threadP; MALLOCVAR(threadP); @@ -215,7 +215,7 @@ ThreadCreate(TThread ** const threadPP, blockSignalClass(SIGCHLD, &oldBlockedSet); rc = fork(); - + if (rc < 0) xmlrpc_asprintf(errorP, "fork() failed, errno=%d (%s)", errno, strerror(errno)); @@ -245,7 +245,7 @@ ThreadCreate(TThread ** const threadPP, abyss_bool ThreadRun(TThread * const threadP ATTR_UNUSED) { - return TRUE; + return TRUE; } diff --git a/modules/mi_xmlrpc/abyss_token.c b/modules/mi_xmlrpc/abyss_token.c index 72a94affbe2..9e95ea7a727 100644 --- a/modules/mi_xmlrpc/abyss_token.c +++ b/modules/mi_xmlrpc/abyss_token.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -61,7 +61,7 @@ char * GetToken(char ** const pP) { char * p0; - + p0 = *pP; while (1) { diff --git a/modules/mi_xmlrpc/abyss_trace.c b/modules/mi_xmlrpc/abyss_trace.c index 3f1719907b3..500cbde0821 100644 --- a/modules/mi_xmlrpc/abyss_trace.c +++ b/modules/mi_xmlrpc/abyss_trace.c @@ -17,7 +17,7 @@ ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. -** +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE diff --git a/modules/mi_xmlrpc/abyss_xmlrpc_int.h b/modules/mi_xmlrpc/abyss_xmlrpc_int.h index 0d6ead79add..6722d1367f6 100644 --- a/modules/mi_xmlrpc/abyss_xmlrpc_int.h +++ b/modules/mi_xmlrpc/abyss_xmlrpc_int.h @@ -8,13 +8,13 @@ extern const char * const xmlrpc_strsol; void xmlrpc_millisecond_sleep(unsigned int const milliseconds); -void +void xmlrpc_asprintf(const char ** const retvalP, const char * const fmt, ...); void xmlrpc_strfree(const char * const string); -static inline unsigned short +static inline unsigned short xmlrpc_streq(const char * const a, const char * const b) { return (strcmp(a, b) == 0); diff --git a/modules/mi_xmlrpc/abyss_xmlrpc_server.c b/modules/mi_xmlrpc/abyss_xmlrpc_server.c index f2ecab182d9..86a3dbabb54 100644 --- a/modules/mi_xmlrpc/abyss_xmlrpc_server.c +++ b/modules/mi_xmlrpc/abyss_xmlrpc_server.c @@ -49,25 +49,25 @@ addAuthCookie(xmlrpc_env * const envP, const char * const authCookie) { const char * cookieResponse; - + xmlrpc_asprintf(&cookieResponse, "auth=%s", authCookie); - + if (cookieResponse == xmlrpc_strsol) xmlrpc_faultf(envP, "Insufficient memory to generate cookie " "response header."); else { ResponseAddField(abyssSessionP, "Set-Cookie", cookieResponse); - + xmlrpc_strfree(cookieResponse); } -} - +} -static void + +static void sendXmlData(xmlrpc_env * const envP, - TSession * const abyssSessionP, - const char * const body, + TSession * const abyssSessionP, + const char * const body, size_t const len, bool const chunked) { /*---------------------------------------------------------------------------- @@ -110,7 +110,7 @@ sendXmlData(xmlrpc_env * const envP, ResponseContentType(abyssSessionP, "text/xml; charset=\"utf-8\""); ResponseContentLength(abyssSessionP, abyssLen); - + ResponseWriteStart(abyssSessionP); ResponseWriteBody(abyssSessionP, body, abyssLen); ResponseWriteEnd(abyssSessionP); @@ -120,11 +120,11 @@ sendXmlData(xmlrpc_env * const envP, static void -sendError(TSession * const abyssSessionP, +sendError(TSession * const abyssSessionP, unsigned int const status) { /*---------------------------------------------------------------------------- Send an error response back to the client. - + -----------------------------------------------------------------------------*/ ResponseStatus(abyssSessionP, (uint16_t) status); ResponseError(abyssSessionP); @@ -192,7 +192,7 @@ getBody(xmlrpc_env * const envP, bytesRead = 0; while (!envP->fault_occurred && bytesRead < contentSize) { - SessionGetReadData(abyssSessionP, contentSize - bytesRead, + SessionGetReadData(abyssSessionP, contentSize - bytesRead, &chunkPtr, &chunkLen); bytesRead += chunkLen; @@ -220,7 +220,7 @@ storeCookies(TSession * const httpRequestP, -----------------------------------------------------------------------------*/ const char * const cookie = RequestHeaderValue(httpRequestP, "cookie"); if (cookie) { - /* + /* Setting the value in an environment variable doesn't make any sense. So for now, cookie code is disabled. -Bryan 04.10.03. @@ -240,10 +240,10 @@ static void validateContentType(TSession * const httpRequestP, unsigned int * const httpErrorP) { /*---------------------------------------------------------------------------- - If the client didn't specify a content-type of "text/xml", return + If the client didn't specify a content-type of "text/xml", return "400 Bad Request". We can't allow the client to default this header, because some firewall software may rely on all XML-RPC requests - using the POST method and a content-type of "text/xml". + using the POST method and a content-type of "text/xml". -----------------------------------------------------------------------------*/ const char * const content_type = RequestHeaderValue(httpRequestP, "content-type"); @@ -279,9 +279,9 @@ processContentLength(TSession * const httpRequestP, Make sure the content length is present and non-zero. This is technically required by XML-RPC, but we only enforce it because we don't want to figure out how to safely handle HTTP < 1.1 requests - without it. If the length is missing, return "411 Length Required". + without it. If the length is missing, return "411 Length Required". -----------------------------------------------------------------------------*/ - const char * const content_length = + const char * const content_length = RequestHeaderValue(httpRequestP, "content-length"); if (content_length == NULL) @@ -292,15 +292,15 @@ processContentLength(TSession * const httpRequestP, else { unsigned long contentLengthValue; char * tail; - + contentLengthValue = strtoul(content_length, &tail, 10); - + if (*tail != '\0') /* There's non-numeric crap in the length */ *httpErrorP = 400; else if (contentLengthValue < 1) *httpErrorP = 400; - else if ((unsigned long)(size_t)contentLengthValue + else if ((unsigned long)(size_t)contentLengthValue != contentLengthValue) *httpErrorP = 400; else { @@ -315,7 +315,7 @@ processContentLength(TSession * const httpRequestP, static void traceHandlerCalled(TSession * const abyssSessionP) { - + const char * methodDesc; const TRequestInfo * requestInfoP; @@ -379,16 +379,16 @@ processCall(TSession * const abyssSessionP, xmlrpc_mem_block * output; /* Process the RPC. */ output = xmlrpc_registry_process_call( - &env, registryP, NULL, + &env, registryP, NULL, XMLRPC_MEMBLOCK_CONTENTS(char, body), XMLRPC_MEMBLOCK_SIZE(char, body)); if (!env.fault_occurred) { /* Send out the result. */ - sendXmlData(&env, abyssSessionP, + sendXmlData(&env, abyssSessionP, XMLRPC_MEMBLOCK_CONTENTS(char, output), XMLRPC_MEMBLOCK_SIZE(char, output), wantChunk); - + XMLRPC_MEMBLOCK_FREE(char, output); } XMLRPC_MEMBLOCK_FREE(char, body); @@ -476,7 +476,7 @@ handleXmlrpcReq(URIHandler2 * const this, *handledP = TRUE; /* We understand only the POST HTTP method. For anything else, return - "405 Method Not Allowed". + "405 Method Not Allowed". */ if (requestInfoP->method != m_post) sendError(abyssSessionP, 405); @@ -494,11 +494,11 @@ handleXmlrpcReq(URIHandler2 * const this, unsigned int httpError; size_t contentSize; - processContentLength(abyssSessionP, + processContentLength(abyssSessionP, &contentSize, &httpError); if (httpError) sendError(abyssSessionP, httpError); - else + else processCall(abyssSessionP, contentSize, uriHandlerXmlrpcP->registryP, uriHandlerXmlrpcP->chunkResponse, @@ -520,7 +520,7 @@ handleXmlrpcReq(URIHandler2 * const this, ** for more documentation. */ -static xmlrpc_bool +static xmlrpc_bool xmlrpc_server_abyss_default_handler(TSession * const sessionP) { if (trace_abyss) @@ -533,7 +533,7 @@ xmlrpc_server_abyss_default_handler(TSession * const sessionP) { -static void +static void sigchld(int const signalClass ATTR_UNUSED) { /*---------------------------------------------------------------------------- This is a signal handler for a SIGCHLD signal (which informs us that @@ -552,19 +552,19 @@ sigchld(int const signalClass ATTR_UNUSED) { error = false; childrenLeft = true; /* initial assumption */ - + /* Reap defunct children until there aren't any more. */ while (childrenLeft && !error) { int status; pid_t pid; pid = waitpid((pid_t) -1, &status, WNOHANG); - + if (pid == 0) childrenLeft = false; else if (pid < 0) { /* because of ptrace */ - if (errno != EINTR) + if (errno != EINTR) error = true; } else ServerHandleSigchld(pid); @@ -584,19 +584,19 @@ static void setupSignalHandlers(struct signalHandlers * const oldHandlersP) { #ifndef WIN32 struct sigaction mysigaction; - + sigemptyset(&mysigaction.sa_mask); mysigaction.sa_flags = 0; /* This signal indicates connection closed in the middle */ mysigaction.sa_handler = SIG_IGN; sigaction(SIGPIPE, &mysigaction, &oldHandlersP->pipe); - + /* This signal indicates a child process (request handler) has died */ mysigaction.sa_handler = sigchld; sigaction(SIGCHLD, &mysigaction, &oldHandlersP->chld); #endif -} +} @@ -624,7 +624,7 @@ runServerDaemon(TServer * const serverP, ServerUseSigchld(serverP); ServerDaemonize(serverP); - + /* We run the user supplied runfirst after forking, but before accepting connections (helpful when running with threads) */ @@ -644,13 +644,13 @@ setHandler(xmlrpc_env * const envP, const char * const uriPath, xmlrpc_registry * const registryP, bool const chunkResponse) { - + struct uriHandlerXmlrpc * uriHandlerXmlrpcP; URIHandler2 uriHandler; abyss_bool success; trace_abyss = getenv("XMLRPC_TRACE_ABYSS"); - + MALLOCVAR_NOFAIL(uriHandlerXmlrpcP); uriHandlerXmlrpcP->registryP = registryP; @@ -684,7 +684,7 @@ xmlrpc_server_abyss_set_handler(xmlrpc_env * const envP, setHandler(envP, srvP, uriPath, registryP, false); } - + static void setHandlers(TServer * const srvP, @@ -697,9 +697,9 @@ setHandlers(TServer * const srvP, xmlrpc_env_init(&env); trace_abyss = getenv("XMLRPC_TRACE_ABYSS"); - + setHandler(&env, srvP, uriPath, registryP, chunkResponse); - + if (env.fault_occurred) abort(); @@ -734,7 +734,7 @@ oldHighLevelAbyssRun(xmlrpc_env * const envP ATTR_UNUSED, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { /*---------------------------------------------------------------------------- - This is the old deprecated interface, where the caller of the + This is the old deprecated interface, where the caller of the xmlrpc_server_abyss API supplies an Abyss configuration file and we use it to daemonize (fork into the background, chdir, set uid, etc.) and run the Abyss server. @@ -747,17 +747,17 @@ oldHighLevelAbyssRun(xmlrpc_env * const envP ATTR_UNUSED, TServer server; runfirstFn runfirst; void * runfirstArg; - + DateInit(); - + ServerCreate(&server, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); - + ConfReadServerFile(parmsP->config_file_name, &server); - + setHandlers(&server, "/RPC2", parmsP->registryP, false); - + ServerInit(&server); - + if (parmSize >= XMLRPC_APSIZE(runfirst_arg)) { runfirst = parmsP->runfirst; runfirstArg = parmsP->runfirst_arg; @@ -779,7 +779,7 @@ setAdditionalServerParms(const xmlrpc_server_abyss_parms * const parmsP, /* The following ought to be parameters on ServerCreate(), but it looks like plugging them straight into the TServer structure is - the only way to set them. + the only way to set them. */ if (parmSize >= XMLRPC_APSIZE(keepalive_timeout) && @@ -806,7 +806,7 @@ extractServerCreateParms( unsigned int * const portNumberP, TOsSocket * const socketFdP, const char ** const logFileNameP) { - + if (parmSize >= XMLRPC_APSIZE(socket_bound)) *socketBoundP = parmsP->socket_bound; @@ -852,9 +852,9 @@ createServerBoundSocket(xmlrpc_env * const envP, TSocket * socketP; const char * error; - + SocketUnixCreateFd(socketFd, &socketP); - + if (!socketP) xmlrpc_faultf(envP, "Unable to create Abyss socket out of " "file descriptor %d.", socketFd); @@ -866,9 +866,9 @@ createServerBoundSocket(xmlrpc_env * const envP, xmlrpc_strfree(error); } else { *socketPP = socketP; - + ServerSetName(serverP, "XmlRpcServer"); - + if (logFileName) ServerSetLogFileName(serverP, logFileName); } @@ -903,9 +903,9 @@ createServer(xmlrpc_env * const envP, createServerBoundSocket(envP, socketFd, logFileName, serverP, socketPP); else { - ServerCreate(serverP, "XmlRpcServer", portNumber, DEFAULT_DOCS, + ServerCreate(serverP, "XmlRpcServer", portNumber, DEFAULT_DOCS, logFileName); - + *socketPP = NULL; } if (logFileName) @@ -922,14 +922,14 @@ chunkResponseParm(const xmlrpc_server_abyss_parms * const parmsP, return parmSize >= XMLRPC_APSIZE(chunk_response) && parmsP->chunk_response; -} +} static const char * uriPathParm(const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { - + const char * uriPath; if (parmSize >= XMLRPC_APSIZE(uri_path) && parmsP->uri_path) @@ -965,7 +965,7 @@ shutdownAbyss(xmlrpc_env * const envP, TServer * const serverP = context; xmlrpc_env_init(envP); - + ServerTerminate(serverP); } @@ -975,7 +975,7 @@ static void normalLevelAbyssRun(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { - + TServer server; TSocket * socketP = 0; @@ -992,18 +992,18 @@ normalLevelAbyssRun(xmlrpc_env * const envP, chunkResponseParm(parmsP, parmSize)); ServerInit(&server); - + setupSignalHandlers(&oldHandlers); ServerUseSigchld(&server); - + if (0) /* Too much of a security risk. In 1.07, there is a server parameter to enable this. */ xmlrpc_registry_set_shutdown(parmsP->registryP, &shutdownAbyss, &server); - + ServerRun(&server); restoreSignalHandlers(oldHandlers); @@ -1021,7 +1021,7 @@ void xmlrpc_server_abyss(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { - + XMLRPC_ASSERT_ENV_OK(envP); if (parmSize < XMLRPC_APSIZE(registryP)) @@ -1062,7 +1062,7 @@ static xmlrpc_registry * builtin_registryP; -void +void xmlrpc_server_abyss_init_registry(void) { /* This used to just create the registry and Caller would be @@ -1072,7 +1072,7 @@ xmlrpc_server_abyss_init_registry(void) { together; there's no sense in using the built-in registry and not the built-in handlers because if you're custom building something, you can just make your own regular registry. So now - we tie them together, and we don't export our handlers. + we tie them together, and we don't export our handlers. */ xmlrpc_env env; @@ -1099,7 +1099,7 @@ xmlrpc_server_abyss_registry(void) { /* A quick & easy shorthand for adding a method. */ -void +void xmlrpc_server_abyss_add_method(char * const method_name, xmlrpc_method const method, void * const user_data) { @@ -1127,20 +1127,20 @@ xmlrpc_server_abyss_add_method_w_doc(char * const method_name, &env, builtin_registryP, NULL, method_name, method, user_data, signature, help); die_if_fault_occurred(&env); - xmlrpc_env_clean(&env); + xmlrpc_env_clean(&env); } -void -xmlrpc_server_abyss_init(int const flags ATTR_UNUSED, +void +xmlrpc_server_abyss_init(int const flags ATTR_UNUSED, const char * const config_file) { DateInit(); MIMETypeInit(); ServerCreate(&globalSrv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); - + ConfReadServerFile(config_file, &globalSrv); xmlrpc_server_abyss_init_registry(); @@ -1153,16 +1153,16 @@ xmlrpc_server_abyss_init(int const flags ATTR_UNUSED, -void +void xmlrpc_server_abyss_run_first(runfirstFn const runfirst, void * const runfirstArg) { - + runServerDaemon(&globalSrv, runfirst, runfirstArg); } -void +void xmlrpc_server_abyss_run(void) { runServerDaemon(&globalSrv, NULL, NULL); } @@ -1181,8 +1181,8 @@ xmlrpc_server_abyss_run(void) { ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** +** derived from this software without specific prior written permission. +** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1195,6 +1195,6 @@ xmlrpc_server_abyss_run(void) { ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** -** There is more copyright information in the bottom half of this file. -** Please see it for more details. +** There is more copyright information in the bottom half of this file. +** Please see it for more details. */ diff --git a/modules/mi_xmlrpc/mi_xmlrpc.c b/modules/mi_xmlrpc/mi_xmlrpc.c index e79333a8cfa..875456c03c3 100644 --- a/modules/mi_xmlrpc/mi_xmlrpc.c +++ b/modules/mi_xmlrpc/mi_xmlrpc.c @@ -78,7 +78,7 @@ static int destroy(void); static void xmlrpc_process(int rank); static int port = 8080; -static char *log_file = NULL; +static char *log_file = NULL; static int read_buf_size = MAX_READ; static TServer srv; @@ -102,8 +102,10 @@ static param_export_t mi_params[] = { /* module exports */ struct module_exports exports = { "mi_xmlrpc", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ mi_params, /* exported parameters */ 0, /* exported statistics */ @@ -155,7 +157,7 @@ static void xmlrpc_sigchld( int sig ) break; } #ifndef XMLRPC_OLD_VERSION - else + else ServerHandleSigchld(pid); #endif } @@ -182,7 +184,7 @@ static void xmlrpc_process(int rank) xmlrpc_server_abyss_init_registry(); registryP= xmlrpc_server_abyss_registry(); #else - registryP = xmlrpc_registry_new(&env); + registryP = xmlrpc_registry_new(&env); #endif DateInit(); diff --git a/modules/mi_xmlrpc/xr_parser.c b/modules/mi_xmlrpc/xr_parser.c index 161e89c62ed..3c62c0e8a45 100644 --- a/modules/mi_xmlrpc/xr_parser.c +++ b/modules/mi_xmlrpc/xr_parser.c @@ -38,7 +38,7 @@ * Convert in argument string each LFLF to CRLF and return length of * the string not including the terminating `\0' character. * This is a hack that is needed as long as Abyss XML-RPC server "normalizes" - * CRLF to LF in XML-RPC strings. + * CRLF to LF in XML-RPC strings. */ int lflf_to_crlf_hack(char *s) { @@ -64,7 +64,7 @@ int lflf_to_crlf_hack(char *s) { struct mi_root * xr_parse_tree( xmlrpc_env * env, xmlrpc_value * paramArray ) { struct mi_root * mi_root; - + int size, i; size_t length; @@ -81,16 +81,16 @@ struct mi_root * xr_parse_tree( xmlrpc_env * env, xmlrpc_value * paramArray ) { char * stringValue = 0; char * byteStringValue =0; xmlrpc_value * item; - + mi_root = init_mi_tree(0, 0, 0); - + if ( !mi_root ) { LM_ERR("the MI tree cannot be initialized!\n"); goto error; } size = xmlrpc_array_size(env, paramArray); - + for (i=0 ; i< size ; i++) { item = xmlrpc_array_get_item(env, paramArray, i); @@ -98,14 +98,14 @@ struct mi_root * xr_parse_tree( xmlrpc_env * env, xmlrpc_value * paramArray ) { LM_ERR("failed to get array item: %s\n", env->fault_string); goto error; } - + switch ( xmlrpc_value_type(item) ) { - + case (XMLRPC_TYPE_INT): #ifdef XMLRPC_OLD_VERSION intValue = item->_value.i; - #else + #else xmlrpc_read_int(env,item,&intValue); #endif @@ -149,7 +149,7 @@ struct mi_root * xr_parse_tree( xmlrpc_env * env, xmlrpc_value * paramArray ) { case (XMLRPC_TYPE_STRING): #if HAVE_UNICODE_WCHAR - + #ifdef XMLRPC_OLD_VERSION xmlrpc_read_string_w(env, item, &stringValue); #else @@ -176,7 +176,7 @@ struct mi_root * xr_parse_tree( xmlrpc_env * env, xmlrpc_value * paramArray ) { LM_ERR("failed to add node to the MI tree.\n"); goto error; } - + break; case (XMLRPC_TYPE_BASE64): @@ -207,12 +207,12 @@ struct mi_root * xr_parse_tree( xmlrpc_env * env, xmlrpc_value * paramArray ) { (const unsigned char **)(void*)&byteStringValue); if ( env->fault_occurred ) { - LM_ERR("failed to read byteStringValue: %s!\n", + LM_ERR("failed to read byteStringValue: %s!\n", env->fault_string); goto error; } - if ( add_mi_node_child(&mi_root->node, MI_DUP_VALUE, 0, 0, + if ( add_mi_node_child(&mi_root->node, MI_DUP_VALUE, 0, 0, byteStringValue, length) == NULL ) { LM_ERR("failed to add node to the MI tree.\n"); goto error; @@ -225,13 +225,13 @@ struct mi_root * xr_parse_tree( xmlrpc_env * env, xmlrpc_value * paramArray ) { default : LM_ERR("unsupported node type %d\n", xmlrpc_value_type(item) ); - xmlrpc_env_set_fault_formatted( env, XMLRPC_TYPE_ERROR, + xmlrpc_env_set_fault_formatted( env, XMLRPC_TYPE_ERROR, "Unsupported value of type %d supplied", xmlrpc_value_type(item)); goto error; } } - + return mi_root; error: diff --git a/modules/mi_xmlrpc/xr_parser_lib.h b/modules/mi_xmlrpc/xr_parser_lib.h index a2dd1f1aa8c..38a7290d056 100644 --- a/modules/mi_xmlrpc/xr_parser_lib.h +++ b/modules/mi_xmlrpc/xr_parser_lib.h @@ -59,10 +59,10 @@ static char * xmlrpc_typeName ( xmlrpc_type type ) { } static void validateType ( xmlrpc_env * env, xmlrpc_value * value, xmlrpc_type expectedType ) { - + if ( value->_type != expectedType ) { xmlrpc_env_set_fault_formatted( - env, XMLRPC_TYPE_ERROR, "Value of type %s supplied where type %s was expected.", + env, XMLRPC_TYPE_ERROR, "Value of type %s supplied where type %s was expected.", xmlrpc_typeName(value->_type), xmlrpc_typeName(expectedType)); } } @@ -78,7 +78,7 @@ static void verifyNoNulls ( xmlrpc_env * env, char * content, unsigned int len ) } static void accessStringValue ( xmlrpc_env * env, xmlrpc_value * value, size_t * length, char ** contents ) { - + validateType(env, value, XMLRPC_TYPE_STRING); if ( !env->fault_occurred ) { @@ -104,10 +104,10 @@ static void xmlrpc_read_string( xmlrpc_env * env, xmlrpc_value * value, char ** accessStringValue(env, value, &length, &contents); if ( !env->fault_occurred ) { - + str = (char*) pkg_malloc (length+1); if ( str == NULL ) { - xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, + xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, "Unable to allocate space for %u-character string", length); LM_ERR("pkg_malloc cannot allocate any more memory!\n"); } @@ -127,7 +127,7 @@ static void verifyNoNullsW( xmlrpc_env * env, wchar_t * contents, unsigned int l for (i = 0; i < len && !env->fault_occurred; i++) if ( contents[i] == '\0' ) - xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR, + xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR, "String must not contain NULL characters."); } @@ -136,11 +136,11 @@ static void accessStringValueW (xmlrpc_env * env, xmlrpc_value * value, size_t * validateType(env, value, XMLRPC_TYPE_STRING); if ( !env->fault_occurred ) { - + if ( !env->fault_occurred ) { wchar_t * wcontents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, value->_wcs_block); size_t len = XMLRPC_TYPED_MEM_BLOCK_SIZE(wchar_t, value->_wcs_block) - 1; - + verifyNoNullsW(env, wcontents, len); *length = len; *stringValueW = wcontents; @@ -152,7 +152,7 @@ static void xmlrpc_read_string_w ( xmlrpc_env * env, xmlrpc_value * value, wchar size_t length; wchar_t * wcontents, * str; - + accessStringValueW(env, value, &length, &wcontents); if ( !env->fault_occurred ) { @@ -164,7 +164,7 @@ static void xmlrpc_read_string_w ( xmlrpc_env * env, xmlrpc_value * value, wchar str = (wchar_t*) pkg_malloc (length + 1); if ( str == NULL ){ - xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, + xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, "Unable to allocate space for %u-byte string", length); LM_ERR("pkg_malloc cannot allocate any more memory!\n"); } diff --git a/modules/mi_xmlrpc/xr_server.c b/modules/mi_xmlrpc/xr_server.c index 1362b182b2a..5926c48526a 100644 --- a/modules/mi_xmlrpc/xr_server.c +++ b/modules/mi_xmlrpc/xr_server.c @@ -154,13 +154,13 @@ static inline struct mi_handler* build_async_handler(void) #ifdef XMLRPC_OLD_VERSION -xmlrpc_value* default_method (xmlrpc_env* env, +xmlrpc_value* default_method (xmlrpc_env* env, char* host, char* methodName, xmlrpc_value* paramArray, void* serverInfo) #else -xmlrpc_value* default_method (xmlrpc_env* env, +xmlrpc_value* default_method (xmlrpc_env* env, const char* host, const char* methodName, xmlrpc_value* paramArray, @@ -177,11 +177,13 @@ xmlrpc_value* default_method (xmlrpc_env* env, LM_DBG("starting up.....\n"); + xr_writer_reset(); + f = lookup_mi_cmd((char*)methodName, strlen(methodName)); - + if ( f == 0 ) { LM_ERR("command %s is not available!\n", methodName); - xmlrpc_env_set_fault_formatted(env, XMLRPC_NO_SUCH_METHOD_ERROR, + xmlrpc_env_set_fault_formatted(env, XMLRPC_NO_SUCH_METHOD_ERROR, "Requested command (%s) is not available!", methodName); goto error; } @@ -220,14 +222,14 @@ xmlrpc_value* default_method (xmlrpc_env* env, if ((mi_rpl=run_mi_cmd(f,mi_cmd,(mi_flush_f*)xr_flush_response,env))==0){ LM_ERR("command (%s) processing failed.\n", methodName); - xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, + xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, "Command (%s) processing failed.\n", methodName); goto error; } else if (mi_rpl==MI_ROOT_ASYNC_RPL) { mi_rpl = wait_async_reply(hdl); hdl = 0; if (mi_rpl==0) { - xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, + xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, "Command (%s) processing failed (async).\n", methodName); goto error; } @@ -240,7 +242,7 @@ xmlrpc_value* default_method (xmlrpc_env* env, if ( xr_build_response_array( env, mi_rpl ) != 0 ){ if ( !env->fault_occurred ) { LM_ERR("failed parsing the xmlrpc response from the mi tree\n"); - xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR, + xmlrpc_env_set_fault(env, XMLRPC_INTERNAL_ERROR, "Failed to parse the xmlrpc response from the mi tree."); } goto error; diff --git a/modules/mi_xmlrpc/xr_writer.c b/modules/mi_xmlrpc/xr_writer.c index b756f595084..551b8277710 100644 --- a/modules/mi_xmlrpc/xr_writer.c +++ b/modules/mi_xmlrpc/xr_writer.c @@ -45,10 +45,15 @@ int xr_writer_init( unsigned int size ) LM_ERR("pkg_malloc cannot allocate any more memory!\n"); return -1; } - + return 0; } +void xr_writer_reset(void) +{ + *reply_buffer = '\0'; +} + #ifndef XMLRPC_HAS_FORCE_CHARS #define XMLRPC_NONXML_CHAR 0x7F @@ -89,7 +94,7 @@ static int xr_write_node(str * buf, struct mi_node * node) memcpy(p, node->value.s, node->value.len); p += node->value.len; } - + /* attributes */ for( attr=node->attributes ; attr!=NULL ; attr=attr->next ) { if ( attr->name.s != NULL ) { @@ -113,7 +118,7 @@ static int xr_write_node(str * buf, struct mi_node * node) return -1; *(p++) = '\n'; - buf->len -= p-buf->s; + buf->len -= p-buf->s; buf->s = p; return 0; } @@ -128,7 +133,7 @@ static int recur_build_response_array( xmlrpc_env * env, struct mi_node * tree, return -1; } - /* we are sure that this node has been written + /* we are sure that this node has been written * => avoid writing it again */ tree->flags |= MI_WRITTEN; } @@ -137,8 +142,8 @@ static int recur_build_response_array( xmlrpc_env * env, struct mi_node * tree, xmlrpc_force_to_xml_chars(reply_buffer); reply_item = xmlrpc_build_value(env, "s", reply_buffer); xmlrpc_array_append_item(env, xr_response, reply_item); - - buf->s = reply_buffer; + + buf->s = reply_buffer; buf->len = reply_buffer_len; if ( tree->kids ) { @@ -152,20 +157,20 @@ static int recur_build_response_array( xmlrpc_env * env, struct mi_node * tree, int xr_build_response_array( xmlrpc_env * env, struct mi_root * tree ) { str buf; - + buf.s = reply_buffer; buf.len = reply_buffer_len; /* test if mi root value is 200 OK (if not no point to continue) */ if ( tree->code<200 || tree->code>=300 ){ - LM_DBG("command processing failure: %s\n", tree->reason.s); + LM_DBG("command processing failure: %s\n", tree->reason.s); if (tree->reason.s) xmlrpc_env_set_fault(env, tree->code, tree->reason.s); else xmlrpc_env_set_fault(env, tree->code, "Error"); goto error; } - + if ( recur_build_response_array(env, (&tree->node)->kids, &buf) != 0 ) { LM_ERR("failed to read from the MI tree!\n"); xmlrpc_env_set_fault(env, 500, "Failed to write reply"); @@ -182,10 +187,10 @@ int xr_build_response_array( xmlrpc_env * env, struct mi_root * tree ) static int recur_flush_response_array(xmlrpc_env * env, struct mi_node *tree, str *buf) { - struct mi_node *kid, *tmp; + struct mi_node *kid, *tmp; int ret; - for(kid = tree->kids ; kid ; ){ + for(kid = tree->kids ; kid ; ){ /* write the current kid */ if (!(kid->flags & MI_WRITTEN)){ if (xr_write_node( buf, kid)!=0) { @@ -193,17 +198,17 @@ static int recur_flush_response_array(xmlrpc_env * env, struct mi_node *tree, return -1; } - /* we are sure that this node has been written + /* we are sure that this node has been written * => avoid writing it again */ kid->flags |= MI_WRITTEN; } - + reply_buffer[reply_buffer_len-buf->len] = 0; xmlrpc_force_to_xml_chars(reply_buffer); reply_item = xmlrpc_build_value(env, "s", reply_buffer); xmlrpc_array_append_item(env, xr_response, reply_item); - - buf->s = reply_buffer; + + buf->s = reply_buffer; buf->len = reply_buffer_len; /* write the current kid's children */ @@ -211,16 +216,13 @@ static int recur_flush_response_array(xmlrpc_env * env, struct mi_node *tree, return -1; else if (ret > 0) return ret; - + if (!(kid->flags & MI_NOT_COMPLETED)){ tmp = kid; kid = kid->next; tree->kids = kid; - if(!tmp->kids){ - /* this node does not have any kids */ - free_mi_node(tmp); - } + free_mi_node(tmp); } else{ /* the node will have more kids => to keep the tree shape, do not @@ -241,14 +243,14 @@ int xr_flush_response_array(xmlrpc_env * env, struct mi_root *tree) /* test if mi root value is 200 OK (if not no point to continue) */ if ( tree->code<200 || tree->code>=300 ){ - LM_DBG("command processing failure: %s\n", tree->reason.s); + LM_DBG("command processing failure: %s\n", tree->reason.s); if (tree->reason.s) xmlrpc_env_set_fault(env, tree->code, tree->reason.s); else xmlrpc_env_set_fault(env, tree->code, "Error"); goto error; } - + if ( recur_flush_response_array(env, (&tree->node)->kids, &buf) != 0 ) { LM_ERR("failed to read from the MI tree!\n"); xmlrpc_env_set_fault(env, 500, "Failed to write reply"); @@ -286,11 +288,11 @@ static int recur_build_response( xmlrpc_env * env, struct mi_node * tree, LM_ERR("failed to get MI node data!\n"); return -1; } - - /* we are sure that this node has been written - * => avoid writing it again */ - tree->flags |= MI_WRITTEN; } + + /* we are sure that this node has been written + * => avoid writing it again */ + tree->flags |= MI_WRITTEN; } if ( tree->kids ) { @@ -305,25 +307,27 @@ static int recur_build_response( xmlrpc_env * env, struct mi_node * tree, char* xr_build_response( xmlrpc_env * env, struct mi_root * tree ) { str buf; - - buf.s = reply_buffer; - buf.len = reply_buffer_len; + int len; + + len = strlen(reply_buffer); + buf.s = reply_buffer + len; + buf.len = reply_buffer_len - len; if ( tree->code<200 || tree->code>=300 ){ - LM_DBG("command processing failure: %s\n", tree->reason.s); + LM_DBG("command processing failure: %s\n", tree->reason.s); if (tree->reason.s) xmlrpc_env_set_fault(env, tree->code, tree->reason.s); else xmlrpc_env_set_fault(env, tree->code, "Error"); return 0; } - + if ( recur_build_response(env, (&tree->node)->kids, &buf) != 0 ) { LM_ERR("failed to read from the MI tree!\n"); xmlrpc_env_set_fault(env, 500, "Failed to build reply"); return 0; } - + reply_buffer[reply_buffer_len-buf.len] = 0; xmlrpc_force_to_xml_chars(reply_buffer); @@ -332,10 +336,19 @@ char* xr_build_response( xmlrpc_env * env, struct mi_root * tree ) static int recur_flush_response(xmlrpc_env * env, struct mi_node *tree, str *buf) { - struct mi_node *kid, *tmp; + struct mi_node *kid, *tmp; int ret; - for(kid = tree->kids ; kid ; ){ + if (!rpl_opt) { + if (recur_build_response(env, tree, buf) != 0) { + LM_ERR("failed to read from the MI tree!\n"); + return -1; + } + + return 0; + } + + for(kid = tree->kids ; kid ; ){ /* write the current kid */ if (!(kid->flags & MI_WRITTEN)){ if (xr_write_node( buf, kid)!=0) { @@ -356,25 +369,22 @@ static int recur_flush_response(xmlrpc_env * env, struct mi_node *tree, str *buf } } - /* we are sure that this node has been written + /* we are sure that this node has been written * => avoid writing it again */ kid->flags |= MI_WRITTEN; } - + if ((ret = recur_flush_response_array(env, kid, buf))<0) return -1; else if (ret > 0) return ret; - + if (!(kid->flags & MI_NOT_COMPLETED)){ tmp = kid; kid = kid->next; tree->kids = kid; - if(!tmp->kids){ - /* this node does not have any kids */ - free_mi_node(tmp); - } + free_mi_node(tmp); } else{ /* the node will have more kids => to keep the tree shape, do not @@ -389,25 +399,27 @@ static int recur_flush_response(xmlrpc_env * env, struct mi_node *tree, str *buf char* xr_flush_response( xmlrpc_env * env, struct mi_root * tree ) { str buf; - - buf.s = reply_buffer; - buf.len = reply_buffer_len; + int len; + + len = strlen(reply_buffer); + buf.s = reply_buffer + len; + buf.len = reply_buffer_len - len; if ( tree->code<200 || tree->code>=300 ){ - LM_DBG("command processing failure: %s\n", tree->reason.s); + LM_DBG("command processing failure: %s\n", tree->reason.s); if (tree->reason.s) xmlrpc_env_set_fault(env, tree->code, tree->reason.s); else xmlrpc_env_set_fault(env, tree->code, "Error"); return 0; } - + if ( recur_flush_response(env, (&tree->node)->kids, &buf) != 0 ) { LM_ERR("failed to read from the MI tree!\n"); xmlrpc_env_set_fault(env, 500, "Failed to build reply"); return 0; } - + reply_buffer[reply_buffer_len-buf.len] = 0; return reply_buffer; diff --git a/modules/mi_xmlrpc/xr_writer.h b/modules/mi_xmlrpc/xr_writer.h index 5ad208fa443..aef9e393dbf 100644 --- a/modules/mi_xmlrpc/xr_writer.h +++ b/modules/mi_xmlrpc/xr_writer.h @@ -34,6 +34,7 @@ #include "../../mi/tree.h" int xr_writer_init( unsigned int size ); +void xr_writer_reset(void); char * xr_build_response( xmlrpc_env * env, struct mi_root * tree ); char * xr_flush_response( xmlrpc_env * env, struct mi_root * tree ); int xr_build_response_array( xmlrpc_env * env, struct mi_root * tree ); diff --git a/modules/mi_xmlrpc_ng/Makefile b/modules/mi_xmlrpc_ng/Makefile new file mode 100644 index 00000000000..f54e5bc3334 --- /dev/null +++ b/modules/mi_xmlrpc_ng/Makefile @@ -0,0 +1,25 @@ +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=mi_xmlrpc_ng.so +LIBS= + +ifeq ($(CROSS_COMPILE),) +XML2CFG=$(shell which xml2-config) +endif + +ifneq ($(XML2CFG),) + DEFS += $(shell $(XML2CFG) --cflags) + LIBS += $(shell $(XML2CFG) --libs) +else + DEFS += -I$(SYSBASE)/include/libxml2 \ + -I$(LOCALBASE)/include/libxml2 \ + -I$(LOCALBASE)/include + LIBS += -L$(SYSBASE)/include/lib \ + -L$(LOCALBASE)/lib -lxml2 +endif + + +include ../../Makefile.modules + diff --git a/modules/mi_xmlrpc_ng/README b/modules/mi_xmlrpc_ng/README new file mode 100644 index 00000000000..d9dec8f9524 --- /dev/null +++ b/modules/mi_xmlrpc_ng/README @@ -0,0 +1,133 @@ +mi_xmlrpc_ng Module + +Ovidiu Sas + + + +Edited by + +Ovidiu Sas + + Copyright © 2013 VoIP Embedded, Inc. + Revision History + Revision $Rev$ $Date$ + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. Dependencies + + 1.2.1. External Libraries or Applications + 1.2.2. OpenSIPS Modules + + 1.3. Exported Parameters + + 1.3.1. mi_xmlrpc_ng_root(string) + + 1.4. Exported Functions + 1.5. Known issues + 1.6. Example + + List of Examples + + 1.1. Set mi_xmlrpc_ng_root parameter + 1.2. XMLRPC request + +Chapter 1. Admin Guide + +1.1. Overview + + This module implements a xmlrpc server that handles xmlrpc + requests and generates xmlrpc responses. When a xmlrpc message + is received a default method is executed. + + At first, it looks up the MI command. If found it parses the + called procedure's parameters into a MI tree and the command is + executed. A MI reply tree is returned that is formatted back in + xmlrpc. The response is built in two ways - like a string that + contains the MI tree nodes information (name, values and + attributes) or like an array whose elements are consisted of + each MI tree node stored information. + +1.2. Dependencies + +1.2.1. External Libraries or Applications + + The following libraries or applications must be installed + before running OpenSIPS with this module loaded: + * libxml2 + +1.2.2. OpenSIPS Modules + + The following modules must be loaded before this module: + * httpd module. + +1.3. Exported Parameters + +1.3.1. mi_xmlrpc_ng_root(string) + + Specifies the root path for xmlrpc requests: + http://[opensips_IP]:[opensips_httpd_port]/[mi_xmlrpc_ng_root] + + The default value is "xmlrpc". + + Example 1.1. Set mi_xmlrpc_ng_root parameter +... +modparam("mi_xmlrpc_ng", "mi_xmlrpc_ng_root", "opensips_mi_xmlrpc") +... + +1.4. Exported Functions + + No function exported to be used from configuration file. + +1.5. Known issues + + Commands with large responses (like ul_dump) will fail if the + configured size of the httpd buffer is to small (or if there + isn't enough pkg memory configured). + + Future realeases of the httpd and mi_xmlrpc_ng modules will + address this issue. + +1.6. Example + + This is an example showing the xmlrpc format for the + “get_statistics net: uri:” MI commad: response. + + Example 1.2. XMLRPC request + +POST /xmlrpc HTTP/1.0 +Host: my.host.com +User-Agent: My xmlrpc UA +Content-Type: text/xml +Content-Length: 216 + + + + get_statistics + + + net: + + + uri: + + + + + +HTTP/1.0 200 OK +Content-Length: 236 +Content-Type: text/xml; charset=utf-8 +Date: Mon, 8 Mar 2013 12:00:00 GMT + + +:: net:waiting_udp = 0 +:: net:waiting_tcp = 0 +:: uri:positive checks = 0 +:: uri:negative_checks = 0 + diff --git a/modules/mi_xmlrpc_ng/doc/mi_xmlrpc_ng.xml b/modules/mi_xmlrpc_ng/doc/mi_xmlrpc_ng.xml new file mode 100644 index 00000000000..3bc1bf18eb9 --- /dev/null +++ b/modules/mi_xmlrpc_ng/doc/mi_xmlrpc_ng.xml @@ -0,0 +1,50 @@ + + + + + + +%docentities; + +]> + + + + mi_xmlrpc_ng Module + &osipsname; + + + Ovidiu + Sas + osas@voipembedded.com + + + Ovidiu + Sas + + + + 2013 + + VoIP Embedded, Inc. + + + + + $Rev$ + $Date$ + + + + + + &admin; + &faq; + + + + diff --git a/modules/mi_xmlrpc_ng/doc/mi_xmlrpc_ng_admin.xml b/modules/mi_xmlrpc_ng/doc/mi_xmlrpc_ng_admin.xml new file mode 100644 index 00000000000..2476769e01a --- /dev/null +++ b/modules/mi_xmlrpc_ng/doc/mi_xmlrpc_ng_admin.xml @@ -0,0 +1,143 @@ + + + + + &adminguide; + +
+ Overview + + This module implements a xmlrpc server that handles xmlrpc + requests and generates xmlrpc responses. + When a xmlrpc message is received a default method is executed. + + + At first, it looks up the MI command. + If found it parses the called procedure's parameters + into a MI tree and the command is executed. + A MI reply tree is returned that is formatted back in xmlrpc. + The response is built in two ways - like a string that + contains the MI tree nodes information (name, values and + attributes) or like an array whose elements are consisted + of each MI tree node stored information. + +
+ +
+ Dependencies +
+ External Libraries or Applications + + The following libraries or applications must be installed before + running &osips; with this module loaded: + + + libxml2 + + + +
+
+ &osips; Modules + + The following modules must be loaded before this module: + + + httpd module. + + + +
+
+ +
+ Exported Parameters +
+ <varname>mi_xmlrpc_ng_root</varname>(string) + + Specifies the root path for xmlrpc requests: + http://[opensips_IP]:[opensips_httpd_port]/[mi_xmlrpc_ng_root] + + + The default value is "xmlrpc". + + + Set <varname>mi_xmlrpc_ng_root</varname> parameter + +... +modparam("mi_xmlrpc_ng", "mi_xmlrpc_ng_root", "opensips_mi_xmlrpc") +... + + +
+
+ +
+ Exported Functions + + No function exported to be used from configuration file. + +
+ +
+ Known issues + + Commands with large responses (like ul_dump) will fail if the + configured size of the httpd buffer is to small (or if there + isn't enough pkg memory configured). + + + Future realeases of the httpd and mi_xmlrpc_ng modules + will address this issue. + +
+ +
+ Example + + This is an example showing the xmlrpc format for the + get_statistics net: uri: MI commad: + response. + + + XMLRPC request + + + + get_statistics + + + net: + + + uri: + + + + + +HTTP/1.0 200 OK +Content-Length: 236 +Content-Type: text/xml; charset=utf-8 +Date: Mon, 8 Mar 2013 12:00:00 GMT + + +:: net:waiting_udp = 0 +:: net:waiting_tcp = 0 +:: uri:positive checks = 0 +:: uri:negative_checks = 0 + +]]> + + +
+ +
+ diff --git a/modules/mi_xmlrpc_ng/http_fnc.c b/modules/mi_xmlrpc_ng/http_fnc.c new file mode 100644 index 00000000000..bd75dc2d311 --- /dev/null +++ b/modules/mi_xmlrpc_ng/http_fnc.c @@ -0,0 +1,759 @@ +/* + * $Id$ + * + * Copyright (C) 2013 VoIP Embedded, Inc. + * + * This file is part of Open SIP Server (opensips). + * + * opensips is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * History: + * --------- + * 2013-03-04 first version (osas) + */ + + +#include + +#include "../../str.h" +#include "../../ut.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../../mi/mi.h" +#include "../../config.h" +#include "../../globals.h" +#include "../../locking.h" + +#include "http_fnc.h" + + +#define MI_XMLRPC_HTTP_XML_METHOD_CALL_NODE "methodCall" +#define MI_XMLRPC_HTTP_XML_METHOD_NAME_NODE "methodName" +#define MI_XMLRPC_HTTP_XML_PARAMS_NODE "params" +#define MI_XMLRPC_HTTP_XML_PARAM_NODE "param" +#define MI_XMLRPC_HTTP_XML_VALUE_NODE "value" +#define MI_XMLRPC_HTTP_XML_STRING_NODE "string" + +extern str http_root; + +mi_xmlrpc_http_page_data_t html_page_data; + +gen_lock_t* mi_xmlrpc_http_lock; + +#define MI_XMLRPC_HTTP_COPY(p,str) \ +do{ \ + if ((int)((p)-buf)+(str).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (str).s, (str).len); (p) += (str).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_2(p,str1,str2) \ +do{ \ + if ((int)((p)-buf)+(str1).len+(str2).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (str1).s, (str1).len); (p) += (str1).len; \ + memcpy((p), (str2).s, (str2).len); (p) += (str2).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_3(p,str1,str2,str3) \ +do{ \ + if ((int)((p)-buf)+(str1).len+(str2).len+(str3).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (str1).s, (str1).len); (p) += (str1).len; \ + memcpy((p), (str2).s, (str2).len); (p) += (str2).len; \ + memcpy((p), (str3).s, (str3).len); (p) += (str3).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_4(p,str1,str2,str3,str4) \ +do{ \ + if ((int)((p)-buf)+(str1).len+(str2).len+(str3).len+(str4).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (str1).s, (str1).len); (p) += (str1).len; \ + memcpy((p), (str2).s, (str2).len); (p) += (str2).len; \ + memcpy((p), (str3).s, (str3).len); (p) += (str3).len; \ + memcpy((p), (str4).s, (str4).len); (p) += (str4).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_5(p,s1,s2,s3,s4,s5) \ +do{ \ + if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (s1).s, (s1).len); (p) += (s1).len; \ + memcpy((p), (s2).s, (s2).len); (p) += (s2).len; \ + memcpy((p), (s3).s, (s3).len); (p) += (s3).len; \ + memcpy((p), (s4).s, (s4).len); (p) += (s4).len; \ + memcpy((p), (s5).s, (s5).len); (p) += (s5).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_6(p,s1,s2,s3,s4,s5,s6) \ +do{ \ + if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len+(s6).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (s1).s, (s1).len); (p) += (s1).len; \ + memcpy((p), (s2).s, (s2).len); (p) += (s2).len; \ + memcpy((p), (s3).s, (s3).len); (p) += (s3).len; \ + memcpy((p), (s4).s, (s4).len); (p) += (s4).len; \ + memcpy((p), (s5).s, (s5).len); (p) += (s5).len; \ + memcpy((p), (s6).s, (s6).len); (p) += (s6).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_7(p,s1,s2,s3,s4,s5,s6,s7) \ +do{ \ + if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len+(s6).len+(s7).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (s1).s, (s1).len); (p) += (s1).len; \ + memcpy((p), (s2).s, (s2).len); (p) += (s2).len; \ + memcpy((p), (s3).s, (s3).len); (p) += (s3).len; \ + memcpy((p), (s4).s, (s4).len); (p) += (s4).len; \ + memcpy((p), (s5).s, (s5).len); (p) += (s5).len; \ + memcpy((p), (s6).s, (s6).len); (p) += (s6).len; \ + memcpy((p), (s7).s, (s7).len); (p) += (s7).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_10(p,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10) \ +do{ \ + if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len+(s6).len+(s7).len+(s8).len+(s9).len+(s10).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (s1).s, (s1).len); (p) += (s1).len; \ + memcpy((p), (s2).s, (s2).len); (p) += (s2).len; \ + memcpy((p), (s3).s, (s3).len); (p) += (s3).len; \ + memcpy((p), (s4).s, (s4).len); (p) += (s4).len; \ + memcpy((p), (s5).s, (s5).len); (p) += (s5).len; \ + memcpy((p), (s6).s, (s6).len); (p) += (s6).len; \ + memcpy((p), (s7).s, (s7).len); (p) += (s7).len; \ + memcpy((p), (s8).s, (s8).len); (p) += (s8).len; \ + memcpy((p), (s9).s, (s9).len); (p) += (s9).len; \ + memcpy((p), (s10).s, (s10).len); (p) += (s10).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_11(p,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11) \ +do{ \ + if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len+(s6).len+(s7).len+(s8).len+(s9).len+(s10).len+(s11).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (s1).s, (s1).len); (p) += (s1).len; \ + memcpy((p), (s2).s, (s2).len); (p) += (s2).len; \ + memcpy((p), (s3).s, (s3).len); (p) += (s3).len; \ + memcpy((p), (s4).s, (s4).len); (p) += (s4).len; \ + memcpy((p), (s5).s, (s5).len); (p) += (s5).len; \ + memcpy((p), (s6).s, (s6).len); (p) += (s6).len; \ + memcpy((p), (s7).s, (s7).len); (p) += (s7).len; \ + memcpy((p), (s8).s, (s8).len); (p) += (s8).len; \ + memcpy((p), (s9).s, (s9).len); (p) += (s9).len; \ + memcpy((p), (s10).s, (s10).len); (p) += (s10).len; \ + memcpy((p), (s11).s, (s11).len); (p) += (s11).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_COPY_12(p,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12) \ +do{ \ + if ((int)((p)-buf)+(s1).len+(s2).len+(s3).len+(s4).len+(s5).len+(s6).len+(s7).len+(s8).len+(s9).len+(s10).len+(s11).len+(s12).len>max_page_len) { \ + goto error; \ + } \ + memcpy((p), (s1).s, (s1).len); (p) += (s1).len; \ + memcpy((p), (s2).s, (s2).len); (p) += (s2).len; \ + memcpy((p), (s3).s, (s3).len); (p) += (s3).len; \ + memcpy((p), (s4).s, (s4).len); (p) += (s4).len; \ + memcpy((p), (s5).s, (s5).len); (p) += (s5).len; \ + memcpy((p), (s6).s, (s6).len); (p) += (s6).len; \ + memcpy((p), (s7).s, (s7).len); (p) += (s7).len; \ + memcpy((p), (s8).s, (s8).len); (p) += (s8).len; \ + memcpy((p), (s9).s, (s9).len); (p) += (s9).len; \ + memcpy((p), (s10).s, (s10).len); (p) += (s10).len; \ + memcpy((p), (s11).s, (s11).len); (p) += (s11).len; \ + memcpy((p), (s12).s, (s12).len); (p) += (s12).len; \ +}while(0) + +#define MI_XMLRPC_HTTP_ESC_COPY(p,str,temp_holder,temp_counter) \ +do{ \ + (temp_holder).s = (str).s; \ + (temp_holder).len = 0; \ + for((temp_counter)=0;(temp_counter)<(str).len;(temp_counter)++) { \ + switch((str).s[(temp_counter)]) { \ + case '<': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_XMLRPC_HTTP_COPY_2(p, (temp_holder), MI_XMLRPC_HTTP_ESC_LT); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '>': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_XMLRPC_HTTP_COPY_2(p, (temp_holder), MI_XMLRPC_HTTP_ESC_GT); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '&': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_XMLRPC_HTTP_COPY_2(p, (temp_holder), MI_XMLRPC_HTTP_ESC_AMP); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '"': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_XMLRPC_HTTP_COPY_2(p, (temp_holder), MI_XMLRPC_HTTP_ESC_QUOT); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '\'': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_XMLRPC_HTTP_COPY_2(p, (temp_holder), MI_XMLRPC_HTTP_ESC_SQUOT); \ + (temp_holder).s += (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + } \ + } \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + MI_XMLRPC_HTTP_COPY(p, (temp_holder)); \ +}while(0) + + +static const str MI_XMLRPC_HTTP_CR = str_init("\n"); +static const str MI_XMLRPC_HTTP_SLASH = str_init("/"); +static const str MI_XMLRPC_HTTP_SEMICOLON = str_init(" : "); + +static const str MI_XMLRPC_HTTP_NODE_INDENT = str_init("\t"); +static const str MI_XMLRPC_HTTP_NODE_SEPARATOR = str_init(":: "); +static const str MI_XMLRPC_HTTP_ATTR_SEPARATOR = str_init(" "); +static const str MI_XMLRPC_HTTP_ATTR_VAL_SEPARATOR = str_init("="); + +static const str MI_XMLRPC_HTTP_XML_START = str_init("\r\n\r\n\r\n"); +static const str MI_XMLRPC_HTTP_XML_STOP = str_init("" +"\r\n\r\n\r\n"); + +static const str MI_XMLRPC_HTTP_ESC_LT = str_init("<"); /* < */ +static const str MI_XMLRPC_HTTP_ESC_GT = str_init(">"); /* > */ +static const str MI_XMLRPC_HTTP_ESC_AMP = str_init("&"); /* & */ +static const str MI_XMLRPC_HTTP_ESC_QUOT = str_init("""); /* " */ +static const str MI_XMLRPC_HTTP_ESC_SQUOT = str_init("'"); /* ' */ + + +int mi_xmlrpc_http_init_async_lock(void) +{ + mi_xmlrpc_http_lock = lock_alloc(); + if (mi_xmlrpc_http_lock==NULL) { + LM_ERR("failed to create lock\n"); + return -1; + } + if (lock_init(mi_xmlrpc_http_lock)==NULL) { + LM_ERR("failed to init lock\n"); + return -1; + } + return 0; +} + +/* +xmlAttrPtr mi_xmlNodeGetAttrByName(xmlNodePtr node, const char *name) +{ + xmlAttrPtr attr = node->properties; + while (attr) { + if(xmlStrcasecmp(attr->name, (const xmlChar*)name)==0) + return attr; + attr = attr->next; + } + return NULL; +} +*/ + +/* +xmlNodePtr mi_xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name) +{ + xmlAttrPtr attr = ph_xmlNodeGetAttrByName(node, name); + if (attr) return (char*)xmlNodeGetContent(attr->children); + else return NULL; +} +*/ + +xmlNodePtr mi_xmlNodeGetNodeByName(xmlNodePtr node, const char *name) +{ + xmlNodePtr cur = node; + while (cur) { + if(xmlStrcasecmp(cur->name, (const xmlChar*)name)==0) + return cur; + cur = cur->next; + } + return NULL; +} + +/* +char *ph_xmlNodeGetNodeContentByName(xmlNodePtr node, const char *name) +{ + xmlNodePtr node1 = mi_xmlNodeGetNodeByName(node, name); + if (node1) return (char*)xmlNodeGetContent(node1); + else return NULL; +} +*/ + +void mi_xmlrpc_http_destroy_async_lock(void) +{ + if (mi_xmlrpc_http_lock) { + lock_destroy(mi_xmlrpc_http_lock); + lock_dealloc(mi_xmlrpc_http_lock); + } +} + + +static int mi_xmlrpc_http_recur_flush_tree(char** pointer, char *buf, int max_page_len, + struct mi_node *tree, int level); + +int mi_xmlrpc_http_flush_content(str *page, int max_page_len, + struct mi_root* tree); + + + +int mi_xmlrpc_http_flush_tree(void* param, struct mi_root *tree) +{ + if (param==NULL) { + LM_CRIT("null param\n"); + return 0; + } + mi_xmlrpc_http_page_data_t* html_p_data = (mi_xmlrpc_http_page_data_t*)param; + mi_xmlrpc_http_flush_content(&html_p_data->page, + html_p_data->buffer.len, + tree); + return 0; +} + + +static void mi_xmlrpc_http_close_async(struct mi_root *mi_rpl, struct mi_handler *hdl, int done) +{ + struct mi_root *shm_rpl = NULL; + gen_lock_t* lock; + mi_xmlrpc_http_async_resp_data_t *async_resp_data; + + if (hdl==NULL) { + LM_CRIT("null mi handler\n"); + return; + } + + LM_DBG("mi_root [%p], hdl [%p], hdl->param [%p], " + "*hdl->param [%p] and done [%u]\n", + mi_rpl, hdl, hdl->param, *(struct mi_root **)hdl->param, done); + + if (!done) { + /* we do not pass provisional stuff (yet) */ + if (mi_rpl) free_mi_tree( mi_rpl ); + return; + } + + async_resp_data = + (mi_xmlrpc_http_async_resp_data_t*)((char*)hdl+sizeof(struct mi_handler)); + lock = async_resp_data->lock; + lock_get(lock); + if (mi_rpl!=NULL && (shm_rpl=clone_mi_tree( mi_rpl, 1))!=NULL) { + *(struct mi_root **)hdl->param = shm_rpl; + } else { + LM_WARN("Unable to process async reply [%p]\n", mi_rpl); + /* mark it as invalid */ + hdl->param = NULL; + } + LM_DBG("shm_rpl [%p], hdl [%p], hdl->param [%p], *hdl->param [%p]\n", + shm_rpl, hdl, hdl->param, + (hdl->param)?*(struct mi_root **)hdl->param:NULL); + lock_release(lock); + + if (mi_rpl) free_mi_tree(mi_rpl); + + return; +} + +static inline struct mi_handler* mi_xmlrpc_http_build_async_handler(void) +{ + struct mi_handler *hdl; + mi_xmlrpc_http_async_resp_data_t *async_resp_data; + unsigned int len; + + len = sizeof(struct mi_handler)+sizeof(mi_xmlrpc_http_async_resp_data_t); + hdl = (struct mi_handler*)shm_malloc(len); + if (hdl==NULL) { + LM_ERR("oom\n"); + return NULL; + } + + memset(hdl, 0, len); + async_resp_data = + (mi_xmlrpc_http_async_resp_data_t*)((char*)hdl+sizeof(struct mi_handler)); + + hdl->handler_f = mi_xmlrpc_http_close_async; + hdl->param = (void*)&async_resp_data->tree; + + async_resp_data->lock = mi_xmlrpc_http_lock; + + LM_DBG("hdl [%p], hdl->param [%p], *hdl->param [%p] mi_xmlrpc_http_lock=[%p]\n", + hdl, hdl->param, (hdl->param)?*(struct mi_root **)hdl->param:NULL, + async_resp_data->lock); + + return hdl; +} + +struct mi_root* mi_xmlrpc_http_run_mi_cmd(const str* arg, + str *page, str *buffer, struct mi_handler **async_hdl) +{ + struct mi_cmd *f; + struct mi_node *node; + struct mi_root *mi_cmd; + struct mi_root *mi_rpl; + struct mi_handler *hdl; + str miCmd; + xmlDocPtr doc; + xmlNodePtr methodCall_node; + xmlNodePtr methodName_node; + xmlNodePtr params_node; + xmlNodePtr param_node; + xmlNodePtr value_node; + xmlNodePtr string_node; + str val; + + //LM_DBG("arg [%p]->[%.*s]\n", arg->s, arg->len, arg->s); + doc = xmlParseMemory(arg->s, arg->len); + if(doc==NULL){ + LM_ERR("Failed to parse xml document: [%s]\n", arg->s); + return NULL; + } + methodCall_node = mi_xmlNodeGetNodeByName(doc->children, + MI_XMLRPC_HTTP_XML_METHOD_CALL_NODE); + if (methodCall_node==NULL) { + LM_ERR("missing node %s\n", MI_XMLRPC_HTTP_XML_METHOD_CALL_NODE); + goto xml_error; + } + methodName_node = mi_xmlNodeGetNodeByName(methodCall_node->children, + MI_XMLRPC_HTTP_XML_METHOD_NAME_NODE); + if (methodName_node==NULL) { + LM_ERR("missing node %s\n", MI_XMLRPC_HTTP_XML_METHOD_NAME_NODE); + goto xml_error; + } + miCmd.s = (char*)xmlNodeGetContent(methodName_node); + if (miCmd.s==NULL) { + LM_ERR("missing content for node %s\n", + MI_XMLRPC_HTTP_XML_METHOD_NAME_NODE); + goto xml_error; + } + miCmd.len = strlen(miCmd.s); + LM_DBG("got methodName=%.*s\n", miCmd.len, miCmd.s); + + f = lookup_mi_cmd(miCmd.s, miCmd.len); + if (f == NULL) { + LM_ERR("unable to find mi command [%.*s]\n", miCmd.len, miCmd.s); + goto xml_error; + } + + if (f->flags&MI_ASYNC_RPL_FLAG) { + /* We need to build an async handler */ + hdl = mi_xmlrpc_http_build_async_handler(); + if (hdl==NULL) { + LM_ERR("failed to build async handler\n"); + goto xml_error; + } + } else { + hdl = NULL; + } + *async_hdl = hdl; + + if (f->flags&MI_NO_INPUT_FLAG) { + mi_cmd = NULL; + } else { + if (arg->s) { + mi_cmd = init_mi_tree(0,0,0); + if (mi_cmd==NULL) { + LM_ERR("the MI tree cannot be initialized!\n"); + goto xml_error; + } + params_node = mi_xmlNodeGetNodeByName(methodCall_node->children, + MI_XMLRPC_HTTP_XML_PARAMS_NODE); + if (params_node==NULL) { + LM_ERR("missing node %s\n", MI_XMLRPC_HTTP_XML_PARAMS_NODE); + goto xml_error; + } + for(param_node=params_node->children; + param_node;param_node=param_node->next){ + if (xmlStrcasecmp(param_node->name, + (const xmlChar*)MI_XMLRPC_HTTP_XML_PARAM_NODE) == 0) { + value_node = mi_xmlNodeGetNodeByName(param_node->children, + MI_XMLRPC_HTTP_XML_VALUE_NODE); + if (value_node==NULL) { + LM_ERR("missing node %s\n", + MI_XMLRPC_HTTP_XML_VALUE_NODE); + goto xml_error; + } + string_node = mi_xmlNodeGetNodeByName(value_node->children, + MI_XMLRPC_HTTP_XML_STRING_NODE); + if (string_node==NULL) { + LM_ERR("missing node %s\n", + MI_XMLRPC_HTTP_XML_STRING_NODE); + goto xml_error; + } + val.s = (char*)xmlNodeGetContent(string_node); + if(val.s==NULL){ + LM_ERR("No content for node [%s]\n", + string_node->name); + goto xml_error; + } + val.len = strlen(val.s); + if(val.len==0){ + LM_ERR("Empty content for node [%s]\n", + string_node->name); + goto xml_error; + } + LM_DBG("got string param [%.*s]\n", val.len, val.s); + node = &mi_cmd->node; + if(!add_mi_node_child(node,0,NULL,0,val.s,val.len)){ + LM_ERR("cannot add the child node to the tree\n"); + free_mi_tree(mi_cmd); + goto xml_error; + } + } + } + mi_cmd->async_hdl = hdl; + } else { + mi_cmd = NULL; + } + } + + html_page_data.page.s = buffer->s; + html_page_data.page.len = 0; + html_page_data.buffer.s = buffer->s; + html_page_data.buffer.len = buffer->len; + + mi_rpl = run_mi_cmd(f, mi_cmd, + (mi_flush_f *)mi_xmlrpc_http_flush_tree, &html_page_data); + if (mi_rpl == NULL) { + LM_ERR("failed to process the command\n"); + if (mi_cmd) free_mi_tree(mi_cmd); + goto xml_error; + } else if (mi_rpl != MI_ROOT_ASYNC_RPL) { + *page = html_page_data.page; + } + LM_DBG("got mi_rpl=[%p]\n",mi_rpl); + + if (mi_cmd) free_mi_tree(mi_cmd); + if(doc)xmlFree(doc);doc=NULL; + return mi_rpl; + +xml_error: + if(doc)xmlFree(doc);doc=NULL; + return NULL; +} + + +static inline int mi_xmlrpc_http_write_node(char** pointer, char* buf, int max_page_len, + struct mi_node *node, int level) +{ + struct mi_attr *attr; + str temp_holder; + int temp_counter; + int insert_node_separator; + + /* name and value */ + if (node->name.s!=NULL) { + for(;level>0;level--) { + MI_XMLRPC_HTTP_COPY(*pointer, + MI_XMLRPC_HTTP_NODE_INDENT); + } + MI_XMLRPC_HTTP_COPY(*pointer, + node->name); + insert_node_separator = 1; + } else { + insert_node_separator = 0; + } + if (node->value.s!=NULL) { + if (insert_node_separator) { + MI_XMLRPC_HTTP_COPY(*pointer, + MI_XMLRPC_HTTP_NODE_SEPARATOR); + insert_node_separator = 0; + } + MI_XMLRPC_HTTP_ESC_COPY(*pointer, node->value, + temp_holder, temp_counter); + } + /* attributes */ + for(attr=node->attributes;attr!=NULL;attr=attr->next) { + if (insert_node_separator) { + MI_XMLRPC_HTTP_COPY(*pointer, + MI_XMLRPC_HTTP_NODE_SEPARATOR); + insert_node_separator = 0; + } + if (attr->name.s!=NULL) { + MI_XMLRPC_HTTP_COPY_3(*pointer, + MI_XMLRPC_HTTP_ATTR_SEPARATOR, + attr->name, + MI_XMLRPC_HTTP_ATTR_VAL_SEPARATOR); + MI_XMLRPC_HTTP_ESC_COPY(*pointer, attr->value, + temp_holder, temp_counter); + } + } + MI_XMLRPC_HTTP_COPY(*pointer, MI_XMLRPC_HTTP_CR); + return 0; +error: + LM_ERR("buffer 2 small: *pointer=[%p] buf=[%p] max_page_len=[%d]\n", + *pointer, buf, max_page_len); + return -1; +} + + +static int mi_xmlrpc_http_recur_flush_tree(char** pointer, char *buf, int max_page_len, + struct mi_node *tree, int level) +{ + struct mi_node *kid, *tmp; + int ret; + + for(kid = tree->kids ; kid ; ){ + if (!(kid->flags & MI_WRITTEN)) { + if (mi_xmlrpc_http_write_node(pointer, buf, max_page_len, + kid, level)!=0) + return -1; + kid->flags |= MI_WRITTEN; + } + if ((ret = mi_xmlrpc_http_recur_flush_tree(pointer, buf, max_page_len, + tree->kids, level+1))<0){ + return -1; + } else if (ret > 0) { + return ret; + } + if (!(kid->flags & MI_NOT_COMPLETED)){ + tmp = kid; + kid = kid->next; + tree->kids = kid; + + if(!tmp->kids){ + /* this node does not have any kids */ + free_mi_node(tmp); + } + } else { + /* the node will have more kids => + * to keep the tree shape, + * do not flush any other node for now */ + return 1; + } + } + return 0; +} + + +static int mi_xmlrpc_http_recur_write_tree(char** pointer, char *buf, int max_page_len, + struct mi_node *tree, int level) +{ + for( ; tree ; tree=tree->next ) { + if (!(tree->flags & MI_WRITTEN)) { + if (mi_xmlrpc_http_write_node(pointer, buf, max_page_len, + tree, level)!=0){ + return -1; + } + } + if (tree->kids) { + if (mi_xmlrpc_http_recur_write_tree(pointer, buf, max_page_len, + tree->kids, level+1)<0){ + return -1; + } + } + } + return 0; +} + + +int mi_xmlrpc_http_build_header(str *page, int max_page_len, + struct mi_root *tree, int flush) +{ + char *p, *buf; + + if (page->s == NULL) { + LM_ERR("Please provide a valid page\n"); + return -1; + } + p = buf = page->s; + + if (tree) { + LM_DBG("return code: %d\n", tree->code); + if (!(tree->node.flags & MI_WRITTEN)) { + MI_XMLRPC_HTTP_COPY(p, MI_XMLRPC_HTTP_XML_START); + tree->node.flags |= MI_WRITTEN; + } + if (flush) { + if (mi_xmlrpc_http_recur_flush_tree(&p, buf, max_page_len, + &tree->node, 0)<0) + return -1; + } else { + if (mi_xmlrpc_http_recur_write_tree(&p, buf, max_page_len, + tree->node.kids, 0)<0) + return -1; + } + MI_XMLRPC_HTTP_COPY(p, MI_XMLRPC_HTTP_XML_STOP); + } + + page->len = p - page->s; + return 0; +error: + LM_ERR("buffer 2 small\n"); + page->len = p - page->s; + return -1; +} + + +int mi_xmlrpc_http_build_content(str *page, int max_page_len, + struct mi_root* tree) +{ + char *p, *buf; + + if (page->len==0) { + if (0!=mi_xmlrpc_http_build_header(page, max_page_len, tree, 0)) + return -1; + } else { + buf = page->s; + p = page->s + page->len; + + if (tree) { /* Build mi reply */ + if (mi_xmlrpc_http_recur_write_tree(&p, buf, max_page_len, + tree->node.kids, 0)<0) + return -1; + page->len = p - page->s; + } + } + return 0; +} + + +int mi_xmlrpc_http_build_page(str *page, int max_page_len, + struct mi_root *tree) +{ + if (0!=mi_xmlrpc_http_build_content(page, max_page_len, tree)) + return -1; + return 0; +} + + +int mi_xmlrpc_http_flush_content(str *page, int max_page_len, + struct mi_root* tree) +{ + char *p, *buf; + + if (page->len==0) + if (0!=mi_xmlrpc_http_build_header(page, max_page_len, tree, 1)) + return -1; + buf = page->s; + p = page->s + page->len; + + if (tree) { /* Build mi reply */ + if (mi_xmlrpc_http_recur_flush_tree(&p, buf, max_page_len, + &tree->node, 0)<0) + return -1; + page->len = p - page->s; + } + return 0; +} diff --git a/modules/mi_xmlrpc_ng/http_fnc.h b/modules/mi_xmlrpc_ng/http_fnc.h new file mode 100644 index 00000000000..d6f03449542 --- /dev/null +++ b/modules/mi_xmlrpc_ng/http_fnc.h @@ -0,0 +1,52 @@ +/* + * $Id$ + * + * Copyright (C) 2013 VoIP Embedded Inc. + * + * This file is part of Open SIP Server (opensips). + * + * opensips is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * History: + * --------- + * 2013-03-04 first version (osas) + */ + + +#ifndef _MI_XMLRPC_HTTP_HTTP_FNC_H +#define _MI_XMLRPC_HTTP_HTTP_FNC_H + + +typedef struct mi_xmlrpc_http_html_page_data_ { + str page; + str buffer; +}mi_xmlrpc_http_page_data_t; + +typedef struct mi_xmlrpc_http_async_resp_data_ { + gen_lock_t* lock; + struct mi_root* tree; +}mi_xmlrpc_http_async_resp_data_t; + + +int mi_xmlrpc_http_init_async_lock(void); +void mi_xmlrpc_http_destroy_async_lock(void); + +struct mi_root* mi_xmlrpc_http_run_mi_cmd(const str* arg, + str *page, str *buffer, struct mi_handler **async_hdl); +int mi_xmlrpc_http_build_page(str* page, int max_page_len, + struct mi_root* tree); + +#endif + diff --git a/modules/mi_xmlrpc_ng/mi_xmlrpc_http.c b/modules/mi_xmlrpc_ng/mi_xmlrpc_http.c new file mode 100644 index 00000000000..7904babcc51 --- /dev/null +++ b/modules/mi_xmlrpc_ng/mi_xmlrpc_http.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2013 VoIP Embedded Inc. + * + * This file is part of Open SIP Server (opensips). + * + * opensips is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * History: + * --------- + * 2013-03-04 first version (osas) + */ + +#include + +#include "../../globals.h" +#include "../../sr_module.h" +#include "../../str.h" +#include "../../ut.h" +#include "../../resolve.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../httpd/httpd_load.h" +#include "http_fnc.h" + +/* module functions */ +static int mod_init(); +static int destroy(void); +void mi_xmlrpc_http_answer_to_connection (void *cls, void *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **con_cls, + str *buffer, str *page); +static ssize_t mi_xmlrpc_http_flush_data(void *cls, uint64_t pos, char *buf, size_t max); + +str http_root = str_init("xmlrpc"); +httpd_api_t httpd_api; + + +static const str MI_HTTP_U_ERROR = str_init("" +"Internal server error!"); +static const str MI_HTTP_U_METHOD = str_init("" +"Unexpected method (only POST is accepted)!"); + + +/* module parameters */ +static param_export_t mi_params[] = { + {"mi_xmlrpc_ng_root", STR_PARAM, &http_root.s}, + {0,0,0} +}; + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "httpd", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + +/* module exports */ +struct module_exports exports = { + "mi_xmlrpc_ng", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ + MODULE_VERSION, + DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ + NULL, /* exported functions */ + mi_params, /* exported parameters */ + NULL, /* exported statistics */ + NULL, /* exported MI functions */ + NULL, /* exported PV */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + (response_function) 0, /* response handling function */ + (destroy_function) destroy, /* destroy function */ + NULL /* per-child init function */ +}; + + +void proc_init(void) +{ + /* Build async lock */ + if (mi_xmlrpc_http_init_async_lock() != 0) + exit(-1); + + return; +} + +static int mod_init(void) +{ + http_root.len = strlen(http_root.s); + + /* Load httpd api */ + if(load_httpd_api(&httpd_api)<0) { + LM_ERR("Failed to load httpd api\n"); + return -1; + } + /* Load httpd hooks */ + httpd_api.register_httpdcb(exports.name, &http_root, + &mi_xmlrpc_http_answer_to_connection, + &mi_xmlrpc_http_flush_data, + &proc_init); + + return 0; +} + + +int destroy(void) +{ + mi_xmlrpc_http_destroy_async_lock(); + return 0; +} + + + +static ssize_t mi_xmlrpc_http_flush_data(void *cls, uint64_t pos, char *buf, size_t max) +{ + struct mi_handler *hdl = (struct mi_handler*)cls; + gen_lock_t *lock; + mi_xmlrpc_http_async_resp_data_t *async_resp_data; + str page = {NULL, 0}; + + if (hdl==NULL) { + LM_ERR("Unexpected NULL mi handler!\n"); + return -1; + } + LM_DBG("hdl=[%p], hdl->param=[%p], pos=[%d], buf=[%p], max=[%d]\n", + hdl, hdl->param, (int)pos, buf, (int)max); + + if (pos){ + LM_DBG("freeing hdl=[%p]: hdl->param=[%p], " + " pos=[%d], buf=[%p], max=[%d]\n", + hdl, hdl->param, (int)pos, buf, (int)max); + shm_free(hdl); + return -1; + } + async_resp_data = + (mi_xmlrpc_http_async_resp_data_t*)((char*)hdl+sizeof(struct mi_handler)); + lock = async_resp_data->lock; + lock_get(lock); + if (hdl->param) { + if (*(struct mi_root**)hdl->param) { + page.s = buf; + LM_DBG("tree=[%p]\n", *(struct mi_root**)hdl->param); + if (mi_xmlrpc_http_build_page(&page, max, + *(struct mi_root**)hdl->param)!=0){ + LM_ERR("Unable to build response\n"); + shm_free(*(void**)hdl->param); + *(void**)hdl->param = NULL; + lock_release(lock); + memcpy(buf, MI_HTTP_U_ERROR.s, MI_HTTP_U_ERROR.len); + return MI_HTTP_U_ERROR.len; + } else { + shm_free(*(void**)hdl->param); + *(void**)hdl->param = NULL; + lock_release(lock); + return page.len; + } + } else { + LM_DBG("data not ready yet\n"); + lock_release(lock); + return 0; + } + } else { + lock_release(lock); + LM_ERR("Invalid async reply\n"); + memcpy(buf, MI_HTTP_U_ERROR.s, MI_HTTP_U_ERROR.len); + return MI_HTTP_U_ERROR.len; + } + lock_release(lock); + LM_CRIT("done?\n"); + shm_free(hdl); + return -1; +} + +void mi_xmlrpc_http_answer_to_connection (void *cls, void *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **con_cls, + str *buffer, str *page) +{ + str arg = {NULL, 0}; + struct mi_root *tree = NULL; + struct mi_handler *async_hdl; + + LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, " + "versio=%s, upload_data[%d]=%p, *con_cls=%p\n", + cls, connection, url, method, version, + (int)*upload_data_size, upload_data, *con_cls); + if (strncmp(method, "POST", 4)==0) { + httpd_api.lookup_arg(connection, "1", *con_cls, &arg); + if (arg.s) { + tree = mi_xmlrpc_http_run_mi_cmd(&arg, + page, buffer, &async_hdl); + if (tree == NULL) { + LM_ERR("no reply\n"); + *page = MI_HTTP_U_ERROR; + } else if (tree == MI_ROOT_ASYNC_RPL) { + LM_DBG("got an async reply\n"); + tree = NULL; + } else { + LM_DBG("building on page [%p:%d]\n", + page->s, page->len); + if(0!=mi_xmlrpc_http_build_page(page, buffer->len, tree)){ + LM_ERR("unable to build response\n"); + *page = MI_HTTP_U_ERROR; + } + } + } else { + page->s = buffer->s; + LM_ERR("unable to build response for empty request\n"); + *page = MI_HTTP_U_ERROR; + } + if (tree) { + free_mi_tree(tree); + tree = NULL; + } + } else { + LM_ERR("unexpected method [%s]\n", method); + *page = MI_HTTP_U_METHOD; + } + + return; +} + diff --git a/modules/mmgeoip/README b/modules/mmgeoip/README index ea8fd49c084..9ef9066b4ca 100644 --- a/modules/mmgeoip/README +++ b/modules/mmgeoip/README @@ -10,8 +10,7 @@ Kobi Eshun Copyright © 2008 SightSpeed, Inc. Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/mmgeoip/mmgeoip.c b/modules/mmgeoip/mmgeoip.c index ad27984b457..691cb85bc7b 100644 --- a/modules/mmgeoip/mmgeoip.c +++ b/modules/mmgeoip/mmgeoip.c @@ -21,7 +21,7 @@ * -------- * 080511 -- Initial revision, KE * - * XXX -- todo: Add command variant to pull source/dest IP from + * XXX -- todo: Add command variant to pull source/dest IP from * current SIP message. * */ @@ -43,7 +43,7 @@ static str MMG_city_db_path = {NULL, 0}; static GeoIP *MMG_gi = NULL; static int -mod_init(void) +mod_init(void) { LM_INFO("MM GeoIP module - initializing\n"); @@ -192,14 +192,14 @@ mmg_lookup_cmd(struct sip_msg *msg, char *_fields_pv, char *_ipaddr_pv, char *_d token=strtok_r(field_buf,MMG_OP_DELIMS,&saveptr); while (token) { if(!strcmp(token,"lat")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%f",gir->latitude); } - else if(!strcmp(token,"lon")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%f",gir->longitude); } - else if(!strcmp(token,"cont")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->continent_code); } - else if(!strcmp(token,"cc")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->country_code); } - else if(!strcmp(token,"reg")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->region); } - else if(!strcmp(token,"city")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->city); } - else if(!strcmp(token,"pc")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->postal_code); } - else if(!strcmp(token,"dma")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%d",gir->dma_code); } - else if(!strcmp(token,"ac")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%d",gir->area_code); } + else if(!strcmp(token,"lon")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%f",gir->longitude); } + else if(!strcmp(token,"cont")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->continent_code); } + else if(!strcmp(token,"cc")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->country_code); } + else if(!strcmp(token,"reg")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->region); } + else if(!strcmp(token,"city")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->city); } + else if(!strcmp(token,"pc")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%s",gir->postal_code); } + else if(!strcmp(token,"dma")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%d",gir->dma_code); } + else if(!strcmp(token,"ac")) { rslt.s.len=snprintf(rslt_buf,sizeof rslt_buf,"%d",gir->area_code); } else if(!strcmp(token,"rbc")) { rslt.s.len=snprintf( rslt_buf,sizeof rslt_buf,"%s",GeoIP_region_name_by_code(gir->country_code, gir->region)); @@ -250,8 +250,10 @@ static cmd_export_t cmds[] = { struct module_exports exports= { "mmgeoip", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module's name */ DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ mod_params, /* param exports */ 0, /* exported statistics */ diff --git a/modules/msilo/README b/modules/msilo/README index 2dd4dfe0b63..b9832878c38 100644 --- a/modules/msilo/README +++ b/modules/msilo/README @@ -12,8 +12,7 @@ Daniel-Constantin Mierla Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -458,7 +457,7 @@ modparam("msilo", "sc_snd_time", "send_reminder_time") Example 1.24. Set the “snd_time_avp” parameter ... -modparam("msilo", "snd_time_avp", "$avp(i:123)") +modparam("msilo", "snd_time_avp", "$avp(snd_time)") ... 1.3.25. add_date (int) diff --git a/modules/msilo/doc/msilo_admin.xml b/modules/msilo/doc/msilo_admin.xml index 4d6e4a50a08..ff421bdc39c 100644 --- a/modules/msilo/doc/msilo_admin.xml +++ b/modules/msilo/doc/msilo_admin.xml @@ -531,7 +531,7 @@ modparam("msilo", "sc_snd_time", "send_reminder_time") Set the <quote>snd_time_avp</quote> parameter ... -modparam("msilo", "snd_time_avp", "$avp(i:123)") +modparam("msilo", "snd_time_avp", "$avp(snd_time)") ... diff --git a/modules/msilo/ms_msg_list.c b/modules/msilo/ms_msg_list.c index b4c9f800258..a14efe70552 100644 --- a/modules/msilo/ms_msg_list.c +++ b/modules/msilo/ms_msg_list.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -68,11 +68,11 @@ void msg_list_el_free(msg_list_el mle) */ void msg_list_el_free_all(msg_list_el mle) { - msg_list_el p0, p1; - + msg_list_el p0, p1; + if(!mle) return; - + p0 = mle; while(p0) { @@ -88,7 +88,7 @@ void msg_list_el_free_all(msg_list_el mle) msg_list msg_list_init(void) { msg_list ml = NULL; - + ml = (msg_list)shm_malloc(sizeof(t_msg_list)); if(ml == NULL) return NULL; @@ -106,7 +106,7 @@ msg_list msg_list_init(void) ml->nrdone = 0; ml->lsent = NULL; ml->ldone = NULL; - + return ml; clean: @@ -137,7 +137,7 @@ void msg_list_free(msg_list ml) p1 = p0->next; msg_list_el_free(p0); p0 = p1; - } + } } if(ml->nrdone>0 && ml->ldone) @@ -152,8 +152,8 @@ void msg_list_free(msg_list ml) p0 = p1; } } - - shm_free(ml); + + shm_free(ml); } /** @@ -161,13 +161,13 @@ void msg_list_free(msg_list ml) */ int msg_list_check_msg(msg_list ml, int mid) { - msg_list_el p0, p1; - + msg_list_el p0, p1; + if(!ml || mid==0) goto errorx; LM_DBG("checking msgid=%d\n", mid); - + lock_get(&ml->sem_sent); p0 = p1 = ml->lsent; @@ -194,9 +194,9 @@ int msg_list_check_msg(msg_list ml, int mid) p0->prev = p1; goto done; } - + ml->lsent = p0; - + done: ml->nrsent++; lock_release(&ml->sem_sent); @@ -205,7 +205,7 @@ int msg_list_check_msg(msg_list ml, int mid) exist: lock_release(&ml->sem_sent); LM_DBG("msg already in sent list.\n"); - return MSG_LIST_EXIST; + return MSG_LIST_EXIST; error: lock_release(&ml->sem_sent); errorx: @@ -217,14 +217,14 @@ int msg_list_check_msg(msg_list ml, int mid) */ int msg_list_set_flag(msg_list ml, int mid, int fl) { - msg_list_el p0; - + msg_list_el p0; + if(ml==0 || mid==0) { LM_ERR("bad param %p / %d\n", ml, fl); goto errorx; } - + lock_get(&ml->sem_sent); p0 = ml->lsent; @@ -251,17 +251,17 @@ int msg_list_set_flag(msg_list ml, int mid, int fl) */ int msg_list_check(msg_list ml) { - msg_list_el p0; - + msg_list_el p0,p1; + if(!ml) goto errorx; - + lock_get(&ml->sem_sent); if(ml->nrsent<=0) goto done; - + lock_get(&ml->sem_done); - + p0 = ml->lsent; while(p0) { @@ -278,14 +278,23 @@ int msg_list_check(msg_list ml) if(!ml->nrsent) ml->lsent = NULL; + p1 = p0->next; + if(ml->ldone) (ml->ldone)->prev = p0; p0->next = ml->ldone; - + p0->prev = NULL; ml->ldone = p0; ml->nrdone++; + + if (!p1) + break; + else { + p0 = p1; + continue; + } } p0 = p0->next; } @@ -305,17 +314,17 @@ int msg_list_check(msg_list ml) */ msg_list_el msg_list_reset(msg_list ml) { - msg_list_el p0; - + msg_list_el p0; + if(!ml) return NULL; - + lock_get(&ml->sem_done); p0 = ml->ldone; ml->ldone = NULL; ml->nrdone = 0; lock_release(&ml->sem_done); - + return p0; } diff --git a/modules/msilo/ms_msg_list.h b/modules/msilo/ms_msg_list.h index a3f922819c9..cfcbbe1b47f 100644 --- a/modules/msilo/ms_msg_list.h +++ b/modules/msilo/ms_msg_list.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/msilo/msfuncs.c b/modules/msilo/msfuncs.c index cdcf71441de..e30ac9b9efd 100644 --- a/modules/msilo/msfuncs.c +++ b/modules/msilo/msfuncs.c @@ -114,7 +114,7 @@ int timetToSipDateStr(time_t date, char* buf, int bufLen) gmt->tm_sec ); - /* snprintf returns number of chars it should have printed, so you + /* snprintf returns number of chars it should have printed, so you * need to bounds check against input*/ return (len > bufLen) ? bufLen : len; } @@ -149,7 +149,7 @@ int m_extract_content_type(char* src, int len, content_type_t* ctype, int flag) while(p < end && *p!=' ' && *p!='\t' && *p!='\0' && *p!=';' && *p!='\r' && *p!='\n') p++; - + LM_DBG("content-type found\n"); f |= CT_TYPE; ctype->type.len = p - ctype->type.s; @@ -184,7 +184,7 @@ int m_extract_content_type(char* src, int len, content_type_t* ctype, int flag) return -1; } -/** build MESSAGE headers +/** build MESSAGE headers * * Add Content-Type, Contact and Date headers if they exist * expects - max buf len of the resulted body in body->len @@ -217,7 +217,7 @@ int m_build_headers(str *buf, str ctype, str contact, time_t date) p += ctype.len; strncpy(p, CRLF, CRLF_LEN); p += CRLF_LEN; - + } if(contact.len > 0) { @@ -234,7 +234,7 @@ int m_build_headers(str *buf, str ctype, str contact, time_t date) return -1; } -/** build MESSAGE body --- add incoming time and 'from' +/** build MESSAGE body --- add incoming time and 'from' * * expects - max buf len of the resulted body in body->len * - body->s MUST be allocated @@ -243,11 +243,11 @@ int m_build_headers(str *buf, str ctype, str contact, time_t date) int m_build_body(str *body, time_t date, str msg, time_t sdate) { char *p; - + if(!body || !(body->s) || body->len <= 0 || msg.len <= 0 || date < 0 || msg.len < 0 || (46+msg.len > body->len) ) goto error; - + p = body->s; if(ms_add_date!=0) @@ -256,7 +256,7 @@ int m_build_body(str *body, time_t date, str msg, time_t sdate) { strncpy(p, "[Reminder message - ", 20); p += 20; - + strncpy(p, ctime(&sdate), 24); p += 24; @@ -264,7 +264,7 @@ int m_build_body(str *body, time_t date, str msg, time_t sdate) } else { strncpy(p, "[Offline message - ", 19); p += 19; - + strncpy(p, ctime(&date), 24); p += 24; @@ -272,12 +272,12 @@ int m_build_body(str *body, time_t date, str msg, time_t sdate) } *p++ = ' '; } - + memcpy(p, msg.s, msg.len); p += msg.len; body->len = p - body->s; - + return 0; error: return -1; @@ -289,13 +289,13 @@ int ms_extract_time(str *time_str, int *time_val) struct tm stm; int i; - if(time_str==NULL || time_str->s==NULL + if(time_str==NULL || time_str->s==NULL || time_str->len<=0 || time_val==NULL) { LM_ERR("bad parameters\n"); return -1; } - + memset(&stm, 0, sizeof(struct tm)); for(i=0; ilen; i++) { diff --git a/modules/msilo/msilo.c b/modules/msilo/msilo.c index bf9e3244dce..6979436e4ac 100644 --- a/modules/msilo/msilo.c +++ b/modules/msilo/msilo.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -69,7 +69,7 @@ #include "ms_msg_list.h" #include "msfuncs.h" -#define MAX_DEL_KEYS 1 +#define MAX_DEL_KEYS 1 #define NR_KEYS 10 static str sc_mid = str_init("id"); /* 0 */ @@ -230,12 +230,25 @@ static stat_export_t msilo_stats[] = { {0,0,0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + #endif /** module exports */ struct module_exports exports= { "msilo", /* module id */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* module's exported functions */ params, /* module's exported parameters */ #ifdef STATISTICS @@ -439,7 +452,7 @@ static int child_init(int rank) LM_ERR("child %d: failed in use_table\n", rank); return -1; } - + LM_DBG("#%d database connection opened successfully\n", rank); } return 0; @@ -460,14 +473,11 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) str duri, owner_s; db_key_t db_keys[NR_KEYS-1]; db_val_t db_vals[NR_KEYS-1]; - db_key_t db_cols[1]; + db_key_t db_cols[1]; db_res_t* res = NULL; - int nr_keys = 0, val, lexpire; - content_type_t ctype; #define MS_BUF1_SIZE 1024 static char ms_buf1[MS_BUF1_SIZE]; - int mime; str notify_from; str notify_body; str notify_ctype; @@ -476,20 +486,20 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) int_str avp_value; struct usr_avp *avp; - LM_DBG("------------ start ------------\n"); - /* get message body - after that whole SIP MESSAGE is parsed */ - if ( get_body( msg, &body)!=0 || body.len==0) + if ( get_body( msg, &body)!=0 ) { LM_ERR("cannot extract body from msg\n"); goto error; } - + /* missing body is not an error here as we can have + * requests with external bodies (refered from content-type hdr) */ + /* get TO URI */ if(!msg->to || !msg->to->body.s) { - LM_ERR("cannot find 'to' header!\n"); - goto error; + LM_ERR("cannot find 'to' header!\n"); + goto error; } pto = get_to(msg); @@ -538,9 +548,9 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) LM_ERR("no username for owner\n"); goto error; } - + db_keys[nr_keys] = &sc_uri_user; - + db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = puri.user.s; @@ -549,7 +559,7 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) nr_keys++; db_keys[nr_keys] = &sc_uri_host; - + db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = puri.host.s; @@ -564,24 +574,24 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) } if (ms_max_messages > 0) { - db_cols[0] = &sc_inc_time; - if (msilo_dbf.query(db_con, db_keys, 0, db_vals, db_cols, + db_cols[0] = &sc_inc_time; + if (msilo_dbf.query(db_con, db_keys, 0, db_vals, db_cols, 2, 1, 0, &res) < 0 ) { LM_ERR("failed to query the database\n"); return -1; - } - if (RES_ROW_N(res) >= ms_max_messages) { + } + if (RES_ROW_N(res) >= ms_max_messages) { LM_ERR("too many messages for AoR '%.*s@%.*s'\n", - puri.user.len, puri.user.s, puri.host.len, puri.host.s); - msilo_dbf.free_result(db_con, res); - return -1; - } - msilo_dbf.free_result(db_con, res); + puri.user.len, puri.user.s, puri.host.len, puri.host.s); + msilo_dbf.free_result(db_con, res); + return -1; + } + msilo_dbf.free_result(db_con, res); } /* Set To key */ db_keys[nr_keys] = &sc_to; - + db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = pto->uri.s; @@ -600,17 +610,17 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) { LM_DBG("'From' header not parsed\n"); /* parsing from header */ - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); goto error; } } pfrom = (struct to_body*)msg->from->parsed; - LM_DBG("'From' header: <%.*s>\n", pfrom->uri.len, pfrom->uri.s); - + LM_DBG("'From' header: <%.*s>\n", pfrom->uri.len, pfrom->uri.s); + db_keys[nr_keys] = &sc_from; - + db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = pfrom->uri.s; @@ -619,45 +629,29 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) nr_keys++; /* add the message's body in SQL query */ - db_keys[nr_keys] = &sc_body; - + /* insert NULL value is body was found empty */ db_vals[nr_keys].type = DB_BLOB; - db_vals[nr_keys].nul = 0; + db_vals[nr_keys].nul = body.len?0:1; db_vals[nr_keys].val.blob_val.s = body.s; db_vals[nr_keys].val.blob_val.len = body.len; nr_keys++; - - lexpire = ms_expire_time; - /* add 'content-type' -- parse the content-type header */ - if ((mime=parse_content_type_hdr(msg))<1 ) - { - LM_ERR("cannot parse Content-Type header\n"); + + /* add 'content-type' header (already found) */ + if (msg->content_type==0) { + LM_ERR("missing Content-Type header\n"); goto error; } - db_keys[nr_keys] = &sc_ctype; db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; - db_vals[nr_keys].val.str_val.s = "text/plain"; - db_vals[nr_keys].val.str_val.len = 10; - - /** check the content-type value */ - if( mime!=(TYPE_TEXT<<16)+SUBTYPE_PLAIN - && mime!=(TYPE_MESSAGE<<16)+SUBTYPE_CPIM ) - { - if(m_extract_content_type(msg->content_type->body.s, - msg->content_type->body.len, &ctype, CT_TYPE) != -1) - { - LM_DBG("'content-type' found\n"); - db_vals[nr_keys].val.str_val.s = ctype.type.s; - db_vals[nr_keys].val.str_val.len = ctype.type.len; - } - } + db_vals[nr_keys].val.str_val = msg->content_type->body; + nr_keys++; /* check 'expires' -- no more parsing - already done by get_body() */ + lexpire = ms_expire_time; if(msg->expires && msg->expires->body.len > 0) { LM_DBG("'expires' found\n"); @@ -668,7 +662,7 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) /* current time */ val = (int)time(NULL); - + /* add expiration time */ db_keys[nr_keys] = &sc_exp_time; db_vals[nr_keys].type = DB_INT; @@ -708,7 +702,7 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) } LM_DBG("message stored. T:<%.*s> F:<%.*s>\n", pto->uri.len, pto->uri.s, pfrom->uri.len, pfrom->uri.s); - + #ifdef STATISTICS update_stat(ms_stored_msgs, 1); #endif @@ -758,18 +752,18 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) && msg->contact->body.len > 0) { LM_DBG("contact header found\n"); - if((msg->contact->parsed!=NULL + if((msg->contact->parsed!=NULL && ((contact_body_t*)(msg->contact->parsed))->contacts!=NULL) || (parse_contact(msg->contact)==0 && msg->contact->parsed!=NULL && ((contact_body_t*)(msg->contact->parsed))->contacts!=NULL)) { LM_DBG("using contact header for info msg\n"); - ctaddr.s = + ctaddr.s = ((contact_body_t*)(msg->contact->parsed))->contacts->uri.s; ctaddr.len = ((contact_body_t*)(msg->contact->parsed))->contacts->uri.len; - + if(!ctaddr.s || ctaddr.len < 6 || strncasecmp(ctaddr.s, "sip:", 4) || ctaddr.s[4]==' ') ctaddr.s = NULL; @@ -777,7 +771,7 @@ static int m_store(struct sip_msg* msg, char* owner, char* s2) LM_DBG("feedback contact [%.*s]\n", ctaddr.len,ctaddr.s); } } - + tmb.t_request(&msg_type, /* Type of the message */ (ctaddr.s)?&ctaddr:&pfrom->uri, /* Request-URI */ &pfrom->uri, /* To */ @@ -816,7 +810,7 @@ static int m_dump(struct sip_msg* msg, char* owner, char* str2) str str_vals[4], hdr_str , body_str; time_t rtime; - + /* init */ ob_key = &sc_mid; @@ -834,13 +828,12 @@ static int m_dump(struct sip_msg* msg, char* owner, char* str2) db_cols[4]=&sc_ctype; db_cols[5]=&sc_inc_time; - - LM_DBG("------------ start ------------\n"); + hdr_str.s=hdr_buf; hdr_str.len=1024; body_str.s=body_buf; body_str.len=1024; - + /* check for TO header */ if(msg->to==NULL && (parse_headers(msg, HDR_TO_F, 0)==-1 || msg->to==NULL || msg->to->body.s==NULL)) @@ -885,7 +878,7 @@ static int m_dump(struct sip_msg* msg, char* owner, char* str2) LM_DBG("MESSAGE method not supported\n"); return -1; } - + /* get the owner */ memset(&puri, 0, sizeof(struct sip_uri)); if(owner) @@ -929,7 +922,7 @@ static int m_dump(struct sip_msg* msg, char* owner, char* str2) db_vals[2].type = DB_INT; db_vals[2].nul = 0; db_vals[2].val.int_val = 0; - + if (msilo_dbf.use_table(db_con, &ms_db_table) < 0) { LM_ERR("failed to use_table\n"); @@ -942,11 +935,11 @@ static int m_dump(struct sip_msg* msg, char* owner, char* str2) LM_DBG("no stored message for <%.*s>!\n", pto->uri.len, pto->uri.s); goto done; } - - LM_DBG("dumping [%d] messages for <%.*s>!!!\n", + + LM_DBG("dumping [%d] messages for <%.*s>!!!\n", RES_ROW_N(db_res), pto->uri.len, pto->uri.s); - for(i = 0; i < RES_ROW_N(db_res); i++) + for(i = 0; i < RES_ROW_N(db_res); i++) { mid = RES_ROWS(db_res)[i].values[0].val.int_val; if(msg_list_check_msg(ml, mid)) @@ -954,13 +947,13 @@ static int m_dump(struct sip_msg* msg, char* owner, char* str2) LM_DBG("message[%d] mid=%d already sent.\n", i, mid); continue; } - + memset(str_vals, 0, 4*sizeof(str)); SET_STR_VAL(str_vals[0], db_res, i, 1); /* from */ SET_STR_VAL(str_vals[1], db_res, i, 2); /* to */ SET_STR_VAL(str_vals[2], db_res, i, 3); /* body */ SET_STR_VAL(str_vals[3], db_res, i, 4); /* ctype */ - rtime = + rtime = (time_t)RES_ROWS(db_res)[i].values[5/*inc time*/].val.int_val; hdr_str.len = 1024; @@ -973,9 +966,9 @@ static int m_dump(struct sip_msg* msg, char* owner, char* str2) msg_list_set_flag(ml, mid, MS_MSG_ERRO); goto error; } - + LM_DBG("msg [%d-%d] for: %.*s\n", i+1, mid, pto->uri.len, pto->uri.s); - + /** sending using TM function: t_uac */ body_str.len = 1024; n = m_build_body(&body_str, rtime, str_vals[2/*body*/], 0); @@ -983,13 +976,13 @@ static int m_dump(struct sip_msg* msg, char* owner, char* str2) LM_DBG("sending simple body\n"); else LM_DBG("sending composed body\n"); - + tmb.t_request(&msg_type, /* Type of the message */ &str_vals[1], /* Request-URI (To) */ &str_vals[1], /* To */ &str_vals[0], /* From */ &hdr_str, /* Optional headers including CRLF */ - (n<0)?&str_vals[2]:&body_str, /* Message body */ + (n<0)?(RES_ROWS(db_res)[i].values[3].nul?NULL:&str_vals[2]):&body_str, /* Message body */ (ms_outbound_proxy.s)?&ms_outbound_proxy:0, /* outbound uri */ m_tm_callback, /* Callback function */ @@ -1022,9 +1015,9 @@ void m_clean_silo(unsigned int ticks, void *param) db_val_t db_vals[MAX_DEL_KEYS]; db_op_t db_ops[1] = { OP_LEQ }; int n; - + LM_DBG("cleaning stored messages - %d\n", ticks); - + msg_list_check(ml); mle = p = msg_list_reset(ml); n = 0; @@ -1047,7 +1040,7 @@ void m_clean_silo(unsigned int ticks, void *param) n++; if(n==MAX_DEL_KEYS) { - if (msilo_dbf.delete(db_con, db_keys, NULL, db_vals, n) < 0) + if (msilo_dbf.delete(db_con, db_keys, NULL, db_vals, n) < 0) LM_ERR("failed to clean %d messages.\n",n); n = 0; } @@ -1068,13 +1061,13 @@ void m_clean_silo(unsigned int ticks, void *param) } if(n>0) { - if (msilo_dbf.delete(db_con, db_keys, NULL, db_vals, n) < 0) + if (msilo_dbf.delete(db_con, db_keys, NULL, db_vals, n) < 0) LM_ERR("failed to clean %d messages\n", n); n = 0; } msg_list_el_free_all(mle); - + /* cleaning expired messages */ if(ticks%(ms_check_time*ms_clean_period)code, (long)ps->param, *((int*)ps->param)); if(!db_con) @@ -1146,7 +1139,7 @@ void m_send_ontimer(unsigned int ticks, void *param) static char body_buf[1024]; str puri; time_t ttime; - + str str_vals[4], hdr_str , body_str; time_t stime; @@ -1155,7 +1148,7 @@ void m_send_ontimer(unsigned int ticks, void *param) LM_WARN("reminder address null\n"); return; } - + /* init */ db_keys[0]=&sc_snd_time; db_keys[1]=&sc_snd_time; @@ -1169,22 +1162,22 @@ void m_send_ontimer(unsigned int ticks, void *param) db_cols[4]=&sc_ctype; db_cols[5]=&sc_snd_time; - + LM_DBG("------------ start ------------\n"); hdr_str.s=hdr_buf; hdr_str.len=1024; body_str.s=body_buf; body_str.len=1024; - + db_vals[0].type = DB_INT; db_vals[0].nul = 0; db_vals[0].val.int_val = 0; - + db_vals[1].type = DB_INT; db_vals[1].nul = 0; ttime = time(NULL); db_vals[1].val.int_val = (int)ttime; - + if (msilo_dbf.use_table(db_con, &ms_db_table) < 0) { LM_ERR("failed to use_table\n"); @@ -1197,11 +1190,11 @@ void m_send_ontimer(unsigned int ticks, void *param) LM_DBG("no message for <%.*s>!\n", 24, ctime((const time_t*)&ttime)); goto done; } - + LM_DBG("dumping [%d] messages for <%.*s>!!!\n", RES_ROW_N(db_res), 24, ctime((const time_t*)&ttime)); - for(i = 0; i < RES_ROW_N(db_res); i++) + for(i = 0; i < RES_ROW_N(db_res); i++) { mid = RES_ROWS(db_res)[i].values[0].val.int_val; if(msg_list_check_msg(ml, mid)) @@ -1209,7 +1202,7 @@ void m_send_ontimer(unsigned int ticks, void *param) LM_DBG("message[%d] mid=%d already sent.\n", i, mid); continue; } - + memset(str_vals, 0, 4*sizeof(str)); SET_STR_VAL(str_vals[0], db_res, i, 1); /* user */ SET_STR_VAL(str_vals[1], db_res, i, 2); /* host */ @@ -1233,21 +1226,21 @@ void m_send_ontimer(unsigned int ticks, void *param) memcpy(puri.s+4, str_vals[0].s, str_vals[0].len); puri.s[4+str_vals[0].len] = '@'; memcpy(puri.s+4+str_vals[0].len+1, str_vals[1].s, str_vals[1].len); - + LM_DBG("msg [%d-%d] for: %.*s\n", i+1, mid, puri.len, puri.s); - + /** sending using TM function: t_uac */ body_str.len = 1024; - stime = + stime = (time_t)RES_ROWS(db_res)[i].values[5/*snd time*/].val.int_val; n = m_build_body(&body_str, 0, str_vals[2/*body*/], stime); if(n<0) LM_DBG("sending simple body\n"); else LM_DBG("sending composed body\n"); - + msg_list_set_flag(ml, mid, MS_MSG_TSND); - + tmb.t_request(&msg_type, /* Type of the message */ &puri, /* Request-URI */ &puri, /* To */ @@ -1279,22 +1272,22 @@ int ms_reset_stime(int mid) db_val_t db_vals[1]; db_key_t db_cols[1]; db_val_t db_cvals[1]; - + db_keys[0]=&sc_mid; db_ops[0]=OP_EQ; db_vals[0].type = DB_INT; db_vals[0].nul = 0; db_vals[0].val.int_val = mid; - + db_cols[0]=&sc_snd_time; db_cvals[0].type = DB_INT; db_cvals[0].nul = 0; db_cvals[0].val.int_val = 0; - + LM_DBG("updating send time for [%d]!\n", mid); - + if (msilo_dbf.use_table(db_con, &ms_db_table) < 0) { LM_ERR("failed to use_table\n"); @@ -1311,7 +1304,7 @@ int ms_reset_stime(int mid) /* * Check if REGISTER request has contacts that support MESSAGE method or - * if MESSAGE method is listed in Allow header and contact does not have + * if MESSAGE method is listed in Allow header and contact does not have * methods parameter. */ int check_message_support(struct sip_msg* msg) @@ -1355,7 +1348,7 @@ int check_message_support(struct sip_msg* msg) if (contact_iterator(&c, msg, 0) < 0) return -1; - /* + /* * Check contacts for MESSAGE method in methods parameter list * If contact does not have methods parameter, use Allow header methods, * if any. Stop if MESSAGE method is found. diff --git a/modules/nat_traversal/README b/modules/nat_traversal/README index e1c0c22d055..94a12a42f45 100644 --- a/modules/nat_traversal/README +++ b/modules/nat_traversal/README @@ -12,8 +12,7 @@ Dan Pascu Copyright © 2008 Dan Pascu Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/nat_traversal/nat_traversal.c b/modules/nat_traversal/nat_traversal.c index c563e996a29..3a62056de2a 100644 --- a/modules/nat_traversal/nat_traversal.c +++ b/modules/nat_traversal/nat_traversal.c @@ -268,10 +268,24 @@ static stat_export_t statistics[] = { }; #endif +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "sl", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "dialog", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports = { "nat_traversal", // module name + MOD_TYPE_DEFAULT,// class of this module MODULE_VERSION, // module version DEFAULT_DLFLAGS, // dlopen flags + &deps, // OpenSIPS module dependencies commands, // exported functions parameters, // exported parameters NULL, // exported statistics (initialized early in mod_init) @@ -1574,6 +1588,8 @@ ClientNatTest(struct sip_msg *msg, unsigned int tests) static void send_keepalive(NAT_Contact *contact) { +#define MAX_BRANCHID 9999999 +#define MIN_BRANCHID 1000000 char buffer[8192], *from_uri, *ptr; static char from[64] = FROM_PREFIX; static char *from_ip = from + sizeof(FROM_PREFIX) - 1; @@ -1596,7 +1612,7 @@ send_keepalive(NAT_Contact *contact) len = snprintf(buffer, sizeof(buffer), "%s %s SIP/2.0\r\n" - "Via: SIP/2.0/UDP %.*s:%d;branch=0\r\n" + "Via: SIP/2.0/UDP %.*s:%d;branch=z9hG4bK%ld\r\n" "From: %s;tag=%x\r\n" "To: %s\r\n" "Call-ID: %s-%x-%x@%.*s\r\n" @@ -1606,6 +1622,7 @@ send_keepalive(NAT_Contact *contact) keepalive_params.method, contact->uri, contact->socket->address_str.len, contact->socket->address_str.s, contact->socket->port_no, + (long)(rand()/(float)RAND_MAX * (MAX_BRANCHID-MIN_BRANCHID) + MIN_BRANCHID), from_uri, keepalive_params.from_tag++, contact->uri, keepalive_params.callid_prefix, keepalive_params.callid_counter++, get_ticks(), @@ -1907,16 +1924,16 @@ preprocess_request(struct sip_msg *msg, void *_param) str totag; if (msg->REQ_METHOD != METHOD_INVITE) - return 1; + return SCB_RUN_ALL; if (parse_headers(msg, HDR_TO_F, 0) == -1) { LM_ERR("failed to parse To header\n"); - return -1; + return SCB_RUN_ALL; } if (!msg->to) { LM_ERR("missing To header\n"); - return -1; + return SCB_RUN_ALL; } totag = get_to(msg)->tag_value; @@ -1924,7 +1941,7 @@ preprocess_request(struct sip_msg *msg, void *_param) msg->msg_flags |= FL_NAT_TRACK_DIALOG; } - return 1; + return SCB_RUN_ALL; } diff --git a/modules/nathelper/README b/modules/nathelper/README index ec504062b99..c223d4eda70 100644 --- a/modules/nathelper/README +++ b/modules/nathelper/README @@ -16,8 +16,7 @@ Bogdan-Andrei Iancu Copyright © 2005 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -201,7 +200,7 @@ Note Example 1.5. Set received_avp parameter ... -modparam("nathelper", "received_avp", "$avp(i:42)") +modparam("nathelper", "received_avp", "$avp(received)") ... 1.4.6. force_socket (string) @@ -328,7 +327,7 @@ if (search("User-Agent: Cisco ATA.*") { source address of the message or the provided IP address (the provide IP address take precedence over the source address). - * ip_address - IP to be used for rewritting SDP. If not + * ip_address - IP to be used for rewriting SDP. If not specified, the received signalling IP will be used. The parameter allows pseudo-variables usage. NOTE: For the IP to be used, you need to use 0x02 or 0x08 flags, otherwise @@ -388,12 +387,13 @@ fix_nated_register(); Meaning of the flags is as follows: * 1 - Contact header field is searched for occurrence of - RFC1918 addresses. + RFC1918 / RFC6598 addresses. * 2 - the "received" test is used: address in Via is compared against source IP address of signaling - * 4 - Top Most VIA is searched for occurrence of RFC1918 + * 4 - Top Most VIA is searched for occurrence of RFC1918 / + RFC6598 addresses + * 8 - SDP is searched for occurrence of RFC1918 / RFC6598 addresses - * 8 - SDP is searched for occurrence of RFC1918 addresses * 16 - test if the source port is different from the port in Via * 32 - address in Contact is compared against source IP @@ -461,4 +461,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/nathelper/doc/nathelper_admin.xml b/modules/nathelper/doc/nathelper_admin.xml index 0edbf6dfa95..46a0ee2ef3d 100644 --- a/modules/nathelper/doc/nathelper_admin.xml +++ b/modules/nathelper/doc/nathelper_admin.xml @@ -214,7 +214,7 @@ modparam("nathelper", "natping_socket", "192.168.1.1:5006") Set <varname>received_avp</varname> parameter ... -modparam("nathelper", "received_avp", "$avp(i:42)") +modparam("nathelper", "received_avp", "$avp(received)") ... @@ -423,7 +423,7 @@ if (search("User-Agent: Cisco ATA.*") { - ip_address - IP to be used for rewritting SDP. + ip_address - IP to be used for rewriting SDP. If not specified, the received signalling IP will be used. The parameter allows pseudo-variables usage. NOTE: For the IP to be used, you need to use 0x02 or 0x08 flags, otherwise it will have @@ -515,7 +515,7 @@ fix_nated_register(); 1 - Contact header field is searched - for occurrence of RFC1918 addresses. + for occurrence of RFC1918 / RFC6598 addresses. 2 - the "received" test is used: address @@ -523,11 +523,11 @@ fix_nated_register(); 4 - Top Most VIA is searched - for occurrence of RFC1918 addresses + for occurrence of RFC1918 / RFC6598 addresses 8 - SDP is searched for occurrence of - RFC1918 addresses + RFC1918 / RFC6598 addresses 16 - test if the source port is different diff --git a/modules/nathelper/nathelper.c b/modules/nathelper/nathelper.c index 2a9a49c8675..dc95e4754e9 100644 --- a/modules/nathelper/nathelper.c +++ b/modules/nathelper/nathelper.c @@ -36,7 +36,7 @@ * * 2006-03-08 fix_nated_sdp() may take one more param to force a specific IP; * force_rtp_proxy() accepts a new flag 's' to swap creation/ - * confirmation between requests/replies; + * confirmation between requests/replies; * add_rcv_param() may take as parameter a flag telling if the * parameter should go to the contact URI or contact header; * (bogdan) @@ -70,7 +70,6 @@ #include "../../mod_fix.h" #include "../registrar/sip_msg.h" #include "../usrloc/usrloc.h" -#include "nathelper.h" #include "sip_pinger.h" #include "../../parser/parse_content.h" @@ -118,9 +117,10 @@ static struct { uint32_t netaddr; uint32_t mask; } nets_1918[] = { - {"10.0.0.0", 0, 0xffffffffu << 24}, - {"172.16.0.0", 0, 0xffffffffu << 20}, - {"192.168.0.0", 0, 0xffffffffu << 16}, + {"10.0.0.0", 0, 0xffffffffu << 24}, /* RFC 1918 */ + {"172.16.0.0", 0, 0xffffffffu << 20}, /* RFC 1918 */ + {"192.168.0.0", 0, 0xffffffffu << 16}, /* RFC 1918 */ + {"100.64.0.0", 0, 0xffffffffu << 22}, /* RFC 6598 */ {NULL, 0, 0} }; /* @@ -242,10 +242,30 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static module_dependency_t *get_deps_natping_interval(param_export_t *param) +{ + if (*(int *)param->param_pointer <= 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_DEFAULT, "usrloc", DEP_ABORT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "natping_interval", get_deps_natping_interval }, + { NULL, NULL }, + }, +}; + struct module_exports exports = { "nathelper", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, params, 0, /* exported statistics */ @@ -297,7 +317,7 @@ static int fixup_fix_nated_register(void** param, int param_no) -static struct mi_root* mi_enable_natping(struct mi_root* cmd_tree, +static struct mi_root* mi_enable_natping(struct mi_root* cmd_tree, void* param ) { unsigned int value; @@ -355,7 +375,7 @@ static int init_raw_socket(void) } -static int get_natping_socket(char *socket, +static int get_natping_socket(char *socket, unsigned int *ip, unsigned short *port) { struct hostent* he; @@ -476,7 +496,7 @@ mod_init(void) return -1; } - fix_flag_name(&sipping_flag_str, sipping_flag); + fix_flag_name(sipping_flag_str, sipping_flag); sipping_flag = get_flag_id_by_name(FLAG_TYPE_BRANCH, sipping_flag_str); sipping_flag = (sipping_flag==-1)?0:(1<uri.s < msg->buf || c->uri.s > msg->buf+msg->len ) { LM_ERR("SCRIPT BUG - second attempt to change URI Contact \n"); @@ -643,7 +663,7 @@ fix_nated_contact_f(struct sip_msg* msg, char* str1, char* str2) /* - * Test if IP address pointed to by saddr belongs to RFC1918 networks + * Test if IP address pointed to by saddr belongs to RFC1918 / RFC6598 networks */ static inline int is1918addr(str *saddr) @@ -673,7 +693,7 @@ is1918addr(str *saddr) } /* - * test for occurrence of RFC1918 IP address in Contact HF + * test for occurrence of RFC1918 / RFC6598 IP address in Contact HF */ static int contact_1918(struct sip_msg* msg) @@ -689,7 +709,7 @@ contact_1918(struct sip_msg* msg) } /* - * test for occurrence of RFC1918 IP address in SDP + * test for occurrence of RFC1918 / RFC6598 IP address in SDP */ static int sdp_1918(struct sip_msg* msg) @@ -704,7 +724,7 @@ sdp_1918(struct sip_msg* msg) if( bodies == NULL) { - LM_ERR("Unable to get bodies from message\n"); + LM_DBG("Unable to get bodies from message\n"); return 0; } @@ -715,14 +735,14 @@ sdp_1918(struct sip_msg* msg) body = p->body; trim_r(body); - if( p->content_type != ((TYPE_APPLICATION << 16) + SUBTYPE_SDP) + if( p->content_type != ((TYPE_APPLICATION << 16) + SUBTYPE_SDP) || body.len == 0) { p=p->next; continue; } - - + + if (extract_mediaip(&body, &ip, &pf, "c=") == -1) { LM_ERR("can't extract media IP from the SDP\n"); @@ -739,7 +759,7 @@ sdp_1918(struct sip_msg* msg) } /* - * test for occurrence of RFC1918 IP address in top Via + * test for occurrence of RFC1918 / RFC6598 IP address in top Via */ static int via_1918(struct sip_msg* msg) @@ -811,18 +831,18 @@ nat_uac_test_f(struct sip_msg* msg, char* str1, char* str2) if ((tests & NAT_UAC_TEST_V_RCVD) && received_test(msg)) return 1; /* - * test for occurrences of RFC1918 addresses in Contact + * test for occurrences of RFC1918 / RFC6598 addresses in Contact * header field */ if ((tests & NAT_UAC_TEST_C_1918) && (contact_1918(msg)>0)) return 1; /* - * test for occurrences of RFC1918 addresses in SDP body + * test for occurrences of RFC1918 / RFC6598 addresses in SDP body */ if ((tests & NAT_UAC_TEST_S_1918) && sdp_1918(msg)) return 1; /* - * test for occurrences of RFC1918 addresses top Via + * test for occurrences of RFC1918 / RFC6598 addresses top Via */ if ((tests & NAT_UAC_TEST_V_1918) && via_1918(msg)) return 1; @@ -874,7 +894,7 @@ alter_mediaip(struct sip_msg *msg, str *body, str *oldip, int oldpf, return 0; if (preserve != 0) { - anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0, 0); + anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0); if (anchor == NULL) { LM_ERR("anchor_lump failed\n"); return -1; @@ -945,7 +965,7 @@ alter_mediaip(struct sip_msg *msg, str *body, str *oldip, int oldpf, return 0; } -static inline int +static inline int replace_sdp_ip(struct sip_msg* msg, str *org_body, char *line, str *ip) { str body1, oldip, newip; @@ -1010,7 +1030,7 @@ fix_nated_sdp_f(struct sip_msg* msg, char* str1, char* str2) return -1; bodies = get_all_bodies(msg); - + if( bodies == NULL) { LM_ERR("Unable to get bodies from message\n"); @@ -1031,7 +1051,7 @@ fix_nated_sdp_f(struct sip_msg* msg, char* str1, char* str2) } if (level & (ADD_ADIRECTION | ADD_ANORTPPROXY)) { msg->msg_flags |= FL_FORCE_ACTIVE; - anchor = anchor_lump(msg, body.s + body.len - msg->buf, 0, 0); + anchor = anchor_lump(msg, body.s + body.len - msg->buf, 0); if (anchor == NULL) { LM_ERR("anchor_lump failed\n"); return -1; @@ -1151,20 +1171,20 @@ nh_timer(unsigned int ticks, void *timer_idx) { static unsigned int iteration = 0; int rval; - void *buf, *cp; + void *buf = NULL; + void *cp; str c; str opt; str path; - struct sip_uri curi; union sockaddr_union to; - struct hostent* he; + struct hostent *he; struct socket_info* send_sock; unsigned int flags; + struct proxy_l next_hop; - if((*natping_state) == 0) + if ((*natping_state) == 0) goto done; - buf = NULL; if (cblen > 0) { buf = pkg_malloc(cblen); if (buf == NULL) { @@ -1192,7 +1212,6 @@ nh_timer(unsigned int ticks, void *timer_idx) ((unsigned int)(unsigned long)timer_idx)*natping_interval+iteration, natping_processes*natping_interval); if (rval != 0) { - pkg_free(buf); goto done; } } @@ -1209,82 +1228,69 @@ nh_timer(unsigned int ticks, void *timer_idx) memcpy(&(c.len), cp, sizeof(c.len)); if (c.len == 0) break; + c.s = (char*)cp + sizeof(c.len); - cp = (char*)cp + sizeof(c.len) + c.len; - memcpy( &send_sock, cp, sizeof(send_sock)); + cp = (char*)cp + sizeof(c.len) + c.len; + memcpy(&path.len, cp, sizeof(path.len)); + path.s = path.len ? ((char*)cp + sizeof(path.len)) : NULL; + cp = (char*)cp + sizeof(path.len) + path.len; + memcpy(&send_sock, cp, sizeof(send_sock)); cp = (char*)cp + sizeof(send_sock); - memcpy( &flags, cp, sizeof(flags)); + memcpy(&flags, cp, sizeof(flags)); cp = (char*)cp + sizeof(flags); - memcpy( &(path.len), cp, sizeof(path.len)); - path.s = path.len ? ((char*)cp + sizeof(path.len)) : NULL ; - cp = (char*)cp + sizeof(path.len) + path.len; - - /* determine the destination */ - if ( path.len && (flags&sipping_flag)!=0 ) { - /* send to first URI in path */ - if (get_path_dst_uri( &path, &opt) < 0) { - LM_ERR("failed to get dst_uri for Path\n"); - continue; - } - /* send to the contact/received */ - if (parse_uri(opt.s, opt.len, &curi) < 0) { - LM_ERR("can't parse contact dst_uri\n"); - continue; - } - } else { - /* send to the contact/received */ - if (parse_uri(c.s, c.len, &curi) < 0) { - LM_ERR("can't parse contact uri\n"); - continue; - } - } - if (curi.proto != PROTO_NONE && curi.proto != PROTO_UDP && - (natping_tcp == 0 || (curi.proto != PROTO_TCP && - curi.proto != PROTO_TLS))) + memcpy(&next_hop, cp, sizeof(next_hop)); + cp = (char*)cp + sizeof(next_hop); + + if (next_hop.proto != PROTO_NONE && next_hop.proto != PROTO_UDP && + (natping_tcp == 0 || (next_hop.proto != PROTO_TCP && + next_hop.proto != PROTO_TLS))) continue; - /* we should get rid of this resolve (too often and too slow); for the - * moment we are lucky since the curi is an IP -bogdan */ - he = sip_resolvehost(&curi.host, &curi.port_no, &curi.proto, 0, 0); - if (he == NULL){ - LM_ERR("can't resolve_host\n"); + LM_DBG("resolving next hop: '%.*s'\n", + next_hop.name.len, next_hop.name.s); + he = sip_resolvehost(&next_hop.name, &next_hop.port, + &next_hop.proto, 0, NULL); + if (!he) { + LM_ERR("failed to resolve next hop: '%.*s'\n", + next_hop.name.len, next_hop.name.s); continue; } - hostent2su(&to, he, 0, curi.port_no); - if (send_sock==0) { - send_sock=force_socket ? force_socket : - get_send_socket(0, &to, curi.proto); - if (send_sock == NULL) { + hostent2su(&to, he, 0, next_hop.port); + + if (!send_sock) { + send_sock = force_socket ? force_socket : + get_send_socket(0, &to, next_hop.proto); + if (!send_sock) { LM_ERR("can't get sending socket\n"); continue; } } - if ( (flags&sipping_flag)!=0 && - (opt.s=build_sipping( &c, send_sock, &path, &opt.len))!=0 ) { - if (msg_send(send_sock, curi.proto, &to, 0, opt.s, opt.len) < 0) { + if ((flags & sipping_flag) && + (opt.s = build_sipping(&c, send_sock, &path, &opt.len))) { + if (msg_send(send_sock, next_hop.proto, &to, 0, opt.s, opt.len) < 0) { LM_ERR("sip msg_send failed\n"); } - } else if (raw_ip && curi.proto == PROTO_UDP) { + } else if (raw_ip && next_hop.proto == PROTO_UDP) { if (send_raw((char*)sbuf, sizeof(sbuf), &to, raw_ip, raw_port)<0) { LM_ERR("send_raw failed\n"); } } else { - if (msg_send(send_sock, curi.proto, &to, 0, + if (msg_send(send_sock, next_hop.proto, &to, 0, (char *)sbuf, sizeof(sbuf)) < 0) { LM_ERR("sip msg_send failed!\n"); } } - } #ifdef USE_TCP tcp_no_new_conn = 0; #endif - pkg_free(buf); done: + if (buf) + pkg_free(buf); iteration++; if (iteration==natping_interval) iteration = 0; @@ -1356,7 +1362,7 @@ create_rcv_uri(str* uri, struct sip_msg* m) p = buf; memcpy(p, "sip:", 4); p += 4; - + if (m->rcv.src_ip.af==AF_INET6) *p++ = '['; memcpy(p, ip.s, ip.len); @@ -1365,7 +1371,7 @@ create_rcv_uri(str* uri, struct sip_msg* m) *p++ = ']'; *p++ = ':'; - + memcpy(p, port.s, port.len); p += port.len; @@ -1420,15 +1426,15 @@ add_rcv_param_f(struct sip_msg* msg, char* str1, char* str2) if (hdr_param) { /* add the param as header param */ - anchor = anchor_lump(msg, c->name.s + c->len - msg->buf, 0, 0); + anchor = anchor_lump(msg, c->name.s + c->len - msg->buf, 0); } else { /* add the param as uri param */ - anchor = anchor_lump(msg, c->uri.s + c->uri.len - msg->buf, 0, 0); + anchor = anchor_lump(msg, c->uri.s + c->uri.len - msg->buf, 0); } if (anchor == NULL) { LM_ERR("anchor_lump failed\n"); return -1; - } + } if (insert_new_lump_after(anchor, param, RECEIVED_LEN + 1 + uri.len + 1, 0) == 0) { LM_ERR("insert_new_lump_after failed\n"); diff --git a/modules/nathelper/nathelper.h b/modules/nathelper/nathelper.h deleted file mode 100644 index b15abf25924..00000000000 --- a/modules/nathelper/nathelper.h +++ /dev/null @@ -1,122 +0,0 @@ -/* $Id$ - * - * Copyright (C) 2003-2008 Sippy Software, Inc., http://www.sippysoft.com - * - * This file is part of opensips, a free SIP server. - * - * opensips is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * opensips is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * History: - * --------- - * 2007-04-13 splitted from nathelper.c (ancuta) -*/ - - -#ifndef _NATHELPER_NATHELPER_H -#define _NATHELPER_NATHELPER_H - -#include "../../str.h" -#include "../../pvar.h" -#include "../dialog/dlg_load.h" - -/* Handy macros */ -#define STR2IOVEC(sx, ix) do {(ix).iov_base = (sx).s; (ix).iov_len = (sx).len;} while(0) -#define SZ2IOVEC(sx, ix) do {(ix).iov_base = (sx); (ix).iov_len = strlen(sx);} while(0) - -struct rtpp_node { - unsigned int idx; /* overall index */ - str rn_url; /* unparsed, deletable */ - int rn_umode; - char *rn_address; /* substring of rn_url */ - int rn_disabled; /* found unaccessible? */ - unsigned rn_weight; /* for load balancing */ - unsigned int rn_recheck_ticks; - int rn_rep_supported; - int rn_ptl_supported; - int abr_supported; - struct rtpp_node *rn_next; -}; - - -struct rtpp_set{ - unsigned int id_set; - unsigned weight_sum; - unsigned int rtpp_node_count; - int set_disabled; - unsigned int set_recheck_ticks; - struct rtpp_node *rn_first; - struct rtpp_node *rn_last; - struct rtpp_set *rset_next; -}; - - -struct rtpp_set_head{ - struct rtpp_set *rset_first; - struct rtpp_set *rset_last; -}; - -struct force_rtpp_args { - char *arg1; - char *arg2; - int offer; - str body; - str callid; - struct rtpp_node *node; - str raddr; -}; - -/* used in timeout_listener_process */ -struct rtpp_notify_node { - int index; - int fd; - int mode; - char* addr; - struct rtpp_notify_node *next; -}; - -struct rtpp_notify_head { - int changed; - gen_lock_t *lock; - struct rtpp_notify_node *rtpp_list; -}; - - -/* parameter type for set_rtp_proxy_set() */ - -#define NH_VAL_SET_FIXED 0 -#define NH_VAL_SET_SPEC 1 - -typedef struct rtpp_set_param{ - int t; - union { - struct rtpp_set * fixed_set; - pv_spec_t var_set; - } v; -} nh_set_param_t; - -extern str rtpp_notify_socket; -extern struct dlg_binds dlg_api; -extern int detect_rtp_idle; -extern struct rtpp_set_head * rtpp_set_list; -extern struct rtpp_notify_head * rtpp_notify_h; -int init_rtpp_notify_list(); -void timeout_listener_process(int rank); - -/* Functions from nathelper */ -struct rtpp_node *select_rtpp_node(str, int); -char *send_rtpp_command(struct rtpp_node *, struct iovec *, int); -int force_rtp_proxy_body(struct sip_msg *, struct force_rtpp_args *); - -#endif diff --git a/modules/nathelper/sip_pinger.h b/modules/nathelper/sip_pinger.h index 5a8d2e0e4a7..fdc344a8b66 100644 --- a/modules/nathelper/sip_pinger.h +++ b/modules/nathelper/sip_pinger.h @@ -129,8 +129,12 @@ static inline char* build_sipping(str *curi, struct socket_info* s, str *path, int *len_p) { #define s_len(_s) (sizeof(_s)-1) +#define MAX_BRANCHID 9999999 +#define MIN_BRANCHID 1000000 +#define LEN_BRANCHID 7 /* NOTE: this must be sync with the MX and MIN values !! */ static char buf[MAX_SIPPING_SIZE]; char *p, proto_str[4]; + str address, port; str st; int len; @@ -139,17 +143,30 @@ static inline char* build_sipping(str *curi, struct socket_info* s, str *path, st.s = proto_str; st.len = p - proto_str; + if (s->adv_name_str.len) + address = s->adv_name_str; + else if (default_global_address.len) + address = default_global_address; + else + address = s->address_str; + if (s->adv_port_str.len) + port = s->adv_port_str; + else if (default_global_port.len) + port = default_global_port; + else + port = s->port_no_str; + /* quick proto uppercase */ *((int *)st.s) &= ~((1 << 21) | (1 << 13) | (1 << 5)); if ( sipping_method.len + 1 + curi->len + s_len(" SIP/2.0"CRLF) + - s_len("Via: SIP/2.0/") + st.len + s->address_str.len + - 1 + s->port_no_str.len + s_len(";branch=0") + + s_len("Via: SIP/2.0/") + st.len + address.len + + 1 + port.len + s_len(";branch=z9hG4bK") + LEN_BRANCHID + (path->len ? (s_len(CRLF"Route: ") + path->len) : 0) + s_len(CRLF"From: ") + sipping_from.len + s_len(";tag=") + 8 + s_len(CRLF"To: ") + curi->len + s_len(CRLF"Call-ID: ") + sipping_callid.len + 1 + 8 + 1 + 8 + 1 + - s->address_str.len + + address.len + s_len(CRLF"CSeq: 1 ") + sipping_method.len + s_len(CRLF"Max-Forwards: "MAX_FORWARD) + s_len(CRLF"Content-Length: 0" CRLF CRLF) @@ -165,16 +182,19 @@ static inline char* build_sipping(str *curi, struct socket_info* s, str *path, append_str( p, *curi); append_fix( p, " SIP/2.0"CRLF"Via: SIP/2.0/"); append_str( p, st); - append_str( p, s->address_str); + append_str( p, address); *(p++) = ':'; - append_str( p, s->port_no_str); + append_str( p, port); + append_fix( p, ";branch=z9hG4bK"); + int2bstr( + (long)(rand()/(float)RAND_MAX * (MAX_BRANCHID-MIN_BRANCHID) + MIN_BRANCHID), + p+LEN_BRANCHID-INT2STR_MAX_LEN+1, NULL); + p += LEN_BRANCHID; if (path->len) { - append_fix( p, ";branch=0"CRLF"Route: "); + append_fix( p, CRLF"Route: "); append_str( p, *path); - append_fix( p, CRLF"From: "); - } else { - append_fix( p, ";branch=0"CRLF"From: "); } + append_fix( p, CRLF"From: "); append_str( p, sipping_from); append_fix( p, ";tag="); len = 8; @@ -190,7 +210,7 @@ static inline char* build_sipping(str *curi, struct socket_info* s, str *path, len = 8; int2reverse_hex( &p, &len, get_ticks() ); *(p++) = '@'; - append_str( p, s->address_str); + append_str( p, address); append_fix( p, CRLF"CSeq: 1 "); append_str( p, sipping_method); append_fix( p, CRLF"Max-Forwards: "MAX_FORWARD); diff --git a/modules/options/README b/modules/options/README index 81e89565dd1..e7d84bf283d 100644 --- a/modules/options/README +++ b/modules/options/README @@ -10,8 +10,7 @@ Nils Ohlmeier Copyright © 2003 FhG Fokus Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/options/mod_options.c b/modules/options/mod_options.c index 421fe6a74af..dca4fdb8693 100644 --- a/modules/options/mod_options.c +++ b/modules/options/mod_options.c @@ -75,13 +75,25 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /* * Module description */ struct module_exports exports = { "options", /* Module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ diff --git a/modules/osp/Makefile b/modules/osp/Makefile index ce11371f44f..b1a2c3b313c 100644 --- a/modules/osp/Makefile +++ b/modules/osp/Makefile @@ -1,4 +1,3 @@ - # osp module makefile # WARNING: do not run this directly, it should be run by the master Makefile @@ -33,7 +32,7 @@ include ../../Makefile.modules install_module_custom: echo "OSP module overwrites the default configuration file" sed \ - -e "s#/usr/local/lib/opensips#$(modules-prefix)/$(lib-dir)#g" \ + -e "s#/usr/local/lib/opensips#$(modules-target)/$(lib-dir)#g" \ < etc/sample-osp-opensips.cfg \ > $(cfg-prefix)/$(cfg-dir)/opensips.cfg diff --git a/modules/osp/README b/modules/osp/README index 04d86bc38ac..813ffd14547 100644 --- a/modules/osp/README +++ b/modules/osp/README @@ -16,8 +16,7 @@ Di-Shi Sun Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2009-07-21 15:45:05 +0800 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -52,9 +51,11 @@ Di-Shi Sun 1.3.20. append_userphone 1.3.21. networkid_location 1.3.22. networkid_parameter - 1.3.23. source_device_avp - 1.3.24. source_networkid_avp - 1.3.25. custom_info_avp + 1.3.23. parameterstring_location + 1.3.24. parameterstring_value + 1.3.25. source_device_avp + 1.3.26. source_networkid_avp + 1.3.27. custom_info_avp 1.4. Exported Functions @@ -96,18 +97,20 @@ Di-Shi Sun 1.20. Append user=phone parameter 1.21. Append networkid location 1.22. Networkid parameter name - 1.23. Setting the source device IP AVP - 1.24. Setting the source network ID AVP - 1.25. Setting the custom info AVP - 1.26. checkospheader usage - 1.27. validateospheader usage - 1.28. requestosprouting usage - 1.29. checkosproute usage - 1.30. prepareosproute usage - 1.31. prepareredirectosproutes usage - 1.32. prepareallosproutes usage - 1.33. checkcallingtranslation usage - 1.34. reportospusage usage + 1.23. Append parameter string location + 1.24. Parameter string value + 1.25. Setting the source device IP AVP + 1.26. Setting the source network ID AVP + 1.27. Setting the custom info AVP + 1.28. checkospheader usage + 1.29. validateospheader usage + 1.30. requestosprouting usage + 1.31. checkosproute usage + 1.32. prepareosproute usage + 1.33. prepareredirectosproutes usage + 1.34. prepareallosproutes usage + 1.35. checkcallingtranslation usage + 1.36. reportospusage usage Chapter 1. Admin Guide @@ -445,7 +448,31 @@ modparam("osp","networkid_location",2) Example 1.22. Networkid parameter name modparam("osp","networkid_param","networkid") -1.3.23. source_device_avp +1.3.23. parameterstring_location + + The parameterstring_location (integer) parameter instructs the + OSP module where the parameter string should be appended. The + default value is 0 + + 0 - parameter string is not appended. + + 1 - parameter string is appended as userinfo parameter. + + 2 - parameter string is appended as URI parameter. + + Example 1.23. Append parameter string location +modparam("osp","parameterstring_location",0) + +1.3.24. parameterstring_value + + The parameterstring_value (string) parameter instructs the OSP + module to append the parameter string in outbound URIs. The + default value is "" + + Example 1.24. Parameter string value +modparam("osp","parameterstring_value","") + +1.3.25. source_device_avp The source_device_avp (string) parameter instructs the OSP module to use the defined AVP to pass the source device IP @@ -455,10 +482,10 @@ modparam("osp","networkid_param","networkid") pseudo variables are described in http://www.opensips.org/Resources/DocsCoreVar. - Example 1.23. Setting the source device IP AVP + Example 1.25. Setting the source device IP AVP modparam("osp","source_device_avp","$avp(srcdev)") -1.3.24. source_networkid_avp +1.3.26. source_networkid_avp The source_networkid_avp (string) parameter instructs the OSP module to use the defined AVP to pass the source network ID @@ -468,10 +495,10 @@ modparam("osp","source_device_avp","$avp(srcdev)") variables are described in http://www.opensips.org/Resources/DocsCoreVar. - Example 1.24. Setting the source network ID AVP + Example 1.26. Setting the source network ID AVP modparam("osp","source_networkid_avp","$avp(snid)") -1.3.25. custom_info_avp +1.3.27. custom_info_avp The custom_info_avp (string) parameter instructs the OSP module to use the defined AVP to pass the custom information values. @@ -480,7 +507,7 @@ modparam("osp","source_networkid_avp","$avp(snid)") pseudo-variables". All pseudo variables are described in http://www.opensips.org/Resources/DocsCoreVar. - Example 1.25. Setting the custom info AVP + Example 1.27. Setting the custom info AVP modparam("osp","custom_info_avp","$avp(cinfo)") 1.4. Exported Functions @@ -492,7 +519,7 @@ modparam("osp","custom_info_avp","$avp(cinfo)") This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.26. checkospheader usage + Example 1.28. checkospheader usage ... if (checkospheader()) { log(1,"OSP header field found.\n"); @@ -511,7 +538,7 @@ if (checkospheader()) { This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.27. validateospheader usage + Example 1.29. validateospheader usage ... if (validateospheader()) { log(1,"valid OSP header found\n"); @@ -540,7 +567,7 @@ if (validateospheader()) { This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.28. requestosprouting usage + Example 1.30. requestosprouting usage ... if (requestosprouting()) { log(1,"successfully queried OSP server, now relaying call\n"); @@ -556,7 +583,7 @@ if (requestosprouting()) { This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.29. checkosproute usage + Example 1.31. checkosproute usage ... if (checkosproute()) { log(1,"There is at least one route for the call\n"); @@ -579,7 +606,7 @@ if (checkosproute()) { This function can be used from BRANCH_ROUTE. - Example 1.30. prepareosproute usage + Example 1.32. prepareosproute usage ... if (prepareosproute()) { log(1,"successfully prepared the route, now relaying call\n"); @@ -598,7 +625,7 @@ if (prepareosproute()) { This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.31. prepareredirectosproutes usage + Example 1.33. prepareredirectosproutes usage ... if (prepareredirectosproutes()) { log(1,"Routes are prepared, now redirecting the call\n"); @@ -616,7 +643,7 @@ if (prepareredirectosproutes()) { This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.32. prepareallosproutes usage + Example 1.34. prepareallosproutes usage ... if (prepareallosproutes()) { log(1,"Routes are prepared, now forking the call\n"); @@ -638,7 +665,7 @@ if (prepareallosproutes()) { This function can be used from BRANCH_ROUTE. - Example 1.33. checkcallingtranslation usage + Example 1.35. checkcallingtranslation usage ... if (checkcallingtranslation()) { # Remove the Remote_Party-ID from the received message @@ -667,7 +694,7 @@ if (checkcallingtranslation()) { This function can be used from REQUEST_ROUTE. - Example 1.34. reportospusage usage + Example 1.36. reportospusage usage ... if (is_direction("downstream")) { log(1,"This BYE message is from SOURCE\n"); diff --git a/modules/osp/doc/osp_admin.xml b/modules/osp/doc/osp_admin.xml index 42736bc7ff3..5c29a6a7667 100644 --- a/modules/osp/doc/osp_admin.xml +++ b/modules/osp/doc/osp_admin.xml @@ -288,6 +288,29 @@ modparam("osp","networkid_param","networkid")
+
+ <varname>parameterstring_location</varname> + The parameterstring_location (integer) parameter instructs the OSP module where the parameter string should be appended. The default value is 0 + 0 - parameter string is not appended. + 1 - parameter string is appended as userinfo parameter. + 2 - parameter string is appended as URI parameter. + + Append parameter string location + +modparam("osp","parameterstring_location",0) + + +
+
+ <varname>parameterstring_value</varname> + The parameterstring_value (string) parameter instructs the OSP module to append the parameter string in outbound URIs. The default value is "" + + Parameter string value + +modparam("osp","parameterstring_value","") + + +
<varname>source_device_avp</varname> The source_device_avp (string) parameter instructs the OSP module to use the defined AVP to pass the source device IP value in the indirect work mode. The default value is "$avp(_osp_source_device_)". Then the source device IP can be set by "$avp(_osp_source_device_) = pseudo-variables". All pseudo variables are described in http://www.opensips.org/Resources/DocsCoreVar. diff --git a/modules/osp/etc/sample-osp-opensips.cfg b/modules/osp/etc/sample-osp-opensips.cfg index 5f21e947505..e313c97f4f5 100644 --- a/modules/osp/etc/sample-osp-opensips.cfg +++ b/modules/osp/etc/sample-osp-opensips.cfg @@ -229,6 +229,27 @@ modparam("osp", "sp1_uri", "http://osptestserver.transnexus.com:5045/osp") # # modparam("osp", "networkid_parameter", "networkid") +# +# Parameter String Location +# ==================================================================== +# This parameter is used to tell the OSP module where the parameter +# string should be appended in the outbound URI. The default value is +# 0. +# +# 0 - parameter string is not appended. +# 1 - parameter string is appended as userinfo parameter. +# 2 - parameter string is appended as URI parameter. +# +# modparam("osp", "parameterstring_location", 0) + +# +# Parameter String Value +# ==================================================================== +# This parameter is used to tell the OSP module the parameter string +# that is appended in outbound URI. The default value is empty. +# +# modparam("osp", "parameterstring_value", "") + # # Source Device IP AVP # ==================================================================== diff --git a/modules/osp/globals.c b/modules/osp/globals.c index abba2f9bbd2..32fd8a14694 100644 --- a/modules/osp/globals.c +++ b/modules/osp/globals.c @@ -68,6 +68,8 @@ int _osp_use_np = OSP_DEF_USENP; int _osp_append_userphone = OSP_DEF_USERPHONE; int _osp_dnid_location = OSP_DEF_DNIDLOC; char* _osp_dnid_param = OSP_DEF_DNIDPARAM; +int _osp_paramstr_location = OSP_DEF_PARAMSTRLOC; +char* _osp_paramstr_value = OSP_DEF_PARAMSTRVAL; char _osp_PRIVATE_KEY[OSP_STRBUF_SIZE]; char _osp_LOCAL_CERTIFICATE[OSP_STRBUF_SIZE]; char _osp_CA_CERTIFICATE[OSP_STRBUF_SIZE]; diff --git a/modules/osp/orig_transaction.c b/modules/osp/orig_transaction.c index c4e823b9b00..8106f194ea0 100644 --- a/modules/osp/orig_transaction.c +++ b/modules/osp/orig_transaction.c @@ -42,7 +42,7 @@ #include "sipheader.h" #include "usage.h" -#ifndef timersub +#ifndef timersub #define timersub(a, b, result) \ { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ @@ -52,7 +52,7 @@ (result)->tv_usec += 1000000; \ } \ } -#endif +#endif extern int _osp_calling_avpid; extern int _osp_service_type; diff --git a/modules/osp/osp_mod.c b/modules/osp/osp_mod.c index 8ec82d4bde1..c270080c9a6 100644 --- a/modules/osp/osp_mod.c +++ b/modules/osp/osp_mod.c @@ -71,6 +71,8 @@ extern int _osp_use_np; extern int _osp_append_userphone; extern int _osp_dnid_location; extern char* _osp_dnid_param; +extern int _osp_paramstr_location; +extern char* _osp_paramstr_value; extern char _osp_PRIVATE_KEY[]; extern char _osp_LOCAL_CERTIFICATE[]; extern char _osp_CA_CERTIFICATE[]; @@ -163,16 +165,32 @@ static param_export_t params[]={ { "append_userphone", INT_PARAM, &_osp_append_userphone }, { "networkid_location", INT_PARAM, &_osp_dnid_location}, { "networkid_parameter", STR_PARAM, &_osp_dnid_param }, + { "parameterstring_location", INT_PARAM, &_osp_paramstr_location}, + { "parameterstring_value", STR_PARAM, &_osp_paramstr_value }, { "source_device_avp", STR_PARAM, &_osp_srcdev_avp }, { "source_networkid_avp", STR_PARAM, &_osp_snid_avp }, { "custom_info_avp", STR_PARAM, &_osp_cinfo_avp }, { 0,0,0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "rr", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "auth", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports = { "osp", + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported params */ 0, /* exported statistics */ @@ -342,6 +360,15 @@ static int ospVerifyParameters(void) _osp_dnid_param = OSP_DEF_DNIDPARAM; } + if ((_osp_paramstr_location < 0) || (_osp_paramstr_location > 2)) { + _osp_paramstr_location = OSP_DEF_PARAMSTRLOC; + LM_WARN("parameterstring_location is out of range, reset to %d\n", OSP_DEF_PARAMSTRLOC); + } + + if (!(_osp_paramstr_value && *_osp_paramstr_value)) { + _osp_paramstr_value = OSP_DEF_PARAMSTRVAL; + } + if ((_osp_work_mode == 1) && _osp_srcdev_avp && *_osp_srcdev_avp) { avp_str.s = _osp_srcdev_avp; avp_str.len = strlen(_osp_srcdev_avp); @@ -429,6 +456,8 @@ static void ospDumpParameters(void) LM_INFO(" append_userphone '%d' ", _osp_append_userphone); LM_INFO(" networkid_location '%d' ", _osp_dnid_location); LM_INFO(" networkid_parameter '%s' ", _osp_dnid_param); + LM_INFO(" parameterstring_location '%d' ", _osp_paramstr_location); + LM_INFO(" parameterstring_value '%s' ", _osp_paramstr_value); LM_INFO(" max_destinations '%d'\n", _osp_max_dests); LM_INFO(" report_networkid '%d'\n", _osp_report_nid); LM_INFO(" support_nonsip_protocol '%d'\n", _osp_non_sip); diff --git a/modules/osp/osp_mod.h b/modules/osp/osp_mod.h index e43430501f0..708c0510184 100644 --- a/modules/osp/osp_mod.h +++ b/modules/osp/osp_mod.h @@ -57,6 +57,8 @@ #define OSP_DEF_USERPHONE 0 #define OSP_DEF_DNIDLOC 2 #define OSP_DEF_DNIDPARAM "networkid" +#define OSP_DEF_PARAMSTRLOC 0 +#define OSP_DEF_PARAMSTRVAL "" #define OSP_DEF_SRCIPAVP "$avp(_osp_source_device_)" #define OSP_DEF_SNIDAVP "$avp(_osp_source_networkid_)" #define OSP_DEF_CINFOS 8 diff --git a/modules/osp/sipheader.c b/modules/osp/sipheader.c index 9742e6cc033..33c48984eab 100644 --- a/modules/osp/sipheader.c +++ b/modules/osp/sipheader.c @@ -49,10 +49,11 @@ extern int _osp_use_np; extern int _osp_append_userphone; extern int _osp_dnid_location; extern char* _osp_dnid_param; +extern int _osp_paramstr_location; +extern char* _osp_paramstr_value; extern int _osp_srcdev_avpid; extern unsigned short _osp_srcdev_avptype; -static void ospSkipPlus(char* e164); static void ospSkipUserParam(char* userinfo); static int ospAppendHeader(struct sip_msg* msg, str* header); @@ -83,22 +84,6 @@ void ospCopyStrToBuffer( buffer[copybytes] = '\0'; } -/* - * Remove '+' in E164 string - * param e164 E164 string - */ -static void ospSkipPlus( - char* e164) -{ - int size; - - if (*e164 == '+') { - size = strlen(e164); - memmove(e164, e164 + 1, size - 1); - e164[size - 1] = '\0'; - } -} - /* * Remove user parameters from userinfo * param userinfo User info @@ -141,7 +126,6 @@ int ospGetFromUserpart( if (parse_uri(from->uri.s, from->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, fromuser, bufsize); ospSkipUserParam(fromuser); - ospSkipPlus(fromuser); result = 0; } else { LM_ERR("failed to parse From uri\n"); @@ -183,7 +167,6 @@ int ospGetRpidUserpart( if (parse_uri(rpid->uri.s, rpid->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, rpiduser, bufsize); ospSkipUserParam(rpiduser); - ospSkipPlus(rpiduser); result = 0; } else { LM_ERR("failed to parse RPID uri\n"); @@ -226,7 +209,6 @@ int ospGetPaiUserpart( if (parse_uri(pai->uri.s, pai->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, paiuser, bufsize); ospSkipUserParam(paiuser); - ospSkipPlus(paiuser); result = 0; } else { LM_ERR("failed to parse PAI uri\n"); @@ -283,7 +265,6 @@ int ospGetPChargeInfoUserpart( if (parse_uri(pci->uri.s, pci->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, pciuser, bufsize); ospSkipUserParam(pciuser); - ospSkipPlus(pciuser); result = 0; } else { LM_ERR("failed to parse P-Charge-Info uri\n"); @@ -333,7 +314,6 @@ int ospGetToUserpart( if (parse_uri(to->uri.s, to->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, touser, bufsize); ospSkipUserParam(touser); - ospSkipPlus(touser); result = 0; } else { LM_ERR("failed to parse To uri\n"); @@ -417,7 +397,6 @@ int ospGetUriUserpart( if (parse_sip_msg_uri(msg) >= 0) { ospCopyStrToBuffer(&msg->parsed_uri.user, uriuser, bufsize); ospSkipUserParam(uriuser); - ospSkipPlus(uriuser); result = 0; } else { LM_ERR("failed to parse Request-Line URI\n"); @@ -452,7 +431,7 @@ static int ospAppendHeader( return -1; } - anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0); + anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0); if (anchor == 0) { LM_ERR("failed to get anchor\n"); return -1; @@ -771,6 +750,7 @@ int ospRebuildDestinationUri( int uriparamsize; int userparamsize; int dnidsize; + int paramstrsize; int count; calledsize = strlen(dest->called); @@ -797,6 +777,8 @@ int ospRebuildDestinationUri( uriparamsize = _osp_append_userphone ? USERPHONE.len : 0; /* destination network ID parameter */ dnidsize = (_osp_dnid_location && dest->dnid[0]) ? 1 + strlen(_osp_dnid_param) + 1 + strlen(dest->dnid) : 0; + /* parameter string */ + paramstrsize = (_osp_paramstr_location && _osp_paramstr_value[0]) ? 1 + strlen(_osp_paramstr_value) : 0; LM_DBG("'%s' (%d) '%s' (%d) '%s' '%s' '%d' '%s' '%s' '%s' '%s' '%s' '%s' (%d) '%s' (%d)\n", dest->called, @@ -819,7 +801,7 @@ int ospRebuildDestinationUri( /* "sip:" + called + NP + "@" + host + ";user=phone" + ";_osp_dnid_param=" + dnid + " SIP/2.0" or "sip:" + called + NP + ";_osp_dnid_param=" + dnid + "@" + host + ";user=phone" SIP/2.0" */ /* OpenSIPS will add "<>" for the Contact headers of SIP 3xx messages */ - if (newuri->len < (4 + calledsize + userparamsize + 1 + hostsize + uriparamsize + dnidsize + 1 + 7 + TRANS.len)) { + if (newuri->len < (4 + calledsize + userparamsize + 1 + hostsize + uriparamsize + dnidsize + paramstrsize + 1 + 7 + TRANS.len)) { LM_ERR("new uri buffer is too small\n"); newuri->len = 0; return -1; @@ -877,6 +859,11 @@ int ospRebuildDestinationUri( buffer += count; } + if ((_osp_paramstr_location == 1) && (_osp_paramstr_value[0] != '\0')) { + count = sprintf(buffer, ";%s", _osp_paramstr_value); + buffer += count; + } + *buffer++ = '@'; strncpy(buffer, dest->host, newuri->len - (buffer - newuri->s)); @@ -892,6 +879,11 @@ int ospRebuildDestinationUri( buffer += count; } + if ((_osp_paramstr_location == 2) && (_osp_paramstr_value[0] != '\0')) { + count = sprintf(buffer, ";%s", _osp_paramstr_value); + buffer += count; + } + /* *buffer++ = ' '; *buffer++ = 'S'; diff --git a/modules/osp/usage.c b/modules/osp/usage.c index c1f432fcae6..5353078a6fa 100644 --- a/modules/osp/usage.c +++ b/modules/osp/usage.c @@ -70,7 +70,7 @@ /* Flags for reporting network ID */ #define OSP_REPORT_SNID (1<<0) -#define OSP_REPORT_DNID (1<<1) +#define OSP_REPORT_DNID (1<<1) extern int _osp_report_nid; extern int _osp_origdest_avpid; diff --git a/modules/path/README b/modules/path/README index 5f38e2823d6..d93df5f175f 100644 --- a/modules/path/README +++ b/modules/path/README @@ -10,8 +10,7 @@ Andreas Granig Copyright © 2006 Inode GmbH Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/path/path.c b/modules/path/path.c index 8edafa84c60..84d404d4563 100644 --- a/modules/path/path.c +++ b/modules/path/path.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -62,7 +62,7 @@ static int build_path(struct sip_msg* _m, struct lump* l, struct lump* l2, int prefix_len, suffix_len; str rcv_addr = {0, 0}; char *src_ip; - + prefix = suffix = crlf = r2 = 0; prefix_len = PATH_PREFIX_LEN + (user->len ? (user->len+1) : 0); @@ -146,9 +146,9 @@ static int build_path(struct sip_msg* _m, struct lump* l, struct lump* l2, } l2 = insert_new_lump_before(l2, crlf, CRLF_LEN+1, 0); if (!l2) goto out5; - + return 1; - + out1: if (prefix) pkg_free(prefix); out2: @@ -178,17 +178,17 @@ static int prepend_path(struct sip_msg* _m, str *user, int recv) for (hf = _m->headers; hf; hf = hf->next) { if (hf->type == HDR_PATH_T) { break; - } + } } if (hf) { /* path found, add ours in front of that */ - l = anchor_lump(_m, hf->name.s - _m->buf, 0, 0); - l2 = anchor_lump(_m, hf->name.s - _m->buf, 0, 0); + l = anchor_lump(_m, hf->name.s - _m->buf, 0); + l2 = anchor_lump(_m, hf->name.s - _m->buf, 0); } else { /* no path, append to message */ - l = anchor_lump(_m, _m->unparsed - _m->buf, 0, 0); - l2 = anchor_lump(_m, _m->unparsed - _m->buf, 0, 0); + l = anchor_lump(_m, _m->unparsed - _m->buf, 0); + l2 = anchor_lump(_m, _m->unparsed - _m->buf, 0); } if (!l || !l2) { @@ -204,12 +204,12 @@ static int prepend_path(struct sip_msg* _m, str *user, int recv) if (enable_double_path) { if (hf) { /* path found, add ours in front of that */ - l = anchor_lump(_m, hf->name.s - _m->buf, 0, 0); - l2 = anchor_lump(_m, hf->name.s - _m->buf, 0, 0); + l = anchor_lump(_m, hf->name.s - _m->buf, 0); + l2 = anchor_lump(_m, hf->name.s - _m->buf, 0); } else { /* no path, append to message */ - l = anchor_lump(_m, _m->unparsed - _m->buf, 0, 0); - l2 = anchor_lump(_m, _m->unparsed - _m->buf, 0, 0); + l = anchor_lump(_m, _m->unparsed - _m->buf, 0); + l2 = anchor_lump(_m, _m->unparsed - _m->buf, 0); } if (!l || !l2) { diff --git a/modules/path/path.h b/modules/path/path.h index 0229494ceee..adc9d8f627e 100644 --- a/modules/path/path.h +++ b/modules/path/path.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/path/path_mod.c b/modules/path/path_mod.c index 5490118d056..ba652cc4ab3 100644 --- a/modules/path/path_mod.c +++ b/modules/path/path_mod.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id$ * * Path handling for intermediate proxies * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -90,14 +90,33 @@ static param_export_t params[] = { { 0, 0, 0 } }; +static module_dependency_t *get_deps_use_received(param_export_t *param) +{ + if (! *(int *)param->param_pointer) + return NULL; + + return alloc_module_dep(MOD_TYPE_DEFAULT, "rr", DEP_ABORT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "use_received", get_deps_use_received }, + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "path", + "path", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -131,7 +150,7 @@ static int mod_init(void) return -1; } } - + return 0; } diff --git a/modules/path/path_mod.h b/modules/path/path_mod.h index 8da67d4e140..496837cfc61 100644 --- a/modules/path/path_mod.h +++ b/modules/path/path_mod.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/pdt/pdt.c b/modules/pdt/pdt.c index 3d784eecc39..b00c69c04a9 100644 --- a/modules/pdt/pdt.c +++ b/modules/pdt/pdt.c @@ -21,7 +21,7 @@ * * History: * ------- - * 2003-04-07: a structure for both hashes introduced (ramona) + * 2003-04-07: a structure for both hashes introduced (ramona) * 2003-04-06: db connection closed in mod_init (janakj) * 2004-06-07: updated to the new DB api (andrei) * 2005-01-26: removed terminating code (ramona) @@ -63,7 +63,7 @@ /** structures containing prefix-domain pairs */ -pdt_tree_t **_ptree = NULL; +pdt_tree_t **_ptree = NULL; /** database connection */ static db_con_t *db_con = NULL; @@ -84,7 +84,7 @@ str prefix = {"", 0}; str pdt_char_list = {"0123456789", 10}; /* reader-writers lock */ -static rw_lock_t *pdt_lock = NULL; +static rw_lock_t *pdt_lock = NULL; static int w_prefix2domain(struct sip_msg* msg, char* str1, char* str2); static int w_prefix2domain_1(struct sip_msg* msg, char* mode, char* str2); @@ -133,11 +133,22 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; struct module_exports exports = { "pdt", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, params, 0, @@ -192,23 +203,23 @@ static int mod_init(void) db_con = pdt_dbf.init(&db_url); if(db_con==NULL) { - LM_ERR("failed to connect to the database\n"); + LM_ERR("failed to connect to the database\n"); return -1; } - + if (pdt_dbf.use_table(db_con, &db_table) < 0) { LM_ERR("failed to use_table\n"); goto error1; } LM_DBG("database connection opened successfully\n"); - + /* create & init lock */ if ((pdt_lock = lock_init_rw()) == NULL) { LM_CRIT("failed to init lock\n"); goto error1; } - + /* tree pointer in shm */ _ptree = (pdt_tree_t**)shm_malloc( sizeof(pdt_tree_t*) ); if (_ptree==0) { @@ -220,10 +231,10 @@ static int mod_init(void) /* loading all information from database */ if(pdt_load_db()!=0) { - LM_ERR("cannot load info from database\n"); + LM_ERR("cannot load info from database\n"); goto error1; } - + pdt_dbf.close(db_con); db_con = 0; @@ -355,13 +366,13 @@ static int prefix2domain(struct sip_msg* msg, int mode, int sd_en) str *d, p, all={"*",1}; int plen; struct sip_uri uri; - + if(msg==NULL) { LM_ERR("received null msg\n"); return -1; } - + /* parse the uri, if not yet */ if(msg->parsed_uri_ok==0) if(parse_sip_msg_uri(msg)<0) @@ -375,28 +386,28 @@ static int prefix2domain(struct sip_msg* msg, int mode, int sd_en) { LM_DBG("user part of the message is empty\n"); return -1; - } - + } + if(prefix.len>0) { if (msg->parsed_uri.user.len<=prefix.len) { LM_DBG("user part is less than prefix\n"); return -1; - } + } if(strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0) { LM_DBG("PSTN prefix did not matched\n"); return -1; } - } - + } + if(prefix.len>0 && prefix.len < msg->parsed_uri.user.len && strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0) { LM_DBG("PSTN prefix did not matched\n"); return -1; - + } p.s = msg->parsed_uri.user.s + prefix.len; @@ -405,22 +416,22 @@ static int prefix2domain(struct sip_msg* msg, int mode, int sd_en) lock_start_read( pdt_lock ); if(sd_en==2) - { + { /* take the domain from FROM uri as sdomain */ - if(parse_from_header(msg)<0 || msg->from == NULL + if(parse_from_header(msg)<0 || msg->from == NULL || get_from(msg)==NULL) { LM_ERR("cannot parse FROM header\n"); goto error; - } - + } + memset(&uri, 0, sizeof(struct sip_uri)); if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len , &uri)<0) { LM_ERR("failed to parse From uri\n"); goto error; } - + /* find the domain that corresponds to this prefix */ plen = 0; if((d=pdt_get_domain(*_ptree, &uri.host, &p, &plen))==NULL) @@ -432,22 +443,22 @@ static int prefix2domain(struct sip_msg* msg, int mode, int sd_en) goto error; } } - } else if(sd_en==1) { + } else if(sd_en==1) { /* take the domain from FROM uri as sdomain */ if(parse_from_header(msg)<0 || msg->from == NULL || get_from(msg)==NULL) { LM_ERR("ERROR cannot parse FROM header\n"); goto error; - } - + } + memset(&uri, 0, sizeof(struct sip_uri)); if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len , &uri)<0) { LM_ERR("failed to parse From uri\n"); goto error; } - + /* find the domain that corresponds to this prefix */ plen = 0; if((d=pdt_get_domain(*_ptree, &uri.host, &p, &plen))==NULL) @@ -464,7 +475,7 @@ static int prefix2domain(struct sip_msg* msg, int mode, int sd_en) goto error; } } - + /* update the new uri */ if(update_new_uri(msg, plen, d, mode)<0) { @@ -489,7 +500,7 @@ static int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode) LM_ERR("bad parameters\n"); return -1; } - + if(mode==0 || (mode==1 && prefix.len>0)) { act.type = STRIP_T; @@ -506,7 +517,7 @@ static int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode) return -1; } } - + act.type = SET_HOSTPORT_T; act.elem[0].type = STR_ST; act.elem[0].u.s = *d; @@ -518,9 +529,9 @@ static int update_new_uri(struct sip_msg *msg, int plen, str *d, int mode) return -1; } - LM_DBG("len=%d uri=%.*s\n", msg->new_uri.len, + LM_DBG("len=%d uri=%.*s\n", msg->new_uri.len, msg->new_uri.len, msg->new_uri.s); - + return 0; } @@ -530,8 +541,8 @@ static int pdt_load_db(void) str p, d, sdomain; db_res_t* db_res = NULL; int i, ret; - pdt_tree_t *_ptree_new = NULL; - pdt_tree_t *old_tree = NULL; + pdt_tree_t *_ptree_new = NULL; + pdt_tree_t *old_tree = NULL; int no_rows = 10; if(db_con==NULL) @@ -539,7 +550,7 @@ static int pdt_load_db(void) LM_ERR("no db connection\n"); return -1; } - + if (pdt_dbf.use_table(db_con, &db_table) < 0) { LM_ERR("failed to use_table\n"); @@ -590,7 +601,7 @@ static int pdt_load_db(void) p.s = (char*)(RES_ROWS(db_res)[i].values[1].val.string_val); p.len = strlen(p.s); - + d.s = (char*)(RES_ROWS(db_res)[i].values[2].val.string_val); d.len = strlen(d.s); @@ -600,7 +611,7 @@ static int pdt_load_db(void) LM_ERR("Error - bad values in db\n"); continue; } - + if(pdt_check_domain!=0 && _ptree_new!=NULL && pdt_check_pd(_ptree_new, &sdomain, &p, &d)==1) { @@ -662,10 +673,10 @@ static struct mi_root* pdt_mi_reload(struct mi_root *cmd_tree, void *param) /* re-loading all information from database */ if(pdt_load_db()!=0) { - LM_ERR("cannot re-load info from database\n"); + LM_ERR("cannot re-load info from database\n"); goto error; } - + return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); error: @@ -724,7 +735,7 @@ struct mi_root* pdt_mi_add(struct mi_root* cmd_tree, void* param) while(i< sp.len) { - if(strpos(pdt_char_list.s,sp.s[i]) < 0) + if(strpos(pdt_char_list.s,sp.s[i]) < 0) return init_mi_tree(400, "bad prefix", 10); i++; } @@ -744,7 +755,7 @@ struct mi_root* pdt_mi_add(struct mi_root* cmd_tree, void* param) if(*sd.s=='.') return init_mi_tree(400, "empty param", 11); - + if(pdt_check_domain!=0 && *_ptree!=NULL && pdt_check_pd(*_ptree, &sdomain, &sp, &sd)==1) { @@ -766,7 +777,7 @@ struct mi_root* pdt_mi_add(struct mi_root* cmd_tree, void* param) db_vals[2].nul = 0; db_vals[2].val.str_val.s = sd.s; db_vals[2].val.str_val.len = sd.len; - + /* insert a new domain into database */ if(pdt_dbf.insert(db_con, db_keys, db_vals, NR_KEYS)<0) { @@ -777,15 +788,15 @@ struct mi_root* pdt_mi_add(struct mi_root* cmd_tree, void* param) /* re-loading all information from database */ if(pdt_load_db()!=0) { - LM_ERR("cannot re-load info from database\n"); + LM_ERR("cannot re-load info from database\n"); goto error; } - + LM_DBG("new prefix added %.*s-%.*s => %.*s\n", sdomain.len, sdomain.s, sp.len, sp.s, sd.len, sd.s); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); - + error: if(pdt_dbf.delete(db_con, db_keys, db_ops, db_vals, NR_KEYS)<0) LM_ERR("database/cache are inconsistent\n"); @@ -841,7 +852,7 @@ struct mi_root* pdt_mi_delete(struct mi_root* cmd_tree, void* param) db_vals[0].nul = 0; db_vals[0].val.str_val.s = sdomain.s; db_vals[0].val.str_val.len = sdomain.len; - + db_vals[1].type = DB_STR; db_vals[1].nul = 0; db_vals[1].val.str_val.s = sd.s; @@ -851,11 +862,11 @@ struct mi_root* pdt_mi_delete(struct mi_root* cmd_tree, void* param) { LM_ERR("database/cache are inconsistent\n"); return init_mi_tree( 500, "database/cache are inconsistent", 31 ); - } + } /* re-loading all information from database */ if(pdt_load_db()!=0) { - LM_ERR("cannot re-load info from database\n"); + LM_ERR("cannot re-load info from database\n"); return init_mi_tree( 500, "cannot reload", 13 ); } @@ -876,7 +887,7 @@ int pdt_print_mi_node(pdt_node_t *pt, struct mi_node* rpl, char *code, if(pt==NULL || len>=PDT_MAX_DEPTH) return 0; - + for(i=0; is==NULL && sd->s==NULL) || (sp->s==NULL && (sd->s!=NULL && pt[i].domain.len==sd->len - && strncasecmp(pt[i].domain.s, sd->s, sd->len)==0)) + && strncasecmp(pt[i].domain.s, sd->s, sd->len)==0)) || (sd->s==NULL && (len+1>=sp->len && strncmp(code, sp->s, sp->len)==0)) || ((sp->s!=NULL && len+1>=sp->len @@ -904,7 +915,7 @@ int pdt_print_mi_node(pdt_node_t *pt, struct mi_node* rpl, char *code, code, len+1); if(attr == NULL) goto error; - + attr = add_mi_attr(node, MI_DUP_VALUE,"DOMAIN", 6, pt[i].domain.s, pt[i].domain.len); if(attr == NULL) @@ -930,10 +941,10 @@ int pdt_print_mi_node(pdt_node_t *pt, struct mi_node* rpl, char *code, * all domains starting with 'a' are listed * * Examples - * pdt_list o 2 . - lists the entries where sdomain is starting with 'o', + * pdt_list o 2 . - lists the entries where sdomain is starting with 'o', * prefix is starting with '2' and domain is anything - * - * pdt_list . 2 open - lists the entries where sdomain is anything, prefix + * + * pdt_list . 2 open - lists the entries where sdomain is anything, prefix * starts with '2' and domain starts with 'open' */ @@ -1005,16 +1016,17 @@ struct mi_root* pdt_mi_list(struct mi_root* cmd_tree, void* param) if(rpl_tree == NULL) return 0; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; if(*_ptree==0) return rpl_tree; pt = *_ptree; - + while(pt!=NULL) { - if(sdomain.s==NULL || - (sdomain.s!=NULL && pt->sdomain.len>=sdomain.len && + if(sdomain.s==NULL || + (sdomain.s!=NULL && pt->sdomain.len>=sdomain.len && strncmp(pt->sdomain.s, sdomain.s, sdomain.len)==0)) { len = 0; @@ -1024,7 +1036,7 @@ struct mi_root* pdt_mi_list(struct mi_root* cmd_tree, void* param) } pt = pt->next; } - + return rpl_tree; error: diff --git a/modules/pdt/pdtree.c b/modules/pdt/pdtree.c index 83242fa3cb9..730bb5692f5 100644 --- a/modules/pdt/pdtree.c +++ b/modules/pdt/pdtree.c @@ -63,7 +63,7 @@ pdt_tree_t* pdt_init_tree(str* sdomain) memcpy(pt->sdomain.s, sdomain->s, sdomain->len); pt->sdomain.len = sdomain->len; // printf("sdomain:%.*s\n", pt->sdomain.len, pt->sdomain.s); - + pt->head = (pdt_node_t*)shm_malloc(PDT_NODE_SIZE*sizeof(pdt_node_t)); if(pt->head == NULL) { @@ -73,7 +73,7 @@ pdt_tree_t* pdt_init_tree(str* sdomain) return NULL; } memset(pt->head, 0, PDT_NODE_SIZE*sizeof(pdt_node_t)); - + return pt; } @@ -81,7 +81,7 @@ int add_to_tree(pdt_tree_t *pt, str *sp, str *sd) { int l; pdt_node_t *itn, *itn0; - + if(pt==NULL || sp==NULL || sp->s==NULL || sd==NULL || sd->s==NULL) { @@ -94,7 +94,7 @@ int add_to_tree(pdt_tree_t *pt, str *sp, str *sd) LM_ERR("max prefix len exceeded\n"); return -1; } - + l = 0; itn0 = pt->head; itn = itn0[strpos(pdt_char_list.s,sp->s[l])%PDT_NODE_SIZE].child; @@ -105,9 +105,9 @@ int add_to_tree(pdt_tree_t *pt, str *sp, str *sd) { LM_ERR("invalid char %d in prefix [%c (0x%x)]\n", l, sp->s[l], sp->s[l]); - return -1; + return -1; } - + if(itn == NULL) { itn = (pdt_node_t*)shm_malloc(PDT_NODE_SIZE*sizeof(pdt_node_t)); @@ -119,7 +119,7 @@ int add_to_tree(pdt_tree_t *pt, str *sp, str *sd) memset(itn, 0, PDT_NODE_SIZE*sizeof(pdt_node_t)); itn0[strpos(pdt_char_list.s,sp->s[l])%PDT_NODE_SIZE].child = itn; } - l++; + l++; itn0 = itn; itn = itn0[strpos(pdt_char_list.s,sp->s[l])%PDT_NODE_SIZE].child; } @@ -143,14 +143,14 @@ int add_to_tree(pdt_tree_t *pt, str *sp, str *sd) itn0[strpos(pdt_char_list.s,sp->s[l])%PDT_NODE_SIZE].domain.len = sd->len; itn0[strpos(pdt_char_list.s,sp->s[l])%PDT_NODE_SIZE].domain.s[sd->len] = '\0'; - + return 0; } pdt_tree_t* pdt_get_tree(pdt_tree_t *pl, str *sdomain) { pdt_tree_t *it; - + if(pl==NULL) return NULL; @@ -167,7 +167,7 @@ pdt_tree_t* pdt_get_tree(pdt_tree_t *pl, str *sdomain) if(it==NULL || str_strcmp(&it->sdomain, sdomain)>0) return NULL; - + return it; } @@ -182,14 +182,14 @@ int pdt_add_to_tree(pdt_tree_t **dpt, str *sdomain, str *code, str *domain) LM_ERR("bad parameters\n"); return -1; } - + ndl = NULL; - + it = *dpt; prev = NULL; /* search the it position before which to insert new domain */ while(it!=NULL && str_strcmp(&it->sdomain, sdomain)<0) - { + { prev = it; it = it->next; } @@ -202,7 +202,7 @@ int pdt_add_to_tree(pdt_tree_t **dpt, str *sdomain, str *code, str *domain) if(ndl==NULL) { LM_ERR("no more shm memory\n"); - return -1; + return -1; } if(add_to_tree(ndl, code, domain)<0) @@ -211,7 +211,7 @@ int pdt_add_to_tree(pdt_tree_t **dpt, str *sdomain, str *code, str *domain) return -1; } ndl->next = it; - + /* new domain must be added as first element */ if(prev==NULL) *dpt = ndl; @@ -219,7 +219,7 @@ int pdt_add_to_tree(pdt_tree_t **dpt, str *sdomain, str *code, str *domain) prev->next=ndl; } - else + else /* add (prefix, code) to already present sdomain */ if(add_to_tree(it, code, domain)<0) { @@ -241,7 +241,7 @@ str* get_domain(pdt_tree_t *pt, str *sp, int *plen) LM_ERR("bad parameters\n"); return NULL; } - + l = len = 0; itn = pt->head; domain = NULL; @@ -260,16 +260,16 @@ str* get_domain(pdt_tree_t *pt, str *sp, int *plen) domain = &itn[strpos(pdt_char_list.s,sp->s[l])%PDT_NODE_SIZE].domain; len = l+1; } - + itn = itn[strpos(pdt_char_list.s,sp->s[l])%PDT_NODE_SIZE].child; - l++; + l++; } - + if(plen!=NULL) *plen = len; - + return domain; - + } str* pdt_get_domain(pdt_tree_t *pl, str* sdomain, str *code, int *plen) { @@ -287,10 +287,10 @@ str* pdt_get_domain(pdt_tree_t *pl, str* sdomain, str *code, int *plen) it = pl; while(it!=NULL && str_strcmp(&it->sdomain, sdomain)<0) it = it->next; - + if(it==NULL || str_strcmp(&it->sdomain, sdomain)>0) return NULL; - + domain = get_domain(it, code, &len); if(plen!=NULL) *plen = len; @@ -319,7 +319,7 @@ void pdt_free_node(pdt_node_t *pn) } shm_free(pn); pn = NULL; - + return; } @@ -328,13 +328,13 @@ void pdt_free_tree(pdt_tree_t *pt) if(pt == NULL) return; - if(pt->head!=NULL) + if(pt->head!=NULL) pdt_free_node(pt->head); if(pt->next!=NULL) pdt_free_tree(pt->next); if(pt->sdomain.s!=NULL) shm_free(pt->sdomain.s); - + shm_free(pt); pt = NULL; return; @@ -346,7 +346,7 @@ int pdt_print_node(pdt_node_t *pn, char *code, int len) if(pn==NULL || code==NULL || len>=PDT_MAX_DEPTH) return 0; - + for(i=0; isdomain.len, pt->sdomain.s); len = 0; pdt_print_node(pt->head, pdt_code_buf, len); @@ -381,7 +381,7 @@ int pdt_check_pd_node(pdt_node_t *pn, str *sp, str *sd, { int i; int ret; - + if(pn==NULL || code==NULL || len>=PDT_MAX_DEPTH) return 0; ret = 0; @@ -414,8 +414,8 @@ int pdt_check_pd_node(pdt_node_t *pn, str *sp, str *sd, return ret; } -/* returns - * 1 if prefix or domain already exists +/* returns + * 1 if prefix or domain already exists * 0 if prefix or domain does not exist * -1 if any error */ @@ -424,7 +424,7 @@ int pdt_check_pd(pdt_tree_t *pt, str* sdomain, str *sp, str *sd) int len; int ret; pdt_tree_t *it; - + if(pt==NULL || sp==NULL || sd==NULL) { LM_ERR("bad parameters\n"); diff --git a/modules/pdt/pdtree.h b/modules/pdt/pdtree.h index 6a659215f1a..1328162ddeb 100644 --- a/modules/pdt/pdtree.h +++ b/modules/pdt/pdtree.h @@ -24,7 +24,7 @@ * 2005-01-25 first tree version (ramona) */ - + #ifndef _PDTREE_H_ #define _PDTREE_H_ diff --git a/modules/peering/README b/modules/peering/README index 6ca06ff16d7..33bf790ba6e 100644 --- a/modules/peering/README +++ b/modules/peering/README @@ -18,8 +18,7 @@ Irina-Maria Stanescu Copyright © 2008 Juha Heinanen Revision History - Revision $Revision$ $Date: 2009-08-14 12:58:29 +0300 - (Fri, 14 Aug 2009) $ + Revision $Revision: 5952 $ $Date$ __________________________________________________________ Table of Contents @@ -169,7 +168,7 @@ modparam("peering", "verify_source_service_type", 22) Example 1.4. verify_destination() usage ... if (verify_destination()) { - append_hf("P-Request-Hash: $avp(i:200)\r\n"); + append_hf("P-Request-Hash: $avp(prh)\r\n"); } ... diff --git a/modules/peering/doc/peering_admin.xml b/modules/peering/doc/peering_admin.xml index 7a9a7f263a1..3d6124dfe3a 100644 --- a/modules/peering/doc/peering_admin.xml +++ b/modules/peering/doc/peering_admin.xml @@ -182,7 +182,7 @@ modparam("peering", "verify_source_service_type", 22) ... if (verify_destination()) { - append_hf("P-Request-Hash: $avp(i:200)\r\n"); + append_hf("P-Request-Hash: $avp(prh)\r\n"); } ... diff --git a/modules/peering/peering.c b/modules/peering/peering.c index 9f5f25c7396..f2db1c89148 100644 --- a/modules/peering/peering.c +++ b/modules/peering/peering.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -71,14 +71,25 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_AAA, NULL, DEP_WARN }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "peering", + "peering", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ diff --git a/modules/peering/peering.h b/modules/peering/peering.h index 8ac2bfcf8ee..92497043885 100644 --- a/modules/peering/peering.h +++ b/modules/peering/peering.h @@ -1,4 +1,4 @@ -/* +/* * Radius based peering module .h file * * Copyright (C) 2008 Juha Heinanen @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/perl/.gitignore b/modules/perl/.gitignore new file mode 100644 index 00000000000..64c139c0ea5 --- /dev/null +++ b/modules/perl/.gitignore @@ -0,0 +1 @@ +opensipsxs.c diff --git a/modules/perl/README b/modules/perl/README index bc9543e41d8..0340f5d6bee 100644 --- a/modules/perl/README +++ b/modules/perl/README @@ -10,8 +10,7 @@ Bastian Friedrich Copyright © 2007 Collax GmbH Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -1174,8 +1173,7 @@ Returns or sets the rows of the object. Chapter 3. Perl samples Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ 3.1. sample directory @@ -1359,4 +1357,4 @@ Chapter 4. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/perl/opensipsxs.xs b/modules/perl/opensipsxs.xs index 54a0b9a8c86..2952a43130f 100644 --- a/modules/perl/opensipsxs.xs +++ b/modules/perl/opensipsxs.xs @@ -267,7 +267,8 @@ int moduleFunc(struct sip_msg *m, char *func, act = mk_action( MODULE_T, 3, elems, - 0); + 0, + NULL); if (!act) { @@ -1199,7 +1200,8 @@ append_branch(self, branch = NULL, qval = NULL) act = mk_action(APPEND_BRANCH_T, 2, elems, - 0); + 0, + NULL); } } else { if (branch) { /* branch set, qval unset */ @@ -1210,7 +1212,8 @@ append_branch(self, branch = NULL, qval = NULL) act = mk_action(APPEND_BRANCH_T, 2, elems, - 0); + 0, + NULL); } else { /* neither branch nor qval set */ elems[0].type = STR_ST; elems[0].u.data = NULL; @@ -1219,7 +1222,8 @@ append_branch(self, branch = NULL, qval = NULL) act = mk_action(APPEND_BRANCH_T, 2, elems, - 0); + 0, + NULL); } } diff --git a/modules/perl/perl.c b/modules/perl/perl.c index 450c913a9ce..b15b1e886ab 100644 --- a/modules/perl/perl.c +++ b/modules/perl/perl.c @@ -99,7 +99,7 @@ static cmd_export_t cmds[] = { { "perl_exec_simple", (cmd_function)perl_exec_simple2, 2, NULL, 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, - { "perl_exec", (cmd_function)perl_exec1, 1, NULL, 0, + { "perl_exec", (cmd_function)perl_exec1, 1, NULL, 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, { "perl_exec", (cmd_function)perl_exec2, 2, NULL, 0, @@ -124,14 +124,21 @@ static param_export_t params[] = { * Exported MI functions */ static mi_export_t mi_cmds[] = { - /* FIXME This does not yet work... + /* FIXME This does not yet work... { "perl_reload", perl_mi_reload, MI_NO_INPUT_FLAG, 0, 0 },*/ { 0, 0, 0, 0, 0, 0} }; - - +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* * Module info @@ -151,9 +158,11 @@ static mi_export_t mi_cmds[] = { * Module interface */ struct module_exports exports = { - "perl", + "perl", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, RTLD_NOW | RTLD_GLOBAL, + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -211,7 +220,7 @@ PerlInterpreter *parser_init(void) { perl_construct(new_perl); argv[0] = ""; argc++; /* First param _needs_ to be empty */ - + /* Possible Include path extension by modparam */ if (modpath && (strlen(modpath) > 0)) { modpathset = argc; diff --git a/modules/perl/perlfunc.c b/modules/perl/perlfunc.c index 2ea56049462..ea8cb80060b 100644 --- a/modules/perl/perlfunc.c +++ b/modules/perl/perlfunc.c @@ -3,7 +3,7 @@ * * Perl module for OpenSIPS * - * Copyright (C) 2006 Collax GmbH + * Copyright (C) 2006 Collax GmbH * (Bastian Friedrich ) * * This file is part of opensips, a free SIP server. @@ -106,7 +106,7 @@ int perl_exec2(struct sip_msg* _msg, char* fnc, char* mystr) { } return -1; } - + switch ((_msg->first_line).type) { case SIP_REQUEST: if (parse_sip_msg_uri(_msg) < 0) { diff --git a/modules/permissions/README b/modules/permissions/README index ee7a05031ff..01c797a783d 100644 --- a/modules/permissions/README +++ b/modules/permissions/README @@ -24,8 +24,7 @@ Irina-Maria Stanescu Copyright © 2009 Irina-Maria Stanescu Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -579,8 +578,8 @@ if (method=="REGISTER") { if (allow_uri("basename", "$rt")) { // Check Refer-To URI t_relay(); }; -if (allow_uri("basename", "$avp(i:705)") { // Check URI stored in $avp( -i:705) +if (allow_uri("basename", "$avp(uri)") { // Check URI stored in $avp(ur +i) t_relay(); }; ... @@ -637,18 +636,17 @@ tocol test" // matches the regular expression field in the database table and stores the -// context information in $avp(i:10) -if (check_address("4","192.168.2.135","5700","$proto","$avp(i:10)", "tex -ttest")) { +// context information in $avp(ctx) +if (check_address("4","192.168.2.135","5700","$proto","$avp(ctx)", "text +test")) { t_relay(); - xlog("$avp(i:10)\n"); + xlog("$avp(ctx)\n"); } ... // Checks if the tuple IP address/port/protocol of the source message is - in group -// 4 and stores context information in $avp(i:10) + in group 4 if (check_address("4","$si","$sp","$proto")) { t_relay(); } @@ -657,14 +655,14 @@ if (check_address("4","$si","$sp","$proto")) { // Checks if the tuple IP address/port/protocol stored in AVPs s:ip/s:po rt/s:proto -// is in group 4 and stores context information in $avp(i:10) -$avp(s:ip) = "192.168.2.135"; -$avp(s:port) = 5061; -$avp(s:proto) = "any"; -if (check_address("4","$avp(s:ip)","$avp(s:port)","$avp(s:proto)","$avp( -i:10))) { +// is in group 4 and stores context information in $avp(ctx) +$avp(ip) = "192.168.2.135"; +$avp(port) = 5061; +$avp(proto) = "any"; +if (check_address("4","$avp(ip)","$avp(port)","$avp(proto)","$avp(ctx))) + { t_relay(); - xlog("$avp(i:10)\n"); + xlog("$avp(ctx)\n"); } ... @@ -693,9 +691,9 @@ if (check_address("4","$si","5700","$proto","", "texttest")) { Example 1.22. check_source_address() usage ... // Check if source address/port/proto is in group 4 and stores -// context information in $avp(i:9) -if (check_source_address("4","$avp(i:9)")) { - xlog("$avp(i:9)\n"); +// context information in $avp(ctx) +if (check_source_address("4","$avp(ctx)")) { + xlog("$avp(ctx)\n"); }else { sl_send_reply("403", "Forbidden"); } diff --git a/modules/permissions/address.c b/modules/permissions/address.c index a01ec636437..905ba566f06 100644 --- a/modules/permissions/address.c +++ b/modules/permissions/address.c @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/permissions/address.h b/modules/permissions/address.h index ce65b62a4d7..48dbb26ec25 100644 --- a/modules/permissions/address.h +++ b/modules/permissions/address.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/permissions/doc/permissions_admin.xml b/modules/permissions/doc/permissions_admin.xml index 10a49366a3b..a4907a8e547 100644 --- a/modules/permissions/doc/permissions_admin.xml +++ b/modules/permissions/doc/permissions_admin.xml @@ -773,7 +773,7 @@ if (method=="REGISTER") { if (allow_uri("basename", "$rt")) { // Check Refer-To URI t_relay(); }; -if (allow_uri("basename", "$avp(i:705)") { // Check URI stored in $avp(i:705) +if (allow_uri("basename", "$avp(uri)") { // Check URI stored in $avp(uri) t_relay(); }; ... @@ -867,16 +867,15 @@ if (allow_uri("basename", "$avp(i:705)") { // Check URI stored in $avp(i:705) // Checks if the tuple IP address/port (given as strings) and source protocol // (given as pvar), belongs to group 4, verifies if pattern string "texttest" // matches the regular expression field in the database table and stores the -// context information in $avp(i:10) -if (check_address("4","192.168.2.135","5700","$proto","$avp(i:10)", "texttest")) { +// context information in $avp(ctx) +if (check_address("4","192.168.2.135","5700","$proto","$avp(ctx)", "texttest")) { t_relay(); - xlog("$avp(i:10)\n"); + xlog("$avp(ctx)\n"); } ... -// Checks if the tuple IP address/port/protocol of the source message is in group -// 4 and stores context information in $avp(i:10) +// Checks if the tuple IP address/port/protocol of the source message is in group 4 if (check_address("4","$si","$sp","$proto")) { t_relay(); } @@ -884,13 +883,13 @@ if (check_address("4","$si","$sp","$proto")) { ... // Checks if the tuple IP address/port/protocol stored in AVPs s:ip/s:port/s:proto -// is in group 4 and stores context information in $avp(i:10) -$avp(s:ip) = "192.168.2.135"; -$avp(s:port) = 5061; -$avp(s:proto) = "any"; -if (check_address("4","$avp(s:ip)","$avp(s:port)","$avp(s:proto)","$avp(i:10))) { +// is in group 4 and stores context information in $avp(ctx) +$avp(ip) = "192.168.2.135"; +$avp(port) = 5061; +$avp(proto) = "any"; +if (check_address("4","$avp(ip)","$avp(port)","$avp(proto)","$avp(ctx))) { t_relay(); - xlog("$avp(i:10)\n"); + xlog("$avp(ctx)\n"); } ... @@ -924,9 +923,9 @@ if (check_address("4","$si","5700","$proto","", "texttest")) { ... // Check if source address/port/proto is in group 4 and stores -// context information in $avp(i:9) -if (check_source_address("4","$avp(i:9)")) { - xlog("$avp(i:9)\n"); +// context information in $avp(ctx) +if (check_source_address("4","$avp(ctx)")) { + xlog("$avp(ctx)\n"); }else { sl_send_reply("403", "Forbidden"); } diff --git a/modules/permissions/hash.c b/modules/permissions/hash.c index 0d3d65d1aa4..347811bc4a7 100644 --- a/modules/permissions/hash.c +++ b/modules/permissions/hash.c @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -166,7 +166,7 @@ int hash_match(struct sip_msg *msg, struct address_list** table, for (node = table[perm_hash(str_ip)]; node; node = node->next) { /* LM_DBG("Comparing (%s %s) , (%d %d) , (%d %d) , (%d %d)\n", - ip_addr2a(node->ip), ip_addr2a(ip), + ip_addr2a(node->ip), ip_addr2a(ip), node->proto, proto, node->port , port, node->grp , grp); diff --git a/modules/permissions/hash.h b/modules/permissions/hash.h index 0a19facc4c2..f1d480cdde8 100644 --- a/modules/permissions/hash.h +++ b/modules/permissions/hash.h @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -102,7 +102,7 @@ int find_group_in_hash_table(struct address_list** table, -#define PERM_MAX_SUBNETS 128 +#define PERM_MAX_SUBNETS 128 /* * Structure used to store a subnet @@ -123,7 +123,7 @@ struct subnet { struct subnet* new_subnet_table(void); -/* +/* * Check if an entry exists in subnet table that matches given group, ip_addr, * and port. Port 0 in subnet table matches any port. */ @@ -132,7 +132,7 @@ int match_subnet_table(struct sip_msg *msg, struct subnet* table, char *pattern, char* info); -/* +/* * Checks if an entry exists in subnet table that matches given ip_addr, * and port. Port 0 in subnet table matches any port. Returns group of * the first match or -1 if no match is found. @@ -140,7 +140,7 @@ int match_subnet_table(struct sip_msg *msg, struct subnet* table, int find_group_in_subnet_table(struct subnet* table, struct ip_addr *ip, unsigned int port); -/* +/* * Empty contents of subnet table */ void empty_subnet_table(struct subnet *table); @@ -153,7 +153,7 @@ void free_subnet_table(struct subnet* table); -/* +/* * Add into subnet table so that table is * kept ordered according to subnet, port, grp. */ @@ -162,7 +162,7 @@ int subnet_table_insert(struct subnet* table, unsigned int grp, str* pattern, str *info); -/* +/* * Print subnets stored in subnet table */ /*void subnet_table_print(struct subnet* table, FILE* reply_file);*/ diff --git a/modules/permissions/mi.c b/modules/permissions/mi.c index 9d52ec0bec3..429b80fadc8 100644 --- a/modules/permissions/mi.c +++ b/modules/permissions/mi.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -60,6 +60,7 @@ struct mi_root* mi_address_dump(struct mi_root *cmd_tree, void *param) rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK)); if (rpl_tree == NULL) return 0; + rpl_tree->node.flags |= MI_IS_ARRAY; if(hash_mi_print(*hash_table, &rpl_tree->node)< 0) { LM_ERR("failed to add a node\n"); @@ -81,7 +82,7 @@ struct mi_root* mi_allow_uri(struct mi_root *cmd, void *param) struct mi_node *node; str *basenamep, *urip, *contactp; char basename[MAX_FILE_LEN + 1]; - char uri[MAX_URI_SIZE + 1], contact[MAX_URI_SIZE + 1]; + char uri[MAX_URI_SIZE + 1], contact[MAX_URI_SIZE + 1]; unsigned int allow_suffix_len; node = cmd->node.kids; @@ -134,6 +135,7 @@ struct mi_root* mi_subnet_dump(struct mi_root *cmd_tree, void *param) rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK)); if (rpl_tree == NULL) return 0; + rpl_tree->node.flags |= MI_IS_ARRAY; if (subnet_table_mi_print(*subnet_table, &rpl_tree->node) < 0) { LM_ERR("failed to add a node\n"); diff --git a/modules/permissions/mi.h b/modules/permissions/mi.h index 8692d7568ea..200202c9fe9 100644 --- a/modules/permissions/mi.h +++ b/modules/permissions/mi.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/permissions/parse_config.c b/modules/permissions/parse_config.c index 5dfe10cc5b3..1ea2e9ecddc 100644 --- a/modules/permissions/parse_config.c +++ b/modules/permissions/parse_config.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -36,12 +36,12 @@ * return 0 on success, -1 on error * parsed expressions are returned in **e */ -static int parse_expression_list(char *str, expression **e) +static int parse_expression_list(char *str, expression **e) { int start=0, i=-1, j=-1, apost=0; char str2[EXPRESSION_LENGTH]; expression *e1=NULL, *e2; - + if (!str || !e) return -1; *e = NULL; @@ -66,12 +66,12 @@ static int parse_expression_list(char *str, expression **e) } strncpy(str2, str+start, j-start+1); str2[j-start+1] = '\0'; - + e2 = new_expression(str2); if (!e2) /* memory error */ goto error; - + if (e1) { /* it is not the first */ e1->next = e2; @@ -104,7 +104,7 @@ static int parse_expression_list(char *str, expression **e) * return 0 on success, -1 on error * parsed expressions are returned in **e, and exceptions are returned in **e_exceptions */ -static int parse_expression(char *str, expression **e, expression **e_exceptions) +static int parse_expression(char *str, expression **e, expression **e_exceptions) { char *except, str2[LINE_LENGTH+1]; int i,j; @@ -149,7 +149,7 @@ static int parse_expression(char *str, expression **e, expression **e_exceptions * parse one line of the config file * return the rule according to line */ -static rule *parse_config_line(char *line) +static rule *parse_config_line(char *line) { rule *rule1; expression *left, *left_exceptions, *right, *right_exceptions; @@ -167,28 +167,28 @@ static rule *parse_config_line(char *line) case '"': apost = !apost; eval = 1; break; - + case ':': if (!apost) colon = i; eval = 1; break; - - case '#': if (apost) break; + + case '#': if (apost) break; case '\0': case '\n': exit = 1; break; case ' ': break; case '\t': break; - + default: eval = 1; - + } } if (eval) { if ((0contact) { /* REGISTER messages that contain no Contact header field * are allowed. Such messages do not modify the contents of @@ -784,7 +786,7 @@ static int check_register(struct sip_msg* msg, int idx) if (search_rule(allow[idx].rules, to_str, contact_str)) { if (check_all_branches) goto skip_deny; } - + /* rule exists in deny file */ if (search_rule(deny[idx].rules, to_str, contact_str)) { LM_DBG("deny rule found => Register denied\n"); @@ -820,7 +822,7 @@ int allow_register_2(struct sip_msg* msg, char* allow_file, char* deny_file) * -1: deny * 1: allow */ -static int allow_uri(struct sip_msg* msg, char* _idx, char* _sp) +static int allow_uri(struct sip_msg* msg, char* _idx, char* _sp) { struct hdr_field *from; int idx, len; @@ -831,30 +833,30 @@ static int allow_uri(struct sip_msg* msg, char* _idx, char* _sp) idx = (int)(long)_idx; sp = (pv_spec_t *)_sp; - + /* turn off control, allow any uri */ if ((!allow[idx].rules) && (!deny[idx].rules)) { LM_DBG("no rules => allow any uri\n"); return 1; } - + /* looking for FROM HF */ if ((!msg->from) && (parse_headers(msg, HDR_FROM_F, 0) == -1)) { LM_ERR("failed to parse message\n"); return -1; } - + if (!msg->from) { LM_ERR("FROM header field not found\n"); return -1; } - + /* we must call parse_from_header explicitly */ if ((!(msg->from)->parsed) && (parse_from_header(msg) < 0)) { LM_ERR("failed to parse From body\n"); return -1; } - + from = msg->from; len = ((struct to_body*)from->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { @@ -888,7 +890,7 @@ static int allow_uri(struct sip_msg* msg, char* _idx, char* _sp) LM_DBG("allow rule found => URI is allowed\n"); return 1; } - + /* rule exists in deny file */ if (search_rule(deny[idx].rules, from_str, uri_str)) { LM_DBG("deny rule found => URI is denied\n"); @@ -908,7 +910,7 @@ int allow_test(char *file, char *uri, char *contact) { char *pathname; int idx; - + pathname = get_pathname(file); if (!pathname) { LM_ERR("Cannot get pathname of <%s>\n", file); @@ -923,13 +925,13 @@ int allow_test(char *file, char *uri, char *contact) } pkg_free(pathname); - + /* turn off control, allow any routing */ if ((!allow[idx].rules) && (!deny[idx].rules)) { LM_DBG("No rules => Allowed\n"); return 1; } - + LM_DBG("Looking for URI: %s, Contact: %s\n", uri, contact); /* rule exists in allow file */ @@ -937,7 +939,7 @@ int allow_test(char *file, char *uri, char *contact) LM_DBG("Allow rule found => Allowed\n"); return 1; } - + /* rule exists in deny file */ if (search_rule(deny[idx].rules, uri, contact)) { LM_DBG("Deny rule found => Denied\n"); diff --git a/modules/permissions/permissions.h b/modules/permissions/permissions.h index 3b8f170c15f..df748f64513 100644 --- a/modules/permissions/permissions.h +++ b/modules/permissions/permissions.h @@ -18,15 +18,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-09-03 replaced /usr/local/et/ser/ with CFG_DIR (andrei) */ - + #ifndef PERMISSIONS_H #define PERMISSIONS_H 1 diff --git a/modules/permissions/rule.c b/modules/permissions/rule.c index 5fae404f80d..597e5c3a95e 100644 --- a/modules/permissions/rule.c +++ b/modules/permissions/rule.c @@ -17,12 +17,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - + #include #include #include @@ -33,10 +33,10 @@ #include "rule.h" -/* - * allocate memory for a new rule +/* + * allocate memory for a new rule */ -rule *new_rule(void) +rule *new_rule(void) { rule *r; @@ -51,13 +51,13 @@ rule *new_rule(void) } -/* - * free memory allocated by a rule +/* + * free memory allocated by a rule */ -void free_rule(rule *r) +void free_rule(rule *r) { if (!r) return; - + if (r->left) free_expression(r->left); if (r->left_exceptions) free_expression(r->left_exceptions); if (r->right) free_expression(r->right); @@ -68,13 +68,13 @@ void free_rule(rule *r) } -/* - * list rules +/* + * list rules */ -void print_rule(rule *r) +void print_rule(rule *r) { if (!r) return; - + printf("\nNEW RULE:\n"); printf("\n\tLEFT: "); if (r->left) print_expression(r->left); else printf("ALL"); @@ -93,10 +93,10 @@ void print_rule(rule *r) } -/* - * look for a proper rule matching with left:right +/* + * look for a proper rule matching with left:right */ -int search_rule(rule *r, char *left, char *right) +int search_rule(rule *r, char *left, char *right) { rule *r1; @@ -114,14 +114,14 @@ int search_rule(rule *r, char *left, char *right) } -/* +/* * allocate memory for a new expression * str is saved in vale, and compiled to POSIX regexp (reg_value) */ -expression *new_expression(char *str) +expression *new_expression(char *str) { expression *e; - + if (!str) return 0; e = (expression *)pkg_malloc(sizeof(expression)); @@ -131,7 +131,7 @@ expression *new_expression(char *str) } strcpy(e->value, str); - + e->reg_value = (regex_t*)pkg_malloc(sizeof(regex_t)); if (!e->reg_value) { LM_ERR("not enough pkg memory\n"); @@ -145,16 +145,16 @@ expression *new_expression(char *str) pkg_free(e); return NULL; } - + e->next = 0; return e; } -/* - * free memory allocated by an expression +/* + * free memory allocated by an expression */ -void free_expression(expression *e) +void free_expression(expression *e) { if (!e) return; @@ -164,10 +164,10 @@ void free_expression(expression *e) } -/* - * list expressions +/* + * list expressions */ -void print_expression(expression *e) +void print_expression(expression *e) { if (!e) return; @@ -176,10 +176,10 @@ void print_expression(expression *e) } -/* - * look for matching expression +/* + * look for matching expression */ -int search_expression(expression *e, char *value) +int search_expression(expression *e, char *value) { expression *e1; diff --git a/modules/permissions/rule.h b/modules/permissions/rule.h index fc8379b6674..c886d3fdbba 100644 --- a/modules/permissions/rule.h +++ b/modules/permissions/rule.h @@ -17,12 +17,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - + #ifndef RULE_H #define RULE_H 1 @@ -37,7 +37,7 @@ typedef struct rule_struct rule; struct expression_struct; typedef struct expression_struct expression; - + rule *new_rule(void); void free_rule(rule *r); void print_rule(rule *r); diff --git a/modules/pi_http/README b/modules/pi_http/README index 4cf50434776..118c1fbb9aa 100644 --- a/modules/pi_http/README +++ b/modules/pi_http/README @@ -10,8 +10,7 @@ Ovidiu Sas Copyright © 2012-2013 VoIP Embedded, Inc. Revision History - Revision $Rev: 8688 $ $Date: 2012-01-25 13:52:05 -0500 (Wed, 25 - Jan 2012) $ + Revision $Rev: 8688 $ $Date$ __________________________________________________________ Table of Contents @@ -36,6 +35,7 @@ Ovidiu Sas 1.7.1. pi_http_root(string) 1.7.2. framework(string) + 1.7.3. pi_http_method(integrer) 1.8. Exported MI Functions @@ -45,6 +45,7 @@ Ovidiu Sas 1.1. Set pi_http_root parameter 1.2. Set framework parameter + 1.3. Set pi_http_method parameter Chapter 1. Admin Guide @@ -77,7 +78,7 @@ Chapter 1. Admin Guide a framework xml file is provided inside the examples directory of the pi_http module. A simple framework file can be generated by the opensipsdbctl command: -opensipsdbctl pframework creata +opensipsdbctl pframework create The generated framework will be saved inside OpenSIPS's config directory as pi_framework_sample. The list of configurable @@ -127,6 +128,8 @@ opensipsdbctl pframework creata * DB_STRING * DB_STR * DB_DATETIME + + Note: input field must be provided in 'YEAR-MM-DD + HH:MM:SS' format. * DB_BLOB * DB_BITMAP @@ -185,8 +188,7 @@ opensipsdbctl pframework creata Features to be added in the future: * full subscriber provisionning with automatic ha1/ha1b - fields; - * accept empty values as NULL; + fields. 1.5. Dependencies @@ -205,9 +207,9 @@ opensipsdbctl pframework creata 1.7.1. pi_http_root(string) - It specifies the root path for pi http requests. The link to - the OpenSIPS provisioning web interface must be constructed - using the following patern: + Specifies the root path for pi HTTP requests. The link to the + OpenSIPS provisioning web interface must be constructed using + the following patern: http://[opensips_IP]:[opensips_mi_port]/[pi_http_root] The default value is "pi". @@ -219,14 +221,27 @@ modparam("pi_http", "pi_http_root", "opensips_pi") 1.7.2. framework(string) - It specifies the full path for xml framework descriptor. + Specifies the full path for xml framework descriptor. There's no default value. This parameter is mandatory. Example 1.2. Set framework parameter ... -modparam("pi_http", "framework", "/usr/local/etc/opensips/pi_framework. -xml") +modparam("pi_http", "framework", "/usr/local/etc/opensips/pi_framework.x +ml") +... + +1.7.3. pi_http_method(integrer) + + Specifies the HTTP request method to be used: + * 0 - use GET HTTP request + * 1 - use POST HTTP request + + The default value is 0. + + Example 1.3. Set pi_http_method parameter +... +modparam("pi_http", "pi_http_method", 1) ... 1.8. Exported MI Functions diff --git a/modules/pi_http/doc/pi_http_admin.xml b/modules/pi_http/doc/pi_http_admin.xml index b0dfb98ec20..508cef903dd 100644 --- a/modules/pi_http/doc/pi_http_admin.xml +++ b/modules/pi_http/doc/pi_http_admin.xml @@ -46,7 +46,7 @@ directory of the pi_http module. A simple framework file can be generated by the opensipsdbctl command: -opensipsdbctl pframework creata +opensipsdbctl pframework create The generated framework will be saved inside &osips;'s config directory as pi_framework_sample. The list of configurable tables will @@ -112,7 +112,13 @@ opensipsdbctl pframework creata DB_DOUBLE DB_STRING DB_STR - DB_DATETIME + DB_DATETIME + + Note: input field must be provided in + 'YEAR-MM-DD HH:MM:SS' format. + + + DB_BLOB DB_BITMAP @@ -215,10 +221,7 @@ opensipsdbctl pframework creata - full subscriber provisionning with automatic ha1/ha1b fields; - - - accept empty values as NULL; + full subscriber provisionning with automatic ha1/ha1b fields.
@@ -258,7 +261,7 @@ opensipsdbctl pframework creata
<varname>pi_http_root</varname>(string) - It specifies the root path for pi http requests. + Specifies the root path for pi HTTP requests. The link to the &osips; provisioning web interface must be constructed using the following patern: http://[opensips_IP]:[opensips_mi_port]/[pi_http_root] @@ -278,7 +281,7 @@ modparam("pi_http", "pi_http_root", "opensips_pi")
<varname>framework</varname>(string) - It specifies the full path for xml framework descriptor. + Specifies the full path for xml framework descriptor. There's no default value. This parameter is mandatory. @@ -289,6 +292,27 @@ modparam("pi_http", "pi_http_root", "opensips_pi") ... modparam("pi_http", "framework", "/usr/local/etc/opensips/pi_framework.xml") ... + + +
+
+ <varname>pi_http_method</varname>(integrer) + + Specifies the HTTP request method to be used: + + 0 - use GET HTTP request + 1 - use POST HTTP request + + + + The default value is 0. + + + Set <varname>pi_http_method</varname> parameter + +... +modparam("pi_http", "pi_http_method", 1) +...
diff --git a/modules/pi_http/http_fnc.c b/modules/pi_http/http_fnc.c index bfcf1384878..8140930ca1a 100644 --- a/modules/pi_http/http_fnc.c +++ b/modules/pi_http/http_fnc.c @@ -1,7 +1,7 @@ /* * $Id$ * - * Copyright (C) 2011 VoIP Embedded Inc. + * Copyright (C) 2011-2013 VoIP Embedded Inc. * * This file is part of Open SIP Server (opensips). * @@ -62,6 +62,7 @@ #define PI_HTTP_XML_COL_NODE "col" #define PI_HTTP_XML_FIELD_NODE "field" +#define PI_HTTP_XML_LINK_CMD_NODE "link_cmd" #define PI_HTTP_XML_TYPE_NODE "type" #define PI_HTTP_XML_OPERATOR_NODE "operator" #define PI_HTTP_XML_VALUE_NODE "value" @@ -70,6 +71,7 @@ #define PI_HTTP_XML_ID_ATTR "id" extern str http_root; +extern int http_method; extern httpd_api_t httpd_api; ph_framework_t *ph_framework_data = NULL; @@ -249,6 +251,54 @@ do{ \ goto error; \ }while(0) +/* */ +#define PI_HTTP_ESC_COPY(p,str,temp_holder,temp_counter) \ +do{ \ + (temp_holder).s = (str).s; \ + (temp_holder).len = 0; \ + for((temp_counter)=0;(temp_counter)<(str).len;(temp_counter)++) { \ + switch((str).s[(temp_counter)]) { \ + case '<': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + PI_HTTP_COPY_2(p, (temp_holder), PI_HTTP_ESC_LT); \ + (temp_holder).s = (str).s + (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '>': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + PI_HTTP_COPY_2(p, (temp_holder), PI_HTTP_ESC_GT); \ + (temp_holder).s = (str).s + (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '&': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + PI_HTTP_COPY_2(p, (temp_holder), PI_HTTP_ESC_AMP); \ + (temp_holder).s = (str).s + (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '"': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + PI_HTTP_COPY_2(p, (temp_holder), PI_HTTP_ESC_QUOT); \ + (temp_holder).s = (str).s + (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + case '\'': \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + PI_HTTP_COPY_2(p, (temp_holder), PI_HTTP_ESC_SQUOT); \ + (temp_holder).s = (str).s + (temp_counter) + 1; \ + (temp_holder).len = (temp_counter) + 1; \ + break; \ + } \ + } \ + (temp_holder).len = (temp_counter) - (temp_holder).len; \ + PI_HTTP_COPY(p, (temp_holder)); \ +}while(0) + + +static const str PI_HTTP_METHOD[] = { + str_init("GET"), + str_init("POST") +}; static const str PI_HTTP_Response_Head_1 = str_init(""\ "OpenSIPS Provisionning Interface"\ @@ -258,14 +308,15 @@ static const str PI_HTTP_Response_Head_1 = str_init(""\ "a:hover{text-decoration:none;}a{text-decoration:underline;}"\ ".foot{padding-top:40px;font-size:10px;color:#333333;}"\ ".foot a{font-size:10px;color:#000000;}" - "table.center{margin-left:auto;margin-right:auto;}\n"\ + "table.center{margin-left:auto;margin-right:auto;}"\ "</style>"\ "<meta http-equiv=\"Expires\" content=\"0\">"\ "<meta http-equiv=\"Pragma\" content=\"no-cache\">"); static const str PI_HTTP_Response_Head_2 = str_init(\ -"</head>"\ +"<link rel=\"icon\" type=\"image/png\" href=\"http://opensips.org/favicon.png\">"\ +"</head>\n"\ "<body alink=\"#000000\" bgcolor=\"#ffffff\" link=\"#000000\" text=\"#000000\" vlink=\"#000000\">"); static const str PI_HTTP_Response_Title_Table_1 = str_init(\ @@ -287,7 +338,6 @@ static const str PI_HTTP_Response_Menu_Cmd_Table_1a = str_init("<table border=\" static const str PI_HTTP_Response_Menu_Cmd_Table_1b = str_init("<table border=\"1\" cellpadding=\"3\" cellspacing=\"0\" width=\"90%\"><tbody>\n"); static const str PI_HTTP_Response_Menu_Cmd_tr_1 = str_init("<tr>\n"); static const str PI_HTTP_Response_Menu_Cmd_td_1a = str_init(" <td width=\"10%\"><a href='"); -static const str PI_HTTP_Response_Menu_Cmd_td_3a = str_init("'>"); static const str PI_HTTP_Response_Menu_Cmd_td_4a = str_init("</a></td>\n"); static const str PI_HTTP_Response_Menu_Cmd_td_1b = str_init(" <td align=\"left\"><b>"); static const str PI_HTTP_Response_Menu_Cmd_td_1c = str_init(" <td valign=\"top\" align=\"left\" rowspan=\""); @@ -304,6 +354,7 @@ static const str PI_HTTP_Response_Menu_Cmd_Table_2 = str_init("</tbody></table>\ static const str PI_HTTP_NBSP = str_init(" "); static const str PI_HTTP_SLASH = str_init("/"); static const str PI_HTTP_SEMICOLON = str_init(" : "); +static const str PI_HTTP_SQUOT_GT = str_init("'>"); static const str PI_HTTP_NODE_INDENT = str_init("\t"); static const str PI_HTTP_NODE_SEPARATOR = str_init(":: "); @@ -314,9 +365,11 @@ static const str PI_HTTP_BREAK = str_init("<br/>"); static const str PI_HTTP_CODE_1 = str_init("<pre>"); static const str PI_HTTP_CODE_2 = str_init("</pre>"); -static const str PI_HTTP_Post_Form_1 = str_init("\n"\ -" <form name=\"input\" method=\"get\">\n" +static const str PI_HTTP_Post_Form_1a = str_init("\n"\ +" <form name=\"input\" method=\""); +static const str PI_HTTP_Post_Form_1b = str_init("\">\n" " <input type=hidden name=cmd value=\"on\">\n"); + static const str PI_HTTP_Post_Input = str_init(\ " "); static const str PI_HTTP_Post_Clause_Input = str_init("<br/>Clause:"); @@ -349,13 +402,23 @@ static const str PI_HTTP_Response_Foot = str_init(\ "\n</center>\n<div align=\"center\" class=\"foot\" style=\"margin:20px auto\">"\ "<span style='margin-left:5px;'></span>"\ "<a href=\"http://opensips.org\">OpenSIPS web site</a><br/>"\ - "Copyright © 2012-2013 <a href=\"http://www.voipembedded.com/\">VoIP Embedded</a>"\ + "Copyright © 2012-2014 <a href=\"http://www.voipembedded.com/\">VoIP Embedded, Inc.</a>"\ ". All rights reserved."\ "</div></body></html>"); #define PI_HTTP_ROWSPAN 20 static const str PI_HTTP_CMD_ROWSPAN = str_init("20"); +static const str PI_HTTP_ESC_LT = str_init("<"); /* < */ +static const str PI_HTTP_ESC_GT = str_init(">"); /* > */ +static const str PI_HTTP_ESC_AMP = str_init("&"); /* & */ +static const str PI_HTTP_ESC_QUOT = str_init("""); /* " */ +static const str PI_HTTP_ESC_SQUOT = str_init("'"); /* ' */ + +static const str PI_HTTP_HREF_1 = str_init("<a href='/"); +static const str PI_HTTP_HREF_2 = str_init("?cmd=pre&"); +static const str PI_HTTP_HREF_3 = str_init("</a>"); + xmlAttrPtr ph_xmlNodeGetAttrByName(xmlNodePtr node, const char *name) { @@ -836,7 +899,7 @@ int ph_getColVals(ph_mod_t *module, ph_cmd_t *cmd, if(vals==NULL||ids==NULL) {LM_ERR("oom\n"); return -1;} col_vals = vals; col_ids = ids; vals = &col_vals[size]; ids = &col_ids[size]; - memset(vals, 0, sizeof(str*)); memset(ids, 0, sizeof(str*)); + memset(vals, 0, sizeof *vals); memset(ids, 0, sizeof *ids); /* Retrieve the node attribute */ attr.s = ph_xmlNodeGetAttrContentByName(node, PI_HTTP_XML_ID_ATTR); @@ -889,7 +952,7 @@ int ph_getColVals(ph_mod_t *module, ph_cmd_t *cmd, int ph_getCols(ph_mod_t *module, ph_cmd_t *cmd, db_op_t **mod_cmd_ops, db_key_t **mod_cmd_keys, - db_type_t **mod_cmd_types, ph_vals_t **mod_cmd_vals, + db_type_t **mod_cmd_types, ph_vals_t **mod_cmd_vals, str **mod_cmd_linkCmd, int *key_size, xmlNodePtr cmd_node) { xmlNodePtr node; @@ -906,6 +969,9 @@ int ph_getCols(ph_mod_t *module, ph_cmd_t *cmd, db_type_t *cmd_types = NULL; ph_vals_t *vals; ph_vals_t *cmd_vals = NULL; + str link_cmd; + str *linkCmd; + str *cmd_linkCmd = NULL; int i; int size = 0; int table_size; @@ -1093,6 +1159,36 @@ int ph_getCols(ph_mod_t *module, ph_cmd_t *cmd, if(ph_getColVals(module, cmd, vals, node)!=0) return -1; } + /* Retrieve the link_cmds */ + if(mod_cmd_linkCmd){ + if(size) + linkCmd = (str*)shm_realloc(cmd_linkCmd, + (size+1)*sizeof(str)); + else + linkCmd = (str*)shm_malloc(sizeof(str)); + if(linkCmd==NULL) {LM_ERR("oom\n");return -1;} + cmd_linkCmd = linkCmd; + linkCmd = &cmd_linkCmd[size]; + memset(linkCmd, 0, sizeof(str)); + /* get the link_cmd */ + link_cmd.s = ph_xmlNodeGetNodeContentByName(node->children, + PI_HTTP_XML_LINK_CMD_NODE); + if(link_cmd.s!=NULL){ + link_cmd.len = strlen(link_cmd.s); + if(link_cmd.len!=0){ + LM_DBG("got %s=[%.*s] in %s [%.*s] %s [%.*s] %s %s\n", + PI_HTTP_XML_LINK_CMD_NODE, + link_cmd.len, link_cmd.s, + cmd_node->parent->parent->name, + module->module.len, module->module.s, + cmd_node->parent->name, + cmd->name.len, cmd->name.s, + cmd_node->name, node->name); + if(shm_str_dup(linkCmd, &link_cmd)) return -1; + } + xmlFree(link_cmd.s); link_cmd.s = NULL; link_cmd.len = 0; + } + } size++; } } @@ -1113,6 +1209,7 @@ int ph_getCols(ph_mod_t *module, ph_cmd_t *cmd, if(mod_cmd_ops) *mod_cmd_ops = cmd_ops; if(mod_cmd_types) *mod_cmd_types = cmd_types; if(mod_cmd_vals&&cmd_vals) *mod_cmd_vals = cmd_vals; + if(mod_cmd_linkCmd) *mod_cmd_linkCmd = cmd_linkCmd; if(cmd_vals) for(i=0;i<size;i++){ LM_DBG("cmd_vals[%d]=[%p]->[%d][%p][%p]\n", i, &cmd_vals[i], cmd_vals[i].vals_size, @@ -1127,6 +1224,7 @@ int ph_getCols(ph_mod_t *module, ph_cmd_t *cmd, cmd_vals[i].vals[op_len].len, cmd_vals[i].vals[op_len].s); } + if(mod_cmd_linkCmd&&cmd_linkCmd) *mod_cmd_linkCmd = cmd_linkCmd; *key_size = size; if(cmd_ops) for(i=0;i<size;i++) LM_DBG("cmd_ops[%d]=[%p]->[%s]\n", @@ -1272,6 +1370,7 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, &cmds->c_keys, &cmds->c_types, &cmds->c_vals, + NULL, &cmds->c_keys_size, cmd_cols)!=0) return -1; @@ -1285,6 +1384,7 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, &cmds->q_keys, &cmds->q_types, NULL, + &cmds->link_cmd, &cmds->q_keys_size, cmd_cols)!=0) return -1; @@ -1308,7 +1408,8 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, NULL, &cmds->o_keys, NULL, - &cmds->q_vals, + NULL, + NULL, &cmds->o_keys_size, cmd_cols)!=0) return -1; @@ -1327,6 +1428,7 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, &cmds->q_keys, &cmds->q_types, &cmds->q_vals, + NULL, &cmds->q_keys_size, cmd_cols)!=0) return -1; @@ -1353,6 +1455,7 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, &cmds->c_keys, &cmds->c_types, &cmds->c_vals, + NULL, &cmds->c_keys_size, cmd_cols)!=0) return -1; @@ -1380,6 +1483,7 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, &cmds->c_keys, &cmds->c_types, &cmds->c_vals, + NULL, &cmds->c_keys_size, cmd_cols)!=0) return -1; @@ -1393,6 +1497,7 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, &cmds->q_keys, &cmds->q_types, &cmds->q_vals, + NULL, &cmds->q_keys_size, cmd_cols)!=0) return -1; @@ -1421,6 +1526,7 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, &cmds->q_keys, &cmds->q_types, &cmds->q_vals, + NULL, &cmds->q_keys_size, cmd_cols)!=0) return -1; @@ -1476,10 +1582,12 @@ int ph_getCmds(ph_db_table_t *ph_db_tables, int ph_db_tables_size, if(cmds->q_keys) for(i=0;i<cmds->q_keys_size;i++){ LM_DBG(" [%d] q_keys=[%.*s] " - "q_types=[%d]\n", + "q_types=[%d] link_cmd=[%.*s]\n", i, (*(cmds->q_keys[i])).len, (*(cmds->q_keys[i])).s, - cmds->q_types[i]); + cmds->q_types[i], + (cmds->link_cmd)?(cmds->link_cmd[i]).len:0, + (cmds->link_cmd)?(cmds->link_cmd[i]).s:NULL); if(cmds->q_vals) for(j=0;j<cmds->q_vals->vals_size;j++) LM_DBG(" c_vals[%d] " @@ -1623,8 +1731,8 @@ void ph_freeMods(ph_mod_t **ph_modules, int ph_modules_size) ph_mod_t *_ph_modules = *ph_modules; db_key_t *cmd_keys; db_op_t *cmd_ops; - db_type_t *cmd_types; ph_vals_t *cmd_vals; + str *cmd_linkCmd; if(_ph_modules==NULL) return; for(i=0;i<ph_modules_size;i++){ @@ -1640,7 +1748,6 @@ void ph_freeMods(ph_mod_t **ph_modules, int ph_modules_size) /* */ cmd_keys = _ph_modules[i].cmds[j].c_keys; cmd_ops = _ph_modules[i].cmds[j].c_ops; - cmd_types = _ph_modules[i].cmds[j].c_types; cmd_vals = _ph_modules[i].cmds[j].c_vals; for(k=0;k<_ph_modules[i].cmds[j].c_keys_size;k++){ if(cmd_ops && cmd_ops[k]){ @@ -1690,12 +1797,10 @@ void ph_freeMods(ph_mod_t **ph_modules, int ph_modules_size) shm_free(_ph_modules[i].cmds[j].c_vals); _ph_modules[i].cmds[j].c_vals = NULL; } - cmd_keys = NULL; cmd_ops = NULL; - cmd_types = NULL; cmd_vals = NULL; /* */ cmd_keys = _ph_modules[i].cmds[j].q_keys; - cmd_types = _ph_modules[i].cmds[j].q_types; cmd_vals = _ph_modules[i].cmds[j].q_vals; + cmd_linkCmd = _ph_modules[i].cmds[j].link_cmd; for(k=0;k<_ph_modules[i].cmds[j].q_keys_size;k++){ if(cmd_keys && cmd_keys[k]){ if(cmd_keys[k]->s){ @@ -1723,6 +1828,10 @@ void ph_freeMods(ph_mod_t **ph_modules, int ph_modules_size) cmd_vals[k].vals = NULL; } } + if(cmd_linkCmd && cmd_linkCmd[k].s){ + shm_free(cmd_linkCmd[k].s); + cmd_linkCmd[k].s = NULL; + } } if(_ph_modules[i].cmds[j].q_keys){ shm_free(_ph_modules[i].cmds[j].q_keys); @@ -1736,7 +1845,11 @@ void ph_freeMods(ph_mod_t **ph_modules, int ph_modules_size) shm_free(_ph_modules[i].cmds[j].q_vals); _ph_modules[i].cmds[j].q_vals = NULL; } - cmd_keys = NULL; cmd_types = NULL; cmd_vals = NULL; + if(_ph_modules[i].cmds[j].link_cmd){ + shm_free(_ph_modules[i].cmds[j].link_cmd); + _ph_modules[i].cmds[j].link_cmd = NULL; + } + cmd_keys = NULL; cmd_vals = NULL; /* */ cmd_keys = _ph_modules[i].cmds[j].c_keys; for(k=0;k<_ph_modules[i].cmds[j].c_keys_size;k++){ @@ -1862,7 +1975,7 @@ int ph_parse_url(const char* url, int* mod, int* cmd) int i; int mod_len, cmd_len; ph_mod_t *ph_modules = ph_framework_data->ph_modules; - + if (url_len<0) { LM_ERR("Invalid url length [%d]\n", url_len); @@ -1928,11 +2041,15 @@ int ph_parse_url(const char* url, int* mod, int* cmd) } -int ph_build_form_imput(char **p, char *buf, int max_page_len, int mod, int cmd) +int ph_build_form_imput(char **p, char *buf, str *page, int max_page_len, + int mod, int cmd, str *clause, db_val_t *values) { unsigned long i, j; char c; str op, arg; + str val_str; + str temp_holder; + int temp_counter; ph_cmd_t *command; ph_mod_t *ph_modules; @@ -1957,6 +2074,10 @@ int ph_build_form_imput(char **p, char *buf, int max_page_len, int mod, int cmd) PI_HTTP_COPY(*p, op); PI_HTTP_COPY(*p, PI_HTTP_Post_Input_Text); PI_HTTP_COPY(*p, arg); + if (i==0 && clause) { + PI_HTTP_COPY(*p, PI_HTTP_Post_Input_Hidden_2); + PI_HTTP_COPY(*p, *clause); + } PI_HTTP_COPY(*p, PI_HTTP_Post_Input_3); break; case 1: @@ -2004,6 +2125,127 @@ int ph_build_form_imput(char **p, char *buf, int max_page_len, int mod, int cmd) PI_HTTP_COPY(*p, *command->q_keys[i]); PI_HTTP_COPY(*p, PI_HTTP_Post_Input_Text); PI_HTTP_COPY(*p, arg); + if (values) { + PI_HTTP_COPY(*p, PI_HTTP_Post_Input_Hidden_2); + switch(command->q_types[i]){ + case DB_STR: + case DB_STRING: + case DB_BLOB: + if(values[i].val.str_val.s==NULL){ + val_str.s = NULL; val_str.len = 0; + } else { + val_str.s = values[i].val.str_val.s; + val_str.len = strlen(val_str.s); + } + LM_DBG("...got %.*s[0]=>" + "[%.*s][%.*s]\n", + command->q_keys[i]->len, + command->q_keys[i]->s, + values[i].val.str_val.len, + values[i].val.str_val.s, + val_str.len, val_str.s); + if (val_str.len) { + PI_HTTP_ESC_COPY(*p, val_str, temp_holder, temp_counter); + } + break; + case DB_INT: + val_str.s = *p; + val_str.len = max_page_len - page->len; + if(db_int2str(values[i].val.int_val, + val_str.s, &val_str.len)!=0){ + LM_ERR("Unable to convert int [%d]\n", + values[i].val.int_val); + goto error; + } + *p += val_str.len; + page->len += val_str.len; + LM_DBG(" got %.*s[0]=>" + "[%d][%.*s]\n", + command->q_keys[i]->len, + command->q_keys[i]->s, + values[i].val.int_val, + val_str.len, val_str.s); + break; + case DB_BITMAP: + val_str.s = *p; + val_str.len = max_page_len - page->len; + if(db_int2str(values[i].val.bitmap_val, + val_str.s, &val_str.len)!=0){ + LM_ERR("Unable to convert bitmap [%d]\n", + values[i].val.bitmap_val); + goto error; + } + *p += val_str.len; + page->len += val_str.len; + LM_DBG(" got %.*s[0]=>" + "[%d][%.*s]\n", + command->q_keys[i]->len, + command->q_keys[i]->s, + values[i].val.bitmap_val, + val_str.len, val_str.s); + break; + case DB_BIGINT: + val_str.s = *p; + val_str.len = max_page_len - page->len; + if(db_bigint2str(values[i].val.bigint_val, + val_str.s, &val_str.len)!=0){ + LM_ERR("Unable to convert bigint [%-lld]\n", + values[i].val.bigint_val); + goto error; + } + *p += val_str.len; + page->len += val_str.len; + LM_DBG(" got %.*s[0]=>" + "[%-lld][%.*s]\n", + command->q_keys[i]->len, + command->q_keys[i]->s, + values[i].val.bigint_val, + val_str.len, val_str.s); + break; + case DB_DOUBLE: + val_str.s = *p; + val_str.len = max_page_len - page->len; + if(db_double2str(values[i].val.double_val, + val_str.s, &val_str.len)!=0){ + LM_ERR("Unable to convert double [%-10.2f]\n", + values[i].val.double_val); + goto error; + } + *p += val_str.len; + page->len += val_str.len; + LM_DBG(" got %.*s[0]=>" + "[%-10.2f][%.*s]\n", + command->q_keys[i]->len, + command->q_keys[i]->s, + values[i].val.double_val, + val_str.len, val_str.s); + break; + case DB_DATETIME: + val_str.s = *p; + val_str.len = max_page_len - page->len; + if (db_time2str_nq(values[i].val.time_val, + val_str.s, &val_str.len)!=0){ + LM_ERR("Unable to convert time [%ld]\n", + (unsigned long int)values[i].val.time_val); + goto error; + } + *p += val_str.len; + page->len += val_str.len; + LM_DBG(" got %.*s[0]=>" + "[%ld][%.*s]\n", + command->q_keys[i]->len, + command->q_keys[i]->s, + (unsigned long int)values[i].val.time_val, + val_str.len, val_str.s); + break; + default: + LM_ERR("unexpected type [%d] " + "for [%.*s]\n", + command->q_types[i], + command->q_keys[i]->len, + command->q_keys[i]->s); + } + } PI_HTTP_COPY(*p, PI_HTTP_Post_Input_3); break; case 1: @@ -2110,7 +2352,7 @@ int ph_build_reply(str *page, int max_page_len, int mod, int cmd) PI_HTTP_COPY_6(p,ph_modules[mod].module, PI_HTTP_SLASH, ph_modules[mod].cmds[cmd].name, - PI_HTTP_Response_Menu_Cmd_td_3a, + PI_HTTP_SQUOT_GT, ph_modules[mod].cmds[cmd].name, PI_HTTP_Response_Menu_Cmd_td_4a); /* Print cmd name */ @@ -2149,7 +2391,7 @@ int ph_build_reply_footer(str *page, int max_page_len) return -1; } -int ph_build_content(str *page, int max_page_len, int mod, int cmd) +int ph_build_content(str *page, int max_page_len, int mod, int cmd, str *clause, db_val_t *values) { char *p, *buf; int j; @@ -2171,7 +2413,7 @@ int ph_build_content(str *page, int max_page_len, int mod, int cmd) PI_HTTP_COPY_6(p,ph_modules[mod].module, PI_HTTP_SLASH, ph_modules[mod].cmds[0].name, - PI_HTTP_Response_Menu_Cmd_td_3a, + PI_HTTP_SQUOT_GT, ph_modules[mod].cmds[0].name, PI_HTTP_Response_Menu_Cmd_td_4a); if (cmd>=0) { @@ -2190,18 +2432,20 @@ int ph_build_content(str *page, int max_page_len, int mod, int cmd) PI_HTTP_COPY_6(p,ph_modules[mod].module, PI_HTTP_SLASH, ph_modules[mod].cmds[j].name, - PI_HTTP_Response_Menu_Cmd_td_3a, + PI_HTTP_SQUOT_GT, ph_modules[mod].cmds[j].name, PI_HTTP_Response_Menu_Cmd_td_4a); if (cmd>=0){ if (j==1) { - PI_HTTP_COPY_4(p, + PI_HTTP_COPY_6(p, PI_HTTP_Response_Menu_Cmd_td_1c, PI_HTTP_CMD_ROWSPAN, PI_HTTP_Response_Menu_Cmd_td_3c, - PI_HTTP_Post_Form_1); - if(ph_build_form_imput(&p, buf, max_page_len, - mod, cmd)!=0) + PI_HTTP_Post_Form_1a, + PI_HTTP_METHOD[http_method], + PI_HTTP_Post_Form_1b); + if(ph_build_form_imput(&p, buf, page, max_page_len, + mod, cmd, clause, values)!=0) return -1; PI_HTTP_COPY_2(p, PI_HTTP_Post_Form_2, PI_HTTP_Response_Menu_Cmd_td_4c); @@ -2216,16 +2460,18 @@ int ph_build_content(str *page, int max_page_len, int mod, int cmd) } if (cmd>=0){ if (j==1) { - PI_HTTP_COPY_8(p,PI_HTTP_Response_Menu_Cmd_tr_1, + PI_HTTP_COPY_10(p,PI_HTTP_Response_Menu_Cmd_tr_1, PI_HTTP_Response_Menu_Cmd_td_1d, PI_HTTP_NBSP, PI_HTTP_Response_Menu_Cmd_td_4d, PI_HTTP_Response_Menu_Cmd_td_1c, PI_HTTP_CMD_ROWSPAN, PI_HTTP_Response_Menu_Cmd_td_3c, - PI_HTTP_Post_Form_1); - if(ph_build_form_imput(&p, buf, max_page_len, - mod, cmd)!=0) + PI_HTTP_Post_Form_1a, + PI_HTTP_METHOD[http_method], + PI_HTTP_Post_Form_1b); + if(ph_build_form_imput(&p, buf, page, max_page_len, + mod, cmd, clause, values)!=0) return -1; PI_HTTP_COPY_3(p, PI_HTTP_Post_Form_2, PI_HTTP_Response_Menu_Cmd_td_4c, @@ -2457,31 +2703,36 @@ int getVal(db_val_t *val, db_type_t val_type, db_key_t key, ph_db_table_t *table -int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) +int ph_run_pi_cmd(int mod, int cmd, + void *connection, void *con_cls, + str *page, str *buffer) { char *p; - char *_p, *buf; + char *buf; int ret; - const char *arg = NULL; str s_arg; - //unsigned long i; + str l_arg; + str temp_holder; + int temp_counter; int i; int j; int max_page_len; ph_cmd_t *command; int _len; + int link_on; + char tmp; char c[2]; db_val_t *c_vals = NULL; db_val_t *q_vals = NULL; db_val_t *val; str val_str = {NULL, 0}; int nr_rows; - ph_db_url_t *db_url; + ph_db_url_t *db_url = NULL; db_res_t *res = NULL; - db_val_t *values; + db_val_t *values = NULL; db_row_t *rows; ph_mod_t *ph_modules; @@ -2499,53 +2750,144 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) buf = page->s; p = page->s + page->len; - if (cmd<0) return ph_build_content(page, buffer->len, mod, cmd); + if (cmd<0) return ph_build_content(page, buffer->len, mod, cmd, NULL, NULL); + + httpd_api.lookup_arg(connection, "cmd", con_cls, &l_arg); + if(l_arg.s==NULL) return ph_build_content(page, buffer->len, mod, cmd, NULL, NULL); - arg = httpd_api.lookup_arg(connection, "cmd"); - if(arg==NULL) return ph_build_content(page, buffer->len, mod, cmd); + LM_DBG("got arg cmd=[%.*s]\n", l_arg.len, l_arg.s); command = &ph_modules[mod].cmds[cmd]; - /* allocate c_vals array */ - if(command->c_keys_size && command->c_keys_size){ + if (l_arg.len==3 && strncmp(l_arg.s, "pre", 3)==0) { + /* We prebuild values only for update */ + if(command->type!=DB_CAP_UPDATE) { + LM_ERR("command [%.*s] is not DB_CAP_UPDATE type\n", + command->name.len, command->name.s); + return ph_build_content(page, buffer->len, mod, cmd, NULL, NULL); + } + /* We prebuild values only for single clause update command */ + if(command->c_keys_size!=1) { + LM_ERR("command [%.*s] has [%d] clause keys\n", + command->name.len, command->name.s, command->c_keys_size); + return ph_build_content(page, buffer->len, mod, cmd, NULL, NULL); + } + LM_DBG("[%.*s] with clause key [%.*s]\n", + command->name.len, command->name.s, + command->c_keys[0]->len, command->c_keys[0]->s); + + tmp = command->c_keys[0]->s[command->c_keys[0]->len]; + command->c_keys[0]->s[command->c_keys[0]->len] = '\0'; + LM_DBG("httpd_api.lookup_arg[%s]\n", command->c_keys[0]->s); + httpd_api.lookup_arg(connection, command->c_keys[0]->s, con_cls, &l_arg); + if(l_arg.s==NULL) { + LM_ERR("missing clause key [%.*s] in args\n", + command->c_keys[0]->len, command->c_keys[0]->s); + command->c_keys[0]->s[command->c_keys[0]->len] = tmp; + return ph_build_content(page, buffer->len, mod, cmd, NULL, NULL); + } + command->c_keys[0]->s[command->c_keys[0]->len] = tmp; + + LM_DBG("got clause [%.*s] with value [%.*s]\n", + command->c_keys[0]->len, command->c_keys[0]->s, l_arg.len, l_arg.s); + c_vals = (db_val_t*)pkg_malloc(command->c_keys_size*sizeof(db_val_t)); if(c_vals==NULL){ LM_ERR("oom\n"); return -1; } memset(c_vals, 0, command->c_keys_size*sizeof(db_val_t)); - for(i=0;i<command->c_keys_size;i++){ - s_arg.s = int2str(i, &s_arg.len); - arg = httpd_api.lookup_arg(connection, s_arg.s); - if(arg==NULL){ - PI_HTTP_BUILD_REPLY(page, buffer, mod, cmd, - "No argument for clause field #%d: %.*s.", - i, command->c_keys[i]->len, - command->c_keys[i]->s); - goto done; + + val = &c_vals[0]; + val->type = command->c_types[0]; + ret = getVal(val, command->c_types[0], command->c_keys[0], + command->db_table, &l_arg, page, buffer, mod, cmd); + if(ret<0) + goto error; + else if(ret>0) + goto finish_page; + + /* Let's run the query to get the values for the record to update*/ + db_url = command->db_table->db_url; + if(use_table(command->db_table)<0){ + PI_HTTP_BUILD_REPLY(page, buffer, mod, cmd, + "Error on table [%.*s].", + command->db_table->name.len, + command->db_table->name.s); + goto finish_page; + } + + if(db_url->http_dbf.query(db_url->http_db_handle, + command->c_keys, command->c_ops, c_vals, + command->q_keys, + command->c_keys_size, + command->q_keys_size, + command->o_keys?*command->o_keys:0, &res) < 0){ + PI_HTTP_COMPLETE_REPLY(page, buffer, mod, cmd, + "Error while querying database."); + goto finish_page; + } + nr_rows = RES_ROW_N(res); + switch (nr_rows) { + case 0: + LM_ERR("no record on clause key [%.*s]\n", + command->c_keys[0]->len, command->c_keys[0]->s); + if(c_vals) pkg_free(c_vals); c_vals = NULL; + goto finish_page; + case 1: + LM_DBG("got [%d] rows for key [%.*s]\n", + nr_rows, command->c_keys[0]->len, command->c_keys[0]->s); + break; + default: + LM_ERR("to many records [%d] on clause key [%.*s]\n", + nr_rows, command->c_keys[0]->len, command->c_keys[0]->s); + goto finish_page; + } + + rows = RES_ROWS(res); + values = ROW_VALUES(rows); + ret = ph_build_content(page, buffer->len, mod, cmd, &l_arg, values); + db_url->http_dbf.free_result(db_url->http_db_handle, res); + //res = NULL; + return ret; + } else if(l_arg.len==2 && strncmp(l_arg.s, "on", 2)==0) { + /* allocate c_vals array */ + if(command->c_keys_size && command->c_keys_size){ + c_vals = (db_val_t*)pkg_malloc(command->c_keys_size*sizeof(db_val_t)); + if(c_vals==NULL){ + LM_ERR("oom\n"); + return -1; } - s_arg.len = strlen(arg); - if(s_arg.len==0){ - PI_HTTP_BUILD_REPLY(page, buffer, mod, cmd, - "Empty argument for clause field #%d: %.*s.", - i,command->c_keys[i]->len, - command->c_keys[i]->s); - goto done; + memset(c_vals, 0, command->c_keys_size*sizeof(db_val_t)); + for(i=0;i<command->c_keys_size;i++){ + s_arg.s = int2str(i, &s_arg.len); + httpd_api.lookup_arg(connection, s_arg.s, con_cls, &l_arg); + if(l_arg.s==NULL){ + PI_HTTP_BUILD_REPLY(page, buffer, mod, cmd, + "No argument for clause field #%d: %.*s.", + i, command->c_keys[i]->len, + command->c_keys[i]->s); + goto done; + } + s_arg.len = l_arg.len; + if(s_arg.len==0){ + PI_HTTP_BUILD_REPLY(page, buffer, mod, cmd, + "Empty argument for clause field #%d: %.*s.", + i,command->c_keys[i]->len, + command->c_keys[i]->s); + goto done; + } + s_arg.s = l_arg.s; + val = &c_vals[i]; + val->type = command->c_types[i]; + + ret = getVal(val, command->c_types[i], command->c_keys[i], + command->db_table, &s_arg, page, buffer, mod, cmd); + if(ret<0) + goto error; + else if(ret>0) + goto done; } - //LM_DBG("s_arg=[%s] arg=[%s]\n", s_arg.s, arg); - s_arg.s = (char*)arg; - val = &c_vals[i]; - val->type = command->c_types[i]; - //c_vals[i].null = 0; - /* FIXME: what should we do here? */ - //c_vals[i].free = ?; - - ret = getVal(val, command->c_types[i], command->c_keys[i], - command->db_table, &s_arg, page, buffer, mod, cmd); - if(ret<0) - goto error; - else if(ret>0) - goto done; } } if(command->q_keys_size && command->q_keys_size && command->type!=DB_CAP_QUERY){ @@ -2563,15 +2905,15 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) goto done; } LM_DBG("looking for arg [%s]\n", c); - arg = httpd_api.lookup_arg(connection, c); - if(arg==NULL){ + httpd_api.lookup_arg(connection, c, con_cls, &l_arg); + if(l_arg.s==NULL){ PI_HTTP_BUILD_REPLY(page, buffer, mod, cmd, "No argument for query field #%d: %.*s.", i, command->q_keys[i]->len, command->q_keys[i]->s); goto done; } - s_arg.len = strlen(arg); + s_arg.len = l_arg.len; if(s_arg.len==0 && (command->q_types[i]!=DB_STR && command->q_types[i]!=DB_STRING && command->q_types[i]!=DB_BLOB)){ @@ -2581,7 +2923,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) command->q_keys[i]->s); goto done; } - s_arg.s = (char*)arg; + s_arg.s = l_arg.s; val = &q_vals[i]; val->type = command->q_types[i]; ret = getVal(val, command->q_types[i], command->q_keys[i], @@ -2602,7 +2944,6 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) command->db_table->name.s); goto done; } - _p = p; if(ph_build_reply(page, buffer->len, mod, cmd)<0) goto error; p = page->s + page->len; @@ -2612,7 +2953,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) if(j)PI_HTTP_COPY(p,PI_HTTP_Response_Menu_Cmd_td_1d); PI_HTTP_COPY_2(p,*(command->q_keys[j]), PI_HTTP_Response_Menu_Cmd_td_4d); - + } if (DB_CAPABILITY(db_url->http_dbf, DB_CAP_FETCH)){ if(db_url->http_dbf.query(db_url->http_db_handle, @@ -2625,7 +2966,6 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) "Error while querying (fetch) database."); goto done; } - /* FIXME: implement proper fetch value */ if(db_url->http_dbf.fetch_result(db_url->http_db_handle, &res, 100)<0){ PI_HTTP_COMPLETE_REPLY(page, buffer, mod, cmd, @@ -2653,6 +2993,21 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) PI_HTTP_COPY(p,PI_HTTP_Response_Menu_Cmd_tr_1); for(j=0;j<command->q_keys_size;j++){ PI_HTTP_COPY(p,PI_HTTP_Response_Menu_Cmd_td_1d); + /* BEGIN */ + link_on = 0; + if(command->link_cmd && command->link_cmd[j].s) { + link_on = 1; + PI_HTTP_COPY(p,PI_HTTP_HREF_1); + if (http_root.len) { + PI_HTTP_COPY_2(p,http_root, PI_HTTP_SLASH); + } + PI_HTTP_COPY_2(p,ph_modules[mod].module, PI_HTTP_SLASH); + PI_HTTP_COPY(p,command->link_cmd[j]); /* this is the command */ + PI_HTTP_COPY_3(p,PI_HTTP_HREF_2, + *command->q_keys[j], + PI_HTTP_ATTR_VAL_SEPARATOR); + } + /* END */ switch(command->q_types[j]){ case DB_STR: case DB_STRING: @@ -2670,8 +3025,19 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) values[j].val.str_val.len, values[j].val.str_val.s, val_str.len, val_str.s); - PI_HTTP_COPY(p, - val_str.len?val_str:PI_HTTP_NBSP); + if (val_str.len) { + if(link_on) { + PI_HTTP_ESC_COPY(p, val_str, temp_holder, temp_counter); + PI_HTTP_COPY(p,PI_HTTP_SQUOT_GT); + } + PI_HTTP_ESC_COPY(p, val_str, temp_holder, temp_counter); + } else { + if(link_on) { + PI_HTTP_COPY(p, PI_HTTP_NBSP); + PI_HTTP_COPY(p,PI_HTTP_SQUOT_GT); + } + PI_HTTP_COPY(p, PI_HTTP_NBSP); + } break; case DB_INT: val_str.s = p; @@ -2684,6 +3050,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) } p += val_str.len; page->len += val_str.len; + if(link_on) PI_HTTP_COPY_2(p,PI_HTTP_SQUOT_GT,val_str); LM_DBG(" got %.*s[%d]=>" "[%d][%.*s]\n", command->q_keys[j]->len, @@ -2702,6 +3069,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) } p += val_str.len; page->len += val_str.len; + if(link_on) PI_HTTP_COPY_2(p,PI_HTTP_SQUOT_GT,val_str); LM_DBG(" got %.*s[%d]=>" "[%d][%.*s]\n", command->q_keys[j]->len, @@ -2720,6 +3088,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) } p += val_str.len; page->len += val_str.len; + if(link_on) PI_HTTP_COPY_2(p,PI_HTTP_SQUOT_GT,val_str); LM_DBG(" got %.*s[%d]=>" "[%-lld][%.*s]\n", command->q_keys[j]->len, @@ -2738,6 +3107,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) } p += val_str.len; page->len += val_str.len; + if(link_on) PI_HTTP_COPY_2(p,PI_HTTP_SQUOT_GT,val_str); LM_DBG(" got %.*s[%d]=>" "[%-10.2f][%.*s]\n", command->q_keys[j]->len, @@ -2756,6 +3126,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) } p += val_str.len; page->len += val_str.len; + if(link_on) PI_HTTP_COPY_2(p,PI_HTTP_SQUOT_GT,val_str); LM_DBG(" got %.*s[%d]=>" "[%ld][%.*s]\n", command->q_keys[j]->len, @@ -2770,6 +3141,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) command->q_keys[j]->len, command->q_keys[j]->s); } + if(link_on) PI_HTTP_COPY(p,PI_HTTP_HREF_3); PI_HTTP_COPY(p,PI_HTTP_Response_Menu_Cmd_td_4d); } PI_HTTP_COPY(p,PI_HTTP_Response_Menu_Cmd_tr_2); @@ -2787,6 +3159,7 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) } }while (nr_rows>0); db_url->http_dbf.free_result(db_url->http_db_handle, res); + res=NULL; goto finish_page; break; case DB_CAP_INSERT: @@ -2842,6 +3215,8 @@ int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer) } LM_ERR("You shoudn't end up here\n"); error: + if (db_url && res) + db_url->http_dbf.free_result(db_url->http_db_handle, res); if(c_vals) pkg_free(c_vals); if(q_vals) pkg_free(q_vals); return -1; diff --git a/modules/pi_http/http_fnc.h b/modules/pi_http/http_fnc.h index ef7a29449ce..c723d46f77e 100644 --- a/modules/pi_http/http_fnc.h +++ b/modules/pi_http/http_fnc.h @@ -67,8 +67,8 @@ typedef struct ph_db_table_ { }ph_db_table_t; typedef struct ph_vals_ { - str *ids; - str *vals; + str *ids; /* String to display for the given value */ + str *vals; /* pre=populated value for a specific field */ int vals_size; }ph_vals_t; @@ -79,11 +79,12 @@ typedef struct ph_cmd_ { db_op_t *c_ops; db_key_t *c_keys; db_type_t *c_types; - ph_vals_t *c_vals; + ph_vals_t *c_vals; /* array of prepopulated values */ int c_keys_size; db_key_t *q_keys; db_type_t *q_types; - ph_vals_t *q_vals; + ph_vals_t *q_vals; /* array of prepopulated values */ + str *link_cmd; /* cmd to be executed for query links */ int q_keys_size; db_key_t *o_keys; int o_keys_size; @@ -118,7 +119,8 @@ void ph_destroy_async_lock(void); int ph_init_cmds(ph_framework_t **framework_data, const char* filename); int ph_parse_url(const char* url, int* mod, int* cmd); -int ph_run_pi_cmd(int mod, int cmd, void *connection, str *page, str *buffer); +int ph_run_pi_cmd(int mod, int cmd, void *connection, void *con_cls, + str *page, str *buffer); #endif diff --git a/modules/pi_http/pi_http.c b/modules/pi_http/pi_http.c index 979bba86065..00289d818fd 100644 --- a/modules/pi_http/pi_http.c +++ b/modules/pi_http/pi_http.c @@ -53,6 +53,7 @@ static ssize_t ph_flush_data(void *cls, uint64_t pos, char *buf, size_t max); static struct mi_root *mi_framework_reload(struct mi_root* cmd, void* param); str http_root = str_init("pi"); +int http_method = 0; str filename = {NULL, 0}; httpd_api_t httpd_api; @@ -68,8 +69,9 @@ static const str PI_HTTP_U_METHOD = str_init("<html><body>" /* module parameters */ static param_export_t params[] = { - {"pi_http_root", STR_PARAM, &http_root.s}, - {"framework", STR_PARAM, &filename.s}, + {"pi_http_root", STR_PARAM, &http_root.s}, + {"pi_http_method", INT_PARAM, &http_method}, + {"framework", STR_PARAM, &filename.s}, {0,0,0} }; @@ -79,11 +81,23 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "httpd", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /* module exports */ struct module_exports exports = { "pi_http", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -140,6 +154,11 @@ static int mod_init(void) http_root.len = strlen(http_root.s); + if (http_method<0 || http_method>1) { + LM_ERR("pi_http_method can be between [0,1]\n"); + return -1; + } + /* Load httpd api */ if(load_httpd_api(&httpd_api)<0) { LM_ERR("Failed to load httpd api\n"); @@ -201,14 +220,15 @@ void ph_answer_to_connection (void *cls, void *connection, int cmd = -1; LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, " - "versio=%s, upload_data[%d]=%p, con_cls=%p\n", + "versio=%s, upload_data[%d]=%p, *con_cls=%p\n", cls, connection, url, method, version, - (int)*upload_data_size, upload_data, con_cls); - if (strncmp(method, "GET", 3)==0) { + (int)*upload_data_size, upload_data, *con_cls); + if ((strncmp(method, "GET", 3)==0) + || (strncmp(method, "POST", 4)==0)) { lock_get(ph_lock); if(0 == ph_parse_url(url, &mod, &cmd)) { page->s = buffer->s; - if(0!=ph_run_pi_cmd(mod, cmd, connection, page, buffer)){ + if(0!=ph_run_pi_cmd(mod, cmd, connection, *con_cls, page, buffer)){ LM_ERR("unable to build response for cmd [%d]\n", cmd); *page = PI_HTTP_U_ERROR; @@ -218,9 +238,6 @@ void ph_answer_to_connection (void *cls, void *connection, *page = PI_HTTP_U_URL; } lock_release(ph_lock); - } else if (strncmp(method, "POST", 4)==0) { - LM_ERR("unexpected method [%s]\n", method); - *page = PI_HTTP_U_METHOD; } else { LM_ERR("unexpected method [%s]\n", method); *page = PI_HTTP_U_METHOD; diff --git a/modules/pike/README b/modules/pike/README index 19b338c548c..2e7cffca6f7 100644 --- a/modules/pike/README +++ b/modules/pike/README @@ -10,8 +10,7 @@ Bogdan-Andrei Iancu Copyright © 2005-2009 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -112,7 +111,7 @@ Chapter 1. Admin Guide Time period used for sampling (or the sampling accuracy ;-) ). The smaller the better, but slower. If you want to detect - peeks, use a small one. To limit the access (like total number + peaks, use a small one. To limit the access (like total number of requests on a long period of time) to a proxy resource (a gateway for ex), use a bigger value of this parameter. diff --git a/modules/pike/doc/pike_admin.xml b/modules/pike/doc/pike_admin.xml index 9c2caed3d50..e992b91b6fd 100644 --- a/modules/pike/doc/pike_admin.xml +++ b/modules/pike/doc/pike_admin.xml @@ -90,7 +90,7 @@ <title><varname>sampling_time_unit</varname> (integer) Time period used for sampling (or the sampling accuracy ;-) ). The - smaller the better, but slower. If you want to detect peeks, use a + smaller the better, but slower. If you want to detect peaks, use a small one. To limit the access (like total number of requests on a long period of time) to a proxy resource (a gateway for ex), use a bigger value of this parameter. diff --git a/modules/pike/ip_tree.c b/modules/pike/ip_tree.c index 1553d5a42f9..b9d8b82b28e 100644 --- a/modules/pike/ip_tree.c +++ b/modules/pike/ip_tree.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pike/ip_tree.h b/modules/pike/ip_tree.h index 6d21fdaf239..87c2e970d7c 100644 --- a/modules/pike/ip_tree.h +++ b/modules/pike/ip_tree.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pike/pike.c b/modules/pike/pike.c index 967d560cfe3..bc21edce5a6 100644 --- a/modules/pike/pike.c +++ b/modules/pike/pike.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -101,8 +101,10 @@ static mi_export_t mi_cmds [] = { struct module_exports exports= { "pike", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, params, 0, /* exported statistics */ diff --git a/modules/pike/pike_funcs.c b/modules/pike/pike_funcs.c index cdafb4f5852..c435a7a8381 100644 --- a/modules/pike/pike_funcs.c +++ b/modules/pike/pike_funcs.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -46,6 +46,7 @@ #include "../../resolve.h" #include "../../action.h" #include "../../route.h" +#include "../../script_cb.h" #include "ip_tree.h" #include "pike_funcs.h" #include "timer.h" @@ -162,7 +163,7 @@ int pike_check_req(struct sip_msg *msg) /* tree leafs which are not potential red nodes are not update in * order to make them to expire */ /* debug */ - assert( has_timer_set(&(node->timer_ll)) + assert( has_timer_set(&(node->timer_ll)) && (node->flags&(NODE_EXPIRED_FLAG|NODE_INTIMER_FLAG)) ); /* if node exprired, ignore the current hit and let is * expire in timer process */ @@ -172,7 +173,7 @@ int pike_check_req(struct sip_msg *msg) } } else { /* debug */ - assert( !has_timer_set(&(node->timer_ll)) + assert( !has_timer_set(&(node->timer_ll)) && !(node->flags&(NODE_INTIMER_FLAG|NODE_EXPIRED_FLAG)) ); /* debug */ assert( !(node->flags&NODE_IPLEAF_FLAG) && node->kids ); @@ -201,12 +202,13 @@ int pike_check_req(struct sip_msg *msg) int run_pike_route( struct sip_msg *msg, void *rt ) { /* the check was dropped */ if ( run_top_route( rlist[(int)(long)rt].a, msg)&ACT_FL_DROP) - return 1; + return SCB_RUN_ALL; /* run the check */ if (pike_check_req(msg)<0) - return 0; - return 1; + return SCB_DROP_MSG; + + return SCB_RUN_ALL; } @@ -267,7 +269,7 @@ void clean_routine(unsigned int ticks , void *param) continue; /* process the node */ - LM_DBG("clean node %p (kids=%p; hits=[%d,%d];leaf=[%d,%d])\n", + LM_DBG("clean node %p (kids=%p; hits=[%d,%d];leaf=[%d,%d])\n", node,node->kids, node->hits[PREV_POS],node->hits[CURR_POS], node->leaf_hits[PREV_POS],node->leaf_hits[CURR_POS]); diff --git a/modules/pike/pike_funcs.h b/modules/pike/pike_funcs.h index 1e939af14c7..f18c93db5b5 100644 --- a/modules/pike/pike_funcs.h +++ b/modules/pike/pike_funcs.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/pike/pike_mi.c b/modules/pike/pike_mi.c index 622d1c56567..877c914f910 100644 --- a/modules/pike/pike_mi.c +++ b/modules/pike/pike_mi.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -103,6 +103,7 @@ struct mi_root* mi_pike_list(struct mi_root* cmd_tree, void* param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==0) return 0; + rpl_tree->node.flags |= MI_IS_ARRAY; for( i=0 ; i #include "../../dprint.h" #include "../../sr_module.h" +#include "presentity.h" #include "presence.h" #include "bind_presence.h" @@ -39,18 +40,20 @@ int bind_presence(presence_api_t* api) LM_ERR("Invalid parameter value\n"); return -1; } - + api->add_event = add_event; api->contains_event= contains_event; api->search_event= search_event; api->get_event_list= get_event_list; api->update_watchers_status= update_watchers_status; + api->terminate_watchers= terminate_watchers; + api->update_presentity = internal_update_presentity; api->new_shtable= new_shtable; - api->destroy_shtable= destroy_shtable; - api->insert_shtable= insert_shtable; - api->search_shtable= search_shtable; - api->delete_shtable= delete_shtable; - api->update_shtable= update_shtable; + api->destroy_shtable= destroy_shtable; + api->insert_shtable= insert_shtable; + api->search_shtable= search_shtable; + api->delete_shtable= delete_shtable; + api->update_shtable= update_shtable; api->mem_copy_subs= mem_copy_subs; api->update_db_subs= update_db_subs; api->extract_sdialog_info= extract_sdialog_info; diff --git a/modules/presence/bind_presence.h b/modules/presence/bind_presence.h index 6a3c9d8c4aa..e35fe83f526 100644 --- a/modules/presence/bind_presence.h +++ b/modules/presence/bind_presence.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -34,6 +34,8 @@ #include "presentity.h" typedef int (*update_watchers_t)(str pres_uri, pres_ev_t* ev, str* rules_doc); +typedef int (*update_presentity_t)(presentity_t* presentity); +typedef int (*terminate_watchers_t)(str *pres_uri, pres_ev_t* ev); typedef struct presence_api { add_event_t add_event; @@ -41,6 +43,8 @@ typedef struct presence_api { search_event_t search_event; get_event_list_t get_event_list; update_watchers_t update_watchers_status; + terminate_watchers_t terminate_watchers; + update_presentity_t update_presentity; /* subs hash table functions */ new_shtable_t new_shtable; destroy_shtable_t destroy_shtable; diff --git a/modules/presence/event_list.c b/modules/presence/event_list.c index 78cb8bb5e5f..e425c0d8cf2 100644 --- a/modules/presence/event_list.c +++ b/modules/presence/event_list.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -31,9 +31,9 @@ #include #include "../../str.h" #include "../../dprint.h" -#include "../../parser/parse_event.h" -#include "../../mem/shm_mem.h" -#include "../../mem/mem.h" +#include "../../parser/parse_event.h" +#include "../../mem/shm_mem.h" +#include "../../mem/mem.h" #include "event_list.h" #include "hash.h" @@ -94,7 +94,7 @@ void shm_free_event(event_t* ev) { if(ev== NULL) return; - + if(ev->text.s) shm_free(ev->text.s); @@ -136,7 +136,7 @@ int add_event(pres_ev_t* event) return -1; } } - + ev= contains_event(&event->name, &parsed_event); if(ev== NULL) { @@ -186,7 +186,7 @@ int add_event(pres_ev_t* event) sep= strchr(event->name.s, '.'); if(sep != NULL && strncasecmp(sep+1, "winfo", 5)== 0) - { + { ev->type= WINFO_TYPE; wipeer_name.s= event->name.s; wipeer_name.len= sep - event->name.s; @@ -202,11 +202,11 @@ int add_event(pres_ev_t* event) wipeer_name.len+= 6; ev->wipeer= contains_event(&wipeer_name, NULL); } - + if(ev->wipeer) ev->wipeer->wipeer= ev; - if(event->req_auth && + if(event->req_auth && ( event->get_auth_status==0 ||event->get_rules_doc== 0)) { LM_ERR("bad event structure\n"); @@ -220,6 +220,7 @@ int add_event(pres_ev_t* event) ev->get_auth_status= event->get_auth_status; ev->get_rules_doc= event->get_rules_doc; ev->evs_publ_handl= event->evs_publ_handl; + ev->evs_subs_handl= event->evs_subs_handl; ev->mandatory_body = event->mandatory_body; ev->mandatory_timeout_notification = event->mandatory_timeout_notification; ev->etag_not_new= event->etag_not_new; @@ -235,7 +236,7 @@ int add_event(pres_ev_t* event) EvList->events= ev; } EvList->ev_count++; - + LM_DBG("succesfully added event: %.*s - len= %d\n",ev->name.len, ev->name.s, ev->name.len); @@ -281,15 +282,15 @@ evlist_t* init_evlist(void) } list->ev_count= 0; list->events= NULL; - + return list; -} +} pres_ev_t* contains_event(str* sname, event_t* parsed_event) { event_t event; pres_ev_t* e; - + memset(&event, 0, sizeof(event_t)); if(event_parser(sname->s, sname->len, &event)< 0) { @@ -321,7 +322,7 @@ void free_event_params(param_t* params, int mem_type) pkg_free(t1); t1= t2; } - + } pres_ev_t* search_event(event_t* event) @@ -339,7 +340,7 @@ pres_ev_t* search_event(event_t* event) { return pres_ev; } - + /* search all parameters in event in ev */ /* if(search_event_params(event, pres_ev->evp)< 0) goto cont; @@ -367,13 +368,13 @@ int search_event_params(event_t* ev, event_t* searched_ev) { p= searched_ev->params; found= 0; - + while(p) { - if(p->name.len== ps->name.len && + if(p->name.len== ps->name.len && strncmp(p->name.s,ps->name.s, ps->name.len)== 0) if((p->body.s== 0 && ps->body.s== 0) || - (p->body.len== ps->body.len && + (p->body.len== ps->body.len && strncmp(p->body.s,ps->body.s,ps->body.len)== 0)) { found= 1; @@ -390,15 +391,15 @@ int search_event_params(event_t* ev, event_t* searched_ev) } int get_event_list(str** ev_list) -{ +{ pres_ev_t* ev= EvList->events; int i; str* list; *ev_list= NULL; - + if(EvList->ev_count== 0) return 0; - + list= (str*)pkg_malloc(sizeof(str)); if(list== NULL) { @@ -414,19 +415,19 @@ int get_event_list(str** ev_list) return -1; } list->s[0]= '\0'; - + for(i= 0; i< EvList->ev_count; i++) { if(i> 0) { memcpy(list->s+ list->len, ", ", 2); list->len+= 2; - } + } memcpy(list->s+ list->len, ev->name.s, ev->name.len ); list->len+= ev->name.len ; ev= ev->next; } - + *ev_list= list; return 0; } @@ -434,7 +435,7 @@ int get_event_list(str** ev_list) void destroy_evlist(void) { pres_ev_t* e1, *e2; - if (EvList) + if (EvList) { e1= EvList->events; while(e1) @@ -442,7 +443,7 @@ void destroy_evlist(void) e2= e1->next; free_pres_event(e1); e1= e2; - } + } shm_free(EvList); } } diff --git a/modules/presence/event_list.h b/modules/presence/event_list.h index e2922e745a9..f6fa8e8a40d 100644 --- a/modules/presence/event_list.h +++ b/modules/presence/event_list.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -43,19 +43,19 @@ typedef int (apply_auth_t)(str* , struct subscription*, str** ); typedef int (publ_handling_t)(struct sip_msg*, int* sent_event); -typedef int (subs_handling_t)(struct sip_msg*); +typedef int (subs_handling_t)(struct sip_msg*,struct subscription *,int*, str*); typedef str* (empty_pres_info_t)(str* pres_uri, str* extra_hdrs); typedef str* (agg_nbody_t)(str* pres_user, str* pres_domain, str** body_array, int n, int off_index); -/* params for agg_body_t +/* params for agg_body_t * body_array= an array with all the bodies stored for that resource * n= the number of bodies * off_index= the index of the registration(etag) for which a Publish * with Expires: 0 has just been received * */ typedef str* (aux_body_processing_t)(struct subscription *subs, str* body); -/* params for agg_body_t +/* params for agg_body_t * subs= a subscription structure to manipulate the body for a certain watcher * body= the original body * @@ -96,12 +96,12 @@ struct pres_ev int mandatory_timeout_notification; /* * 0 - the standard mechanism (allocating new etag for each Publish) - * 1 - allocating an etag only for an initial Publish + * 1 - allocating an etag only for an initial Publish * */ int etag_not_new; /* fileds that deal with authorization rules*/ /* - * req_auth -> flag 0 - if not require + * req_auth -> flag 0 - if not require * is_watcher_allowed - get subscription state from xcap rules * apply_auth_nbody - alter the body according to authorization rules */ @@ -109,11 +109,11 @@ struct pres_ev get_rules_doc_t* get_rules_doc; apply_auth_t* apply_auth_nbody; is_allowed_t* get_auth_status; - + /* an agg_body_t function should be registered if the event permits having * multiple published states and requires an aggregation of the information - * otherwise, this field should be NULL and the last published state is taken - * when constructing Notify msg + * otherwise, this field should be NULL and the last published state is taken + * when constructing Notify msg * */ agg_nbody_t* agg_nbody; publ_handling_t * evs_publ_handl; @@ -124,14 +124,14 @@ struct pres_ev */ empty_pres_info_t * build_empty_pres_info; free_body_t* free_body; - /* sometimes it is necessary that a module make changes for a body for each + /* sometimes it is necessary that a module make changes for a body for each * active watcher (e.g. setting the "version" parameter in an XML document. * If a module registers the aux_body_processing callback, it gets called for * each watcher. It either gets the body received by the PUBLISH, or the body * generated by the agg_nbody function. * The module can deceide if it makes a copy of the original body, which is then * manipulated, or if it works directly in the original body. If the module makes a - * copy of the original body, it also has to register the aux_free_body() to + * copy of the original body, it also has to register the aux_free_body() to * free this "per watcher" body. */ aux_body_processing_t* aux_body_processing; @@ -150,7 +150,7 @@ typedef struct evlist { int ev_count; pres_ev_t* events; -}evlist_t; +}evlist_t; evlist_t* init_evlist(void); diff --git a/modules/presence/hash.c b/modules/presence/hash.c index e520029a14d..cc0b062d81c 100644 --- a/modules/presence/hash.c +++ b/modules/presence/hash.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -259,13 +259,13 @@ int insert_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs) new_rec->db_flag= INSERTDB_FLAG; lock_get(&htable[hash_code].lock); - + new_rec->next= htable[hash_code].entries->next; - + htable[hash_code].entries->next= new_rec; - + lock_release(&htable[hash_code].lock); - + return 0; error: @@ -287,7 +287,7 @@ int delete_shtable(shtable_t htable,unsigned int hash_code,str to_tag) int found= -1; lock_get(&htable[hash_code].lock); - + ps= htable[hash_code].entries; s= ps->next; @@ -331,7 +331,7 @@ void free_subs_list(subs_t* s_array, int mem_type, int ic) } } -int update_shtable(shtable_t htable,unsigned int hash_code, +int update_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs, int type) { subs_t* s; @@ -355,7 +355,7 @@ int update_shtable(shtable_t htable,unsigned int hash_code, else { subs->local_cseq= s->local_cseq++; - s->version= subs->version+ 1; + subs->version= s->version++; } if(strncmp(s->contact.s, subs->contact.s, subs->contact.len)) @@ -423,7 +423,7 @@ phtable_t* new_phtable(void) { if(htable[i].entries) shm_free(htable[i].entries); - else + else break; lock_destroy(&htable[i].lock); } @@ -506,7 +506,7 @@ void update_pres_etag(pres_entry_t* p, str* etag) p->etag_count++; } -int insert_phtable(str* pres_uri, int event, str* etag, char* sphere) +pres_entry_t* insert_phtable(str* pres_uri, int event, str* etag, char* sphere, int init_turn) { unsigned int hash_code; pres_entry_t* p= NULL; @@ -543,14 +543,16 @@ int insert_phtable(str* pres_uri, int event, str* etag, char* sphere) p->next= pres_htable[hash_code].entries->next; pres_htable[hash_code].entries->next= p; + p->last_turn = init_turn; + lock_release(&pres_htable[hash_code].lock); - return 0; + return p; error: if(p) shm_free(p); - return -1; + return NULL; } int delete_phtable_query(str *pres_uri, int event, str* etag) @@ -572,12 +574,32 @@ int delete_phtable_query(str *pres_uri, int event, str* etag) return 0; } + +void next_turn_phtable(pres_entry_t* p_p, unsigned int hash_code) +{ + pres_entry_t* p; + + lock_get(&pres_htable[hash_code].lock); + for ( p=pres_htable[hash_code].entries->next ; p ; p=p->next ) { + if(p==p_p) { + p->current_turn++; + LM_DBG("new current turn is %d for <%.*s>\n",p->current_turn, + p_p->pres_uri.len, p_p->pres_uri.s); + break; + } + } + + lock_release(&pres_htable[hash_code].lock); + return; +} + + int delete_phtable(pres_entry_t* p, unsigned int hash_code) { pres_entry_t* prev_p= NULL; LM_DBG("Count = 0, delete\n"); - /* delete record */ + /* delete record */ prev_p= pres_htable[hash_code].entries; while(prev_p->next) { @@ -616,7 +638,7 @@ int update_phtable(presentity_t* presentity, str pres_uri, str body) /* search for record in hash table */ hash_code= core_hash(&pres_uri, NULL, phtable_size); - + lock_get(&pres_htable[hash_code].lock); p= search_phtable(&pres_uri, presentity->event->evp->parsed, hash_code); @@ -625,7 +647,7 @@ int update_phtable(presentity_t* presentity, str pres_uri, str body) lock_release(&pres_htable[hash_code].lock); goto done; } - + if(p->sphere) { if(strcmp(p->sphere, sphere)!= 0) @@ -640,7 +662,7 @@ int update_phtable(presentity_t* presentity, str pres_uri, str body) pkg_free(sphere); return 0; } - + } @@ -652,7 +674,7 @@ int update_phtable(presentity_t* presentity, str pres_uri, str body) goto done; } strcpy(p->sphere, sphere); - + lock_release(&pres_htable[hash_code].lock); /* call for watchers status update */ diff --git a/modules/presence/hash.h b/modules/presence/hash.h index d09df1a244e..175abbf5fa8 100644 --- a/modules/presence/hash.h +++ b/modules/presence/hash.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -75,7 +75,7 @@ typedef struct subs_entry { struct subscription* entries; gen_lock_t lock; -}subs_entry_t; +}subs_entry_t; typedef subs_entry_t* shtable_t; @@ -127,6 +127,9 @@ typedef struct pres_entry char* sphere; char etag[ETAG_LEN]; int etag_len; + /* ordering */ + unsigned int current_turn; + unsigned int last_turn; struct pres_entry* next; }pres_entry_t; @@ -144,10 +147,12 @@ pres_entry_t* search_phtable_etag(str* pres_uri, int event, void update_pres_etag(pres_entry_t* p, str* etag); -int insert_phtable(str* pres_uri, int event, str* etag, char* sphere); +pres_entry_t* insert_phtable(str* pres_uri, int event, str* etag, char* sphere, int init_turn); int update_phtable(struct presentity* presentity, str pres_uri, str body); +void next_turn_phtable(pres_entry_t* p_p, unsigned int hash_code); + int delete_phtable(pres_entry_t* p, unsigned int hash_code); int delete_phtable_query(str *pres_uri, int event, str* etag); diff --git a/modules/presence/notify.c b/modules/presence/notify.c index ee548cf281b..aae88601d1c 100644 --- a/modules/presence/notify.c +++ b/modules/presence/notify.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -92,7 +92,7 @@ char* get_status_str(int status_flag) case PENDING_STATUS: return "pending"; case TERMINATED_STATUS: return "terminated"; case WAITING_STATUS: return "waiting"; - + } return NULL; } @@ -103,7 +103,7 @@ static void pkg_free_w(char* s) } inline void printf_subs(subs_t* subs) -{ +{ LM_DBG("\n\t[pres_uri]= %.*s\n\t[to_user]= %.*s\t[to_domain]= %.*s" "\n\t[w_user]= %.*s\t[w_domain]= %.*s\n\t[event]= %.*s\n\t[status]= %s" "\n\t[expires]= %u\n\t[callid]= %.*s\t[local_cseq]=%d" @@ -178,7 +178,7 @@ int build_str_hdr(subs_t* subs, int is_body, str* hdr, str* extra_hdrs) p+= 7; memcpy(p, subs->event->name.s, subs->event->name.len); p+= subs->event->name.len; - if(subs->event_id.len && subs->event_id.s) + if(subs->event_id.len && subs->event_id.s) { memcpy(p, ";id=", 4); p += 4; @@ -192,8 +192,8 @@ int build_str_hdr(subs_t* subs, int is_body, str* hdr, str* extra_hdrs) p += 10; memcpy(p, subs->local_contact.s, subs->local_contact.len); p += subs->local_contact.len; - - if (subs->sockinfo && subs->sockinfo->proto!=PROTO_UDP) + + if (subs->sockinfo && subs->sockinfo->proto!=PROTO_UDP) { memcpy(p,";transport=",11); p += 11; @@ -209,13 +209,13 @@ int build_str_hdr(subs_t* subs, int is_body, str* hdr, str* extra_hdrs) memcpy(p, CRLF, CRLF_LEN); p += CRLF_LEN; - + memcpy(p, "Subscription-State: ", 20); p+= 20; memcpy(p, status.s, status.len); p += status.len; - + if(subs->status== TERMINATED_STATUS) { LM_DBG("state = terminated\n"); @@ -227,7 +227,7 @@ int build_str_hdr(subs_t* subs, int is_body, str* hdr, str* extra_hdrs) p+= CRLF_LEN; } else - { + { memcpy(p,";expires=", 9); p += 9; memcpy(p, lexpire_s ,lexpire_len ); @@ -235,9 +235,9 @@ int build_str_hdr(subs_t* subs, int is_body, str* hdr, str* extra_hdrs) memcpy(p, CRLF, CRLF_LEN); p += CRLF_LEN; } - + if(is_body && subs->event->content_type.s && subs->event->content_type.len) - { + { memcpy(p,"Content-Type: ", 14); p += 14; memcpy(p, subs->event->content_type.s , subs->event->content_type.len); @@ -245,7 +245,7 @@ int build_str_hdr(subs_t* subs, int is_body, str* hdr, str* extra_hdrs) memcpy(p, CRLF, CRLF_LEN); p += CRLF_LEN; } - + hdr->len = p - hdr->s; return 0; @@ -259,7 +259,7 @@ int get_wi_subs_db(subs_t* subs, watcher_t* watchers) db_val_t query_vals[6]; db_key_t result_cols[6]; db_res_t *result = NULL; - db_row_t *row = NULL ; + db_row_t *row = NULL ; db_val_t *row_vals = NULL; int n_result_cols = 0; int n_query_cols = 0; @@ -287,7 +287,7 @@ int get_wi_subs_db(subs_t* subs, watcher_t* watchers) result_cols[from_domain_col=n_result_cols++] = &str_watcher_domain_col; result_cols[callid_col=n_result_cols++] = &str_callid_col; - if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) + if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) { LM_ERR("in use_table\n"); goto error; @@ -295,7 +295,7 @@ int get_wi_subs_db(subs_t* subs, watcher_t* watchers) // CON_PS_REFERENCE(pa_db) = &my_ps; if (pa_dbf.query (pa_db, query_cols, query_ops, query_vals, - result_cols, n_query_cols, n_result_cols, 0, &result) < 0) + result_cols, n_query_cols, n_result_cols, 0, &result) < 0) { LM_ERR("querying active_watchers db table\n"); goto error; @@ -313,12 +313,12 @@ int get_wi_subs_db(subs_t* subs, watcher_t* watchers) pa_dbf.free_result(pa_db, result); return 0; } - + for(i=0; in; i++) { row = &result->rows[i]; row_vals = ROW_VALUES(row); - + s.from_user.s= (char*)row_vals[from_user_col].val.string_val; s.from_user.len= strlen(s.from_user.s); @@ -330,14 +330,14 @@ int get_wi_subs_db(subs_t* subs, watcher_t* watchers) s.event =subs->event->wipeer; s.status= row_vals[status_col].val.int_val; - + if(add_watcher_list(&s, watchers) <0) { LM_ERR("failed to add watcher to list\n"); goto error; } } - + pa_dbf.free_result(pa_db, result); return 0; @@ -372,8 +372,8 @@ str* get_wi_notify_body(subs_t* subs, subs_t* watcher_subs) } memset(watchers, 0, sizeof(watcher_t)); - if(watcher_subs != NULL) - { + if(watcher_subs != NULL) + { if(add_watcher_list(watcher_subs, watchers)< 0) { LM_ERR("failed to add watcher to list\n"); @@ -403,7 +403,7 @@ str* get_wi_notify_body(subs_t* subs, subs_t* watcher_subs) s= s->next; if(s->expires< (int)time(NULL)) - { + { LM_DBG("expired record\n"); continue; } @@ -437,8 +437,8 @@ str* get_wi_notify_body(subs_t* subs, subs_t* watcher_subs) done: notify_body = create_winfo_xml(watchers,version_str,subs->pres_uri, subs->event->wipeer->name, state ); - - if(watcher_subs == NULL) + + if(watcher_subs == NULL) lock_release(&subs_htable[hash_code].lock); if(notify_body== NULL) @@ -465,7 +465,7 @@ void free_watcher_list(watcher_t* watchers) watcher_t* w; while(watchers) - { + { w= watchers; if(w->uri.s !=NULL) pkg_free(w->uri.s); @@ -544,7 +544,7 @@ int add_waiting_watchers(watcher_t* watchers, str pres_uri, str event) db_val_t query_vals[3]; db_key_t result_cols[2]; db_res_t *result = NULL; - db_row_t *row= NULL ; + db_row_t *row= NULL ; db_val_t *row_vals; int n_result_cols = 0; int n_query_cols = 0; @@ -575,8 +575,8 @@ int add_waiting_watchers(watcher_t* watchers, str pres_uri, str event) result_cols[wuser_col=n_result_cols++] = &str_watcher_username_col; result_cols[wdomain_col=n_result_cols++] = &str_watcher_domain_col; - - if (pa_dbf.use_table(pa_db, &watchers_table) < 0) + + if (pa_dbf.use_table(pa_db, &watchers_table) < 0) { LM_ERR("sql use table 'watchers_table' failed\n"); return -1; @@ -585,14 +585,14 @@ int add_waiting_watchers(watcher_t* watchers, str pres_uri, str event) // CON_PS_REFERENCE(pa_db) = &my_ps; if (pa_dbf.query (pa_db, query_cols, 0, query_vals, - result_cols, n_query_cols, n_result_cols, 0, &result) < 0) + result_cols, n_query_cols, n_result_cols, 0, &result) < 0) { LM_ERR("failed to query %.*s table\n", watchers_table.len, watchers_table.s); if(result) pa_dbf.free_result(pa_db, result); return -1; } - + if(result== NULL) { LM_ERR("mysql query failed - null result\n"); @@ -628,7 +628,7 @@ int add_waiting_watchers(watcher_t* watchers, str pres_uri, str event) pkg_free(wuri.s); continue; } - + w= (watcher_t*)pkg_malloc(sizeof(watcher_t)); if(w== NULL) { @@ -649,7 +649,7 @@ int add_waiting_watchers(watcher_t* watchers, str pres_uri, str event) to64frombits((unsigned char *)w->id.s, (const unsigned char*)w->uri.s, w->uri.len); w->id.len = strlen(w->id.s); - + w->next= watchers->next; watchers->next= w; } @@ -726,7 +726,7 @@ str* build_empty_bla_body(str pres_uri) pkg_free(entity); goto error; } - + body = (str*) pkg_malloc(sizeof(str)); if(body== NULL) { @@ -747,7 +747,7 @@ str* build_empty_bla_body(str pres_uri) memcpy(body->s, text, len); body->len= len; - + pkg_free(entity); xmlFreeDoc(doc); xmlFree(text); @@ -802,7 +802,7 @@ static inline db_res_t* pres_search_db(struct sip_uri* uri,str* ev_name, int* bo result_cols[n_result_cols] = &str_etag_col; *etag_col=n_result_cols++; - if (pa_dbf.use_table(pa_db, &presentity_table) < 0) + if (pa_dbf.use_table(pa_db, &presentity_table) < 0) { LM_ERR("in use_table\n"); return NULL; @@ -922,7 +922,7 @@ str* get_presence_from_dialog(str* pres_uri, struct sip_uri* uri, } str* get_p_notify_body(str pres_uri, pres_ev_t* event, str* etag, str* publ_body, - str* contact, str* dbody, str* extra_hdrs, free_body_t** free_fct) + str* contact, str* dbody, str* extra_hdrs, free_body_t** free_fct, int from_publish) { int body_col, extra_hdrs_col, expires_col, etag_col= 0; db_res_t *result = NULL; @@ -1140,7 +1140,7 @@ str* get_p_notify_body(str pres_uri, pres_ev_t* event, str* etag, str* publ_body init_i = body_cnt; if(etag!= NULL) { - LM_DBG("searched etag = %.*s len= %d\n", + LM_DBG("searched etag = %.*s len= %d\n", etag->len, etag->s, etag->len); LM_DBG("etag not NULL\n"); for(i= 0; i< n; i++) @@ -1251,12 +1251,31 @@ str* get_p_notify_body(str pres_uri, pres_ev_t* event, str* etag, str* publ_body } /* if the Publish with expires=0 has body -> use this one */ - if(etag && publ_body && build_off_n>=0) + if(etag && publ_body && build_off_n>=0) { pkg_free(body_array[build_off_n]); body_array[build_off_n] = publ_body; build_off_n = -1; } + + /* RFC 4235 states that a NOTIFY generated after an initial + * or refreshed SUBSCRIBE request must contain a full-state notification. + * In other cases, only the modified state should be notified using + * a partial state notification. + */ + if (event->evp->parsed == EVENT_DIALOG && from_publish && publ_body) { + + /* Presence dialoginfo knows that special n value of -2 means we publish + * a partial state. Calling the agg_nbody method is however required because + * it builds the full NOTIFY body as described in the RFC (it adds the version + * field to the body, defines if state is partial or full, ...). + */ + notify_body = event->agg_nbody(&uri.user, &uri.host, &publ_body, -2, build_off_n); + if(notify_body) { + goto done; + } + } + notify_body = event->agg_nbody(&uri.user, &uri.host, body_array, body_cnt, build_off_n); if(notify_body == NULL) { @@ -1345,7 +1364,7 @@ dlg_t* build_dlg_t(subs_t* subs) td->id.call_id = subs->callid; td->id.rem_tag = subs->from_tag; td->id.loc_tag =subs->to_tag; - + uandd_to_uri(subs->to_user, subs->to_domain, &td->loc_uri); if(td->loc_uri.s== NULL) { @@ -1369,7 +1388,7 @@ dlg_t* build_dlg_t(subs_t* subs) LM_ERR("while creating uri\n"); goto error; } - + if(found_contact == 0) { td->rem_target = td->rem_uri; @@ -1382,13 +1401,13 @@ dlg_t* build_dlg_t(subs_t* subs) LM_ERR("in function parse_rr_body\n"); goto error; } - } + } td->state= DLG_CONFIRMED ; td->send_sock = subs->sockinfo; return td; -error: +error: free_tm_dlg(td); return NULL; } @@ -1415,8 +1434,8 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, str sockinfo_str; int port, proto; str host; - - if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) + + if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) { LM_ERR("in use_table\n"); return -1; @@ -1429,7 +1448,7 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = *pres_uri; n_query_cols++; - + query_cols[n_query_cols] = &str_event_col; query_ops[n_query_cols] = OP_EQ; query_vals[n_query_cols].type = DB_STR; @@ -1443,14 +1462,14 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.int_val = ACTIVE_STATUS; n_query_cols++; - + query_cols[n_query_cols] = &str_contact_col; query_ops[n_query_cols] = OP_NEQ; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; if(sender) - { + { LM_DBG("Do not send Notify to:[uri]= %.*s\n",sender->len,sender->s); query_vals[n_query_cols].val.str_val = *sender; } @@ -1480,7 +1499,7 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, //CON_PS_REFERENCE(pa_db) = &my_ps; if (pa_dbf.query(pa_db, query_cols, query_ops, query_vals,result_cols, - n_query_cols, n_result_cols, 0, &result) < 0) + n_query_cols, n_result_cols, 0, &result) < 0) { LM_ERR("while querying database\n"); if(result) @@ -1502,12 +1521,12 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, return 0; } LM_DBG("found %d dialogs\n", result->n); - + for(i=0; in; i++) { row = &result->rows[i]; - row_vals = ROW_VALUES(row); - + row_vals = ROW_VALUES(row); + // if(row_vals[expires_col].val.int_val< (int)time(NULL)) // continue; @@ -1520,38 +1539,38 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, memset(&s, 0, sizeof(subs_t)); s.status= ACTIVE_STATUS; - + s.pres_uri= *pres_uri; s.to_user.s= (char*)row_vals[to_user_col].val.string_val; s.to_user.len= strlen(s.to_user.s); - + s.to_domain.s= (char*)row_vals[to_domain_col].val.string_val; s.to_domain.len= strlen(s.to_domain.s); - + s.from_user.s= (char*)row_vals[from_user_col].val.string_val; s.from_user.len= strlen(s.from_user.s); - + s.from_domain.s= (char*)row_vals[from_domain_col].val.string_val; s.from_domain.len= strlen(s.from_domain.s); - + s.event_id.s=(char*)row_vals[event_id_col].val.string_val; s.event_id.len= (s.event_id.s)?strlen(s.event_id.s):0; - + s.to_tag.s= (char*)row_vals[to_tag_col].val.string_val; s.to_tag.len= strlen(s.to_tag.s); - - s.from_tag.s= (char*)row_vals[from_tag_col].val.string_val; + + s.from_tag.s= (char*)row_vals[from_tag_col].val.string_val; s.from_tag.len= strlen(s.from_tag.s); - + s.callid.s= (char*)row_vals[callid_col].val.string_val; s.callid.len= strlen(s.callid.s); - + s.record_route.s= (char*)row_vals[record_route_col].val.string_val; s.record_route.len= (s.record_route.s)?strlen(s.record_route.s):0; s.contact.s= (char*)row_vals[contact_col].val.string_val; s.contact.len= strlen(s.contact.s); - + sockinfo_str.s = (char*)row_vals[sockinfo_col].val.string_val; if (sockinfo_str.s) { @@ -1568,7 +1587,7 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, s.local_contact.s = (char*)row_vals[local_contact_col].val.string_val; s.local_contact.len = s.local_contact.s?strlen(s.local_contact.s):0; - + s.event= event; s.local_cseq = row_vals[cseq_col].val.int_val; @@ -1586,7 +1605,7 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, } s_new->next= (*s_array); (*s_array)= s_new; - + printf_subs(s_new); inc++; } @@ -1598,7 +1617,7 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, error: if(result) pa_dbf.free_result(pa_db, result); - + return -1; } @@ -1608,7 +1627,7 @@ int update_in_list(subs_t* s, subs_t* s_array, int new_rec_no, int n) subs_t* ls; ls= s_array; - + while(i< new_rec_no) { i++; @@ -1623,7 +1642,7 @@ int update_in_list(subs_t* s, subs_t* s_array, int new_rec_no, int n) return -1; } printf_subs(ls); - + if(ls->callid.len== s->callid.len && strncmp(ls->callid.s, s->callid.s, s->callid.len)== 0 && ls->to_tag.len== s->to_tag.len && @@ -1648,7 +1667,7 @@ subs_t* get_subs_dialog(str* pres_uri, pres_ev_t* event, str* sender) subs_t* s= NULL, *s_new; subs_t* s_array= NULL; int n= 0, i= 0; - + /* if fallback2db -> should take all dialogs from db * and the only those dialogs from cache with db_flag= INSERTDB_FLAG */ @@ -1664,7 +1683,7 @@ subs_t* get_subs_dialog(str* pres_uri, pres_ev_t* event, str* sender) { /* get records from hash table */ hash_code= core_hash(pres_uri, &event->name, shtable_size); - + lock_get(&subs_htable[hash_code].lock); s= subs_htable[hash_code].entries; @@ -1672,20 +1691,20 @@ subs_t* get_subs_dialog(str* pres_uri, pres_ev_t* event, str* sender) while(s->next) { s= s->next; - + printf_subs(s); - + if(s->expires< (int)time(NULL)) { LM_DBG("expired subs\n"); continue; } - + if((!(s->status== ACTIVE_STATUS && s->reason.len== 0 && s->event== event && s->pres_uri.len== pres_uri->len && - strncmp(s->pres_uri.s, pres_uri->s, pres_uri->len)== 0)) || - (sender && sender->len== s->contact.len && + strncmp(s->pres_uri.s, pres_uri->s, pres_uri->len)== 0)) || + (sender && sender->len== s->contact.len && strncmp(sender->s, s->contact.s, sender->len)== 0)) continue; @@ -1715,7 +1734,7 @@ subs_t* get_subs_dialog(str* pres_uri, pres_ev_t* event, str* sender) } int publ_notify(presentity_t* p, str pres_uri, str* body, str* offline_etag, - str* rules_doc, str* dialog_body) + str* rules_doc, str* dialog_body, int from_publish) { str *notify_body = NULL; str notify_extra_hdrs = {NULL, 0}; @@ -1736,7 +1755,8 @@ int publ_notify(presentity_t* p, str pres_uri, str* body, str* offline_etag, { notify_body = get_p_notify_body(pres_uri, p->event , offline_etag, body, NULL, dialog_body, - p->extra_hdrs?p->extra_hdrs:¬ify_extra_hdrs, &free_fct); + p->extra_hdrs?p->extra_hdrs:¬ify_extra_hdrs, &free_fct, + from_publish); } s= subs_array; @@ -1745,7 +1765,7 @@ int publ_notify(presentity_t* p, str pres_uri, str* body, str* offline_etag, s->auth_rules_doc= rules_doc; LM_INFO("notify\n"); if(notify(s, NULL, notify_body?notify_body:body, - 0, p->extra_hdrs?p->extra_hdrs:¬ify_extra_hdrs)< 0 ) + 0, p->extra_hdrs?p->extra_hdrs:¬ify_extra_hdrs, from_publish)< 0 ) { LM_ERR("Could not send notify for %.*s\n", p->event->name.len, p->event->name.s); @@ -1793,7 +1813,7 @@ int query_db_notify(str* pres_uri, pres_ev_t* event, subs_t* watcher_subs) if(event->type & PUBL_TYPE) { notify_body = get_p_notify_body(*pres_uri, event, 0, 0, 0, 0, - ¬ify_extra_hdrs, &free_fct); + ¬ify_extra_hdrs, &free_fct, 0); } s= subs_array; @@ -1801,7 +1821,7 @@ int query_db_notify(str* pres_uri, pres_ev_t* event, subs_t* watcher_subs) while(s) { LM_INFO("notify\n"); - if(notify(s, watcher_subs, notify_body, 0, NULL)< 0 ) + if(notify(s, watcher_subs, notify_body, 0, NULL, 0)< 0 ) { LM_ERR("Could not send notify for [event]=%.*s\n", event->name.len, event->name.s); @@ -1836,7 +1856,7 @@ int query_db_notify(str* pres_uri, pres_ev_t* event, subs_t* watcher_subs) } int send_notify_request(subs_t* subs, subs_t * watcher_subs, - str* n_body,int force_null_body, str* extra_hdrs) + str* n_body,int force_null_body, str* extra_hdrs, int from_publish) { dlg_t* td = NULL; str met = {"NOTIFY", 6}; @@ -1880,8 +1900,8 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, } else { - if(subs->status== TERMINATED_STATUS || - subs->status== PENDING_STATUS) + if(subs->status== TERMINATED_STATUS || + subs->status== PENDING_STATUS) { LM_DBG("state terminated or pending- notify body NULL\n"); notify_body = NULL; @@ -1899,9 +1919,13 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, } else { - notify_body = get_p_notify_body(subs->pres_uri, - subs->event, 0, 0, (subs->contact.s)?&subs->contact:NULL, - NULL, extra_hdrs?extra_hdrs:¬ify_extra_hdrs, &free_fct); + if (from_publish && n_body!= 0 && n_body->s!= 0) + notify_body = n_body; + else + notify_body = get_p_notify_body(subs->pres_uri, + subs->event, 0, 0, (subs->contact.s)?&subs->contact:NULL, + NULL, extra_hdrs?extra_hdrs:¬ify_extra_hdrs, + &free_fct, from_publish); if(notify_body == NULL || notify_body->s== NULL) { LM_DBG("Could not get the notify_body\n"); @@ -1946,7 +1970,7 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, { LM_ERR("while building headers\n"); goto error; - } + } LM_DBG("headers:\n%.*s\n", str_hdr.len, str_hdr.s); /* construct the dlg_t structure */ @@ -2004,12 +2028,12 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, td->id.loc_tag.len, td->id.loc_tag.s, td->loc_seq.value); free_tm_dlg(td); - + pkg_free(str_hdr.s); if (notify_extra_hdrs.s) pkg_free(notify_extra_hdrs.s); - + if((int)(long)n_body!= (int)(long)notify_body) { if(notify_body!=NULL) @@ -2036,7 +2060,7 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, pkg_free(str_hdr.s); if (notify_extra_hdrs.s) pkg_free(notify_extra_hdrs.s); - + if((int)(long)n_body!= (int)(long)notify_body) { if(notify_body!=NULL) @@ -2058,7 +2082,7 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, } -int notify(subs_t* subs, subs_t * watcher_subs, str* n_body, int force_null_body, str* extra_hdrs) +int notify(subs_t* subs, subs_t * watcher_subs, str* n_body, int force_null_body, str* extra_hdrs, int from_publish) { /* update first in hash table and the send Notify */ if(subs->expires!= 0 && subs->status != TERMINATED_STATUS) @@ -2080,13 +2104,13 @@ int notify(subs_t* subs, subs_t * watcher_subs, str* n_body, int force_null_body } } - if(subs->reason.s && subs->status== ACTIVE_STATUS && + if(subs->reason.s && subs->status== ACTIVE_STATUS && subs->reason.len== 12 && strncmp(subs->reason.s, "polite-block", 12)== 0) { force_null_body = 1; } - if(send_notify_request(subs, watcher_subs, n_body, force_null_body, extra_hdrs)< 0) + if(send_notify_request(subs, watcher_subs, n_body, force_null_body, extra_hdrs, from_publish)< 0) { LM_ERR("sending Notify not successful\n"); return -1; @@ -2099,8 +2123,8 @@ void p_tm_callback( struct cell *t, int type, struct tmcb_params *ps) { c_back_param* cb; - if(ps->param==NULL || *ps->param==NULL || - ((c_back_param*)(*ps->param))->pres_uri.s == NULL || + if(ps->param==NULL || *ps->param==NULL || + ((c_back_param*)(*ps->param))->pres_uri.s == NULL || ((c_back_param*)(*ps->param))->ev_name.s== NULL || ((c_back_param*)(*ps->param))->to_tag.s== NULL) { @@ -2131,7 +2155,7 @@ void p_tm_callback( struct cell *t, int type, struct tmcb_params *ps) delete_shtable(subs_htable, hash_code, cb->to_tag); delete_db_subs(cb->pres_uri, cb->ev_name, cb->to_tag); } - + if(cb != NULL) free_cbparam(cb); return ; @@ -2163,7 +2187,7 @@ c_back_param* shm_dup_cbparam(subs_t* subs) CONT_COPY(cb_param, cb_param->pres_uri, subs->pres_uri); CONT_COPY(cb_param, cb_param->ev_name, subs->event->name); CONT_COPY(cb_param, cb_param->to_tag, subs->to_tag); - + return cb_param; } @@ -2171,9 +2195,9 @@ c_back_param* shm_dup_cbparam(subs_t* subs) str* create_winfo_xml(watcher_t* watchers, char* version, str resource, str event, int STATE_FLAG ) { - xmlDocPtr doc = NULL; + xmlDocPtr doc = NULL; xmlNodePtr root_node = NULL, node = NULL; - xmlNodePtr w_list_node = NULL; + xmlNodePtr w_list_node = NULL; char content[200]; str *body= NULL; char* buffer= NULL; @@ -2221,7 +2245,7 @@ str* create_winfo_xml(watcher_t* watchers, char* version, buffer[resource.len]= '\0'; xmlNewProp(w_list_node, BAD_CAST "resource", BAD_CAST buffer); pkg_free(buffer); - + buffer= (char*)pkg_malloc(event.len+1); if(buffer== NULL) { @@ -2248,15 +2272,15 @@ str* create_winfo_xml(watcher_t* watchers, char* version, { LM_ERR("while adding new attribute\n"); goto error; - } - + } + if(xmlNewProp(node, BAD_CAST "event", BAD_CAST "subscribe")== NULL) { LM_ERR("while adding new attribute\n"); goto error; - } - - if(xmlNewProp(node, BAD_CAST "status", + } + + if(xmlNewProp(node, BAD_CAST "status", BAD_CAST get_status_str(w->status))== NULL) { LM_ERR("while adding new attribute\n"); @@ -2267,7 +2291,7 @@ str* create_winfo_xml(watcher_t* watchers, char* version, body = (str*)pkg_malloc(sizeof(str)); if(body == NULL) { - ERR_MEM(PKG_MEM_STR); + ERR_MEM(PKG_MEM_STR); } memset(body, 0, sizeof(str)); diff --git a/modules/presence/notify.h b/modules/presence/notify.h index 5a76564fd36..9ec4a9ffe8a 100644 --- a/modules/presence/notify.h +++ b/modules/presence/notify.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -100,12 +100,12 @@ void printf_subs(subs_t* subs); int query_db_notify(str* pres_uri,pres_ev_t* event, subs_t* watcher_subs ); int publ_notify(presentity_t* p, str pres_uri, str* body, str* offline_etag, - str* rules_doc, str* dialog_publish); + str* rules_doc, str* dialog_publish, int from_publish); -int notify(subs_t* subs, subs_t* watcher_subs, str* n_body,int force_null_body, str* extra_hdrs); +int notify(subs_t* subs, subs_t* watcher_subs, str* n_body,int force_null_body, str* extra_hdrs, int from_publish); int send_notify_request(subs_t* subs, subs_t * watcher_subs, - str* n_body,int force_null_body, str* extra_hdrs); + str* n_body,int force_null_body, str* extra_hdrs, int from_publish); char* get_status_str(int flag); void free_watcher_list(watcher_t* w); diff --git a/modules/presence/presence.c b/modules/presence/presence.c index 4686941fca4..eac2406c394 100644 --- a/modules/presence/presence.c +++ b/modules/presence/presence.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -42,7 +42,7 @@ #include "../../error.h" #include "../../ut.h" #include "../../parser/parse_to.h" -#include "../../parser/parse_uri.h" +#include "../../parser/parse_uri.h" #include "../../parser/parse_content.h" #include "../../parser/parse_from.h" #include "../../mem/mem.h" @@ -169,11 +169,25 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_url", get_deps_sqldb_url }, + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports= { "presence", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -226,7 +240,7 @@ static int mod_init(void) if(expires_offset<0) expires_offset = 0; - + if(max_expires_subscribe<= 0) max_expires_subscribe = 3600; @@ -235,7 +249,7 @@ static int mod_init(void) if(server_address.s== NULL) LM_DBG("server_address parameter not set in configuration file\n"); - + if(server_address.s) server_address.len= strlen(server_address.s); else @@ -254,7 +268,7 @@ static int mod_init(void) LM_ERR("can't load tm functions\n"); return -1; } - + if(db_url.s== NULL) { LM_ERR("database url not set!\n"); @@ -281,7 +295,7 @@ static int mod_init(void) LM_ERR("connecting to database failed\n"); return -1; } - + /*verify table versions */ if((db_check_table_version(&pa_dbf, pa_db, &presentity_table, P_TABLE_VERSION) < 0) || (db_check_table_version(&pa_dbf, pa_db, &active_watchers_table, ACTWATCH_TABLE_VERSION) < 0) || @@ -328,12 +342,12 @@ static int mod_init(void) if(clean_period>0) { - register_timer("presnce-pclean", msg_presentity_clean, 0, + register_timer("presence-pclean", msg_presentity_clean, 0, clean_period); register_timer("presence-wclean", msg_watchers_clean, 0, watchers_clean_period); } - + if(db_update_period>0) register_timer("presence-dbupdate", timer_db_update, 0, db_update_period); @@ -428,7 +442,7 @@ static void destroy(void) if(subs_htable) destroy_shtable(subs_htable, shtable_size); - + if(pres_htable) destroy_phtable(); @@ -465,7 +479,7 @@ static int fixup_presence(void** param, int param_no) LM_ERR( "wrong format[%s]\n",(char*)(*param)); return E_UNSPEC; } - + *param = (void*)model; return 0; } @@ -484,12 +498,12 @@ static int fixup_subscribe(void** param, int param_no) return 0; } -/* +/* * mi cmd: refreshWatchers - * + * * * // can be: = 0 -> watchers autentification type or - * != 0 -> publish type // + * != 0 -> publish type // * * */ static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param) @@ -515,7 +529,7 @@ static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param) LM_ERR( "empty uri\n"); return init_mi_tree(404, "Empty presentity URI", 20); } - + node = node->next; if(node == NULL) return 0; @@ -526,14 +540,14 @@ static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param) return init_mi_tree(400, "Empty event parameter", 21); } LM_DBG("event '%.*s'\n", event.len, event.s); - + node = node->next; if(node == NULL) return 0; if(node->value.s== NULL || node->value.len== 0) { LM_ERR( "empty event parameter\n"); - return init_mi_tree(400, "Empty event parameter", 21); + return init_mi_tree(400, "Empty event parameter", 21); } if(str2int(&node->value, &refresh_type)< 0) { @@ -553,7 +567,7 @@ static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param) LM_ERR( "wrong event parameter\n"); return 0; } - + if(refresh_type== 0) /* if a request to refresh watchers authorization*/ { if(ev->get_rules_doc== NULL) @@ -562,7 +576,7 @@ static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param) "for an event that does not require authorization\n"); goto error; } - + if(parse_uri(pres_uri.s, pres_uri.len, &uri)< 0) { LM_ERR( "parsing uri\n"); @@ -609,17 +623,17 @@ static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param) return 0; } -/* +/* * mi cmd: cleanup * * */ static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param) { LM_DBG("mi_cleanup:start\n"); - + (void)msg_watchers_clean(0,0); (void)msg_presentity_clean(0,0); - + return init_mi_tree(200, MI_OK_S, MI_OK_LEN); } @@ -656,7 +670,7 @@ static inline int mi_print_phtable_record(struct mi_node *rpl, pres_entry_t* pre static struct mi_root* mi_list_phtable(struct mi_root* cmd, void* param) { - + struct mi_root *rpl_tree; struct mi_node* rpl; pres_entry_t* p; @@ -665,6 +679,7 @@ static struct mi_root* mi_list_phtable(struct mi_root* cmd, void* param) rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return NULL; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; for(i= 0; ievent_id.s, s->event_id.len); if (attr==NULL) goto error; */ - p= int2str((unsigned long)s->status, &len); - attr = add_mi_attr(node, MI_DUP_VALUE, "status", 6, p, len); if (attr==NULL) goto error; - p= int2str((unsigned long)s->expires, &len); - attr = add_mi_attr(node, MI_DUP_VALUE, "expires", 7, p, len); + _ts = (time_t)s->expires; + date_buf_len = strftime(date_buf, MI_DATE_BUF_LEN - 1, + "%Y-%m-%d %H:%M:%S", localtime(&_ts)); + if (date_buf_len != 0) { + attr = add_mi_attr(node, MI_DUP_VALUE, "expires", 7, date_buf, date_buf_len); + } else { + p= int2str((unsigned long)s->expires, &len); + attr = add_mi_attr(node, MI_DUP_VALUE, "expires", 7, p, len); + } if (attr==NULL) goto error; p= int2str((unsigned long)s->db_flag, &len); attr = add_mi_attr(node, MI_DUP_VALUE, "db_flag", 7, p, len); @@ -750,13 +773,14 @@ static struct mi_root* mi_list_shtable(struct mi_root* cmd, void* param) struct mi_root *rpl_tree; struct mi_node* rpl; subs_t *s; - unsigned int i; + unsigned int i,j; rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return NULL; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; - for(i= 0; i< shtable_size; i++) + for(i=0,j=0; i< shtable_size; i++) { lock_get(&subs_htable[i].lock); s = subs_htable[i].entries->next; @@ -764,8 +788,12 @@ static struct mi_root* mi_list_shtable(struct mi_root* cmd, void* param) { if(mi_print_shtable_record(rpl, s)<0) goto error; s= s->next; + j++; } lock_release(&subs_htable[i].lock); + + if ((j % 50) == 0) + flush_mi_tree(rpl_tree); } return rpl_tree; error: @@ -824,13 +852,13 @@ int pres_update_status(subs_t subs, str reason, db_key_t* query_cols, reason.len))) { /* update in watchers_table */ - query_vals[q_wuser_col].val.str_val= subs.from_user; - query_vals[q_wdomain_col].val.str_val= subs.from_domain; + query_vals[q_wuser_col].val.str_val= subs.from_user; + query_vals[q_wdomain_col].val.str_val= subs.from_domain; update_vals[u_status_col].val.int_val= subs.status; update_vals[u_reason_col].val.str_val= subs.reason; - - if (pa_dbf.use_table(pa_db, &watchers_table) < 0) + + if (pa_dbf.use_table(pa_db, &watchers_table) < 0) { LM_ERR( "in use_table\n"); return -1; @@ -880,7 +908,7 @@ int pres_db_delete_status(subs_t* s) db_key_t query_cols[5]; db_val_t query_vals[5]; - if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) + if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) { LM_ERR("sql use table failed\n"); return -1; @@ -920,6 +948,35 @@ int pres_db_delete_status(subs_t* s) return 0; } + +int terminate_watchers(str *pres_uri, pres_ev_t* ev) +{ + subs_t *all_s; + subs_t *s; + subs_t *tmp; + + /* get all watchers for the presentity */ + all_s = get_subs_dialog( pres_uri, ev, NULL); + if ( all_s==NULL ) { + LM_DBG("No subscription dialogs found for <%.*s>\n", + pres_uri->len, pres_uri->s); + return 0; + } + /* set expire on 0 for all watchers */ + for( s=all_s ; s ; ) { + s->expires = 0; + tmp = s; + s = s->next; + /* update subscription */ + update_subscription( NULL, tmp, 0); + } + + free_subs_list( all_s, PKG_MEM_TYPE, 0); + + return 0; +} + + int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) { // static db_ps_t my_ps = NULL; @@ -983,7 +1040,7 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) result_cols[w_user_col= n_result_cols++]= &str_watcher_username_col; result_cols[w_domain_col= n_result_cols++]= &str_watcher_domain_col; - if (pa_dbf.use_table(pa_db, &watchers_table) < 0) + if (pa_dbf.use_table(pa_db, &watchers_table) < 0) { LM_ERR( "in use_table\n"); goto done; @@ -1027,7 +1084,7 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) row_vals = ROW_VALUES(row); status= row_vals[status_col].val.int_val; - + reason.s= (char*)row_vals[reason_col].val.string_val; reason.len= reason.s?strlen(reason.s):0; @@ -1041,7 +1098,7 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) { ws_list[i].reason.s = (char*)pkg_malloc(reason.len); if(ws_list[i].reason.s== NULL) - { + { LM_ERR("No more private memory\n"); goto done; } @@ -1050,7 +1107,7 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) } else ws_list[i].reason.s= NULL; - + ws_list[i].w_user.s = (char*)pkg_malloc(w_user.len); if(ws_list[i].w_user.s== NULL) { @@ -1060,7 +1117,7 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) } memcpy(ws_list[i].w_user.s, w_user.s, w_user.len); ws_list[i].w_user.len= w_user.len; - + ws_list[i].w_domain.s = (char*)pkg_malloc(w_domain.len); if(ws_list[i].w_domain.s== NULL) { @@ -1069,7 +1126,7 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) } memcpy(ws_list[i].w_domain.s, w_domain.s, w_domain.len); ws_list[i].w_domain.len= w_domain.len; - + ws_list[i].status= status; } @@ -1091,7 +1148,7 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) } } - + for(i=0; i< n; i++) { pkg_free(ws_list[i].w_user.s); @@ -1104,14 +1161,14 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) goto send_notify; } - + for(i = 0; i< result->n; i++) { row= &result->rows[i]; row_vals = ROW_VALUES(row); status= row_vals[status_col].val.int_val; - + reason.s= (char*)row_vals[reason_col].val.string_val; reason.len= reason.s?strlen(reason.s):0; @@ -1153,7 +1210,7 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) while(s) { - if(notify(s, NULL, NULL, 0, NULL)< 0) + if(notify(s, NULL, NULL, 0, NULL, 0)< 0) { LM_ERR( "sending Notify request\n"); goto done; @@ -1204,9 +1261,9 @@ int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc) pkg_free(ws_list[i].reason.s); } } - + free_watcher_list(watchers); - + return err_ret; } @@ -1243,13 +1300,13 @@ int refresh_send_winfo_notify(watcher_t* watchers, str pres_uri, goto error; } - if(notify(s, NULL, winfo_nbody, 0, NULL)< 0 ) + if(notify(s, NULL, winfo_nbody, 0, NULL, 0)< 0 ) { LM_ERR("Could not send notify for [event]=%.*s\n", s->event->name.len, s->event->name.s); goto error; } - + s = s->next; } xmlFree(winfo_nbody->s); @@ -1274,15 +1331,15 @@ static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs LM_DBG("start\n"); lock_get(&subs_htable[hash_code].lock); - + ps= subs_htable[hash_code].entries; - + while(ps && ps->next) { s= ps->next; if(s->event== subs->event && s->pres_uri.len== subs->pres_uri.len && - s->from_user.len== subs->from_user.len && + s->from_user.len== subs->from_user.len && s->from_domain.len==subs->from_domain.len && strncmp(s->pres_uri.s, subs->pres_uri.s, subs->pres_uri.len)== 0 && strncmp(s->from_user.s, subs->from_user.s, s->from_user.len)== 0 && @@ -1310,7 +1367,7 @@ static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs shm_free(s); LM_DBG(" deleted terminated dialog from hash table\n"); /* delete from database also */ - if( delete_db_subs(cs->pres_uri, + if( delete_db_subs(cs->pres_uri, cs->event->name, cs->to_tag)< 0) { LM_ERR("deleting subscription record from database\n"); @@ -1322,16 +1379,16 @@ static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs } else ps= s; - - + + printf_subs(cs); } else ps= s; } - + LM_DBG("found %d matching dialogs\n", i); lock_release(&subs_htable[hash_code].lock); - + return 0; } diff --git a/modules/presence/presence.h b/modules/presence/presence.h index 5479347855d..bcc9a6628e2 100644 --- a/modules/presence/presence.h +++ b/modules/presence/presence.h @@ -2,7 +2,7 @@ * $Id * * presence - presence server implementation - * + * * Copyright (C) 2006 Voice Sistem SRL * * This file is part of opensips, a free SIP server. @@ -50,7 +50,7 @@ extern db_con_t* pa_db; extern str db_url; extern str presentity_table; extern str active_watchers_table; -extern str watchers_table; +extern str watchers_table; extern int counter; extern int pid; @@ -73,6 +73,8 @@ extern long waiting_subs_time; int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc); +int terminate_watchers(str *pres_uri, pres_ev_t* ev); + extern str bla_presentity_spec_param; extern pv_spec_t bla_presentity_spec; extern int fix_remote_target; diff --git a/modules/presence/presentity.c b/modules/presence/presentity.c index 227daa6b681..95af636c754 100644 --- a/modules/presence/presentity.c +++ b/modules/presence/presentity.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -41,7 +41,7 @@ #include "../alias_db/alias_db.h" #include "../../data_lump_rpl.h" #include "presentity.h" -#include "presence.h" +#include "presence.h" #include "notify.h" #include "publish.h" #include "hash.h" @@ -98,7 +98,7 @@ int publ_send200ok(struct sip_msg *msg, int lexpire, str etag) hdr_append.s = buf; hdr_append.s[0]='\0'; - + hdr_append.len = sprintf(hdr_append.s, "Expires: %d\r\n",((lexpire< expires_offset)?0: (lexpire - expires_offset))); if(hdr_append.len < 0) @@ -112,7 +112,7 @@ int publ_send200ok(struct sip_msg *msg, int lexpire, str etag) goto error; } hdr_append.s[hdr_append.len]= '\0'; - + if (add_lump_rpl( msg, hdr_append.s, hdr_append.len, LUMP_RPL_HDR)==0 ) { LM_ERR("unable to add lump_rl\n"); @@ -296,7 +296,7 @@ int dialog_fix_remote_target(str *body, str *fixed_body) &fixed_body->len); xmlFreeDoc(doc); - + return 0; error: @@ -411,6 +411,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r str pres_uri= {NULL, 0}; pres_entry_t* p= NULL; unsigned int hash_code; + unsigned int turn; str body = presentity->body; str *extra_hdrs = presentity->extra_hdrs; db_res_t *result= NULL; @@ -426,7 +427,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r goto error; } } - + if(uandd_to_uri(presentity->user, presentity->domain, &pres_uri)< 0) { LM_ERR("constructing uri from user and domain\n"); @@ -462,10 +463,11 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r n_query_cols++; result_cols[0] = &str_etag_col; + hash_code= core_hash(&pres_uri, NULL, phtable_size); if(presentity->etag_new) { - if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0) + if (msg && publ_send200ok(msg,presentity->expires,presentity->etag)<0) { LM_ERR("sending 200OK\n"); goto error; @@ -473,14 +475,15 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r *sent_reply= 1; /* insert new record in hash_table */ - if(insert_phtable(&pres_uri, presentity->event->evp->parsed, - &presentity->etag, presentity->sphere)< 0) + p = insert_phtable(&pres_uri, presentity->event->evp->parsed, + &presentity->etag, presentity->sphere, 1); + if (p==NULL) { LM_ERR("inserting record in hash table\n"); goto error; } - /* insert new record into database */ + /* insert new record into database */ query_cols[n_query_cols] = &str_expires_col; query_vals[n_query_cols].type = DB_INT; query_vals[n_query_cols].nul = 0; @@ -524,7 +527,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r n_query_cols++; } - if (pa_dbf.use_table(pa_db, &presentity_table) < 0) + if (pa_dbf.use_table(pa_db, &presentity_table) < 0) { LM_ERR("unsuccessful use_table\n"); goto error; @@ -533,7 +536,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r LM_DBG("inserting %d cols into table\n",n_query_cols); //CON_PS_REFERENCE(pa_db) = &my_ps_insert; - if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) + if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) { LM_ERR("inserting new record in database\n"); goto error; @@ -542,14 +545,28 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r } else { - hash_code= core_hash(&pres_uri, NULL, phtable_size); lock_get(&pres_htable[hash_code].lock); - p = search_phtable_etag(&pres_uri, presentity->event->evp->parsed, &presentity->etag, hash_code); + if (p) { + + turn = p->last_turn++; + LM_DBG("pres <%.*s> my turn is %d, current turn is %d\n",pres_uri.len, + pres_uri.s, turn, p->current_turn); + + /* wait to get our turn as order of handling pubishs + (need to wait the ongoing published to terminate + before starting */ + while (p && turn!=p->current_turn) { + lock_release(&pres_htable[hash_code].lock); + sleep_us(100); + lock_get(&pres_htable[hash_code].lock); + p = search_phtable_etag(&pres_uri, presentity->event->evp->parsed, + &presentity->etag, hash_code); + } + + } else { - if(!p) - { lock_release(&pres_htable[hash_code].lock); /* search also in db */ if (pa_dbf.use_table(pa_db, &presentity_table) < 0) @@ -571,16 +588,15 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r pa_dbf.free_result(pa_db, result); LM_ERR("No E_Tag match [%.*s]\n", presentity->etag.len, presentity->etag.s); - if (sigb.reply(msg, 412, &pu_412_rpl, 0) == -1) + if (msg && sigb.reply(msg, 412, &pu_412_rpl, 0)==-1 ) { - LM_ERR("sending '412 Conditional request failed' reply\n"); - goto error; + LM_ERR("sending '412 Conditional request failed' reply\n"); + goto error; } *sent_reply= 1; goto done; } - pa_dbf.free_result(pa_db, result); LM_INFO("*** found in db but not in htable [%.*s]\n", presentity->etag.len, presentity->etag.s); @@ -594,35 +610,45 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r { LM_ERR("deleting record from hash table failed\n"); } + /* presentity removed, pointer no longer valid */ + p = NULL; lock_release(&pres_htable[hash_code].lock); - if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0) + if(msg && publ_send200ok(msg,presentity->expires,presentity->etag)<0) { LM_ERR("sending 200OK reply\n"); goto error; } *sent_reply= 1; - if(publ_notify(presentity, pres_uri, body.s ? &body : 0, - &presentity->etag, rules_doc, NULL) < 0) + if(publ_notify(presentity, pres_uri, body.s ? &body : 0, + &presentity->etag, rules_doc, NULL, 1) < 0) { LM_ERR("while sending notify\n"); goto error; } - if (pa_dbf.use_table(pa_db, &presentity_table) < 0) + if (pa_dbf.use_table(pa_db, &presentity_table) < 0) { LM_ERR("unsuccessful sql use table\n"); goto error; } - // CON_PS_REFERENCE(pa_db) = &my_ps_delete; + //CON_PS_REFERENCE(pa_db) = &my_ps_delete; if(pa_dbf.delete(pa_db,query_cols,0,query_vals,n_query_cols)<0) { LM_ERR("unsuccessful sql delete operation"); goto error; } LM_DBG("Expires=0, deleted from db %.*s\n", - presentity->user.len,presentity->user.s); + presentity->user.len,presentity->user.s); + /* Send another NOTIFY, this time rely on whatever is on the DB, + * so in case there are no documents an empty + * NOTIFY will be sent to the watchers */ + if(publ_notify(presentity, pres_uri, NULL, NULL, rules_doc, NULL, 1) < 0) + { + LM_ERR("while sending notify\n"); + goto error; + } goto send_mxd_notify; } @@ -644,8 +670,9 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r else { lock_release(&pres_htable[hash_code].lock); - if(insert_phtable(&pres_uri, presentity->event->evp->parsed, - &presentity->etag, presentity->sphere)< 0) + p = insert_phtable(&pres_uri, presentity->event->evp->parsed, + &presentity->etag, presentity->sphere, 1); + if ( p==NULL ) { LM_ERR("inserting record in hash table\n"); goto error; @@ -723,7 +750,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r n_update_cols++; /* updated stored sphere */ - if(sphere_enable && + if(sphere_enable && presentity->event->evp->parsed== EVENT_PRESENCE) { if(update_phtable(presentity, pres_uri, body)< 0) @@ -732,28 +759,28 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r goto error; } } - // CON_PS_REFERENCE(pa_db) = &my_ps_update_body; + //CON_PS_REFERENCE(pa_db) = &my_ps_update_body; } else { - // CON_PS_REFERENCE(pa_db) = &my_ps_update_no_body; + //CON_PS_REFERENCE(pa_db) = &my_ps_update_no_body; } - if (pa_dbf.use_table(pa_db, &presentity_table) < 0) + if (pa_dbf.use_table(pa_db, &presentity_table) < 0) { LM_ERR("unsuccessful sql use table\n"); goto error; } if( pa_dbf.update( pa_db,query_cols, query_ops, query_vals, - update_keys, update_vals, n_query_cols, n_update_cols )<0) + update_keys, update_vals, n_query_cols, n_update_cols )<0) { LM_ERR("updating published info in database\n"); goto error; } - + /* send 200OK */ - if( publ_send200ok(msg, presentity->expires, cur_etag)< 0) + if (msg && publ_send200ok(msg, presentity->expires, cur_etag)<0 ) { LM_ERR("sending 200OK reply\n"); goto error; @@ -767,7 +794,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r send_notify: if (publ_notify(presentity, pres_uri, body.s?&body:0, - NULL, rules_doc, NULL)<0) + NULL, rules_doc, NULL, 1)<0) { LM_ERR("while sending Notify requests to watchers\n"); goto error; @@ -776,7 +803,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r send_mxd_notify: /* if event dialog -> send Notify for presence also */ if(mix_dialog_presence && *pres_event_p && - presentity->event->evp->parsed == EVENT_DIALOG) + presentity->event->evp->parsed == EVENT_DIALOG) { str* dialog_body= NULL; @@ -787,7 +814,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r { /* send Notify for presence */ presentity->event = *pres_event_p; - if (publ_notify(presentity, pres_uri, 0, NULL, 0, dialog_body)<0) + if (publ_notify(presentity, pres_uri, 0, NULL, 0, dialog_body, 1)<0) { LM_ERR("while sending Notify requests to watchers\n"); if(dialog_body && dialog_body!=FAKED_BODY) @@ -806,6 +833,10 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r } done: + /* allow next publish to be handled */ + if (p) + next_turn_phtable( p, hash_code); + if (notify_body.s) xmlFree(notify_body.s); @@ -820,6 +851,10 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r return 0; error: + /* allow next publish to be handled */ + if (p) + next_turn_phtable( p, hash_code); + if(result) pa_dbf.free_result(pa_db, result); if(etag.s) @@ -839,9 +874,21 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_r return -1; } + +/* This is just a wrappter over "update_presentity" to be able to export the + * function via the internal API - basically provides the "publishing" support + * without actually having the PUBLISH SIP request, but directly a presentity + */ +int internal_update_presentity(presentity_t* presentity) +{ + int dummy; + return update_presentity( NULL, presentity, &dummy); +} + + int pres_htable_restore(void) { - /* query all records from presentity table and insert records + /* query all records from presentity table and insert records * in presentity table */ db_key_t result_cols[6]; db_res_t *result= NULL; @@ -873,10 +920,10 @@ int pres_htable_restore(void) } /* select the whole tabel and all the columns */ - if (DB_CAPABILITY(pa_dbf, DB_CAP_FETCH)) + if (DB_CAPABILITY(pa_dbf, DB_CAP_FETCH)) { if(pa_dbf.query(pa_db,0,0,0,result_cols, 0, - n_result_cols, result_cols[user_col], 0) < 0) + n_result_cols, result_cols[user_col], 0) < 0) { LM_ERR("Error while querying (fetch) database\n"); return -1; @@ -888,7 +935,7 @@ int pres_htable_restore(void) LM_ERR("fetching rows failed\n"); return -1; } - } else + } else { if (pa_dbf.query (pa_db, 0, 0, 0,result_cols,0, n_result_cols, result_cols[user_col], &result) < 0) @@ -918,7 +965,7 @@ int pres_htable_restore(void) continue; } - if (VAL_NULL(row_vals+2) || VAL_NULL(row_vals+3)) + if (VAL_NULL(row_vals+2) || VAL_NULL(row_vals+3)) { LM_ERR("columns %.*s or/and %.*s cannot be null -> skipping\n", str_event_col.len, str_event_col.s, @@ -928,7 +975,7 @@ int pres_htable_restore(void) if(row_vals[expires_col].val.int_val< (int)time(NULL)) continue; - + sphere= NULL; user.s= (char*)row_vals[user_col].val.string_val; user.len= strlen(user.s); @@ -954,7 +1001,7 @@ int pres_htable_restore(void) goto error; } /* insert in hash_table*/ - + if(sphere_enable && event== EVENT_PRESENCE ) { body.s= (char*)row_vals[body_col].val.string_val; @@ -962,7 +1009,7 @@ int pres_htable_restore(void) sphere= extract_sphere(body); } - if(insert_phtable(&uri, event, &etag, sphere)< 0) + if(insert_phtable(&uri, event, &etag, sphere, 0)== NULL) { LM_ERR("inserting record in presentity hash table"); pkg_free(uri.s); @@ -976,27 +1023,27 @@ int pres_htable_restore(void) } /* any more data to be fetched ?*/ - if (DB_CAPABILITY(pa_dbf, DB_CAP_FETCH)) + if (DB_CAPABILITY(pa_dbf, DB_CAP_FETCH)) { - if (pa_dbf.fetch_result( pa_db, &result, no_rows) < 0) + if (pa_dbf.fetch_result( pa_db, &result, no_rows) < 0) { LM_ERR("fetching more rows failed\n"); goto error; } nr_rows = RES_ROW_N(result); - } else + } else nr_rows = 0; }while (nr_rows>0); pa_dbf.free_result(pa_db, result); - + return 0; error: if(result) pa_dbf.free_result(pa_db, result); - return -1; + return -1; } char* extract_sphere(str body) @@ -1006,7 +1053,7 @@ char* extract_sphere(str body) xmlDocPtr doc= NULL; xmlNodePtr node; char* cont, *sphere= NULL; - + doc= xmlParseMemory(body.s, body.len); if(doc== NULL) @@ -1016,7 +1063,7 @@ char* extract_sphere(str body) } node= xmlNodeGetNodeByName(doc->children, "sphere", "rpid"); - + if(node== NULL) node= xmlNodeGetNodeByName(doc->children, "sphere", "r"); @@ -1075,7 +1122,7 @@ char* get_sphere(str* pres_uri) db_val_t query_vals[6]; db_key_t result_cols[6]; db_res_t *result = NULL; - db_row_t *row= NULL ; + db_row_t *row= NULL ; db_val_t *row_vals; int n_result_cols = 0; int n_query_cols = 0; @@ -1144,23 +1191,23 @@ char* get_sphere(str* pres_uri) result_cols[n_result_cols++] = &str_body_col; result_cols[n_result_cols++] = &str_extra_hdrs_col; - - if (pa_dbf.use_table(pa_db, &presentity_table) < 0) + + if (pa_dbf.use_table(pa_db, &presentity_table) < 0) { LM_ERR("in use_table\n"); return NULL; } - // CON_PS_REFERENCE(pa_db) = &my_ps; + // CON_PS_REFERENCE(pa_db) = &my_ps; if (pa_dbf.query (pa_db, query_cols, 0, query_vals, - result_cols, n_query_cols, n_result_cols, &query_str , &result) < 0) + result_cols, n_query_cols, n_result_cols, &query_str , &result) < 0) { LM_ERR("failed to query %.*s table\n", presentity_table.len, presentity_table.s); if(result) pa_dbf.free_result(pa_db, result); return NULL; } - + if(result== NULL) return NULL; @@ -1186,7 +1233,7 @@ char* get_sphere(str* pres_uri) LM_ERR("Empty notify body record\n"); goto error; } - + sphere= extract_sphere(body); pa_dbf.free_result(pa_db, result); diff --git a/modules/presence/presentity.h b/modules/presence/presentity.h index 44717093415..fe14a7a203f 100644 --- a/modules/presence/presentity.h +++ b/modules/presence/presentity.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -31,7 +31,7 @@ #define PRESENTITY_H #include "../../str.h" -#include "../../parser/msg_parser.h" +#include "../../parser/msg_parser.h" #include "event_list.h" //#include "presence.h" @@ -54,6 +54,8 @@ typedef struct presentity str body; } presentity_t; +int internal_update_presentity(presentity_t* presentity); + /* update presentity in database */ int update_presentity(struct sip_msg* msg, presentity_t* presentity, int* sent_reply); diff --git a/modules/presence/publish.c b/modules/presence/publish.c index 4f6b1045e02..f764382f899 100644 --- a/modules/presence/publish.c +++ b/modules/presence/publish.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -32,10 +32,10 @@ #include "../../ut.h" #include "../../str.h" #include "../../parser/parse_to.h" -#include "../../parser/parse_uri.h" -#include "../../parser/parse_expires.h" -#include "../../parser/parse_event.h" -#include "../../parser/parse_content.h" +#include "../../parser/parse_uri.h" +#include "../../parser/parse_expires.h" +#include "../../parser/parse_event.h" +#include "../../parser/parse_content.h" #include "../../lock_ops.h" #include "../../hash_func.h" #include "../../db/db.h" @@ -119,7 +119,7 @@ void msg_presentity_clean(unsigned int ticks,void *param) db_op_t db_ops[2] ; db_key_t result_cols[6]; db_res_t *result = NULL; - db_row_t *row ; + db_row_t *row ; db_val_t *row_vals ; int i =0, size= 0; struct p_modif* p= NULL; @@ -132,7 +132,7 @@ void msg_presentity_clean(unsigned int ticks,void *param) str* rules_doc= NULL; static str query_str = str_init("username"); - if (pa_dbf.use_table(pa_db, &presentity_table) < 0) + if (pa_dbf.use_table(pa_db, &presentity_table) < 0) { LM_ERR("in use_table\n"); return ; @@ -196,7 +196,7 @@ void msg_presentity_clean(unsigned int ticks,void *param) event.s= (char*)row_vals[event_col].val.string_val; event.len= strlen(event.s); - + size= sizeof(presentity_t) + user.len+ domain.len+ etag.len; pres= (presentity_t*)pkg_malloc(size); if(pres== NULL) @@ -205,7 +205,7 @@ void msg_presentity_clean(unsigned int ticks,void *param) } memset(pres, 0, size); size= sizeof(presentity_t); - + pres->user.s= (char*)pres+ size; memcpy(pres->user.s, user.s, user.len); pres->user.len= user.len; @@ -253,13 +253,13 @@ void msg_presentity_clean(unsigned int ticks,void *param) rules_doc= NULL; - if(p[i].p->event->get_rules_doc && + if(p[i].p->event->get_rules_doc && p[i].p->event->get_rules_doc(&p[i].p->user, &p[i].p->domain, &rules_doc)< 0) { LM_ERR("getting rules doc\n"); goto error; } - if(publ_notify( p[i].p, p[i].uri, NULL, &p[i].p->etag, rules_doc, NULL)< 0) + if(publ_notify( p[i].p, p[i].uri, NULL, &p[i].p->etag, rules_doc, NULL, 0)< 0) { LM_ERR("sending Notify request\n"); goto error; @@ -279,7 +279,10 @@ void msg_presentity_clean(unsigned int ticks,void *param) } error: - if (pa_dbf.use_table(pa_db, &presentity_table) < 0) + if(result) + pa_dbf.free_result(pa_db, result); + + if (pa_dbf.use_table(pa_db, &presentity_table) < 0) { LM_ERR("in use_table\n"); goto clean; @@ -291,14 +294,11 @@ void msg_presentity_clean(unsigned int ticks,void *param) LM_ERR("cleaning expired messages\n"); clean: - if(result) - pa_dbf.free_result(pa_db, result); - if(p) { for(i= 0; i< n; i++) { - + if(p[i].p) pkg_free(p[i].p); if(p[i].uri.s) @@ -394,7 +394,7 @@ int handle_publish(struct sip_msg* msg, char* sender_uri, char* str2) LM_DBG("Expires header found, value= %d\n", lexpire); } - else + else { LM_DBG("'expires' not found; default=%d\n", event->default_expires); lexpire = event->default_expires; @@ -433,7 +433,7 @@ int handle_publish(struct sip_msg* msg, char* sender_uri, char* str2) LM_DBG("existing etag= %.*s\n", etag.len, etag.s); } - if (!msg->content_length) + if (!msg->content_length) { LM_ERR("no Content-Length header found!\n"); goto error; @@ -489,8 +489,8 @@ int handle_publish(struct sip_msg* msg, char* sender_uri, char* str2) { LM_ERR("bad sender SIP address!\n"); goto error; - } - else + } + else { LM_DBG("using user id [%.*s]\n",buf_len,buf); } @@ -549,14 +549,14 @@ int handle_publish(struct sip_msg* msg, char* sender_uri, char* str2) return 1; unsupported_event: - + LM_ERR("Missing or unsupported event header field value\n"); - + if(msg->event && msg->event->body.s && msg->event->body.len>0) LM_ERR("\tevent=[%.*s]\n", msg->event->body.len, msg->event->body.s); reply_code= BAD_EVENT_CODE; - reply_str= pu_489_rpl; + reply_str= pu_489_rpl; error: if(sent_reply== 0) diff --git a/modules/presence/publish.h b/modules/presence/publish.h index 9ca95ba709d..bd76592cdbf 100644 --- a/modules/presence/publish.h +++ b/modules/presence/publish.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence/subscribe.c b/modules/presence/subscribe.c index fd7162e83e5..07393c79c44 100644 --- a/modules/presence/subscribe.c +++ b/modules/presence/subscribe.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -117,7 +117,7 @@ int send_2XX_reply(struct sip_msg * msg, int reply_code, int lexpire, LM_ERR("sending reply\n"); goto error; } - + pkg_free(hdr_append); return 0; @@ -152,8 +152,8 @@ int delete_db_subs(str pres_uri, str ev_stored_name, str to_tag) query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = to_tag; n_query_cols++; - - if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) + + if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) { LM_ERR("in use table sql operation\n"); return -1; @@ -181,7 +181,7 @@ int update_subs_db(subs_t* subs, int type) if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) { - LM_ERR("in use table sql operation\n"); + LM_ERR("in use table sql operation\n"); return -1; } @@ -271,7 +271,7 @@ int update_subs_db(subs_t* subs, int type) update_vals[n_update_cols].nul = 0; update_vals[n_update_cols].val.int_val = subs->local_cseq+ 1; n_update_cols++; - + update_keys[n_update_cols] = &str_version_col; update_vals[n_update_cols].type = DB_INT; update_vals[n_update_cols].nul = 0; @@ -374,7 +374,7 @@ int update_subscription(struct sip_msg* msg, subs_t* subs, int init_req) subs->local_cseq= delete_shtable(subs_htable,hash_code, subs->to_tag); - if( send_2XX_reply(msg, reply_code, subs->expires, 0, + if( msg && send_2XX_reply(msg, reply_code, subs->expires, 0, &subs->local_contact) <0) { LM_ERR("sending %d OK\n", reply_code); @@ -398,7 +398,7 @@ int update_subscription(struct sip_msg* msg, subs_t* subs, int init_req) } } - if(send_2XX_reply(msg, reply_code, subs->expires, 0, + if(msg && send_2XX_reply(msg, reply_code, subs->expires, 0, &subs->local_contact)<0) { LM_ERR("sending 2XX reply\n"); @@ -407,7 +407,7 @@ int update_subscription(struct sip_msg* msg, subs_t* subs, int init_req) } else { - if(send_2XX_reply(msg, reply_code, subs->expires, &subs->to_tag, + if(msg && send_2XX_reply(msg, reply_code, subs->expires, &subs->to_tag, &subs->local_contact)<0) { LM_ERR("sending 2XX reply\n"); @@ -432,7 +432,7 @@ int update_subscription(struct sip_msg* msg, subs_t* subs, int init_req) } } } - /*otherwise there is a subscription outside a dialog with expires= 0 + /*otherwise there is a subscription outside a dialog with expires= 0 * no update in database, but should try to send Notify */ } @@ -448,7 +448,7 @@ int update_subscription(struct sip_msg* msg, subs_t* subs, int init_req) } } LM_INFO("notify\n"); - if(notify(subs, NULL, NULL, 0 , NULL)< 0) + if(notify(subs, NULL, NULL, 0 , NULL, 0)< 0) { LM_ERR("Failed to send notify request\n"); goto error; @@ -480,13 +480,13 @@ void msg_watchers_clean(unsigned int ticks,void *param) db_vals[1].nul = 0; db_vals[1].val.int_val = PENDING_STATUS; - if (pa_dbf.use_table(pa_db, &watchers_table) < 0) + if (pa_dbf.use_table(pa_db, &watchers_table) < 0) { LM_ERR("unsuccessful use_table sql operation\n"); return; } - if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, 2) < 0) + if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, 2) < 0) LM_ERR("cleaning pending subscriptions\n"); } @@ -515,7 +515,7 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) counter++; memset(&subs, 0, sizeof(subs_t)); - + reply_code= 400; reply_str= pu_400_rpl; @@ -524,7 +524,7 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) LM_ERR("parsing headers\n"); goto error; } - + /* inspecting the Event header field */ if(msg->event && msg->event->body.len > 0) { @@ -533,7 +533,7 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) goto error; } if(((event_t*)msg->event->parsed)->parsed == EVENT_OTHER) - { + { goto bad_event; } } @@ -548,7 +548,7 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) goto bad_event; } subs.event= event; - + /* extract the id if any*/ ev_param= parsed_event->params; while(ev_param) @@ -560,7 +560,7 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) } ev_param= ev_param->next; } - + ret = extract_sdialog_info(&subs, msg, max_expires_subscribe, &init_req, server_address); if(ret< 0) @@ -611,7 +611,7 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) /* call event specific subscription handling */ if(event->evs_subs_handl) { - if(event->evs_subs_handl(msg)< 0) + if(event->evs_subs_handl(msg, &subs, &reply_code, &reply_str)< 0) { LM_ERR("in event specific subscription handling\n"); goto error; @@ -623,10 +623,10 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) { if(!event->req_auth ||(force_active_param && force_active_param[0] == '1')) subs.status = ACTIVE_STATUS; - else + else { /* query in watchers_table - if negative reply - server error */ - + if(get_db_subs_auth(&subs, &found) < 0) { LM_ERR("getting subscription status from watchers table\n"); @@ -653,7 +653,7 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) LM_ERR("wrong status\n"); goto error; } - LM_DBG("subscription status= %s - %s\n", get_status_str(subs.status), + LM_DBG("subscription status= %s - %s\n", get_status_str(subs.status), found==0?"inserted":"found in watcher table"); if(update_subscription(msg, &subs, init_req) <0) @@ -668,7 +668,7 @@ int handle_subscribe(struct sip_msg* msg, char* force_active_param, char* str2) } if(reason.s) pkg_free(reason.s); - + if(subs.pres_uri.s) pkg_free(subs.pres_uri.s); if(subs.record_route.s) @@ -732,7 +732,7 @@ int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int mexp, int* init_r LM_DBG("'Expires' header found, value= %d\n", lexpire); } - else + else { LM_DBG("'expires' not found; default=%d\n",subs->event->default_expires); lexpire = subs->event->default_expires; @@ -780,15 +780,15 @@ int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int mexp, int* init_r { LM_DBG("'From' header not parsed\n"); /* parsing from header */ - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); goto error; } } pfrom = (struct to_body*)msg->from->parsed; - - if( pfrom->parsed_uri.user.s && pfrom->parsed_uri.host.s && + + if( pfrom->parsed_uri.user.s && pfrom->parsed_uri.host.s && pfrom->parsed_uri.user.len && pfrom->parsed_uri.host.len) { subs->from_user = pfrom->parsed_uri.user; @@ -807,7 +807,7 @@ int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int mexp, int* init_r /*check if the message is an initial request */ if (pto->tag_value.s==NULL || pto->tag_value.len==0 ) - { + { LM_DBG("initial request\n"); *init_req = 1; } @@ -852,7 +852,7 @@ int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int mexp, int* init_r goto error; } subs->contact = b->contacts->uri; - + LM_DBG("subs->contact= %.*s - len = %d\n",subs->contact.len, subs->contact.s, subs->contact.len); @@ -906,14 +906,14 @@ int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int mexp, int* init_r rt = print_rr_body(msg->record_route, &rec_route, 0, 0); if(rt != 0) { - LM_ERR("processing the record route [%d]\n", rt); + LM_ERR("processing the record route [%d]\n", rt); rec_route.s=NULL; rec_route.len=0; // goto error; } } subs->record_route = rec_route; - + subs->sockinfo= msg->rcv.bind_address; if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) @@ -924,7 +924,7 @@ int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int mexp, int* init_r subs->from_tag = pfrom->tag_value; subs->version = 0; - + if(!local_address.s || !local_address.len) { if(get_local_contact(msg->rcv.bind_address, &subs->local_contact) < 0) @@ -1026,9 +1026,9 @@ int get_stored_info(struct sip_msg* msg, subs_t* subs, int* reply_code, return -1; found_rec: - + LM_DBG("Record found in hash_table\n"); - + if(s->event->evp->parsed!= EVENT_DIALOG_SLA) subs->pres_uri= pres_uri; @@ -1059,18 +1059,18 @@ int get_stored_info(struct sip_msg* msg, subs_t* subs, int* reply_code, } subs->local_cseq= s->local_cseq; - + if(subs->remote_cseq<= s->remote_cseq) { LM_ERR("wrong sequence number;received: %d - stored: %d\n", subs->remote_cseq, s->remote_cseq); - + *reply_code= 400; *reply_str= pu_400_rpl; lock_release(&subs_htable[i].lock); goto error; - } + } lock_release(&subs_htable[i].lock); return 0; @@ -1092,7 +1092,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r db_val_t query_vals[10]; db_key_t result_cols[9]; db_res_t *result= NULL; - db_row_t *row ; + db_row_t *row ; db_val_t *row_vals ; int n_query_cols = 0; int n_result_cols = 0; @@ -1108,7 +1108,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = subs->to_user; n_query_cols++; - + query_cols[n_query_cols] = &str_to_domain_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; @@ -1120,7 +1120,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = subs->from_user; n_query_cols++; - + query_cols[n_query_cols] = &str_watcher_domain_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; @@ -1145,7 +1145,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r query_vals[n_query_cols].val.str_val.len = 0; } n_query_cols++; - + query_cols[n_query_cols] = &str_callid_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; @@ -1172,16 +1172,16 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r result_cols[record_route_col=n_result_cols++] = &str_record_route_col; result_cols[version_col=n_result_cols++] = &str_version_col; - if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) + if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) { LM_ERR("unsuccessful use_table sql operation\n"); return -1; } - + CON_PS_REFERENCE(pa_db) = &my_ps; if (pa_dbf.query (pa_db, query_cols, 0, query_vals, - result_cols, n_query_cols, n_result_cols, 0, &result) < 0) + result_cols, n_query_cols, n_result_cols, 0, &result) < 0) { LM_ERR("querying subscription dialog\n"); if(result) @@ -1194,7 +1194,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r if(result && result->n <=0) { LM_ERR("No matching subscription dialog found in database\n"); - + pa_dbf.free_result(pa_db, result); *reply_code= 481; *reply_str= pu_481_rpl; @@ -1205,7 +1205,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r row = &result->rows[0]; row_vals = ROW_VALUES(row); remote_cseq= row_vals[remote_cseq_col].val.int_val; - + if(subs->remote_cseq<= remote_cseq) { LM_ERR("wrong sequence number received: %d - stored: %d\n", @@ -1215,7 +1215,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r pa_dbf.free_result(pa_db, result); return -1; } - + subs->status= row_vals[status_col].val.int_val; reason.s= (char*)row_vals[reason_col].val.string_val; if(reason.s) @@ -1284,13 +1284,13 @@ int handle_expired_subs(subs_t* s) s->expires= 0; LM_INFO("notify\n"); - if(send_notify_request(s, NULL, NULL, 1, NULL)< 0) + if(send_notify_request(s, NULL, NULL, 1, NULL, 0)< 0) { LM_ERR("send Notify not successful\n"); return -1; } } - + return 0; } @@ -1301,14 +1301,14 @@ void timer_db_update(unsigned int ticks,void *param) if(ticks== 0 && param == NULL) no_lock= 1; - + if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0) { LM_ERR("sql use table failed\n"); return; } - update_db_subs(pa_db, pa_dbf, subs_htable, + update_db_subs(pa_db, pa_dbf, subs_htable, shtable_size, no_lock, handle_expired_subs); } @@ -1323,10 +1323,10 @@ void update_db_subs(db_con_t *db,db_func_t dbf, shtable_t hash_table, db_op_t update_ops[1]; subs_t* del_s; int pres_uri_col, to_user_col, to_domain_col, from_user_col, from_domain_col, - callid_col, totag_col, fromtag_col, event_col,status_col, event_id_col, - local_cseq_col, remote_cseq_col, expires_col, record_route_col, + callid_col, totag_col, fromtag_col, event_col,status_col, event_id_col, + local_cseq_col, remote_cseq_col, expires_col, record_route_col, contact_col, local_contact_col, version_col,socket_info_col,reason_col; - int u_expires_col, u_local_cseq_col, u_remote_cseq_col, u_version_col, + int u_expires_col, u_local_cseq_col, u_remote_cseq_col, u_version_col, u_reason_col, u_status_col, u_contact_col; int i; subs_t* s= NULL, *prev_s= NULL; @@ -1337,7 +1337,7 @@ void update_db_subs(db_con_t *db,db_func_t dbf, shtable_t hash_table, query_vals[pres_uri_col].type = DB_STR; query_vals[pres_uri_col].nul = 0; n_query_cols++; - + query_cols[callid_col= n_query_cols] =&str_callid_col; query_vals[callid_col].type = DB_STR; query_vals[callid_col].nul = 0; @@ -1364,7 +1364,7 @@ void update_db_subs(db_con_t *db,db_func_t dbf, shtable_t hash_table, query_vals[to_domain_col].type = DB_STR; query_vals[to_domain_col].nul = 0; n_query_cols++; - + query_cols[from_user_col= n_query_cols] =&str_watcher_username_col; query_vals[from_user_col].type = DB_STR; query_vals[from_user_col].nul = 0; @@ -1378,7 +1378,7 @@ void update_db_subs(db_con_t *db,db_func_t dbf, shtable_t hash_table, query_cols[event_col= n_query_cols] =&str_event_col; query_vals[event_col].type = DB_STR; query_vals[event_col].nul = 0; - n_query_cols++; + n_query_cols++; query_cols[event_id_col= n_query_cols] =&str_event_id_col; query_vals[event_id_col].type = DB_STR; @@ -1414,7 +1414,7 @@ void update_db_subs(db_con_t *db,db_func_t dbf, shtable_t hash_table, query_vals[record_route_col].type = DB_STR; query_vals[record_route_col].nul = 0; n_query_cols++; - + query_cols[contact_col= n_query_cols] =&str_contact_col; query_vals[contact_col].type = DB_STR; query_vals[contact_col].nul = 0; @@ -1471,34 +1471,19 @@ void update_db_subs(db_con_t *db,db_func_t dbf, shtable_t hash_table, update_vals[u_version_col].nul = 0; n_update_cols++; - if(db== NULL) - { + if (db==NULL){ LM_ERR("null database connection\n"); return; } - LM_DBG("delete expired\n"); - update_vals[0].val.int_val= (int)time(NULL); - update_ops[0]= OP_LT; - CON_PS_REFERENCE(db) = &my_ps_delete; - if(dbf.use_table(db, &active_watchers_table) < 0) - { - LM_ERR("deleting expired information from database\n"); - } - - if(dbf.delete(db, update_cols, update_ops, update_vals, 1) < 0) - { - LM_ERR("deleting expired information from database\n"); - } - - for(i=0; inext; - + while(s) { printf_subs(s); @@ -1555,7 +1540,7 @@ void update_db_subs(db_con_t *db,db_func_t dbf, shtable_t hash_table, { LM_ERR("updating in database\n"); if(!no_lock) - lock_release(&hash_table[i].lock); + lock_release(&hash_table[i].lock); return ; } break; @@ -1610,8 +1595,24 @@ void update_db_subs(db_con_t *db,db_func_t dbf, shtable_t hash_table, if(!no_lock) lock_release(&hash_table[i].lock); } + + /* now that all records were updated, delete whatever + was still left as expired */ + LM_DBG("delete expired\n"); + update_vals[0].val.int_val = (int)time(NULL); + update_ops[0] = OP_LT; + CON_PS_REFERENCE(db) = &my_ps_delete; + if (dbf.use_table(db, &active_watchers_table) < 0) { + LM_ERR("deleting expired information from database\n"); + } else { + if (dbf.delete(db, update_cols, update_ops, update_vals, 1) < 0) + LM_ERR("deleting expired information from database\n"); + } + + return; } + int insert_subs_db(subs_t* s) { static db_ps_t my_ps = NULL; @@ -1624,7 +1625,7 @@ int insert_subs_db(subs_t* s) query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= s->pres_uri; n_query_cols++; - + query_cols[n_query_cols] =&str_callid_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; @@ -1636,7 +1637,7 @@ int insert_subs_db(subs_t* s) query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= s->to_tag; n_query_cols++; - + query_cols[n_query_cols] =&str_from_tag_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; @@ -1654,7 +1655,7 @@ int insert_subs_db(subs_t* s) query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = s->to_domain; n_query_cols++; - + query_cols[n_query_cols] =&str_watcher_username_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; @@ -1666,12 +1667,12 @@ int insert_subs_db(subs_t* s) query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = s->from_domain; n_query_cols++; - + query_cols[n_query_cols] =&str_event_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = s->event->name; - n_query_cols++; + n_query_cols++; query_cols[n_query_cols] =&str_event_id_col; query_vals[n_query_cols].type = DB_STR; @@ -1714,7 +1715,7 @@ int insert_subs_db(subs_t* s) query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = s->record_route; n_query_cols++; - + query_cols[n_query_cols] =&str_contact_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; @@ -1762,13 +1763,13 @@ int insert_subs_db(subs_t* s) int restore_db_subs(void) { - db_key_t result_cols[22]; + db_key_t result_cols[22]; db_res_t *result= NULL; - db_row_t *rows = NULL; + db_row_t *rows = NULL; db_val_t *row_vals= NULL; int i; int n_result_cols= 0; - int pres_uri_col, expires_col, from_user_col, from_domain_col,to_user_col; + int pres_uri_col, expires_col, from_user_col, from_domain_col,to_user_col; int callid_col,totag_col,fromtag_col,to_domain_col,sockinfo_col,reason_col; int event_col,contact_col,record_route_col, event_id_col, status_col; int remote_cseq_col, local_cseq_col, local_contact_col, version_col; @@ -1803,7 +1804,7 @@ int restore_db_subs(void) result_cols[version_col= n_result_cols++] =&str_version_col; result_cols[status_col= n_result_cols++] =&str_status_col; result_cols[reason_col= n_result_cols++] =&str_reason_col; - + if(!pa_db) { LM_ERR("null database connection\n"); @@ -1816,10 +1817,10 @@ int restore_db_subs(void) return -1; } /* select the whole tabel and all the columns */ - if (DB_CAPABILITY(pa_dbf, DB_CAP_FETCH)) + if (DB_CAPABILITY(pa_dbf, DB_CAP_FETCH)) { if(pa_dbf.query(pa_db,0,0,0,result_cols, 0, - n_result_cols, 0, 0) < 0) + n_result_cols, 0, 0) < 0) { LM_ERR("Error while querying (fetch) database\n"); return -1; @@ -1832,7 +1833,7 @@ int restore_db_subs(void) LM_ERR("fetching rows failed\n"); goto error; } - } else + } else { if (pa_dbf.query (pa_db, 0, 0, 0,result_cols,0, n_result_cols, 0, &result) < 0) @@ -1856,13 +1857,13 @@ int restore_db_subs(void) memset(&s, 0, sizeof(subs_t)); expires= row_vals[expires_col].val.int_val; - + if(expires< (int)time(NULL)) continue; - + s.pres_uri.s= (char*)row_vals[pres_uri_col].val.string_val; s.pres_uri.len= strlen(s.pres_uri.s); - + s.to_user.s=(char*)row_vals[to_user_col].val.string_val; s.to_user.len= strlen(s.to_user.s); @@ -1871,7 +1872,7 @@ int restore_db_subs(void) s.from_user.s=(char*)row_vals[from_user_col].val.string_val; s.from_user.len= strlen(s.from_user.s); - + s.from_domain.s=(char*)row_vals[from_domain_col].val.string_val; s.from_domain.len= strlen(s.from_domain.s); @@ -1886,13 +1887,13 @@ int restore_db_subs(void) ev_sname.s= (char*)row_vals[event_col].val.string_val; ev_sname.len= strlen(ev_sname.s); - + event= contains_event(&ev_sname, &parsed_event); if(event== NULL) { LM_DBG("insert a new event structure in the list waiting" " to be filled in\n"); - + /*insert a new event structure in the list waiting to be filled in*/ event= (pres_ev_t*)shm_malloc(sizeof(pres_ev_t)); if(event== NULL) @@ -1909,7 +1910,7 @@ int restore_db_subs(void) } memcpy(event->name.s,ev_sname.s, ev_sname.len); event->name.len= ev_sname.len; - + event->evp= shm_copy_event(&parsed_event); if(event->evp== NULL) { @@ -1920,7 +1921,7 @@ int restore_db_subs(void) event->next= EvList->events; EvList->events= event; } - + free_event_params(parsed_event.params, PKG_MEM_TYPE); s.event= event; @@ -1932,7 +1933,7 @@ int restore_db_subs(void) s.remote_cseq= row_vals[remote_cseq_col].val.int_val; s.local_cseq= row_vals[local_cseq_col].val.int_val; s.version= row_vals[version_col].val.int_val; - + s.expires= expires- (int)time(NULL); s.status = row_vals[status_col].val.int_val; @@ -1956,11 +1957,11 @@ int restore_db_subs(void) s.local_contact.s=(char*)row_vals[local_contact_col].val.string_val; s.local_contact.len= strlen(s.local_contact.s); - + s.record_route.s=(char*)row_vals[record_route_col].val.string_val; if(s.record_route.s) s.record_route.len= strlen(s.record_route.s); - + sockinfo_str.s = (char*)row_vals[sockinfo_col].val.string_val; if (sockinfo_str.s) { @@ -2016,12 +2017,12 @@ int restore_db_subs(void) return -1; } -int refresh_watcher(str* pres_uri, str* watcher_uri, str* event, +int refresh_watcher(str* pres_uri, str* watcher_uri, str* event, int status, str* reason) { unsigned int hash_code; subs_t* s, *s_copy; - pres_ev_t* ev; + pres_ev_t* ev; struct sip_uri uri; str user, domain; /* refresh status in subs_htable and send notify */ @@ -2052,13 +2053,13 @@ int refresh_watcher(str* pres_uri, str* watcher_uri, str* event, if(s->event== ev && s->pres_uri.len== pres_uri->len && strncmp(s->pres_uri.s, pres_uri->s, pres_uri->len)== 0 && s->from_user.len==user.len && strncmp(s->from_user.s,user.s, user.len)==0 && - s->from_domain.len== domain.len && + s->from_domain.len== domain.len && strncmp(s->from_domain.s, domain.s, domain.len)== 0) { s->status= status; if(reason) s->reason= *reason; - + s_copy= mem_copy_subs(s, PKG_MEM_TYPE); if(s_copy== NULL) { @@ -2067,7 +2068,7 @@ int refresh_watcher(str* pres_uri, str* watcher_uri, str* event, return -1; } lock_release(&subs_htable[hash_code].lock); - if(notify(s_copy, NULL, NULL, 0, NULL)< 0) + if(notify(s_copy, NULL, NULL, 0, NULL, 0)< 0) { LM_ERR("in notify function\n"); pkg_free(s_copy); @@ -2089,7 +2090,7 @@ int get_db_subs_auth(subs_t* subs, int* found) static db_ps_t my_ps = NULL; db_key_t db_keys[5]; db_val_t db_vals[5]; - int n_query_cols= 0; + int n_query_cols= 0; db_key_t result_cols[3]; db_res_t *result = NULL; db_row_t *row ; @@ -2112,7 +2113,7 @@ int get_db_subs_auth(subs_t* subs, int* found) db_vals[n_query_cols].nul = 0; db_vals[n_query_cols].val.str_val = subs->from_domain; n_query_cols++; - + db_keys[n_query_cols] =&str_event_col; db_vals[n_query_cols].type = DB_STR; db_vals[n_query_cols].nul = 0; @@ -2121,7 +2122,7 @@ int get_db_subs_auth(subs_t* subs, int* found) result_cols[0] = &str_status_col; result_cols[1] = &str_reason_col; - + if(pa_dbf.use_table(pa_db, &watchers_table)< 0) { LM_ERR("in use table\n"); @@ -2139,7 +2140,7 @@ int get_db_subs_auth(subs_t* subs, int* found) } if(result== NULL) return -1; - + if(result->n<= 0) { *found= 0; @@ -2165,14 +2166,16 @@ int get_db_subs_auth(subs_t* subs, int* found) { pa_dbf.free_result(pa_db, result); ERR_MEM(PKG_MEM_STR); - } + } memcpy(subs->reason.s, row_vals[1].val.string_val, subs->reason.len); } } - + pa_dbf.free_result(pa_db, result); return 0; error: + if (result) + pa_dbf.free_result(pa_db, result); return -1; } @@ -2181,7 +2184,7 @@ int insert_db_subs_auth(subs_t* subs) static db_ps_t my_ps = NULL; db_key_t db_keys[10]; db_val_t db_vals[10]; - int n_query_cols= 0; + int n_query_cols= 0; db_keys[n_query_cols] =&str_presentity_uri_col; db_vals[n_query_cols].type = DB_STR; @@ -2200,7 +2203,7 @@ int insert_db_subs_auth(subs_t* subs) db_vals[n_query_cols].nul = 0; db_vals[n_query_cols].val.str_val = subs->from_domain; n_query_cols++; - + db_keys[n_query_cols] =&str_event_col; db_vals[n_query_cols].type = DB_STR; db_vals[n_query_cols].nul = 0; @@ -2212,7 +2215,7 @@ int insert_db_subs_auth(subs_t* subs) db_vals[n_query_cols].nul = 0; db_vals[n_query_cols].val.int_val = subs->status; n_query_cols++; - + db_keys[n_query_cols] = &str_inserted_time_col; db_vals[n_query_cols].type = DB_INT; db_vals[n_query_cols].nul = 0; @@ -2233,8 +2236,8 @@ int insert_db_subs_auth(subs_t* subs) db_vals[n_query_cols].val.str_val.len = 0; } n_query_cols++; - - if (pa_dbf.use_table(pa_db, &watchers_table) < 0) + + if (pa_dbf.use_table(pa_db, &watchers_table) < 0) { LM_ERR("in use_table\n"); return -1; diff --git a/modules/presence/subscribe.h b/modules/presence/subscribe.h index b969f569dd4..c77cbb355cf 100644 --- a/modules/presence/subscribe.h +++ b/modules/presence/subscribe.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -56,8 +56,8 @@ struct subscription str from_tag; str callid; struct socket_info* sockinfo; - unsigned int remote_cseq; - unsigned int local_cseq; + unsigned int remote_cseq; + unsigned int local_cseq; str contact; str local_contact; str record_route; @@ -85,7 +85,7 @@ void timer_db_update(unsigned int ticks,void *param); int update_subs_db(subs_t* subs, int type); -int refresh_watcher(str* pres_uri, str* watcher_uri, str* event, +int refresh_watcher(str* pres_uri, str* watcher_uri, str* event, int status, str* reason); typedef int (*refresh_watcher_t)(str*, str* , str* ,int , str* ); @@ -105,4 +105,6 @@ int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int max_expire, typedef int (*extract_sdialog_info_t)(subs_t* subs, struct sip_msg* msg, int max_expire, int* to_tag_gen, str local_address); +int update_subscription(struct sip_msg* msg, subs_t* subs, int init_req); + #endif diff --git a/modules/presence/utils_func.c b/modules/presence/utils_func.c index 846a22e879b..26a5a65a640 100644 --- a/modules/presence/utils_func.c +++ b/modules/presence/utils_func.c @@ -81,16 +81,16 @@ void to64frombits(unsigned char *out, const unsigned char *in, int inlen) *out++ = '='; } *out = '\0'; - + } int a_to_i (char *s,int len) { int n = 0, i= 0; - - while( iname.s, ev->name.len ); hdr_append.len+= ev->name.len ; ev= ev->next; @@ -126,7 +126,7 @@ int send_error_reply(struct sip_msg* msg, int reply_code, str reply_str) memcpy(hdr_append.s+ hdr_append.len, CRLF, CRLF_LEN); hdr_append.len+= CRLF_LEN; hdr_append.s[hdr_append.len]= '\0'; - + if (add_lump_rpl( msg, hdr_append.s, hdr_append.len, LUMP_RPL_HDR)==0 ) { LM_ERR("unable to add lump_rl\n"); diff --git a/modules/presence/utils_func.h b/modules/presence/utils_func.h index 6f0c38e6723..2493f4d4256 100644 --- a/modules/presence/utils_func.h +++ b/modules/presence/utils_func.h @@ -67,7 +67,7 @@ static inline int uandd_to_uri(str user, str domain, str *out) memcpy(out->s + out->len, domain.s, domain.len); out->len += domain.len; out->s[out->len] = '\0'; - + return 0; } diff --git a/modules/presence_callinfo/README b/modules/presence_callinfo/README index 9bad2c5fb2a..20321750bb6 100644 --- a/modules/presence_callinfo/README +++ b/modules/presence_callinfo/README @@ -4,16 +4,26 @@ Ovidiu Sas +Bogdan-Andrei Iancu + + + Edited by Ovidiu Sas - Copyright © 2010 VoIP Embedded, Inc. +Edited by + +Bogdan-Andrei Iancu + + + + Copyright © 2010-2013 VoIP Embedded, Inc. , + www.opensips-solutions.com Revision History - Revision $Revision: 7754 $ $Date: 2011-02-23 20:57:21 +0200 - (Wed, 23 Feb 2011) $ + Revision $Revision: 7754 $ $Date$ __________________________________________________________ Table of Contents @@ -21,33 +31,88 @@ Ovidiu Sas 1. Admin Guide 1.1. Overview - 1.2. Dependencies + 1.2. Usage modes - 1.2.1. OpenSIPS Modules - 1.2.2. External Libraries or Applications + 1.2.1. External publishing + 1.2.2. Internal publishing - 1.3. Exported Parameters + 1.3. Dependencies - 1.3.1. call_info_timeout_notification (int) - 1.3.2. line_seize_timeout_notification (int) + 1.3.1. OpenSIPS Modules + 1.3.2. External Libraries or Applications - 1.4. Exported Functions + 1.4. Exported Parameters + + 1.4.1. call_info_timeout_notification (int) + 1.4.2. line_seize_timeout_notification (int) + 1.4.3. disable_dialog_support_for_sca (int) + 1.4.4. line_hash_size (int) + + 1.5. Exported Functions + + 1.5.1. sca_set_calling_line([line]) + 1.5.2. sca_set_called_line([line]) List of Examples 1.1. Set call_info_timeout_notification parameter 1.2. Set line_seize_timeout_notification parameter + 1.3. Set disable_dialog_support_for_sca parameter + 1.4. Set line_hash_size parameter + 1.5. sca_set_calling_line() usage + 1.6. sca_set_called_line() usage Chapter 1. Admin Guide 1.1. Overview + This module provides OpenSIPS support for shared call + appearances (SCA) as defined by BroadWorks SIP Access Side + Extensions Interface specifications. The SCA mechanism is a + fundamental building block for a variety of enhanced telephony + services. Features like attendant console, line extensions, and + key system emulation cannot be delivered without some mechanism + for sharing call appearances across access devices. Although + SIP (RFC 3261) by itself offers no inherent semantics for + supporting SCA features, when coupled with an appropriate + instantiation of the “SIP Specific Event Notification” + framework (RFC 3265), these services can be deployed quite + easily in a distributed network. + + A shared line is an address of record managed by central + controlling element, such as an application server. The + application server allows multiple endpoints to register + locations against the address of record. The application server + is responsible for policing who can register and who cannot + register against the shared line. + The module enables the handling of "call-info" and "line-seize" events inside the presence module. It is used with the general event handling module: presence and it constructs and adds - "Call-Info" headers to notification events. To send "call-info" - notification to watchers, a third-party application must - publish "call-info" events to the presence server. + "Call-Info" headers to notification events. + +1.2. Usage modes + + The module can be used in two ways (depending on who is doing + the publishing of the "call-info" data: + * external publishing - the "call-info" data is received from + a third party via SIP PUBLISH requests. In this mode, the + modules simply distributes the SCA info, it is not + producing any of it - a third-party application must + publish "call-info" events to the presence server. + * internal publishing - the "call-info" data is internally + generated by the module, based on the information received + from the dialog module - what calls are using what + line/index, what is the state of the call, etc. There is no + SIP PUBLISH in this case and there is no need for a + third-party - the module is self-sufficient and stand alone + as functionality. + + The used mode can be controlled via the module parameter + "disable_dialog_support_for_sca" - see below in the parameter's + section. + +1.2.1. External publishing The module does not currently implement any authorization rules. It assumes that publish requests are only issued by a @@ -56,9 +121,6 @@ Chapter 1. Admin Guide can thus be easily done by OpenSIPS configuration file before calling handle_publish() and handle_subscribe() functions. - The module implements a simple check for the presence of - Call-Info headers in received PUBLISH requests. - To get better understanding on how the module works please take a look at the follwing figure: @@ -106,20 +168,49 @@ alice@example presence bob@example watcher@example checks for active watchers of the presentity. The active watcher is notified via a NOTIFY SIP request. -1.2. Dependencies +1.2.2. Internal publishing -1.2.1. OpenSIPS Modules + In this mode, the module requires the "dialog" module to be + loaded into OpenSIPS. All the publishing will be automatically + done (the modules will exchange data directly via C API). + + From presence perspective, the OpenSIPS script must be + configured to handle the SUBSCRIBE requests only (there is no + need for PUBLISH handling as there is no SIP publishing in this + mode). So be sure to use the "handle_subscribe()" function + (from presence module) in the script. + + To trigger the internal publishing (from the dialog module) for + a certain call, use the "sca_set_calling_line()" or + "sca_set_called_line()" functions from the script when handling + a new call. These functions will do all the work (creating + dialog, setting the internal publishing, etc) - you just need + to use them and eventually specify the name of the line (if + other then the one from the SIP INVITE) - see the below + documentation. + + LIMITATIONS : in this mode, the module does not really check if + the line exists or not (like defined) - it blindly trust the + traffic; also there is no check on how many indexes are for + each line. Such information (lines and indexes) are not + provisioned into the module, but the module will dynamically + accept and handle any line and index based on the SIP traffic. + +1.3. Dependencies + +1.3.1. OpenSIPS Modules The following modules must be loaded before this module: * presence. + * dialog. -1.2.2. External Libraries or Applications +1.3.2. External Libraries or Applications None. -1.3. Exported Parameters +1.4. Exported Parameters -1.3.1. call_info_timeout_notification (int) +1.4.1. call_info_timeout_notification (int) Enables or disables call_info event timeout notifications. @@ -130,7 +221,7 @@ alice@example presence bob@example watcher@example modparam("presence_callinfo", "call_info_timeout_notification", 0) ... -1.3.2. line_seize_timeout_notification (int) +1.4.2. line_seize_timeout_notification (int) Enables or disables line_seize event timeout notifications. @@ -141,6 +232,74 @@ modparam("presence_callinfo", "call_info_timeout_notification", 0) modparam("presence_callinfo", "line_seize_timeout_notification", 1) ... -1.4. Exported Functions +1.4.3. disable_dialog_support_for_sca (int) + + Disables the internal publishing of the "call-info" events + (generated by the dialog module). The publishing is expected to + be done via SIP PUBLISH from a third-party. See the wroking + mode described in the beginning of this document. + + Default value is “0” (not disabled). + + Example 1.3. Set disable_dialog_support_for_sca parameter +... +modparam("presence_callinfo", "disable_dialog_support_for_sca", 1) +... + +1.4.4. line_hash_size (int) + + Allows you to controll the size of the internal hash table used + for storing the information about the lines and indexes (in the + internal publishing mode). + + The value must be a power of 2. You may consider increasing the + value if using a large set of lines (>1000). + + Default value is “64”. + + Example 1.4. Set line_hash_size parameter +... +modparam("presence_callinfo", "line_hash_size", 128) +... + +1.5. Exported Functions + +1.5.1. sca_set_calling_line([line]) + + The function (to be used only in internal publishing mode) is + setting for the current new call (initinal INVITE) the outbound + line - the line used for calling out. + + If no parameter is provided, the name of the line is taken from + the SIP FROM header of the INVITE. You can override that by + providing the name of the line a parameter - be careful as the + value must be a SIP URI ! Variables are accepted. - None to be used in configuration file. + This function can be used from REQUEST_ROUTE. + + Example 1.5. sca_set_calling_line() usage +... + if (is_method("INVITE") and !has_totag()) { + sca_set_calling_line(); + } +... + +1.5.2. sca_set_called_line([line]) + + The function (to be used only in internal publishing mode) is + setting for the current new call (initinal INVITE) the inbound + line - the line the call was received on. + + If no parameter is provided, the name of the line is taken from + the SIP RURI of the INVITE. You can override that by providing + the name of the line a parameter - be careful as the value must + be a SIP URI ! Variables are accepted. + + This function can be used from REQUEST_ROUTE. + + Example 1.6. sca_set_called_line() usage +... + if (is_method("INVITE") and !has_totag()) { + sca_set_called_line(); + } +... diff --git a/modules/presence_callinfo/add_events.c b/modules/presence_callinfo/add_events.c index bdfa0f21c17..8690343c0b8 100644 --- a/modules/presence_callinfo/add_events.c +++ b/modules/presence_callinfo/add_events.c @@ -2,6 +2,7 @@ * Add "call-info" event to presence module * * Copyright (C) 2010 Ovidiu Sas + * Copyright (C) 2013 OpenSIPS Solutions * * This file is part of opensips, a free SIP server. * @@ -22,15 +23,20 @@ * History: * -------- * 2010-03-11 initial version (osas) + * 2010-07-13 added support for SCA Broadsoft with dialog module (bogdan) */ #include #include #include +#include "../../timer.h" +#include "../../ut.h" #include "../../parser/parse_call_info.h" #include "../presence/event_list.h" #include "presence_callinfo.h" +#include "sca_hash.h" +#include "add_events.h" extern int call_info_timeout_notification; @@ -42,72 +48,367 @@ static str extra_hdrs[] = { {NULL,0}, }; -static str dummy_header=str_init("Call-Info: ;appearance-index=*;appearance-state=idle\r\n"); +static pres_ev_t *callinfo_event = NULL; +static pres_ev_t *seize_event = NULL; + +static str dummy_ci_hdr1 = str_init("Call-Info: <"); +static str dummy_ci_hdr2 = str_init(">;appearance-index=*;appearance-state=idle\r\n"); + + /* * event specific publish handling - check if body format is ok */ -int callinfo_publ_handl(struct sip_msg* msg, int* sent_reply) +static int callinfo_hdr_checker(struct sip_msg* msg, int* sent_reply) { - if (parse_headers(msg,HDR_EOH_F, 0) == -1) { - LM_ERR("parsing headers\n"); - return -1; - } - - if (!msg->call_info) - { - LM_ERR("No 'Call-Info' header\n"); - return -1; - } - if (0 != parse_call_info_header(msg)) { - LM_ERR("Unable to parse Call-Info\n"); - return -1; - } - - return 1; -} + if (parse_headers(msg,HDR_EOH_F, 0) == -1) { + LM_ERR("parsing headers\n"); + return -1; + } -/* - * event specific publish handling - check if body format is ok - */ -int lineseize_publ_handl(struct sip_msg* msg, int* sent_reply) -{ - if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { - LM_ERR("parsing headers\n"); - return -1; - } - - if (!msg->call_info) - { - LM_ERR("No 'Call-Info' header\n"); - return -1; - } - - return 1; + if (!msg->call_info) { + LM_ERR("No 'Call-Info' header\n"); + return -1; + } + if (0 != parse_call_info_header(msg)) { + LM_ERR("Unable to parse Call-Info\n"); + return -1; + } + + return 1; } + /* * event specific extra headers builder - for empty notifications */ -str* build_callinfo_dumy_header(str* pres_uri, str* extra_hdrs) +str* build_callinfo_dummy_header(str* pres_uri, str* extra_hdrs) { if (extra_hdrs->s == NULL) { - extra_hdrs->s = (char*)pkg_malloc(dummy_header.len); + extra_hdrs->s = (char*)pkg_malloc( dummy_ci_hdr1.len + + pres_uri->len + dummy_ci_hdr2.len); if (extra_hdrs->s == NULL) { LM_ERR("oom: no dummy header\n"); return NULL; } - memcpy(extra_hdrs->s, dummy_header.s, dummy_header.len); - extra_hdrs->len = dummy_header.len; + memcpy(extra_hdrs->s, dummy_ci_hdr1.s, dummy_ci_hdr1.len); + extra_hdrs->len = dummy_ci_hdr1.len; + memcpy(extra_hdrs->s+extra_hdrs->len, pres_uri->s, pres_uri->len); + extra_hdrs->len += pres_uri->len; + memcpy(extra_hdrs->s+extra_hdrs->len, dummy_ci_hdr2.s, dummy_ci_hdr2.len); + extra_hdrs->len += dummy_ci_hdr2.len; + } + return NULL; +} + + + +/* assumes the Call-INFO hdr is parsed ! */ +unsigned int get_appearance_index(struct sip_msg *msg) +{ + struct to_param *top; + unsigned int idx; + + top = get_call_info(msg)->call_info_body.param_lst; + for ( ; top ; top=top->next) { + if ( (top->name.len==CI_hdr_AI_param_len) && + (memcmp(CI_hdr_AI_param_s,top->name.s,CI_hdr_AI_param_len)==0) ) { + /* found */ + if ( str2int( &top->value, &idx)<0 ) { + LM_ERR("appearance-index <%.*s> param is not numerical\n", + top->value.len, top->value.s); + return 0; + } + return idx; + } + } + + LM_ERR("Call-INFO hdr <%.*s> does not contain 'appearance-index' parameter\n", + msg->call_info->body.len,msg->call_info->body.s); + return 0; +} + + +/* + * Line must be locked, returned unlocked ! + */ +int terminate_line_sieze(struct sca_line *sca) +{ + /* do we have a valid seize on the line ? */ + if (sca->seize_state==0 || sca->seize_expiresseize_state = 0; + sca->seize_expires = 0; + + unlock_sca_line(sca); + + return pres.terminate_watchers( &sca->line, seize_event); +} + + +/* Function to be called under lock - extracts and saved in local buffers + * the sca info that is needed for by "do_callinfo_publish" (as we need to + * call this function without locking). + * You need to take care and free the "user" string (only that one) !!! + */ +int extract_publish_data_from_line(struct sca_line *sca, str *user, str *host, str *etag, int *new) +{ + char *buf; + + buf = (char*)pkg_malloc( sca->user.len + sca->domain.len + MD5_LEN ); + if (buf==NULL) { + LM_ERR("no more pkg mem\n"); + return -1; + } + + user->s = buf ; + user->len = sca->user.len; + memcpy( user->s, sca->user.s, user->len); + buf += user->len; + + host->s = buf ; + host->len = sca->domain.len; + memcpy( host->s, sca->domain.s, host->len); + buf += host->len; + + etag->s = buf; + etag->len = MD5_LEN; + if (sca->etag.len==0) { + MD5StringArray( sca->etag.s, &sca->line, 1); + sca->etag.len = MD5_LEN; + *new = 1; + } else { + *new = 0; + } + memcpy( etag->s, sca->etag.s, etag->len); + + return 0; +} + + +/* send the pusblish for the line - expects to get the line locked, + * returnes the line unlocked */ +int do_callinfo_publish(struct sca_line *sca) +{ + str user, host, etag, ci_hdr; + presentity_t presentity; + int new_etag; + + /* generate the new call-info line */ + ci_hdr.s = sca_print_line_status( sca, &ci_hdr.len ); + if (ci_hdr.s==NULL || + extract_publish_data_from_line(sca, &user, &host, &etag, &new_etag)<0){ + unlock_sca_line(sca); + LM_ERR("failed to extract Call-INFO data for publishing\n"); + } else { + unlock_sca_line(sca); + /* do publish for callinfo */ + memset(&presentity, 0, sizeof(presentity_t)); + presentity.domain = host; + presentity.user = user; + presentity.etag = etag; + presentity.event = callinfo_event; + presentity.expires = callinfo_event->default_expires; + presentity.received_time= (int)time(NULL); + presentity.extra_hdrs = &ci_hdr; + presentity.etag_new = new_etag; + if ( pres.update_presentity( &presentity )<0 ) + LM_ERR("failed to update presentity\n"); + /* release memory from "extract_publish_data_from_line" */ + pkg_free(user.s); + } + + /* release memory from "sca_print_line_status" */ + if (ci_hdr.s) pkg_free(ci_hdr.s); + + return 0; +} + + + +/* + * event specific SUBSCRIBE handling - check if body format is ok + */ +int lineseize_subs_handl(struct sip_msg* msg, struct subscription *subs, int *reply_code, str *reply_reason) +{ + str *line; + struct sca_line *sca; + unsigned int idx; + int is_initial; + int new_state; + + /* search for the Call-INFO hdr */ + if ( parse_call_info_header( msg )!=0 ) { + LM_ERR("missing or bogus Call-Info header in SUBSCRIBE lineseize\n"); + *reply_code = 400; + reply_reason->s = "Bad request"; + reply_reason->len = sizeof("Bad request")-1; + return -1; + } + is_initial = (subs->to_tag.len==0)?1:0; + + idx = get_appearance_index(msg); + if (idx==0) { + LM_ERR("failed to extract index from Call-Info hdr\n"); + *reply_code = 400; + reply_reason->s = "Bad request"; + reply_reason->len = sizeof("Bad request")-1; + return -1; + } + + /* get the name of the line -> the subscribed presentity */ + line = &subs->pres_uri; + + /* search for the line in the SCA hash */ + LM_DBG("searching for SCA <%.*s>, initial=%d\n", + line->len,line->s,is_initial); + if (subs->expires==0) { + /* if un-subscribe, search without auto create */ + sca = get_sca_line(line, 0); + } else { + /* search with auto create (only if initial) */ + sca = get_sca_line(line, is_initial ); + } + + if (sca==NULL) { + LM_DBG("SCA not found, expires=%d\n",subs->expires); + if (subs->expires==0) { + /* an unsubscribe from an inexisting list, + let presence deal with it, we do not really care */ + return 0; + } else { + /* for sure this is an internal error, default reply of + presence dore */ + return -1; + } } + + LM_DBG("SCA found (%p), seizing (%d,%d), subs expires %d\n", + sca, sca->seize_state,sca->seize_expires, subs->expires); + + new_state = 0; + + /* SCA found, careful now, it is locked !! */ + if (!is_initial) { + + /* sequential FIXME - some double check here? */ + if (subs->expires==0) { + /* terminate the subscription */ + LM_DBG("seizing terminated by un-subscribe\n"); + sca->seize_state = 0; + sca->seize_expires = 0; + new_state = SCA_STATE_IDLE; + } else { + LM_DBG("seizing changed by re-subscribe\n"); + sca->seize_expires = get_ticks() + subs->expires; + } + + } else { + + /* new SUBSCRIBE */ + if (sca->seize_state!=0) { + /* already in seizing from a different subscrine */ + if (sca->seize_expires < get_ticks()) { + /* old seizing still valid -> reject it */ + *reply_code = 480; + reply_reason->s = "Temporarily Unavailable"; + reply_reason->len = sizeof("Temporarily Unavailable")-1; + unlock_sca_line(sca); + return -1; + } + } + /* FIXME - check the seized idx is not already in a call */ + /* do the seizing */ + sca->seize_state = idx; + sca->seize_expires = get_ticks() + subs->expires; + + new_state = SCA_STATE_SEIZED; + + } + + + if (!new_state) { + unlock_sca_line(sca); + return 0; + } + + /* push new state for the index and do the publishing */ + /* STILL LOCKED HERE !! */ + + /* everything ok, change the state of the line and notify */ + set_sca_index_state( sca, idx, new_state); + + /* do publish for callinfo */ + do_callinfo_publish( sca ); + + return 0; +} + + +/* + * event specific extra headers builder - for empty notifications + */ +str* build_lineseize_notify_hdrs(str* pres_uri, str* extra_hdrs) +{ + struct sca_line *sca; + unsigned int idx; + int l; + char *p; + char *q; + + if (extra_hdrs->s!= NULL) + return NULL; + + /* search for the SCA */ + sca = get_sca_line(pres_uri, 0); + if (sca==NULL) { + LM_CRIT("BUG? notify to line-seize but SCA (%.*s) not found\n", + pres_uri->len, pres_uri->s); + return NULL; + } + /* watch it!!!! SCA is locked now */ + idx = sca->seize_state; + unlock_sca_line(sca); + + if (idx==0) + return NULL; + + /* build the header */ + extra_hdrs->s = (char*)pkg_malloc( CI_hdr_name_len + 1 /*<*/ + + pres_uri->len + 2 /*>;*/ + CI_hdr_AI_param_len + 1 /*=*/ + + 5 /*idx*/ + 2 /*CRLF*/); + if (extra_hdrs->s == NULL) { + LM_ERR("no more pkg mem for the Call-Info hdr in Notify\n"); + return NULL; + } + p = extra_hdrs->s; + memcpy( p, CI_hdr_name_s "<", CI_hdr_name_len+1); + p += CI_hdr_name_len + 1; + memcpy( p, pres_uri->s, pres_uri->len); + p += pres_uri->len; + memcpy( p, ">;" CI_hdr_AI_param_s "=", 3+CI_hdr_AI_param_len); + p += 3 + CI_hdr_AI_param_len; + q = int2str( (unsigned long)idx, &l ); + LM_DBG("index is <%.*s>\n",l,q); + memcpy( p , q, l); + p += l; + memcpy( p, CRLF, CRLF_LEN); + p += CRLF_LEN; + + extra_hdrs->len = p - extra_hdrs->s; + LM_DBG("hdr is <%.*s>\n",extra_hdrs->len,extra_hdrs->s); + return NULL; } + int callinfo_add_events(void) { pres_ev_t event; + event_t ev; /* constructing call-info event */ memset(&event, 0, sizeof(pres_ev_t)); @@ -116,20 +417,31 @@ int callinfo_add_events(void) event.extra_hdrs = extra_hdrs; + event.etag_not_new = 1; + event.default_expires= 3600; event.mandatory_timeout_notification = call_info_timeout_notification; event.type = PUBL_TYPE; - event.evs_publ_handl = callinfo_publ_handl; + event.evs_publ_handl = callinfo_hdr_checker; /* register the dummy Call-Info header builder */ - event.build_empty_pres_info = build_callinfo_dumy_header; + event.build_empty_pres_info = build_callinfo_dummy_header; - - if (pres_add_event(&event) < 0) { + if (pres.add_event(&event) < 0) { LM_ERR("failed to add event \"call-info\"\n"); return -1; } + /* now search it back as we need the internal event structure */ + ev.parsed = EVENT_CALL_INFO; + ev.text = event.name; + callinfo_event = pres.search_event( &ev ); + if (callinfo_event==NULL) { + LM_CRIT("BUG: failed to get back the registered CALL INFO event!\n"); + return -1; + } + + /* constructing line-seize-info event */ memset(&event, 0, sizeof(pres_ev_t)); event.name.s = "line-seize"; @@ -138,13 +450,30 @@ int callinfo_add_events(void) event.default_expires= 15; event.mandatory_timeout_notification = line_seize_timeout_notification; event.type = PUBL_TYPE; - event.evs_publ_handl = lineseize_publ_handl; + if (no_dialog_support) { + /* with no dialog, just check the Call-Info hdrs */ + event.evs_publ_handl = callinfo_hdr_checker; + } else { + /* with dialog, handle the subscribes */ + event.evs_subs_handl = lineseize_subs_handl; + /* register the Call-Info builder for NOTIFIES */ + event.build_empty_pres_info = build_lineseize_notify_hdrs; + } - if (pres_add_event(&event) < 0) { + if (pres.add_event(&event) < 0) { LM_ERR("failed to add event \"line-seize\"\n"); return -1; } + /* now search it back as we need the internal event structure */ + ev.parsed = EVENT_LINE_SEIZE; + ev.text = event.name; + seize_event = pres.search_event( &ev ); + if (seize_event==NULL) { + LM_CRIT("BUG: failed to get back the registered CALL INFO event!\n"); + return -1; + } + return 0; } diff --git a/modules/presence_callinfo/add_events.h b/modules/presence_callinfo/add_events.h index ab305f4069c..6eb103fcc7b 100644 --- a/modules/presence_callinfo/add_events.h +++ b/modules/presence_callinfo/add_events.h @@ -2,6 +2,7 @@ * presence_callinfo module - add_event header file * * Copyright (C) 2010 Ovidiu Sas + * Copyright (C) 2013 OpenSIPS Solutions * * This file is part of opensips, a free SIP server. * @@ -15,18 +16,36 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2010-03-11 initial version (osas) + * 2010-07-13 added support for SCA Broadsoft with dialog module (bogdan) */ #ifndef _CALLINFO_ADD_EV_H_ #define _CALLINFO_ADD_EV_H_ +#include "../../parser/msg_parser.h" + +#define CI_hdr_name_s "Call-Info: " +#define CI_hdr_name_len (sizeof(CI_hdr_name_s)-1) +#define CI_hdr_AI_param_s "appearance-index" +#define CI_hdr_AI_param_len (sizeof(CI_hdr_AI_param_s)-1) +#define CI_hdr_AS_param_s "appearance-state" +#define CI_hdr_AS_param_len (sizeof(CI_hdr_AS_param_s)-1) + +#include "sca_hash.h" + int callinfo_add_events(); +unsigned int get_appearance_index(struct sip_msg *msg); + +int do_callinfo_publish(struct sca_line *sca); + +int terminate_line_sieze(struct sca_line *sca); + #endif diff --git a/modules/presence_callinfo/doc/presence_callinfo.xml b/modules/presence_callinfo/doc/presence_callinfo.xml index fd2a32d1bec..f7a4fbc145b 100644 --- a/modules/presence_callinfo/doc/presence_callinfo.xml +++ b/modules/presence_callinfo/doc/presence_callinfo.xml @@ -13,39 +13,50 @@ ]> - - Presence_CallInfo Module - &osipsname; - - - Ovidiu - Sas - osas@voipembedded.com - - - Ovidiu - Sas - osas@voipembedded.com - - - - 2010 - - VoIP Embedded, Inc. - - - - - $Revision: 7754 $ - $Date$ - - - - - - &admin; - &faq; - + + Presence_CallInfo Module + &osipsname; + + + Ovidiu + Sas + osas@voipembedded.com + + + Bogdan-Andrei + Iancu + bogdan@opensips.org + + + Ovidiu + Sas + osas@voipembedded.com + + + Bogdan-Andrei + Iancu + bogdan@opensips.org + + + + 2010-2013 + + VoIP Embedded, Inc. + + &osipssol; + + + + $Revision: 7754 $ + $Date$ + + + + + + &admin; + &faq; + diff --git a/modules/presence_callinfo/doc/presence_callinfo_admin.xml b/modules/presence_callinfo/doc/presence_callinfo_admin.xml index b58704f280e..30a65501771 100644 --- a/modules/presence_callinfo/doc/presence_callinfo_admin.xml +++ b/modules/presence_callinfo/doc/presence_callinfo_admin.xml @@ -6,31 +6,74 @@ &adminguide;
- Overview - - The module enables the handling of "call-info" and "line-seize" - events inside the presence module. - It is used with the general event handling module: presence and - it constructs and adds "Call-Info" headers to notification events. - To send "call-info" notification to watchers, a third-party - application must publish "call-info" events to the presence server. - - - The module does not currently implement any authorization - rules. It assumes that publish requests are only issued by - a third-party application and subscribe requests only by - subscriber to call-info and line-seize events. Authorization - can thus be easily done by &osips; configuration file before - calling handle_publish() and handle_subscribe() functions. - - - The module implements a simple check for the presence of - Call-Info headers in received PUBLISH requests. - - - To get better understanding on how the module works please take a - look at the follwing figure: - + Overview + + This module provides OpenSIPS support for shared call appearances (SCA) + as defined by BroadWorks SIP Access Side Extensions Interface specifications. + The SCA mechanism is a fundamental building block for a variety of enhanced + telephony services. Features like attendant console, line extensions, + and key system emulation cannot be delivered without some mechanism for + sharing call appearances across access devices. Although SIP (RFC 3261) + by itself offers no inherent semantics for supporting SCA features, when + coupled with an appropriate instantiation of the “SIP Specific Event Notification” + framework (RFC 3265), these services can be deployed quite easily in a + distributed network. + + + A shared line is an address of record managed by central + controlling element, such as an application server. The application server + allows multiple endpoints to register locations against the address of record. + The application server is responsible for policing who can register and who + cannot register against the shared line. + + + The module enables the handling of "call-info" and "line-seize" + events inside the presence module. It is used with the general event + handling module: presence and it constructs and adds "Call-Info" headers + to notification events. + +
+ +
+ Usage modes + + The module can be used in two ways (depending on who is doing the + publishing of the "call-info" data: + + + external publishing - the "call-info" data + is received from a third party via SIP PUBLISH requests. In this + mode, the modules simply distributes the SCA info, it is not + producing any of it - a third-party application must publish + "call-info" events to the presence server. + + internal publishing - the "call-info" data + is internally generated by the module, based on the information + received from the dialog module - what calls are using what + line/index, what is the state of the call, etc. There is no SIP + PUBLISH in this case and there is no need for a third-party - + the module is self-sufficient and stand alone as functionality. + + + The used mode can be controlled via the module parameter + "disable_dialog_support_for_sca" - see below in the parameter's + section. + + +
+ External publishing + + The module does not currently implement any authorization + rules. It assumes that publish requests are only issued by + a third-party application and subscribe requests only by + subscriber to call-info and line-seize events. Authorization + can thus be easily done by &osips; configuration file before + calling handle_publish() and handle_subscribe() functions. + + + To get better understanding on how the module works please take a + look at the follwing figure: + - - - - The watcher subscribes the "Event: dialog" of Bob. - - - Alice calls Bob. - - - The publisher is publishing the "alerting" state for Bob. - - - PUBLISH is received and handled by presence module. - Presence module updates the "presentity". - Presence module checks for active watchers of the presentity. - The active watcher is notified via a NOTIFY SIP request. - - - Bob answers the call. - - - The publisher is publishing the "active" state for Bob. - - - PUBLISH is received and handled by presence module. - Presence module updates the "presentity". - Presence module checks for active watchers of the presentity. - The active watcher is notified via a NOTIFY SIP request. - - - + + + + The watcher subscribes the "Event: dialog" of Bob. + + + Alice calls Bob. + + + The publisher is publishing the "alerting" state for Bob. + + + PUBLISH is received and handled by presence module. + Presence module updates the "presentity". + Presence module checks for active watchers of the presentity. + The active watcher is notified via a NOTIFY SIP request. + + + Bob answers the call. + + + The publisher is publishing the "active" state for Bob. + + + PUBLISH is received and handled by presence module. + Presence module updates the "presentity". + Presence module checks for active watchers of the presentity. + The active watcher is notified via a NOTIFY SIP request. + + + +
+ +
+ Internal publishing + + In this mode, the module requires the "dialog" module to be + loaded into OpenSIPS. All the publishing will be automatically + done (the modules will exchange data directly via C API). + + + From presence perspective, the OpenSIPS script must be configured + to handle the SUBSCRIBE requests only (there is no need for PUBLISH + handling as there is no SIP publishing in this mode). So be sure + to use the "handle_subscribe()" function (from presence module) in + the script. + + + To trigger the internal publishing (from the dialog module) for a + certain call, use the "sca_set_calling_line()" or + "sca_set_called_line()" functions from the script when handling a + new call. These functions will do all the work (creating dialog, + setting the internal publishing, etc) - you just need to use them + and eventually specify the name of the line (if other then the one + from the SIP INVITE) - see the below documentation. + + + LIMITATIONS : in this mode, the module does not really check if the + line exists or not (like defined) - it blindly trust the traffic; + also there is no check on how many indexes are for each line. Such + information (lines and indexes) are not provisioned into the module, + but the module will dynamically accept and handle any line and index + based on the SIP traffic. + +
- Dependencies -
- &osips; Modules - - The following modules must be loaded before this module: - - + Dependencies +
+ &osips; Modules + The following modules must be loaded before this module: + + + presence. - - + + + + + dialog. + + - -
+
+
-
- External Libraries or Applications - - None. - -
+
+ External Libraries or Applications + + None. + +
- -
- Exported Parameters +
- <varname>call_info_timeout_notification</varname> (int) - - Enables or disables call_info event timeout notifications. - - Default value is 1 (enabled). - - Set <varname>call_info_timeout_notification</varname> parameter - + Exported Parameters +
+ <varname>call_info_timeout_notification</varname> (int) + + Enables or disables call_info event timeout notifications. + + Default value is 1 (enabled). + + Set <varname>call_info_timeout_notification</varname> parameter + ... modparam("presence_callinfo", "call_info_timeout_notification", 0) ... - - -
-
- <varname>line_seize_timeout_notification</varname> (int) - - Enables or disables line_seize event timeout notifications. - - Default value is 0 (disabled). - - Set <varname>line_seize_timeout_notification</varname> parameter - + + +
+ +
+ <varname>line_seize_timeout_notification</varname> (int) + + Enables or disables line_seize event timeout notifications. + + Default value is 0 (disabled). + + Set <varname>line_seize_timeout_notification</varname> parameter + ... modparam("presence_callinfo", "line_seize_timeout_notification", 1) ... - - + + +
+ +
+ <varname>disable_dialog_support_for_sca</varname> (int) + + Disables the internal publishing of the "call-info" events (generated by the dialog module). + The publishing is expected to be done via SIP PUBLISH from a third-party. See + the wroking mode described in the beginning of this document. + + Default value is 0 (not disabled). + + Set <varname>disable_dialog_support_for_sca</varname> parameter + +... +modparam("presence_callinfo", "disable_dialog_support_for_sca", 1) +... + + +
+ +
+ <varname>line_hash_size</varname> (int) + + Allows you to controll the size of the internal hash table used for storing the + information about the lines and indexes (in the internal publishing mode). + + + The value must be a power of 2. You may consider increasing the value if using + a large set of lines (>1000). + + Default value is 64. + + Set <varname>line_hash_size</varname> parameter + +... +modparam("presence_callinfo", "line_hash_size", 128) +... + + +
+
-
-
- Exported Functions - - None to be used in configuration file. - +
+ Exported Functions + +
+ + <function moreinfo="none">sca_set_calling_line([line])</function> + + + The function (to be used only in internal publishing mode) is setting + for the current new call (initinal INVITE) the outbound line - the line + used for calling out. + + + If no parameter is provided, the name of the line is taken from the + SIP FROM header of the INVITE. You can override that by providing + the name of the line a parameter - be careful as the value must be + a SIP URI ! Variables are accepted. + + + This function can be used from REQUEST_ROUTE. + + + <function>sca_set_calling_line()</function> usage + +... + if (is_method("INVITE") and !has_totag()) { + sca_set_calling_line(); + } +... + + +
+ +
+ + <function moreinfo="none">sca_set_called_line([line])</function> + + + The function (to be used only in internal publishing mode) is setting + for the current new call (initinal INVITE) the inbound line - the line + the call was received on. + + + If no parameter is provided, the name of the line is taken from the + SIP RURI of the INVITE. You can override that by providing + the name of the line a parameter - be careful as the value must be + a SIP URI ! Variables are accepted. + + + This function can be used from REQUEST_ROUTE. + + + <function>sca_set_called_line()</function> usage + +... + if (is_method("INVITE") and !has_totag()) { + sca_set_called_line(); + } +... + + +
+
diff --git a/modules/presence_callinfo/presence_callinfo.c b/modules/presence_callinfo/presence_callinfo.c index 237da7602c1..2698130e903 100644 --- a/modules/presence_callinfo/presence_callinfo.c +++ b/modules/presence_callinfo/presence_callinfo.c @@ -2,6 +2,7 @@ * presence_callinfo module - Presence Handling of call-info events * * Copyright (C) 2010 Ovidiu Sas + * Copyright (C) 2013 OpenSIPS Solutions * * This file is part of opensips, a free SIP server. * @@ -15,13 +16,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2010-03-11 initial version (osas) + * 2010-07-13 added support for SCA Broadsoft with dialog module (bogdan) */ #include @@ -34,97 +36,228 @@ #include "../../sr_module.h" #include "../../dprint.h" #include "../../str.h" +#include "../../mod_fix.h" #include "../../parser/msg_parser.h" +#include "../../parser/parse_from.h" #include "../../mem/mem.h" #include "../presence/bind_presence.h" #include "add_events.h" -#include "presence_callinfo.h" +#include "sca_hash.h" +#include "sca_dialog.h" int call_info_timeout_notification = 1; int line_seize_timeout_notification = 0; +int no_dialog_support = 0; +static int hash_size = 64; + +/* external API's */ +presence_api_t pres; /* module functions */ static int mod_init(void); static int child_init(int); static void destroy(void); -/* module variables */ -add_event_t pres_add_event; + +int sca_set_calling_line(struct sip_msg *msg, char *line_var); +int sca_set_called_line(struct sip_msg *msg, char *line_var); + /* module exported commands */ static cmd_export_t cmds[] = { - {0, 0, 0, 0, 0, 0} + {"sca_set_calling_line", (cmd_function)sca_set_calling_line, 0, + NULL, NULL, REQUEST_ROUTE }, + {"sca_set_calling_line", (cmd_function)sca_set_calling_line, 1, + fixup_pvar_null, fixup_free_pvar_null, REQUEST_ROUTE }, + {"sca_set_called_line", (cmd_function)sca_set_called_line, 0, + NULL, NULL, REQUEST_ROUTE }, + {"sca_set_called_line", (cmd_function)sca_set_called_line, 1, + fixup_pvar_null, fixup_free_pvar_null, REQUEST_ROUTE }, + {0, 0, 0, 0, 0, 0} }; /* module exported paramaters */ static param_export_t params[] = { - {"call_info_timeout_notification", INT_PARAM, &call_info_timeout_notification}, - {"line_seize_timeout_notification", INT_PARAM, &line_seize_timeout_notification}, - {0, 0, 0} + {"line_hash_size", INT_PARAM, &hash_size}, + {"disable_dialog_support_for_sca", INT_PARAM, &no_dialog_support}, + {"call_info_timeout_notification", INT_PARAM, &call_info_timeout_notification}, + {"line_seize_timeout_notification", INT_PARAM, &line_seize_timeout_notification}, + {0, 0, 0} +}; + +static module_dependency_t *get_deps_dialog_support(param_export_t *param) +{ + int no_dialog_support = *(int *)param->param_pointer; + + if (no_dialog_support) + return NULL; + + return alloc_module_dep(MOD_TYPE_DEFAULT, "dialog", DEP_ABORT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "presence", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "disable_dialog_support_for_sca", get_deps_dialog_support }, + { NULL, NULL }, + }, }; /* module exports */ struct module_exports exports= { - "presence_callinfo", /* module name */ - MODULE_VERSION, /* module version */ - DEFAULT_DLFLAGS, /* dlopen flags */ - cmds, /* exported functions */ - params, /* exported parameters */ - 0, /* exported statistics */ - 0, /* exported MI functions */ - 0, /* exported pseudo-variables */ - 0, /* extra processes */ - mod_init, /* module initialization function */ - (response_function) 0, /* response handling function */ - destroy, /* destroy function */ - child_init /* per-child init function */ + "presence_callinfo", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ + MODULE_VERSION, /* module version */ + DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ + cmds, /* exported functions */ + params, /* exported parameters */ + 0, /* exported statistics */ + 0, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + (response_function) 0, /* response handling function */ + destroy, /* destroy function */ + child_init /* per-child init function */ }; - + + /* * init module function */ static int mod_init(void) { - presence_api_t pres; - LM_INFO("initializing...\n"); - - bind_presence_t bind_presence; - - bind_presence= (bind_presence_t)find_export("bind_presence", 1,0); - if (!bind_presence) { - LM_ERR("can't bind presence\n"); - return -1; - } - if (bind_presence(&pres) < 0) { - LM_ERR("can't bind pua\n"); - return -1; - } - - pres_add_event = pres.add_event; - if (pres_add_event == NULL) { - LM_ERR("could not import add_event\n"); - return -1; - } - if(callinfo_add_events() < 0) { - LM_ERR("failed to add call-info events\n"); - return -1; - } - - return 0; + bind_presence_t bind_presence; + + LM_INFO("initializing...\n"); + + /* bind to presence module */ + bind_presence= (bind_presence_t)find_export("bind_presence", 1,0); + if (!bind_presence) { + LM_ERR("can't bind presence\n"); + return -1; + } + if (bind_presence(&pres) < 0) { + LM_ERR("can't bind pua\n"); + return -1; + } + + if (pres.add_event == NULL) { + LM_ERR("could not import add_event\n"); + return -1; + } + if(callinfo_add_events() < 0) { + LM_ERR("failed to add call-info events\n"); + return -1; + } + + if (no_dialog_support==0) { + /* bind to the dialog API */ + if (init_dialog_support()<0 ) { + LM_ERR("failed to enable the dialog support\n"); + return -1; + } + + /* init internal hash table to keep the SCA/lines status */ + if ( init_sca_hash(hash_size) < 0 ) { + LM_ERR("failed to init hash table for SCA lines\n"); + return -1; + } + } + + return 0; } + static int child_init(int rank) { - LM_DBG("[%d] pid [%d]\n", rank, getpid()); - return 0; -} +} + static void destroy(void) -{ - LM_DBG("destroying module ...\n"); +{ + LM_DBG("destroying module ...\n"); + if (no_dialog_support==0) + destroy_sca_hash(); + return; +} + + +int sca_set_calling_line(struct sip_msg *msg, char *line_var) +{ + pv_value_t value; + str line; + + if (no_dialog_support) { + LM_ERR("dialog support is disabled, cannot use this function\n"); + return -1; + } + + if (msg->REQ_METHOD != METHOD_INVITE) + return 1; - return; + /* get the name of line first */ + if (line_var) { + /* take it from param */ + if ( pv_get_spec_value( msg, (pv_spec_p)line_var, &value) < 0 ) { + LM_ERR("failed to evaluate parameter\n"); + return -1; + } + if ( (value.flags&PV_VAL_STR)==0 ) { + LM_ERR("line value is not a string (flags are %d)\n",value.flags); + return -1; + } + line = value.rs; + } else { + /* take it from FROM msg */ + if (parse_from_header(msg) < 0 ) { + LM_ERR("failed to extract FROM URI\n"); + return -1; + } + line = get_from(msg)->uri; + } + + return sca_set_line(msg, &line, 1/*calling*/); +} + + +int sca_set_called_line(struct sip_msg *msg, char *line_var) +{ + pv_value_t value; + str line; + + if (no_dialog_support) { + LM_ERR("dialog support is disabled, cannot use this function\n"); + return -1; + } + + if (msg->REQ_METHOD != METHOD_INVITE) + return 1; + + /* get the name of line first */ + if (line_var) { + /* take it from param */ + if ( pv_get_spec_value( msg, (pv_spec_p)line_var, &value) < 0 ) { + LM_ERR("failed to evaluate parameter\n"); + return -1; + } + if ( (value.flags&PV_VAL_STR)==0 ) { + LM_ERR("line value is not a string (flags are %d)\n",value.flags); + return -1; + } + line = value.rs; + } else { + /* take it from RURI msg */ + line = *GET_RURI(msg); + } + + return sca_set_line(msg, &line, 0/*called*/); } + diff --git a/modules/presence_callinfo/presence_callinfo.h b/modules/presence_callinfo/presence_callinfo.h index 93c329c4891..ea00a28ffef 100644 --- a/modules/presence_callinfo/presence_callinfo.h +++ b/modules/presence_callinfo/presence_callinfo.h @@ -2,6 +2,7 @@ * presence_callinfo module - presence_callinfo header file * * Copyright (C) 2010 Ovidiu Sas + * Copyright (C) 2013 OpenSIPS Solutions * * This file is part of opensips, a free SIP server. * @@ -15,18 +16,25 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2010-03-11 initial version (osas) + * 2010-07-13 added support for SCA Broadsoft with dialog module (bogdan) */ #ifndef _PRES_CALLINFO_H_ #define _PRES_CALLINFO_H_ -extern add_event_t pres_add_event; +#include "../presence/bind_presence.h" + +/* presence API */ +extern presence_api_t pres; + +/* if dialog support is on or off */ +extern int no_dialog_support; #endif diff --git a/modules/presence_callinfo/sca_dialog.c b/modules/presence_callinfo/sca_dialog.c new file mode 100644 index 00000000000..20856741e1a --- /dev/null +++ b/modules/presence_callinfo/sca_dialog.c @@ -0,0 +1,189 @@ +/* + * Add "call-info" event to presence module + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-07-13 added support for SCA Broadsoft with dialog module (bogdan) + */ + + +#include "../../dprint.h" +#include "../../mem/shm_mem.h" +#include "../../parser/parse_call_info.h" +#include "../dialog/dlg_load.h" +#include "sca_dialog.h" +#include "add_events.h" + + +static struct dlg_binds dlgf; +static str calling_line_Dvar = {"PCI_calling_line",16}; +static str called_line_Dvar = {"PCI_called_line", 15}; + + +int init_dialog_support(void) +{ + if (load_dlg_api(&dlgf)!=0) { + LM_ERR("failed to find dialog API - is dialog module loaded?\n"); + return -1; + } + + return 0; +} + + +static void sca_dialog_callback(struct dlg_cell *dlg, int type, + struct dlg_cb_params *_params) +{ + str calling_line = {NULL,0}; + str called_line = {NULL,0}; + struct sca_line *line=NULL; + int idx; + int state; + + /* search the lines */ + if ( dlgf.fetch_dlg_value(dlg, &calling_line_Dvar, &calling_line, 1)==0 || + calling_line.s!=NULL) { + LM_DBG("calling line <%.*s> found \n",calling_line.len,calling_line.s); + /* search without auto create */ + line = get_sca_line( &calling_line, 0); + } else if ( dlgf.fetch_dlg_value(dlg, &called_line_Dvar, &called_line, 1)==0 || + called_line.s!=NULL) { + LM_DBG("called line <%.*s> found \n",called_line.len,called_line.s); + /* search without auto create */ + line = get_sca_line( &called_line, 0); + } + + if (line==NULL) { + LM_ERR("could not found the line in dialog callback :( \n"); + return; + } + + /* careful now, the line is LOCKED !! */ + + /* get the index and the new state */ + idx = (int)(long)(*(_params->param)); + switch (type) { + case DLGCB_FAILED: + case DLGCB_TERMINATED: + case DLGCB_EXPIRED: + state = SCA_STATE_IDLE; + break; + case DLGCB_EARLY: + state = calling_line.len?SCA_STATE_PROGRESSING:SCA_STATE_ALERTING; + break; + case DLGCB_CONFIRMED: + state = SCA_STATE_ACTIVE; + break; + default: + LM_CRIT("BUG: unsupported callback type %d \n",type); + unlock_sca_line(line); + return; + } + + /* everything ok, change the state of the line and notify */ + set_sca_index_state( line, idx, state); + + do_callinfo_publish( line ); + /* now the line is unlocked */ + + return; +} + + +int sca_set_line(struct sip_msg *msg, str *line_s, int calling) +{ + struct dlg_cell *dlg; + unsigned int idx; + struct sca_line *line; + + /* extract the index from the call-info line */ + if ( parse_call_info_header( msg )!=0 ) { + LM_ERR("missing or bogus Call-Info header in INVITE\n"); + return -1; + } + idx = get_appearance_index(msg); + if (idx==0) { + LM_ERR("failed to extract line index from Call-Info hdr\n"); + return -1; + } + + LM_DBG("looking for line <%.*s>, idx %d, calling %d \n", + line_s->len, line_s->s, idx, calling); + + /* search for the line (with no creation) */ + line = get_sca_line( line_s, 0); + if (line==NULL) { + LM_ERR("used line <%.*s> not found in hash. Using without seizing?\n", + line_s->len, line_s->s); + return -1; + } + /* NOTE: the line is now locked !!!!! */ + + /* check if the index is seized */ + if (calling) { + if (line->seize_state!=idx) { + LM_ERR("line not seized or seized for other index " + "(idx=%d,seize=%d)\n",idx,line->seize_state); + goto error; + } + } + + /* create and bind to the dialog */ + if (dlgf.create_dlg(msg,0)< 0) { + LM_ERR("failed to create dialog\n"); + goto error; + } + + dlg = dlgf.get_dlg(); + + LM_DBG("INVITE dialog created: using line <%.*s>\n", + line_s->len, line_s->s); + + /* store the line variable into dialog */ + if (calling) { + if(dlgf.store_dlg_value(dlg, &calling_line_Dvar, line_s)< 0) { + LM_ERR("Failed to store calling line\n"); + goto error; + } + } else { + if(dlgf.store_dlg_value(dlg, &called_line_Dvar, line_s)< 0) { + LM_ERR("Failed to store called line\n"); + goto error; + } + } + + /* register callbacks */ + if (dlgf.register_dlgcb( dlg, + DLGCB_FAILED| DLGCB_CONFIRMED | DLGCB_TERMINATED | DLGCB_EXPIRED | + DLGCB_EARLY , sca_dialog_callback, (void*)(long)idx, 0) != 0) { + LM_ERR("cannot register callbacks for dialog\n"); + goto error; + } + + /* STILL LOCKED HERE !! */ + terminate_line_sieze(line); + /* lock released by above function */ + + return 1; +error: + unlock_sca_line(line); + return -1; +} diff --git a/modules/presence_callinfo/sca_dialog.h b/modules/presence_callinfo/sca_dialog.h new file mode 100644 index 00000000000..3152375dd5c --- /dev/null +++ b/modules/presence_callinfo/sca_dialog.h @@ -0,0 +1,41 @@ +/* + * Add "call-info" event to presence module + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-07-13 added support for SCA Broadsoft with dialog module (bogdan) + */ + + +#ifndef _H_PRESENCE_CALL_INFO_SCA_DIALOG +#define _H_PRESENCE_CALL_INFO_SCA_DIALOG + +#include "../../str.h" +#include "../../locking.h" +#include "../../parser/msg_parser.h" + + +int init_dialog_support(void); + +int sca_set_line(struct sip_msg *msg, str *line, int calling); + + +#endif diff --git a/modules/presence_callinfo/sca_hash.c b/modules/presence_callinfo/sca_hash.c new file mode 100644 index 00000000000..0591f08bbcb --- /dev/null +++ b/modules/presence_callinfo/sca_hash.c @@ -0,0 +1,359 @@ +/* + * Add "call-info" event to presence module + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-07-13 added support for SCA Broadsoft with dialog module (bogdan) + */ + + + + +#include "../../dprint.h" +#include "../../ut.h" +#include "../../mem/mem.h" +#include "../../hash_func.h" +#include "../../parser/parse_uri.h" +#include "sca_hash.h" +#include "add_events.h" + +static struct sca_hash *sca_table = NULL; + +#define sca_lock(_entry) \ + lock_set_get( sca_table->locks, sca_table->entries[_entry].lock_idx) + +#define sca_unlock(_entry) \ + lock_set_release( sca_table->locks, sca_table->entries[_entry].lock_idx) + +#define sca_hash(_line) core_hash(_line, 0, sca_table->size) + +int init_sca_hash(int size) +{ + int n; + + /* check/ajust the size of the hash table */ + for( n=0 ; n<(8*sizeof(n)) ; n++) { + if (size==(1< rounding from %d to %d\n", + size, 1<<(n-1)); + size = 1<<(n-1); + break; + } + } + + /* allocate the hash table + entries */ + sca_table = (struct sca_hash*)shm_malloc + ( sizeof(struct sca_hash) + size*sizeof(struct sca_entry)); + if (sca_table==0) { + LM_ERR("no more shm mem for SCA hash table\n"); + goto error0; + } + + memset( sca_table, 0, + sizeof(struct sca_hash) + size*sizeof(struct sca_entry) ); + + sca_table->size = size; + sca_table->entries = (struct sca_entry*)(sca_table+1); + + /* calculate how many locks we can get */ + n = (size=MIN_SCA_LOCKS ; n-- ) { + sca_table->locks = lock_set_alloc(n); + if (sca_table->locks==0) + continue; + if (lock_set_init(sca_table->locks)==0) { + lock_set_dealloc(sca_table->locks); + sca_table->locks = 0; + continue; + } + sca_table->locks_no = n; + break; + } + + if (sca_table->locks==0) { + LM_ERR("unable to allocted at least %d locks for the hash table\n", + MIN_SCA_LOCKS); + goto error1; + } + + /* distribute the locks over all entries */ + for( n=0 ; nentries[n].lock_idx = n % sca_table->locks_no; + + return 0; +error1: + shm_free( sca_table ); +error0: + return -1; +} + + +/* + * Creates new SCA structure, adds into hash table + * Assumes hash entry is locked !!!! + */ +static struct sca_line* create_sca_line(str *line, unsigned int hash) +{ + struct sca_line *scal; + struct sip_uri puri; + + /* parse the URI line */ + if ( parse_uri( line->s, line->len, &puri)<0 ) { + LM_ERR("failed to parse URI line <%.*s> \n", line->len, line->s); + return NULL; + } + + scal = (struct sca_line *)shm_malloc( sizeof(struct sca_line) + + line->len + MD5_LEN ); + if (scal==NULL) { + LM_ERR("no more shm - failed to allocate new SCA structure\n"); + return NULL; + } + + memset( scal, 0, sizeof(struct sca_line)); + scal->hash = hash; + /* name of the line */ + scal->line.s = (char*)(scal+1); + scal->line.len = line->len; + memcpy( scal->line.s, line->s, line->len); + /* user anf host, just as pointers */ + scal->user.s = scal->line.s + (puri.user.s - line->s); + scal->user.len = puri.user.len; + scal->domain.s = scal->line.s + (puri.host.s - line->s); + scal->domain.len = puri.host.len; + /* etag space */ + scal->etag.s = scal->line.s + scal->line.len; + scal->etag.len = 0; + + /* insert into hash */ + if (sca_table->entries[hash].first!=NULL) { + scal->next = sca_table->entries[hash].first; + scal->next->prev = scal; + } + sca_table->entries[hash].first = scal; + + return scal; +} + + +/* + * Searches for an SCA by name ; if found, it will returned with the lock taken !! + */ +struct sca_line* get_sca_line(str *line, int create) +{ + unsigned int hash; + struct sca_line *scal; + + hash = sca_hash( line ); + + sca_lock(hash); + + /* search */ + for( scal=sca_table->entries[hash].first ; scal ; scal=scal->next ) { + if ( (scal->line.len==line->len) && (memcmp(scal->line.s, line->s , line->len)==0) ) + return scal; + } + + /* not found */ + if (create==0) { + sca_unlock(hash); + return NULL; + } + + /* create */ + scal = create_sca_line(line, hash); + if (scal==NULL) { + LM_ERR("failed to create new SCA record\n"); + sca_unlock(hash); + return NULL; + } + return scal; +} + + +/* + * sets a new state for an index - it assumes the line is locked + */ +int set_sca_index_state(struct sca_line *line, unsigned int idx, + unsigned int state) +{ + struct sca_idx *scai; + struct sca_idx *prev; + + /* search for the index */ + for( scai=line->indexes,prev=NULL ; scai ; prev=scai,scai=scai->next) + if (scai->idx>=idx) break; + + /* if not found, add it to the right position */ + if (scai==NULL || scai->idx!=idx) { + scai = (struct sca_idx*)shm_malloc(sizeof(struct sca_idx)); + if (scai==NULL) { + LM_ERR("not enough shm mem for a new sca index\n"); + return -1; + } + scai->idx = idx; + /* insert it after prev */ + if (prev==NULL) { + scai->next = line->indexes; + line->indexes = scai; + } else { + scai->next = prev->next; + prev->next = scai; + } + } + + /* set the state */ + scai->state = state; + + return 0; +} + + +char * sca_print_line_status(struct sca_line *line, int *l) +{ + unsigned int len; + struct sca_idx *scai; + char *buf; + char *p, *q; + int n; + + len = CI_hdr_name_len + 1/*<*/ + line->line.len + 1 /*>*/ + + 1/*;*/ + CI_hdr_AI_param_len + 2/* =* */ + + 1/*;*/ + CI_hdr_AS_param_len + 15/* =idle */ + + CRLF_LEN; + + for( scai=line->indexes ; scai ; scai=scai->next ) { + if (scai->state!=SCA_STATE_IDLE) + len += 1/*;*/ + CI_hdr_AI_param_len +1 + 3 /* =idx */ + + 1/*;*/ + CI_hdr_AS_param_len + 1 + 3 /* =state */; + } + + buf = (char *)pkg_malloc(len); + if (buf==NULL) { + LM_ERR("no more mem (needed %d)\n",len); + return NULL; + } + + p = buf; + memcpy( p, CI_hdr_name_s "<", CI_hdr_name_len+1); + p += CI_hdr_name_len+1; + memcpy( p, line->line.s, line->line.len); + p += line->line.len; + *(p++) = '>'; + + for( scai=line->indexes ; scai ; scai=scai->next ) { + if (scai->state==SCA_STATE_IDLE) + continue; + memcpy( p, ";"CI_hdr_AI_param_s "=", CI_hdr_AI_param_len+2 ); + p += CI_hdr_AI_param_len+2 ; + q = int2str(scai->idx, &n); + memcpy( p , q, n); + p += n; + memcpy( p, ";"CI_hdr_AS_param_s "=", CI_hdr_AS_param_len+2 ); + p += CI_hdr_AS_param_len+2 ; + switch (scai->state) { + case SCA_STATE_SEIZED: + memcpy( p, "seized", 6); p += 6 ; + break; + case SCA_STATE_PROGRESSING: + memcpy( p, "progressing", 11); p += 11 ; + break; + case SCA_STATE_ALERTING: + memcpy( p, "alerting", 8); p += 8 ; + break; + case SCA_STATE_ACTIVE: + memcpy( p, "active", 6); p += 6 ; + break; + default: + LM_ERR("unsupported state %d for index %d line %.*s\n", + scai->state, scai->idx, line->line.len, line->line.s); + pkg_free(buf); + return NULL; + } + } + + /* add the idle state */ + memcpy( p, ";"CI_hdr_AI_param_s "=*;" CI_hdr_AS_param_s "=idle" CRLF, + 1+CI_hdr_AI_param_len+3+CI_hdr_AS_param_len+5+CRLF_LEN ); + p += 1+CI_hdr_AI_param_len+3+CI_hdr_AS_param_len+5+CRLF_LEN ; + + *l = (int)(p-buf); + + if (p-buf>len) + LM_ERR("BUG: allocated %d, wrote, %d\n",len,(int)(p-buf)); + LM_DBG("hdr is <%.*s>",*l,buf); + + return buf; +} + + + +void unlock_sca_line(struct sca_line *scal) +{ + sca_unlock(scal->hash); +} + + +void free_sca_line(struct sca_line *scal) +{ + struct sca_idx *idx,*tmp; + + /* free indexes */ + for( idx=scal->indexes ; idx ; ) { + tmp = idx; + idx = idx->next; + shm_free(tmp); + } + /* free main structure */ + shm_free(scal); +} + + +void destroy_sca_hash(void) +{ + struct sca_line *sline, *l_sline; + unsigned int i; + + if (sca_table==NULL) + return; + + if (sca_table->locks) { + lock_set_destroy(sca_table->locks); + lock_set_dealloc(sca_table->locks); + } + + for( i=0 ; isize; i++ ) { + sline = sca_table->entries[i].first; + while (sline) { + l_sline = sline; + sline = sline->next; + free_sca_line(l_sline); + } + + } + + shm_free(sca_table); + sca_table = NULL; +} + diff --git a/modules/presence_callinfo/sca_hash.h b/modules/presence_callinfo/sca_hash.h new file mode 100644 index 00000000000..b19a124da01 --- /dev/null +++ b/modules/presence_callinfo/sca_hash.h @@ -0,0 +1,97 @@ +/* + * Add "call-info" event to presence module + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2010-07-13 added support for SCA Broadsoft with dialog module (bogdan) + */ + + + +#ifndef _H_PRESENCE_CALL_INFO_SCA_HASH +#define _H_PRESENCE_CALL_INFO_SCA_HASH + +#include "../../str.h" +#include "../../locking.h" + +#define MAX_SCA_LOCKS 512 +#define MIN_SCA_LOCKS 1 + +#define SCA_STATE_IDLE 1 +#define SCA_STATE_SEIZED 2 +#define SCA_STATE_PROGRESSING 3 +#define SCA_STATE_ALERTING 4 +#define SCA_STATE_ACTIVE 5 + +struct sca_idx { + unsigned int idx; + unsigned int state; + struct sca_idx *next; +}; + +struct sca_line { + /* name of the line */ + str line; + str user; + str domain; + str etag; + + /* seizing info */ + unsigned int seize_state; + unsigned int seize_expires; + + /* index info */ + struct sca_idx *indexes; + + /* linking in the sca_hash */ + unsigned int hash; + struct sca_line *prev; + struct sca_line *next; +}; + +struct sca_entry { + struct sca_line *first; + unsigned int lock_idx; +}; + +struct sca_hash { + unsigned int size; + struct sca_entry *entries; + unsigned int locks_no; + gen_lock_set_t *locks; +}; + + +int init_sca_hash(int size); + +struct sca_line* get_sca_line(str *line, int create); + +void unlock_sca_line(struct sca_line *scal); + +int set_sca_index_state(struct sca_line *line, unsigned int idx, + unsigned int state); + +char * sca_print_line_status(struct sca_line *line, int *l); + +void destroy_sca_hash(); + +#endif + diff --git a/modules/presence_dialoginfo/README b/modules/presence_dialoginfo/README index 3f96c08b673..4eedf1312ef 100644 --- a/modules/presence_dialoginfo/README +++ b/modules/presence_dialoginfo/README @@ -24,8 +24,7 @@ Klaus Darilion Copyright © 2008 Klaus Darilion, IPCom (Module implementation was partly sponsored by Silver Server (www.sil.at)) Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/presence_dialoginfo/add_events.c b/modules/presence_dialoginfo/add_events.c index e35892dc616..a23ca8baa15 100644 --- a/modules/presence_dialoginfo/add_events.c +++ b/modules/presence_dialoginfo/add_events.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Add "dialog" event to presence module @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_dialoginfo/add_events.h b/modules/presence_dialoginfo/add_events.h index 2cc322ed5bb..c1ca3683ad5 100644 --- a/modules/presence_dialoginfo/add_events.h +++ b/modules/presence_dialoginfo/add_events.h @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_dialoginfo/notify_body.c b/modules/presence_dialoginfo/notify_body.c index b2aa2ac1f61..8e1e92e5349 100644 --- a/modules/presence_dialoginfo/notify_body.c +++ b/modules/presence_dialoginfo/notify_body.c @@ -1,7 +1,7 @@ /* * $Id$ * - * presence_dialoginfo module - + * presence_dialoginfo module - * * Copyright (C) 2006 Voice Sistem S.R.L. * Copyright (C) 2008 Klaus Darilion, IPCom @@ -43,10 +43,12 @@ #include "notify_body.h" #include "pidf.h" -str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n); +str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n, int partial); str* build_dialoginfo(str* pres_user, str* pres_domain); extern int force_single_dialog; +static str* _build_empty_dialoginfo(const char* pres_uri_char, str* extra_hdrs); + #define VERSION_HOLDER "00000000000" void free_xml_body(char* body) @@ -55,18 +57,39 @@ void free_xml_body(char* body) xmlFree(body); } +/* Joins user and domain into "sip:USER@DOMAIN". + * dst must fit at least MAX_URI_SIZE+1 characters! */ +static inline int sipuri_cat(char* dst, const str* user, const str* domain) { + if ((4 + user->len + 1 + domain->len) > MAX_URI_SIZE) { + LM_ERR("entity URI too long, maximum=%d\n", MAX_URI_SIZE); + return -1; + } + memcpy(dst, "sip:", 4); + memcpy(dst + 4, user->s, user->len); + dst[user->len + 4] = '@'; + memcpy(dst + user->len + 5, domain->s, domain->len); + dst[user->len + 5 + domain->len] = '\0'; + return 0; +} str* dlginfo_agg_nbody(str* pres_user, str* pres_domain, str** body_array, int n, int off_index) { str* n_body= NULL; + char pres_uri_char[MAX_URI_SIZE+1]; - LM_DBG("[pres_user]=%.*s [pres_domain]= %.*s, [n]=%d\n", - pres_user->len, pres_user->s, pres_domain->len, pres_domain->s, n); + if (sipuri_cat(pres_uri_char, pres_user, pres_domain) != 0) + return NULL; + LM_DBG("[pres_uri] %s (%d), [n]=%d\n", pres_uri_char, + pres_user->len + 5 + pres_domain->len, n); - if(body_array== NULL) - return build_dialoginfo(pres_user, pres_domain); + if(body_array == NULL) + return _build_empty_dialoginfo(pres_uri_char, NULL); + + if (n == -2) + n_body= agregate_xmls(pres_user, pres_domain, body_array, 1, 1); + else + n_body= agregate_xmls(pres_user, pres_domain, body_array, n, 0); - n_body= agregate_xmls(pres_user, pres_domain, body_array, n); LM_DBG("[n_body]=%p\n", n_body); if(n_body) { LM_DBG("[*n_body]=%.*s\n", @@ -78,14 +101,14 @@ str* dlginfo_agg_nbody(str* pres_user, str* pres_domain, str** body_array, int n } xmlCleanupParser(); - xmlMemoryDump(); + xmlMemoryDump(); if (n_body== NULL) - n_body= build_dialoginfo(pres_user, pres_domain); + n_body = _build_empty_dialoginfo(pres_uri_char, NULL); return n_body; } -str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n) +str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n, int partial) { int i, j= 0; @@ -100,7 +123,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n) int winner_priority = -1, priority ; xmlNodePtr winner_dialog_node = NULL ; str *body= NULL; - char buf[MAX_URI_SIZE+1]; + char buf[MAX_URI_SIZE+1]; LM_DBG("[pres_user]=%.*s [pres_domain]= %.*s, [n]=%d\n", pres_user->len, pres_user->s, pres_domain->len, pres_domain->s, n); @@ -121,7 +144,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n) xml_array[j] = NULL; xml_array[j] = xmlParseMemory( body_array[i]->s, body_array[i]->len ); - + /* LM_DBG("parsing XML body: [n]=%d, [i]=%d, [j]=%d xml_array[j]=%p\n", n, i, j, xml_array[j] ); */ if( xml_array[j]== NULL) @@ -131,7 +154,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n) } j++; - } + } if(j== 0) /* no body */ { @@ -146,14 +169,8 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n) /* LM_DBG("number of bodies in total [n]=%d, number of useful bodies [j]=%d\n", n, j ); */ /* create the new NOTIFY body */ - if ( (pres_user->len + pres_domain->len + 1) > MAX_URI_SIZE) { - LM_ERR("entity URI too long, maximum=%d\n", MAX_URI_SIZE); - return NULL; - } - memcpy(buf, pres_user->s, pres_user->len); - buf[pres_user->len] = '@'; - memcpy(buf + pres_user->len + 1, pres_domain->s, pres_domain->len); - buf[pres_user->len + 1 + pres_domain->len]= '\0'; + if (sipuri_cat(buf, pres_user, pres_domain) != 0) + goto error; doc = xmlNewDoc(BAD_CAST "1.0"); if(doc==0) @@ -171,7 +188,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n) xmlSetNs(root_node, namespace); /* The version must be increased for each new document and is a 32bit int. As the version is different for each watcher, we can not set here the - correct value. Thus, we just put here a placeholder which will be + correct value. Thus, we just put here a placeholder which will be replaced by the correct value in the aux_body_processing callback. Thus we have CPU intensive XML aggregation only once and can use quick search&replace in the per-watcher aux_body_processing callback. @@ -180,8 +197,11 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n) signed int) has max. 10 characters + 1 character for the sign */ xmlNewProp(root_node, BAD_CAST "version", BAD_CAST VERSION_HOLDER); - xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "partial" ); xmlNewProp(root_node, BAD_CAST "entity", BAD_CAST buf); + if (!partial) + xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "full" ); + else + xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "partial" ); /* loop over all bodies and create the aggregated body */ for(i=0; iname); /* we do not copy the node, but unlink it and then add it ot the new node * this destroys the original document but we do not need it anyway. - * using "copy" instead of "unlink" would also copy the namespace which - * would then be declared redundant (libxml unfortunately can not remove + * using "copy" instead of "unlink" would also copy the namespace which + * would then be declared redundant (libxml unfortunately can not remove * namespaces) */ if (!force_single_dialog || (j==1)) { @@ -242,7 +262,7 @@ str* agregate_xmls(str* pres_user, str* pres_domain, str** body_array, int n) ERR_MEM(PKG_MEM_STR); } - xmlDocDumpMemory(doc,(xmlChar**)(void*)&body->s, + xmlDocDumpMemory(doc,(xmlChar**)(void*)&body->s, &body->len); for(i=0; ilen + pres_domain->len + 1) > MAX_URI_SIZE) { - LM_ERR("entity URI too long, maximum=%d\n", MAX_URI_SIZE); - return NULL; - } - memcpy(buf, "sip:", 4); - memcpy(buf+4, pres_user->s, pres_user->len); - buf[pres_user->len+4] = '@'; - memcpy(buf + pres_user->len + 5, pres_domain->s, pres_domain->len); - buf[pres_user->len + 5 + pres_domain->len]= '\0'; - - pres_uri = (str*)pkg_malloc(sizeof(str)); - if(pres_uri == NULL) - { - LM_ERR("while allocating memory\n"); + if (sipuri_cat(buf, pres_user, pres_domain) != 0) return NULL; - } - memset(pres_uri, 0, sizeof(str)); - pres_uri->s = buf; - pres_uri->len = pres_user->len + 5 + pres_domain->len; - - LM_DBG("[pres_uri] %.*s\n", pres_uri->len, pres_uri->s); + pres_uri.s = buf; + pres_uri.len = 4 + pres_user->len + 1 + pres_domain->len; + LM_DBG("[pres_uri] %.*s\n", pres_uri.len, pres_uri.s); - if ( pres_contains_presence(pres_uri)<0 ) { + if (pres_contains_presence(&pres_uri) < 0) { LM_DBG("No record exists in hash_table\n"); goto error; } - /* create the Publish body */ + /* create the Publish body */ doc = xmlNewDoc(BAD_CAST "1.0"); if(doc==0) goto error; @@ -394,8 +398,10 @@ str* build_dialoginfo(str* pres_user, str* pres_domain) LM_ERR("while adding child [dialog]\n"); goto error; } + + /* reuse buf for user-part only */ memcpy(buf, pres_user->s, pres_user->len); - buf[pres_user->len]= '\0'; + buf[pres_user->len] = '\0'; xmlNewProp(dialog_node, BAD_CAST "id", BAD_CAST buf); @@ -423,10 +429,6 @@ str* build_dialoginfo(str* pres_user, str* pres_domain) xmlCleanupParser(); return body; error: - if ( pres_uri ) - { - pkg_free(pres_uri); - } if(body) { if(body->s) @@ -438,12 +440,11 @@ str* build_dialoginfo(str* pres_user, str* pres_domain) return NULL; } -str* build_empty_dialoginfo(str* pres_uri, str* extra_hdrs) +static str* _build_empty_dialoginfo(const char* pres_uri_char, str* extra_hdrs) { str* nbody= 0; xmlDocPtr doc = NULL; xmlNodePtr node; - char* pres_uri_char = NULL; nbody= (str*) pkg_malloc(sizeof(str)); if(nbody== NULL) @@ -471,16 +472,7 @@ str* build_empty_dialoginfo(str* pres_uri, str* extra_hdrs) xmlNewProp(node, BAD_CAST "version", BAD_CAST VERSION_HOLDER); xmlNewProp(node, BAD_CAST "state", BAD_CAST "full"); - pres_uri_char = (char*)pkg_malloc(pres_uri->len + 1); - if(pres_uri_char == NULL) - { - LM_ERR("No more memory\n"); - goto error; - } - memcpy(pres_uri_char, pres_uri->s, pres_uri->len); - pres_uri_char[pres_uri->len] = '\0'; xmlNewProp(node, BAD_CAST "entity", BAD_CAST pres_uri_char); - pkg_free(pres_uri_char); xmlDocDumpMemory(doc,(xmlChar**)(void*)&nbody->s, &nbody->len); @@ -498,3 +490,24 @@ str* build_empty_dialoginfo(str* pres_uri, str* extra_hdrs) return 0; } +str* build_empty_dialoginfo(str* pres_uri, str* extra_hdrs) +{ + char* pres_uri_char; + str* ret; + + pres_uri_char = (char*)pkg_malloc(pres_uri->len + 1); + if(pres_uri_char == NULL) + { + LM_ERR("No more memory\n"); + return NULL; + } + memcpy(pres_uri_char, pres_uri->s, pres_uri->len); + pres_uri_char[pres_uri->len] = '\0'; + + /* do the call with a null-terminated pres_uri */ + ret = _build_empty_dialoginfo(pres_uri_char, extra_hdrs); + + pkg_free(pres_uri_char); + + return ret; +} diff --git a/modules/presence_dialoginfo/notify_body.h b/modules/presence_dialoginfo/notify_body.h index 062889ace4a..2444710c565 100644 --- a/modules/presence_dialoginfo/notify_body.h +++ b/modules/presence_dialoginfo/notify_body.h @@ -1,7 +1,7 @@ /* * $Id$ * - * presence_dialoginfo module + * presence_dialoginfo module * * Copyright (C) 2006 Voice Sistem S.R.L. * Copyright (C) 2008 Klaus Darilion, IPCom @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_dialoginfo/pidf.c b/modules/presence_dialoginfo/pidf.c index 0d10c9ea98f..fb33f8d0f86 100644 --- a/modules/presence_dialoginfo/pidf.c +++ b/modules/presence_dialoginfo/pidf.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -115,7 +115,7 @@ xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns) return xmlNodeGetNodeByName(cur, name, ns); } -char *xmlDocGetNodeContentByName(xmlDocPtr doc, const char *name, +char *xmlDocGetNodeContentByName(xmlDocPtr doc, const char *name, const char *ns) { xmlNodePtr node = xmlDocGetNodeByName(doc, name, ns); @@ -147,7 +147,7 @@ time_t xml_parse_dateTime(char* xml_time_str) printf("error: failed to parse time\n"); return 0; } - + if(*p== '\0') goto done; @@ -164,7 +164,7 @@ time_t xml_parse_dateTime(char* xml_time_str) if(*p== '\0') goto done; - + /* read time zone */ if(*p== 'Z') @@ -178,14 +178,14 @@ time_t xml_parse_dateTime(char* xml_time_str) p++; sscanf(p, "%c%c:%c%c", &h1, &h2, &m1, &m2); - + h= (h1- '0')*10+ h2- '0'; m= (m1- '0')*10+ m2- '0'; timezone_diff= sign* ((m+ h* 60)* 60); done: - return (mktime(&tm) + timezone_diff); + return (mktime(&tm) + timezone_diff); } diff --git a/modules/presence_dialoginfo/pidf.h b/modules/presence_dialoginfo/pidf.h index 10d2a88fb30..1e8217ecc8e 100644 --- a/modules/presence_dialoginfo/pidf.h +++ b/modules/presence_dialoginfo/pidf.h @@ -44,4 +44,4 @@ char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name); time_t xml_parse_dateTime(char* xml_time_str); -#endif +#endif diff --git a/modules/presence_dialoginfo/presence_dialoginfo.c b/modules/presence_dialoginfo/presence_dialoginfo.c index 994dfc0f944..5304a2f22b4 100644 --- a/modules/presence_dialoginfo/presence_dialoginfo.c +++ b/modules/presence_dialoginfo/presence_dialoginfo.c @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -67,11 +67,23 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "presence", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /* module exports */ struct module_exports exports= { "presence_dialoginfo", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -83,7 +95,7 @@ struct module_exports exports= { 0, /* destroy function */ 0 /* per-child init function */ }; - + /* * init module function */ @@ -114,8 +126,8 @@ static int mod_init(void) } if(dlginfo_add_events() < 0) { LM_ERR("failed to add dialog-info events\n"); - return -1; - } - + return -1; + } + return 0; } diff --git a/modules/presence_dialoginfo/presence_dialoginfo.h b/modules/presence_dialoginfo/presence_dialoginfo.h index ab33cf9051d..43de1247bd8 100644 --- a/modules/presence_dialoginfo/presence_dialoginfo.h +++ b/modules/presence_dialoginfo/presence_dialoginfo.h @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_mwi/README b/modules/presence_mwi/README index a85b633d001..fa64ad8ff84 100644 --- a/modules/presence_mwi/README +++ b/modules/presence_mwi/README @@ -12,8 +12,7 @@ Juha Heinanen Copyright © 2007 Juha Heinanen Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/presence_mwi/add_events.c b/modules/presence_mwi/add_events.c index 7e053a53b34..206f581c62a 100644 --- a/modules/presence_mwi/add_events.c +++ b/modules/presence_mwi/add_events.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -53,7 +53,7 @@ inline char *eat_printable(char *at, char *over) * event specific publish handling - check if body format is ok */ int mwi_publ_handl(struct sip_msg* msg, int *sent_reply) -{ +{ return 1; str body; char *at, *over; @@ -80,7 +80,7 @@ int mwi_publ_handl(struct sip_msg* msg, int *sent_reply) at = at + 16; at = eat_sp_tab(at, over); - if ((at >= over) || (*at != ':')){ + if ((at >= over) || (*at != ':')){ goto err; } @@ -97,21 +97,21 @@ int mwi_publ_handl(struct sip_msg* msg, int *sent_reply) goto err; } - if (strncasecmp(at, "yes", 3) == 0) + if (strncasecmp(at, "yes", 3) == 0) at = at + 3; else { - if (strncasecmp(at, "no", 2) == 0) + if (strncasecmp(at, "no", 2) == 0) at = at + 2; else goto err; } - if ((at + 1 >= over) || (*at != '\r') || (*(at + 1) != '\n')) + if ((at + 1 >= over) || (*at != '\r') || (*(at + 1) != '\n')) goto err; at = at + 2; - + /* check that remaining body consists of lines that only contain printable ascii chars */ while (at < over) { @@ -122,7 +122,7 @@ int mwi_publ_handl(struct sip_msg* msg, int *sent_reply) at = at + 2; } - + return 1; err: @@ -135,7 +135,7 @@ int mwi_publ_handl(struct sip_msg* msg, int *sent_reply) int mwi_add_events(void) { pres_ev_t event; - + /* constructing message-summary event */ memset(&event, 0, sizeof(pres_ev_t)); event.name.s = "message-summary"; @@ -150,11 +150,11 @@ int mwi_add_events(void) event.type = PUBL_TYPE; event.req_auth = 0; event.evs_publ_handl = mwi_publ_handl; - + if (pres_add_event(&event) < 0) { LM_ERR("failed to add event \"message-summary\"\n"); return -1; - } - + } + return 0; } diff --git a/modules/presence_mwi/add_events.h b/modules/presence_mwi/add_events.h index 5e33f8bcb6a..775da49f76e 100644 --- a/modules/presence_mwi/add_events.h +++ b/modules/presence_mwi/add_events.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_mwi/presence_mwi.c b/modules/presence_mwi/presence_mwi.c index c7d43da219d..bd0f3f7b383 100644 --- a/modules/presence_mwi/presence_mwi.c +++ b/modules/presence_mwi/presence_mwi.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -61,11 +61,23 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "presence", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /* module exports */ struct module_exports exports= { "presence_mwi", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -77,7 +89,7 @@ struct module_exports exports= { destroy, /* destroy function */ child_init /* per-child init function */ }; - + /* * init module function */ @@ -105,21 +117,21 @@ static int mod_init(void) } if(mwi_add_events() < 0) { LM_ERR("failed to add mwi events\n"); - return -1; - } - + return -1; + } + return 0; } static int child_init(int rank) { LM_DBG("[%d] pid [%d]\n", rank, getpid()); - + return 0; -} +} static void destroy(void) -{ +{ LM_DBG("destroying module ...\n"); return; diff --git a/modules/presence_mwi/presence_mwi.h b/modules/presence_mwi/presence_mwi.h index 816e5447788..4a53794395a 100644 --- a/modules/presence_mwi/presence_mwi.h +++ b/modules/presence_mwi/presence_mwi.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_xcapdiff/README b/modules/presence_xcapdiff/README index 52e5d23e4cb..62fc67da7a3 100644 --- a/modules/presence_xcapdiff/README +++ b/modules/presence_xcapdiff/README @@ -12,8 +12,7 @@ Denis Bilenko Copyright © 2008 AG Projects Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 (Tue, 21 - Jul 2009) $ + Revision $Revision$ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/presence_xcapdiff/presence_xcapdiff.c b/modules/presence_xcapdiff/presence_xcapdiff.c index e12c3d0d7cf..084e6c33092 100644 --- a/modules/presence_xcapdiff/presence_xcapdiff.c +++ b/modules/presence_xcapdiff/presence_xcapdiff.c @@ -39,10 +39,23 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "presence", DEP_SILENT }, + { MOD_TYPE_DEFAULT, "pua", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports= { "presence_xcapdiff", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ diff --git a/modules/presence_xml/README b/modules/presence_xml/README index 84beba2cf92..e94a200c841 100644 --- a/modules/presence_xml/README +++ b/modules/presence_xml/README @@ -2,8 +2,6 @@ Presence_XML Module Anca-Maria Vamanu - Voice Sistem SRL - Edited by Anca-Maria Vamanu @@ -14,8 +12,7 @@ Saul Ibarra Corretge Copyright © 2007 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-05-17 09:53:13 +0200 - (Thu, 17 May 2012) $ + Revision $Revision: 9037 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/presence_xml/add_events.c b/modules/presence_xml/add_events.c index 9f305f26d20..0f8c2bc441c 100644 --- a/modules/presence_xml/add_events.c +++ b/modules/presence_xml/add_events.c @@ -1,7 +1,7 @@ /* * $Id$ * - * presence_xml module - + * presence_xml module - * * Copyright (C) 2006 Voice Sistem S.R.L. * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -48,7 +48,7 @@ static str pu_415_rpl = str_init("Unsupported media type"); * in event specific publish handling - only check is good body format */ int xml_publ_handl(struct sip_msg* msg, int* sent_reply) -{ +{ str body= {0, 0}; xmlDocPtr doc= NULL; @@ -141,7 +141,7 @@ str* bla_set_version(subs_t* subs, str* body) int xml_add_events(void) { pres_ev_t event; - + /* constructing presence event */ memset(&event, 0, sizeof(pres_ev_t)); event.name.s= "presence"; @@ -185,7 +185,7 @@ int xml_add_events(void) LM_ERR("while adding event presence.winfo\n"); return -1; } - + /* constructing bla event */ memset(&event, 0, sizeof(pres_ev_t)); event.name.s= "dialog;sla"; @@ -208,7 +208,7 @@ int xml_add_events(void) LM_ERR("while adding event dialog;sla\n"); return -1; } - + return 0; } diff --git a/modules/presence_xml/add_events.h b/modules/presence_xml/add_events.h index f3ef85a377a..ebea7df5c12 100644 --- a/modules/presence_xml/add_events.h +++ b/modules/presence_xml/add_events.h @@ -1,7 +1,7 @@ /* * $Id$ * - * presence_xml module - + * presence_xml module - * * Copyright (C) 2006 Voice Sistem S.R.L. * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_xml/notify_body.c b/modules/presence_xml/notify_body.c index 56d85460239..1f8421722e5 100644 --- a/modules/presence_xml/notify_body.c +++ b/modules/presence_xml/notify_body.c @@ -1,7 +1,7 @@ /* * $Id$ * - * presence_xml module - + * presence_xml module - * * Copyright (C) 2006 Voice Sistem S.R.L. * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -269,7 +269,7 @@ str* agregate_dialog_xmls(str* pres_user, str* pres_domain, str** body_array, in xml_array = (xmlDocPtr*)pkg_malloc( (n+2)*sizeof(xmlDocPtr)); if(xml_array== NULL) { - + LM_ERR("while alocating memory"); return NULL; } @@ -317,7 +317,7 @@ str* agregate_dialog_xmls(str* pres_user, str* pres_domain, str** body_array, in LM_ERR("while geting the xml_tree root\n"); goto error; } - + node= xmlNodeGetChildByName(new_p_root, elem_name); if(node== NULL) { @@ -388,7 +388,7 @@ str* agregate_dialog_xmls(str* pres_user, str* pres_domain, str** body_array, in ERR_MEM(PKG_MEM_STR); } - xmlDocDumpMemory(xml_array[j],(xmlChar**)(void*)&body->s, + xmlDocDumpMemory(xml_array[j],(xmlChar**)(void*)&body->s, &body->len); LM_DBG("body = %.*s\n", body->len, body->s); @@ -512,8 +512,8 @@ str* agregate_presence_xmls(str* pres_user, str* pres_domain, str** body_array, LM_DBG("[pres_uri] %.*s\n", pres_uri.len, pres_uri.s); - /* if pidf_manipulation usage is configured */ - if(pidf_manipulation) + /* if pidf_manipulation usage is configured and there are no other bodies */ + if(pidf_manipulation && body_array == NULL) { if(p_get_xcap_doc(pres_user, pres_domain, PIDF_MANIPULATION, &pidf_doc) < 0) { @@ -889,7 +889,7 @@ int pres_apply_auth(str* notify_body, subs_t* subs, str** final_nbody) xmlDocPtr doc= NULL; xmlNodePtr node= NULL; str* n_body= NULL; - + *final_nbody= NULL; if(force_active) return 0; @@ -905,7 +905,7 @@ int pres_apply_auth(str* notify_body, subs_t* subs, str** final_nbody) LM_ERR("parsing xml doc\n"); return -1; } - + node= get_rule_node(subs, doc); if(node== NULL) { @@ -913,7 +913,7 @@ int pres_apply_auth(str* notify_body, subs_t* subs, str** final_nbody) xmlFreeDoc(doc); return 0; } - + n_body= get_final_notify_body(subs, notify_body, node); if(n_body== NULL) { @@ -971,11 +971,11 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node transf_node = xmlNodeGetChildByName(rule_node, "transformations"); if(transf_node == NULL) - { + { LM_DBG("No transformations node found\n"); goto done; } - + for(node = transf_node->children; node; node = node->next ) { if(xmlStrcasecmp(node->name, (unsigned char*)"text")== 0) @@ -985,7 +985,7 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node strcpy((char*)name ,(char*)(node->name + 8)); strcpy(all_name+4, name); - + if(xmlStrcasecmp((unsigned char*)name,(unsigned char*)"services") == 0) strcpy(name, "tuple"); if(strncmp((char*)name,"person", 6) == 0) @@ -995,26 +995,26 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node if(doc_node == NULL) continue; LM_DBG("searched doc_node->name:%s\n",name); - + content = (char*)xmlNodeGetContent(node); if(content) { LM_DBG("content = %s\n", content); - + if(xmlStrcasecmp((unsigned char*)content, (unsigned char*) "FALSE") == 0) { LM_DBG("found content false\n"); while( doc_node ) { - xmlUnlinkNode(doc_node); + xmlUnlinkNode(doc_node); xmlFreeNode(doc_node); doc_node = xmlNodeGetChildByName(doc_root, name); } xmlFree(content); continue; } - + if(xmlStrcasecmp((unsigned char*)content, (unsigned char*) "TRUE") == 0) { @@ -1038,7 +1038,7 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node break; } all_node = xmlNodeGetChildByName(node, all_name) ; - + if( all_node ) { LM_DBG("must provide all\n"); @@ -1047,7 +1047,7 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node } found = 0; - class_cont = xmlNodeGetNodeContentByName(doc_node, "class", + class_cont = xmlNodeGetNodeContentByName(doc_node, "class", NULL); if(class_cont == NULL) LM_DBG("no class tag found\n"); @@ -1062,7 +1062,7 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node deviceID = xmlNodeGetNodeContentByName(doc_node, "deviceID", - NULL); + NULL); if(deviceID== NULL) LM_DBG("no deviceID found\n"); else @@ -1070,7 +1070,7 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node service_uri = xmlNodeGetNodeContentByName(doc_node, "contact", - NULL); + NULL); if(service_uri == NULL) LM_DBG("no service_uri found\n"); else @@ -1088,7 +1088,7 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node } provide_node = node->children; - + while ( provide_node!= NULL ) { if(xmlStrcasecmp(provide_node->name,(unsigned char*) "text")==0) @@ -1162,7 +1162,7 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node xmlFree(content); } - + if(xmlStrcasecmp(provide_node->name, (unsigned char*)"service-uri-scheme")==0&& i) { @@ -1175,7 +1175,7 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node LM_DBG("found service_uri_scheme= %s", service_uri_scheme); xmlFree(content); break; - } + } if(content) xmlFree(content); @@ -1183,18 +1183,18 @@ str* get_final_notify_body( subs_t *subs, str* notify_body, xmlNodePtr rule_node provide_node = provide_node->next; } - + if(found == 0) { LM_DBG("delete node: %s\n", doc_node->name); dont_provide = doc_node; doc_node = doc_node->next; - xmlUnlinkNode(dont_provide); + xmlUnlinkNode(dont_provide); xmlFreeNode(dont_provide); - } + } else doc_node = doc_node->next; - + } } done: diff --git a/modules/presence_xml/notify_body.h b/modules/presence_xml/notify_body.h index ed12afcbef6..3070cb393a9 100644 --- a/modules/presence_xml/notify_body.h +++ b/modules/presence_xml/notify_body.h @@ -1,7 +1,7 @@ /* * $Id$ * - * presence_xml module - + * presence_xml module - * * Copyright (C) 2006 Voice Sistem S.R.L. * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_xml/pidf.c b/modules/presence_xml/pidf.c index ad3880d05b0..84f2a691aae 100644 --- a/modules/presence_xml/pidf.c +++ b/modules/presence_xml/pidf.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -101,7 +101,7 @@ xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns) return xmlNodeGetNodeByName(cur, name, ns); } -char *xmlDocGetNodeContentByName(xmlDocPtr doc, const char *name, +char *xmlDocGetNodeContentByName(xmlDocPtr doc, const char *name, const char *ns) { xmlNodePtr node = xmlDocGetNodeByName(doc, name, ns); @@ -133,7 +133,7 @@ time_t xml_parse_dateTime(char* xml_time_str) printf("error: failed to parse time\n"); return 0; } - + if(*p== '\0') goto done; @@ -150,7 +150,7 @@ time_t xml_parse_dateTime(char* xml_time_str) if(*p== '\0') goto done; - + /* read time zone */ if(*p== 'Z') @@ -164,14 +164,14 @@ time_t xml_parse_dateTime(char* xml_time_str) p++; sscanf(p, "%c%c:%c%c", &h1, &h2, &m1, &m2); - + h= (h1- '0')*10+ h2- '0'; m= (m1- '0')*10+ m2- '0'; timezone_diff= sign* ((m+ h* 60)* 60); done: - return (mktime(&tm) + timezone_diff); + return (mktime(&tm) + timezone_diff); } diff --git a/modules/presence_xml/pidf.h b/modules/presence_xml/pidf.h index 953180902a4..1b06afa307a 100644 --- a/modules/presence_xml/pidf.h +++ b/modules/presence_xml/pidf.h @@ -43,4 +43,4 @@ char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name); time_t xml_parse_dateTime(char* xml_time_str); -#endif +#endif diff --git a/modules/presence_xml/presence_xml.c b/modules/presence_xml/presence_xml.c index 2277448584a..8db65d320d9 100644 --- a/modules/presence_xml/presence_xml.c +++ b/modules/presence_xml/presence_xml.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -99,7 +99,7 @@ xcapGetNewDoc_t xcap_GetNewDoc; static param_export_t params[]={ { "force_active", INT_PARAM, &force_active }, - { "pidf_manipulation", INT_PARAM, &pidf_manipulation}, + { "pidf_manipulation", INT_PARAM, &pidf_manipulation}, { "xcap_server", STR_PARAM|USE_FUNC_PARAM,(void*)pxml_add_xcap_server}, { "pres_rules_auid", STR_PARAM, &pres_rules_auid.s}, { "pres_rules_filename", STR_PARAM, &pres_rules_filename.s}, @@ -107,12 +107,25 @@ static param_export_t params[]={ { 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "xcap", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "presence", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /** module exports */ struct module_exports exports= { "presence_xml", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -133,7 +146,7 @@ static int verify_db(void) LM_ERR("Database module not found\n"); return -1; } - + if (!DB_CAPABILITY(pxml_dbf, DB_CAP_ALL)) { LM_ERR("Database module does not implement all functions" " needed by the module\n"); @@ -150,7 +163,7 @@ static int verify_db(void) /* pxml_db is free'd by caller later, not sure if safe to do now */ return 0; } - + /** * init module function */ @@ -187,7 +200,7 @@ static int mod_init(void) return -1; } - + /* load SL API */ if(load_sig_api(&xml_sigb)==-1) { @@ -206,7 +219,7 @@ static int mod_init(void) LM_ERR("Can't bind module pua\n"); return -1; } - + pres_get_sphere= pres.get_sphere; pres_add_event= pres.add_event; pres_update_watchers= pres.update_watchers_status; @@ -218,7 +231,7 @@ static int mod_init(void) if(xml_add_events()< 0) { LM_ERR("adding xml events\n"); - return -1; + return -1; } if(pres_rules_auid.s) @@ -255,7 +268,7 @@ static int mod_init(void) LM_ERR("Can't bind xcap_client\n"); return -1; } - + if (bind_xcap_client(&xcap_client_api) < 0) { LM_ERR("Can't bind xcap_client_api\n"); @@ -295,7 +308,7 @@ static int mod_init(void) static int child_init(int rank) { LM_DBG("[%d] pid [%d]\n", rank, getpid()); - + if(force_active==0) { if (pxml_dbf.init==0) @@ -309,15 +322,15 @@ static int child_init(int rank) LM_ERR("child %d: ERROR while connecting database\n",rank); return -1; } - + LM_DBG("child %d: Database connection opened successfully\n",rank); } return 0; -} +} static void destroy(void) -{ +{ LM_DBG("start\n"); if(pxml_db && pxml_dbf.close) pxml_dbf.close(pxml_db); @@ -335,20 +348,20 @@ static int pxml_add_xcap_server( modparam_t type, void* val) char* sep= NULL; unsigned int port= 80; str serv_addr_str; - + serv_addr_str.s= serv_addr; serv_addr_str.len= strlen(serv_addr); sep= strchr(serv_addr, ':'); if(sep) - { + { char* sep2= NULL; str port_str; - + sep2= strchr(sep+ 1, ':'); if(sep2) sep= sep2; - + port_str.s= sep+ 1; port_str.len= serv_addr_str.len- (port_str.s- serv_addr); @@ -407,7 +420,7 @@ static int shm_copy_xcap_list(void) } xs_list= NULL; size= sizeof(xcap_serv_t); - + while(xs) { size+= (strlen(xs->addr)+ 1)* sizeof(char); @@ -422,7 +435,7 @@ static int shm_copy_xcap_list(void) shm_xs->addr= (char*)shm_xs+ size; strcpy(shm_xs->addr, xs->addr); shm_xs->port= xs->port; - shm_xs->next= xs_list; + shm_xs->next= xs_list; xs_list= shm_xs; prev_xs= xs; @@ -470,7 +483,7 @@ static int xcap_doc_updated(int doc_type, str xid, char* doc) if(pres_update_watchers(xid, &ev, &rules_doc)< 0) { LM_ERR("updating watchers in presence\n"); - return -1; + return -1; } return 0; diff --git a/modules/presence_xml/presence_xml.h b/modules/presence_xml/presence_xml.h index 3ec8458bf62..b963f97a9bc 100644 --- a/modules/presence_xml/presence_xml.h +++ b/modules/presence_xml/presence_xml.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/presence_xml/xcap_auth.c b/modules/presence_xml/xcap_auth.c index f3d9d14ea5f..2420c75e50e 100644 --- a/modules/presence_xml/xcap_auth.c +++ b/modules/presence_xml/xcap_auth.c @@ -1,7 +1,7 @@ /* * $Id$ * - * presence_xml module - + * presence_xml module - * * Copyright (C) 2007 Voice Sistem S.R.L. * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -78,7 +78,7 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule LM_DBG("ruleset_node NULL\n"); goto error; - } + } for(node1 = ruleset_node->children ; node1; node1 = node1->next) { if(xmlStrcasecmp(node1->name, (unsigned char*)"text")==0 ) @@ -89,7 +89,7 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule cond_node = xmlNodeGetChildByName(node1, "conditions"); if(cond_node == NULL) - { + { LM_DBG("cond node NULL\n"); goto error; } @@ -99,9 +99,9 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule if(validity_node !=NULL) { LM_DBG("found validity tag\n"); - + t= time(NULL); - + /* search all from-until pair */ for(time_node= validity_node->children; time_node; time_node= time_node->next) @@ -124,22 +124,22 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule LM_DBG("the lower time limit is not respected\n"); continue; } - + time_node= time_node->next; while(1) { if(time_node== NULL) - { + { LM_ERR("bad formatted xml doc:until child not found in" " validity pair\n"); goto error; } - if( xmlStrcasecmp(time_node->name, + if( xmlStrcasecmp(time_node->name, (unsigned char*)"until")== 0) break; time_node= time_node->next; } - + time_cont= (char*)xmlNodeGetContent(time_node); t_fin= xml_parse_dateTime(time_cont); xmlFree(time_cont); @@ -149,29 +149,29 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule LM_ERR("failed to parse xml dateTime\n"); goto error; } - + if(t <= t_fin) { LM_DBG("the rule is active at this time\n"); valid= 1; } - + } - + if(!valid) { LM_DBG("the rule is not active at this time\n"); continue; } - } - + } + sphere_node = xmlNodeGetChildByName(cond_node, "sphere"); if(sphere_node!= NULL) { /* check to see if matches presentity current sphere */ /* ask presence for sphere information */ - + char* sphere= pres_get_sphere(&subs->pres_uri); if(sphere) { @@ -185,7 +185,7 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule } pkg_free(sphere); xmlFree(attr); - + } else { @@ -201,24 +201,24 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule { LM_ERR("didn't find identity tag\n"); goto error; - } - + } + iden_child= xmlNodeGetChildByName(identity_node, "one"); - if(iden_child) + if(iden_child) { for(node2 = identity_node->children; node2; node2 = node2->next) { if(xmlStrcasecmp(node2->name, (unsigned char*)"one")!= 0) continue; - - id = xmlNodeGetAttrContentByName(node2, "id"); + + id = xmlNodeGetAttrContentByName(node2, "id"); if(id== NULL) { LM_ERR("while extracting attribute\n"); goto error; } - if((strlen(id)== w_uri.len && - (strncmp(id, w_uri.s, w_uri.len)==0))) + if((strlen(id)== w_uri.len && + (strncmp(id, w_uri.s, w_uri.len)==0))) { apply_rule = 1; xmlFree(id); @@ -226,33 +226,33 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule } xmlFree(id); } - } + } /* search for many node*/ iden_child= xmlNodeGetChildByName(identity_node, "many"); - if(iden_child) + if(iden_child) { domain = NULL; for(node2 = identity_node->children; node2; node2 = node2->next) { if(xmlStrcasecmp(node2->name, (unsigned char*)"many")!= 0) continue; - + domain = xmlNodeGetAttrContentByName(node2, "domain"); if(domain == NULL) - { + { LM_DBG("No domain attribute to many\n"); } - else + else { LM_DBG("\n", domain); - if((strlen(domain)!= subs->from_domain.len && + if((strlen(domain)!= subs->from_domain.len && strncmp(domain, subs->from_domain.s, subs->from_domain.len) )) { xmlFree(domain); continue; - } + } } xmlFree(domain); apply_rule = 1; @@ -265,18 +265,18 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule if(xmlStrcasecmp(except_node->name, (unsigned char*)"except")) continue; - id = xmlNodeGetAttrContentByName(except_node, "id"); + id = xmlNodeGetAttrContentByName(except_node, "id"); if(id!=NULL) { - if((strlen(id)- 1== w_uri.len && - (strncmp(id, w_uri.s, w_uri.len)==0))) + if((strlen(id)- 1== w_uri.len && + (strncmp(id, w_uri.s, w_uri.len)==0))) { xmlFree(id); apply_rule = 0; break; } xmlFree(id); - } + } else { domain = NULL; @@ -286,7 +286,7 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule LM_DBG("Found except domain= %s\n- strlen(domain)= %d\n", domain, (int)strlen(domain)); if(strlen(domain)==subs->from_domain.len && - (strncmp(domain,subs->from_domain.s , subs->from_domain.len)==0)) + (strncmp(domain,subs->from_domain.s , subs->from_domain.len)==0)) { LM_DBG("except domain match\n"); xmlFree(domain); @@ -294,14 +294,14 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule break; } xmlFree(domain); - } + } - } + } } if(apply_rule== 1) /* if a match was found no need to keep searching*/ break; - } + } } if(apply_rule ==1) break; @@ -314,18 +314,19 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule if( !apply_rule || !node1) return; - rule = (xcap_rule_t *)pkg_malloc(sizeof(*rule)); - if (rule == NULL) - { - LM_ERR("cannot allocate pkg_mem\n"); - return; - } + rule = (xcap_rule_t *)pkg_malloc(sizeof(*rule)); + if (rule == NULL) + { + LM_ERR("cannot allocate pkg_mem\n"); + return; + } - /* TODO: in IETF mode only the first matching rule is returned */ - rule->node = node1; - rule->next = NULL; - *rules = rule; + /* TODO: in IETF mode only the first matching rule is returned */ + rule->node = node1; + rule->next = NULL; + *rules = rule; + return; error: if(w_uri.s) pkg_free(w_uri.s); @@ -337,26 +338,37 @@ static void ietf_get_rules(subs_t* subs, xmlDocPtr xcap_tree, xcap_rule_t **rule static inline int oma_match_identity_condition(xmlNodePtr condition, subs_t *subs, str *w_uri) { int r = 0, many_match = 0; - char *id = NULL, *domain = NULL; + char *domain = NULL; + str uri; + str *normalized_uri; xmlNodePtr node = NULL, except_node = NULL; for(node = condition->children; node; node = node->next) { if(xmlStrcasecmp(node->name, (unsigned char*)"one") == 0) { - id = xmlNodeGetAttrContentByName(node, "id"); - if(id == NULL) + uri.s = xmlNodeGetAttrContentByName(node, "id"); + if(uri.s == NULL) + { + LM_ERR("when extracting entry attribute\n"); + continue; + } + uri.len = strlen(uri.s); + + normalized_uri = normalizeSipUri(&uri); + if (normalized_uri->s == NULL || normalized_uri->len == 0) { - LM_ERR("while extracting attribute\n"); + LM_ERR("normalizing URI\n"); + xmlFree(uri.s); continue; } - if((strlen(id) == w_uri->len && (strncmp(id, w_uri->s, w_uri->len)==0))) + xmlFree(uri.s); + + if (normalized_uri->len == w_uri->len && strncmp(normalized_uri->s, w_uri->s, w_uri->len) == 0) { - xmlFree(id); r = 1; break; } - xmlFree(id); } else if(xmlStrcasecmp(node->name, (unsigned char*)"many") == 0) { @@ -383,17 +395,24 @@ static inline int oma_match_identity_condition(xmlNodePtr condition, subs_t *sub if(xmlStrcasecmp(except_node->name, (unsigned char*)"except")) continue; - id = xmlNodeGetAttrContentByName(except_node, "id"); - if(id != NULL) + uri.s = xmlNodeGetAttrContentByName(except_node, "id"); + if(uri.s != NULL) { - if((strlen(id) == w_uri->len && - (strncmp(id, w_uri->s, w_uri->len)==0))) - { - xmlFree(id); - many_match = 0; - break; - } - xmlFree(id); + uri.len = strlen(uri.s); + normalized_uri = normalizeSipUri(&uri); + if (normalized_uri->s == NULL || normalized_uri->len == 0) + { + LM_ERR("normalizing URI\n"); + xmlFree(uri.s); + continue; + } + xmlFree(uri.s); + + if (normalized_uri->len == w_uri->len && strncmp(normalized_uri->s, w_uri->s, w_uri->len) == 0) + { + many_match = 0; + break; + } } else { @@ -1184,7 +1203,6 @@ static int http_get_xcap_doc(str* user, str* domain, int type, str** doc) int p_get_xcap_doc(str* user, str* domain, int type, str** doc) { - int r; str *etag = NULL; if (xcapDbGetDoc(user, domain, type, NULL, NULL, doc, &etag) < 0) diff --git a/modules/presence_xml/xcap_auth.h b/modules/presence_xml/xcap_auth.h index f0fcbff77ae..583a81f65d0 100644 --- a/modules/presence_xml/xcap_auth.h +++ b/modules/presence_xml/xcap_auth.h @@ -1,7 +1,7 @@ /* * $Id$ * - * presence_xml module - + * presence_xml module - * * Copyright (C) 2006 Voice Sistem S.R.L. * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pua/README b/modules/pua/README index 01c7c0409c4..372dcc83c95 100644 --- a/modules/pua/README +++ b/modules/pua/README @@ -2,8 +2,6 @@ Presence User Agent Module Anca-Maria Vamanu - Voice Sistem SRL - Edited by Anca-Maria Vamanu @@ -14,8 +12,7 @@ Saul Ibarra Corretge Copyright © 2006 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-10-22 13:41:25 +0200 - (Mon, 22 Oct 2012) $ + Revision $Revision: 9371 $ $Date$ __________________________________________________________ Table of Contents @@ -147,7 +144,7 @@ modparam("pua", "db_table", "pua") The inferior expires limit for both Publish and Subscribe. - Default value is “0”. + Default value is “300”. Example 1.4. Set min_expires parameter ... diff --git a/modules/pua/add_events.c b/modules/pua/add_events.c index 0f481d2703f..5eca520484e 100644 --- a/modules/pua/add_events.c +++ b/modules/pua/add_events.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * initial version 2007-05-03 (anca) @@ -136,7 +136,7 @@ int pres_process_body(publ_info_t* publ, str** fin_body, int ver, str* tuple) { xmlFree(person_id); } - } + } body= (str*)pkg_malloc(sizeof(str)); if(body== NULL) { @@ -152,7 +152,7 @@ int pres_process_body(publ_info_t* publ, str** fin_body, int ver, str* tuple) } xmlFreeDoc(doc); doc= NULL; - + *fin_body= body; xmlMemoryDump(); xmlCleanupParser(); diff --git a/modules/pua/add_events.h b/modules/pua/add_events.h index 52d180a8d18..512abd2b4b2 100644 --- a/modules/pua/add_events.h +++ b/modules/pua/add_events.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * initial version 2007-05-03 (anca) @@ -31,7 +31,7 @@ /* * should return: 0 if not changed ( fin_body points to publ->body) - * 1 if changed ( must be freed) + * 1 if changed ( must be freed) * */ int pua_add_events(void); diff --git a/modules/pua/doc/pua_admin.xml b/modules/pua/doc/pua_admin.xml index 7b4e159ef39..10b90fb2c99 100644 --- a/modules/pua/doc/pua_admin.xml +++ b/modules/pua/doc/pua_admin.xml @@ -130,7 +130,7 @@ modparam("pua", "db_table", "pua") The inferior expires limit for both Publish and Subscribe. - Default value is 0. + Default value is 300. diff --git a/modules/pua/event_list.c b/modules/pua/event_list.c index 750eb1a8a5b..6182bb67392 100644 --- a/modules/pua/event_list.c +++ b/modules/pua/event_list.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * initial version 2007-05-03 (anca) @@ -43,7 +43,7 @@ pua_event_t* init_pua_evlist(void) return NULL; } list->next= NULL; - + return list; } @@ -55,7 +55,7 @@ int add_pua_event(int ev_flag, char* name, char* content_type, int size; int name_len; int ctype_len= 0; - str str_name; + str str_name; if(pua_evlist == NULL) { @@ -82,7 +82,7 @@ int add_pua_event(int ev_flag, char* name, char* content_type, { LM_ERR("No more share memory\n"); return -1; - } + } memset(event, 0, size); size= sizeof(pua_event_t); @@ -90,13 +90,13 @@ int add_pua_event(int ev_flag, char* name, char* content_type, memcpy(event->name.s, name, name_len); event->name.len= name_len; size+= name_len; - + if(content_type) { event->content_type.s= (char*)event+ size; memcpy(event->content_type.s, content_type, ctype_len); event->content_type.len= ctype_len; - size+= ctype_len; + size+= ctype_len; } event->process_body= process_body; @@ -121,9 +121,9 @@ pua_event_t* contains_pua_event(str* name) return event; } event= event->next; - } + } - return NULL; + return NULL; } pua_event_t* get_event(int ev_flag) @@ -155,8 +155,8 @@ void destroy_pua_evlist(void) e2= e1->next; shm_free(e1); e1= e2; - } + } shm_free(pua_evlist); - } + } -} +} diff --git a/modules/pua/event_list.h b/modules/pua/event_list.h index 2b3452afd29..3f5451bf75d 100644 --- a/modules/pua/event_list.h +++ b/modules/pua/event_list.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * initial version 2007-05-03 (anca) @@ -39,7 +39,7 @@ typedef struct pua_event { int ev_flag; str name; - str content_type; /* default content type for that event*/ + str content_type; /* default content type for that event*/ evs_process_body_t* process_body; struct pua_event* next; diff --git a/modules/pua/hash.c b/modules/pua/hash.c index 7bef90cd556..05a5ddb3ab6 100644 --- a/modules/pua/hash.c +++ b/modules/pua/hash.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -34,7 +34,7 @@ #include "../../parser/msg_parser.h" #include "../../parser/parse_from.h" #include "../../db/db.h" -#include "hash.h" +#include "hash.h" #include "pua.h" #include "send_publish.h" #include "../presence/hash.h" @@ -50,27 +50,36 @@ static str str_remote_contact_col= str_init("remote_contact"); void print_ua_pres(ua_pres_t* p) { - LM_DBG("\tpres_uri= %.*s len= %d\n", p->pres_uri->len, p->pres_uri->s, p->pres_uri->len); + int now = (int)time(NULL); + + LM_DBG("p=[%p] pres_uri=[%.*s]\n", p, p->pres_uri->len, p->pres_uri->s); if(p->watcher_uri) - { - LM_DBG("\twatcher_uri= %.*s len= %d\n", p->watcher_uri->len, p->watcher_uri->s, p->watcher_uri->len); - LM_DBG("\tto_uri= %.*s len= %d\n", p->to_uri.len, p->to_uri.s, p->to_uri.len); - LM_DBG("\tcall_id= %.*s len= %d\n", p->call_id.len, p->call_id.s, p->call_id.len); - LM_DBG("\tfrom_tag= %.*s len= %d\n", p->from_tag.len, p->from_tag.s, p->from_tag.len); - LM_DBG("\tto_tag= %.*s len= %d\n", p->to_tag.len, p->to_tag.s, p->to_tag.len); - } + { + LM_DBG("watcher_uri=[%.*s]\n", p->watcher_uri->len, p->watcher_uri->s); + LM_DBG("to_uri=[%.*s]\n", p->to_uri.len, p->to_uri.s); + LM_DBG("call_id=[%.*s]\n", p->call_id.len, p->call_id.s); + LM_DBG("from_tag=[%.*s]\n", p->from_tag.len, p->from_tag.s); + LM_DBG("to_tag=[%.*s]\n", p->to_tag.len, p->to_tag.s); + LM_DBG("etag=[%.*s]\n", p->etag.len, p->etag.s); + } else { - LM_DBG("\tetag= %.*s - len= %d\n", p->etag.len, p->etag.s, p->etag.len); if(p->id.s) - LM_DBG("\tid= %.*s\n", p->id.len, p->id.s); - } - LM_DBG("\tflag= %d\n", p->flag); - LM_DBG("\tevent= %d\n", p->event); - if(p->expires > (int)time(NULL)) - LM_DBG("\texpires= %d\n", p->expires- (int)time(NULL)); + LM_DBG("etag=[%.*s] id=[%.*s]\n", + p->etag.len, p->etag.s, p->id.len, p->id.s); + else + LM_DBG("etag=[%.*s]\n", p->etag.len, p->etag.s); + } + LM_DBG("flag=[%d] event=[%d]\n", p->flag, p->event); + if (p->extra_headers.s && p->extra_headers.len) + LM_DBG("extra_headers=[%.*s]\n", + p->extra_headers.len, p->extra_headers.s); + if(p->expires > now) + LM_DBG("countdown=[%d] expires=[%d] desired_expires=[%d]\n", + p->expires - now, p->expires, p->desired_expires); else - LM_DBG("\texpires= %d\n", p->expires); + LM_DBG("expires=[%d] desired_expires=[%d]\n", + p->expires, p->desired_expires); } htable_t* new_htable(void) @@ -104,8 +113,8 @@ htable_t* new_htable(void) if(H->p_records[i].entity== NULL) { LM_ERR("No more share memory\n"); - goto error; - } + goto error; + } H->p_records[i].entity->next= NULL; } return H; @@ -190,9 +199,14 @@ ua_pres_t* search_htable(ua_pres_t* pres, unsigned int hash_code) } } - if(p && p->expires < (int)time(NULL)) - return 0; + if (p && p->expires < (int)time(NULL) && + !(p->expires==0 && p->waiting_reply && p->etag.len==0) ) + /* presentities with expires=0, waiting for reply and no etag are newly added + * presentities which were not yet confirmed (no reply received for first PUBLISH) + * and we should find such records ! -bogdan */ + return NULL; + LM_DBG("got presentity [%p]\n", p); return p; } @@ -241,7 +255,7 @@ int update_htable(unsigned int hash_index, unsigned int local_index, if(contact) { - if(!(p->remote_contact.len== contact->len && + if(!(p->remote_contact.len== contact->len && strncmp(p->remote_contact.s, contact->s, contact->len)==0)) { /* update remote contact */ @@ -284,8 +298,6 @@ ua_pres_t* new_ua_pres(publ_info_t* publ, str* tuple_id) size= sizeof(ua_pres_t) + sizeof(str)+ publ->pres_uri->len+ publ->id.len; - if(publ->extra_headers) - size+= sizeof(str)+ publ->extra_headers->len; if(publ->outbound_proxy.s) size+= sizeof(str)+ publ->outbound_proxy.len; if(tuple_id->s) @@ -295,7 +307,7 @@ ua_pres_t* new_ua_pres(publ_info_t* publ, str* tuple_id) if(presentity== NULL) { LM_ERR("no more share memory\n"); - return 0; + goto error; } memset(presentity, 0, size); @@ -303,7 +315,7 @@ ua_pres_t* new_ua_pres(publ_info_t* publ, str* tuple_id) presentity->pres_uri= (str*)((char*)presentity+ size); size+= sizeof(str); presentity->pres_uri->s= (char*)presentity+ size; - memcpy(presentity->pres_uri->s, publ->pres_uri->s, + memcpy(presentity->pres_uri->s, publ->pres_uri->s, publ->pres_uri->len); presentity->pres_uri->len= publ->pres_uri->len; size+= publ->pres_uri->len; @@ -311,14 +323,16 @@ ua_pres_t* new_ua_pres(publ_info_t* publ, str* tuple_id) // presentity->id.s=(char*)presentity+ size; CONT_COPY(presentity, presentity->id, publ->id); - if(publ->extra_headers) + if(publ->extra_headers && publ->extra_headers->s && publ->extra_headers->len) { - presentity->extra_headers = (str*)((char*)presentity + size); - size+= sizeof(str); - presentity->extra_headers->s = (char*)presentity + size; - memcpy(presentity->extra_headers->s, publ->extra_headers->s, publ->extra_headers->len); - presentity->extra_headers->len = publ->extra_headers->len; - size+= publ->extra_headers->len; + presentity->extra_headers.s = (char*)shm_malloc(publ->extra_headers->len); + if(presentity->extra_headers.s == NULL) + { + LM_ERR("No more shared memory\n"); + goto error; + } + memcpy(presentity->extra_headers.s, publ->extra_headers->s, publ->extra_headers->len); + presentity->extra_headers.len = publ->extra_headers->len; } if(publ->outbound_proxy.s) @@ -339,6 +353,10 @@ ua_pres_t* new_ua_pres(publ_info_t* publ, str* tuple_id) presentity->waiting_reply = 1; return presentity; + +error: + if (presentity) shm_free(presentity); + return NULL; } /* insert in front; so when searching the most recent result is returned*/ @@ -373,7 +391,7 @@ unsigned long insert_htable(ua_pres_t* presentity) (presentity->watcher_uri?presentity->watcher_uri->len:0), (presentity->watcher_uri?presentity->watcher_uri->s:0)); - hash_code= core_hash(s1, presentity->watcher_uri, + hash_code= core_hash(s1, presentity->watcher_uri, HASH_SIZE); presentity->hash_index = hash_code; LM_DBG("hash_code = %d\n", hash_code); @@ -412,6 +430,12 @@ static void pua_db_delete(ua_pres_t* pres) vals[n_query_cols].val.str_val = *pres->pres_uri; n_query_cols++; + cols[n_query_cols] = &str_event_col; + vals[n_query_cols].type = DB_INT; + vals[n_query_cols].nul = 0; + vals[n_query_cols].val.int_val = pres->event; + n_query_cols++; + if(pres->flag) { cols[n_query_cols] = &str_flag_col; @@ -421,12 +445,6 @@ static void pua_db_delete(ua_pres_t* pres) n_query_cols++; } - cols[n_query_cols] = &str_event_col; - vals[n_query_cols].type = DB_INT; - vals[n_query_cols].nul = 0; - vals[n_query_cols].val.int_val = pres->event; - n_query_cols++; - if(pres->id.s && pres->id.len) { cols[n_query_cols] = &str_pres_id_col; @@ -443,7 +461,7 @@ static void pua_db_delete(ua_pres_t* pres) vals[n_query_cols].nul = 0; vals[n_query_cols].val.str_val = *pres->watcher_uri; n_query_cols++; - + if(pres->remote_contact.s) { cols[n_query_cols] = &str_remote_contact_col; @@ -464,7 +482,7 @@ static void pua_db_delete(ua_pres_t* pres) n_query_cols++; } } - /* should not search after etag because I don't know if it has been updated */ + /* should not search after etag because I don't know if it has been updated */ if(pua_dbf.use_table(pua_db, &db_table)< 0) { @@ -486,12 +504,11 @@ void free_htable_entry(ua_pres_t* p) pua_db_delete(p); if(p->etag.s) - { shm_free(p->etag.s); - } - else if(p->remote_contact.s) shm_free(p->remote_contact.s); + if(p->extra_headers.s) + shm_free(p->extra_headers.s); shm_free(p); } @@ -547,6 +564,7 @@ void destroy_htable(void) else if(q->remote_contact.s) shm_free(q->remote_contact.s); + if(q->extra_headers.s) shm_free(q->extra_headers.s); shm_free(q); q= NULL; } @@ -672,7 +690,7 @@ int is_dialog(ua_pres_t* dialog) else ret_code= 0; lock_release(&HashT->p_records[hash_code].lock); - + return ret_code; } @@ -695,8 +713,8 @@ int update_contact(struct sip_msg* msg, char* str1, char* str2) { LM_ERR("cannot parse callid header\n"); return -1; - } - + } + if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); @@ -704,26 +722,26 @@ int update_contact(struct sip_msg* msg, char* str1, char* str2) } if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); return -1; } } - + pfrom = (struct to_body*)msg->from->parsed; - + if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); return -1; - } - + } + if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); return -1; - } + } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { @@ -743,11 +761,11 @@ int update_contact(struct sip_msg* msg, char* str1, char* str2) hentity.flag = BLA_SUBSCRIBE | XMPP_SUBSCRIBE | XMPP_INITIAL_SUBS | MI_SUBSCRIBE | RLS_SUBSCRIBE; hentity.watcher_uri= &pto->uri; - hentity.to_uri= pfrom->uri; + hentity.to_uri= pfrom->uri; hentity.call_id= msg->callid->body; hentity.to_tag= pto->tag_value; hentity.from_tag= pfrom->tag_value; - + hash_code= core_hash(&hentity.to_uri,hentity.watcher_uri, HASH_SIZE); @@ -769,9 +787,7 @@ int update_contact(struct sip_msg* msg, char* str1, char* str2) return -1; } - shm_free(p->remote_contact.s); - - if(!(p->remote_contact.len== contact.len && + if(!(p->remote_contact.len== contact.len && strncmp(p->remote_contact.s, contact.s, contact.len)==0)) { /* update remote contact */ diff --git a/modules/pua/hash.h b/modules/pua/hash.h index d5ab122cdea..34c62c42b65 100644 --- a/modules/pua/hash.h +++ b/modules/pua/hash.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -106,7 +106,7 @@ typedef struct ua_pres{ int version; int watcher_count; str* outbound_proxy; - str* extra_headers; + str extra_headers; str record_route; str remote_contact; str contact; @@ -117,7 +117,7 @@ typedef struct hash_entry { ua_pres_t* entity; gen_lock_t lock; -}hash_entry_t; +}hash_entry_t; typedef struct htable{ hash_entry_t* p_records; @@ -153,7 +153,7 @@ typedef int (*query_dialog_t)(ua_pres_t* presentity); static inline int get_event_flag(str* event) { - switch (event->len) + switch (event->len) { case 6: if (strncasecmp(event->s, "dialog", 6) == 0) diff --git a/modules/pua/pidf.c b/modules/pua/pidf.c index 8479693137a..1712ca2bc24 100644 --- a/modules/pua/pidf.c +++ b/modules/pua/pidf.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -100,7 +100,7 @@ xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns) return xmlNodeGetNodeByName(cur, name, ns); } -char *xmlDocGetNodeContentByName(xmlDocPtr doc, const char *name, +char *xmlDocGetNodeContentByName(xmlDocPtr doc, const char *name, const char *ns) { xmlNodePtr node = xmlDocGetNodeByName(doc, name, ns); @@ -121,7 +121,7 @@ int bind_libxml_api(libxml_api_t* api) api->xmlNodeGetNodeByName = xmlNodeGetNodeByName; api->xmlNodeGetNodeContentByName = xmlNodeGetNodeContentByName; api->xmlNodeGetAttrContentByName = xmlNodeGetAttrContentByName; - + return 0; -} +} diff --git a/modules/pua/pua.c b/modules/pua/pua.c index 63ed46c6817..269bb0a7f75 100644 --- a/modules/pua/pua.c +++ b/modules/pua/pua.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -98,7 +98,7 @@ static int mod_init(void); static int child_init(int); static void destroy(void); -static int update_pua(ua_pres_t* p, unsigned int hash_code); +static int update_pua(ua_pres_t* p, unsigned int hash_code, unsigned int final); static int db_restore(void); static void db_update(unsigned int ticks,void *param); @@ -122,11 +122,23 @@ static param_export_t params[]={ {0, 0, 0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports= { "pua", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -332,13 +344,13 @@ static int db_restore(void) LM_ERR("null database connection\n"); return -1; } - + if(pua_dbf.use_table(pua_db, &db_table)< 0) { LM_ERR("in use table\n"); return -1; } - + if (DB_CAPABILITY(pua_dbf, DB_CAP_FETCH)) { if(pua_dbf.query(pua_db,0, 0, 0, result_cols,0, n_result_cols, 0,0)< 0) { @@ -432,24 +444,24 @@ static int db_restore(void) LM_DBG("to_uri= %.*s\n", to_uri.len, to_uri.s); call_id.s= (char*)row_vals[callid_col].val.string_val; call_id.len = strlen(call_id.s); - + to_tag.s= (char*)row_vals[totag_col].val.string_val; to_tag.len = strlen(to_tag.s); - + from_tag.s= (char*)row_vals[fromtag_col].val.string_val; from_tag.len = strlen(from_tag.s); - + if(row_vals[record_route_col].val.string_val) { record_route.s= (char*) row_vals[record_route_col].val.string_val; record_route.len= strlen(record_route.s); } - + contact.s= (char*)row_vals[contact_col].val.string_val; contact.len = strlen(contact.s); - - remote_contact.s= + + remote_contact.s= (char*)row_vals[remote_contact_col].val.string_val; if(remote_contact.s) remote_contact.len = strlen(remote_contact.s); @@ -462,13 +474,11 @@ static int db_restore(void) size= sizeof(ua_pres_t)+ sizeof(str)+ (pres_uri.len+ pres_id.len+ tuple_id.len)* sizeof(char); - if(extra_headers.s) - size+= sizeof(str)+ extra_headers.len* sizeof(char); if(watcher_uri.s) size+= sizeof(str)+ to_uri.len + watcher_uri.len+ call_id.len+ to_tag.len+ from_tag.len+ record_route.len+ contact.len; - + p= (ua_pres_t*)shm_malloc(size); if(p== NULL) { @@ -477,14 +487,14 @@ static int db_restore(void) } memset(p, 0, size); size= sizeof(ua_pres_t); - + p->pres_uri= (str*)((char*)p+ size); size+= sizeof(str); p->pres_uri->s= (char*)p + size; memcpy(p->pres_uri->s, pres_uri.s, pres_uri.len); p->pres_uri->len= pres_uri.len; size+= pres_uri.len; - + if(pres_id.s) { CONT_COPY(p, p->id, pres_id); @@ -525,16 +535,6 @@ static int db_restore(void) p->version= row_vals[version_col].val.int_val; } - if(extra_headers.s) - { - p->extra_headers= (str*)((char*)p+ size); - size+= sizeof(str); - p->extra_headers->s= (char*)p+ size; - memcpy(p->extra_headers->s, extra_headers.s, extra_headers.len); - p->extra_headers->len= extra_headers.len; - size+= extra_headers.len; - } - LM_DBG("size= %d\n", size); p->event= row_vals[event_col].val.int_val; p->expires= row_vals[expires_col].val.int_val; @@ -550,11 +550,25 @@ static int db_restore(void) { LM_ERR("no more share memory\n"); goto error; - } + } memcpy(p->etag.s, etag.s, etag.len); p->etag.len= etag.len; } + memset(&p->extra_headers, 0, sizeof(str)); + if(extra_headers.s && extra_headers.len) + { + /* alloc separately */ + p->extra_headers.s= (char*)shm_malloc(extra_headers.len); + if(p->extra_headers.s== NULL) + { + LM_ERR("no more share memory\n"); + goto error; + } + memcpy(p->extra_headers.s, extra_headers.s, extra_headers.len); + p->extra_headers.len= extra_headers.len; + } + print_ua_pres(p); insert_htable(p); } /* end for(all rows)*/ @@ -571,7 +585,7 @@ static int db_restore(void) pua_dbf.free_result(pua_db, res); res = NULL; - + if(pua_dbf.delete(pua_db, 0, 0 , 0, 0) < 0) { LM_ERR("while deleting information from db\n"); @@ -585,7 +599,12 @@ static int db_restore(void) pua_dbf.free_result(pua_db, res); if(p) + { + if(p->remote_contact.s) shm_free(p->remote_contact.s); + if(p->extra_headers.s) shm_free(p->extra_headers.s); + if(p->etag.s) shm_free(p->etag.s); shm_free(p); + } return -1; } @@ -595,7 +614,6 @@ static void hashT_clean(unsigned int ticks,void *param) time_t now; ua_pres_t* p= NULL, *q= NULL; - return; now = time(NULL); for(i= 0;i< HASH_SIZE; i++) { @@ -607,14 +625,14 @@ static void hashT_clean(unsigned int ticks,void *param) LM_DBG("---\n"); if(p->expires -update_period < now ) { - if((p->desired_expires> p->expires + 5) || + if((p->desired_expires> p->expires + 5) || (p->desired_expires== 0 )) { LM_DBG("Desired expires greater than expires -> send a " "refresh PUBLISH desired_expires=%d - expires=%d\n", p->desired_expires, p->expires); - if(update_pua(p, i)< 0) + if(update_pua(p, i, 0)< 0) { LM_ERR("while updating record\n"); lock_release(&HashT->p_records[i].lock); @@ -626,17 +644,14 @@ static void hashT_clean(unsigned int ticks,void *param) LM_DBG("Found expired: uri= %.*s\n", p->pres_uri->len, p->pres_uri->s); - p->desired_expires = p->expires; - if(update_pua(p, i)< 0) + if(update_pua(p, i, 1)< 0) { - LM_ERR("failed to update record\n"); - /* delete it */ - q = p->next; - delete_htable_safe(p, p->hash_index); - p = q; + LM_ERR("while updating record\n"); } - else - p = p->next; + /* delete it */ + q = p->next; + delete_htable_safe(p, p->hash_index); + p = q; } else p= p->next; @@ -645,24 +660,31 @@ static void hashT_clean(unsigned int ticks,void *param) } } -int update_pua(ua_pres_t* p, unsigned int hash_code) +int update_pua(ua_pres_t* p, unsigned int hash_code, unsigned int final) { str* str_hdr= NULL; int expires; int result; - - if(p->desired_expires== 0) - expires= 3600; - else - expires= p->desired_expires- (int)time(NULL); - if(expires < min_expires) - expires = min_expires; + if(final > 0) + { + expires= 0; + p->desired_expires= 0; + } + else + { + if(p->desired_expires== 0) + expires= 3600; + else + expires= p->desired_expires- (int)time(NULL); + if(expires < min_expires) + expires = min_expires; + } if(p->watcher_uri== NULL) { str met= {"PUBLISH", 7}; - ua_pres_t* cb_param; + unsigned long cb_param; pua_event_t* ev; ev = get_event(p->event); @@ -673,15 +695,15 @@ int update_pua(ua_pres_t* p, unsigned int hash_code) } str_hdr = publ_build_hdr(expires, ev, NULL, - &p->etag, p->extra_headers, 0); + &p->etag, &p->extra_headers, 0); if(str_hdr == NULL) { LM_ERR("while building extra_headers\n"); goto error; } - LM_DBG("str_hdr:\n%.*s\n ", str_hdr->len, str_hdr->s); + LM_DBG("str_hdr:\n%.*s expires:%d\n ", str_hdr->len, str_hdr->s, expires); - cb_param = p; + cb_param = PRES_HASH_ID(p); result= tmb.t_request(&met, /* Type of the message*/ p->pres_uri, /* Request-URI */ @@ -708,7 +730,7 @@ int update_pua(ua_pres_t* p, unsigned int hash_code) goto error; } LM_DBG("td->rem_uri= %.*s\n", td->rem_uri.len, td->rem_uri.s); - str_hdr= subs_build_hdr(&p->contact, expires,p->event,p->extra_headers); + str_hdr= subs_build_hdr(&p->contact, expires,p->event,&p->extra_headers); if(str_hdr== NULL || str_hdr->s== NULL) { LM_ERR("while building extra headers\n"); @@ -741,7 +763,7 @@ int update_pua(ua_pres_t* p, unsigned int hash_code) pkg_free(td); td= NULL; - } + } pkg_free(str_hdr); return 0; @@ -750,15 +772,15 @@ int update_pua(ua_pres_t* p, unsigned int hash_code) if(str_hdr) pkg_free(str_hdr); return -1; - } static void db_update(unsigned int ticks,void *param) { ua_pres_t* p= NULL; - db_key_t q_cols[20]; + db_key_t q_cols[19]; + db_val_t q_vals[19]; db_key_t db_cols[5]; - db_val_t q_vals[21], db_vals[5]; + db_val_t db_vals[5]; db_op_t db_ops[1] ; int n_query_cols= 0, n_query_update= 0; int n_update_cols= 0; @@ -776,7 +798,7 @@ static void db_update(unsigned int ticks,void *param) q_vals[puri_col].type = DB_STR; q_vals[puri_col].nul = 0; n_query_cols++; - + q_cols[pid_col= n_query_cols] = &str_pres_id_col; q_vals[pid_col].type = DB_STR; q_vals[pid_col].nul = 0; @@ -885,6 +907,10 @@ static void db_update(unsigned int ticks,void *param) db_vals[3].type = DB_INT; db_vals[3].nul = 0; + db_cols[4]= &str_extra_headers_col; + db_vals[4].type = DB_STR; + db_vals[4].nul = 0; + if(pua_db== NULL) { LM_ERR("null database connection\n"); @@ -897,13 +923,6 @@ static void db_update(unsigned int ticks,void *param) return ; } - db_vals[0].val.int_val= (int)time(NULL)- 10; - db_ops[0]= OP_LT; - if(pua_dbf.delete(pua_db, db_cols, db_ops, db_vals, 1) < 0) - { - LM_ERR("while deleting from db table pua\n"); - } - for(i=0; icseq; db_vals[2].val.str_val= p->etag; db_vals[3].val.int_val= p->desired_expires; - n_update_cols= 4; + if(p->extra_headers.s && p->extra_headers.len) + { + db_vals[4].val.str_val= p->extra_headers; + n_update_cols= 5; + } + else + { + db_vals[4].val.str_val.s= NULL; + db_vals[4].val.str_val.len= 0; + n_update_cols= 4; + } LM_DBG("Updating:n_query_update= %d\tn_update_cols= %d\n", n_query_update, n_update_cols); @@ -994,11 +1023,7 @@ static void db_update(unsigned int ticks,void *param) q_vals[record_route_col].val.str_val = p->record_route; q_vals[contact_col].val.str_val = p->contact; q_vals[remote_contact_col].val.str_val = p->remote_contact; - - if(p->extra_headers) - q_vals[extra_headers_col].val.str_val = *(p->extra_headers); - else - memset(&q_vals[extra_headers_col].val.str_val, 0, sizeof(str)); + q_vals[extra_headers_col].val.str_val = p->extra_headers; if(pua_dbf.insert(pua_db, q_cols, q_vals, n_query_cols)< 0) { @@ -1018,6 +1043,13 @@ static void db_update(unsigned int ticks,void *param) lock_release(&HashT->p_records[i].lock); } + db_vals[0].val.int_val= (int)time(NULL)- 10; + db_ops[0]= OP_LT; + if(pua_dbf.delete(pua_db, db_cols, db_ops, db_vals, 1) < 0) + { + LM_ERR("while deleting from db table pua\n"); + } + return ; } diff --git a/modules/pua/pua.h b/modules/pua/pua.h index 75830bc02cc..e221d1283bb 100644 --- a/modules/pua/pua.h +++ b/modules/pua/pua.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/pua/pua_bind.c b/modules/pua/pua_bind.c index e8bbc51a28e..8292a5ad7df 100644 --- a/modules/pua/pua_bind.c +++ b/modules/pua/pua_bind.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -34,7 +34,7 @@ int bind_pua(pua_api_t* api) return -1; } - api->send_publish = send_publish; + api->send_publish = send_publish; api->send_subscribe = send_subscribe; api->register_puacb = register_puacb; api->is_dialog = is_dialog; diff --git a/modules/pua/pua_bind.h b/modules/pua/pua_bind.h index e71a2cc5dc9..1464fb71215 100644 --- a/modules/pua/pua_bind.h +++ b/modules/pua/pua_bind.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/pua/pua_callback.c b/modules/pua/pua_callback.c index 18d087a2816..842dea4fc1d 100644 --- a/modules/pua/pua_callback.c +++ b/modules/pua/pua_callback.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -57,7 +57,7 @@ void destroy_puacb_list(void) { cbp_tmp = cbp; cbp = cbp->next; - if (cbp_tmp->param) + if (cbp_tmp->param) shm_free( cbp_tmp->param ); shm_free( cbp_tmp ); } @@ -73,7 +73,7 @@ int register_puacb( int types, pua_cb f, void* param ) struct pua_callback *cbp; /* are the callback types valid?... */ - if ( types<0 || types>PUACB_MAX ) + if ( types<0 || types>PUACB_MAX ) { LM_CRIT("invalid callback types: mask=%d\n",types); return E_BUG; @@ -86,7 +86,7 @@ int register_puacb( int types, pua_cb f, void* param ) } /* build a new callback structure */ - if (!(cbp=(struct pua_callback*)shm_malloc(sizeof( struct pua_callback)))) + if (!(cbp=(struct pua_callback*)shm_malloc(sizeof( struct pua_callback)))) { LM_ERR("out of share mem\n"); return E_OUT_OF_MEM; diff --git a/modules/pua/pua_callback.h b/modules/pua/pua_callback.h index b0cb68e24c9..2e1234e3937 100644 --- a/modules/pua/pua_callback.h +++ b/modules/pua/pua_callback.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -66,8 +66,8 @@ static inline void run_pua_callbacks(ua_pres_t* hentity, struct sip_msg* msg) struct pua_callback *cbp; for (cbp= puacb_list->first; cbp; cbp=cbp->next) { - if(cbp->types & hentity->flag) - { + if(cbp->types & hentity->flag) + { LM_DBG("found callback\n"); cbp->callback(hentity, msg); } diff --git a/modules/pua/send_publish.c b/modules/pua/send_publish.c index 7a8f0cd3878..4b1e41e0ec5 100644 --- a/modules/pua/send_publish.c +++ b/modules/pua/send_publish.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -89,7 +89,7 @@ str* publ_build_hdr(int expires, pua_event_t* ev, str* content_type, str* etag, str_hdr->len+= len; memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN); str_hdr->len += CRLF_LEN; - + if(etag) { LM_DBG("UPDATE_TYPE [etag]= %.*s\n", etag->len, etag->s); @@ -101,13 +101,13 @@ str* publ_build_hdr(int expires, pua_event_t* ev, str* content_type, str* etag, str_hdr->len += CRLF_LEN; } if(is_body) - { + { if(content_type== NULL || content_type->s== NULL || content_type->len== 0) { - ctype= ev->content_type; /* use event default value */ + ctype= ev->content_type; /* use event default value */ } else - { + { ctype.s= content_type->s; ctype.len= content_type->len; } @@ -235,11 +235,11 @@ void publ_cback_func(struct cell *t, int type, struct tmcb_params *ps) LM_ERR("no reply message found\n"); return; } - LM_DBG("cback param = %ld\n", (long)*ps->param); + LM_DBG("cback param = %lu\n", (unsigned long)*ps->param); - pres_id = (long)*ps->param; + pres_id = (unsigned long)*ps->param; PUA_PARSE_PRES_ID(pres_id, hash_index, local_index); - LM_DBG("hash_index= %d, local_index= %d\n", hash_index, local_index); + LM_DBG("hash_index= %u, local_index= %u\n", hash_index, local_index); if(!find_htable(hash_index, local_index)) { @@ -377,7 +377,7 @@ int send_publish_int(ua_pres_t* presentity, publ_info_t* publ, pua_event_t* ev, int hash_index) { unsigned long pres_id= 0; - int ret = -1; + int ret = ERR_PUBLISH_GENERIC; char etag_buf[256]; char tuple_buf[128]; str tuple_id= {0, 0}; @@ -409,6 +409,7 @@ int send_publish_int(ua_pres_t* presentity, publ_info_t* publ, pua_event_t* ev, memcpy(tuple_id.s, presentity->tuple_id.s, presentity->tuple_id.len); tuple_id.len = presentity->tuple_id.len; } + presentity->desired_expires= publ->expires + (int)time(NULL); presentity->waiting_reply = 1; presentity->cb_param = publ->cb_param; @@ -446,6 +447,7 @@ int send_publish_int(ua_pres_t* presentity, publ_info_t* publ, pua_event_t* ev, { LM_DBG("request for a publish with expires 0 and" " no record found\n"); + ret = ERR_PUBLISH_NO_RECORD; goto error; } if(publ->body== NULL) @@ -460,7 +462,7 @@ int send_publish_int(ua_pres_t* presentity, publ_info_t* publ, pua_event_t* ev, pres_id = new_publ_record(publ, ev, &tuple_id); } - str_hdr = publ_build_hdr(((publ->expires< 0)?3600:publ->expires), ev, &publ->content_type, + str_hdr = publ_build_hdr(((publ->expires< 0)?3600:publ->expires), ev, &publ->content_type, (etag.s?&etag:NULL), publ->extra_headers, ((body)?1:0)); if(str_hdr == NULL) { @@ -495,7 +497,7 @@ int send_publish_int(ua_pres_t* presentity, publ_info_t* publ, pua_event_t* ev, pkg_free(body); } - return 0; + return ERR_PUBLISH_NO_ERROR; error: if(body && ev->process_body) @@ -550,21 +552,42 @@ int send_publish( publ_info_t* publ ) lock_release(&HashT->p_records[hash_code].lock); return 418; } - if(presentity && presentity->waiting_reply) + if(presentity) { - LM_DBG("Presentity is waiting for reply, queue this PUBLISH\n"); - last = &presentity->pending_publ; - while (*last) - last = &((*last)->next); - *last = build_pending_publ(publ); - if(! *last) + /* handle extra headers */ + if(presentity->extra_headers.s) shm_free(presentity->extra_headers.s); + presentity->extra_headers.len= 0; + if(publ->extra_headers && publ->extra_headers->s && publ->extra_headers->len) + { + presentity->extra_headers.s= (char*)shm_malloc(publ->extra_headers->len); + if(presentity->extra_headers.s == NULL) + { + LM_ERR("while processing extra_headers\n"); + lock_release(&HashT->p_records[hash_code].lock); + return -1; + } + memcpy(presentity->extra_headers.s, publ->extra_headers->s, + publ->extra_headers->len); + presentity->extra_headers.len= publ->extra_headers->len; + } + if(presentity->db_flag == NO_UPDATEDB_FLAG) + presentity->db_flag= UPDATEDB_FLAG; + if (presentity->waiting_reply) { - LM_ERR("Failed to create pending publ record\n"); + LM_DBG("Presentity is waiting for reply, queue this PUBLISH\n"); + last = &presentity->pending_publ; + while (*last) + last = &((*last)->next); + *last = build_pending_publ(publ); + if(! *last) + { + LM_ERR("Failed to create pending publ record\n"); + lock_release(&HashT->p_records[hash_code].lock); + return -1; + } lock_release(&HashT->p_records[hash_code].lock); - return -1; + return 0; } - lock_release(&HashT->p_records[hash_code].lock); - return 0; } return send_publish_int(presentity, publ, ev, hash_code); diff --git a/modules/pua/send_publish.h b/modules/pua/send_publish.h index 8de73b78988..107add66774 100644 --- a/modules/pua/send_publish.h +++ b/modules/pua/send_publish.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -31,7 +31,10 @@ #include "hash.h" #include "event_list.h" -#define ERR_PUBLISH_NO_BODY -10 +#define ERR_PUBLISH_NO_ERROR 0 +#define ERR_PUBLISH_GENERIC -1 +#define ERR_PUBLISH_NO_RECORD -9 +#define ERR_PUBLISH_NO_BODY -10 typedef struct publ_info { @@ -47,7 +50,7 @@ typedef struct publ_info str* etag; str* extra_headers; str outbound_proxy; - void* cb_param; /* the parameter for the function to be called on the callback + void* cb_param; /* the parameter for the function to be called on the callback for the received reply; it must be allocated in share memory; a reference to it will be found in the cb_param filed of the ua_pres_structure receied as a parameter for the registered function*/ diff --git a/modules/pua/send_subscribe.c b/modules/pua/send_subscribe.c index 39eb0754eb3..0989a11e6ee 100644 --- a/modules/pua/send_subscribe.c +++ b/modules/pua/send_subscribe.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -48,13 +48,12 @@ void print_subs(subs_info_t* subs) { - LM_DBG("pres_uri= %.*s - len: %d\n", - subs->pres_uri->len, subs->pres_uri->s, subs->pres_uri->len ); - LM_DBG("watcher_uri= %.*s - len: %d\n", - subs->watcher_uri->len, subs->watcher_uri->s, - subs->watcher_uri->len); + LM_DBG("pres_uri[%d]=[%.*s]\n", subs->pres_uri->len, + subs->pres_uri->len, subs->pres_uri->s); + LM_DBG("watcher_uri[%d]=[%.*s]\n", subs->watcher_uri->len, + subs->watcher_uri->len, subs->watcher_uri->s); if(subs->to_uri.s) - LM_DBG("to_uri= %.*s\n", subs->to_uri.len, subs->to_uri.s); + LM_DBG("to_uri=[%.*s]\n", subs->to_uri.len, subs->to_uri.s); } str* subs_build_hdr(str* contact, int expires, int event, str* extra_headers) @@ -63,7 +62,7 @@ str* subs_build_hdr(str* contact, int expires, int event, str* extra_headers) static char buf[3000]; char* subs_expires= NULL; int len= 1; - pua_event_t* ev; + pua_event_t* ev; str_hdr= (str*)pkg_malloc(sizeof(str)); if(str_hdr== NULL) @@ -73,8 +72,8 @@ str* subs_build_hdr(str* contact, int expires, int event, str* extra_headers) } memset(str_hdr, 0, sizeof(str)); str_hdr->s= buf; - - ev= get_event(event); + + ev= get_event(event); if(ev== NULL) { LM_ERR("getting event from list\n"); @@ -87,10 +86,10 @@ str* subs_build_hdr(str* contact, int expires, int event, str* extra_headers) str_hdr->len+= ev->name.len; memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN); str_hdr->len += CRLF_LEN; - + memcpy(str_hdr->s+ str_hdr->len ,"Contact: <", 10); str_hdr->len += 10; - memcpy(str_hdr->s +str_hdr->len, contact->s, + memcpy(str_hdr->s +str_hdr->len, contact->s, contact->len); str_hdr->len+= contact->len; memcpy(str_hdr->s+ str_hdr->len, ">", 1); @@ -114,7 +113,7 @@ str* subs_build_hdr(str* contact, int expires, int event, str* extra_headers) memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN); str_hdr->len += CRLF_LEN; - if(extra_headers && extra_headers->len) + if(extra_headers && extra_headers->s && extra_headers->len) { memcpy(str_hdr->s+str_hdr->len, extra_headers->s, extra_headers->len); str_hdr->len += extra_headers->len; @@ -136,7 +135,7 @@ dlg_t* pua_build_dlg_t(ua_pres_t* presentity) int size; size= sizeof(dlg_t)+ presentity->call_id.len+ presentity->to_tag.len+ - presentity->from_tag.len+ presentity->watcher_uri->len+ + presentity->from_tag.len+ presentity->watcher_uri->len+ presentity->to_uri.len+ presentity->remote_contact.len; td = (dlg_t*)pkg_malloc(size); @@ -194,7 +193,7 @@ dlg_t* pua_build_dlg_t(ua_pres_t* presentity) td->loc_seq.value = presentity->cseq++; td->loc_seq.is_set = 1; td->state= DLG_CONFIRMED ; - + return td; } @@ -250,7 +249,7 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) lock_release(&HashT->p_records[hentity->hash_index].lock); goto done; } - + if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("when parsing headers\n"); @@ -272,8 +271,8 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) { LM_ERR("cannot parse callid header\n"); goto done; - } - + } + if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); @@ -281,24 +280,24 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) } if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); goto done; } } pfrom = (struct to_body*)msg->from->parsed; - + if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto done; - } + } if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); goto done; - } + } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { @@ -314,7 +313,7 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) hentity->call_id= msg->callid->body; hentity->to_tag= pto->tag_value; hentity->from_tag= pfrom->tag_value; - + } /* extract the other necesary information for inserting a new record */ @@ -330,9 +329,9 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) } if(ps->code >= 300 ) - { /* if an error code and a stored dialog delete it and try to send - a subscription with type= INSERT_TYPE, else return*/ - + { /* if an error code and a stored dialog delete it and try to send + a subscription with type= INSERT_TYPE, else return*/ + if(!initial_request) { subs_info_t subs; @@ -363,15 +362,15 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) subs.expires= 0; else subs.expires= hentity->desired_expires- (int)time(NULL)+ 3; - + subs.flag= INSERT_TYPE; subs.source_flag= flag; subs.event= hentity->event; subs.id= hentity->id; subs.outbound_proxy= hentity->outbound_proxy; - subs.extra_headers= hentity->extra_headers; + subs.extra_headers= &hentity->extra_headers; subs.cb_param= hentity->cb_param; - + if(send_subscribe(&subs)< 0) { LM_ERR("when trying to send SUBSCRIBE\n"); @@ -415,7 +414,7 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) /* if a new dialog -> insert */ if(lexpire== 0) - { + { LM_DBG("expires= 0: no not insert\n"); goto done; } @@ -430,15 +429,15 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) { LM_ERR("while converting str to int\n"); goto done; - } - + } + /*process record route and add it to a string*/ if (msg->record_route!=NULL) { rt = print_rr_body(msg->record_route, &record_route, 1, 0); if(rt != 0) { - LM_ERR("parsing record route [%d]\n", rt); + LM_ERR("parsing record route [%d]\n", rt); record_route.s=NULL; record_route.len=0; } @@ -449,9 +448,6 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) +msg->callid->body.len+ record_route.len+ hentity->contact.len+ hentity->id.len )*sizeof(char); - if(hentity->extra_headers) - size+= sizeof(str)+ hentity->extra_headers->len*sizeof(char); - presentity= (ua_pres_t*)shm_malloc(size); if(presentity== NULL) { @@ -483,19 +479,19 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) size+= pfrom->uri.len; presentity->call_id.s= (char*)presentity + size; - memcpy(presentity->call_id.s,msg->callid->body.s, + memcpy(presentity->call_id.s,msg->callid->body.s, msg->callid->body.len); presentity->call_id.len= msg->callid->body.len; size+= presentity->call_id.len; presentity->to_tag.s= (char*)presentity + size; - memcpy(presentity->to_tag.s,pto->tag_value.s, + memcpy(presentity->to_tag.s,pto->tag_value.s, pto->tag_value.len); presentity->to_tag.len= pto->tag_value.len; size+= pto->tag_value.len; presentity->from_tag.s= (char*)presentity + size; - memcpy(presentity->from_tag.s,pfrom->tag_value.s, + memcpy(presentity->from_tag.s,pfrom->tag_value.s, pfrom->tag_value.len); presentity->from_tag.len= pfrom->tag_value.len; size+= pfrom->tag_value.len; @@ -509,7 +505,7 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) pkg_free(record_route.s); } - + presentity->contact.s= (char*)presentity + size; memcpy(presentity->contact.s, hentity->contact.s, hentity->contact.len); presentity->contact.len= hentity->contact.len; @@ -518,28 +514,30 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) if(hentity->id.s) { presentity->id.s=(char*)presentity+ size; - memcpy(presentity->id.s, hentity->id.s, + memcpy(presentity->id.s, hentity->id.s, hentity->id.len); - presentity->id.len= hentity->id.len; + presentity->id.len= hentity->id.len; size+= presentity->id.len; } - - if(hentity->extra_headers) + + if(hentity->extra_headers.s && hentity->extra_headers.len) { - presentity->extra_headers= (str*)((char*)presentity+ size); - size+= sizeof(str); - presentity->extra_headers->s=(char*)presentity+ size; - memcpy(presentity->extra_headers->s, hentity->extra_headers->s, - hentity->extra_headers->len); - presentity->extra_headers->len= hentity->extra_headers->len; - size+= hentity->extra_headers->len; + presentity->extra_headers.s= (char*)shm_malloc(hentity->extra_headers.len* sizeof(char)); + if(presentity->extra_headers.s== NULL) + { + LM_ERR("no more share memory\n"); + goto mem_error; + } + memcpy(presentity->extra_headers.s, hentity->extra_headers.s, hentity->extra_headers.len); + presentity->extra_headers.len= hentity->extra_headers.len; } /* write the remote contact filed */ presentity->remote_contact.s= (char*)shm_malloc(contact.len* sizeof(char)); if(presentity->remote_contact.s== NULL) { - ERR_MEM(SHARE_MEM); + LM_ERR("no more share memory\n"); + goto mem_error; } memcpy(presentity->remote_contact.s, contact.s, contact.len); presentity->remote_contact.len= contact.len; @@ -553,7 +551,7 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) if(BLA_SUBSCRIBE & presentity->flag) { LM_DBG("BLA_SUBSCRIBE FLAG inserted\n"); - } + } LM_DBG("record for subscribe from %.*s to %.*s inserted in datatbase\n", presentity->watcher_uri->len, presentity->watcher_uri->s, presentity->pres_uri->len, presentity->pres_uri->s); @@ -565,17 +563,26 @@ void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps) hentity->flag= flag; run_pua_callbacks( hentity, msg); } -error: - if(hentity) - { - shm_free(hentity); - hentity= NULL; - } + +error: + if(hentity->extra_headers.s) + shm_free(hentity->extra_headers.s); + shm_free(hentity); return; + +mem_error: + if(presentity->extra_headers.s) + shm_free(presentity->extra_headers.s); + if(presentity->remote_contact.s) + shm_free(presentity->remote_contact.s); + shm_free(presentity); + if(hentity->extra_headers.s) + shm_free(hentity->extra_headers.s); + shm_free(hentity); } ua_pres_t* subscribe_cbparam(subs_info_t* subs, int ua_flag) -{ +{ ua_pres_t* hentity= NULL; int size; str to_uri; @@ -589,9 +596,6 @@ ua_pres_t* subscribe_cbparam(subs_info_t* subs, int ua_flag) if(subs->outbound_proxy && subs->outbound_proxy->len && subs->outbound_proxy->s ) size+= sizeof(str)+ subs->outbound_proxy->len* sizeof(char); - if(subs->extra_headers && subs->extra_headers->s) - size+= sizeof(str)+ subs->extra_headers->len* sizeof(char); - hentity= (ua_pres_t*)shm_malloc(size); if(hentity== NULL) { @@ -644,23 +648,35 @@ ua_pres_t* subscribe_cbparam(subs_info_t* subs, int ua_flag) { CONT_COPY(hentity, hentity->id, subs->id); } - if(subs->extra_headers) + CONT_COPY(hentity, hentity->to_uri, to_uri); + + if(subs->extra_headers && subs->extra_headers->s && subs->extra_headers->len) { - hentity->extra_headers= (str*)((char*)hentity+ size); - size+= sizeof(str); - hentity->extra_headers->s= (char*)hentity+ size; - memcpy(hentity->extra_headers->s, subs->extra_headers->s, + hentity->extra_headers.s= + (char*)shm_malloc(subs->extra_headers->len* sizeof(char)); + if(hentity->extra_headers.s== NULL) + { + LM_ERR("no more share memory\n"); + goto error; + } + memcpy(hentity->extra_headers.s, subs->extra_headers->s, subs->extra_headers->len); - hentity->extra_headers->len= subs->extra_headers->len; - size+= subs->extra_headers->len; + hentity->extra_headers.len= subs->extra_headers->len; } - CONT_COPY(hentity, hentity->to_uri, to_uri); + hentity->flag= subs->source_flag; hentity->event= subs->event; hentity->ua_flag= hentity->ua_flag; hentity->cb_param= subs->cb_param; return hentity; +error: + if(hentity) + { + if(hentity->extra_headers.s) shm_free(hentity->extra_headers.s); + shm_free(hentity); + } + return NULL; } ua_pres_t* subs_cbparam_indlg(ua_pres_t* subs, int expires, int ua_flag) @@ -675,9 +691,6 @@ ua_pres_t* subs_cbparam_indlg(ua_pres_t* subs, int expires, int ua_flag) if(subs->outbound_proxy && subs->outbound_proxy->len && subs->outbound_proxy->s ) size+= sizeof(str)+ subs->outbound_proxy->len; - if(subs->extra_headers && subs->extra_headers->s) - size+= sizeof(str)+ subs->extra_headers->len; - if(subs->remote_contact.s) size+= subs->remote_contact.len; @@ -720,34 +733,37 @@ ua_pres_t* subs_cbparam_indlg(ua_pres_t* subs, int expires, int ua_flag) memcpy(hentity->outbound_proxy->s, subs->outbound_proxy->s, subs->outbound_proxy->len); hentity->outbound_proxy->len= subs->outbound_proxy->len; size+= subs->outbound_proxy->len; - } + } if(subs->id.s) { CONT_COPY(hentity, hentity->id, subs->id); } - + if(subs->remote_contact.s) { CONT_COPY(hentity, hentity->remote_contact, subs->remote_contact); } - if(subs->extra_headers) - { - hentity->extra_headers= (str*)((char*)hentity+ size); - size+= sizeof(str); - hentity->extra_headers->s= (char*)hentity+ size; - memcpy(hentity->extra_headers->s, subs->extra_headers->s, - subs->extra_headers->len); - hentity->extra_headers->len= subs->extra_headers->len; - size+= subs->extra_headers->len; - } /* copy dialog information */ - CONT_COPY(hentity, hentity->to_tag, subs->to_tag); CONT_COPY(hentity, hentity->from_tag, subs->from_tag); CONT_COPY(hentity, hentity->call_id, subs->call_id); - + + if(subs->extra_headers.s && subs->extra_headers.len) + { + hentity->extra_headers.s= + (char*)shm_malloc(subs->extra_headers.len* sizeof(char)); + if(hentity->extra_headers.s== NULL) + { + LM_ERR("no more share memory\n"); + goto error; + } + memcpy(hentity->extra_headers.s, subs->extra_headers.s, + subs->extra_headers.len); + hentity->extra_headers.len= subs->extra_headers.len; + } + if(expires< 0) hentity->desired_expires= 0; else @@ -762,6 +778,13 @@ ua_pres_t* subs_cbparam_indlg(ua_pres_t* subs, int expires, int ua_flag) return hentity; +error: + if(hentity) + { + if(hentity->extra_headers.s) shm_free(hentity->extra_headers.s); + shm_free(hentity); + } + return NULL; } int send_subscribe(subs_info_t* subs) @@ -824,7 +847,7 @@ int send_subscribe(subs_info_t* subs) if(presentity== NULL ) { - lock_release(&HashT->p_records[hash_index].lock); + lock_release(&HashT->p_records[hash_index].lock); if(subs->flag & UPDATE_TYPE) { /* @@ -834,7 +857,7 @@ int send_subscribe(subs_info_t* subs) goto done; commented this because of the strange type parameter in usrloc callback functions */ - + LM_DBG("request for a subscription with update type" " and no record found\n"); subs->flag= INSERT_TYPE; @@ -866,6 +889,8 @@ int send_subscribe(subs_info_t* subs) if(result< 0) { LM_ERR("while sending request with t_request\n"); + if (hentity->extra_headers.s) + shm_free(hentity->extra_headers.s); shm_free(hentity); goto done; } @@ -875,24 +900,24 @@ int send_subscribe(subs_info_t* subs) /* if(presentity->desired_expires== 0) { - + if(subs->expires< 0) { LM_DBG("Found previous request for unlimited subscribe-" " do not send subscribe\n"); - + if (subs->event & PWINFO_EVENT) - { + { presentity->watcher_count++; } lock_release(&HashT->p_records[hash_index].lock); goto done; - + } - - + + if(subs->event & PWINFO_EVENT) - { + { if(subs->expires== 0) { presentity->watcher_count--; @@ -911,9 +936,8 @@ int send_subscribe(subs_info_t* subs) goto done; } } - } - - } + } + } */ dlg_t* td= NULL; diff --git a/modules/pua/send_subscribe.h b/modules/pua/send_subscribe.h index d60af833c1c..d29cb798ca5 100644 --- a/modules/pua/send_subscribe.h +++ b/modules/pua/send_subscribe.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -47,7 +47,7 @@ typedef struct subs_info int source_flag; int internal_update_flag; int flag; /* it can be : INSERT_TYPE or UPDATE_TYPE; not compulsory */ - void* cb_param; /* the parameter for the function to be called on the callback + void* cb_param; /* the parameter for the function to be called on the callback for the received reply; it must be allocated in share memory; a reference to it will be found in the cb_param filed of the ua_pres_structure receied as a parameter for the registered function*/ diff --git a/modules/pua_bla/README b/modules/pua_bla/README index 72510dc8308..ec8daebe1a6 100644 --- a/modules/pua_bla/README +++ b/modules/pua_bla/README @@ -2,16 +2,13 @@ PUA Bridged Line Appearances Anca-Maria Vamanu - voice-system.ro - Edited by Anca-Maria Vamanu - Copyright © 2007 voice-system.ro + Copyright © 2007 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/pua_bla/notify.c b/modules/pua_bla/notify.c index 7bb0bacf8d8..c8fa33e285a 100644 --- a/modules/pua_bla/notify.c +++ b/modules/pua_bla/notify.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -44,7 +44,7 @@ static int bla_body_is_valid(str *bla_body) xmlNodePtr node = NULL; xmlErrorPtr xml_err = NULL; int valid = 0; - + doc = xmlParseMemory(bla_body->s, bla_body->len); if (!doc) { @@ -202,7 +202,7 @@ int bla_handle_notify(struct sip_msg* msg, char* s1, char* s2) return -1; } } - + if(msg->contact== NULL || msg->contact->body.s== NULL) { LM_ERR("no contact header found"); diff --git a/modules/pua_bla/pua_bla.c b/modules/pua_bla/pua_bla.c index 2cffb47f162..c3227bfb1d7 100644 --- a/modules/pua_bla/pua_bla.c +++ b/modules/pua_bla/pua_bla.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -74,11 +74,24 @@ static param_export_t params[]= {0, 0, 0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "pua", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "usrloc", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports= { "pua_bla", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -118,14 +131,14 @@ static int mod_init(void) } if(header_name.s == NULL ) - { + { LM_ERR("header_name parameter not set\n"); return -1; } header_name.len= strlen(header_name.s); if(bla_outbound_proxy.s == NULL ) - { + { LM_DBG("No outbound proxy set\n"); } else @@ -137,7 +150,7 @@ static int mod_init(void) LM_ERR("Can't bind pua\n"); return -1; } - + if (bind_pua(&pua) < 0) { LM_ERR("Can't bind pua\n"); @@ -163,12 +176,12 @@ static int mod_init(void) return -1; } pua_is_dialog= pua.is_dialog; - + if(pua.register_puacb== NULL) { LM_ERR("Could not import register callback\n"); return -1; - } + } bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) @@ -194,19 +207,19 @@ static int mod_init(void) return -1; } if(ul.register_ulcb(UL_CONTACT_EXPIRE, bla_cb, 0)< 0) - { + { LM_ERR("can not register callback for" " insert\n"); return -1; } if(ul.register_ulcb(UL_CONTACT_UPDATE, bla_cb, 0)< 0) - { + { LM_ERR("can not register callback for" " update\n"); return -1; } if(ul.register_ulcb(UL_CONTACT_DELETE, bla_cb, 0)< 0) - { + { LM_ERR("can not register callback for" " delete\n"); return -1; @@ -219,10 +232,10 @@ static int child_init(int rank) { LM_DBG("child [%d] pid [%d]\n", rank, getpid()); return 0; -} +} static void destroy(void) -{ +{ LM_DBG("destroying module ...\n"); return ; @@ -231,19 +244,19 @@ static void destroy(void) int bla_set_flag(struct sip_msg* msg , char* s1, char* s2) { LM_DBG("mark as bla aor\n"); - + is_bla_aor= 1; - + if( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); return -1; } - + if (msg->from->parsed == NULL) { - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_DBG("cannot parse From header\n"); return -1; @@ -253,5 +266,5 @@ int bla_set_flag(struct sip_msg* msg , char* s1, char* s2) reg_from_uri= ((struct to_body*)(msg->from->parsed))->uri; return 1; -} +} diff --git a/modules/pua_bla/pua_bla.h b/modules/pua_bla/pua_bla.h index d3a4d734e4b..170260387a1 100644 --- a/modules/pua_bla/pua_bla.h +++ b/modules/pua_bla/pua_bla.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pua_bla/registrar_cb.c b/modules/pua_bla/registrar_cb.c index bb1c9ab2231..0fea23dde46 100644 --- a/modules/pua_bla/registrar_cb.c +++ b/modules/pua_bla/registrar_cb.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -100,7 +100,7 @@ void bla_cb(ucontact_t* c, int type, void* param) subs.source_flag= BLA_SUBSCRIBE; subs.event= BLA_EVENT; subs.contact= &server_address; - + if(bla_outbound_proxy.s && bla_outbound_proxy.len) subs.outbound_proxy= &bla_outbound_proxy; else @@ -115,9 +115,9 @@ void bla_cb(ucontact_t* c, int type, void* param) if(pua_send_subscribe(&subs)< 0) { LM_ERR("while sending subscribe\n"); - } + } pkg_free(uri.s); error: is_bla_aor= 0; return ; -} +} diff --git a/modules/pua_bla/registrar_cb.h b/modules/pua_bla/registrar_cb.h index 20797ece7d0..5b8d9a6c5b2 100644 --- a/modules/pua_bla/registrar_cb.h +++ b/modules/pua_bla/registrar_cb.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pua_dialoginfo/README b/modules/pua_dialoginfo/README index 1616845b42c..e5ed9ca8fce 100644 --- a/modules/pua_dialoginfo/README +++ b/modules/pua_dialoginfo/README @@ -2,29 +2,29 @@ pua dialoginfo Anca-Maria Vamanu - voice-system.ro - Edited by Anca-Maria Vamanu Klaus Darilion - IPCom (Module implementation was partly sponsored by Silver - Server (www.sil.at)) - Edited by Klaus Darilion - IPCom +Ovidiu Sas + +Edited by + +Ovidiu Sas - Copyright © 2006 voice-system.ro + Copyright © 2006 Voice Sistem SRL Copyright © 2008 Klaus Darilion IPCom + + Copyright © 2014 VoIP Embedded, Inc. Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -43,10 +43,12 @@ Klaus Darilion 1.3.2. include_tags (int) 1.3.3. include_localremote (int) 1.3.4. caller_confirmed (int) - 1.3.5. presence_server (string) - 1.3.6. caller_spec_param (string) - 1.3.7. callee_spec_param (string) - 1.3.8. osips_ps (int) + 1.3.5. publish_on_trying (int) + 1.3.6. nopublish_flag (int) + 1.3.7. presence_server (string) + 1.3.8. caller_spec_param (string) + 1.3.9. callee_spec_param (string) + 1.3.10. osips_ps (int) 1.4. Exported Functions @@ -58,11 +60,14 @@ Klaus Darilion 1.2. Set include_tags parameter 1.3. Set include_localremote parameter 1.4. Set caller_confirmed parameter - 1.5. Set presence_server parameter - 1.6. Set caller_spec_param parameter - 1.7. Set caller_spec_param parameter - 1.8. Set osips_ps parameter - 1.9. dialoginfo_set usage + 1.5. Set publish_on_trying parameter to 0 + 1.6. Set publish_on_trying parameter to 1 + 1.7. Set nopublish_flag parameter + 1.8. Set presence_server parameter + 1.9. Set caller_spec_param parameter + 1.10. Set caller_spec_param parameter + 1.11. Set osips_ps parameter + 1.12. dialoginfo_set usage Chapter 1. Admin Guide @@ -293,18 +298,118 @@ modparam("pua_dialoginfo", "include_localremote", 0) modparam("pua_dialoginfo", "caller_confirmed", 1) ... -1.3.5. presence_server (string) +1.3.5. publish_on_trying (int) + + Usually the dialog-info of the caller will be "trying -> early + -> confirmed". The "trying" state will be triggered as soon as + you call dialoginfo_set on the caller, while "early" is + triggered as soon as the callee is ringing (triggered by a 180 + or 183 provisional reply). Sometimes, it is advisable to be + notified only when the callee reaches the early state and not + before. In other cases, it is advisable to notify the early + state. This setting allows controlling the behavior. + + The intended purpose of this parameter is to reduce the rate of + notifications (see RFC4235, section 3.10. Rate of + Notifications). + + Default value is “0”. + + Example 1.5. Set publish_on_trying parameter to 0 +... +modparam("pua_dialoginfo", "publish_on_trying", 0) + +# Successful call scenario: +# +# UAC proxy UAS presence server +# |--INVITE->| | | +# |<-100-----|--INVITE->| | +# | |<-100-----| | +# | | | | +# | |<-18x-----| | +# |<-18x-----|--PUBLISH(early)------>| +# | | | | +# | |<-200-----| | +# |<-200-----|--PUBLISH(confirmed)-->| +# |--ACK---->| | | +# | |--ACK---->| | +# | | | | +# +# +# Unsuccessful call scenario: +# +# UAC proxy UAS presence server +# |--INVITE->| | | +# |<-100-----|--INVITE->| | +# | |<-100-----| | +# | | | | +# | |<-456xx---| | +# |<-456xx---|--ACK---->| | +# |--ACK---->| | | +... + + Example 1.6. Set publish_on_trying parameter to 1 +... +modparam("pua_dialoginfo", "publish_on_trying", 1) + +# Successful call scenario: +# +# UAC proxy UAS presence server +# |--INVITE->| | | +# |<-100-----|--INVITE->| | +# | |--PUBLISH(trying)----->| +# | |<-100-----| | +# | | | | +# | |<-18x-----| | +# |<-18x-----|--PUBLISH(early)------>| +# | | | | +# | |<-200-----| | +# |<-200-----|--PUBLISH(confirmed)-->| +# |--ACK---->| | | +# | |--ACK---->| | +# | | | | +# +# +# Unsuccessful call scenario: +# +# UAC proxy UAS presence server +# |--INVITE->| | | +# |<-100-----|--INVITE->| | +# | |--PUBLISH(trying)----->| +# | |<-100-----| | +# | | | | +# | |<-456xx---| | +# | |--PUBLISH(terminated)->| +# |<-456xx---|--ACK---->| | +# |--ACK---->| | | +... + +1.3.6. nopublish_flag (int) + + By default, reINVITEs will trigger a PUBLISH. They are actually + the only in-dialog request for which it makes sense. In some + cases, it does not make sense to republish a dialog state. + (e.g. when handling a B2BUA reINVITE). This setting defines the + flag that needs to be set in the request route to prevent the + generation of a PUBLISH request in case of a specific reINVITE. + + Example 1.7. Set nopublish_flag parameter +... +modparam("pua_dialoginfo", "nopublish_flag", 5) +... + +1.3.7. presence_server (string) The address of the presence server, where the PUBLISH messages should be sent (not compulsory). - Example 1.5. Set presence_server parameter + Example 1.8. Set presence_server parameter ... modparam("pua_dialoginfo", "presence_server", "sip:ps@opensips.org:5060" ) ... -1.3.6. caller_spec_param (string) +1.3.8. caller_spec_param (string) The name of the pseudovariable that will hold a custom caller URI. If this variable is not set, the information in From @@ -314,12 +419,12 @@ modparam("pua_dialoginfo", "presence_server", "sip:ps@opensips.org:5060" the format of To/From SIP headers: "display_name" or "sip_uri". - Example 1.6. Set caller_spec_param parameter + Example 1.9. Set caller_spec_param parameter ... -modparam("pua_dialoginfo", "caller_spec_param", "$avp(i:10)") +modparam("pua_dialoginfo", "caller_spec_param", "$avp(10)") ... -1.3.7. callee_spec_param (string) +1.3.9. callee_spec_param (string) The name of the pseudovariable that will hold the callee URI. If this variable will not be set, the callee information used @@ -327,12 +432,12 @@ modparam("pua_dialoginfo", "caller_spec_param", "$avp(i:10)") string to set this pseudovariable to is the same as described in caller_spec_param section. - Example 1.7. Set caller_spec_param parameter + Example 1.10. Set caller_spec_param parameter ... -modparam("pua_dialoginfo", "callee_spec_param", "$avp(i:11)") +modparam("pua_dialoginfo", "callee_spec_param", "$avp(11)") ... -1.3.8. osips_ps (int) +1.3.10. osips_ps (int) It is advisable to specify if you use a different presence server than OpenSIPS presence server, by setting this parameter @@ -343,7 +448,7 @@ modparam("pua_dialoginfo", "callee_spec_param", "$avp(i:11)") Default value is “1”. - Example 1.8. Set osips_ps parameter + Example 1.11. Set osips_ps parameter ... modparam("pua_dialoginfo", "osips_ps", 0) ... @@ -360,7 +465,7 @@ modparam("pua_dialoginfo", "osips_ps", 0) * side (optional) - can be "A" or "B" for caller or callee PUBLISH only - if missing, both sides will be published. - Example 1.9. dialoginfo_set usage + Example 1.12. dialoginfo_set usage ... if(is_method("INVITE")) if(uri =~ "opensips.org") diff --git a/modules/pua_dialoginfo/dialog_publish.c b/modules/pua_dialoginfo/dialog_publish.c index 2fd221add7f..56b16cb8a68 100644 --- a/modules/pua_dialoginfo/dialog_publish.c +++ b/modules/pua_dialoginfo/dialog_publish.c @@ -2,7 +2,7 @@ * $Id$ * * pua_dialoginfo module - sending publish with dialog info from dialog module - * + * * Copyright (C) 2006 Voice Sistem S.R.L. * * This file is part of opensips, a free SIP server. @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -58,7 +58,7 @@ void print_publ(publ_info_t* p) str* build_dialoginfo(char *state, struct to_body *entity, struct to_body *peer, str *callid, unsigned int initiator, str *localtag, str *remotetag) { - xmlDocPtr doc = NULL; + xmlDocPtr doc = NULL; xmlNodePtr root_node = NULL; xmlNodePtr dialog_node = NULL; xmlNodePtr state_node = NULL; @@ -85,7 +85,7 @@ str* build_dialoginfo(char *state, struct to_body *entity, struct to_body *peer, root_node = xmlNewNode(NULL, BAD_CAST "dialog-info"); if(root_node==0) goto error; - + xmlDocSetRootElement(doc, root_node); xmlNewProp(root_node, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:dialog-info"); @@ -158,7 +158,7 @@ str* build_dialoginfo(char *state, struct to_body *entity, struct to_body *peer, } if (include_localremote) { - /* remote tag*/ + /* remote tag*/ remote_node = xmlNewChild(dialog_node, NULL, BAD_CAST "remote", NULL) ; if( remote_node ==NULL) { @@ -295,6 +295,7 @@ void dialog_publish(char *state, struct to_body* entity, struct to_body *peer, s { str* body= NULL; publ_info_t publ; + int ret_code; body= build_dialoginfo(state, entity, peer, callid, initiator, localtag, remotetag); if(body == NULL || body->s == NULL) @@ -302,7 +303,7 @@ void dialog_publish(char *state, struct to_body* entity, struct to_body *peer, s LM_ERR("failed to construct dialoginfo body\n"); goto error; } - + memset(&publ, 0, sizeof(publ_info_t)); publ.pres_uri= &entity->uri; @@ -314,8 +315,8 @@ void dialog_publish(char *state, struct to_body* entity, struct to_body *peer, s publ.content_type.len= 27; publ.expires= lifetime; - - /* make UPDATE_TYPE, as if this "publish dialog" is not found + + /* make UPDATE_TYPE, as if this "publish dialog" is not found by pua it will fallback to INSERT_TYPE anyway */ publ.flag|= UPDATE_TYPE; @@ -325,12 +326,16 @@ void dialog_publish(char *state, struct to_body* entity, struct to_body *peer, s publ.outbound_proxy = presence_server; print_publ(&publ); - if(pua_send_publish(&publ)< 0) - { + ret_code = pua_send_publish(&publ); + switch (ret_code) { + case ERR_PUBLISH_NO_ERROR: + case ERR_PUBLISH_NO_RECORD: + break; + default: LM_ERR("sending publish failed for pres_uri [%.*s] to server [%.*s]\n", publ.pres_uri->len, publ.pres_uri->s, publ.outbound_proxy.len, publ.outbound_proxy.s); - } + } error: diff --git a/modules/pua_dialoginfo/doc/pua_dialoginfo.xml b/modules/pua_dialoginfo/doc/pua_dialoginfo.xml index 757adbd345c..3dcf6bfb197 100644 --- a/modules/pua_dialoginfo/doc/pua_dialoginfo.xml +++ b/modules/pua_dialoginfo/doc/pua_dialoginfo.xml @@ -26,13 +26,21 @@ Vamanu - Klaus + Klaus Darilion - Klaus + Klaus Darilion + + Ovidiu + Sas + + + Ovidiu + Sas + 2006 @@ -42,6 +50,12 @@ 2008 Klaus Darilion IPCom + + 2014 + + VoIP Embedded, Inc. + + $Revision: 8740 $ diff --git a/modules/pua_dialoginfo/doc/pua_dialoginfo_admin.xml b/modules/pua_dialoginfo/doc/pua_dialoginfo_admin.xml index c9aa54aa170..8ee9a6119ab 100644 --- a/modules/pua_dialoginfo/doc/pua_dialoginfo_admin.xml +++ b/modules/pua_dialoginfo/doc/pua_dialoginfo_admin.xml @@ -73,10 +73,10 @@ - The dialog element can contain optional "local" and "remote" elements which - describes the local and the remote party in more detail, for example: + The dialog element can contain optional "local" and "remote" elements which + describes the local and the remote party in more detail, for example: - + - The local and remote elements are needed to implement call pickup. For example if + The local and remote elements are needed to implement call pickup. For example if the above XML document is received by somebody who SUBSCRIBEd the dialog-info of Alice, then it can pick-up the call by sending an INVITE to Bob (actually I am not sure if it should use the URI in the identity element or the URI in the target @@ -293,6 +293,122 @@ modparam("pua_dialoginfo", "caller_confirmed", 1)
+
+ <varname>publish_on_trying</varname> (int) + + Usually the dialog-info of the caller will be + "trying -> early -> confirmed". The "trying" state will be triggered as soon + as you call dialoginfo_set on the caller, while "early" is triggered + as soon as the callee is ringing (triggered by a 180 or 183 provisional reply). + Sometimes, it is advisable to be notified only when the callee reaches + the early state and not before. In other cases, it is advisable to + notify the early state. This setting allows controlling the behavior. + + + The intended purpose of this parameter is to reduce the rate of notifications + (see RFC4235, section 3.10. Rate of Notifications). + + + Default value is 0. + + + Set <varname>publish_on_trying</varname> parameter to 0 + +... +modparam("pua_dialoginfo", "publish_on_trying", 0) + +# Successful call scenario: +# +# UAC proxy UAS presence server +# |--INVITE->| | | +# |<-100-----|--INVITE->| | +# | |<-100-----| | +# | | | | +# | |<-18x-----| | +# |<-18x-----|--PUBLISH(early)------>| +# | | | | +# | |<-200-----| | +# |<-200-----|--PUBLISH(confirmed)-->| +# |--ACK---->| | | +# | |--ACK---->| | +# | | | | +# +# +# Unsuccessful call scenario: +# +# UAC proxy UAS presence server +# |--INVITE->| | | +# |<-100-----|--INVITE->| | +# | |<-100-----| | +# | | | | +# | |<-456xx---| | +# |<-456xx---|--ACK---->| | +# |--ACK---->| | | +... + + + + Set <varname>publish_on_trying</varname> parameter to 1 + +... +modparam("pua_dialoginfo", "publish_on_trying", 1) + +# Successful call scenario: +# +# UAC proxy UAS presence server +# |--INVITE->| | | +# |<-100-----|--INVITE->| | +# | |--PUBLISH(trying)----->| +# | |<-100-----| | +# | | | | +# | |<-18x-----| | +# |<-18x-----|--PUBLISH(early)------>| +# | | | | +# | |<-200-----| | +# |<-200-----|--PUBLISH(confirmed)-->| +# |--ACK---->| | | +# | |--ACK---->| | +# | | | | +# +# +# Unsuccessful call scenario: +# +# UAC proxy UAS presence server +# |--INVITE->| | | +# |<-100-----|--INVITE->| | +# | |--PUBLISH(trying)----->| +# | |<-100-----| | +# | | | | +# | |<-456xx---| | +# | |--PUBLISH(terminated)->| +# |<-456xx---|--ACK---->| | +# |--ACK---->| | | +... + + +
+ +
+ <varname>nopublish_flag</varname> (int) + + By default, reINVITEs will trigger a PUBLISH. They are actually + the only in-dialog request for which it makes sense. + In some cases, it does not make sense to republish a dialog state. + (e.g. when handling a B2BUA reINVITE). + This setting defines the flag that needs to be set in the request + route to prevent the generation of a PUBLISH request in case of a + specific reINVITE. + + + Set <varname>nopublish_flag</varname> parameter + +... +modparam("pua_dialoginfo", "nopublish_flag", 5) +... + + +
+
<varname>presence_server</varname> (string) @@ -323,7 +439,7 @@ modparam("pua_dialoginfo", "presence_server", "sip:ps@opensips.org:5060") Set <varname>caller_spec_param</varname> parameter ... -modparam("pua_dialoginfo", "caller_spec_param", "$avp(i:10)") +modparam("pua_dialoginfo", "caller_spec_param", "$avp(10)") ... @@ -342,7 +458,7 @@ modparam("pua_dialoginfo", "caller_spec_param", "$avp(i:10)") Set <varname>caller_spec_param</varname> parameter ... -modparam("pua_dialoginfo", "callee_spec_param", "$avp(i:11)") +modparam("pua_dialoginfo", "callee_spec_param", "$avp(11)") ... diff --git a/modules/pua_dialoginfo/pua_dialoginfo.c b/modules/pua_dialoginfo/pua_dialoginfo.c index 4e05fcd73fe..f1a4d663667 100644 --- a/modules/pua_dialoginfo/pua_dialoginfo.c +++ b/modules/pua_dialoginfo/pua_dialoginfo.c @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -60,7 +60,7 @@ #define DEFAULT_CREATED_LIFETIME 3600 -/* define PUA_DIALOGINFO_DEBUG to activate more verbose +/* define PUA_DIALOGINFO_DEBUG to activate more verbose * logging and dialog info callback debugging */ /* #define PUA_DIALOGINFO_DEBUG 1 */ @@ -87,6 +87,8 @@ static str callee_spec_param= {0, 0}; static pv_spec_t caller_spec; static pv_spec_t callee_spec; static int osips_ps = 1; +static int publish_on_trying = 0; +static int nopublish_flag = -1; /** module functions */ @@ -108,17 +110,32 @@ static param_export_t params[]={ {"include_localremote", INT_PARAM, &include_localremote }, {"include_tags", INT_PARAM, &include_tags }, {"caller_confirmed", INT_PARAM, &caller_confirmed }, + {"publish_on_trying", INT_PARAM, &publish_on_trying }, {"presence_server", STR_PARAM, &presence_server.s }, {"caller_spec_param", STR_PARAM, &caller_spec_param.s }, {"callee_spec_param", STR_PARAM, &callee_spec_param.s }, {"osips_ps", INT_PARAM, &osips_ps }, + {"nopublish_flag", INT_PARAM, &nopublish_flag }, {0, 0, 0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "pua", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "dialog", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports= { "pua_dialoginfo", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -166,7 +183,7 @@ __dialog_cbtest(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) "or missing TO hdr :-/\n"); tag.s = 0; tag.len = 0; - } else + } else tag = get_to(_params->msg)->tag_value; } else { tag = get_to(_params->msg)->tag_value; @@ -241,6 +258,7 @@ __dialog_sendpublish(struct dlg_cell *dlg, int type, struct dlg_cb_params *_para struct to_body peer_to_body; str entity_uri= {0, 0}; int buf_len = 255; + struct sip_msg* msg = _params->msg; flag_str.s = &flag; flag_str.len = 1; @@ -308,8 +326,18 @@ __dialog_sendpublish(struct dlg_cell *dlg, int type, struct dlg_cb_params *_para if(flag == DLG_PUB_AB || flag == DLG_PUB_B) dialog_publish("terminated", &peer_to_body, &from, &(dlg->callid), 0, 0, 0, 0); break; + case DLGCB_RESPONSE_WITHIN: + if (get_cseq(msg)->method_id==METHOD_INVITE) { + if (msg->flags & nopublish_flag) { + LM_DBG("nopublish flag was set for this INVITE\n"); + break; + } + LM_DBG("nopublish flag not set for this INVITE, will publish\n"); + } else { + /* no publish for non-INVITEs */ + break; + } case DLGCB_CONFIRMED: - case DLGCB_REQ_WITHIN: LM_DBG("dialog confirmed, from=%.*s\n", dlg->from_uri.len, dlg->from_uri.s); if(flag == DLG_PUB_AB || flag == DLG_PUB_A) dialog_publish("confirmed", &from, &peer_to_body, &(dlg->callid), 1, dlg->lifetime, 0, 0); @@ -384,6 +412,23 @@ __dialog_sendpublish(struct dlg_cell *dlg, int type, struct dlg_cb_params *_para free_to_params(&from); } + +static void +__dialog_loaded(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) +{ + str peer_uri= {0, 0}; + if(dlg_api.fetch_dlg_value(dlg, &peer_dlg_var, &peer_uri, 1)==0 && peer_uri.len!=0) { + /* register dialog callbacks which triggers sending PUBLISH */ + if (dlg_api.register_dlgcb(dlg, + DLGCB_FAILED| DLGCB_CONFIRMED | DLGCB_TERMINATED | DLGCB_EXPIRED | + DLGCB_RESPONSE_WITHIN | DLGCB_EARLY, + __dialog_sendpublish, 0, 0) != 0) { + LM_ERR("cannot register callback for interesting dialog types\n"); + } + } +} + + int dialoginfo_process_body(struct publ_info* publ, str** fin_body, int ver, str* tuple) { @@ -456,7 +501,7 @@ static int mod_init(void) LM_ERR("Can't bind pua\n"); return -1; } - + if (bind_pua(&pua) < 0) { LM_ERR("Can't bind pua\n"); @@ -469,6 +514,12 @@ static int mod_init(void) } pua_send_publish= pua.send_publish; + if (nopublish_flag!= -1 && nopublish_flag > MAX_FLAG) { + LM_ERR("invalid nopublish flag %d!!\n", nopublish_flag); + return -1; + } + nopublish_flag = (nopublish_flag!=-1)?(1<callid), 1, DEFAULT_CREATED_LIFETIME, 0, 0); + if(publish_on_trying) { + if(flag == DLG_PUB_A || flag == DLG_PUB_AB) + dialog_publish("trying", from, &peer_to_body, &(dlg->callid), 1, DEFAULT_CREATED_LIFETIME, 0, 0); - if(flag == DLG_PUB_B || flag == DLG_PUB_AB) - dialog_publish("trying", &peer_to_body, from, &(dlg->callid), 0, DEFAULT_CREATED_LIFETIME, 0, 0); + if(flag == DLG_PUB_B || flag == DLG_PUB_AB) + dialog_publish("trying", &peer_to_body, from, &(dlg->callid), 0, DEFAULT_CREATED_LIFETIME, 0, 0); + } ret=1; end: diff --git a/modules/pua_dialoginfo/pua_dialoginfo.h b/modules/pua_dialoginfo/pua_dialoginfo.h index 68cef729d68..817a6b82a7b 100644 --- a/modules/pua_dialoginfo/pua_dialoginfo.h +++ b/modules/pua_dialoginfo/pua_dialoginfo.h @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/pua_mi/README b/modules/pua_mi/README index f1838a1b1a0..7b3866f7135 100644 --- a/modules/pua_mi/README +++ b/modules/pua_mi/README @@ -2,8 +2,6 @@ PUA MI Anca-Maria Vamanu - voice-system.ro - Edited by Anca-Maria Vamanu @@ -12,10 +10,9 @@ Edited by Juha Heinanen - Copyright © 2006 voice-system.ro + Copyright © 2006 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/pua_mi/mi_func.c b/modules/pua_mi/mi_func.c index d4c850de8de..f545949fa77 100644 --- a/modules/pua_mi/mi_func.c +++ b/modules/pua_mi/mi_func.c @@ -17,11 +17,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #include #include #include @@ -38,11 +38,11 @@ /* * mi cmd: pua_publish - * + * * * * - body type if body of a type different from default - * event content-type or . + * event content-type or . * - ETag that publish should match or . if no ETag * - extra headers to be added to the request or . * - may not be present in case of update for expire @@ -105,7 +105,7 @@ struct mi_root* mi_pua_publish(struct mi_root* cmd, void* param) LM_ERR("invalid expires parameter\n" ); goto error; } - + exp= exp* sign; LM_DBG("expires '%d'\n", exp); @@ -196,13 +196,13 @@ struct mi_root* mi_pua_publish(struct mi_root* cmd, void* param) /* Create the publ_info_t structure */ memset(&publ, 0, sizeof(publ_info_t)); - + publ.pres_uri= &pres_uri; if(body.s) { publ.body= &body; } - + publ.event= get_event_flag(&event); if(publ.event< 0) { @@ -212,12 +212,12 @@ struct mi_root* mi_pua_publish(struct mi_root* cmd, void* param) if(content_type.len!= 1) { publ.content_type= content_type; - } - + } + if(! (etag.len== 1 && etag.s[0]== '.')) { publ.etag= &etag; - } + } publ.expires= exp; if (!(extra_headers.len == 1 && extra_headers.s[0] == '.')) { @@ -228,7 +228,7 @@ struct mi_root* mi_pua_publish(struct mi_root* cmd, void* param) { publ.source_flag= MI_ASYN_PUBLISH; publ.cb_param= (void*)cmd->async_hdl; - } + } else publ.source_flag|= MI_PUBLISH; @@ -240,10 +240,10 @@ struct mi_root* mi_pua_publish(struct mi_root* cmd, void* param) { LM_ERR("sending publish failed\n"); return init_mi_tree(500, "MI/PUBLISH failed", 17); - } + } if(result== 418) return init_mi_tree(418, "Wrong ETag", 10); - + if (cmd->async_hdl==NULL) return init_mi_tree( 202, "Accepted", 8); else @@ -264,11 +264,16 @@ int mi_publ_rpl_cback( ua_pres_t* hentity, struct sip_msg* reply) str etag; str reason= {0, 0}; - if(reply== NULL || hentity== NULL || hentity->cb_param== NULL) + if(reply== NULL || hentity== NULL) { LM_ERR("NULL parameter\n"); return -1; } + if(hentity->cb_param== NULL) + { + LM_DBG("NULL callback parameter, probably a refresh\n"); + return -1; + } if(reply== FAKED_REPLY) { statuscode= 408; @@ -282,21 +287,21 @@ int mi_publ_rpl_cback( ua_pres_t* hentity, struct sip_msg* reply) } mi_hdl = (struct mi_handler *)(hentity->cb_param); - + rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==0) goto done; - + addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%d %.*s", statuscode, reason.len, reason.s); - - + + if(statuscode== 200) { /* extract ETag and expires */ lexpire = ((exp_body_t*)reply->expires->parsed)->val; LM_DBG("lexpire= %d\n", lexpire); - + hdr = get_header_by_static_name( reply, "SIP-ETag"); if( hdr==NULL ) /* must find SIP-Etag header field in 200 OK msg*/ { @@ -304,18 +309,18 @@ int mi_publ_rpl_cback( ua_pres_t* hentity, struct sip_msg* reply) goto error; } etag= hdr->body; - + addf_mi_node_child( &rpl_tree->node, 0, "ETag", 4, "%.*s", etag.len, etag.s); - + addf_mi_node_child( &rpl_tree->node, 0, "Expires", 7, "%d", lexpire); - } + } done: - if ( statuscode >= 200) + if ( statuscode >= 200) { mi_hdl->handler_f( rpl_tree, mi_hdl, 1); } - else + else { mi_hdl->handler_f( rpl_tree, mi_hdl, 0 ); } @@ -358,7 +363,7 @@ struct mi_root* mi_pua_subscribe(struct mi_root* cmd, void* param) } if(parse_uri(pres_uri.s, pres_uri.len, &uri)<0 ) { - LM_ERR("bad uri\n"); + LM_ERR("bad uri\n"); return init_mi_tree(400, "Bad uri", 7); } @@ -373,7 +378,7 @@ struct mi_root* mi_pua_subscribe(struct mi_root* cmd, void* param) } if(parse_uri(watcher_uri.s, watcher_uri.len, &uri)<0 ) { - LM_ERR("bad uri\n"); + LM_ERR("bad uri\n"); return init_mi_tree(400, "Bad uri", 7); } @@ -402,7 +407,7 @@ struct mi_root* mi_pua_subscribe(struct mi_root* cmd, void* param) { LM_ERR("Bad expires parameter\n"); return init_mi_tree(400, "Bad expires", 11); - } + } if(expires.s[0]== '-') { sign= -1; @@ -414,19 +419,19 @@ struct mi_root* mi_pua_subscribe(struct mi_root* cmd, void* param) LM_ERR("invalid expires parameter\n" ); goto error; } - + exp= exp* sign; LM_DBG("expires '%d'\n", exp); - + memset(&subs, 0, sizeof(subs_info_t)); - + subs.pres_uri= &pres_uri; subs.watcher_uri= &watcher_uri; subs.contact= &watcher_uri; - + subs.expires= exp; subs.source_flag |= MI_SUBSCRIBE; subs.event= get_event_flag(&event); @@ -441,11 +446,11 @@ struct mi_root* mi_pua_subscribe(struct mi_root* cmd, void* param) LM_ERR("while sending subscribe\n"); goto error; } - + rpl= init_mi_tree(202, "accepted", 8); if(rpl == NULL) return 0; - + return rpl; error: diff --git a/modules/pua_mi/mi_func.h b/modules/pua_mi/mi_func.h index e07550508ab..628f2ab9c91 100644 --- a/modules/pua_mi/mi_func.h +++ b/modules/pua_mi/mi_func.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -29,4 +29,4 @@ struct mi_root* mi_pua_publish(struct mi_root* cmd, void* param); struct mi_root* mi_pua_subscribe(struct mi_root* cmd, void* param); int mi_publ_rpl_cback(ua_pres_t* hentity, struct sip_msg* reply); -#endif +#endif diff --git a/modules/pua_mi/pua_mi.c b/modules/pua_mi/pua_mi.c index 52ae112ae93..ece12b24489 100644 --- a/modules/pua_mi/pua_mi.c +++ b/modules/pua_mi/pua_mi.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -75,11 +75,23 @@ static param_export_t params[]={ {0, 0, 0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "pua", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports= { "pua_mi", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -91,14 +103,14 @@ struct module_exports exports= { destroy, /* destroy function */ child_init /* per-child init function */ }; - + /** * init module function */ static int mod_init(void) { bind_pua_t bind_pua; - + if(presence_server.s) presence_server.len = strlen(presence_server.s); @@ -108,7 +120,7 @@ static int mod_init(void) LM_ERR("Can't bind pua (check if pua module is loaded)\n"); return -1; } - + if (bind_pua(&pua) < 0) { LM_ERR("Can't bind pua\n"); @@ -127,12 +139,12 @@ static int mod_init(void) return -1; } pua_send_subscribe= pua.send_subscribe; - + if(pua.register_puacb(MI_ASYN_PUBLISH, mi_publ_rpl_cback, NULL)< 0) { LM_ERR("Could not register callback\n"); return -1; - } + } return 0; } @@ -141,10 +153,10 @@ static int child_init(int rank) { LM_DBG("child [%d] pid [%d]\n", rank, getpid()); return 0; -} +} static void destroy(void) -{ +{ LM_DBG("destroying module ...\n"); return ; diff --git a/modules/pua_mi/pua_mi.h b/modules/pua_mi/pua_mi.h index fa82bc5f9e3..64194f87517 100644 --- a/modules/pua_mi/pua_mi.h +++ b/modules/pua_mi/pua_mi.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/pua_usrloc/README b/modules/pua_usrloc/README index 7a973d1a625..3702f0b6dbe 100644 --- a/modules/pua_usrloc/README +++ b/modules/pua_usrloc/README @@ -2,16 +2,13 @@ PUA Usrloc Anca-Maria Vamanu - voice-system.ro - Edited by Anca-Maria Vamanu - Copyright © 2006 voice-system.ro + Copyright © 2006 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/pua_usrloc/pua_usrloc.c b/modules/pua_usrloc/pua_usrloc.c index 7026245f498..04c8963fcc0 100644 --- a/modules/pua_usrloc/pua_usrloc.c +++ b/modules/pua_usrloc/pua_usrloc.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -69,8 +69,8 @@ int pua_set_publish(struct sip_msg* , char*, char*); static cmd_export_t cmds[]= { - {"pua_set_publish", (cmd_function)pua_set_publish, 0, 0, 0, REQUEST_ROUTE}, - {0, 0, 0, 0, 0, 0} + {"pua_set_publish", (cmd_function)pua_set_publish, 0, 0, 0, REQUEST_ROUTE}, + {0, 0, 0, 0, 0, 0} }; static param_export_t params[]={ @@ -80,10 +80,23 @@ static param_export_t params[]={ {0, 0, 0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "pua", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "usrloc", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports= { "pua_usrloc", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -95,7 +108,7 @@ struct module_exports exports= { destroy, /* destroy function */ child_init /* per-child init function */ }; - + /** * init module function */ @@ -105,21 +118,21 @@ static int mod_init(void) bind_pua_t bind_pua; LM_DBG("initializing module ...\n"); - + if(default_domain.s == NULL ) - { + { LM_ERR("default domain parameter not set\n"); return -1; } default_domain.len= strlen(default_domain.s); - + if(pres_prefix.s == NULL ) - { + { LM_DBG("No pres_prefix configured\n"); } else pres_prefix.len= strlen(pres_prefix.s); - + if(presence_server.s) { presence_server.len= strlen(presence_server.s); @@ -154,26 +167,26 @@ static int mod_init(void) " expire\n"); return -1; } - + if(ul.register_ulcb(UL_CONTACT_UPDATE, ul_publish, 0)< 0) { LM_ERR("can not register callback for update\n"); return -1; } - + if(ul.register_ulcb(UL_CONTACT_DELETE, ul_publish, 0)< 0) { LM_ERR("can not register callback for delete\n"); return -1; } - + bind_pua= (bind_pua_t)find_export("bind_pua", 1,0); if (!bind_pua) { LM_ERR("Can't bind pua\n"); return -1; } - + if (bind_pua(&pua) < 0) { LM_ERR("Can't bind pua\n"); @@ -192,7 +205,7 @@ static int mod_init(void) return -1; } pua_send_subscribe= pua.send_subscribe; - + /* register post-script pua_unset_publish unset function */ if(register_script_cb(pua_unset_publish, POST_SCRIPT_CB|REQ_TYPE_CB, 0)<0) { @@ -208,10 +221,10 @@ static int child_init(int rank) { LM_DBG("child [%d] pid [%d]\n", rank, getpid()); return 0; -} +} static void destroy(void) -{ +{ LM_DBG("destroying module ...\n"); return ; diff --git a/modules/pua_usrloc/pua_usrloc.h b/modules/pua_usrloc/pua_usrloc.h index 6883989aab9..313920427c1 100644 --- a/modules/pua_usrloc/pua_usrloc.h +++ b/modules/pua_usrloc/pua_usrloc.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/pua_usrloc/ul_publish.c b/modules/pua_usrloc/ul_publish.c index 6a74b2fa7b2..bc03821d57d 100644 --- a/modules/pua_usrloc/ul_publish.c +++ b/modules/pua_usrloc/ul_publish.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -31,6 +31,7 @@ #include "../../parser/parse_expires.h" #include "../../parser/msg_parser.h" #include "../../str.h" +#include "../../script_cb.h" #include "../usrloc/usrloc.h" #include "../usrloc/ul_callback.h" #include "../tm/tm_load.h" @@ -48,10 +49,11 @@ int pua_set_publish(struct sip_msg* msg , char* s1, char* s2) int pua_unset_publish(struct sip_msg* msg , void* param) { pua_ul_publish= 0; - return 1; + + return SCB_RUN_ALL; } - + /* for debug purpose only */ void print_publ(publ_info_t* p) { @@ -59,11 +61,11 @@ void print_publ(publ_info_t* p) LM_DBG("uri= %.*s\n", p->pres_uri->len, p->pres_uri->s); LM_DBG("id= %.*s\n", p->id.len, p->id.s); LM_DBG("expires= %d\n", p->expires); -} +} str* build_pidf(ucontact_t* c) { - xmlDocPtr doc = NULL; + xmlDocPtr doc = NULL; xmlNodePtr root_node = NULL; xmlNodePtr tuple_node = NULL; xmlNodePtr status_node = NULL; @@ -107,7 +109,7 @@ str* build_pidf(ucontact_t* c) pres_uri.s[pres_uri.len++]= '@'; memcpy(pres_uri.s+ pres_uri.len, default_domain.s, default_domain.len); - pres_uri.len+= default_domain.len; + pres_uri.len+= default_domain.len; } pres_uri.s[pres_uri.len]= '\0'; @@ -119,7 +121,7 @@ str* build_pidf(ucontact_t* c) root_node = xmlNewNode(NULL, BAD_CAST "presence"); if(root_node==0) goto error; - + xmlDocSetRootElement(doc, root_node); xmlNewProp(root_node, BAD_CAST "xmlns", @@ -138,23 +140,23 @@ str* build_pidf(ucontact_t* c) LM_ERR("while adding child\n"); goto error; } - + status_node = xmlNewChild(tuple_node, NULL, BAD_CAST "status", NULL) ; if( status_node ==NULL) { LM_ERR("while adding child\n"); goto error; } - + basic_node = xmlNewChild(status_node, NULL, BAD_CAST "basic", BAD_CAST "open") ; - + if( basic_node ==NULL) { LM_ERR("while adding child\n"); goto error; } - + body = (str*)pkg_malloc(sizeof(str)); if(body == NULL) { @@ -218,7 +220,7 @@ void ul_publish(ucontact_t* c, int type, void* param) } else body = NULL; - + uri.s = (char*)pkg_malloc(sizeof(char)*(c->aor->len+default_domain.len+6)); if(uri.s == NULL) goto error; @@ -236,7 +238,7 @@ void ul_publish(ucontact_t* c, int type, void* param) memcpy(uri.s+ uri.len, default_domain.s, default_domain.len); uri.len+= default_domain.len; } - + LM_DBG("uri= %.*s\n", uri.len, uri.s); memset(&publ, 0, sizeof(publ_info_t)); @@ -250,7 +252,7 @@ void ul_publish(ucontact_t* c, int type, void* param) publ.expires= 0; else publ.expires= c->expires - (int)time(NULL); - + if(type & UL_CONTACT_INSERT) publ.flag= INSERT_TYPE; else @@ -291,7 +293,7 @@ void ul_publish(ucontact_t* c, int type, void* param) xmlFree(body->s); pkg_free(body); } - + if(uri.s) pkg_free(uri.s); pua_ul_publish= 0; diff --git a/modules/pua_xmpp/README b/modules/pua_xmpp/README index 6992851aa78..ab033e7107c 100644 --- a/modules/pua_xmpp/README +++ b/modules/pua_xmpp/README @@ -2,16 +2,13 @@ Presence User Agent for XMPP (Presence gateway between SIP and XMPP) Anca-Maria Vamanu - Voice Sistem SRL - Edited by Anca-Maria Vamanu Copyright © 2007 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/pua_xmpp/pidf.c b/modules/pua_xmpp/pidf.c index f55a06b5be2..cc32e5fb822 100644 --- a/modules/pua_xmpp/pidf.c +++ b/modules/pua_xmpp/pidf.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pua_xmpp/pidf.h b/modules/pua_xmpp/pidf.h index 85fe067a857..5871eeb11c4 100644 --- a/modules/pua_xmpp/pidf.h +++ b/modules/pua_xmpp/pidf.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -35,7 +35,7 @@ char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name); xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name); xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns); -xmlNodePtr xmlNodeGetNodeByName(xmlNodePtr node, const char *name, +xmlNodePtr xmlNodeGetNodeByName(xmlNodePtr node, const char *name, const char *ns); char *xmlNodeGetNodeContentByName(xmlNodePtr root, const char *name, const char *ns); diff --git a/modules/pua_xmpp/pua_xmpp.c b/modules/pua_xmpp/pua_xmpp.c index 50b25bcba65..a9582d27db3 100644 --- a/modules/pua_xmpp/pua_xmpp.c +++ b/modules/pua_xmpp/pua_xmpp.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -96,11 +96,25 @@ static param_export_t params[]={ {0, 0, 0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "xmpp", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "pua", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports= { "pua_xmpp", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -134,7 +148,7 @@ static int mod_init(void) if(presence_server.s) presence_server.len = strlen(presence_server.s); - + /* import the TM auto-loading function */ if((load_tm=(load_tm_f)find_export("load_tm", 0, 0))==NULL) { @@ -198,7 +212,7 @@ static int mod_init(void) return -1; } xmpp_notify= xmpp_api.xnotify; - + if(xmpp_api.xpacket== NULL) { LM_ERR("Could not import xnotify from xmpp\n"); @@ -208,7 +222,7 @@ static int mod_init(void) xmpp_uri_xmpp2sip = xmpp_api.uri_xmpp2sip; xmpp_uri_sip2xmpp = xmpp_api.uri_sip2xmpp; - + if(xmpp_api.register_callback== NULL) { LM_ERR("Could not import register_callback" @@ -229,7 +243,7 @@ static int mod_init(void) LM_ERR("Can't bind pua\n"); return -1; } - + if (bind_pua(&pua) < 0) { LM_ERR("Can't bind pua\n"); @@ -248,7 +262,7 @@ static int mod_init(void) return -1; } pua_send_subscribe= pua.send_subscribe; - + if(pua.is_dialog == NULL) { LM_ERR("Could not import send_subscribe\n"); @@ -260,7 +274,7 @@ static int mod_init(void) { LM_ERR("Could not register callback\n"); return -1; - } + } return 0; } @@ -283,7 +297,7 @@ static int fixup_pua_xmpp(void** param, int param_no) LM_ERR("wrong format[%s]\n",(char*)(*param)); return E_UNSPEC; } - + *param = (void*)model; return 0; } diff --git a/modules/pua_xmpp/pua_xmpp.h b/modules/pua_xmpp/pua_xmpp.h index 3bda4d511ce..94d6fd8ed15 100644 --- a/modules/pua_xmpp/pua_xmpp.h +++ b/modules/pua_xmpp/pua_xmpp.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pua_xmpp/request_winfo.c b/modules/pua_xmpp/request_winfo.c index 2651669b45e..0476c9cbe76 100644 --- a/modules/pua_xmpp/request_winfo.c +++ b/modules/pua_xmpp/request_winfo.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -61,7 +61,7 @@ int request_winfo(struct sip_msg* msg, char* uri, char* expires) LM_DBG("using user id [%.*s]\n", printbuf_len, buffer); } - } + } if(puri.user.len<=0 || puri.user.s==NULL || puri.host.len<=0 || puri.host.s==NULL) { @@ -73,13 +73,13 @@ int request_winfo(struct sip_msg* msg, char* uri, char* expires) LM_DBG("uri= %.*s:\n", uri_str.len, uri_str.s); memset(&subs, 0, sizeof(subs_info_t)); - + subs.pres_uri= &uri_str; subs.watcher_uri= &uri_str; subs.contact= &server_address; - + if(presence_server.s && presence_server.len) subs.outbound_proxy = &presence_server; @@ -90,7 +90,7 @@ int request_winfo(struct sip_msg* msg, char* uri, char* expires) else { subs.expires= -1; - + } /* -1 - for a subscription with no time limit */ /* 0 -for unsubscribe */ diff --git a/modules/pua_xmpp/request_winfo.h b/modules/pua_xmpp/request_winfo.h index d1a188da082..05c59be0bdd 100644 --- a/modules/pua_xmpp/request_winfo.h +++ b/modules/pua_xmpp/request_winfo.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pua_xmpp/simple2xmpp.c b/modules/pua_xmpp/simple2xmpp.c index 405a3e1dbee..d036fa76fcb 100644 --- a/modules/pua_xmpp/simple2xmpp.c +++ b/modules/pua_xmpp/simple2xmpp.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -72,7 +72,7 @@ int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) char buf_to[256]; memset(&dialog, 0, sizeof(ua_pres_t)); - + LM_DBG("start...\n\n"); if( parse_headers(msg,HDR_EOH_F, 0)==-1 ) @@ -103,7 +103,7 @@ int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) URI_ADD_NULL_TERM(to_uri, buf_to, dialog.watcher_uri); if (pto->tag_value.s==NULL || pto->tag_value.len==0 ) - { + { LM_ERR("to tag value not parsed\n"); goto error; } @@ -125,7 +125,7 @@ int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) if (msg->from->parsed == NULL) { /* parsing from header */ - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("ERROR cannot parse From header\n"); goto error; @@ -151,20 +151,20 @@ int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) dialog.to_tag= pfrom->tag_value; dialog.flag|= XMPP_SUBSCRIBE; - if(msg->event->body.len== 8 && + if(msg->event->body.len== 8 && (strncasecmp(msg->event->body.s,"presence",8 )==0)) event_flag|= PRESENCE_EVENT; else - if(msg->event->body.len== 14 && + if(msg->event->body.len== 14 && (strncasecmp(msg->event->body.s,"presence.winfo",14 )==0)) event_flag|= PWINFO_EVENT; else { LM_ERR("wrong event\n"); goto error; - } + } dialog.event= event_flag; - + if(pua_is_dialog(&dialog)< 0) // verify if within a stored dialog { LM_ERR("Notify in a non existing dialog\n"); @@ -175,7 +175,7 @@ int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) { body.s= NULL; body.len= 0; - } + } else { if ( get_body(msg,&body)!=0 || body.len==0) @@ -185,7 +185,7 @@ int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) } } - /* treat the two cases: event= presence & event=presence.winfo */ + /* treat the two cases: event= presence & event=presence.winfo */ if(event_flag & PRESENCE_EVENT) { LM_DBG("PRESENCE\n"); @@ -198,14 +198,14 @@ int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) LM_DBG("Received Notification with state" "terminated; reason= timeout=> don't send notification\n"); return 1; - } + } is_terminated= 1; } - + if(build_xmpp_content(&to_uri, &from_uri, &body, &id, is_terminated)< 0) { - LM_ERR("in function build_xmpp_content\n"); + LM_ERR("in function build_xmpp_content\n"); goto error; } xmlFreeDoc(doc); @@ -218,7 +218,7 @@ int Notify2Xmpp(struct sip_msg* msg, char* s1, char* s2) hdr = get_header_by_static_name( msg, "Subscription-State" ); if(hdr && strncasecmp(hdr->body.s,"terminated", 10)== 0) { - LM_DBG("Notify for presence.winfo with" + LM_DBG("Notify for presence.winfo with" " Subscription-State terminated- should not translate\n"); goto error; } @@ -288,7 +288,7 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, goto error; } if(is_terminated) - { + { attr= xmlNewProp(xmpp_root, BAD_CAST "type", BAD_CAST "unsubscribed"); if(attr== NULL) { @@ -321,7 +321,7 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, LM_ERR("while extracting 'presence' node\n"); goto error; } - + node = XMLNodeGetNodeByName(sip_root, "basic", NULL); if(node== NULL) { @@ -361,11 +361,11 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, } node= XMLNodeGetNodeByName(node, "note", NULL); if(node== NULL) - { + { LM_DBG("Person node has no note node\n"); goto done; - } - } + } + } note= (char*)xmlNodeGetContent(node); if(note== NULL) { @@ -381,7 +381,7 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, { LM_ERR("while adding node show: away\n"); goto error; - } + } } else if(xmlStrcasecmp((unsigned char*)note, (unsigned char*)"busy")== 0) @@ -392,7 +392,7 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, { LM_ERR("while adding node show: away\n"); goto error; - } + } } /* @@ -403,9 +403,9 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, { LM_ERR("while adding node show: chat\n"); goto error; - } + } } - else + else if(xmlStrcasecmp((unsigned char*)note, (unsigned char*)"idle")== 0) { new_node = xmlNewChild(xmpp_root, NULL, BAD_CAST "show", BAD_CAST "idle"); @@ -413,9 +413,9 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, { LM_ERR("while adding node: idle\n"); goto error; - } + } } - else */ + else */ if((xmlStrcasecmp((unsigned char*)note, (unsigned char*)"dnd")== 0)|| (xmlStrcasecmp((unsigned char*)note, @@ -427,18 +427,18 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, { LM_ERR("while adding node show: dnd\n"); goto error; - } + } } - + /* adding status node */ new_node = xmlNewChild(xmpp_root, NULL, BAD_CAST "status", BAD_CAST note); if(new_node== NULL) { LM_ERR("while adding node status\n"); goto error; - } - + } + xmlFree(note); note= NULL; @@ -474,7 +474,7 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, LM_ERR("while adding creating new buffer\n"); goto error; } - + xmpp_msg.len= xmlNodeDump(buffer, doc, xmpp_root, 1,1); if(xmpp_msg.len== -1) { @@ -487,7 +487,7 @@ int build_xmpp_content(str* to_uri, str* from_uri, str* body, str* id, LM_ERR("while extracting buffer content\n"); goto error; } - + LM_DBG("xmpp_msg: %.*s\n",xmpp_msg.len, xmpp_msg.s); if( xmpp_notify(from_uri, to_uri, &xmpp_msg, id)< 0) { @@ -547,11 +547,11 @@ int winfo2xmpp(str* to_uri, str* body, str* id) LM_ERR("while extracting 'presence' node\n"); goto error; } - + node = XMLNodeGetNodeByName(pidf_root, "watcher", NULL); for (; node!=NULL; node = node->next) - { + { if( xmlStrcasecmp(node->name,(unsigned char*)"watcher")) continue; @@ -612,7 +612,7 @@ int winfo2xmpp(str* to_uri, str* body, str* id) LM_ERR("while adding creating new buffer\n"); goto error; } - + xmpp_msg.len= xmlNodeDump(buffer, doc, root_node, 1,1); if(xmpp_msg.len== -1) { @@ -625,9 +625,9 @@ int winfo2xmpp(str* to_uri, str* body, str* id) LM_ERR("while extracting buffer content\n"); goto error; } - + LM_DBG("xmpp_msg: %.*s\n",xmpp_msg.len, xmpp_msg.s); - + if( xmpp_subscribe(&from_uri, to_uri, &xmpp_msg, id)< 0) { LM_ERR("while sending xmpp_subscribe\n"); @@ -656,7 +656,7 @@ int winfo2xmpp(str* to_uri, str* body, str* id) xmlBufferFree(buffer); xmlCleanupParser(); xmlMemoryDump(); - + return -1; } @@ -670,7 +670,7 @@ char* get_error_reason(int code, str* reason) LM_ERR("no more memory\n"); return NULL; } - + switch( code ) { case 300: { strcpy(err_cond, "redirect"); break;} @@ -718,10 +718,10 @@ char* get_error_reason(int code, str* reason) } return err_cond; -} +} -int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) +int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) { /* named according to the direction of the message in xmpp*/ str from_uri; @@ -734,7 +734,7 @@ int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) str reason; char* err_reason= NULL; xmlBufferPtr buffer= NULL; - char buf_to[256]; + char buf_to[256]; LM_DBG("*** Entered the callback\n"); @@ -750,9 +750,9 @@ int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) doc= xmlNewDoc(BAD_CAST "1.0"); if(doc==0) goto error; - + root_node = xmlNewNode(NULL, BAD_CAST "presence"); - + if(root_node==0) goto error; xmlDocSetRootElement(doc, root_node); @@ -793,7 +793,7 @@ int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) LM_ERR("couldn't get response phrase\n"); goto error; } - + attr= xmlNewProp(root_node, BAD_CAST "type", BAD_CAST "error"); if(attr== NULL) { @@ -805,15 +805,15 @@ int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) { LM_ERR("while adding new node\n"); goto error; - } + } node= xmlNewChild(node, 0, BAD_CAST err_reason, 0 ); if(node== NULL) { LM_ERR("while adding new node\n"); goto error; - } + } - attr= xmlNewProp(node, BAD_CAST "xmlns", + attr= xmlNewProp(node, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:xmpp-stanzas"); if(attr== NULL) { @@ -838,7 +838,7 @@ int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) LM_ERR("while adding creating new buffer\n"); goto error; } - + xmpp_msg.len= xmlNodeDump(buffer, doc, root_node, 1,1); if(xmpp_msg.len== -1) { @@ -851,10 +851,10 @@ int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) LM_ERR("while extracting buffer content\n"); goto error; } - + LM_DBG("xmpp_msg: %.*s\n",xmpp_msg.len, xmpp_msg.s); - + if(xmpp_packet(&from_uri, &to_uri, &xmpp_msg, &hentity->to_tag)< 0) { LM_ERR("while sending xmpp_reply_to_subscribe\n"); @@ -863,7 +863,7 @@ int Sipreply2Xmpp(ua_pres_t* hentity, struct sip_msg * msg) if(err_reason) pkg_free(err_reason); xmlFreeDoc(doc); - + return 0; error: diff --git a/modules/pua_xmpp/simple2xmpp.h b/modules/pua_xmpp/simple2xmpp.h index 453fbe188b3..2ac7a330bf8 100644 --- a/modules/pua_xmpp/simple2xmpp.h +++ b/modules/pua_xmpp/simple2xmpp.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/pua_xmpp/xmpp2simple.c b/modules/pua_xmpp/xmpp2simple.c index ff793eb782c..c031a11e460 100644 --- a/modules/pua_xmpp/xmpp2simple.c +++ b/modules/pua_xmpp/xmpp2simple.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -44,7 +44,7 @@ int build_publish(xmlNodePtr pres_node, int expire); int presence_subscribe(xmlNodePtr pres_node, int expires, int flag); /* the function registered as a callback in xmpp, - * to be called when a new message with presence type is received + * to be called when a new message with presence type is received * */ void pres_Xmpp2Sip(char *msg, int type, void *param) @@ -93,15 +93,15 @@ void pres_Xmpp2Sip(char *msg, int type, void *param) goto error; } - } + } else - if((strcmp(pres_type, "subscribe")==0)|| + if((strcmp(pres_type, "subscribe")==0)|| ( strcmp(pres_type, "unsubscribe")== 0)|| (strcmp(pres_type, "probe")== 0)) { - if(strcmp(pres_type, "subscribe")==0 || + if(strcmp(pres_type, "subscribe")==0 || strcmp(pres_type, "probe")== 0) - { + { LM_DBG("send Subscribe message (no time limit)\n"); if(presence_subscribe(pres_node, -1, XMPP_INITIAL_SUBS)< 0) @@ -110,10 +110,10 @@ void pres_Xmpp2Sip(char *msg, int type, void *param) xmlFree(pres_type); goto error; } - } + } if(strcmp(pres_type, "unsubscribe")== 0) { - if(presence_subscribe(pres_node, 0, + if(presence_subscribe(pres_node, 0, XMPP_INITIAL_SUBS)< 0) { LM_ERR("when unsubscribing for presence"); @@ -124,7 +124,7 @@ void pres_Xmpp2Sip(char *msg, int type, void *param) } xmlFree(pres_type); - // else + // else // send_reply_message(pres_node); xmlFreeDoc(doc); @@ -156,7 +156,7 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) entity=(char*)pkg_malloc(7+ strlen(uri)*sizeof(char)); if(entity== NULL) - { + { LM_ERR("no more memory\n"); goto error; } @@ -188,7 +188,7 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) xmlNewProp(root_node, BAD_CAST "xmlns:c", BAD_CAST "urn:ietf:params:xml:ns:pidf:cipid"); xmlNewProp(root_node, BAD_CAST "entity", BAD_CAST entity); - + tuple_node =xmlNewChild(root_node, NULL, BAD_CAST "tuple", NULL) ; if( tuple_node ==NULL) { @@ -228,7 +228,7 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) /*if no type present search for suplimentary information */ status_cont= XMLNodeGetNodeContentByName(pres_node, "status", NULL); show_cont= XMLNodeGetNodeContentByName(pres_node, "show", NULL); - + if(show_cont) { if(strcmp(show_cont, "xa")== 0) @@ -263,7 +263,7 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) }else if(show_cont) { - node = xmlNewChild(root_node, NULL, BAD_CAST "note", + node = xmlNewChild(root_node, NULL, BAD_CAST "note", BAD_CAST status); if(node== NULL) { @@ -276,7 +276,7 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) { LM_DBG("show_cont= %s\n", show_cont); if(person_node== NULL) - { + { person_node= xmlNewChild(root_node, NULL, BAD_CAST "person",0 ); if(person_node== NULL) { @@ -284,7 +284,7 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) goto error; } } - node= xmlNewChild(person_node, NULL, BAD_CAST "activities", + node= xmlNewChild(person_node, NULL, BAD_CAST "activities", BAD_CAST 0); if(node== NULL) { @@ -292,8 +292,8 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) goto error; } - - if( xmlNewChild(person_node, NULL, BAD_CAST "note", + + if( xmlNewChild(person_node, NULL, BAD_CAST "note", BAD_CAST status )== NULL) { LM_ERR("while adding node\n"); @@ -302,9 +302,9 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) } - - -done: + + +done: body= (str* )pkg_malloc(sizeof(str)); if(body== NULL) { @@ -322,7 +322,7 @@ str* build_pidf(xmlNodePtr pres_node, char* uri, char* resource) if(type) xmlFree(type); xmlFreeDoc(doc); - + return body; error: @@ -445,7 +445,7 @@ int presence_subscribe(xmlNodePtr pres_node, int expires,int flag) str from_uri= {0, 0}; char buf_from[256]; - uri= XMLNodeGetAttrContentByName(pres_node, "to"); + uri= XMLNodeGetAttrContentByName(pres_node, "to"); if(uri== NULL) { LM_ERR("failed to get to attribute from xml doc\n"); @@ -458,17 +458,17 @@ int presence_subscribe(xmlNodePtr pres_node, int expires,int flag) goto error; } xmlFree(uri); - + uri= XMLNodeGetAttrContentByName(pres_node, "from"); if(uri == NULL) { LM_ERR("failed to get from attribute from xml doc\n"); goto error; } - + ENC_SIP_URI(from_uri, buf_from, uri); xmlFree(uri); - + memset(&subs, 0, sizeof(subs_info_t)); subs.pres_uri= &to_uri; @@ -480,7 +480,7 @@ int presence_subscribe(xmlNodePtr pres_node, int expires,int flag) type= XMLNodeGetAttrContentByName(pres_node, "type" ); if(strcmp(type, "subscribe")==0 ||strcmp(type, "probe")== 0) subs->flag|= INSERT_TYPE; - else + else if(strcmp(type, "unsubscribe")== 0) subs->flag|= UPDATE_TYPE; xmlFree(type); @@ -490,11 +490,11 @@ int presence_subscribe(xmlNodePtr pres_node, int expires,int flag) subs.source_flag|= flag; subs.event= PRESENCE_EVENT; subs.expires= expires; - + if(presence_server.s && presence_server.len) subs.outbound_proxy = &presence_server; - LM_DBG("XMPP subscription to [%.*s] , from [%.*s], expires= [%d]\n", + LM_DBG("XMPP subscription to [%.*s] , from [%.*s], expires= [%d]\n", subs.pres_uri->len, subs.pres_uri->s, subs.watcher_uri->len, subs.watcher_uri->s, expires); if(subs.outbound_proxy) diff --git a/modules/pua_xmpp/xmpp2simple.h b/modules/pua_xmpp/xmpp2simple.h index db9b5336aba..8b408a9efc6 100644 --- a/modules/pua_xmpp/xmpp2simple.h +++ b/modules/pua_xmpp/xmpp2simple.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/python/python_mod.c b/modules/python/python_mod.c index 49ecf8da692..e6d37ad6f9c 100644 --- a/modules/python/python_mod.c +++ b/modules/python/python_mod.c @@ -67,8 +67,10 @@ static cmd_export_t cmds[] = { /** module exports */ struct module_exports exports = { "python", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, RTLD_NOW | RTLD_GLOBAL, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ diff --git a/modules/qos/README b/modules/qos/README index 19a2c656f0c..1e7a2583c6f 100644 --- a/modules/qos/README +++ b/modules/qos/README @@ -10,8 +10,7 @@ Ovidiu Sas Copyright © 2008 SOMA Networks, Inc. Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/qos/qos.c b/modules/qos/qos.c index efb33590e4e..fd37a2b9a9a 100644 --- a/modules/qos/qos.c +++ b/modules/qos/qos.c @@ -68,11 +68,22 @@ static param_export_t mod_params[]={ { 0,0,0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "dialog", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; struct module_exports exports= { "qos", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ mod_params, /* param exports */ 0, /* exported statistics */ @@ -99,16 +110,16 @@ int load_qos( struct qos_binds *qosb) * Bind to the dialog module and setup the callbacks. Also initialize * the shared memory to store our interninal information in. */ -static int mod_init(void) +static int mod_init(void) { - fix_flag_name(&qos_flag_str, qos_flag); + fix_flag_name(qos_flag_str, qos_flag); qos_flag = get_flag_id_by_name(FLAG_TYPE_MSG, qos_flag_str); if (qos_flag == -1) { LM_ERR("no qos flag set!!\n"); return -1; - } + } else if (qos_flag > MAX_FLAG) { LM_ERR("invalid qos flag %d!!\n", qos_flag); return -1; diff --git a/modules/qos/qos_cb.c b/modules/qos/qos_cb.c index 9955e474d8e..b81092dd515 100644 --- a/modules/qos/qos_cb.c +++ b/modules/qos/qos_cb.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/qos/qos_cb.h b/modules/qos/qos_cb.h index aa3d0dc5e73..00ca6974b86 100644 --- a/modules/qos/qos_cb.h +++ b/modules/qos/qos_cb.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/qos/qos_ctx_helpers.c b/modules/qos/qos_ctx_helpers.c index 13b0a2de66a..0e4337ba1a9 100644 --- a/modules/qos/qos_ctx_helpers.c +++ b/modules/qos/qos_ctx_helpers.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/qos/qos_ctx_helpers.h b/modules/qos/qos_ctx_helpers.h index fa7c7d159cb..a00799e4d68 100644 --- a/modules/qos/qos_ctx_helpers.h +++ b/modules/qos/qos_ctx_helpers.h @@ -56,7 +56,7 @@ typedef struct qos_ctx_st { } qos_ctx_t; /* - + ** AFTER INVITE/183 ** qos_ctx: @@ -67,7 +67,7 @@ typedef struct qos_ctx_st { +----------------+ | *prev | +----------------+ | *next | - +----------------+ + +----------------+ | method_dir | sdp_session (caller) | method_id | +-->+----------+ | method | | | | @@ -89,7 +89,7 @@ typedef struct qos_ctx_st { +----------------+ | *prev | | *pending_sdp | +----------------+ +----------------+ | *next | - +----------------+ + +----------------+ | method_dir | sdp_session (caller) | method_id | +-->+----------+ | method | | | | diff --git a/modules/qos/qos_load.h b/modules/qos/qos_load.h index 643a09b973e..10008c8256e 100644 --- a/modules/qos/qos_load.h +++ b/modules/qos/qos_load.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/qos/qos_mi.c b/modules/qos/qos_mi.c index 362b4aaf8c3..0647c025b68 100644 --- a/modules/qos/qos_mi.c +++ b/modules/qos/qos_mi.c @@ -68,16 +68,16 @@ int add_mi_stream_nodes(struct mi_node* node, int index, sdp_stream_cell_t* stre int i, len; p = int2str((unsigned long)(index), &len); - node1 = add_mi_node_child( node, MI_DUP_VALUE, "stream", 6, p, len); + node1 = add_mi_node_child( node, MI_IS_ARRAY|MI_DUP_VALUE, "stream", 6, p, len); if (node1==NULL) return 1; - + attr = add_mi_attr(node1, MI_DUP_VALUE, "media", 5, stream->media.s, stream->media.len); - if(attr == NULL) - return 1; + if(attr == NULL) + return 1; attr = add_mi_attr(node1, MI_DUP_VALUE, "IP", 2, stream->ip_addr.s, stream->ip_addr.len); - if(attr == NULL) + if(attr == NULL) return 1; attr = add_mi_attr(node1, MI_DUP_VALUE, "port", 4, stream->port.s, stream->port.len); @@ -130,12 +130,14 @@ int add_mi_session_nodes(struct mi_node* node, int index, sdp_session_cell_t* se switch (index) { case 0: - node1 = add_mi_node_child( node, MI_DUP_VALUE, "session", 7, "caller", 6); + node1 = add_mi_node_child( node, MI_IS_ARRAY|MI_DUP_VALUE, + "session", 7, "caller", 6); if (node1==NULL) return 1; break; case 1: - node1 = add_mi_node_child( node, MI_DUP_VALUE, "session", 7, "callee", 6); + node1 = add_mi_node_child( node, MI_IS_ARRAY|MI_DUP_VALUE, + "session", 7, "callee", 6); if (node1==NULL) return 1; break; @@ -155,7 +157,7 @@ int add_mi_session_nodes(struct mi_node* node, int index, sdp_session_cell_t* se if(attr == NULL) return 1; - p = int2str((unsigned long)(session->streams_num), &len); + p = int2str((unsigned long)(session->streams_num), &len); attr = add_mi_attr(node1, MI_DUP_VALUE, "streams", 7, p, len); if(attr == NULL) return 1; @@ -186,7 +188,7 @@ int add_mi_sdp_nodes(struct mi_node* node, qos_sdp_t* qos_sdp) if ( qos_sdp->prev != NULL ) LM_ERR("got qos_sdp->prev=%p\n", qos_sdp->prev); while (qos_sdp) { - node1 = add_mi_node_child( node, MI_DUP_VALUE, "sdp", 3, NULL, 0); + node1 = add_mi_node_child( node, MI_IS_ARRAY|MI_DUP_VALUE, "sdp", 3, NULL, 0); if (node1==NULL) return 1; @@ -235,7 +237,8 @@ void qos_dialog_mi_context_CB(struct dlg_cell* did, int type, struct dlg_cb_para qos_sdp = qos_ctx->pending_sdp; if (qos_sdp) { - node = add_mi_node_child(parent_node, MI_DUP_VALUE, "qos", 3, "pending_sdp", 11); + node = add_mi_node_child(parent_node, MI_IS_ARRAY|MI_DUP_VALUE, + "qos_pending_sdp", 15, NULL, 0); if (node==NULL) { LM_ERR("oom\n"); return; @@ -248,7 +251,8 @@ void qos_dialog_mi_context_CB(struct dlg_cell* did, int type, struct dlg_cb_para qos_sdp = qos_ctx->negotiated_sdp; if (qos_sdp) { - node = add_mi_node_child(parent_node, MI_DUP_VALUE, "qos", 3, "negotiated_sdp", 14); + node = add_mi_node_child(parent_node, MI_IS_ARRAY|MI_DUP_VALUE, + "qos_negotiated_sdp", 18, NULL, 0); if (node==NULL) { LM_ERR("oom\n"); return; diff --git a/modules/ratelimit/README b/modules/ratelimit/README index cf1f19c3bc1..ad7e03f1c44 100644 --- a/modules/ratelimit/README +++ b/modules/ratelimit/README @@ -30,8 +30,7 @@ Razvan Crainea Copyright © 2011 OpenSIPS Foundation Revision History - Revision $Revision: 5901 $ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/ratelimit/ratelimit.c b/modules/ratelimit/ratelimit.c index e4c9f49ad64..9df4525c436 100644 --- a/modules/ratelimit/ratelimit.c +++ b/modules/ratelimit/ratelimit.c @@ -18,15 +18,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * --------- * * 2008-01-10 ported from SER project (osas) - * 2008-01-16 ported enhancements from openims project (osas) + * 2008-01-16 ported enhancements from openims project (osas) */ #include @@ -104,13 +104,13 @@ static cmd_export_t cmds[] = { fixup_rl_check, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE| BRANCH_ROUTE|ERROR_ROUTE|LOCAL_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"rl_check", (cmd_function)w_rl_check_3, 3, - fixup_rl_check, 0, REQUEST_ROUTE|LOCAL_ROUTE|ONREPLY_ROUTE| + fixup_rl_check, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE| BRANCH_ROUTE|ERROR_ROUTE|LOCAL_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"rl_dec_count", (cmd_function)w_rl_dec, 1, - fixup_spve_null, 0, REQUEST_ROUTE|LOCAL_ROUTE|ONREPLY_ROUTE| + fixup_spve_null, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE| BRANCH_ROUTE|ERROR_ROUTE|LOCAL_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {"rl_reset_count", (cmd_function)w_rl_reset, 1, - fixup_spve_null, 0, REQUEST_ROUTE|LOCAL_ROUTE|ONREPLY_ROUTE| + fixup_spve_null, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE| BRANCH_ROUTE|ERROR_ROUTE|LOCAL_ROUTE|TIMER_ROUTE|EVENT_ROUTE}, {0,0,0,0,0,0} }; @@ -142,8 +142,10 @@ static mi_export_t mi_cmds [] = { struct module_exports exports= { "ratelimit", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, params, 0, /* exported statistics */ @@ -160,7 +162,7 @@ struct module_exports exports= { /* not using /proc/loadavg because it only works when our_timer_interval == theirs */ int get_cpuload(void) { - static + static long long o_user, o_nice, o_sys, o_idle, o_iow, o_irq, o_sirq, o_stl; long long n_user, n_nice, n_sys, n_idle, n_iow, n_irq, n_sirq, n_stl; static int first_time = 1; @@ -181,29 +183,29 @@ int get_cpuload(void) if (first_time) { first_time = 0; *rl_load_value = 0; - } else { - long long d_total = (n_user - o_user) + - (n_nice - o_nice) + - (n_sys - o_sys) + - (n_idle - o_idle) + - (n_iow - o_iow) + - (n_irq - o_irq) + - (n_sirq - o_sirq) + + } else { + long long d_total = (n_user - o_user) + + (n_nice - o_nice) + + (n_sys - o_sys) + + (n_idle - o_idle) + + (n_iow - o_iow) + + (n_irq - o_irq) + + (n_sirq - o_sirq) + (n_stl - o_stl); long long d_idle = (n_idle - o_idle); *rl_load_value = 1.0 - ((double)d_idle) / (double)d_total; } - o_user = n_user; - o_nice = n_nice; - o_sys = n_sys; - o_idle = n_idle; - o_iow = n_iow; - o_irq = n_irq; - o_sirq = n_sirq; + o_user = n_user; + o_nice = n_nice; + o_sys = n_sys; + o_idle = n_idle; + o_iow = n_iow; + o_irq = n_irq; + o_sirq = n_sirq; o_stl = n_stl; - + return 0; } @@ -228,8 +230,8 @@ void do_update_load(void) dif_err = err - last_err; /* - * TODO?: the 'if' is needed so low cpu loads for - * long periods (which can't be compensated by + * TODO?: the 'if' is needed so low cpu loads for + * long periods (which can't be compensated by * negative drop rates) don't confuse the controller * * NB: - "err < 0" means "desired_cpuload < actual_cpuload" @@ -238,8 +240,8 @@ void do_update_load(void) if (int_err < 0 || err < 0) int_err += err; - output = (*pid_kp) * err + - (*pid_ki) * int_err + + output = (*pid_kp) * err + + (*pid_ki) * int_err + (*pid_kd) * dif_err; last_err = err; @@ -270,7 +272,7 @@ static int mod_init(void) unsigned int n; LM_INFO("Ratelimit module - initializing ...\n"); - + if (rl_timer_interval < 0) { LM_ERR("invalid timer interval\n"); return -1; @@ -384,11 +386,11 @@ void mod_destroy(void) /* this is here to avoid using rand() ... which doesn't _always_ return * exactly what we want (see NOTES section in 'man 3 rand') */ -int hash[100] = {18, 50, 51, 39, 49, 68, 8, 78, 61, 75, 53, 32, 45, 77, 31, - 12, 26, 10, 37, 99, 29, 0, 52, 82, 91, 22, 7, 42, 87, 43, 73, 86, 70, - 69, 13, 60, 24, 25, 6, 93, 96, 97, 84, 47, 79, 64, 90, 81, 4, 15, 63, - 44, 57, 40, 21, 28, 46, 94, 35, 58, 11, 30, 3, 20, 41, 74, 34, 88, 62, - 54, 33, 92, 76, 85, 5, 72, 9, 83, 56, 17, 95, 55, 80, 98, 66, 14, 16, +int hash[100] = {18, 50, 51, 39, 49, 68, 8, 78, 61, 75, 53, 32, 45, 77, 31, + 12, 26, 10, 37, 99, 29, 0, 52, 82, 91, 22, 7, 42, 87, 43, 73, 86, 70, + 69, 13, 60, 24, 25, 6, 93, 96, 97, 84, 47, 79, 64, 90, 81, 4, 15, 63, + 44, 57, 40, 21, 28, 46, 94, 35, 58, 11, 30, 3, 20, 41, 74, 34, 88, 62, + 54, 33, 92, 76, 85, 5, 72, 9, 83, 56, 17, 95, 55, 80, 98, 66, 14, 16, 38, 71, 23, 2, 67, 36, 65, 27, 1, 19, 59, 89, 48}; @@ -431,6 +433,7 @@ struct mi_root* mi_stats(struct mi_root* cmd_tree, void* param) { struct mi_root *rpl_tree; struct mi_node *node=NULL, *rpl=NULL; + struct mi_attr *attr; int len; char * p; @@ -440,15 +443,19 @@ struct mi_root* mi_stats(struct mi_root* cmd_tree, void* param) if (rpl_tree==0) return 0; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; if (rl_stats(rpl_tree, &node->value)) { LM_ERR("cannoti mi print values\n"); goto free; } + if (!(node = add_mi_node_child(rpl, 0, "PIPE", 4, NULL, 0))) + goto free; + LOCK_GET(rl_lock); p = int2str((unsigned long)(*drop_rate), &len); - if (!(node = add_mi_node_child(rpl, MI_DUP_VALUE, "DROP_RATE", 9, p, len))) { + if (!(attr = add_mi_attr(node, MI_DUP_VALUE, "drop_rate", 9, p, len))) { LOCK_RELEASE(rl_lock); goto free; } diff --git a/modules/ratelimit/ratelimit_helper.c b/modules/ratelimit/ratelimit_helper.c index ae85ba3431b..487d6092ae6 100644 --- a/modules/ratelimit/ratelimit_helper.c +++ b/modules/ratelimit/ratelimit_helper.c @@ -105,12 +105,31 @@ static inline int rl_set_name(str * name) static int rl_change_counter(str *name, rl_pipe_t *pipe, int c) { int new_counter; + int ret; if (rl_set_name(name) < 0) return -1; - if (cdbf.add(cdbc, &rl_name_buffer, c ? c : -(pipe->my_counter), - rl_expire_time, &new_counter) < 0){ + if (pipe->my_counter + c < 0) { + LM_DBG("Counter going negative\n"); + return 1; + } + + if (c) { + if (c < 0) + ret = cdbf.sub(cdbc, &rl_name_buffer, -c, rl_expire_time, &new_counter); + else + ret = cdbf.add(cdbc, &rl_name_buffer, c, rl_expire_time, &new_counter); + } else { + if (pipe->my_counter) { + ret = cdbf.sub(cdbc, &rl_name_buffer, pipe->my_counter, rl_expire_time, + &new_counter); + } else { + ret = cdbf.get_counter(cdbc, &rl_name_buffer, &new_counter); + } + } + + if (ret < 0) { LM_ERR("cannot change counter for pipe %.*s with %d\n", name->len, name->s, c); return -1; @@ -213,7 +232,7 @@ int init_rl_table(unsigned int size) LM_DBG("default algorithm is %.*s [ %d ]\n", rl_default_algo_s.len, rl_default_algo_s.s, rl_default_algo); - /* if at least 25% of the size locks can't be alocated + /* if at least 25% of the size locks can't be allocated * we return an error */ for ( i = size; i > size / 4; i--) { rl_htable.locks = lock_set_alloc(i); @@ -388,7 +407,7 @@ int w_rl_check_3(struct sip_msg *_m, char *_n, char *_l, char *_a) LM_DBG("Pipe %.*s counter:%d load:%d limit:%d should %sbe blocked (%p)\n", name.len, name.s, (*pipe)->counter, (*pipe)->load, (*pipe)->limit, ret == 1? "NOT " : "", *pipe); - + release: RL_RELEASE_LOCK(hash_idx); @@ -408,6 +427,7 @@ void rl_timer(unsigned int ticks, void *param) map_iterator_t it, del; rl_pipe_t **pipe; str *key; + void *value; unsigned long now = time(0); /* get CPU load */ @@ -450,10 +470,8 @@ void rl_timer(unsigned int ticks, void *param) if ((*pipe)->last_used + rl_expire_time < now) { /* this pipe is engaged in a transaction */ del = it; - if (iterator_prev(&it) < 0) { - LM_DBG("cannot find previous iterator\n"); - goto next_pipe; - } + if (iterator_next(&it) < 0) + LM_DBG("cannot find next iterator\n"); if ((*pipe)->algo == PIPE_ALGO_NETWORK) { lock_get(rl_lock); (*rl_network_count)--; @@ -461,17 +479,16 @@ void rl_timer(unsigned int ticks, void *param) } LM_DBG("Deleting ratelimit pipe key \"%.*s\"\n", key->len, key->s); - if (*pipe != iterator_delete(&del)) { - LM_ERR("error while deleting key\n"); - } + value = iterator_delete(&del); /* free resources */ - shm_free(*pipe); + if (value) + shm_free(value); + continue; } else { /* leave the lock if a cachedb query should be done*/ if (RL_USE_CDB(*pipe)) { if (rl_get_counter(key, *pipe) < 0) { LM_ERR("cannot get pipe counter\n"); - RL_GET_LOCK(i); goto next_pipe; } } @@ -481,7 +498,7 @@ void rl_timer(unsigned int ticks, void *param) (*pipe)->load = (*rl_network_load > (*pipe)->limit) ? -1 : 1; break; - + case PIPE_ALGO_RED: if ((*pipe)->limit && rl_timer_interval) (*pipe)->load = (*pipe)->counter / @@ -494,7 +511,6 @@ void rl_timer(unsigned int ticks, void *param) if (RL_USE_CDB(*pipe)) { if (rl_change_counter(key, *pipe, 0) < 0) { LM_ERR("cannot reset counter\n"); - RL_GET_LOCK(i); } } else { (*pipe)->counter = 0; @@ -645,8 +661,8 @@ int w_rl_set_count(str key, int val) goto release; } } else { - if (val && val < (*pipe)->counter) { - (*pipe)->counter -= val; + if (val && (val + (*pipe)->counter >= 0)) { + (*pipe)->counter += val; } else { (*pipe)->counter = 0; } diff --git a/modules/regex/README b/modules/regex/README index 45c7de5e98c..00b32b708c0 100644 --- a/modules/regex/README +++ b/modules/regex/README @@ -12,8 +12,7 @@ Iñaki Baz Castillo Copyright © 2009 Iñaki Baz Castillo Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/regex/regex_mod.c b/modules/regex/regex_mod.c index ae3a6c35661..4ade924346e 100644 --- a/modules/regex/regex_mod.c +++ b/modules/regex/regex_mod.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -159,8 +159,10 @@ static mi_export_t mi_cmds[] = { */ struct module_exports exports = { "regex", /*!< module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /*!< dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /*!< exported functions */ params, /*!< exported parameters */ 0, /*!< exported statistics */ @@ -180,9 +182,9 @@ struct module_exports exports = { */ static int mod_init(void) { - + LM_INFO("initializing module...\n"); - + /* Group matching feature */ if (file == NULL) { LM_NOTICE("'file' parameter is not set, group matching disabled\n"); @@ -198,7 +200,7 @@ static int mod_init(void) lock_dealloc(reload_lock); goto err; } - + /* PCRE options */ if (pcre_caseless != 0) { LM_DBG("PCRE CASELESS enabled\n"); @@ -217,19 +219,19 @@ static int mod_init(void) pcre_options = pcre_options | PCRE_EXTENDED; } LM_DBG("PCRE options: %i\n", pcre_options); - + /* Pointer to pcres */ if ((pcres_addr = shm_malloc(sizeof(pcre **))) == 0) { LM_ERR("no memory for pcres_addr\n"); goto err; } - + /* Integer containing the number of pcres */ if ((num_pcres = shm_malloc(sizeof(int))) == 0) { LM_ERR("no memory for num_pcres\n"); goto err; } - + /* Load the pcres */ LM_NOTICE("loading pcres...\n"); if (load_pcres(START)) { @@ -237,9 +239,9 @@ static int mod_init(void) goto err; } } - + return 0; - + err: free_shared_memory(); return -1; @@ -247,7 +249,7 @@ static int mod_init(void) static void destroy(void) -{ +{ free_shared_memory(); } @@ -266,15 +268,15 @@ static int load_pcres(int action) int pcre_erroffset; int num_pcres_tmp = 0; pcre **pcres_tmp = NULL; - + /* Get the lock */ lock_get(reload_lock); - + if (!(f = fopen(file, "r"))) { LM_ERR("could not open file '%s'\n", file); goto err; } - + /* Array containing each pattern in the file */ if ((patterns = pkg_malloc(sizeof(char*) * max_groups)) == 0) { LM_ERR("no more memory for patterns\n"); @@ -292,25 +294,25 @@ static int load_pcres(int action) } memset(patterns[i], '\0', group_max_size); } - + /* Read the file and extract the patterns */ memset(line, '\0', FILE_MAX_LINE); i = -1; while (fgets(line, FILE_MAX_LINE, f) != NULL) { - + /* Ignore comments and lines starting by space, tab, CR, LF */ if(isspace(line[0]) || line[0]=='#') { memset(line, '\0', FILE_MAX_LINE); continue; } - + /* First group */ if (i == -1 && line[0] != '[') { LM_ERR("first group must be initialized with [0] before any regular expression\n"); fclose(f); goto err; } - + /* New group */ if (line[0] == '[') { i++; @@ -325,14 +327,14 @@ static int load_pcres(int action) memset(line, '\0', FILE_MAX_LINE); continue; } - + /* Check if the patter size is too big (aprox) */ if (strlen(patterns[i]) + strlen(line) >= group_max_size - 2) { LM_ERR("pattern max file exceded\n"); fclose(f); goto err; } - + /* Append ')' at the end of the line */ if (line[strlen(line) - 1] == '\n') { line[strlen(line)] = line[strlen(line) - 1]; @@ -341,22 +343,22 @@ static int load_pcres(int action) /* This is the last char in the file and it's not \n */ line[strlen(line)] = ')'; } - + /* Append '(' at the beginning of the line */ memcpy(patterns[i]+strlen(patterns[i]), "(", 1); - + /* Append the line to the current pattern */ memcpy(patterns[i]+strlen(patterns[i]), line, strlen(line)); - + memset(line, '\0', FILE_MAX_LINE); } num_pcres_tmp = i + 1; - + fclose(f); - + /* Fix the patterns */ for (i=0; i < num_pcres_tmp; i++) { - + /* Convert empty groups in unmatcheable regular expression ^$ */ if (strlen(patterns[i]) == 1) { patterns[i][0] = '^'; @@ -364,29 +366,29 @@ static int load_pcres(int action) patterns[i][2] = '\0'; continue; } - + /* Delete possible '\n' at the end of the pattern */ if (patterns[i][strlen(patterns[i])-1] == '\n') { patterns[i][strlen(patterns[i])-1] = '\0'; } - + /* Replace '\n' with '|' (except at the end of the pattern) */ for (j=0; j < strlen(patterns[i]); j++) { if (patterns[i][j] == '\n' && j != strlen(patterns[i])-1) { patterns[i][j] = '|'; } } - + /* Add ')' at the end of the pattern */ patterns[i][strlen(patterns[i])] = ')'; } - + /* Log the group patterns */ LM_NOTICE("num groups = %d\n\n", num_pcres_tmp); for (i=0; i < num_pcres_tmp; i++) { LM_NOTICE("%s (size = %i)\n", i, patterns[i], i, (int)strlen(patterns[i])); } - + /* Temporal pointer of pcres */ if ((pcres_tmp = pkg_malloc(sizeof(pcre *) * num_pcres_tmp)) == 0) { LM_ERR("no more memory for pcres_tmp\n"); @@ -395,10 +397,10 @@ static int load_pcres(int action) for (i=0; i= *num_pcres) { LM_ERR("invalid pcre index '%i', there are %i pcres\n", num_pcre, *num_pcres); return -4; } - + if (fixup_get_svalue(_msg, (gparam_p)_s1, &string)) { LM_ERR("cannot print the format\n"); return -5; } - + lock_get(reload_lock); - + pcre_rc = pcre_exec( (*pcres_addr)[num_pcre], /* the compiled pattern */ NULL, /* no extra data - we didn't study the pattern */ @@ -630,9 +632,9 @@ static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2) 0, /* default options */ NULL, /* output vector for substring information */ 0); /* number of elements in the output vector */ - + lock_release(reload_lock); - + /* Matching failed: handle error cases */ if (pcre_rc < 0) { switch(pcre_rc) { @@ -649,7 +651,7 @@ static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2) LM_DBG("'%s' matches pcres[%i]\n", string.s, num_pcre); return 1; } - + } @@ -665,7 +667,7 @@ static struct mi_root* mi_pcres_reload(struct mi_root* cmd, void* param) LM_NOTICE("'file' parameter is not set, group matching disabled\n"); return init_mi_tree(403, MI_SSTR("Group matching not enabled")); } - + LM_NOTICE("reloading pcres...\n"); if (load_pcres(RELOAD)) { LM_ERR("failed to reload pcres\n"); diff --git a/modules/registrar/README b/modules/registrar/README index 48604e5d00b..ff77e53ae4d 100644 --- a/modules/registrar/README +++ b/modules/registrar/README @@ -14,8 +14,7 @@ Bogdan-Andrei Iancu Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -47,16 +46,18 @@ Bogdan-Andrei Iancu 1.3.11. retry_after (integer) 1.3.12. sock_hdr_name (string) 1.3.13. mcontact_avp (string) - 1.3.14. gruu_secret (string) - 1.3.15. disable_gruu (int) + 1.3.14. attr_avp (string) + 1.3.15. gruu_secret (string) + 1.3.16. disable_gruu (int) 1.4. Exported Functions 1.4.1. save(domain [,flags ,[aor]]) - 1.4.2. lookup(domain [, flags [, aor]]) - 1.4.3. registered(domain [,AOR[, callid]]) - 1.4.4. is_other_contact(domain , IPs) - 1.4.5. add_sock_hdr(hdr_name) + 1.4.2. remove(domain, AOR[, target]) + 1.4.3. lookup(domain [, flags [, aor]]) + 1.4.4. registered(domain [,AOR[, callid]]) + 1.4.5. is_other_contact(domain , IPs) + 1.4.6. add_sock_hdr(hdr_name) 1.5. Exported Statistics @@ -83,13 +84,15 @@ Bogdan-Andrei Iancu 1.11. Set retry_after parameter 1.12. Set sock_hdr_namer parameter 1.13. Set mcontact_avp parameter - 1.14. Set gruu_secret parameter + 1.14. Set attr_avp parameter 1.15. Set gruu_secret parameter - 1.16. save usage - 1.17. lookup usage - 1.18. registered usage - 1.19. is_other_contact usage - 1.20. add_sock_hdr usage + 1.16. Set gruu_secret parameter + 1.17. save usage + 1.18. remove usage + 1.19. lookup usage + 1.20. registered usage + 1.21. is_other_contact usage + 1.22. add_sock_hdr usage Chapter 1. Admin Guide @@ -229,7 +232,7 @@ modparam("registrar", "default_q", 1000) The parameter specifies the message flag to be used to control the module behaviour regarding TCP connections. If the flag is set for a REGISTER via TCP containing a TCP contact, the - module, via the “save()” functions will set the lifetime of the + module, via the “save()” function, will set the lifetime of the TCP connection to the contact expire value. By doing this, the TCP connection will stay on as long as the contact is valid. @@ -348,7 +351,7 @@ modparam("registrar", "retry_after", 30) and used only if the flag 's' (Socket header) is set at "save()" time. - This make sens only in multiple replicated servers scenarios. + This makes sense only in multiple replicated servers scenarios. Default value is NULL. @@ -364,7 +367,7 @@ modparam("registrar", "sock_hdr_name", "Sock-Info") registrar). The AVP will be used to extract the imposed expires from the 200ok reply. - This make sens only in cached registrations scenario. + This makes sense only in cached registrations scenario. Default value is NULL. @@ -373,27 +376,63 @@ modparam("registrar", "sock_hdr_name", "Sock-Info") modparam("registrar", "mcontact_avp", "$avp(register)") ... -1.3.14. gruu_secret (string) +1.3.14. attr_avp (string) + + AVP to store specific additional information for each + registration. This information is read from the AVP and stored + (in memory, db or both) at every registrar 'save'. When a + registrar 'lookup' or 'registered' function is called, the + attr_avp is populated with the value saved at [re]registration. + + When doing call forking, the avp will hold multiple values. The + position of the corresponding attribute information in attr_avp + is equal to the branch index. An example scenario is given + below. + + Default value is NULL. + + Example 1.14. Set attr_avp parameter +# reading attributes from the attr_pvar when doing parallel forking +... +modparam("registrar", "attr_avp", "$avp(attr)") + +... +if (is_method("REGISTER")) { + $avp(attr) = "contact_info"; + save("location"); + exit; +} +... +lookup("location"); +t_on_branch("branch_route_1"); +... +branch_route[branch_route_1] { + xlog("Attributes for branch $T_branch_idx: $(avp(attr)[$T_branch +_idx])\n"); +} + + +1.3.15. gruu_secret (string) The string that will be used in XORing when generating temporary GRUUs. If not set, 'OpenSIPS' is the default secret. - Example 1.14. Set gruu_secret parameter + Example 1.15. Set gruu_secret parameter ... modparam("registrar", "gruu_secret", "top_secret") ... -1.3.15. disable_gruu (int) +1.3.16. disable_gruu (int) Globally disable GRUU handling - Default value is 0 ( GRUU will be handled ). + Default value is 1 ( GRUU will not be handled ). - Example 1.15. Set gruu_secret parameter + Example 1.16. Set gruu_secret parameter ... -modparam("registrar", "gruu_secret", 1) +modparam("registrar", "disable_gruu", 0) ... 1.4. Exported Functions @@ -469,7 +508,7 @@ modparam("registrar", "gruu_secret", 1) This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE. - Example 1.16. save usage + Example 1.17. save usage ... # save into 'location', no flags, use default AOR (TO URI) save("location"); @@ -482,10 +521,40 @@ save("location","mc5"); save("location","","$fu"); ... # save into 'location',no DB update, no reply to send, take AOR from AVP -save("location","mr", "$avp(i:1)"); +save("location","mr", "$avp(aor)"); +... + +1.4.2. remove(domain, AOR[, target]) + + Explicitly remove contacts behind a given address-of-record. + + Meaning of the parameters is as follows: + * domain - Logical domain within registrar. If database is + used then this must be name of the table which stores the + contacts. + * AOR - address-of-record to be searched (SIP URI) + * target (optional) - may be specified in two ways: + + single delete - Specific contact to be deleted (SIP + URI) + + multi delete - IP/hostname of the AOR's contacts which + will be deleted + + This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE. + + Example 1.18. remove usage +... +# remove all contacts belonging to the "bob" AOR +remove("location", "sip:bob@atlanta.com"); +... +# remove only bob's home phone +remove("location", "sip:bob@atlanta.com", "sip:bob@46.50.64.78"); +... +# remove all bob's phones which are behind "50.60.50.60" +$var(next_hop) = "50.60.50.60" +remove("location", "sip:bob@atlanta.com", "$var(next_hop)"); ... -1.4.2. lookup(domain [, flags [, aor]]) +1.4.3. lookup(domain [, flags [, aor]]) The functions extracts username from Request-URI and tries to find all contacts for the username in usrloc. If there are no @@ -514,7 +583,7 @@ save("location","mr", "$avp(i:1)"); contact filtering based on supported methods should be performed during lookup. * AOR (optional)- AOR to lookup for; if missing, the RURI is - used as AOR; This can be a variable. + used as AOR; This must be a variable. Return codes: * 1 - contacts found and returned. @@ -524,7 +593,7 @@ save("location","mr", "$avp(i:1)"); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.17. lookup usage + Example 1.19. lookup usage ... lookup("location"); # simple lookup #or @@ -542,7 +611,7 @@ switch ($retcode) { }; ... -1.4.3. registered(domain [,AOR[, callid]]) +1.4.4. registered(domain [,AOR[, callid]]) The function returns true if an AOR is registered, false otherwise. The function does not modify the message being @@ -554,7 +623,7 @@ switch ($retcode) { Meaning of the parameters is as follows: * domain - Name of table that should be used for the lookup. * AOR (optional)- AOR to lookup for; if missing, the RURI is - used as AOR; This can be a variable. + used as AOR; This must be a variable. * callid (optional)- callid to check if a contact if registered with this callid (this may help you to make distinction between newly registered contact (callid not @@ -564,7 +633,7 @@ switch ($retcode) { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, ONREPLY_ROUTE, LOCAL_ROUTE. - Example 1.18. registered usage + Example 1.20. registered usage ... if (registered("location")) { sl_send_reply("100", "Trying"); @@ -575,7 +644,7 @@ if (registered("location","$fu")) { } ... -1.4.4. is_other_contact(domain , IPs) +1.4.5. is_other_contact(domain , IPs) This function returns true if there are any other contacts registered, different from the ones from the IPs avp. @@ -588,7 +657,7 @@ if (registered("location","$fu")) { This function can be used from REQUEST_ROUTE. - Example 1.19. is_other_contact usage + Example 1.21. is_other_contact usage ... if (is_other_contact("location", "$avp(ips)")) { @@ -597,20 +666,20 @@ if (is_other_contact("location", "$avp(ips)")) { }; ... -1.4.5. add_sock_hdr(hdr_name) +1.4.6. add_sock_hdr(hdr_name) Adds to the current REGISTER request a new header with “hdr_name” which contains the description of the received socket (proto:ip:port) - This make sens only in multiple replicated servers scenarios. + This makes sense only in multiple replicated servers scenarios. Meaning of the parameters is as follows: * hdr_name - header name to be used. This function can be used from REQUEST_ROUTE. - Example 1.20. add_sock_hdr usage + Example 1.22. add_sock_hdr usage ... add_sock_hdr("Sock-Info"); ... @@ -733,7 +802,7 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. 2.12. diff --git a/modules/registrar/common.c b/modules/registrar/common.c index f8f321d2656..656037319c0 100644 --- a/modules/registrar/common.c +++ b/modules/registrar/common.c @@ -17,10 +17,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History * ------ * 2003-02-14 un-escaping added (janakj) @@ -34,7 +34,7 @@ * \ingroup registrar */ -#include +#include #include "../../dprint.h" #include "../../ut.h" /* q_memchr */ #include "../../parser/parse_uri.h" @@ -76,7 +76,7 @@ int extract_aor(str* _uri, str* _a,str *sip_instance,str *call_id) return -1; } - /* if have ;gr param and func caller is interested in + /* if have ;gr param and func caller is interested in * potentially extracting the sip instance */ if ((puri.gr.s && puri.gr.len) && sip_instance) { @@ -103,7 +103,7 @@ int extract_aor(str* _uri, str* _a,str *sip_instance,str *call_id) tgruu_dec[i] ^= magic->s[i%magic->len]; LM_DBG("decoded [%.*s]\n",dec_size,tgruu_dec); - /* extract aor - skip tgruu generation time at + /* extract aor - skip tgruu generation time at * the beggining */ _a->s = (char *)memchr(tgruu_dec,' ',dec_size) + 1; if (_a->s == NULL) { @@ -112,7 +112,7 @@ int extract_aor(str* _uri, str* _a,str *sip_instance,str *call_id) return -1; } _a->len = (char *)memchr(_a->s,' ',dec_size - (_a->s-tgruu_dec)) - _a->s; - if (_a->len < 0) { + if (_a->len < 0) { rerrno = R_AOR_PARSE; LM_ERR("failed to parse Address of Record\n"); return -1; @@ -126,7 +126,7 @@ int extract_aor(str* _uri, str* _a,str *sip_instance,str *call_id) } sip_instance->len = (char *)memchr(sip_instance->s,' ', dec_size-(sip_instance->s-tgruu_dec)) - sip_instance->s; - if (sip_instance->len < 0) { + if (sip_instance->len < 0) { rerrno = R_AOR_PARSE; LM_ERR("failed to parse Address of Record\n"); return -1; @@ -138,7 +138,7 @@ int extract_aor(str* _uri, str* _a,str *sip_instance,str *call_id) LM_ERR("failed to parse Address of Record\n"); return -1; } - call_id->len = (tgruu_dec+dec_size) - call_id->s -1; + call_id->len = (tgruu_dec+dec_size) - call_id->s; LM_DBG("extracted aor [%.*s] and instance [%.*s] and callid [%.*s]\n",_a->len,_a->s, sip_instance->len,sip_instance->s,call_id->len,call_id->s); @@ -152,7 +152,7 @@ int extract_aor(str* _uri, str* _a,str *sip_instance,str *call_id) *sip_instance = puri.gr_val; } } - + if ( (puri.user.len + puri.host.len + 1) > MAX_AOR_LEN || puri.user.len > USERNAME_MAX_SIZE || puri.host.len > DOMAIN_MAX_SIZE ) { diff --git a/modules/registrar/common.h b/modules/registrar/common.h index 7e4df4c463e..46915536fc4 100644 --- a/modules/registrar/common.h +++ b/modules/registrar/common.h @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! * \file * \brief SIP registrar module - common stuff - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef COMMON_H diff --git a/modules/registrar/doc/registrar_admin.xml b/modules/registrar/doc/registrar_admin.xml index ad0331a5dbc..7b65b053082 100644 --- a/modules/registrar/doc/registrar_admin.xml +++ b/modules/registrar/doc/registrar_admin.xml @@ -237,7 +237,7 @@ modparam("registrar", "default_q", 1000) The parameter specifies the message flag to be used to control the module behaviour regarding TCP connections. If the flag is set for a REGISTER via TCP containing a TCP contact, the module, via the - save() functions will set the lifetime of the TCP + save() function, will set the lifetime of the TCP connection to the contact expire value. By doing this, the TCP connection will stay on as long as the contact is valid. @@ -421,7 +421,7 @@ modparam("registrar", "retry_after", 30) the flag 's' (Socket header) is set at "save()" time. - This make sens only in multiple replicated servers scenarios. + This makes sense only in multiple replicated servers scenarios. @@ -447,7 +447,7 @@ modparam("registrar", "sock_hdr_name", "Sock-Info") expires from the 200ok reply. - This make sens only in cached registrations scenario. + This makes sense only in cached registrations scenario. @@ -463,6 +463,49 @@ modparam("registrar", "mcontact_avp", "$avp(register)")
+
+ <varname>attr_avp</varname> (string) + + AVP to store specific additional information for each registration. + This information is read from the AVP and stored (in memory, db or both) + at every registrar 'save'. When a registrar 'lookup' or 'registered' + function is called, the attr_avp is populated with + the value saved at [re]registration. + + + When doing call forking, the avp will hold multiple values. The position of + the corresponding attribute information in attr_avp is + equal to the branch index. An example scenario is given below. + + + + Default value is NULL. + + + + Set <varname>attr_avp</varname> parameter + +# reading attributes from the attr_pvar when doing parallel forking +... +modparam("registrar", "attr_avp", "$avp(attr)") + +... +if (is_method("REGISTER")) { + $avp(attr) = "contact_info"; + save("location"); + exit; +} +... +lookup("location"); +t_on_branch("branch_route_1"); +... +branch_route[branch_route_1] { + xlog("Attributes for branch $T_branch_idx: $(avp(attr)[$T_branch_idx])\n"); +} + + + +
<varname>gruu_secret</varname> (string) @@ -490,14 +533,14 @@ modparam("registrar", "gruu_secret", "top_secret") - Default value is 0 ( GRUU will be handled ). + Default value is 1 ( GRUU will not be handled ). Set <varname>gruu_secret</varname> parameter ... -modparam("registrar", "gruu_secret", 1) +modparam("registrar", "disable_gruu", 0) ... @@ -647,7 +690,70 @@ save("location","mc5"); save("location","","$fu"); ... # save into 'location',no DB update, no reply to send, take AOR from AVP -save("location","mr", "$avp(i:1)"); +save("location","mr", "$avp(aor)"); +... + + +
+ +
+ + <function moreinfo="none">remove(domain, AOR[, target])</function> + + + Explicitly remove contacts behind a given address-of-record. + + Meaning of the parameters is as follows: + + + + domain - Logical domain within registrar. + If database is used then this must be name of the table which + stores the contacts. + + + + + AOR - address-of-record to be searched (SIP URI) + + + + + target (optional) - + may be specified in two ways: + + + + single delete - + Specific contact to be deleted (SIP URI) + + + + + multi delete - + IP/hostname of the AOR's contacts which will be deleted + + + + + + + + This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE. + + + <function>remove</function> usage + +... +# remove all contacts belonging to the "bob" AOR +remove("location", "sip:bob@atlanta.com"); +... +# remove only bob's home phone +remove("location", "sip:bob@atlanta.com", "sip:bob@46.50.64.78"); +... +# remove all bob's phones which are behind "50.60.50.60" +$var(next_hop) = "50.60.50.60" +remove("location", "sip:bob@atlanta.com", "$var(next_hop)"); ... @@ -706,7 +812,7 @@ save("location","mr", "$avp(i:1)"); AOR (optional)- AOR to lookup for; if - missing, the RURI is used as AOR; This can be a variable. + missing, the RURI is used as AOR; This must be a variable. @@ -777,7 +883,7 @@ switch ($retcode) { AOR (optional)- AOR to lookup for; if - missing, the RURI is used as AOR; This can be a variable. + missing, the RURI is used as AOR; This must be a variable. @@ -860,7 +966,7 @@ if (is_other_contact("location", "$avp(ips)")) { received socket (proto:ip:port) - This make sens only in multiple replicated servers scenarios. + This makes sense only in multiple replicated servers scenarios. Meaning of the parameters is as follows: diff --git a/modules/registrar/lookup.c b/modules/registrar/lookup.c index 45bcfbacd51..231638ac55f 100644 --- a/modules/registrar/lookup.c +++ b/modules/registrar/lookup.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -28,8 +28,8 @@ /*! * \file * \brief SIP registrar module - lookup contacts in usrloc - * \ingroup registrar - */ + * \ingroup registrar + */ #include @@ -71,6 +71,7 @@ int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s) str path_dst; str flags_s; pv_value_t val; + int_str istr; str sip_instance = {0,0},call_id = {0,0}; flags = 0; @@ -134,7 +135,7 @@ int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s) if (sip_instance.len && sip_instance.s) { LM_DBG("ruri has gruu in lookup\n"); /* uri has GRUU */ - if (ptr->instance.len-2 != sip_instance.len || + if (ptr->instance.len-2 != sip_instance.len || memcmp(ptr->instance.s+1,sip_instance.s,sip_instance.len)) { LM_DBG("no match to sip instace - [%.*s] - [%.*s]\n",ptr->instance.len-2,ptr->instance.s+1, sip_instance.len,sip_instance.s); @@ -171,6 +172,7 @@ int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s) break; } } + it=it->next; } if (it != NULL) { @@ -223,6 +225,14 @@ int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s) if (ptr->sock) _m->force_send_socket = ptr->sock; + /* populate the 'attributes' avp */ + if (attr_avp_name != -1) { + istr.s = ptr->attr; + if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { + LM_ERR("Failed to populate attr avp!\n"); + } + } + ptr = ptr->next; } @@ -235,13 +245,13 @@ int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s) for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m,ptr,flags)) { path_dst.len = 0; - if(ptr->path.s && ptr->path.len + if(ptr->path.s && ptr->path.len && get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); continue; } - /* The same as for the first contact applies for branches + /* The same as for the first contact applies for branches * regarding path vs. received. */ LM_DBG("setting branch <%.*s>\n",ptr->c.len,ptr->c.s); if (append_branch(_m,&ptr->c,path_dst.len?&path_dst:&ptr->received, @@ -250,11 +260,19 @@ int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s) /* Also give a chance to the next branches*/ continue; } + + /* populate the 'attributes' avp */ + if (attr_avp_name != -1) { + istr.s = ptr->attr; + if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { + LM_ERR("Failed to populate attr avp!\n"); + } + } } } done: - ul.release_urecord(r); + ul.release_urecord(r, 0); ul.unlock_udomain((udomain_t*)_t, &aor); return ret; } @@ -273,6 +291,7 @@ int registered(struct sip_msg* _m, char* _t, char* _s, char *_c) pv_value_t val; str callid; int res; + int_str istr; /* get the AOR */ if (_s) { @@ -333,6 +352,15 @@ int registered(struct sip_msg* _m, char* _t, char* _s, char *_c) for( ; ptr ; ptr=ptr->next ) { if (callid.len==0 || (callid.len==ptr->callid.len && memcmp(callid.s,ptr->callid.s,callid.len)==0 ) ) { + + /* also populate the 'attributes' avp */ + if (attr_avp_name != -1) { + istr.s = ptr->attr; + + if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) + LM_ERR("Failed to populate attr avp!\n"); + } + ul.unlock_udomain((udomain_t*)_t, &aor); LM_DBG("'%.*s' found in usrloc\n", aor.len, ZSW(aor.s)); return 1; diff --git a/modules/registrar/lookup.h b/modules/registrar/lookup.h index 2dc689fb1d8..7b74edc2a7e 100644 --- a/modules/registrar/lookup.h +++ b/modules/registrar/lookup.h @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! * \file * \brief SIP registrar module - lookup contacts in usrloc - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef LOOKUP_H diff --git a/modules/registrar/path.c b/modules/registrar/path.c index 55135911ea3..c9013426662 100644 --- a/modules/registrar/path.c +++ b/modules/registrar/path.c @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*! * \file * \brief SIP registrar module - Helper functions for Path support - * \ingroup registrar - */ + * \ingroup registrar + */ #include "../../data_lump.h" diff --git a/modules/registrar/path.h b/modules/registrar/path.h index 11a8c9c3892..64a52e6b140 100644 --- a/modules/registrar/path.h +++ b/modules/registrar/path.h @@ -25,8 +25,8 @@ /*! * \file * \brief SIP registrar module - helper functions for Path support - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef REG_PATH_H #define REG_PATH_H diff --git a/modules/registrar/reg_mod.c b/modules/registrar/reg_mod.c index 09e1090ad69..51166d098a9 100644 --- a/modules/registrar/reg_mod.c +++ b/modules/registrar/reg_mod.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -37,9 +37,9 @@ * removed the module parameter "use_domain" - now it is * imported from usrloc module (bogdan) * 2006-11-28 Added statistics tracking for the number of accepted/rejected - * registrations, as well as for the max expiry time, max + * registrations, as well as for the max expiry time, max * contacts and default expiry time(Jeffrey Magder-SOMA Networks) - * 2007-02-24 sip_natping_flag moved into branch flags, so migrated to + * 2007-02-24 sip_natping_flag moved into branch flags, so migrated to * nathelper module (bogdan) * */ @@ -47,13 +47,13 @@ /*! * \defgroup registrar SIP Registrar support * The module contains REGISTER processing logic. - */ + */ /*! * \file * \brief SIP registrar module - interface - * \ingroup registrar - */ + * \ingroup registrar + */ #include #include "../../sr_module.h" @@ -81,6 +81,7 @@ static int child_init(int); static void mod_destroy(void); /*! \brief Fixup functions */ static int registrar_fixup(void** param, int param_no); +static int fixup_remove(void** param, int param_no); static int registered_fixup(void** param, int param_no); /*! \brief Functions */ static int add_sock_hdr(struct sip_msg* msg, char *str, char *foo); @@ -92,6 +93,7 @@ int default_expires = 3600; /*!< Default expires value in seconds */ qvalue_t default_q = Q_UNSPECIFIED; /*!< Default q value multiplied by 1000 */ int case_sensitive = 1; /*!< If set to 0, username in aor will be case insensitive */ int tcp_persistent_flag = -1; /*!< if the TCP connection should be kept open */ +char *tcp_persistent_flag_s = 0; int min_expires = 60; /*!< Minimum expires the phones are allowed to use in seconds * use 0 to switch expires checking off */ int max_expires = 0; /*!< Maximum expires the phones are allowed to use in seconds, @@ -108,6 +110,10 @@ char* mct_avp_param = 0; unsigned short mct_avp_type = 0; int mct_avp_name; +char* attr_avp_param = 0; +unsigned short attr_avp_type = 0; +int attr_avp_name; + int reg_use_domain = 0; /*!< Realm prefix to be removed */ @@ -116,7 +122,7 @@ str realm_prefix; str sock_hdr_name = {0,0}; str gruu_secret = {0,0}; -int disable_gruu = 0; +int disable_gruu = 1; #define RCV_NAME "received" str rcv_param = str_init(RCV_NAME); @@ -143,6 +149,10 @@ static cmd_export_t cmds[] = { REQUEST_ROUTE|ONREPLY_ROUTE }, {"save", (cmd_function)save, 3, registrar_fixup, 0, REQUEST_ROUTE|ONREPLY_ROUTE }, + {"remove", (cmd_function)_remove, 2, fixup_remove, 0, + REQUEST_ROUTE|ONREPLY_ROUTE }, + {"remove", (cmd_function)_remove, 3, fixup_remove, 0, + REQUEST_ROUTE|ONREPLY_ROUTE }, {"lookup", (cmd_function)lookup, 1, registrar_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"lookup", (cmd_function)lookup, 2, registrar_fixup, 0, @@ -167,21 +177,23 @@ static cmd_export_t cmds[] = { * Exported parameters */ static param_export_t params[] = { - {"default_expires", INT_PARAM, &default_expires }, - {"default_q", INT_PARAM, &default_q }, - {"case_sensitive", INT_PARAM, &case_sensitive }, - {"tcp_persistent_flag",INT_PARAM, &tcp_persistent_flag }, - {"realm_prefix", STR_PARAM, &realm_pref }, - {"min_expires", INT_PARAM, &min_expires }, - {"max_expires", INT_PARAM, &max_expires }, - {"received_param", STR_PARAM, &rcv_param }, - {"received_avp", STR_PARAM, &rcv_avp_param }, - {"max_contacts", INT_PARAM, &max_contacts }, - {"retry_after", INT_PARAM, &retry_after }, - {"sock_hdr_name", STR_PARAM, &sock_hdr_name.s }, - {"mcontact_avp", STR_PARAM, &mct_avp_param }, - {"gruu_secret", STR_PARAM, &gruu_secret.s }, - {"disable_gruu", INT_PARAM, &disable_gruu }, + {"default_expires", INT_PARAM, &default_expires }, + {"default_q", INT_PARAM, &default_q }, + {"case_sensitive", INT_PARAM, &case_sensitive }, + {"tcp_persistent_flag",INT_PARAM, &tcp_persistent_flag }, + {"tcp_persistent_flag",STR_PARAM, &tcp_persistent_flag_s }, + {"realm_prefix", STR_PARAM, &realm_pref }, + {"min_expires", INT_PARAM, &min_expires }, + {"max_expires", INT_PARAM, &max_expires }, + {"received_param", STR_PARAM, &rcv_param }, + {"received_avp", STR_PARAM, &rcv_avp_param }, + {"max_contacts", INT_PARAM, &max_contacts }, + {"retry_after", INT_PARAM, &retry_after }, + {"sock_hdr_name", STR_PARAM, &sock_hdr_name.s }, + {"mcontact_avp", STR_PARAM, &mct_avp_param }, + {"attr_avp", STR_PARAM, &attr_avp_param }, + {"gruu_secret", STR_PARAM, &gruu_secret.s }, + {"disable_gruu", INT_PARAM, &disable_gruu }, {0, 0, 0} }; @@ -196,14 +208,27 @@ static stat_export_t mod_stats[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "usrloc", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "tm", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /*! \brief * Module exports structure */ struct module_exports exports = { "registrar", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ mod_stats, /* exported statistics */ @@ -279,6 +304,24 @@ static int mod_init(void) mct_avp_type = 0; } + if (attr_avp_param && *attr_avp_param) { + s.s = attr_avp_param; s.len = strlen(s.s); + if (pv_parse_spec(&s, &avp_spec)==0 + || avp_spec.type!=PVT_AVP) { + LM_ERR("malformed or non AVP %s AVP definition\n", attr_avp_param); + return -1; + } + + if(pv_get_avp_name(0, &avp_spec.pvp, &attr_avp_name, &attr_avp_type)!=0) + { + LM_ERR("[%s]- invalid AVP definition\n", attr_avp_param); + return -1; + } + } else { + attr_avp_name = -1; + attr_avp_type = 0; + } + bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) { LM_ERR("can't bind usrloc\n"); @@ -295,7 +338,7 @@ static int mod_init(void) default_q = MIN_Q; } } - + if (bind_usrloc(&ul) < 0) { return -1; @@ -313,6 +356,8 @@ static int mod_init(void) gruu_secret.len = strlen(gruu_secret.s); /* fix the flags */ + fix_flag_name(tcp_persistent_flag_s, tcp_persistent_flag); + tcp_persistent_flag = get_flag_id_by_name(FLAG_TYPE_MSG, tcp_persistent_flag_s); tcp_persistent_flag = (tcp_persistent_flag!=-1)?(1<unparsed-msg->buf, 0, 0); + anchor = anchor_lump( msg, msg->unparsed-msg->buf, 0); if (anchor==0) { LM_ERR("can't get anchor\n"); goto error; diff --git a/modules/registrar/reg_mod.h b/modules/registrar/reg_mod.h index cd61ca9b48a..a0edcc6f0c1 100644 --- a/modules/registrar/reg_mod.h +++ b/modules/registrar/reg_mod.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * registrar module interface * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -29,15 +29,15 @@ * 2006-11-28 Added statistics tracking for the number of accepted/rejected * registrations, as well as for the max expiry time, max contacts, * and default expiry time. (Jeffrey Magder - SOMA Networks) - * 2007-02-24 sip_natping_flag moved into branch flags, so migrated to + * 2007-02-24 sip_natping_flag moved into branch flags, so migrated to * nathelper module (bogdan) */ /*! * \file * \brief SIP registrar module - interface - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef REG_MOD_H @@ -50,7 +50,7 @@ #include "../signaling/signaling.h" #include "../tm/tm_load.h" -/* if DB support is used, this values must not exceed the +/* if DB support is used, this values must not exceed the * storage capacity of the DB columns! See db/schema/entities.xml */ #define CONTACT_MAX_SIZE 255 #define RECEIVED_MAX_SIZE 255 @@ -93,6 +93,8 @@ extern unsigned short rcv_avp_type; extern int rcv_avp_name; extern unsigned short mct_avp_type; extern int mct_avp_name; +extern unsigned short attr_avp_type; +extern int attr_avp_name; extern str rcv_param; extern int max_contacts; diff --git a/modules/registrar/regtime.c b/modules/registrar/regtime.c index dbf3e7ebb41..66ee55b827a 100644 --- a/modules/registrar/regtime.c +++ b/modules/registrar/regtime.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/registrar/regtime.h b/modules/registrar/regtime.h index fe117eb7193..e7ada4a97c7 100644 --- a/modules/registrar/regtime.h +++ b/modules/registrar/regtime.h @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! * \file * \brief SIP registrar module - time related functions - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef REGTIME_H diff --git a/modules/registrar/reply.c b/modules/registrar/reply.c index 40e52792375..24cd1242821 100644 --- a/modules/registrar/reply.c +++ b/modules/registrar/reply.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -32,8 +32,8 @@ /*! * \file * \brief SIP registrar module - Send a reply - * \ingroup registrar - */ + * \ingroup registrar + */ #include #include "../../ut.h" @@ -129,10 +129,10 @@ static inline unsigned int calc_buf_len(ucontact_t* c,int build_gruu, if (qlen) len += Q_PARAM_LEN + qlen; len += EXPIRES_PARAM_LEN + INT2STR_MAX_LEN; if (c->received.s) { - len += 1 /* ; */ - + rcv_param.len - + 1 /* = */ - + 1 /* dquote */ + len += 1 /* ; */ + + rcv_param.len + + 1 /* = */ + + 1 /* dquote */ + c->received.len + 1 /* dquote */ ; @@ -159,7 +159,7 @@ static inline unsigned int calc_buf_len(ucontact_t* c,int build_gruu, + sock->name.len + 1 /* : */ + sock->port_no_str.len - + GR_NO_VAL_SIZE + + GR_NO_VAL_SIZE + 1 /* quote */ ; /* sip.instance */ @@ -168,7 +168,7 @@ static inline unsigned int calc_buf_len(ucontact_t* c,int build_gruu, + (c->instance.len - 2) + 1 /* quote */ ; - } + } } c = c->next; } @@ -188,7 +188,7 @@ char * build_temp_gruu(str *aor,str *instance,str *callid,int *len) char *time_str = int2str((unsigned long)act_time,&time_len); str *magic; - *len = time_len + aor->len + instance->len + callid->len + 3; /* blank spaces */ + *len = time_len + aor->len + instance->len + callid->len + 3 - 2; /* +3 blank spaces, -2 discarded chars of instance in memcpy below */ p = temp_gruu_buf; memcpy(p,time_str,time_len); @@ -248,7 +248,7 @@ int build_contact(ucontact_t* c,struct sip_msg *_m) } p = contact.buf; - + memcpy(p, CONTACT_BEGIN, CONTACT_BEGIN_LEN); p += CONTACT_BEGIN_LEN; @@ -324,7 +324,7 @@ int build_contact(ucontact_t* c,struct sip_msg *_m) p += SIP_PROTO_SIZE; memcpy(p,TEMP_GRUU_HEADER,TEMP_GRUU_HEADER_SIZE); p += TEMP_GRUU_HEADER_SIZE; - + tmpgr = build_temp_gruu(c->aor,&c->instance,&c->callid,&grlen); base64encode((unsigned char *)p, (unsigned char *)tmpgr,grlen); @@ -385,7 +385,7 @@ int build_contact(ucontact_t* c,struct sip_msg *_m) #define EI_R_PARSE "Message parse error" /* R_PARSE */ #define EI_R_TO_MISS "To header not found" /* R_TO_MISS */ #define EI_R_CID_MISS "Call-ID header not found" /* R_CID_MISS */ -#define EI_R_CS_MISS "CSeq header not found" /* R_CS_MISS */ +#define EI_R_CS_MISS "CSeq header not found" /* R_CS_MISS */ #define EI_R_PARSE_EXP "Expires parse error" /* R_PARSE_EXP */ #define EI_R_PARSE_CONT "Contact parse error" /* R_PARSE_CONT */ #define EI_R_STAR_EXP "* used in contact and expires is not zero" /* R_STAR__EXP */ @@ -475,7 +475,7 @@ static int add_retry_after(struct sip_msg* _m) { char* buf, *ra_s; int ra_len; - + ra_s = int2str(retry_after, &ra_len); buf = (char*)pkg_malloc(RETRY_AFTER_LEN + ra_len + CRLF_LEN); if (!buf) { @@ -529,7 +529,7 @@ static int add_unsupported(struct sip_msg* _m, str* _p) LUMP_RPL_HDR | LUMP_RPL_NODUP); return 0; } - + /*! \brief * Send a reply */ @@ -544,7 +544,7 @@ int send_reply(struct sip_msg* _m, unsigned int _flags) add_lump_rpl( _m, contact.buf, contact.data_len, LUMP_RPL_HDR|LUMP_RPL_NODUP|LUMP_RPL_NOFREE); contact.data_len = 0; } - + if (rerrno == R_FINE && (_flags®_SAVE_PATH_FLAG) && _m->path_vec.s) { if ( (_flags®_SAVE_PATH_OFF_FLAG)==0 ) { if (parse_supported(_m)<0 && (_flags®_SAVE_PATH_STRICT_FLAG)) { @@ -575,7 +575,7 @@ int send_reply(struct sip_msg* _m, unsigned int _flags) case 500: msg.s = MSG_500; msg.len = sizeof(MSG_500)-1;break; case 503: msg.s = MSG_503; msg.len = sizeof(MSG_503)-1;break; } - + if (code != 200) { buf = (char*)pkg_malloc(E_INFO_LEN + error_info[rerrno].len + CRLF_LEN + 1); if (!buf) { @@ -592,9 +592,9 @@ int send_reply(struct sip_msg* _m, unsigned int _flags) if (add_retry_after(_m) < 0) { return -1; } - } + } } - + if (sigb.reply(_m, code, &msg, NULL) == -1) { LM_ERR("failed to send %ld %.*s\n", code, msg.len,msg.s); return -1; diff --git a/modules/registrar/reply.h b/modules/registrar/reply.h index 9d188504de4..4c4328e94fa 100644 --- a/modules/registrar/reply.h +++ b/modules/registrar/reply.h @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! * \file * \brief SIP registrar module - send a reply - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef REPLY_H diff --git a/modules/registrar/rerrno.c b/modules/registrar/rerrno.c index 521f7863af5..ad5f26a4d8f 100644 --- a/modules/registrar/rerrno.c +++ b/modules/registrar/rerrno.c @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! * \file * \brief SIP registrar module - registrar errno - * \ingroup registrar - */ + * \ingroup registrar + */ #include "rerrno.h" diff --git a/modules/registrar/rerrno.h b/modules/registrar/rerrno.h index fd410f081ff..cc81560e884 100644 --- a/modules/registrar/rerrno.h +++ b/modules/registrar/rerrno.h @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! * \file * \brief SIP registrar module - registrar errno - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef RERRNO_H diff --git a/modules/registrar/save.c b/modules/registrar/save.c index aef95e624f3..c473a7e3f0b 100644 --- a/modules/registrar/save.c +++ b/modules/registrar/save.c @@ -18,31 +18,31 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ---------- * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri) * 2003-02-28 scrathcpad compatibility abandoned (jiri) - * 2003-03-21 save_noreply added, patch provided by Maxim Sobolev + * 2003-03-21 save_noreply added, patch provided by Maxim Sobolev * (janakj) * 2005-07-11 added sip_natping_flag for nat pinging with SIP method * instead of UDP package (bogdan) * 2006-04-13 added tcp_persistent_flag for keeping the TCP connection as long * as a TCP contact is registered (bogdan) * 2006-11-22 save_noreply and save_memory merged into save() (bogdan) - * 2006-11-28 Added statistic support for the number of accepted/rejected - * registrations. (Jeffrey Magder - SOMA Networks) - * 2007-02-24 sip_natping_flag moved into branch flags, so migrated to + * 2006-11-28 Added statistic support for the number of accepted/rejected + * registrations. (Jeffrey Magder - SOMA Networks) + * 2007-02-24 sip_natping_flag moved into branch flags, so migrated to * nathelper module (bogdan) */ /*! * \file * \brief SIP registrar module - Process REGISTER request and send reply - * \ingroup registrar - */ + * \ingroup registrar + */ #include "../../str.h" @@ -74,8 +74,8 @@ #include "save.h" /*! \brief - * Process request that contained a star, in that case, - * we will remove all bindings with the given username + * Process request that contained a star, in that case, + * we will remove all bindings with the given username * from the usrloc and return 200 OK response */ static inline int star(udomain_t* _d, struct save_ctx *_sctx, @@ -83,7 +83,7 @@ static inline int star(udomain_t* _d, struct save_ctx *_sctx, { urecord_t* r; ucontact_t* c; - + ul.lock_udomain(_d, &_sctx->aor); if (!ul.get_urecord(_d, &_sctx->aor, &r)) { @@ -98,9 +98,9 @@ static inline int star(udomain_t* _d, struct save_ctx *_sctx, } } - if (ul.delete_urecord(_d, &_sctx->aor, 0) < 0) { + if (ul.delete_urecord(_d, &_sctx->aor, NULL, 0) < 0) { LM_ERR("failed to remove record from usrloc\n"); - + /* Delete failed, try to get corresponding * record structure and send back all existing * contacts @@ -141,7 +141,7 @@ static struct socket_info *get_sock_hdr(struct sip_msg *msg) if (socks.len==0) return 0; - if (parse_phostport( socks.s, socks.len, &hosts.s, &hosts.len, + if (parse_phostport( socks.s, socks.len, &hosts.s, &hosts.len, &port, &proto)!=0) { LM_ERR("bad socket <%.*s> in \n", socks.len, socks.s); @@ -171,7 +171,7 @@ static inline int no_contacts(udomain_t* _d, str* _a,struct sip_msg *_m) { urecord_t* r; int res; - + ul.lock_udomain(_d, _a); res = ul.get_urecord(_d, _a, &r); if (res < 0) { @@ -180,7 +180,7 @@ static inline int no_contacts(udomain_t* _d, str* _a,struct sip_msg *_m) ul.unlock_udomain(_d, _a); return -1; } - + if (res == 0) { /* Contacts found */ build_contact(r->contacts,_m); } @@ -205,6 +205,8 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, static int received_found; static unsigned int allowed, allow_parsed; static struct sip_msg *m = 0; + static int_str attr_avp_value; + static struct usr_avp *avp_attr; int_str val; if (_m!=0) { @@ -338,6 +340,16 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, } } + /* additional information (script pvar) */ + if (attr_avp_name != -1) { + avp_attr = search_first_avp(attr_avp_type, attr_avp_name, + &attr_avp_value, NULL); + if (avp_attr) { + ci.attr = &attr_avp_value.s; + + LM_DBG("Attributes: %.*s\n", ci.attr->len, ci.attr->s); + } + } } return &ci; @@ -395,12 +407,12 @@ static inline int insert_contacts(struct sip_msg* _m, contact_t* _c, "contacts=%p\n",r,r->contacts); goto error; } - if (ul.delete_ucontact( r, r->contacts)!=0) { + if (ul.delete_ucontact( r, r->contacts, 0)!=0) { LM_ERR("failed to remove contact\n"); goto error; } } else { - LM_INFO("too many contacts (%d) for AOR <%.*s>, max=%d\n", + LM_INFO("too many contacts (%d) for AOR <%.*s>, max=%d\n", num, _a->len, _a->s, _sctx->max_contacts); rerrno = R_TOO_MANY; goto error; @@ -410,7 +422,7 @@ static inline int insert_contacts(struct sip_msg* _m, contact_t* _c, } if (r==0) { - if (ul.insert_urecord(_d, _a, &r) < 0) { + if (ul.insert_urecord(_d, _a, &r, 0) < 0) { rerrno = R_UL_NEW_R; LM_ERR("failed to insert new record structure\n"); goto error; @@ -425,23 +437,24 @@ static inline int insert_contacts(struct sip_msg* _m, contact_t* _c, if ( r->contacts==0 || ul.get_ucontact(r, &_c->uri, ci->callid, ci->cseq+1, &c)!=0 ) { - if (ul.insert_ucontact( r, &_c->uri, ci, &c) < 0) { + if (ul.insert_ucontact( r, &_c->uri, ci, &c, 0) < 0) { rerrno = R_UL_INS_C; LM_ERR("failed to insert contact\n"); goto error; } } else { - if (ul.update_ucontact( r, c, ci) < 0) { + if (ul.update_ucontact( r, c, ci, 0) < 0) { rerrno = R_UL_UPD_C; LM_ERR("failed to update contact\n"); goto error; } } + #ifdef USE_TCP if (tcp_check) { /* parse contact uri to see if transport is TCP */ if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) { - LM_ERR("failed to parse contact <%.*s>\n", + LM_ERR("failed to parse contact <%.*s>\n", _c->uri.len, _c->uri.s); } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) { if (e_max) { @@ -459,7 +472,7 @@ static inline int insert_contacts(struct sip_msg* _m, contact_t* _c, if (r->contacts) { build_contact(r->contacts,_m); } - ul.release_urecord(r); + ul.release_urecord(r, 0); } #ifdef USE_TCP @@ -472,7 +485,7 @@ static inline int insert_contacts(struct sip_msg* _m, contact_t* _c, return 0; error: if (r) - ul.delete_urecord(_d, _a, r); + ul.delete_urecord(_d, _a, r, 0); return -1; } @@ -493,7 +506,7 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c, struct save_ctx *_sctx) { ucontact_info_t *ci; - ucontact_t* c; + ucontact_t *c, *c_last, *c_it; int e; unsigned int cflags; int ret; @@ -553,19 +566,23 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, continue; /* we need to add a new contact -> too many ?? */ - if (_sctx->max_contacts && num>=_sctx->max_contacts) { + while (_sctx->max_contacts && num>=_sctx->max_contacts) { if (_sctx->flags®_SAVE_FORCE_REG_FLAG) { /* we are overflowing the number of maximum contacts, - so remove the first (oldest) one to prevent this */ - if (_r==NULL || _r->contacts==NULL) { - LM_CRIT("BUG - overflow detected with r=%p and " - "contacts=%p\n",_r,_r->contacts); + so remove the oldest valid one to prevent this */ + for( c_it=_r->contacts,c_last=NULL ; c_it ; c_it=c_it->next ) + if (VALID_CONTACT(c_it, act_time)) c_last=c_it; + if (c_last==NULL) { + LM_CRIT("BUG - overflow detected but no valid contacts found :( \n"); goto error; } - if (ul.delete_ucontact( _r, _r->contacts)!=0) { + LM_DBG("overflow on inserting new contact -> removing <%.*s>\n", + c_last->c.len, c_last->c.s); + if (ul.delete_ucontact( _r, c_last, 0)!=0) { LM_ERR("failed to remove contact\n"); goto error; } + num--; } else { LM_INFO("too many contacts for AOR <%.*s>, max=%d\n", _r->aor.len, _r->aor.s, _sctx->max_contacts); @@ -580,7 +597,7 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, goto error; } - if (ul.insert_ucontact( _r, &_c->uri, ci, &c) < 0) { + if (ul.insert_ucontact( _r, &_c->uri, ci, &c, 0) < 0) { rerrno = R_UL_INS_C; LM_ERR("failed to insert contact\n"); goto error; @@ -595,20 +612,50 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, c->flags &= ~FL_MEM; } - if (ul.delete_ucontact(_r, c) < 0) { + if (ul.delete_ucontact(_r, c, 0) < 0) { rerrno = R_UL_DEL_C; LM_ERR("failed to delete contact\n"); goto error; } } else { /* do update */ + /* if the contact to be updated is not valid, it will be after update, so need + * to compensate the total number of contact */ + if ( !VALID_CONTACT(c,act_time) ) + num++; + while ( _sctx->max_contacts && num>_sctx->max_contacts ) { + if (_sctx->flags®_SAVE_FORCE_REG_FLAG) { + /* we are overflowing the number of maximum contacts, + so remove the first (oldest) one to prevent this (but not the one + to be updated !) */ + for( c_it=_r->contacts,c_last=NULL ; c_it ; c_it=c_it->next ) + if (VALID_CONTACT(c_it, act_time) && c_it!=c) c_last=c_it; + if (c_last==NULL) { + LM_CRIT("BUG - overflow detected but no valid contacts found :( \n"); + goto error; + } + LM_DBG("overflow on update -> removing contact <%.*s>\n", + c_last->c.len, c_last->c.s); + if (ul.delete_ucontact( _r, c_last, 0)!=0) { + LM_ERR("failed to remove contact\n"); + goto error; + } + num--; + } else { + LM_INFO("too many contacts for AOR <%.*s>, max=%d\n", + _r->aor.len, _r->aor.s, _sctx->max_contacts); + rerrno = R_TOO_MANY; + return -1; + } + } + /* pack the contact specific info */ if ( (ci=pack_ci( 0, _c, e, 0, _sctx->flags))==0 ) { LM_ERR("failed to pack contact specific info\n"); goto error; } - if (ul.update_ucontact(_r, c, ci) < 0) { + if (ul.update_ucontact(_r, c, ci, 0) < 0) { rerrno = R_UL_UPD_C; LM_ERR("failed to update contact\n"); goto error; @@ -619,7 +666,7 @@ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, if (tcp_check) { /* parse contact uri to see if transport is TCP */ if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) { - LM_ERR("failed to parse contact <%.*s>\n", + LM_ERR("failed to parse contact <%.*s>\n", _c->uri.len, _c->uri.s); } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) { if (e_max>0) { @@ -666,12 +713,12 @@ static inline int add_contacts(struct sip_msg* _m, contact_t* _c, if (res == 0) { /* Contacts found */ if (update_contacts(_m, r, _c, _sctx) < 0) { build_contact(r->contacts,_m); - ul.release_urecord(r); + ul.release_urecord(r, 0); ul.unlock_udomain(_d, &_sctx->aor); return -3; } build_contact(r->contacts,_m); - ul.release_urecord(r); + ul.release_urecord(r, 0); } else { if (insert_contacts(_m, _c, _d, &_sctx->aor, _sctx) < 0) { ul.unlock_udomain(_d, &_sctx->aor); @@ -702,7 +749,9 @@ int save_aux(struct sip_msg* _m, str* forced_binding, char* _d, char* _f, char* sctx.max_contacts = -1; sctx.flags = 0; - if (_f && _f[0]!=0) { + sctx.min_expires = min_expires; + sctx.max_expires = max_expires; + if ( _f ) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid flags parameter"); return -1; @@ -717,7 +766,7 @@ int save_aux(struct sip_msg* _m, str* forced_binding, char* _d, char* _f, char* case 'c': sctx.max_contacts = 0; while (st 0) return -1; /* msg - request - _m - reply + _m - reply */ request_c = get_first_contact(msg); if(request_c) { @@ -1003,6 +1052,192 @@ int save(struct sip_msg* _m, char* _d, char* _f, char* _s) return ret; } +/** + * _remove - Delete an entire AOR entry or just one or more of its Contacts + * Parameter format: _remove(domain, AOR[, Contact URI or plain hostname]) + * + * @udomain: (udomain_t *) + * @aor_gp: address-of-record as a SIP URI (plain string or pvar) + * @contact_gp: contact to be deleted or domain in front of multiple contacts + * + * @return: 1 on success, negative on failure + */ +int _remove(struct sip_msg *msg, char *udomain, char *aor_gp, char *contact_gp) +{ + static struct sip_uri puri; + + struct hostent delete_he, *he; + urecord_t *record; + ucontact_t *contact, *it; + str uri, aor_user, delete_user = { NULL, 0 }; + int err, count = 0; + int delete_by_hostname = 0; + unsigned short delete_port; + + memset(&delete_he, 0, sizeof delete_he); + + if (fixup_get_svalue(msg, (gparam_p)aor_gp, &uri) != 0) { + LM_ERR("failed to get gparam_t value\n"); + return E_UNSPEC; + } + + if (parse_uri(uri.s, uri.len, &puri) != 0) { + LM_ERR("failed to parse aor: '%.*s'\n", uri.len, uri.s); + return E_BAD_URI; + } + + aor_user = puri.user; + + ul.lock_udomain((udomain_t *)udomain, &aor_user); + + if (ul.get_urecord((udomain_t *)udomain, &aor_user, &record) != 0) { + LM_DBG("no record '%.*s' found!\n", aor_user.len, aor_user.s); + err = 1; + goto out_unlock; + } + + /* if no contact uri param is given, delete the whole urecord entry */ + if (!contact_gp) { + if (ul.delete_urecord((udomain_t *)udomain, &aor_user, record, 0) != 0) { + LM_ERR("failed to delete urecord for aor '%.*s'\n", + aor_user.len, aor_user.s); + err = E_UNSPEC; + goto out_unlock; + } + + err = 1; + goto out_unlock; + } + + if (fixup_get_svalue(msg, (gparam_p)contact_gp, &uri) != 0) { + LM_ERR("failed to retrieve value of contact pv\n"); + err = E_UNSPEC; + goto out_unlock; + } + + /* minimum two-letters for the domain name */ + if (uri.len < 5) { + LM_ERR("Invalid domain given: '%.*s'\n", uri.len, uri.s); + err = E_INVALID_PARAMS; + goto out_unlock; + } + + /* a domain/IP address was given instead of a SIP contact URI */ + if (uri.s[0] != 's' || uri.s[1] != 'i' || + uri.s[2] != 'p' || (uri.s[3] != ':' && + (uri.s[3] != 's' || uri.s[4] != ':'))) { + + delete_by_hostname = 1; + + he = sip_resolvehost(&uri, &delete_port, &puri.proto, 0, NULL); + if (!he) { + LM_ERR("cannot resolve given host: '%.*s'\n", uri.len, uri.s); + err = E_UNSPEC; + goto out_unlock; + } + + LM_DBG("Delete by host: '%s'\n", + inet_ntoa(*(struct in_addr *)(he->h_addr_list[0]))); + } else { + LM_DBG("parsing uri: %.*s\n", uri.len, uri.s); + + if (parse_uri(uri.s, uri.len, &puri) != 0) { + LM_ERR("failed to parse contact uri: '%.*s'\n", + uri.len, uri.s); + err = E_BAD_URI; + goto out_unlock; + } + + delete_user = puri.user; + + he = sip_resolvehost(&puri.host, &delete_port, &puri.proto, 0, NULL); + if (!he) { + LM_ERR("cannot resolve given uri: '%.*s'\n", uri.len, uri.s); + err = E_UNSPEC; + goto out_unlock; + } + + if (puri.port_no > 0) + delete_port = puri.port_no; + + LM_DBG("Delete by contact: [ User %.*s | Host %s | Port %d ]\n", + delete_user.len, delete_user.s, + inet_ntoa(*(struct in_addr *)(he->h_addr_list[0])), + delete_port); + } + + if (hostent_cpy(&delete_he, he) != 0) { + LM_ERR("no more pkg mem\n"); + err = E_OUT_OF_MEM; + goto out_unlock; + } + + for (it = record->contacts; it; ) { + contact = it; + it = it->next; + count++; + + LM_DBG("parsing contact uri '%.*s'\n", contact->c.len, contact->c.s); + + if (parse_uri(contact->c.s, contact->c.len, &puri) != 0) { + LM_ERR("failed to parse contact uri: '%.*s'\n", + contact->c.len, contact->c.s); + err = E_BAD_URI; + goto out_unlock; + } + + /* if necessary, solve the next_hop towards the contact */ + he = sip_resolvehost(&contact->next_hop.name, + &contact->next_hop.port, + &contact->next_hop.proto, 0, NULL); + if (!he) { + LM_ERR("failed to resolve next hop of contact '%.*s'\n", + contact->c.len, contact->c.s); + continue; + } + + LM_DBG("Contact: [ User %.*s | Host %s | Port %d ]\n", + puri.user.len, puri.user.s, + inet_ntoa(*(struct in_addr *)(he->h_addr_list[0])), + puri.port_no); + + if (delete_by_hostname) { + if (!memcmp(delete_he.h_addr_list[0], + he->h_addr_list[0], he->h_length)) + { + ul.delete_ucontact(record, contact, 0); + count--; + } + } else { + if (delete_user.len == puri.user.len && + delete_port == puri.port_no && + !memcmp(delete_he.h_addr_list[0], + he->h_addr_list[0], he->h_length) + && !memcmp(delete_user.s, puri.user.s, puri.user.len)) + { + ul.delete_ucontact(record, contact, 0); + count--; + } + } + } + + err = 1; + + /* remove the AOR if no more contacts are attached */ + if (count == 0) { + if (ul.delete_urecord((udomain_t *)udomain, &aor_user, record, 0) != 0) { + LM_ERR("failed to delete urecord for aor '%.*s'\n", + aor_user.len, aor_user.s); + err = 1; + } + } + +out_unlock: + ul.unlock_udomain((udomain_t *)udomain, &aor_user); + free_hostent(&delete_he); + + return err; +} int is_other_contact_f(struct sip_msg* msg, char* _d, char *_s) { @@ -1015,7 +1250,7 @@ int is_other_contact_f(struct sip_msg* msg, char* _d, char *_s) contact_t* ct; int exp, found; udomain_t* ud = (udomain_t*)_d; - + if (parse_message(msg) < 0) { LM_ERR("unable to parse message\n"); return -2; @@ -1059,7 +1294,7 @@ int is_other_contact_f(struct sip_msg* msg, char* _d, char *_s) goto end; } else { c = r->contacts; - } + } while (c) { if (!c->received.len || !c->received.s || c->received.len < 4 /* sip:*/) { diff --git a/modules/registrar/save.h b/modules/registrar/save.h index 83d67a4ab88..3891f6b2ea0 100644 --- a/modules/registrar/save.h +++ b/modules/registrar/save.h @@ -1,7 +1,7 @@ /* * $Id$ * - * Functions that process REGISTER message + * Functions that process REGISTER message * and store data in usrloc * * Copyright (C) 2001-2003 FhG Fokus @@ -18,21 +18,21 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- - * 2003-03-21 save_noreply added, provided by Maxim Sobolev + * 2003-03-21 save_noreply added, provided by Maxim Sobolev * (janakj) * 2006-11-22 save_noreply and save_memory merged into save() (bogdan) */ /*! * \file * \brief SIP registrar module - process REGISTER message - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef SAVE_H @@ -41,15 +41,26 @@ #include "../../parser/msg_parser.h" - /*! \brief * Process REGISTER request and save it's contacts */ int save(struct sip_msg* _m, char* _d, char* _cflags, char* _s); +/** + * _remove - Delete an entire AOR entry or one or more of its Contacts + * Parameter format: delete(domain, AOR[, Contact URI or plain hostname]) + * + * @domain: logical domain name (usually name of location table) + * @aor_gp: address-of-record as a SIP URI (plain string or pvar) + * @contact_gp: contact to be deleted or domain in front of multiple contacts + * + * @return: 1 on success, negative on failure + */ +int _remove(struct sip_msg *msg, char *domain, char *aor, char *fixed_uri_param); + /* * checks if there is another contact except the ones specified in the avp - */ + */ int is_other_contact_f(struct sip_msg* msg, char* _d, char *_s); #endif /* SAVE_H */ diff --git a/modules/registrar/sip_msg.c b/modules/registrar/sip_msg.c index 372f4e5554a..28ad6bb30da 100644 --- a/modules/registrar/sip_msg.c +++ b/modules/registrar/sip_msg.c @@ -17,16 +17,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! * \file * \brief SIP registrar module - SIP message related functions - * \ingroup registrar - */ + * \ingroup registrar + */ @@ -53,7 +53,7 @@ static struct hdr_field* act_contact; static inline int get_expires_hf(struct sip_msg* _m) { exp_body_t* p; - + if (_m->expires) { p = (exp_body_t*)_m->expires->parsed; if (p->valid) { @@ -74,13 +74,13 @@ static inline int get_expires_hf(struct sip_msg* _m) int parse_message(struct sip_msg* _m) { struct hdr_field* ptr; - + if (parse_headers(_m, HDR_EOH_F, 0) == -1) { rerrno = R_PARSE; LM_ERR("failed to parse headers\n"); return -1; } - + if (!_m->to) { rerrno = R_TO_MISS; LM_ERR("To not found\n"); @@ -104,7 +104,7 @@ int parse_message(struct sip_msg* _m) LM_ERR("failed to parse expires body\n"); return -5; } - + if (_m->contact) { ptr = _m->contact; while(ptr) { @@ -118,7 +118,7 @@ int parse_message(struct sip_msg* _m) ptr = ptr->next; } } - + return 0; } @@ -132,11 +132,11 @@ int check_contacts(struct sip_msg* _m, int* _s) { struct hdr_field* p; contact_t* c; - + *_s = 0; /* Message without contacts is OK */ if (_m->contact == 0) return 0; - + if (((contact_body_t*)_m->contact->parsed)->star == 1) { /* The first Contact HF is star */ /* Expires must be zero */ @@ -144,13 +144,13 @@ int check_contacts(struct sip_msg* _m, int* _s) rerrno = R_STAR_EXP; return 1; } - + /* Message must contain no contacts */ if (((contact_body_t*)_m->contact->parsed)->contacts) { rerrno = R_STAR_CONT; return 1; } - + /* Message must contain no other Contact HFs */ p = _m->contact->next; while(p) { @@ -160,7 +160,7 @@ int check_contacts(struct sip_msg* _m, int* _s) } p = p->next; } - + *_s = 1; } else { /* The first Contact HF is not star */ /* Message must contain no star Contact HF */ diff --git a/modules/registrar/sip_msg.h b/modules/registrar/sip_msg.h index e3cef6a06ef..5b05a706906 100644 --- a/modules/registrar/sip_msg.h +++ b/modules/registrar/sip_msg.h @@ -17,15 +17,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! * \file * \brief SIP registrar module - SIP message related functions - * \ingroup registrar - */ + * \ingroup registrar + */ #ifndef SIP_MSG_H diff --git a/modules/rest_client/Makefile b/modules/rest_client/Makefile new file mode 100644 index 00000000000..f37a965ba55 --- /dev/null +++ b/modules/rest_client/Makefile @@ -0,0 +1,13 @@ +# Makefile v 1.0 2002/12/27 +# +# Mathops module makefile +# +# +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=rest_client.so +LIBS+=-lcurl + +include ../../Makefile.modules diff --git a/modules/rest_client/README b/modules/rest_client/README new file mode 100644 index 00000000000..c94daf5ad34 --- /dev/null +++ b/modules/rest_client/README @@ -0,0 +1,203 @@ +rest_client Module + +Liviu Chircu + + OpenSIPS Solutions + + +Edited by + +Liviu Chircu + + Copyright © 2013 www.opensips-solutions.com + Revision History + Revision $Revision$ $Date$ + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. Dependencies + + 1.2.1. OpenSIPS Modules + 1.2.2. External Libraries or Applications + + 1.3. Exported Parameters + + 1.3.1. connection_timeout (integer) + 1.3.2. curl_timeout (integer) + 1.3.3. ssl_verifypeer (integer) + 1.3.4. ssl_verifyhost (integer) + 1.3.5. ssl_capath (integer) + + 1.4. Exported Functions + + 1.4.1. rest_get(url, body_pv[, ctype_pv[, + retcode_pv]]) + + 1.4.2. rest_post(url, send_body_pv, send_ctype_pv, + recv_body_pv[, recv_ctype_pv[, retcode_pv]]) + + List of Examples + + 1.1. Setting the connection_timeout parameter + 1.2. Setting the curl_timeout parameter + 1.3. Setting the ssl_verifypeer parameter + 1.4. Setting the ssl_verifyhost parameter + 1.5. Setting the ssl_capath parameter + 1.6. rest_get usage + 1.7. rest_post usage + +Chapter 1. Admin Guide + +1.1. Overview + + The rest_client module provides a means of interacting with an + HTTP server by doing RESTful queries, such as GET and POST. + +1.2. Dependencies + +1.2.1. OpenSIPS Modules + + The following modules must be loaded before this module: + * No dependencies on other OpenSIPS modules.. + +1.2.2. External Libraries or Applications + + The following libraries or applications must be installed + before running OpenSIPS with this module loaded: + * libcurl. + +1.3. Exported Parameters + +1.3.1. connection_timeout (integer) + + Maximum time allowed to establish a connection with the server. + + Default value is “20” seconds. + + Example 1.1. Setting the connection_timeout parameter +... +modparam("rest_client", "connection_timeout", 300) +... + +1.3.2. curl_timeout (integer) + + Maximum time allowed for the libcurl transfer to complete. + + Default value is “20” seconds. + + Example 1.2. Setting the curl_timeout parameter +... +modparam("rest_client", "curl_timeout", 300) +... + +1.3.3. ssl_verifypeer (integer) + + Set this to 0 in order to disable the verification of the + remote peer's certificate. Verification is done using a default + bundle of CA certificates which come with libcurl. + + Default value is “1” (enabled). + + Example 1.3. Setting the ssl_verifypeer parameter +... +modparam("rest_client", "ssl_verifypeer", 0) +... + +1.3.4. ssl_verifyhost (integer) + + Set this to 0 in order to disable the verification that the + remote peer actually corresponds to the server listed in the + certificate. + + Default value is “1” (enabled). + + Example 1.4. Setting the ssl_verifyhost parameter +... +modparam("rest_client", "ssl_verifyhost", 0) +... + +1.3.5. ssl_capath (integer) + + An optional path for CA certificates to be used for host + verifications. + + Example 1.5. Setting the ssl_capath parameter +... +modparam("rest_client", "ssl_capath", "/home/opensips/ca_certificates") +... + +1.4. Exported Functions + +1.4.1. rest_get(url, body_pv[, ctype_pv[, retcode_pv]]) + + Issues an HTTP GET request to the given 'url', and returns a + representation of the resource. + + The body_pv pseudo-var will hold the body of the HTTP response. + + The optional ctype_pv pseudo-var will contain the value of the + "Content-Type:" header. + + The optional retcode_pv pseudo-var is used to retain the HTTP + status code of the response message. + + Possible parameter types + * url - String, pseudo-variable, or a String which includes + pseudo-variables. (useful for specifying additional + attribute-value fields in the URL) + * body_pv, ctype_pv, retcode_pv - pseudo-variables + + This function can be used from the startup, branch, failure, + request and timer routes. + + Example 1.6. rest_get usage +... +# Example of querying a REST service to get the credit of an account + +if (!rest_get("http://getcredit.org/?ruri=$fU", "$var(credit)", "$var(ct +)", "$var(rcode)")) { + xlog("Error code $var(rcode) in HTTP GET!\n"); + send_reply("403", "Not registered"); + exit; +} +... + +1.4.2. rest_post(url, send_body_pv, send_ctype_pv, recv_body_pv[, +recv_ctype_pv[, retcode_pv]]) + + Issues an HTTP POST request to the specified 'url'. The request + body will be copied from the 'send_body_pv' pseudo-variable. + Its MIME content type will be taken from 'send_ctype_pv'. + + The recv_body_pv pseudo-var will hold the body of the HTTP + response. + + The optional recv_ctype_pv parameter will contain the value of + the "Content-Type:" header of the response message. + + The optional retcode_pv pseudo-var parameter can be given in + order to save the HTTP status code of the response message. + + Possible parameter types + * url, send_body_pv, send_type_pv - String, pseudo-variable, + or a String which includes pseudo-variables. + * recv_body_pv, recv_ctype_pv, retcode_pv - pseudo-variables + + This function can be used from the startup, branch, failure, + request and timer routes. + + Example 1.7. rest_post usage +... +# Storing data using a RESTful service with an HTTP POST request + +if (!rest_post("http://myserver.org/register_user", "$fU", "text/plain", + "$var(body)", "$var(ct)", "$var(rcode)")) { + xlog("Error code $var(rcode) in HTTP POST!\n"); + send_reply("403", "POST Forbidden"); + exit; +} +... diff --git a/modules/rest_client/doc/rest_client.xml b/modules/rest_client/doc/rest_client.xml new file mode 100644 index 00000000000..b10dadb6d4e --- /dev/null +++ b/modules/rest_client/doc/rest_client.xml @@ -0,0 +1,47 @@ + + + + + +%docentities; + +]> + + + + rest_client Module + + + Liviu + Chircu + OpenSIPS Solutions + liviu@opensips.org + + + Liviu + Chircu +
+ liviu@opensips.org +
+
+
+ + 2013 + &osipssol; + + + + $Revision$ + $Date$ + + +
+ + + &admin; + +
diff --git a/modules/rest_client/doc/rest_client_admin.xml b/modules/rest_client/doc/rest_client_admin.xml new file mode 100644 index 00000000000..44e6ed69ce2 --- /dev/null +++ b/modules/rest_client/doc/rest_client_admin.xml @@ -0,0 +1,262 @@ + + + + + &adminguide; + +
+ Overview + + The rest_client module provides a means of interacting + with an HTTP server by doing RESTful queries, such as GET and POST. + +
+ +
+ Dependencies +
+ &osips; Modules + + The following modules must be loaded before this module: + + + + No dependencies on other &osips; modules.. + + + + +
+ +
+ External Libraries or Applications + + The following libraries or applications must be installed before + running &osips; with this module loaded: + + + + libcurl. + + + + +
+
+ +
+ Exported Parameters +
+ <varname>connection_timeout</varname> (integer) + + Maximum time allowed to establish a connection with the server. + + + + Default value is 20 seconds. + + + + Setting the <varname>connection_timeout</varname> parameter + +... +modparam("rest_client", "connection_timeout", 300) +... + + +
+ +
+ <varname>curl_timeout</varname> (integer) + + Maximum time allowed for the libcurl transfer to complete. + + + + Default value is 20 seconds. + + + + Setting the <varname>curl_timeout</varname> parameter + +... +modparam("rest_client", "curl_timeout", 300) +... + + +
+ +
+ <varname>ssl_verifypeer</varname> (integer) + + Set this to 0 in order to disable the verification of the remote peer's + certificate. Verification is done using a default bundle of CA certificates + which come with libcurl. + + + + Default value is 1 (enabled). + + + + Setting the <varname>ssl_verifypeer</varname> parameter + +... +modparam("rest_client", "ssl_verifypeer", 0) +... + + +
+ +
+ <varname>ssl_verifyhost</varname> (integer) + + Set this to 0 in order to disable the verification that the remote peer + actually corresponds to the server listed in the certificate. + + + + Default value is 1 (enabled). + + + + Setting the <varname>ssl_verifyhost</varname> parameter + +... +modparam("rest_client", "ssl_verifyhost", 0) +... + + +
+ +
+ <varname>ssl_capath</varname> (integer) + + An optional path for CA certificates to be used for host verifications. + + + Setting the <varname>ssl_capath</varname> parameter + +... +modparam("rest_client", "ssl_capath", "/home/opensips/ca_certificates") +... + + +
+ +
+ +
+ Exported Functions +
+ + <function moreinfo="none">rest_get(url, body_pv[, ctype_pv[, retcode_pv]]) + </function> + + + Issues an HTTP GET request to the given 'url', and returns a representation + of the resource. + + + The body_pv pseudo-var will hold the body of the HTTP + response. + + + The optional ctype_pv pseudo-var will contain the value + of the "Content-Type:" header. + + + The optional retcode_pv pseudo-var is used to retain the + HTTP status code of the response message. + + + Possible parameter types + + + url - String, pseudo-variable, or a String + which includes pseudo-variables. (useful for specifying additional + attribute-value fields in the URL) + + + + body_pv, ctype_pv, retcode_pv - + pseudo-variables + + + + This function can be used from the startup, branch, failure, + request and timer routes. + + + <function moreinfo="none">rest_get</function> usage + +... +# Example of querying a REST service to get the credit of an account + +if (!rest_get("http://getcredit.org/?ruri=$fU", "$var(credit)", "$var(ct)", "$var(rcode)")) { + xlog("Error code $var(rcode) in HTTP GET!\n"); + send_reply("403", "Not registered"); + exit; +} +... + + +
+
+ + <function moreinfo="none">rest_post(url, send_body_pv, send_ctype_pv, + recv_body_pv[, recv_ctype_pv[, retcode_pv]]) + </function> + + + Issues an HTTP POST request to the specified 'url'. The request body will + be copied from the 'send_body_pv' pseudo-variable. Its MIME content type + will be taken from 'send_ctype_pv'. + + + The recv_body_pv pseudo-var will hold the body of the HTTP + response. + + + The optional recv_ctype_pv parameter will contain + the value of the "Content-Type:" header of the response message. + + + The optional retcode_pv pseudo-var parameter can be given + in order to save the HTTP status code of the response message. + + Possible parameter types + + + url, send_body_pv, send_type_pv - + String, pseudo-variable, or a String which includes pseudo-variables. + + + + recv_body_pv, recv_ctype_pv, retcode_pv - + pseudo-variables + + + + This function can be used from the startup, branch, failure, + request and timer routes. + + + <function moreinfo="none">rest_post</function> usage + +... +# Storing data using a RESTful service with an HTTP POST request + +if (!rest_post("http://myserver.org/register_user", "$fU", "text/plain", "$var(body)", "$var(ct)", "$var(rcode)")) { + xlog("Error code $var(rcode) in HTTP POST!\n"); + send_reply("403", "POST Forbidden"); + exit; +} +... + + +
+ +
+
+ diff --git a/modules/rest_client/rest_cb.c b/modules/rest_client/rest_cb.c new file mode 100644 index 00000000000..21cd4477e21 --- /dev/null +++ b/modules/rest_client/rest_cb.c @@ -0,0 +1,99 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-02-28: Created (Liviu) + */ + +#include +#include +#include + +#include "rest_cb.h" + +/** + * write_func - callback; reallocates and extends the @body buffer each time. + * @ptr: pointer to the raw data + * @size: size of a block + * @nmemb: number of blocks + * @body: parameter previously set with the CURLOPT_WRITEDATA option + */ +size_t write_func(char *ptr, size_t size, size_t nmemb, void *body) +{ + int len = size * nmemb; + str *buff = (str *)body; + + if (len == 0) + return 0; + + if (len < 0) + len = strlen(ptr); + + buff->s = pkg_realloc(buff->s, buff->len + len + 1); + if (!buff->s) { + LM_ERR("No more pkg memory!\n"); + return E_OUT_OF_MEM; + } + + memcpy(buff->s + buff->len, ptr, len); + buff->len += len; + buff->s[buff->len] = '\0'; + + return len; +} + +/** + * header_func - callback; called once for each header. retrieves "Content-Type" + * @ptr: pointer to the current header info + * @size: size of a block + * @nmemb: number of blocks + * @body: parameter previously set with the CURLOPT_HEADERFUNCTION option + */ +size_t header_func(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + int len, left; + str *st = (str *)userdata; + + len = left = size * nmemb; + + if (len > CONTENT_TYPE_HDR_LEN && *ptr == 'C' && + memcmp(ptr, HTTP_HDR_CONTENT_TYPE, CONTENT_TYPE_HDR_LEN) == 0) { + + ptr += CONTENT_TYPE_HDR_LEN + 1; + left -= CONTENT_TYPE_HDR_LEN + 1; + + while (*ptr == ' ') { + ptr++; + left--; + } + + st->len = left; + memcpy(st->s, ptr, left); + + trim(st); + } + + LM_DBG("Received: %.*s\n", len, ptr); + + return len; +} + diff --git a/modules/rest_client/rest_cb.h b/modules/rest_client/rest_cb.h new file mode 100644 index 00000000000..2f4b91ffd12 --- /dev/null +++ b/modules/rest_client/rest_cb.h @@ -0,0 +1,45 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-02-28: Created (Liviu) + */ + +#ifndef _REST_CB_H_ +#define _REST_CB_H_ + +#include "../../str.h" +#include "../../mem/mem.h" +#include "../../error.h" +#include "../../dprint.h" +#include "../../pvar.h" +#include "../../trim.h" + +#define HTTP_HDR_CONTENT_TYPE "Content-Type" +#define CONTENT_TYPE_HDR_LEN 12 +#define MAX_CONTENT_TYPE_LEN 64 + +size_t write_func(char *ptr, size_t size, size_t nmemb, void *userdata); +size_t header_func(char *ptr, size_t size, size_t nmemb, void *userdata); + +#endif /* _REST_CB_H_ */ + diff --git a/modules/rest_client/rest_client.c b/modules/rest_client/rest_client.c new file mode 100644 index 00000000000..2a98e844b0a --- /dev/null +++ b/modules/rest_client/rest_client.c @@ -0,0 +1,226 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-02-28: Created (Liviu) + */ + + +#include +#include +#include + +#include "../../sr_module.h" +#include "../../dprint.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../../mod_fix.h" + +#include "rest_methods.h" + +/* + * Module parameters + */ +long connection_timeout = 20; +long curl_timeout = 20; + +char *ssl_capath; + +/* libcurl enables these by default */ +int ssl_verifypeer = 1; +int ssl_verifyhost = 1; + +/* + * Module initialization and cleanup + */ +static int mod_init(void); +static void mod_destroy(void); + +/* + * Fixup functions + */ +static int fixup_rest_get(void **param, int param_no); +static int fixup_rest_post(void **param, int param_no); + +/* + * Function headers + */ +static int w_rest_get(struct sip_msg *msg, char *gp_url, char *body_pv, + char *type_pv, char *code_pv); +static int w_rest_post(struct sip_msg *msg, char *gp_url, char *gp_body, + char *gp_ctype, char *body_pv, char *ctype_pv, char *code_pv); + + +/* + * Exported functions + */ +static cmd_export_t cmds[] = { + { "rest_get",(cmd_function)w_rest_get, 2, fixup_rest_get, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| + ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE }, + { "rest_get",(cmd_function)w_rest_get, 3, fixup_rest_get, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| + ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE }, + { "rest_get",(cmd_function)w_rest_get, 4, fixup_rest_get, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| + ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE }, + { "rest_post",(cmd_function)w_rest_post, 4, fixup_rest_post, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| + ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE }, + { "rest_post",(cmd_function)w_rest_post, 5, fixup_rest_post, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| + ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE }, + { "rest_post",(cmd_function)w_rest_post, 6, fixup_rest_post, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE| + ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE }, + { 0, 0, 0, 0, 0, 0 } +}; + + +/* + * Exported parameters + */ +static param_export_t params[] = { + { "connection_timeout", INT_PARAM, &connection_timeout }, + { "curl_timeout", INT_PARAM, &curl_timeout }, + { "ssl_capath", STR_PARAM, &ssl_capath }, + { "ssl_verifypeer", INT_PARAM, &ssl_verifypeer }, + { "ssl_verifyhost", INT_PARAM, &ssl_verifyhost }, + { 0, 0, 0 } +}; + + +/* + * Module parameter variables + */ +struct module_exports exports = { + "rest_client", + MOD_TYPE_DEFAULT,/* class of this module */ + MODULE_VERSION, /* module version */ + DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ + cmds, /* Exported functions */ + params, /* Exported parameters */ + 0, /* exported statistics */ + 0, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + 0, /* response function*/ + mod_destroy, + 0 /* per-child init function */ +}; + + +static int mod_init(void) +{ + LM_DBG("Initializing...\n"); + + curl_global_init(CURL_GLOBAL_ALL); + + LM_INFO("Module initialized!\n"); + + return 0; +} + +static void mod_destroy(void) +{ + curl_global_cleanup(); +} + +/**************************** Fixup functions *******************************/ + + +static int fixup_rest_get(void **param, int param_no) +{ + switch (param_no) { + case 1: + return fixup_spve(param); + case 2: + case 3: + case 4: + return fixup_pvar(param); + + default: + LM_ERR("Too many parameters!\n"); + return -1; + } +} + +static int fixup_rest_post(void **param, int param_no) +{ + switch (param_no) { + case 1: + case 2: + case 3: + return fixup_spve(param); + case 4: + case 5: + case 6: + return fixup_pvar(param); + + default: + LM_ERR("Too many parameters!\n"); + return -1; + } +} + +/**************************** Module functions *******************************/ + +static int w_rest_get(struct sip_msg *msg, char *gp_url, char *body_pv, + char *type_pv, char *code_pv) +{ + str url; + + if (fixup_get_svalue(msg, (gparam_p)gp_url, &url) != 0) { + LM_ERR("Invalid HTTP URL pseudo variable!\n"); + return -1; + } + + return rest_get_method(msg, url.s, (pv_spec_p)body_pv, (pv_spec_p)type_pv, + (pv_spec_p)code_pv); +} + +static int w_rest_post(struct sip_msg *msg, char *gp_url, char *gp_body, + char *gp_ctype, char *body_pv, char *ctype_pv, char *code_pv) +{ + str url, ctype, body; + + if (fixup_get_svalue(msg, (gparam_p)gp_url, &url) != 0) { + LM_ERR("Invalid HTTP URL pseudo variable!\n"); + return -1; + } + + if (fixup_get_svalue(msg, (gparam_p)gp_ctype, &ctype) != 0) { + LM_ERR("Invalid HTTP POST content type pseudo variable!\n"); + return -1; + } + + if (fixup_get_svalue(msg, (gparam_p)gp_body, &body) != 0) { + LM_ERR("Invalid HTTP POST body pseudo variable!\n"); + return -1; + } + + return rest_post_method(msg, url.s, ctype.s, body.s, (pv_spec_p)body_pv, + (pv_spec_p)ctype_pv, (pv_spec_p)code_pv); +} + diff --git a/modules/rest_client/rest_methods.c b/modules/rest_client/rest_methods.c new file mode 100644 index 00000000000..543f5a075dd --- /dev/null +++ b/modules/rest_client/rest_methods.c @@ -0,0 +1,260 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-02-28: Created (Liviu) + */ + +#include +#include +#include + +#include "rest_methods.h" +#include "rest_cb.h" + +static char err_buff[CURL_ERROR_SIZE]; +static char print_buff[MAX_CONTENT_TYPE_LEN]; + +#define w_curl_easy_setopt(h, opt, value) \ + do { \ + rc = curl_easy_setopt(h, opt, value); \ + if (rc != CURLE_OK) { \ + LM_ERR("setopt operation %d failed (%d)\n", opt, rc); \ + goto error; \ + } \ + } while (0) + +/** + * rest_get_method - performs an HTTP GET request, stores results in pvars + * @msg: sip message struct + * @url: HTTP URL to be queried + * @body_pv: pseudo var which will hold the result body + * @ctype_pv: pvar which will hold the body encoding method + * @code_pv: pvar to hold the HTTP return code + */ +int rest_get_method(struct sip_msg *msg, char *url, + pv_spec_p body_pv, pv_spec_p ctype_pv, pv_spec_p code_pv) +{ + CURLcode rc; + CURL *handle = NULL; + long http_rc; + pv_value_t pv_val; + str st = { print_buff, 0 }; + str body = { 0, 0 }; + + handle = curl_easy_init(); + if (!handle) { + LM_ERR("Init curl handle failed!\n"); + return -1; + } + + w_curl_easy_setopt(handle, CURLOPT_URL, url); + + w_curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, connection_timeout); + w_curl_easy_setopt(handle, CURLOPT_TIMEOUT, curl_timeout); + + w_curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); + w_curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1); + w_curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, err_buff); + w_curl_easy_setopt(handle, CURLOPT_STDERR, stdout); + + w_curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func); + w_curl_easy_setopt(handle, CURLOPT_WRITEDATA, &body); + + w_curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, header_func); + w_curl_easy_setopt(handle, CURLOPT_WRITEHEADER, &st); + + if (ssl_capath) + w_curl_easy_setopt(handle, CURLOPT_CAPATH, ssl_capath); + + if (!ssl_verifypeer) + w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L); + + if (!ssl_verifyhost) + w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L); + + rc = curl_easy_perform(handle); + if (rc != CURLE_OK) { + LM_ERR("Error [%i] while performing curl operation\n", rc); + LM_ERR("[%s]\n", err_buff); + + goto error; + } + + trim(&body); + + pv_val.flags = PV_VAL_STR; + pv_val.rs = body; + + if (pv_set_value(msg, body_pv, 0, &pv_val) != 0) { + LM_ERR("Set body pv value failed!\n"); + goto error; + } + + if (body.s) { + pkg_free(body.s); + } + + if (ctype_pv) { + pv_val.rs = st; + + if (pv_set_value(msg, ctype_pv, 0, &pv_val) != 0) { + LM_ERR("Set content type pv value failed!\n"); + goto error; + } + } + + if (code_pv) { + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_rc); + LM_DBG("Last response code: %ld\n", http_rc); + + pv_val.flags = PV_VAL_INT|PV_TYPE_INT; + pv_val.ri = (int)http_rc; + + if (pv_set_value(msg, code_pv, 0, &pv_val) != 0) { + LM_ERR("Set code pv value failed!\n"); + goto error; + } + } + + curl_easy_cleanup(handle); + return 1; + +error: + curl_easy_cleanup(handle); + return -1; +} + +/** + * rest_post_method - performs an HTTP POST request, stores results in pvars + * @msg: sip message struct + * @url: HTTP URL to be queried + * @ctype: Value for the "Content-Type: " header of the request + * @body: Body of the request + * @body_pv: pseudo var which will hold the result body + * @ctype_pv: pvar which will hold the result content type + * @code_pv: pvar to hold the HTTP return code + */ +int rest_post_method(struct sip_msg *msg, char *url, char *ctype, char *body, + pv_spec_p body_pv, pv_spec_p ctype_pv, pv_spec_p code_pv) +{ + CURLcode rc; + CURL *handle = NULL; + long http_rc; + struct curl_slist *list = NULL; + str st = { print_buff, 0 }; + str res_body = { 0, 0 }; + pv_value_t pv_val; + + handle = curl_easy_init(); + if (!handle) { + LM_ERR("Init curl handle failed!\n"); + return -1; + } + + if (ctype) { + sprintf(print_buff, "Content-Type: %s", ctype); + list = curl_slist_append(list, print_buff); + w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, list); + } + + w_curl_easy_setopt(handle, CURLOPT_URL, url); + + w_curl_easy_setopt(handle, CURLOPT_POST, 1); + w_curl_easy_setopt(handle, CURLOPT_POSTFIELDS, body); + + w_curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, connection_timeout); + w_curl_easy_setopt(handle, CURLOPT_TIMEOUT, curl_timeout); + + w_curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); + w_curl_easy_setopt(handle, CURLOPT_STDERR, stdout); + w_curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, err_buff); + w_curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1); + + w_curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func); + w_curl_easy_setopt(handle, CURLOPT_WRITEDATA, &res_body); + + w_curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, header_func); + w_curl_easy_setopt(handle, CURLOPT_WRITEHEADER, &st); + + if (ssl_capath) + w_curl_easy_setopt(handle, CURLOPT_CAPATH, ssl_capath); + + if (!ssl_verifypeer) + w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L); + + if (!ssl_verifyhost) + w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L); + + rc = curl_easy_perform(handle); + curl_slist_free_all(list); + + if (rc != CURLE_OK) { + LM_ERR("Error [%i] while performing curl operation\n", rc); + LM_ERR("[%s]\n", err_buff); + + goto error; + } + + trim(&res_body); + + pv_val.flags = PV_VAL_STR; + pv_val.rs = res_body; + + if (pv_set_value(msg, body_pv, 0, &pv_val) != 0) { + LM_ERR("Set body pv value failed!\n"); + goto error; + } + + if (res_body.s) { + pkg_free(res_body.s); + } + + if (ctype_pv) { + pv_val.rs = st; + + if (pv_set_value(msg, ctype_pv, 0, &pv_val) != 0) { + LM_ERR("Set content type pv value failed!\n"); + goto error; + } + } + + if (code_pv) { + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_rc); + LM_DBG("Last response code: %ld\n", http_rc); + + pv_val.flags = PV_VAL_INT|PV_TYPE_INT; + pv_val.ri = (int)http_rc; + + if (pv_set_value(msg, code_pv, 0, &pv_val) != 0) { + LM_ERR("Set code pv value failed!\n"); + goto error; + } + } + + curl_easy_cleanup(handle); + return 1; + +error: + curl_easy_cleanup(handle); + return -1; +} diff --git a/modules/rest_client/rest_methods.h b/modules/rest_client/rest_methods.h new file mode 100644 index 00000000000..8067bd2f2af --- /dev/null +++ b/modules/rest_client/rest_methods.h @@ -0,0 +1,48 @@ +/* + * $Id$ + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2013-02-28: Created (Liviu) + */ + +#ifndef _REST_METHODS_ +#define _REST_METHODS_ + +#include "../../pvar.h" +#include "../../dprint.h" +#include "../../error.h" +#include "../../mem/mem.h" + +extern long connection_timeout; +extern long curl_timeout; + +extern char *ssl_capath; +extern int ssl_verifypeer; +extern int ssl_verifyhost; + +int rest_get_method(struct sip_msg *msg, char *url, + pv_spec_p body_pv, pv_spec_p ctype_pv, pv_spec_p code_pv); +int rest_post_method(struct sip_msg *msg, char *url, char *ctype, char *body, + pv_spec_p body_pv, pv_spec_p ctype_pv, pv_spec_p code_pv); + +#endif /* _REST_METHODS_ */ + diff --git a/modules/rls/README b/modules/rls/README index 49d03af4e0a..c5e339c3457 100644 --- a/modules/rls/README +++ b/modules/rls/README @@ -2,8 +2,6 @@ Resource List Server Anca-Maria Vamanu - Voice Sistem SRL - Edited by Anca-Maria Vamanu @@ -14,8 +12,7 @@ Saul Ibarra Corretge Copyright © 2007 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-10-22 13:41:25 +0200 - (Mon, 22 Oct 2012) $ + Revision $Revision: 9371 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/rls/notify.c b/modules/rls/notify.c index 10bcb648269..adc9db35289 100644 --- a/modules/rls/notify.c +++ b/modules/rls/notify.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -99,15 +99,15 @@ int send_full_notify(subs_t* subs, xmlNodePtr service_node, int version, str* rl query_cols[0]= &str_rlsubs_did_col; query_vals[0].type = DB_STR; query_vals[0].nul = 0; - query_vals[0].val.str_val= rlsubs_did; + query_vals[0].val.str_val= rlsubs_did; result_cols[resource_uri_col= n_result_cols++]= &str_resource_uri_col; result_cols[ctype_col= n_result_cols++]= &str_content_type_col; result_cols[pres_state_col= n_result_cols++]= &str_presence_state_col; result_cols[auth_state_col= n_result_cols++]= &str_auth_state_col; result_cols[reason_col= n_result_cols++]= &str_reason_col; - - if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) + + if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto error; @@ -167,9 +167,9 @@ int send_full_notify(subs_t* subs, xmlNodePtr service_node, int version, str* rl update_cols[0]= &str_updated_col; update_vals[0].type = DB_INT; update_vals[0].nul = 0; - update_vals[0].val.int_val= NO_UPDATE_TYPE; - - if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) + update_vals[0].val.int_val= NO_UPDATE_TYPE; + + if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto error; @@ -185,7 +185,7 @@ int send_full_notify(subs_t* subs, xmlNodePtr service_node, int version, str* rl xmlFree(rlmi_body->s); pkg_free(rlmi_body); - if(multipart_body) + if(multipart_body) { pkg_free(multipart_body->s); pkg_free(multipart_body); @@ -210,7 +210,7 @@ int send_full_notify(subs_t* subs, xmlNodePtr service_node, int version, str* rl pkg_free(multipart_body->s); pkg_free(multipart_body); } - + if(cid_array) { for(i= 0; i< result->n ; i++) @@ -245,7 +245,7 @@ int agg_body_sendn_update(str* rl_uri, str bstr, str* rlmi_body, len= 2*bstr.len+ 4+ 102+ cid.len+ 2+ rlmi_body->len+50+1; if(multipart_body) len+= multipart_body->len; - + init_len= len; body.s= (char*)pkg_malloc(len); @@ -255,8 +255,8 @@ int agg_body_sendn_update(str* rl_uri, str bstr, str* rlmi_body, } len= sprintf(body.s, "--%.*s\r\n", bstr.len, bstr.s); len+= sprintf(body.s+ len , "Content-Transfer-Encoding: binary\r\n"); - len+= sprintf(body.s+ len , "Content-ID: <%.*s>\r\n", cid.len, cid.s); - len+= sprintf(body.s+ len , + len+= sprintf(body.s+ len , "Content-ID: <%.*s>\r\n", cid.len, cid.s); + len+= sprintf(body.s+ len , "Content-Type: application/rlmi+xml;charset=\"UTF-8\"\r\n"); len+= sprintf(body.s+ len, "\r\n"); /*blank line*/ body_len = rlmi_body->len; @@ -287,7 +287,7 @@ int agg_body_sendn_update(str* rl_uri, str bstr, str* rlmi_body, } pkg_free(body.s); body.s= NULL; - + if(subs->expires!= 0 && subs->status != TERMINATED_STATUS) { if(pres_update_shtable(rls_table, hash_code,subs, LOCAL_TYPE)< 0) @@ -314,7 +314,7 @@ int add_resource_instance(char* uri, xmlNodePtr resource_node, db_res_t* result, str* cid_array) { xmlNodePtr instance_node= NULL; - db_row_t *row; + db_row_t *row; db_val_t *row_vals; int i, cmp_code; char* auth_state= NULL; @@ -325,7 +325,7 @@ int add_resource_instance(char* uri, xmlNodePtr resource_node, { row = &result->rows[i]; row_vals = ROW_VALUES(row); - + cmp_code= strncmp(row_vals[resource_uri_col].val.string_val, uri, strlen(uri)); if(cmp_code> 0) @@ -333,7 +333,7 @@ int add_resource_instance(char* uri, xmlNodePtr resource_node, if(cmp_code== 0) { - instance_node= xmlNewChild(resource_node, NULL, + instance_node= xmlNewChild(resource_node, NULL, BAD_CAST "instance", NULL); if(instance_node== NULL) { @@ -367,13 +367,13 @@ int add_resource_instance(char* uri, xmlNodePtr resource_node, else if(auth_state_flag & TERMINATED_STATE) { - xmlNewProp(instance_node, BAD_CAST "reason", - BAD_CAST row_vals[reason_col].val.string_val); + xmlNewProp(instance_node, BAD_CAST "reason", + BAD_CAST row_vals[reason_col].val.string_val); } } } - /* if record not found should not add a instance node */ + /* if record not found should not add a instance node */ return 0; error: return -1; @@ -413,7 +413,7 @@ str* constr_rlmi_doc(db_res_t *result, str* rl_uri, int version, xmlDocPtr doc= NULL; xmlNodePtr list_node= NULL; str* rlmi_cont= NULL; - int len; + int len; char* uri; res_param_t param; str* cid_array= NULL; @@ -455,9 +455,9 @@ str* constr_rlmi_doc(db_res_t *result, str* rl_uri, int version, xmlNewProp(list_node, BAD_CAST "fullState", BAD_CAST "true"); xmlDocSetRootElement(doc, list_node); - + /* go through the list -- and add the appropriate 'resource' nodes*/ - + param.list_node= list_node; param.db_result= result; param.cid_array= cid_array; @@ -476,7 +476,7 @@ str* constr_rlmi_doc(db_res_t *result, str* rl_uri, int version, &rlmi_cont->len); *rlmi_cid_array= cid_array; - + xmlFreeDoc(doc); return rlmi_cont; @@ -484,7 +484,7 @@ str* constr_rlmi_doc(db_res_t *result, str* rl_uri, int version, error: if(doc) xmlFreeDoc(doc); - return NULL; + return NULL; } @@ -493,13 +493,13 @@ str* constr_multipart_body(db_res_t* result, str* cid_array, str bstr) char* buf= NULL; int size= BUF_REALLOC_SIZE; int i, buf_len= 0; - db_row_t *row; + db_row_t *row; db_val_t *row_vals; str cid={0, 0}; str body= {0, 0}; str* multi_body= NULL; str ctype; - + LM_DBG("start\n"); buf= pkg_malloc(size); if(buf== NULL) @@ -511,7 +511,7 @@ str* constr_multipart_body(db_res_t* result, str* cid_array, str bstr) { row = &result->rows[i]; row_vals = ROW_VALUES(row); - + if(row_vals[auth_state_col].val.int_val!= ACTIVE_STATE) continue; @@ -539,7 +539,7 @@ str* constr_multipart_body(db_res_t* result, str* cid_array, str bstr) } buf[buf_len]= '\0'; - + multi_body= (str*)pkg_malloc(sizeof(str)); if(multi_body== NULL) { @@ -567,14 +567,14 @@ int rls_notify_extra_hdr(subs_t* subs, str* start_cid, str* bstr, char* p; lexpire_s = int2str(subs->expires, &lexpire_len); - + len = 7 /*Event: */ + subs->event->name.len +4 /*;id=*/+ subs->event_id.len+ CRLF_LEN + 10 /*Contact: <*/ + subs->local_contact.len + 1/*>*/ + ((subs->sockinfo && subs->sockinfo->proto!=PROTO_UDP)? 15/*";transport=xxxx"*/:0) + CRLF_LEN +/*Subscription-State:*/ 20 + ((subs->expires>0)?(15+lexpire_len):25) + CRLF_LEN + /*Require: */ 18 + CRLF_LEN + ((start_cid && bstr)?(/*Content-Type*/59 + - /*start*/12 + start_cid->len + /*boundary*/12 + + /*start*/12 + start_cid->len + /*boundary*/12 + bstr->len + CRLF_LEN):0); hdr->s = (char*)pkg_malloc(len); @@ -590,7 +590,7 @@ int rls_notify_extra_hdr(subs_t* subs, str* start_cid, str* bstr, p+= 7; memcpy(p, subs->event->name.s, subs->event->name.len); p+= subs->event->name.len; - if(subs->event_id.len && subs->event_id.s) + if(subs->event_id.len && subs->event_id.s) { memcpy(p, ";id=", 4); p += 4; @@ -604,7 +604,7 @@ int rls_notify_extra_hdr(subs_t* subs, str* start_cid, str* bstr, p += 10; memcpy(p, subs->local_contact.s, subs->local_contact.len); p += subs->local_contact.len; - + if (subs->sockinfo && subs->sockinfo->proto!=PROTO_UDP) { memcpy(p,";transport=",11); @@ -686,20 +686,20 @@ int rls_send_notify(subs_t* subs, str* body, str* start_cid, if(td ==NULL) { LM_ERR("while building dlg_t structure\n"); - goto error; + goto error; } LM_DBG("constructed dlg_t struct\n"); - size= sizeof(dialog_id_t)+(subs->to_tag.len+ subs->callid.len+ + size= sizeof(dialog_id_t)+(subs->to_tag.len+ subs->callid.len+ subs->from_tag.len) *sizeof(char); - + cb_param = (dialog_id_t*)shm_malloc(size); if(cb_param== NULL) { ERR_MEM(SHARE_MEM); } size= sizeof(dialog_id_t); - + cb_param->callid.s= (char*)cb_param + size; memcpy(cb_param->callid.s, subs->callid.s, subs->callid.len); cb_param->callid.len= subs->callid.len; @@ -713,7 +713,7 @@ int rls_send_notify(subs_t* subs, str* body, str* start_cid, cb_param->from_tag.s= (char*)cb_param + size; memcpy(cb_param->from_tag.s, subs->from_tag.s, subs->from_tag.len); cb_param->from_tag.len= subs->from_tag.len; - + LM_DBG("constructed cb_param\n"); if(rls_notify_extra_hdr(subs, start_cid, bstr, &str_hdr) < 0) @@ -744,7 +744,7 @@ int rls_send_notify(subs_t* subs, str* body, str* start_cid, if(rt < 0) { LM_ERR("in function tmb.t_request_within\n"); - goto error; + goto error; } pkg_free(str_hdr.s); @@ -756,10 +756,10 @@ int rls_send_notify(subs_t* subs, str* body, str* start_cid, rls_free_td(td); if(cb_param) shm_free(cb_param); - + if(str_hdr.s) pkg_free(str_hdr.s); - + return -1; } @@ -785,7 +785,7 @@ dlg_t* rls_notify_dlg(subs_t* subs) LM_ERR("while constructing uri from user and domain\n"); goto error; } - + if(uandd_to_uri(subs->from_user, subs->from_domain, &td->rem_uri)< 0) { LM_ERR("while constructing uri from user and domain\n"); @@ -820,27 +820,27 @@ dlg_t* rls_notify_dlg(subs_t* subs) { if(td->loc_uri.s) pkg_free(td->loc_uri.s); - + if(td->rem_uri.s) pkg_free(td->rem_uri.s); pkg_free(td); - } + } return NULL; } void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps) { - if(ps->param==NULL || *ps->param==NULL || + if(ps->param==NULL || *ps->param==NULL || ((dialog_id_t*)(*ps->param)) == NULL) { LM_DBG("message id not received\n"); return; } - + LM_DBG("completed with status %d [to_tag:" "%.*s]\n",ps->code, - ((dialog_id_t*)(*ps->param))->to_tag.len, + ((dialog_id_t*)(*ps->param))->to_tag.len, ((dialog_id_t*)(*ps->param))->to_tag.s); if(ps->code >= 300) @@ -850,19 +850,19 @@ void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps) db_val_t db_vals[2]; unsigned int hash_code; subs_t subs; - + memset(&subs, 0, sizeof(subs_t)); subs.to_tag= ((dialog_id_t*)(*ps->param))->to_tag; subs.from_tag= ((dialog_id_t*)(*ps->param))->from_tag; subs.callid= ((dialog_id_t*)(*ps->param))->callid; - if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0) + if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0) { LM_ERR("in use_table\n"); goto done; } - + db_keys[0] =&str_to_tag_col; db_vals[0].type = DB_STR; db_vals[0].nul = 0; @@ -874,8 +874,8 @@ void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps) db_vals[1].val.str_val = subs.callid; - if (rls_dbf.delete(rls_db, db_keys, 0, db_vals, 2) < 0) - LM_ERR("cleaning expired messages\n"); + if (rls_dbf.delete(rls_db, db_keys, 0, db_vals, 2) < 0) + LM_ERR("cleaning expired messages\n"); /* delete from cache table */ hash_code= core_hash(&subs.callid, &subs.to_tag , hash_size); @@ -884,9 +884,9 @@ void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps) { LM_ERR("record not found in hash table\n"); } - } + } -done: +done: if(*ps->param !=NULL ) shm_free(*ps->param); return ; @@ -996,15 +996,15 @@ char* generate_string(int seed, int length) int r,i; rstr = (char*) pkg_malloc(length + 1); - if(rstr == NULL) + if(rstr == NULL) { LM_ERR("no more memory\n"); return NULL; } srand(seed); - - for(i=0; i'Z' && r< 'a') diff --git a/modules/rls/notify.h b/modules/rls/notify.h index 08ed0ee4da5..a8fae8c8151 100644 --- a/modules/rls/notify.h +++ b/modules/rls/notify.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -66,10 +66,10 @@ static inline int append_multipart_body(char **buf, int *buf_len, int *size, str } -int send_full_notify(subs_t* subs, xmlNodePtr rl_node, +int send_full_notify(subs_t* subs, xmlNodePtr rl_node, int version, str* rl_uri, unsigned int hash_code); -typedef int (*list_func_t)(char* uri, void* param); +typedef int (*list_func_t)(char* uri, void* param); int process_list_and_exec(xmlNodePtr list, str username, str domain, list_func_t f, void* p, int* c); char* generate_string(int seed, int length); diff --git a/modules/rls/resource_notify.c b/modules/rls/resource_notify.c index 765958e3283..8b056ebdb3a 100644 --- a/modules/rls/resource_notify.c +++ b/modules/rls/resource_notify.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -38,7 +38,7 @@ #include "resource_notify.h" /* how to relate resource oriented dialogs to list_uri */ -/* sol1: use the same callid in Subscribe requests +/* sol1: use the same callid in Subscribe requests * sol2: include an extra header * sol3: put the list_uri as the id of the record stored in * pua and write a function to return that id @@ -58,7 +58,7 @@ int parse_subs_state(str auth_state, str* reason, int* expires) flag= ACTIVE_STATE; if( strncasecmp(auth_state.s, "pending", 7)== 0) - flag= PENDING_STATE; + flag= PENDING_STATE; if( strncasecmp(auth_state.s, "terminated", 10)== 0) { @@ -160,7 +160,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2) int err_ret = -1; LM_DBG("start\n"); - /* extract the dialog information and check if an existing dialog*/ + /* extract the dialog information and check if an existing dialog*/ if( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); @@ -186,7 +186,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2) memset(&dialog, 0, sizeof(ua_pres_t)); dialog.watcher_uri= &pto->uri; if (pto->tag_value.s==NULL || pto->tag_value.len==0 ) - { + { LM_ERR("to tag value not parsed\n"); goto error; } @@ -208,7 +208,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2) { LM_DBG("'From' header not parsed\n"); /* parsing from header */ - if ( parse_from_header( msg )<0 ) + if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); goto error; @@ -216,7 +216,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2) } pfrom = (struct to_body*)msg->from->parsed; dialog.pres_uri= &pfrom->uri; - + if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); @@ -291,31 +291,31 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2) } LM_DBG("[body]= %.*s\n", body.len, body.s); } - + /* update in rlpres_table where rlsusb_did= res_id and resource_uri= from_uri*/ query_cols[n_query_cols]= &str_rlsubs_did_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; - query_vals[n_query_cols].val.str_val= *res_id; + query_vals[n_query_cols].val.str_val= *res_id; n_query_cols++; - + query_cols[n_query_cols]= &str_resource_uri_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; - query_vals[n_query_cols].val.str_val= *dialog.pres_uri; + query_vals[n_query_cols].val.str_val= *dialog.pres_uri; n_query_cols++; query_cols[n_query_cols]= &str_updated_col; query_vals[n_query_cols].type = DB_INT; query_vals[n_query_cols].nul = 0; - query_vals[n_query_cols].val.int_val= UPDATED_TYPE; + query_vals[n_query_cols].val.int_val= UPDATED_TYPE; n_query_cols++; query_cols[n_query_cols]= &str_auth_state_col; query_vals[n_query_cols].type = DB_INT; query_vals[n_query_cols].nul = 0; - query_vals[n_query_cols].val.int_val= auth_flag; + query_vals[n_query_cols].val.int_val= auth_flag; n_query_cols++; query_cols[n_query_cols]= &str_reason_col; @@ -346,7 +346,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2) n_query_cols++; } - if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) + if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto error; @@ -427,7 +427,7 @@ int parse_rlsubs_did(char* str_did, str* callid, str* from_tag, str* to_tag) } callid->s= str_did; callid->len= smc- str_did; - + from_tag->s= smc+ DID_SEP_LEN; smc= strstr(from_tag->s, DID_SEP); if(smc== NULL) @@ -437,7 +437,7 @@ int parse_rlsubs_did(char* str_did, str* callid, str* from_tag, str* to_tag) return -1; } from_tag->len= smc- from_tag->s; - + to_tag->s= smc+ DID_SEP_LEN; to_tag->len= strlen(str_did)- 2* DID_SEP_LEN- callid->len- from_tag->len; @@ -516,7 +516,7 @@ void timer_send_notify(unsigned int ticks,void *param) int n_result_cols= 0, i; db_res_t *result= NULL; char* prev_did= NULL, * curr_did= NULL; - db_row_t *row; + db_row_t *row; db_val_t *row_vals; char* resource_uri; str body; @@ -535,7 +535,7 @@ void timer_send_notify(unsigned int ticks,void *param) query_cols[0]= &str_updated_col; query_vals[0].type = DB_INT; query_vals[0].nul = 0; - query_vals[0].val.int_val= UPDATED_TYPE; + query_vals[0].val.int_val= UPDATED_TYPE; result_cols[did_col= n_result_cols++]= &str_rlsubs_did_col; result_cols[resource_uri_col= n_result_cols++]= &str_resource_uri_col; @@ -544,10 +544,10 @@ void timer_send_notify(unsigned int ticks,void *param) result_cols[reason_col= n_result_cols++]= &str_reason_col; result_cols[body_col= n_result_cols++]= &str_presence_state_col; - /* query in alfabetical order after rlsusbs_did + /* query in alfabetical order after rlsusbs_did * (resource list Subscribe dialog indentifier)*/ - if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) + if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto error; @@ -566,9 +566,9 @@ void timer_send_notify(unsigned int ticks,void *param) update_cols[0]= &str_updated_col; update_vals[0].type = DB_INT; update_vals[0].nul = 0; - update_vals[0].val.int_val= NO_UPDATE_TYPE; + update_vals[0].val.int_val= NO_UPDATE_TYPE; - if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) + if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto error; @@ -603,7 +603,7 @@ void timer_send_notify(unsigned int ticks,void *param) { row = &result->rows[i]; row_vals = ROW_VALUES(row); - + curr_did= (char*)row_vals[did_col].val.string_val; resource_uri= (char*)row_vals[resource_uri_col].val.string_val; auth_state_flag= row_vals[auth_state_col].val.int_val; @@ -627,7 +627,7 @@ void timer_send_notify(unsigned int ticks,void *param) dialog = NULL; } - /* for the new dialog -> search the dialog info and + /* for the new dialog -> search the dialog info and * fill the dialog structure and start a new rlmi document */ if(prev_did== NULL || strcmp(prev_did, curr_did) != 0) { @@ -671,13 +671,13 @@ void timer_send_notify(unsigned int ticks,void *param) xmlDocSetRootElement(rlmi_doc, list_node); buf_len = 0; - /* !!!! for now I will include the auth state without checking if - * it has changed - > in future chech if it works */ - } + /* !!!! for now I will include the auth state without checking if + * it has changed - > in future chech if it works */ + } - /* add a node in rlmi_doc and if any presence state registered add + /* add a node in rlmi_doc and if any presence state registered add * it in the buffer */ - + resource_node= xmlNewChild(list_node,NULL,BAD_CAST "resource", NULL); if(resource_node== NULL) { @@ -685,10 +685,10 @@ void timer_send_notify(unsigned int ticks,void *param) goto error; } xmlNewProp(resource_node, BAD_CAST "uri", BAD_CAST resource_uri); - + /* there might be more records with the same uri- more instances- * search and add them all */ - + while(1) { cid.s = NULL; @@ -708,7 +708,7 @@ void timer_send_notify(unsigned int ticks,void *param) goto error; } xmlNewProp(instance_node, BAD_CAST "state", BAD_CAST auth_state); - + if(auth_state_flag & ACTIVE_STATE) { cid.s= generate_cid(resource_uri, strlen(resource_uri)); @@ -721,7 +721,7 @@ void timer_send_notify(unsigned int ticks,void *param) xmlNewProp(instance_node, BAD_CAST "reason", BAD_CAST row_vals[reason_col].val.string_val); } - + /* add in the multipart buffer */ if(cid.s) { @@ -743,9 +743,9 @@ void timer_send_notify(unsigned int ticks,void *param) row = &result->rows[i]; row_vals = ROW_VALUES(row); - + if(strncmp(row_vals[resource_uri_col].val.string_val,resource_uri, - strlen(resource_uri)) || strncmp(curr_did, + strlen(resource_uri)) || strncmp(curr_did, row_vals[did_col].val.string_val, strlen(curr_did))) { i--; diff --git a/modules/rls/resource_notify.h b/modules/rls/resource_notify.h index 51baa30af40..056ec82ba1b 100644 --- a/modules/rls/resource_notify.h +++ b/modules/rls/resource_notify.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/rls/rls.c b/modules/rls/rls.c index 20eae96d60b..f95dd5f11dd 100644 --- a/modules/rls/rls.c +++ b/modules/rls/rls.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -197,11 +197,27 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "xcap", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "pua", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "presence", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports= { "rls", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -238,7 +254,7 @@ static int mod_init(void) return -1; } server_address.len= strlen(server_address.s); - + if(presence_server.s) presence_server.len= strlen(presence_server.s); @@ -351,7 +367,7 @@ static int mod_init(void) LM_ERR("error during table version check.\n"); return -1; } - + if(hash_size<=1) hash_size= 512; else @@ -409,7 +425,7 @@ static int mod_init(void) LM_ERR("Can't bind pua\n"); return -1; } - + if (bind_pua(&pua) < 0) { LM_ERR("mod_init Can't bind pua\n"); @@ -421,7 +437,7 @@ static int mod_init(void) return -1; } pua_send_subscribe= pua.send_subscribe; - + if(pua.get_record_id == NULL) { LM_ERR("Could not import send_subscribe\n"); @@ -445,7 +461,7 @@ static int mod_init(void) LM_ERR("Can't bind xcap_client\n"); return -1; } - + if (bind_xcap_client(&xcap_client_api) < 0) { LM_ERR("Can't bind xcap\n"); @@ -459,11 +475,11 @@ static int mod_init(void) } } register_timer( "rls-notify", timer_send_notify, 0, waitn_time); - + register_timer( "rls-pclean", rls_presentity_clean, 0, clean_period); - + register_timer( "rls-dbupdate", rlsubs_table_update, 0, clean_period); - + return 0; } @@ -471,12 +487,12 @@ int parse_xcap_root(void) { char* sep; sep= strchr(xcap_root, ':'); - + if(sep) { char* sep2= NULL; str port_str; - + sep2= strchr(sep+ 1, '/'); if(!sep2) sep2 = xcap_root + strlen(xcap_root); @@ -519,12 +535,12 @@ static int child_init(int rank) } else { - if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0) + if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0) { LM_ERR("child %d: Error in use_table rlsubs_table\n", rank); return -1; } - if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) + if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("child %d: Error in use_table rlpres_table\n", rank); return -1; @@ -543,7 +559,7 @@ static int child_init(int rank) void destroy(void) { LM_DBG("start\n"); - + if(rls_table) { if(rls_db) @@ -558,7 +574,7 @@ int handle_expired_record(subs_t* s) { int expires = s->expires; s->expires = 0; - /* send Notify with state terminated*/ + /* send Notify with state terminated*/ if( rls_send_notify(s, NULL, NULL, NULL)< 0) { LM_ERR("in function send_notify\n"); @@ -576,26 +592,26 @@ void rlsubs_table_update(unsigned int ticks,void *param) if(ticks== 0 && param == NULL) no_lock= 1; - + if(rls_dbf.use_table(rls_db, &rlsubs_table)< 0) { LM_ERR("sql use table failed\n"); return; } - pres_update_db_subs(rls_db, rls_dbf, rls_table, hash_size, + pres_update_db_subs(rls_db, rls_dbf, rls_table, hash_size, no_lock, handle_expired_record); } int rls_restore_db_subs(void) { - db_key_t result_cols[22]; + db_key_t result_cols[22]; db_res_t *res= NULL; - db_row_t *row = NULL; + db_row_t *row = NULL; db_val_t *row_vals= NULL; int i; int n_result_cols= 0; - int pres_uri_col, expires_col, from_user_col, from_domain_col,to_user_col; + int pres_uri_col, expires_col, from_user_col, from_domain_col,to_user_col; int callid_col,totag_col,fromtag_col,to_domain_col,sockinfo_col,reason_col; int event_col,contact_col,record_route_col, event_id_col, status_col; int remote_cseq_col, local_cseq_col, local_contact_col, version_col; @@ -631,7 +647,7 @@ int rls_restore_db_subs(void) result_cols[version_col= n_result_cols++] = &str_version_col; result_cols[status_col= n_result_cols++] = &str_status_col; result_cols[reason_col= n_result_cols++] = &str_reason_col; - + if(!rls_db) { LM_ERR("null database connection\n"); @@ -673,13 +689,13 @@ int rls_restore_db_subs(void) memset(&s, 0, sizeof(subs_t)); expires= row_vals[expires_col].val.int_val; - + if(expires< (int)time(NULL)) continue; - + s.pres_uri.s= (char*)row_vals[pres_uri_col].val.string_val; s.pres_uri.len= strlen(s.pres_uri.s); - + s.to_user.s=(char*)row_vals[to_user_col].val.string_val; s.to_user.len= strlen(s.to_user.s); @@ -688,7 +704,7 @@ int rls_restore_db_subs(void) s.from_user.s=(char*)row_vals[from_user_col].val.string_val; s.from_user.len= strlen(s.from_user.s); - + s.from_domain.s=(char*)row_vals[from_domain_col].val.string_val; s.from_domain.len= strlen(s.from_domain.s); @@ -703,7 +719,7 @@ int rls_restore_db_subs(void) ev_sname.s= (char*)row_vals[event_col].val.string_val; ev_sname.len= strlen(ev_sname.s); - + event= pres_contains_event(&ev_sname, &parsed_event); if(event== NULL) { @@ -719,7 +735,7 @@ int rls_restore_db_subs(void) s.remote_cseq= row_vals[remote_cseq_col].val.int_val; s.local_cseq= row_vals[local_cseq_col].val.int_val; s.version= row_vals[version_col].val.int_val; - + s.expires= expires- (int)time(NULL); s.status= row_vals[status_col].val.int_val; @@ -732,11 +748,11 @@ int rls_restore_db_subs(void) s.local_contact.s=(char*)row_vals[local_contact_col].val.string_val; s.local_contact.len= strlen(s.local_contact.s); - + s.record_route.s=(char*)row_vals[record_route_col].val.string_val; if(s.record_route.s) s.record_route.len= strlen(s.record_route.s); - + sockinfo_str.s = (char*)row_vals[sockinfo_col].val.string_val; if (sockinfo_str.s) { diff --git a/modules/rls/rls.h b/modules/rls/rls.h index de675579b3f..81d878885ca 100644 --- a/modules/rls/rls.h +++ b/modules/rls/rls.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -41,8 +41,8 @@ #include "../../db/db_con.h" #include "../../db/db.h" -#define NO_UPDATE_TYPE -1 -#define UPDATED_TYPE 1 +#define NO_UPDATE_TYPE -1 +#define UPDATED_TYPE 1 #define NOT_KNOWN_STATE 0 #define ACTIVE_STATE 1<<1 @@ -83,9 +83,9 @@ typedef struct rls_resource extern char* xcap_root; extern unsigned int xcap_port; -extern str server_address; -extern str presence_server; -extern int waitn_time; +extern str server_address; +extern str presence_server; +extern int waitn_time; extern str rlsubs_table; extern str rlpres_table; extern int hash_size; @@ -191,13 +191,13 @@ static inline int CONSTR_RLSUBS_DID(subs_t* subs, str *did) return -1; } did->s= (char*)pkg_malloc(len); - if(did->s== NULL) + if(did->s== NULL) { - ERR_MEM(PKG_MEM_STR); + ERR_MEM(PKG_MEM_STR); } - - did->len= sprintf(did->s, "%.*s%s%.*s%s%.*s", subs->callid.len, - subs->callid.s, DID_SEP,subs->from_tag.len, subs->from_tag.s, + + did->len= sprintf(did->s, "%.*s%s%.*s%s%.*s", subs->callid.len, + subs->callid.s, DID_SEP,subs->from_tag.len, subs->from_tag.s, DID_SEP, subs->to_tag.len, subs->to_tag.s); if(did->len>= len) @@ -207,7 +207,7 @@ static inline int CONSTR_RLSUBS_DID(subs_t* subs, str *did) return -1; } did->s[did->len]= '\0'; - + LM_DBG("did= %s\n", did->s); return 0; error: diff --git a/modules/rls/subscribe.c b/modules/rls/subscribe.c index bae247436f7..b83b5b4140e 100644 --- a/modules/rls/subscribe.c +++ b/modules/rls/subscribe.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -61,7 +61,7 @@ static str pu_404_rpl = str_init("Not Found"); #define SUBS_EXTRA_HDRS "Supported: eventlist\r\nAccept: application/pidf+xml, application/rlmi+xml, application/watcherinfo+xml, multipart/related, application/xcap-diff+xml\r\n" #define SUBS_EXTRA_HDRS_LEN sizeof(SUBS_EXTRA_HDRS) -1 -subs_t* constr_new_subs(struct sip_msg* msg, struct to_body *pto, +subs_t* constr_new_subs(struct sip_msg* msg, struct to_body *pto, pres_ev_t* event); int update_rlsubs( subs_t* subs,unsigned int hash_code, @@ -112,7 +112,7 @@ xmlNodePtr search_service_uri(xmlDocPtr doc, str* service_uri) LM_ERR("failed to construct uri from user and domain\n"); return NULL; } - if(uri_str.len== service_uri->len && + if(uri_str.len== service_uri->len && strncmp(uri_str.s, service_uri->s, uri_str.len) == 0) { pkg_free(uri_str.s); @@ -283,7 +283,7 @@ int reply_421(struct sip_msg* msg) { str hdr_append; char buffer[256]; - + hdr_append.s = buffer; hdr_append.s[0]='\0'; hdr_append.len = sprintf(hdr_append.s, "Require: eventlist\r\n"); @@ -371,14 +371,14 @@ int reply_200(struct sip_msg* msg, str* local_contact, int expires, str* rtag) { LM_ERR("failed to send reply\n"); goto error; - } + } pkg_free(hdr_append); return 0; error: pkg_free(hdr_append); return -1; -} +} int reply_489(struct sip_msg * msg) { @@ -399,7 +399,7 @@ int reply_489(struct sip_msg * msg) { LM_ERR("while getting ev_list\n"); return -1; - } + } memcpy(hdr_append.s+ hdr_append.len, ev_list->s, ev_list->len); hdr_append.len+= ev_list->len; pkg_free(ev_list->s); @@ -407,7 +407,7 @@ int reply_489(struct sip_msg * msg) memcpy(hdr_append.s+ hdr_append.len, CRLF, CRLF_LEN); hdr_append.len+= CRLF_LEN; hdr_append.s[hdr_append.len]= '\0'; - + if (add_lump_rpl( msg, hdr_append.s, hdr_append.len, LUMP_RPL_HDR)==0 ) { LM_ERR("unable to add lump_rl\n"); @@ -431,7 +431,7 @@ int reply_489(struct sip_msg * msg) int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) { - struct to_body *pto, *pfrom = NULL; + struct to_body *pto, *pfrom = NULL; subs_t subs; pres_ev_t* event= NULL; str* contact= NULL; @@ -463,7 +463,7 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) LM_DBG("no supported header found\n"); return to_presence_code; } - + if(parse_supported(msg) < 0) { LM_ERR("failed to parse supported headers\n"); @@ -506,7 +506,7 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) goto bad_event; } subs.event= event; - + /* extract the id if any*/ ev_param= parsed_event->params; while(ev_param) @@ -550,7 +550,7 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) goto error; } - /*verify if Request URI represents a list by asking xcap server*/ + /*verify if Request URI represents a list by asking xcap server*/ if(uandd_to_uri(msg->parsed_uri.user, msg->parsed_uri.host, &subs.pres_uri)< 0) { @@ -559,7 +559,7 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) reply_str = pu_500_rpl; goto error; } - + if( get_resource_list(&subs.pres_uri, fu.user, fu.host, &service_node, &doc) < 0) { @@ -568,7 +568,7 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) reply_str = pu_500_rpl; goto error; } - + if(doc== NULL|| service_node==NULL) { LM_DBG("list not found - search for uri = %.*s\n",subs.pres_uri.len, @@ -675,12 +675,12 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) } if(contact) - { + { if(contact->s) pkg_free(contact->s); pkg_free(contact); } - + pkg_free(subs.pres_uri.s); if(subs.record_route.s) pkg_free(subs.record_route.s); @@ -703,16 +703,16 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) error_free: if(contact) - { + { if(contact->s) pkg_free(contact->s); pkg_free(contact); } if(subs.pres_uri.s) pkg_free(subs.pres_uri.s); - + if(subs.record_route.s) - pkg_free(subs.record_route.s); + pkg_free(subs.record_route.s); if(doc) xmlFreeDoc(doc); return -1; @@ -741,10 +741,10 @@ int update_rlsubs( subs_t* subs, unsigned int hash_code, } s->expires= subs->expires+ (int)time(NULL); - + if(s->db_flag == NO_UPDATEDB_FLAG) s->db_flag= UPDATEDB_FLAG; - + if( s->remote_cseq>= subs->remote_cseq) { lock_release(&rls_table[hash_code].lock); @@ -798,10 +798,10 @@ int update_rlsubs( subs_t* subs, unsigned int hash_code, } ps->next= s->next; shm_free(s); - + /* delete from rls_presentity table also */ } - + lock_release(&rls_table[hash_code].lock); return 0; @@ -866,7 +866,7 @@ int resource_subscriptions(subs_t* subs, xmlNodePtr rl_node) list_entry_t *rls_subs_list = NULL; void* params[2] = {&s, &rls_contact_list}; - /* if is initial send an initial Subscribe + /* if is initial send an initial Subscribe * else search in hash table for a previous subscription */ if(CONSTR_RLSUBS_DID(subs, &did_str)< 0) diff --git a/modules/rls/subscribe.h b/modules/rls/subscribe.h index 549985a0baf..9444c9bcd0c 100644 --- a/modules/rls/subscribe.h +++ b/modules/rls/subscribe.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/rr/README b/modules/rr/README index 3965afbde20..a390c952461 100644 --- a/modules/rr/README +++ b/modules/rr/README @@ -18,8 +18,7 @@ Bogdan-Andrei Iancu Copyright © 2005 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -89,8 +88,8 @@ Chapter 1. Admin Guide OpenSIPS is basically only a transaction statefull proxy, without any dialog support build in. There are many - features/services which actually requires a dialog awareness, - like storing the information in the dialog creation stage, + features/services which actually require dialog awareness, like + storing the information in the dialog creation stage, information which will be used during the whole dialog existence. @@ -529,4 +528,4 @@ Chapter 3. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/rr/api.c b/modules/rr/api.c index d54cff9f1dc..74d8bd88ef8 100644 --- a/modules/rr/api.c +++ b/modules/rr/api.c @@ -53,6 +53,9 @@ int load_rr( struct rr_binds *rrb ) rrb->removed_routes = &removed_routes; rrb->routing_type = &routing_type; + rrb->loose_route = loose_route; + rrb->record_route = record_route; + return 1; } diff --git a/modules/rr/api.h b/modules/rr/api.h index 97c9b416fac..60ef32ef038 100644 --- a/modules/rr/api.h +++ b/modules/rr/api.h @@ -51,6 +51,8 @@ typedef int (*is_direction_t)(struct sip_msg*, int); typedef int (*get_route_param_t)(struct sip_msg*, str*, str*); typedef str* (*get_remote_target_t)(struct sip_msg*); typedef str* (*get_route_set_t)(struct sip_msg*,int *nr_routes); +typedef int (*loose_route_t)(struct sip_msg*); +typedef int (*record_route_t)(struct sip_msg*, str*); struct rr_binds { add_rr_param_t add_rr_param; @@ -63,6 +65,9 @@ struct rr_binds { int append_fromtag; int* removed_routes; int* routing_type; + + loose_route_t loose_route; + record_route_t record_route; }; typedef int (*load_rr_f)( struct rr_binds* ); @@ -74,7 +79,7 @@ int load_rr( struct rr_binds * ); /*! \brief - * function to be called directly from other modules + * function to be called directly from other modules * to load the RR API */ inline static int load_rr_api( struct rr_binds *rrb ) diff --git a/modules/rr/doc/rr_admin.xml b/modules/rr/doc/rr_admin.xml index 8e0654f6ac6..77c0526308f 100644 --- a/modules/rr/doc/rr_admin.xml +++ b/modules/rr/doc/rr_admin.xml @@ -14,7 +14,7 @@ Dialog support &osips; is basically only a transaction statefull proxy, without any dialog support build in. There are many features/services - which actually requires a dialog awareness, like storing the information in + which actually require dialog awareness, like storing the information in the dialog creation stage, information which will be used during the whole dialog existence. diff --git a/modules/rr/loose.c b/modules/rr/loose.c index 7dfb7732556..f8c5c37e9ac 100644 --- a/modules/rr/loose.c +++ b/modules/rr/loose.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -27,7 +27,7 @@ * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri) * 2005-04-10 check_route_param() and all hooks for keeping reference to * Route params added (bogdan) - * 2005-10-17 fixed socket selection when double routing changes + * 2005-10-17 fixed socket selection when double routing changes * the port or the IP address (bogdan) */ @@ -111,7 +111,7 @@ static int is_preloaded(struct sip_msg* msg) /* * Parse the message and find first occurrence of - * Route header field. The function returns -1 or -2 + * Route header field. The function returns -1 or -2 * on a parser error, 0 if there is a Route HF and * 1 if there is no Route HF. */ @@ -199,7 +199,7 @@ static inline int is_2rr(str* _params) default: break; } break; - + case 5: switch(s.s[i]) { case '\\': state = 6; break; @@ -211,7 +211,7 @@ static inline int is_2rr(str* _params) case 6: state = 5; break; } } - + if ((state == 2) || (state == 3)) return 1; else return 0; } @@ -227,7 +227,7 @@ static inline int is_myself(str* _host, unsigned short _port) #endif { int ret; - + ret = check_self(_host, _port ? _port : SIP_PORT, 0);/* match all protos*/ if (ret < 0) return 0; @@ -239,7 +239,7 @@ static inline int is_myself(str* _host, unsigned short _port) return -1; } #endif - + return ret; } @@ -306,7 +306,7 @@ static inline int save_ruri(struct sip_msg* _m) } /* Create an anchor */ - anchor = anchor_lump(_m, _m->unparsed - _m->buf, 0, 0); + anchor = anchor_lump(_m, _m->unparsed - _m->buf, 0); if (anchor == 0) { LM_ERR("failed to get anchor\n"); return -2; @@ -372,12 +372,12 @@ static inline int get_maddr_uri(str *uri, struct sip_uri *puri) } memcpy( builturi, "sip:", 4 ); memcpy( builturi+4, puri->maddr_val.s, puri->maddr_val.len ); - + if( puri->port.len > 0 ) { builturi[4+puri->maddr_val.len] =':'; memcpy(builturi+5+puri->maddr_val.len, puri->port.s, - puri->port.len); + puri->port.len); } uri->len = 4+puri->maddr_val.len @@ -406,7 +406,7 @@ static inline int handle_sr(struct sip_msg* _m, struct hdr_field* _hdr, rr_t* _r LM_ERR("failed to save Request-URI\n"); return -1; } - + /* Put the first Route in Request-URI */ uri = _r->nameaddr.uri; @@ -555,7 +555,7 @@ static inline int after_strict(struct sip_msg* _m) } /* set the hooks for the params -bogdan - * important note: RURI is already parsed by the above function, so + * important note: RURI is already parsed by the above function, so * we just used it without any checking */ routed_msg_id = _m->id; routed_params = _m->parsed_uri.params; @@ -571,7 +571,7 @@ static inline int after_strict(struct sip_msg* _m) /* Note: when there is only one Route URI left (endpoint), it will * always be a strict router because endpoints don't use ;lr parameter - * In this case we will simply put the URI in R-URI and forward it, + * In this case we will simply put the URI in R-URI and forward it, * which will work perfectly */ if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("failed to check maddr\n"); @@ -581,7 +581,7 @@ static inline int after_strict(struct sip_msg* _m) LM_ERR("failed to rewrite request URI\n"); return RR_ERROR; } - + if (rt->next) { rem_off = hdr->body.s; rem_len = rt->next->nameaddr.name.s - hdr->body.s; @@ -611,8 +611,8 @@ static inline int after_strict(struct sip_msg* _m) } /* Next hop is a loose router - Which means that is is not endpoint yet - * In This case we have to recover from previous strict routing, that - * means we have to find the last Route URI and put in in R-URI and + * In This case we have to recover from previous strict routing, that + * means we have to find the last Route URI and put in in R-URI and * remove the last Route URI. */ if (rt != hdr->parsed) { /* There is a previous route uri which was 2nd uri of mine @@ -623,7 +623,7 @@ static inline int after_strict(struct sip_msg* _m) LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } - + del_rt = (rr_t*)hdr->parsed; /* mark route hdr as deleted */ del_rt->deleted = 1; @@ -651,8 +651,8 @@ static inline int after_strict(struct sip_msg* _m) /* mark remote contact route as deleted */ rt->deleted = 1; - /* The first character if uri will be either '<' when it is the - * only URI in a Route header field or ',' if there is more than + /* The first character if uri will be either '<' when it is the + * only URI in a Route header field or ',' if there is more than * one URI in the header field */ LM_DBG("The last route URI: '%.*s'\n", rt->nameaddr.uri.len, ZSW(rt->nameaddr.uri.s)); @@ -670,7 +670,7 @@ static inline int after_strict(struct sip_msg* _m) } } - + /* run RR callbacks -bogdan */ run_rr_callbacks( _m, &routed_params ); @@ -747,7 +747,7 @@ static inline int after_loose(struct sip_msg* _m, int preloaded) } rt = (rr_t*)hdr->parsed; } else rt = rt->next; - + if (enable_double_rr && is_2rr(&puri.params)) { /* double route may occure due different IP and port, so force as * send interface the one advertise in second Route */ @@ -792,7 +792,7 @@ static inline int after_loose(struct sip_msg* _m, int preloaded) rt = (rr_t*)hdr->parsed; } else rt = rt->next; } - + uri = rt->nameaddr.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse the first route URI\n"); @@ -834,7 +834,7 @@ static inline int after_loose(struct sip_msg* _m, int preloaded) /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ if (rt != hdr->parsed) { - if (!del_lump(_m, hdr->body.s - _m->buf, + if (!del_lump(_m, hdr->body.s - _m->buf, rt->nameaddr.name.s - hdr->body.s, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; @@ -855,7 +855,7 @@ static inline int after_loose(struct sip_msg* _m, int preloaded) /* * Do loose routing as defined in RFC3261 */ -int loose_route(struct sip_msg* _m, char* _s1, char* _s2) +int loose_route(struct sip_msg* _m) { int ret; @@ -866,7 +866,7 @@ int loose_route(struct sip_msg* _m, char* _s1, char* _s2) LM_DBG("There is no Route HF\n"); return -1; } - + if (parse_sip_msg_uri(_m)<0) { LM_ERR("failed to parse Request URI\n"); return -1; @@ -1092,12 +1092,12 @@ str* get_remote_target(struct sip_msg *msg) { /* searching for last header field */ res = find_rem_target(msg, &hdr, &rt, &prev); - if (res < 0) + if (res < 0) { LM_ERR("searching for last Route URI failed\n"); return 0; - } - else if (res > 0) + } + else if (res > 0) { /* No remote target is an error */ LM_ERR("couldn't find any remote target !\n"); @@ -1105,7 +1105,7 @@ str* get_remote_target(struct sip_msg *msg) } uri = &rt->nameaddr.uri; - if(get_maddr_uri(uri, 0)!=0) + if(get_maddr_uri(uri, 0)!=0) { LM_ERR("failed to check maddr\n"); return 0; diff --git a/modules/rr/loose.h b/modules/rr/loose.h index 8619625d3d3..33aa3d20d9b 100644 --- a/modules/rr/loose.h +++ b/modules/rr/loose.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -47,7 +47,7 @@ extern int routing_type; /*! \brief * Do loose routing as per RFC3261 */ -int loose_route(struct sip_msg* _m, char* _s1, char* _s2); +int loose_route(struct sip_msg* _m); /*! \brief @@ -144,7 +144,7 @@ static inline int is_strict(str* _params) default: break; } break; - + case 5: switch(s.s[i]) { case '\\': state = 6; break; @@ -156,7 +156,7 @@ static inline int is_strict(str* _params) case 6: state = 5; break; } } - + if ((state == 2) || (state == 3)) return 0; else return 1; } diff --git a/modules/rr/record.c b/modules/rr/record.c index 77ec3a939e4..4e1496c0bfe 100644 --- a/modules/rr/record.c +++ b/modules/rr/record.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -76,8 +76,8 @@ #define RR_PARAM_BUF_SIZE 512 -/*! \brief RR param buffer - * \note used for storing RR param which are added before RR insertion -bogdan +/*! \brief RR param buffer + * \note used for storing RR param which are added before RR insertion -bogdan */ static char rr_param_buf_ptr[RR_PARAM_BUF_SIZE]; static str rr_param_buf = {rr_param_buf_ptr,0}; @@ -101,7 +101,7 @@ static inline int get_username(struct sip_msg* _m, str* _user) /* no username in original uri -- hmm; maybe it is a uri * with just host address and username is in a preloaded route, * which is now no rewritten r-uri (assumed rewriteFromRoute - * was called somewhere in script's beginning) + * was called somewhere in script's beginning) */ if (!puri.user.len && _m->new_uri.s) { if (parse_uri(_m->new_uri.s, _m->new_uri.len, &puri) < 0) { @@ -168,13 +168,13 @@ static inline int build_rr(struct lump* _l, struct lump* _l2, str* user, if (r2) pkg_free(r2); return -3; } - + memcpy(prefix, RR_PREFIX, RR_PREFIX_LEN); if (user->len) { memcpy(prefix + RR_PREFIX_LEN, user->s, user->len); #ifdef ENABLE_USER_CHECK /* don't add the ignored user into a RR */ - if(i_user.len && i_user.len == user->len && + if(i_user.len && i_user.len == user->len && !strncmp(i_user.s, user->s, i_user.len)) { if(prefix[RR_PREFIX_LEN]=='x') @@ -200,11 +200,11 @@ static inline int build_rr(struct lump* _l, struct lump* _l2, str* user, memcpy(p, params->s, params->len); p += params->len; } - + memcpy(term, RR_TERM, RR_TERM_LEN); memcpy(r2, RR_R2, RR_R2_LEN); - if (!(_l = insert_new_lump_after(_l, prefix, prefix_len, 0))) + if (!(_l = insert_new_lump_after(_l, prefix, prefix_len, 0))) goto lump_err; prefix = 0; _l = insert_subst_lump_after(_l, _inbound?SUBST_RCV_ALL:SUBST_SND_ALL, 0); @@ -233,7 +233,7 @@ static inline int build_rr(struct lump* _l, struct lump* _l2, str* user, goto lump_err; term = 0; return 0; - + lump_err: LM_ERR("failed to insert lumps\n"); if (prefix) pkg_free(prefix); @@ -255,10 +255,10 @@ int record_route(struct sip_msg* _m, str *params) str user; struct to_body* from; str* tag; - + from = 0; /* Makes gcc happy */ user.len = 0; - + if (add_username) { if (get_username(_m, &user) < 0) { LM_ERR("failed to extract username\n"); @@ -282,21 +282,21 @@ int record_route(struct sip_msg* _m, str *params) rr_param_buf.len = 0; } - l = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, HDR_RECORDROUTE_T); - l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0); + l = anchor_lump(_m, _m->headers->name.s - _m->buf, HDR_RECORDROUTE_T); + l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0); if (!l || !l2) { LM_ERR("failed to create an anchor\n"); return -3; } - + if (build_rr(l, l2, &user, tag, params, OUTBOUND) < 0) { LM_ERR("failed to insert inbound Record-Route\n"); return -4; } if (enable_double_rr) { - l = anchor_lump(_m, _m->headers->name.s - _m->buf,0,HDR_RECORDROUTE_T); - l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0); + l = anchor_lump(_m, _m->headers->name.s - _m->buf,HDR_RECORDROUTE_T); + l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0); if (!l || !l2) { LM_ERR("failed to create an anchor\n"); return -5; @@ -312,7 +312,7 @@ int record_route(struct sip_msg* _m, str *params) return -7; } } - + /* reset the rr_param buffer */ rr_param_buf.len = 0; return 0; @@ -405,8 +405,8 @@ int record_route_preset(struct sip_msg* _m, str* _data) memcpy(term, RR_TERM, RR_TERM_LEN); - l = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, HDR_RECORDROUTE_T); - l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0); + l = anchor_lump(_m, _m->headers->name.s - _m->buf, HDR_RECORDROUTE_T); + l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0); if (!l || !l2) { LM_ERR("failed to create lump anchor\n"); goto error; @@ -459,7 +459,7 @@ static struct lump *get_rr_param_lump( struct lump** root) for( crt=*root ; crt && !last ; crt=crt->next,(*root)=crt ) { /* check on before list */ for( r=crt->before ; r ; r=r->before ) { - /* we are looking for the lump that adds the + /* we are looking for the lump that adds the * suffix of the RR header */ if ( r->type==HDR_RECORDROUTE_T && r->op==LUMP_ADD) last = r; diff --git a/modules/rr/record.h b/modules/rr/record.h index 3ec0d621308..08741f4be76 100644 --- a/modules/rr/record.h +++ b/modules/rr/record.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/rr/rr_mod.c b/modules/rr/rr_mod.c index 4fd631fc8bf..a426ee25b35 100644 --- a/modules/rr/rr_mod.c +++ b/modules/rr/rr_mod.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -122,7 +122,7 @@ static cmd_export_t cmds[] = { /*! \brief * Exported parameters */ -static param_export_t params[] ={ +static param_export_t params[] ={ {"append_fromtag", INT_PARAM, &append_fromtag }, {"enable_double_rr", INT_PARAM, &enable_double_rr }, #ifdef ENABLE_USER_CHECK @@ -150,8 +150,10 @@ struct module_exports rr_exports = { struct module_exports exports = { #endif "rr", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /*!< dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /*!< Exported functions */ params, /*!< Exported parameters */ 0, /*!< exported statistics */ diff --git a/modules/rr/rr_mod.h b/modules/rr/rr_mod.h index 0d1d81f11e2..4e5588823fa 100644 --- a/modules/rr/rr_mod.h +++ b/modules/rr/rr_mod.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/rtpengine/Makefile b/modules/rtpengine/Makefile new file mode 100644 index 00000000000..33d6853a768 --- /dev/null +++ b/modules/rtpengine/Makefile @@ -0,0 +1,14 @@ +# $Id: Makefile 5901 2009-07-21 07:45:05Z bogdan_iancu $ +# +# print example module makefile +# +# +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=rtpengine.so +LIBS= + +include ../../Makefile.modules + diff --git a/modules/rtpengine/README b/modules/rtpengine/README new file mode 100644 index 00000000000..0da096c4979 --- /dev/null +++ b/modules/rtpengine/README @@ -0,0 +1,661 @@ +rtpengine Module + +Maxim Sobolev + + Sippy Software, Inc. + +Juha Heinanen + + TuTPro, Inc. + +Edited by + +Maxim Sobolev + +Edited by + +Bogdan-Andrei Iancu + +Edited by + +Juha Heinanen + +Edited by + +Sas Ovidiu + +Edited by + +Carsten Bock + + ng-voice GmbH + +Edited by + +Richard Fuchs + + Sipwise GmbH + + Copyright © 2003-2008 Sippy Software, Inc. + + Copyright © 2005 Voice Sistem SRL + + Copyright © 2009-2014 TuTPro Inc. + + Copyright © 2010 VoIPEmbedded Inc. + + Copyright © 2013-2014 Sipwise GmbH + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. Multiple RTP proxy usage + 1.3. Dependencies + + 1.3.1. OpenSIPS Modules + 1.3.2. External Libraries or Applications + + 1.4. Parameters + + 1.4.1. rtpengine_sock (string) + 1.4.2. rtpengine_disable_tout (integer) + 1.4.3. rtpengine_tout (integer) + 1.4.4. rtpengine_retr (integer) + 1.4.5. extra_id_pv (string) + 1.4.6. setid_avp (string) + + 1.5. Functions + + 1.5.1. rtpengine_use_set(setid) + 1.5.2. rtpengine_offer([flags]) + 1.5.3. rtpengine_answer([flags]) + 1.5.4. rtpengine_delete([flags]) + 1.5.5. rtpengine_manage([flags]) + 1.5.6. rtpengine_start_recording() + + 1.6. Exported Pseudo Variables + + 1.6.1. $rtpstat + + 1.7. MI Commands + + 1.7.1. rtpengine_enable + 1.7.2. rtpengine_show + + 2. Frequently Asked Questions + + List of Examples + + 1.1. Set rtpengine_sock parameter + 1.2. Set rtpengine_disable_tout parameter + 1.3. Set rtpengine_tout parameter + 1.4. Set rtpengine_retr parameter + 1.5. Set extra_id_pv parameter + 1.6. Set setid_avp parameter + 1.7. rtpengine_use_set usage + 1.8. rtpengine_offer usage + 1.9. rtpengine_answer usage + 1.10. rtpengine_delete usage + 1.11. rtpengine_manage usage + 1.12. rtpengine_start_recording usage + 1.13. $rtpstat Usage + 1.14. rtpengine_enable usage + 1.15. rtpengine_show usage + +Chapter 1. Admin Guide + +1.1. Overview + + This is a module that enables media streams to be proxied via + an RTP proxy. The only RTP proxy currently known to work with + this module is the Sipwise rtpengine + https://github.com/sipwise/rtpengine. The rtpengine module is a + modified version of the original rtpproxy module using a new + control protocol. The module is designed to be a drop-in + replacement for the old module from a configuration file point + of view, however due to the incompatible control protocol, it + only works with RTP proxies which specifically support it. + +1.2. Multiple RTP proxy usage + + The rtpengine module can support multiple RTP proxies for + balancing/distribution and control/selection purposes. + + The module allows definition of several sets of rtpengines. + Load-balancing will be performed over a set and the admin has + the ability to choose what set should be used. The set is + selected via its id - the id being defined with the set. Refer + to the “rtpengine_sock” module parameter definition for syntax + description. + + The balancing inside a set is done automatically by the module + based on the weight of each RTP proxy from the set. + + The selection of the set is done from script prior using + rtpengine_delete(), rtpengine_offer() or rtpengine_answer() + functions - see the rtpengine_use_set() function. + + Another way to select the set is to define setid_avp module + parameter and assign setid to the defined avp before calling + rtpengine_offer() or rtpengine_manage() function. If forwarding + of the requests fails and there is another branch to try, + remember to unset the avp after calling rtpengine_delete() + function. + + For backward compatibility reasons, a set with no id take by + default the id 0. Also if no set is explicitly set before + rtpengine_delete(), rtpengine_offer() or rtpengine_answer() the + 0 id set will be used. + + IMPORTANT: if you use multiple sets, take care and use the same + set for both rtpengine_offer()/rtpengine_answer() and + rtpengine_delete()!! If the set was selected using setid_avp, + the avp needs to be set only once before rtpengine_offer() or + rtpengine_manage() call. + +1.3. Dependencies + +1.3.1. OpenSIPS Modules + + The following modules must be loaded before this module: + * tm module - (optional) if you want to have + rtpengine_manage() fully functional + +1.3.2. External Libraries or Applications + + The following libraries or applications must be installed + before running OpenSIPS with this module loaded: + * None. + +1.4. Parameters + +1.4.1. rtpengine_sock (string) + + Definition of socket(s) used to connect to (a set) RTP proxy. + It may specify a UNIX socket or an IPv4/IPv6 UDP socket. + + Default value is “NONE” (disabled). + + Example 1.1. Set rtpengine_sock parameter +... +# single rtproxy +modparam("rtpengine", "rtpengine_sock", "udp:localhost:12221") +# multiple rtproxies for LB +modparam("rtpengine", "rtpengine_sock", + "udp:localhost:12221 udp:localhost:12222") +# multiple sets of multiple rtproxies +modparam("rtpengine", "rtpengine_sock", + "1 == udp:localhost:12221 udp:localhost:12222") +modparam("rtpengine", "rtpengine_sock", + "2 == udp:localhost:12225") +... + +1.4.2. rtpengine_disable_tout (integer) + + Once an RTP proxy was found unreachable and marked as disabled, + the rtpengine module will not attempt to establish + communication to that RTP proxy for rtpengine_disable_tout + seconds. + + Default value is “60”. + + Example 1.2. Set rtpengine_disable_tout parameter +... +modparam("rtpengine", "rtpengine_disable_tout", 20) +... + +1.4.3. rtpengine_tout (integer) + + Timeout value in waiting for reply from RTP proxy. + + Default value is “1”. + + Example 1.3. Set rtpengine_tout parameter +... +modparam("rtpengine", "rtpengine_tout", 2) +... + +1.4.4. rtpengine_retr (integer) + + How many times the module should retry to send and receive + after timeout was generated. + + Default value is “5”. + + Example 1.4. Set rtpengine_retr parameter +... +modparam("rtpengine", "rtpengine_retr", 2) +... + +1.4.5. extra_id_pv (string) + + The parameter sets the PV defination to use when the “b” + parameter is used on rtpengine_delete(), rtpengine_offer(), + rtpengine_answer() or rtpengine_manage() command. + + Default is empty, the “b” parameter may not be used then. + + Example 1.5. Set extra_id_pv parameter +... +modparam("rtpengine", "extra_id_pv", "$avp(extra_id)") +... + +1.4.6. setid_avp (string) + + The parameter defines an AVP that, if set, determines which RTP + proxy set rtpengine_offer(), rtpengine_answer(), + rtpengine_delete(), and rtpengine_manage() functions use. + + There is no default value. + + Example 1.6. Set setid_avp parameter +... +modparam("rtpengine", "setid_avp", "$avp(setid)") +... + +1.5. Functions + +1.5.1. rtpengine_use_set(setid) + + Sets the ID of the RTP proxy set to be used for the next + rtpengine_delete(), rtpengine_offer(), rtpengine_answer() or + rtpengine_manage() command. The parameter can be an integer or + a config variable holding an integer. + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, + BRANCH_ROUTE. + + Example 1.7. rtpengine_use_set usage +... +rtpengine_use_set("2"); +rtpengine_offer(); +... + +1.5.2. rtpengine_offer([flags]) + + Rewrites SDP body to ensure that media is passed through an RTP + proxy. To be invoked on INVITE for the cases the SDPs are in + INVITE and 200 OK and on 200 OK when SDPs are in 200 OK and + ACK. + + Meaning of the parameters is as follows: + * flags - flags to turn on some features. + The “flags” string is a list of space-separated items. Each + item is either an individual token, or a token in + “key=value” format. The possible tokens are described + below. + + via-branch=... - Include the “branch” value of one of + the “Via” headers in the request to the RTP proxy. + Possible values are: “1” - use the first “Via” header; + “2” - use the second “Via” header; “auto” - use the + first “Via” header if this is a request, or the second + one if this is a reply; “extra” - don't take the value + from a header, but instead use the value of the + “extra_id_pv” variable. This can be used to create one + media session per branch on the RTP proxy. When + sending a subsequent “delete” command to the RTP + proxy, you can then stop just the session for a + specific branch when passing the flag '1' or '2' in + the “rtpengine_delete”, or stop all sessions for a + call when not passing one of those two flags there. + This is especially useful if you have serially forked + call scenarios where the RTP proxy gets an “offer” + command for a new branch, and then a “delete” command + for the previous branch, which would otherwise delete + the full call, breaking the subsequent “answer” for + the new branch. This flag is only supported by the + Sipwise rtpengine RTP proxy at the moment! + + asymmetric - flags that UA from which message is + received doesn't support symmetric RTP. (automatically + sets the 'r' flag) + + force-answer - force “answer”, that is, only rewrite + SDP when corresponding session already exists in the + RTP proxy. By default is on when the session is to be + completed. + + internal, external - these flags specify the direction + of the SIP message. These flags only make sense when + the RTP proxy is running in bridge mode. “internal” + corresponds to the proxy's first interface, “external” + corresponds to the RTP proxy's second interface. You + always have to specify two flags to define the + incoming network and the outgoing network. For + example, “internal external” should be used for SIP + message received from the local interface and sent out + on the external interface, and “external internal” + vice versa. Other options are “internal internal” and + “external external”. So, for example if a SIP requests + is processed with “internal external” flags, the + corresponding response must be processed with + “internal external” flags. + + auto-bridge - this flag an alternative to the + “internal” and “external” flags in order to do + automatic bridging between IPv4 on the "internal + network" and IPv6 on the "external network". Instead + of explicitly instructing the RTP proxy to select a + particular address family, the distinction is done by + the given IP in the SDP body by the RTP proxy itself. + Not supported by Sipwise rtpengine. + + address-family=... - instructs the RTP proxy that the + recipient of this SDP body expects to see addresses of + a particular family. Possible values are “IP4” and + “IP6”. For example, if the SDP body contains IPv4 + addresses but the recipient only speaks IPv6, you + would use “address-family=IP6” to bridge between the + two address families. + Sipwise rtpengine remembers the address family + preference of each party after it has seen an SDP body + from them. This means that normally it is only + necessary to explicitly specify the address family in + the “offer”, but not in the “answer”. + Note: Please note, that this will only work properly + with non-dual-stack user-agents or with dual-stack + clients according to RFC6157 (which suggest ICE for + Dual-Stack implementations). This short-cut will not + work properly with RFC4091 (ANAT) compatible clients, + which suggests having different m-lines with different + IP-protocols grouped together. + + force - instructs the RTP proxy to ignore marks + inserted by another RTP proxy in transit to indicate + that the session is already goes through another + proxy. Allows creating a chain of proxies. Not + supported and ignored by Sipwise rtpengine. + + trust-address - flags that IP address in SDP should be + trusted. Without this flag, the RTP proxy ignores + address in the SDP and uses source address of the SIP + message as media address which is passed to the RTP + proxy. + + replace-origin - flags that IP from the origin + description (o=) should be also changed. + + replace-session-connection - flags to change the + session-level SDP connection (c=) IP if media + description also includes connection information. + + symmetric - flags that for the UA from which message + is received, support symmetric RTP must be forced. + + repacketize=NN - requests the RTP proxy to perform + re-packetization of RTP traffic coming from the UA + which has sent the current message to increase or + decrease payload size per each RTP packet forwarded if + possible. The NN is the target payload size in ms, for + the most codecs its value should be in 10ms + increments, however for some codecs the increment + could differ (e.g. 30ms for GSM or 20ms for G.723). + The RTP proxy would select the closest value supported + by the codec. This feature could be used for + significantly reducing bandwith overhead for low + bitrate codecs, for example with G.729 going from 10ms + to 100ms saves two thirds of the network bandwith. Not + supported by Sipwise rtpengine. + + ICE=... - controls the RTP proxy's behaviour regarding + ICE attributes within the SDP body. Possible values + are: “force” - discard any ICE attributes already + present in the SDP body and then generate and insert + new ICE data, leaving itself as the only ICE + candidates; “remove” instructs the RTP proxy to + discard any ICE attributes and not insert any new ones + into the SDP. The default (if no “ICE=...” is given at + all), new ICE data will only be generated if no ICE + was present in the SDP originally; otherwise the RTP + proxy will only insert itself as an additional ICE + candidate. Other SDP substitutions (c=, m=, etc) are + unaffected by this flag. + + RTP, SRTP, AVP, AVPF - These flags control the RTP + transport protocol that should be used towards the + recipient of the SDP. If none of them are specified, + the protocol given in the SDP is left untouched. + Otherwise, the “SRTP” flag indicates that SRTP should + be used, while “RTP” indicates that SRTP should not be + used. “AVPF” indicates that the advanced RTCP profile + with feedback messages should be used, and “AVP” + indicates that the regular RTCP profile should be + used. See also the next set of flags below. + + RTP/AVP, RTP/SAVP, RTP/AVPF, RTP/SAVPF - these serve + as an alternative, more explicit way to select between + the different RTP protocols and profiles supported by + the RTP proxy. For example, giving the flag + “RTP/SAVPF” has the same effect as giving the two + flags “SRTP AVPF”. + + to-tag - force inclusion of the “To” tag. Normally, + the “To” tag is always included when present, except + for “delete” messages. Including the “To” tag in a + “delete” messages allows you to be more selective + about which dialogues within a call are being torn + down. + + rtcp-mux-demux - if rtcp-mux (RFC 5761) was offered, + make the RTP proxy accept the offer, but not offer it + to the recipient of this message. + + rtcp-mux-reject - if rtcp-mux was offered, make the + RTP proxy reject the offer, but still offer it to the + recipient. Can be combined with “rtcp-mux-offer” to + always offer it. + + rtcp-mux-offer - make the RTP proxy offer rtcp-mux to + the recipient of this message, regardless of whether + it was offered originally or not. + + rtcp-mux-accept - if rtcp-mux was offered, make the + RTP proxy accept the offer and also offer it to the + recipient of this message. Can be combined with + “rtcp-mux-offer” to always offer it. + + media-address=... - force a particular media address + to be used in the SDP body. Address family is detected + automatically. + + This function can be used from ANY_ROUTE. + + Example 1.8. rtpengine_offer usage +route { +... + if (is_method("INVITE")) { + if (has_body("application/sdp")) { + if (rtpengine_offer()) + t_on_reply("1"); + } else { + t_on_reply("2"); + } + } + if (is_method("ACK") && has_body("application/sdp")) + rtpengine_answer(); +... +} + +onreply_route[1] +{ +... + if (has_body("application/sdp")) + rtpengine_answer(); +... +} + +onreply_route[2] +{ +... + if (has_body("application/sdp")) + rtpengine_offer(); +... +} + +1.5.3. rtpengine_answer([flags]) + + Rewrites SDP body to ensure that media is passed through an RTP + proxy. To be invoked on 200 OK for the cases the SDPs are in + INVITE and 200 OK and on ACK when SDPs are in 200 OK and ACK. + + See rtpengine_offer() function description above for the + meaning of the parameters. + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, + FAILURE_ROUTE, BRANCH_ROUTE. + + Example 1.9. rtpengine_answer usage + + See rtpengine_offer() function example above for example. + +1.5.4. rtpengine_delete([flags]) + + Tears down the RTPProxy session for the current call. + + See rtpengine_offer() function description above for the + meaning of the parameters. Note that not all flags make sense + for a “delete”. + + This function can be used from ANY_ROUTE. + + Example 1.10. rtpengine_delete usage +... +rtpengine_delete(); +... + +1.5.5. rtpengine_manage([flags]) + + Manage the RTPProxy session - it combines the functionality of + rtpengine_offer(), rtpengine_answer() and rtpengine_delete(), + detecting internally based on message type and method which one + to execute. + + It can take the same parameters as rtpengine_offer(). The flags + parameter to rtpengine_manage() can be a configuration variable + containing the flags as a string. + + Functionality: + * If INVITE with SDP, then do rtpengine_offer() + * If INVITE with SDP, when the tm module is loaded, mark + transaction with internal flag FL_SDP_BODY to know that the + 1xx and 2xx are for rtpengine_answer() + * If ACK with SDP, then do rtpengine_answer() + * If BYE or CANCEL, or called within a FAILURE_ROUTE[], then + do rtpengine_delete() + * If reply to INVITE with code >= 300 do rtpengine_delete() + * If reply with SDP to INVITE having code 1xx and 2xx, then + do rtpengine_answer() if the request had SDP or tm is not + loaded, otherwise do rtpengine_offer() + + This function can be used from ANY_ROUTE. + + Example 1.11. rtpengine_manage usage +... +rtpengine_manage(); +... + +1.5.6. rtpengine_start_recording() + + This function will send a signal to the RTP proxy to record the + RTP stream on the RTP proxy. This function is not supported by + Sipwise rtpengine at the moment! + + This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE. + + Example 1.12. rtpengine_start_recording usage +... +rtpengine_start_recording(); +... + +1.6. Exported Pseudo Variables + +1.6.1. $rtpstat + + Returns the RTP statistics from the RTP proxy. The RTP + statistics from the RTP proxy are provided as a string and it + does contain several packet counters. The statistics must be + retrieved before the session is deleted (before + rtpengine_delete()). + + Example 1.13. $rtpstat Usage +... + append_hf("X-RTP-Statistics: $rtpstat\r\n"); +... + +1.7. MI Commands + +1.7.1. rtpengine_enable + + Enables a RTP proxy if parameter value is greater than 0. + Disables it if a zero value is given. + + The first parameter is the RTP proxy url (exactly as defined in + the config file). + + The second parameter value must be a number in decimal. + + NOTE: if a RTP proxy is defined multiple times (in the same or + diferente sete), all of its instances will be enables/disabled. + + Example 1.14. rtpengine_enable usage +... +$ opensipsctl fifo rtpengine_enable udp:192.168.2.133:8081 0 +... + +1.7.2. rtpengine_show + + Displays all the RTP proxies and their information: set and + status (disabled or not, weight and recheck_ticks). + + No parameter. + + Example 1.15. rtpengine_show usage +... +$ opensipsctl fifo rtpengine_show +... + +Chapter 2. Frequently Asked Questions + + 2.1. + + How do I migrate from “rtpproxy” or “rtpproxy-ng” to + “rtpengine”? + + For the most part, only the names of the functions have + changed, with “rtpproxy” in each name replaced with + “rtpengine”. For example, “rtpproxy_manage()” has become + “rtpengine_manage()”. A few name duplications have also been + resolved, for example there is now a single + “rtpengine_delete()” instead of “unforce_rtp_proxy()” and the + identical “rtpproxy_destroy()”. + + The largest difference to the old module is how flags are + passed to “rtpengine_offer()”, “rtpengine_answer()”, + “rtpengine_manage()” and “rtpengine_delete()”. Instead of + having a string of single-letter flags, they now take a string + of space-separated items, with each item being either a single + token (word) or a “key=value” pair. + + For example, if you had a call “rtpproxy_offer("FRWOC+PS");”, + this would then become: +rtpengine_offer("force trust-address symmetric replace-origin replace-se +ssion-connection ICE=force RTP/SAVPF"); + + Finally, if you were using the second paramater (explicit media + address) to any of these functions, this has been replaced by + the “media-address=...” option within the first string of + flags. + + 2.2. + + Where can I find more about OpenSIPS? + + Take a look at http://www.opensips.org/. + + 2.3. + + Where can I post a question about this module? + + First at all check if your question was already answered on one + of our mailing lists: + * User Mailing List - + http://lists.opensips.org/cgi-bin/mailman/listinfo/users + * Developer Mailing List - + http://lists.opensips.org/cgi-bin/mailman/listinfo/devel + + E-mails regarding any stable OpenSIPS release should be sent to + and e-mails regarding development + versions should be sent to . + + If you want to keep the mail private, send it to + . + + 2.4. + + How can I report a bug? + + Please follow the guidelines provided at: + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/rtpengine/bencode.c b/modules/rtpengine/bencode.c new file mode 100644 index 00000000000..9de3f5e98c6 --- /dev/null +++ b/modules/rtpengine/bencode.c @@ -0,0 +1,729 @@ +/* + * Copyright ?? + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * --------- + * 2014-06-17 Initial upload + */ + + + +#include "bencode.h" +#include +#include +#include +#include +#include +#include + + +/* set to 0 for alloc debugging, e.g. through valgrind */ +#define BENCODE_MIN_BUFFER_PIECE_LEN 512 + +#define BENCODE_HASH_BUCKETS 31 /* prime numbers work best */ + +struct __bencode_buffer_piece { + char *tail; + unsigned int left; + struct __bencode_buffer_piece *next; + char buf[0]; +}; +struct __bencode_free_list { + void *ptr; + free_func_t func; + struct __bencode_free_list *next; +}; +struct __bencode_hash { + struct bencode_item *buckets[BENCODE_HASH_BUCKETS]; +}; + + + + + +static bencode_item_t __bencode_end_marker = { + .type = BENCODE_END_MARKER, + .iov[0].iov_len = 1, + .iov[0].iov_base = "e", + .iov_cnt = 1, + .str_len = 1, +}; + + + + +static bencode_item_t *__bencode_decode(bencode_buffer_t *buf, const char *s, const char *end); + + + +static void __bencode_item_init(bencode_item_t *item) { + item->last_child = item->parent = item->child = item->sibling = NULL; +} + +static void __bencode_container_init(bencode_item_t *cont) { + cont->iov[0].iov_len = 1; + cont->iov[1].iov_base = "e"; + cont->iov[1].iov_len = 1; + cont->iov_cnt = 2; + cont->str_len = 2; +} + +static void __bencode_dictionary_init(bencode_item_t *dict) { + dict->type = BENCODE_DICTIONARY; + dict->iov[0].iov_base = "d"; + dict->value = 0; + __bencode_container_init(dict); +} + +static void __bencode_list_init(bencode_item_t *list) { + list->type = BENCODE_LIST; + list->iov[0].iov_base = "l"; + __bencode_container_init(list); +} + +static struct __bencode_buffer_piece *__bencode_piece_new(unsigned int size) { + struct __bencode_buffer_piece *ret; + + if (size < BENCODE_MIN_BUFFER_PIECE_LEN) + size = BENCODE_MIN_BUFFER_PIECE_LEN; + ret = BENCODE_MALLOC(sizeof(*ret) + size); + if (!ret) + return NULL; + + ret->tail = ret->buf; + ret->left = size; + ret->next = NULL; + + return ret; +} + +int bencode_buffer_init(bencode_buffer_t *buf) { + buf->pieces = __bencode_piece_new(0); + if (!buf->pieces) + return -1; + buf->free_list = NULL; + buf->error = 0; + return 0; +} + +static void *__bencode_alloc(bencode_buffer_t *buf, unsigned int size) { + struct __bencode_buffer_piece *piece; + void *ret; + + if (!buf) + return NULL; + if (buf->error) + return NULL; + + piece = buf->pieces; + + if (size <= piece->left) + goto alloc; + + piece = __bencode_piece_new(size); + if (!piece) { + buf->error = 1; + return NULL; + } + piece->next = buf->pieces; + buf->pieces = piece; + + assert(size <= piece->left); + +alloc: + piece->left -= size; + ret = piece->tail; + piece->tail += size; + return ret; +} + +void bencode_buffer_free(bencode_buffer_t *buf) { + struct __bencode_free_list *fl; + struct __bencode_buffer_piece *piece, *next; + + for (fl = buf->free_list; fl; fl = fl->next) + fl->func(fl->ptr); + + for (piece = buf->pieces; piece; piece = next) { + next = piece->next; + BENCODE_FREE(piece); + } +} + +static bencode_item_t *__bencode_item_alloc(bencode_buffer_t *buf, unsigned int payload) { + bencode_item_t *ret; + + ret = __bencode_alloc(buf, sizeof(struct bencode_item) + payload); + if (!ret) + return NULL; + ret->buffer = buf; + __bencode_item_init(ret); + return ret; +} + +bencode_item_t *bencode_dictionary(bencode_buffer_t *buf) { + bencode_item_t *ret; + + ret = __bencode_item_alloc(buf, 0); + if (!ret) + return NULL; + __bencode_dictionary_init(ret); + return ret; +} + +bencode_item_t *bencode_list(bencode_buffer_t *buf) { + bencode_item_t *ret; + + ret = __bencode_item_alloc(buf, 0); + if (!ret) + return NULL; + __bencode_list_init(ret); + return ret; +} + +static void __bencode_container_add(bencode_item_t *parent, bencode_item_t *child) { + if (!parent) + return; + if (!child) + return; + + assert(child->parent == NULL); + assert(child->sibling == NULL); + + child->parent = parent; + if (parent->last_child) + parent->last_child->sibling = child; + parent->last_child = child; + if (!parent->child) + parent->child = child; + + while (parent) { + parent->iov_cnt += child->iov_cnt; + parent->str_len += child->str_len; + parent = parent->parent; + } +} + +static bencode_item_t *__bencode_string_alloc(bencode_buffer_t *buf, const void *base, + int str_len, int iov_len, int iov_cnt, bencode_type_t type) +{ + bencode_item_t *ret; + int len_len; + + assert((str_len <= 99999) && (str_len >= 0)); + ret = __bencode_item_alloc(buf, 7); + if (!ret) + return NULL; + len_len = sprintf(ret->__buf, "%d:", str_len); + + ret->type = type; + ret->iov[0].iov_base = ret->__buf; + ret->iov[0].iov_len = len_len; + ret->iov[1].iov_base = (void *) base; + ret->iov[1].iov_len = iov_len; + ret->iov_cnt = iov_cnt + 1; + ret->str_len = len_len + str_len; + + return ret; +} + +bencode_item_t *bencode_string_len_dup(bencode_buffer_t *buf, const char *s, int len) { + char *sd = __bencode_alloc(buf, len); + if (!sd) + return NULL; + memcpy(sd, s, len); + return bencode_string_len(buf, sd, len); +} + +bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len) { + return __bencode_string_alloc(buf, s, len, len, 1, BENCODE_STRING); +} + +bencode_item_t *bencode_string_iovec(bencode_buffer_t *buf, const struct iovec *iov, int iov_cnt, int str_len) { + int i; + + if (iov_cnt < 0) + return NULL; + if (str_len < 0) { + str_len = 0; + for (i = 0; i < iov_cnt; i++) + str_len += iov[i].iov_len; + } + + return __bencode_string_alloc(buf, iov, str_len, iov_cnt, iov_cnt, BENCODE_IOVEC); +} + +bencode_item_t *bencode_integer(bencode_buffer_t *buf, long long int i) { + bencode_item_t *ret; + int alen, rlen; + + alen = 8; + while (1) { + ret = __bencode_item_alloc(buf, alen + 3); + if (!ret) + return NULL; + rlen = snprintf(ret->__buf, alen, "i%llde", i); + if (rlen < alen) + break; + alen <<= 1; + } + + ret->type = BENCODE_INTEGER; + ret->iov[0].iov_base = ret->__buf; + ret->iov[0].iov_len = rlen; + ret->iov[1].iov_base = NULL; + ret->iov[1].iov_len = 0; + ret->iov_cnt = 1; + ret->str_len = rlen; + + return ret; +} + +bencode_item_t *bencode_dictionary_add_len(bencode_item_t *dict, const char *key, int keylen, bencode_item_t *val) { + bencode_item_t *str; + + if (!dict || !val) + return NULL; + assert(dict->type == BENCODE_DICTIONARY); + + str = bencode_string_len(dict->buffer, key, keylen); + if (!str) + return NULL; + __bencode_container_add(dict, str); + __bencode_container_add(dict, val); + return val; +} + +bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item) { + if (!list || !item) + return NULL; + assert(list->type == BENCODE_LIST); + __bencode_container_add(list, item); + return item; +} + +static int __bencode_iovec_cpy(struct iovec *out, const struct iovec *in, int num) { + memcpy(out, in, num * sizeof(*out)); + return num; +} + +static int __bencode_str_cpy(char *out, const struct iovec *in, int num) { + char *orig = out; + + while (--num >= 0) { + memcpy(out, in->iov_base, in->iov_len); + out += in->iov_len; + in++; + } + return out - orig; +} + +static int __bencode_iovec_dump(struct iovec *out, bencode_item_t *item) { + bencode_item_t *child; + struct iovec *orig = out; + + assert(item->iov[0].iov_base != NULL); + out += __bencode_iovec_cpy(out, &item->iov[0], 1); + + child = item->child; + while (child) { + out += __bencode_iovec_dump(out, child); + child = child->sibling; + } + + if (item->type == BENCODE_IOVEC) + out += __bencode_iovec_cpy(out, item->iov[1].iov_base, item->iov[1].iov_len); + else if (item->iov[1].iov_base) + out += __bencode_iovec_cpy(out, &item->iov[1], 1); + + assert((out - orig) == item->iov_cnt); + return item->iov_cnt; +} + +static int __bencode_str_dump(char *out, bencode_item_t *item) { + char *orig = out; + bencode_item_t *child; + + assert(item->iov[0].iov_base != NULL); + out += __bencode_str_cpy(out, &item->iov[0], 1); + + child = item->child; + while (child) { + out += __bencode_str_dump(out, child); + child = child->sibling; + } + + if (item->type == BENCODE_IOVEC) + out += __bencode_str_cpy(out, item->iov[1].iov_base, item->iov[1].iov_len); + else if (item->iov[1].iov_base) + out += __bencode_str_cpy(out, &item->iov[1], 1); + + assert((out - orig) == item->str_len); + *out = '\0'; + return item->str_len; +} + +struct iovec *bencode_iovec(bencode_item_t *root, int *cnt, unsigned int head, unsigned int tail) { + struct iovec *ret; + + if (!root) + return NULL; + assert(cnt != NULL); + assert(root->iov_cnt > 0); + + ret = __bencode_alloc(root->buffer, sizeof(*ret) * (root->iov_cnt + head + tail)); + if (!ret) + return NULL; + *cnt = __bencode_iovec_dump(ret + head, root); + return ret; +} + +char *bencode_collapse(bencode_item_t *root, int *len) { + char *ret; + int l; + + if (!root) + return NULL; + assert(root->str_len > 0); + + ret = __bencode_alloc(root->buffer, root->str_len + 1); + if (!ret) + return NULL; + l = __bencode_str_dump(ret, root); + if (len) + *len = l; + return ret; +} + +char *bencode_collapse_dup(bencode_item_t *root, int *len) { + char *ret; + int l; + + if (!root) + return NULL; + assert(root->str_len > 0); + + ret = BENCODE_MALLOC(root->str_len + 1); + if (!ret) + return NULL; + + l = __bencode_str_dump(ret, root); + if (len) + *len = l; + return ret; +} + +static unsigned int __bencode_hash_str_len(const unsigned char *s, int len) { + unsigned long *ul; + unsigned int *ui; + unsigned short *us; + + if (len >= sizeof(*ul)) { + ul = (void *) s; + return *ul % BENCODE_HASH_BUCKETS; + } + if (len >= sizeof(*ui)) { + ui = (void *) s; + return *ui % BENCODE_HASH_BUCKETS; + } + if (len >= sizeof(*us)) { + us = (void *) s; + return *us % BENCODE_HASH_BUCKETS; + } + if (len >= sizeof(*s)) + return *s % BENCODE_HASH_BUCKETS; + + return 0; +} + +static unsigned int __bencode_hash_str(bencode_item_t *str) { + assert(str->type == BENCODE_STRING); + return __bencode_hash_str_len(str->iov[1].iov_base, str->iov[1].iov_len); +} + +static void __bencode_hash_insert(bencode_item_t *key, struct __bencode_hash *hash) { + unsigned int bucket, i; + + i = bucket = __bencode_hash_str(key); + + while (1) { + if (!hash->buckets[i]) { + hash->buckets[i] = key; + break; + } + i++; + if (i >= BENCODE_HASH_BUCKETS) + i = 0; + if (i == bucket) + break; + } +} + +static bencode_item_t *__bencode_decode_dictionary(bencode_buffer_t *buf, const char *s, const char *end) { + bencode_item_t *ret, *key, *value; + struct __bencode_hash *hash; + + if (*s != 'd') + return NULL; + s++; + + ret = __bencode_item_alloc(buf, sizeof(*hash)); + if (!ret) + return NULL; + __bencode_dictionary_init(ret); + ret->value = 1; + hash = (void *) ret->__buf; + memset(hash, 0, sizeof(*hash)); + + while (s < end) { + key = __bencode_decode(buf, s, end); + if (!key) + return NULL; + s += key->str_len; + if (key->type == BENCODE_END_MARKER) + break; + if (key->type != BENCODE_STRING) + return NULL; + __bencode_container_add(ret, key); + + if (s >= end) + return NULL; + value = __bencode_decode(buf, s, end); + if (!value) + return NULL; + s += value->str_len; + if (value->type == BENCODE_END_MARKER) + return NULL; + __bencode_container_add(ret, value); + + __bencode_hash_insert(key, hash); + } + + return ret; +} + +static bencode_item_t *__bencode_decode_list(bencode_buffer_t *buf, const char *s, const char *end) { + bencode_item_t *ret, *item; + + if (*s != 'l') + return NULL; + s++; + + ret = __bencode_item_alloc(buf, 0); + if (!ret) + return NULL; + __bencode_list_init(ret); + + while (s < end) { + item = __bencode_decode(buf, s, end); + if (!item) + return NULL; + s += item->str_len; + if (item->type == BENCODE_END_MARKER) + break; + __bencode_container_add(ret, item); + } + + return ret; +} + +static bencode_item_t *__bencode_decode_integer(bencode_buffer_t *buf, const char *s, const char *end) { + long long int i; + const char *orig = s; + char *convend; + bencode_item_t *ret; + + if (*s != 'i') + return NULL; + s++; + + if (s >= end) + return NULL; + + if (*s == '0') { + i = 0; + s++; + goto done; + } + + i = strtoll(s, &convend, 10); + if (convend == s) + return NULL; + s += (convend - s); + +done: + if (s >= end) + return NULL; + if (*s != 'e') + return NULL; + s++; + + ret = __bencode_item_alloc(buf, 0); + if (!ret) + return NULL; + ret->type = BENCODE_INTEGER; + ret->iov[0].iov_base = (void *) orig; + ret->iov[0].iov_len = s - orig; + ret->iov[1].iov_base = NULL; + ret->iov[1].iov_len = 0; + ret->iov_cnt = 1; + ret->str_len = s - orig; + ret->value = i; + + return ret; +} + +static bencode_item_t *__bencode_decode_string(bencode_buffer_t *buf, const char *s, const char *end) { + unsigned long int sl; + char *convend; + const char *orig = s; + bencode_item_t *ret; + + if (*s == '0') { + sl = 0; + s++; + goto colon; + } + + sl = strtoul(s, &convend, 10); + if (convend == s) + return NULL; + s += (convend - s); + +colon: + if (s >= end) + return NULL; + if (*s != ':') + return NULL; + s++; + + if (s + sl > end) + return NULL; + + ret = __bencode_item_alloc(buf, 0); + if (!ret) + return NULL; + ret->type = BENCODE_STRING; + ret->iov[0].iov_base = (void *) orig; + ret->iov[0].iov_len = s - orig; + ret->iov[1].iov_base = (void *) s; + ret->iov[1].iov_len = sl; + ret->iov_cnt = 2; + ret->str_len = s - orig + sl; + + return ret; +} + +static bencode_item_t *__bencode_decode(bencode_buffer_t *buf, const char *s, const char *end) { + if (s >= end) + return NULL; + + switch (*s) { + case 'd': + return __bencode_decode_dictionary(buf, s, end); + case 'l': + return __bencode_decode_list(buf, s, end); + case 'i': + return __bencode_decode_integer(buf, s, end); + case 'e': + return &__bencode_end_marker; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return __bencode_decode_string(buf, s, end); + default: + return NULL; + } +} + +bencode_item_t *bencode_decode(bencode_buffer_t *buf, const char *s, int len) { + assert(s != NULL); + return __bencode_decode(buf, s, s + len); +} + + +static int __bencode_dictionary_key_match(bencode_item_t *key, const char *keystr, int keylen) { + assert(key->type == BENCODE_STRING); + + if (keylen != key->iov[1].iov_len) + return 0; + if (memcmp(keystr, key->iov[1].iov_base, keylen)) + return 0; + + return 1; +} + +bencode_item_t *bencode_dictionary_get_len(bencode_item_t *dict, const char *keystr, int keylen) { + bencode_item_t *key; + unsigned int bucket, i; + struct __bencode_hash *hash; + + if (!dict) + return NULL; + if (dict->type != BENCODE_DICTIONARY) + return NULL; + + /* try hash lookup first if possible */ + if (dict->value == 1) { + hash = (void *) dict->__buf; + i = bucket = __bencode_hash_str_len((const unsigned char *) keystr, keylen); + while (1) { + key = hash->buckets[i]; + if (!key) + return NULL; /* would be there, but isn't */ + assert(key->sibling != NULL); + if (__bencode_dictionary_key_match(key, keystr, keylen)) + return key->sibling; + i++; + if (i >= BENCODE_HASH_BUCKETS) + i = 0; + if (i == bucket) + break; /* fall back to regular lookup */ + } + } + + for (key = dict->child; key; key = key->sibling->sibling) { + assert(key->sibling != NULL); + if (__bencode_dictionary_key_match(key, keystr, keylen)) + return key->sibling; + } + + return NULL; +} + +void bencode_buffer_destroy_add(bencode_buffer_t *buf, free_func_t func, void *p) { + struct __bencode_free_list *li; + + if (!p) + return; + li = __bencode_alloc(buf, sizeof(*li)); + if (!li) + return; + li->ptr = p; + li->func = func; + li->next = buf->free_list; + buf->free_list = li; +} diff --git a/modules/rtpengine/bencode.h b/modules/rtpengine/bencode.h new file mode 100644 index 00000000000..ed1eb8c8ddf --- /dev/null +++ b/modules/rtpengine/bencode.h @@ -0,0 +1,555 @@ +/* + * Copyright ?? + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * --------- + * 2014-06-17 Initial upload + */ + + +#ifndef _BENCODE_H_ +#define _BENCODE_H_ + +#include +#include + +#if defined(PKG_MALLOC) || defined(pkg_malloc) +/* opensips */ +# include "../../mem/mem.h" +# include "../../str.h" +# ifndef BENCODE_MALLOC +# define BENCODE_MALLOC pkg_malloc +# define BENCODE_FREE pkg_free +# endif +#else +/* mediaproxy-ng */ +# include "str.h" +# ifndef BENCODE_MALLOC +# define BENCODE_MALLOC malloc +# define BENCODE_FREE free +# endif +#endif + +struct bencode_buffer; +enum bencode_type; +struct bencode_item; +struct __bencode_buffer_piece; +struct __bencode_free_list; + +typedef enum bencode_type bencode_type_t; +typedef struct bencode_buffer bencode_buffer_t; +typedef struct bencode_item bencode_item_t; +typedef void (*free_func_t)(void *); + +enum bencode_type { + BENCODE_INVALID = 0, + BENCODE_STRING, /* byte string */ + BENCODE_INTEGER, /* long long int */ + BENCODE_LIST, /* flat list of other objects */ + BENCODE_DICTIONARY, /* dictionary of key/values pairs. keys are always strings */ + BENCODE_IOVEC, /* special case of a string, built through bencode_string_iovec() */ + BENCODE_END_MARKER, /* used internally only */ +}; + +struct bencode_item { + bencode_type_t type; + struct iovec iov[2]; /* when decoding, iov[1] contains the contents of a string object */ + unsigned int iov_cnt; + unsigned int str_len; /* length of the whole ENCODED object. NOT the length of a byte string */ + long long int value; /* when decoding an integer, contains the value; otherwise used internally */ + bencode_item_t *parent, *child, *last_child, *sibling; + bencode_buffer_t *buffer; + char __buf[0]; +}; + +struct bencode_buffer { + struct __bencode_buffer_piece *pieces; + struct __bencode_free_list *free_list; + int error:1; /* set to !0 if allocation failed at any point */ +}; + + + + + +/*** INIT & DESTROY ***/ + +/* Initializes a bencode_buffer_t object. This object is used to group together all memory allocations + * made when encoding or decoding. Its memory usage is always growing, until it is freed, at which point + * all objects created through it become invalid. The actual object must be allocated separately, for + * example by being put on the stack. + * Returns 0 on success or -1 on failure (if no memory could be allocated). */ +int bencode_buffer_init(bencode_buffer_t *buf); + +/* Destroys a previously initialized bencode_buffer_t object. All memory used by the object is freed + * and all objects created through it become invalid. */ +void bencode_buffer_free(bencode_buffer_t *buf); + +/* Creates a new empty dictionary object. Memory will be allocated from the bencode_buffer_t object. + * Returns NULL if no memory could be allocated. */ +bencode_item_t *bencode_dictionary(bencode_buffer_t *buf); + +/* Creates a new empty list object. Memory will be allocated from the bencode_buffer_t object. + * Returns NULL if no memory could be allocated. */ +bencode_item_t *bencode_list(bencode_buffer_t *buf); + +/* Adds a pointer to the bencode_buffer_t object's internal free list. When the bencode_buffer_t + * object is destroyed, the specified function will be called on this pointer. */ +void bencode_buffer_destroy_add(bencode_buffer_t *buf, free_func_t, void *); + +/* Returns the buffer associated with an item, or NULL if pointer given is NULL */ +static inline bencode_buffer_t *bencode_item_buffer(bencode_item_t *); + + + + + +/*** DICTIONARY BUILDING ***/ + +/* Adds a new key/value pair to a dictionary. Memory will be allocated from the same bencode_buffer_t + * object as the dictionary was allocated from. Returns NULL if no memory could be allocated, otherwise + * returns "val". + * The function does not check whether the key being added is already present in the dictionary. + * Also, the function does not reorder keys into lexicographical order; keys will be encoded in + * the same order as they've been added. The key must a null-terminated string. + * The value to be added must not have been previously linked into any other dictionary or list. */ +static inline bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val); + +/* Identical to bencode_dictionary_add() but doesn't require the key string to be null-terminated */ +bencode_item_t *bencode_dictionary_add_len(bencode_item_t *dict, const char *key, int keylen, bencode_item_t *val); + +/* Convenience function to add a string value to a dictionary, possibly duplicated into the + * bencode_buffer_t object. */ +static inline bencode_item_t *bencode_dictionary_add_string(bencode_item_t *dict, const char *key, const char *val); +static inline bencode_item_t *bencode_dictionary_add_string_dup(bencode_item_t *dict, const char *key, const char *val); + +/* Ditto, but for a "str" object */ +static inline bencode_item_t *bencode_dictionary_add_str(bencode_item_t *dict, const char *key, const str *val); +static inline bencode_item_t *bencode_dictionary_add_str_dup(bencode_item_t *dict, const char *key, const str *val); + +/* Ditto, but adds a string created through an iovec array to the dictionary. See + * bencode_string_iovec(). */ +static inline bencode_item_t *bencode_dictionary_add_iovec(bencode_item_t *dict, const char *key, + const struct iovec *iov, int iov_cnt, int str_len); + +/* Convenience functions to add the respective (newly created) objects to a dictionary */ +static inline bencode_item_t *bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val); +static inline bencode_item_t *bencode_dictionary_add_dictionary(bencode_item_t *dict, const char *key); +static inline bencode_item_t *bencode_dictionary_add_list(bencode_item_t *dict, const char *key); + + + + + +/*** LIST BUILDING ***/ + +/* Adds a new item to a list. Returns "item". + * The item to be added must not have been previously linked into any other dictionary or list. */ +bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item); + +/* Convenience function to add the respective (newly created) objects to a list */ +static inline bencode_item_t *bencode_list_add_string(bencode_item_t *list, const char *s); +static inline bencode_item_t *bencode_list_add_list(bencode_item_t *list); +static inline bencode_item_t *bencode_list_add_dictionary(bencode_item_t *list); + + + + + +/*** STRING BUILDING & HANDLING ***/ + +/* Creates a new byte-string object. The given string does not have to be null-terminated, instead + * the length of the string is specified by the "len" parameter. Returns NULL if no memory could + * be allocated. + * Strings are not copied or duplicated, so the string pointed to by "s" must remain valid until + * the complete document is finally encoded or sent out. */ +bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len); + +/* Creates a new byte-string object. The given string must be null-terminated. Otherwise identical + * to bencode_string_len(). */ +static inline bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s); + +/* Creates a new byte-string object from a "str" object. The string does not have to be null- + * terminated. */ +static inline bencode_item_t *bencode_str(bencode_buffer_t *buf, const str *s); + +/* Identical to the above three functions, but copies the string into the bencode_buffer_t object. + * Thus, the given string doesn't have to remain valid and accessible afterwards. */ +bencode_item_t *bencode_string_len_dup(bencode_buffer_t *buf, const char *s, int len); +static inline bencode_item_t *bencode_string_dup(bencode_buffer_t *buf, const char *s); +static inline bencode_item_t *bencode_str_dup(bencode_buffer_t *buf, const str *s); + +/* Creates a new byte-string object from an iovec array. The created object has different internal + * semantics (not a BENCODE_STRING, but a BENCODE_IOVEC) and must not be treated like other string + * objects. The array pointer and contents must still be valid and accessible when the complete + * document is encoded. The full length of the string composed of the iovec array is given in the + * "str_len" parameter, which can be negative, in which case the array is iterated to calculate the + * length. */ +bencode_item_t *bencode_string_iovec(bencode_buffer_t *buf, const struct iovec *iov, int iov_cnt, int str_len); + +/* Convenience function to compare a string object to a regular C string. Returns 2 if object + * isn't a string object, otherwise returns according to strcmp(). */ +static inline int bencode_strcmp(bencode_item_t *a, const char *b); + +/* Converts the string object "in" into a str object "out". Returns "out" on success, or NULL on + * error ("in" was NULL or not a string object). */ +static inline str *bencode_get_str(bencode_item_t *in, str *out); + + + + + +/*** INTEGER BUILDING ***/ + +/* Creates a new integer object. Returns NULL if no memory could be allocated. */ +bencode_item_t *bencode_integer(bencode_buffer_t *buf, long long int i); + + + + + +/*** COLLAPSING & ENCODING ***/ + +/* Collapses and encodes the complete document structure under the "root" element (which normally + * is either a dictionary or a list) into an array of "iovec" structures. This array can then be + * passed to functions ala writev() or sendmsg() to output the encoded document as a whole. Memory + * is allocated from the same bencode_buffer_t object as the "root" object was allocated from. + * The "head" and "tail" parameters specify additional "iovec" structures that should be included + * in the allocated array before or after (respectively) the iovec structures used by the encoded + * document. Both parameters can be zero if no additional elements in the array are required. + * Returns a pointer to the allocated array or NULL if no memory could be allocated. The number of + * array elements is returned in "cnt" which must be a valid pointer to an int. This number does + * not include any additional elements allocated through the "head" or "tail" parameters. + * + * Therefore, the contents of the returned array are: + * [0 .. (head - 1)] = unused and uninitialized iovec structures + * [(head) .. (head + cnt - 1)] = the encoded document + * [(head + cnt) .. (head + cnt + tail - 1)] = unused and uninitialized iovec structures + * + * The returned array will be freed when the corresponding bencode_buffer_t object is destroyed. */ +struct iovec *bencode_iovec(bencode_item_t *root, int *cnt, unsigned int head, unsigned int tail); + +/* Similar to bencode_iovec(), but instead returns the encoded document as a null-terminated string. + * Memory for the string is allocated from the same bencode_buffer_t object as the "root" object + * was allocated from. If "len" is a non-NULL pointer, the length of the genrated string is returned + * in *len. This is important if the encoded document contains binary data, in which case null + * termination cannot be trusted. The returned string is freed when the corresponding + * bencode_buffer_t object is destroyed. */ +char *bencode_collapse(bencode_item_t *root, int *len); + +/* Identical to bencode_collapse() but fills in a "str" object. Returns "out". */ +static str *bencode_collapse_str(bencode_item_t *root, str *out); + +/* Identical to bencode_collapse(), but the memory for the returned string is not allocated from + * a bencode_buffer_t object, but instead using the function defined as BENCODE_MALLOC (normally + * malloc() or pkg_malloc()), similar to strdup(). Using this function, the bencode_buffer_t + * object can be destroyed, but the returned string remains valid and usable. */ +char *bencode_collapse_dup(bencode_item_t *root, int *len); + + + + + +/*** DECODING ***/ + +/* Decodes an encoded document from a string into a tree of bencode_item_t objects. The string does + * not need to be null-terminated, instead the length of the string is given through the "len" + * parameter. Memory is allocated from the bencode_buffer_t object. Returns NULL if no memory could + * be allocated or if the document could not be successfully decoded. + * + * The returned element is the "root" of the document tree and normally is either a list object or + * a dictionary object, but can also be a single string or integer object with no other objects + * underneath or besides it (no childred and no siblings). The type of the object can be determined + * by its ->type property. + * + * The number of bytes that could successfully be decoded into an object tree can be accessed through + * the root element's ->str_len property. Normally, this number should be equal to the "len" parameter + * passed, in which case the full string could be decoded. If ->str_len is less than "len", then there + * was additional stray byte data after the end of the encoded document. + * + * The document tree can be traversed through the ->child and ->sibling pointers in each object. The + * ->child pointer will be NULL for string and integer objects, as they don't contain other objects. + * For lists and dictionaries, ->child will be a pointer to the first contained object. This first + * contained object's ->sibling pointer will point to the next (second) contained object of the list + * or the dictionary, and so on. The last contained element of a list of dictionary will have a + * NULL ->sibling pointer. + * + * Dictionaries are like lists with ordered key/value pairs. When traversing dictionaries like + * lists, the following applies: The first element in the list (where ->child points to) will be the + * key of the first key/value pair (guaranteed to be a string and guaranteed to be present). The + * next element (following one ->sibling) will be the value of the first key/value pair. Following + * another ->sibling will point to the key of the next (second) key/value pair, and so on. + * + * However, to access children objects of dictionaries, the special functions following the naming + * scheme bencode_dictionary_get_* below should be used. They perform key lookup through a simple + * hash built into the dictionary object and so perform the lookup much faster. Only dictionaries + * created through a decoding process (i.e. not ones created from bencode_dictionary()) have this + * property. The hash is efficient only up to a certain number of elements (BENCODE_HASH_BUCKETS + * in bencode.c) contained in the dictionary. If the number of children object exceeds this number, + * key lookup will be slower than simply linearily traversing the list. + * + * The decoding function for dictionary object does not check whether keys are unique within the + * dictionary. It also does not care about lexicographical order of the keys. + * + * Decoded string objects will contain the raw decoded byte string in ->iov[1] (including the correct + * length). Strings are NOT null-terminated. Decoded integer objects will contain the decoded value + * in ->value. + * + * All memory is freed when the bencode_buffer_t object is destroyed. + */ +bencode_item_t *bencode_decode(bencode_buffer_t *buf, const char *s, int len); + +/* Identical to bencode_decode(), but returns successfully only if the type of the decoded object match + * "expect". */ +static inline bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char *s, int len, bencode_type_t expect); + +/* Identical to bencode_decode_expect() but takes a "str" argument. */ +static inline bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect); + + + + + +/*** DICTIONARY LOOKUP & EXTRACTION ***/ + +/* Searches the given dictionary object for the given key and returns the respective value. Returns + * NULL if the given object isn't a dictionary or if the key doesn't exist. The key must be a + * null-terminated string. */ +static inline bencode_item_t *bencode_dictionary_get(bencode_item_t *dict, const char *key); + +/* Identical to bencode_dictionary_get() but doesn't require the key to be null-terminated. */ +bencode_item_t *bencode_dictionary_get_len(bencode_item_t *dict, const char *key, int key_len); + +/* Identical to bencode_dictionary_get() but returns the value only if its type is a string, and + * returns it as a pointer to the string itself. Returns NULL if the value is of some other type. The + * returned string is NOT null-terminated. Length of the string is returned in *len, which must be a + * valid pointer. The returned string will be valid until dict's bencode_buffer_t object is destroyed. */ +static inline char *bencode_dictionary_get_string(bencode_item_t *dict, const char *key, int *len); + +/* Identical to bencode_dictionary_get_string() but fills in a "str" struct. Returns str->s, which + * may be NULL. */ +static inline char *bencode_dictionary_get_str(bencode_item_t *dict, const char *key, str *str); + +/* Looks up the given key in the dictionary and compares the corresponding value to the given + * null-terminated string. Returns 2 if the key isn't found or if the value isn't a string, otherwise + * returns according to strcmp(). */ +static inline int bencode_dictionary_get_strcmp(bencode_item_t *dict, const char *key, const char *str); + +/* Identical to bencode_dictionary_get() but returns the string in a newly allocated buffer (using the + * BENCODE_MALLOC function), which remains valid even after bencode_buffer_t is destroyed. */ +static inline char *bencode_dictionary_get_string_dup(bencode_item_t *dict, const char *key, int *len); + +/* Combines bencode_dictionary_get_str() and bencode_dictionary_get_string_dup(). Fills in a "str" + * struct, but copies the string into a newly allocated buffer. Returns str->s. */ +static inline char *bencode_dictionary_get_str_dup(bencode_item_t *dict, const char *key, str *str); + +/* Identical to bencode_dictionary_get_string() but expects an integer object. The parameter "defval" + * specified which value should be returned if the key is not found or if the value is not an integer. */ +static inline long long int bencode_dictionary_get_integer(bencode_item_t *dict, const char *key, long long int defval); + +/* Identical to bencode_dictionary_get(), but returns the object only if its type matches "expect". */ +static inline bencode_item_t *bencode_dictionary_get_expect(bencode_item_t *dict, const char *key, bencode_type_t expect); + + + + + +/**************************/ + +static inline bencode_buffer_t *bencode_item_buffer(bencode_item_t *i) { + if (!i) + return NULL; + return i->buffer; +} + +static inline bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s) { + return bencode_string_len(buf, s, strlen(s)); +} + +static inline bencode_item_t *bencode_string_dup(bencode_buffer_t *buf, const char *s) { + return bencode_string_len_dup(buf, s, strlen(s)); +} + +static inline bencode_item_t *bencode_str(bencode_buffer_t *buf, const str *s) { + return bencode_string_len(buf, s->s, s->len); +} + +static inline bencode_item_t *bencode_str_dup(bencode_buffer_t *buf, const str *s) { + return bencode_string_len_dup(buf, s->s, s->len); +} + +static inline bencode_item_t *bencode_dictionary_add(bencode_item_t *dict, const char *key, bencode_item_t *val) { + if (!key) + return NULL; + return bencode_dictionary_add_len(dict, key, strlen(key), val); +} + +static inline bencode_item_t *bencode_dictionary_add_string(bencode_item_t *dict, const char *key, const char *val) { + if (!val) + return NULL; + return bencode_dictionary_add(dict, key, bencode_string(bencode_item_buffer(dict), val)); +} + +static inline bencode_item_t *bencode_dictionary_add_string_dup(bencode_item_t *dict, const char *key, const char *val) { + if (!val) + return NULL; + return bencode_dictionary_add(dict, key, bencode_string_dup(bencode_item_buffer(dict), val)); +} + +static inline bencode_item_t *bencode_dictionary_add_str(bencode_item_t *dict, const char *key, const str *val) { + if (!val) + return NULL; + return bencode_dictionary_add(dict, key, bencode_str(bencode_item_buffer(dict), val)); +} + +static inline bencode_item_t *bencode_dictionary_add_str_dup(bencode_item_t *dict, const char *key, const str *val) { + if (!val) + return NULL; + return bencode_dictionary_add(dict, key, bencode_str_dup(bencode_item_buffer(dict), val)); +} + +static inline bencode_item_t *bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val) { + return bencode_dictionary_add(dict, key, bencode_integer(bencode_item_buffer(dict), val)); +} + +static inline bencode_item_t *bencode_dictionary_add_dictionary(bencode_item_t *dict, const char *key) { + return bencode_dictionary_add(dict, key, bencode_dictionary(bencode_item_buffer(dict))); +} + +static inline bencode_item_t *bencode_dictionary_add_list(bencode_item_t *dict, const char *key) { + return bencode_dictionary_add(dict, key, bencode_list(bencode_item_buffer(dict))); +} + +static inline bencode_item_t *bencode_list_add_string(bencode_item_t *list, const char *s) { + return bencode_list_add(list, bencode_string(bencode_item_buffer(list), s)); +} + +static inline bencode_item_t *bencode_list_add_list(bencode_item_t *list) { + return bencode_list_add(list, bencode_list(bencode_item_buffer(list))); +} + +static inline bencode_item_t *bencode_list_add_dictionary(bencode_item_t *list) { + return bencode_list_add(list, bencode_dictionary(bencode_item_buffer(list))); +} + +static inline bencode_item_t *bencode_dictionary_get(bencode_item_t *dict, const char *key) { + if (!key) + return NULL; + return bencode_dictionary_get_len(dict, key, strlen(key)); +} + +static inline char *bencode_dictionary_get_string(bencode_item_t *dict, const char *key, int *len) { + bencode_item_t *val; + val = bencode_dictionary_get(dict, key); + if (!val || val->type != BENCODE_STRING) + return NULL; + *len = val->iov[1].iov_len; + return val->iov[1].iov_base; +} + +static inline char *bencode_dictionary_get_str(bencode_item_t *dict, const char *key, str *str) { + str->s = bencode_dictionary_get_string(dict, key, &str->len); + if (!str->s) + str->len = 0; + return str->s; +} + +static inline char *bencode_dictionary_get_string_dup(bencode_item_t *dict, const char *key, int *len) { + const char *s; + char *ret; + s = bencode_dictionary_get_string(dict, key, len); + if (!s) + return NULL; + ret = BENCODE_MALLOC(*len); + if (!ret) + return NULL; + memcpy(ret, s, *len); + return ret; +} + +static inline char *bencode_dictionary_get_str_dup(bencode_item_t *dict, const char *key, str *str) { + str->s = bencode_dictionary_get_string_dup(dict, key, &str->len); + return str->s; +} + +static inline long long int bencode_dictionary_get_integer(bencode_item_t *dict, const char *key, long long int defval) { + bencode_item_t *val; + val = bencode_dictionary_get(dict, key); + if (!val || val->type != BENCODE_INTEGER) + return defval; + return val->value; +} + +static inline bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char *s, int len, bencode_type_t expect) { + bencode_item_t *ret; + ret = bencode_decode(buf, s, len); + if (!ret || ret->type != expect) + return NULL; + return ret; +} + +static inline bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect) { + return bencode_decode_expect(buf, s->s, s->len, expect); +} + +static inline bencode_item_t *bencode_dictionary_get_expect(bencode_item_t *dict, const char *key, bencode_type_t expect) { + bencode_item_t *ret; + ret = bencode_dictionary_get(dict, key); + if (!ret || ret->type != expect) + return NULL; + return ret; +} +static inline str *bencode_collapse_str(bencode_item_t *root, str *out) { + out->s = bencode_collapse(root, &out->len); + return out; +} +static inline int bencode_strcmp(bencode_item_t *a, const char *b) { + int len; + if (a->type != BENCODE_STRING) + return 2; + len = strlen(b); + if (a->iov[1].iov_len < len) + return -1; + if (a->iov[1].iov_len > len) + return 1; + return memcmp(a->iov[1].iov_base, b, len); +} +static inline int bencode_dictionary_get_strcmp(bencode_item_t *dict, const char *key, const char *str) { + bencode_item_t *i; + i = bencode_dictionary_get(dict, key); + if (!i) + return 2; + return bencode_strcmp(i, str); +} + +static inline str *bencode_get_str(bencode_item_t *in, str *out) { + if (!in || in->type != BENCODE_STRING) + return NULL; + out->s = in->iov[1].iov_base; + out->len = in->iov[1].iov_len; + return out; +} + +static inline bencode_item_t *bencode_dictionary_add_iovec(bencode_item_t *dict, const char *key, + const struct iovec *iov, int iov_cnt, int str_len) +{ + return bencode_dictionary_add(dict, key, bencode_string_iovec(bencode_item_buffer(dict), iov, iov_cnt, str_len)); +} + +#endif diff --git a/modules/rtpengine/doc/rtpengine.xml b/modules/rtpengine/doc/rtpengine.xml new file mode 100644 index 00000000000..30ef34a31db --- /dev/null +++ b/modules/rtpengine/doc/rtpengine.xml @@ -0,0 +1,108 @@ + + + + + + +%docentities; + +]> + + + + rtpengine Module + &osipsname; + + + Maxim + Sobolev + Sippy Software, Inc. +
+ sobomax@sippysoft.com +
+
+ + Juha + Heinanen + TuTPro, Inc. +
+ jh@tutpro.com +
+
+ + Maxim + Sobolev +
+ sobomax@sippysoft.com +
+
+ + Bogdan-Andrei + Iancu +
+ bogdan@voice-system.ro +
+
+ + Juha + Heinanen +
+ jh@tutpro.com +
+
+ + Sas + Ovidiu +
+ osas@voipembedded.com +
+
+ + Carsten + Bock + ng-voice GmbH +
+ carsten@ng-voice.com +
+
+ + Richard + Fuchs + Sipwise GmbH +
+ rfuchs@sipwise.com +
+
+
+ + 2003-2008 + Sippy Software, Inc. + + + 2005 + Voice Sistem SRL + + + 2009-2014 + TuTPro Inc. + + + 2010 + VoIPEmbedded Inc. + + + 2013-2014 + Sipwise GmbH + +
+ + + &admin; + &faq; + + +
diff --git a/modules/rtpengine/doc/rtpengine_admin.xml b/modules/rtpengine/doc/rtpengine_admin.xml new file mode 100644 index 00000000000..ee9e3a8df27 --- /dev/null +++ b/modules/rtpengine/doc/rtpengine_admin.xml @@ -0,0 +1,715 @@ + + + + + &adminguide; + +
+ Overview + + This is a module that enables media streams to be proxied + via an &rtp; proxy. The only &rtp; proxy currently known to work + with this module is the Sipwise rtpengine + . + The rtpengine module is a modified version of the original + rtpproxy module using a new control protocol. The module is + designed to be a drop-in replacement for the old module from + a configuration file point of view, however due to the + incompatible control protocol, it only works with &rtp; proxies + which specifically support it. + +
+ +
+ Multiple &rtp; proxy usage + + The rtpengine module can support multiple &rtp; proxies for + balancing/distribution and control/selection purposes. + + + The module allows definition of several sets of rtpengines. + Load-balancing will be performed over a set and the admin has the + ability to choose what set should be used. The set is selected via + its id - the id being defined with the set. Refer to the + rtpengine_sock module parameter definition for syntax + description. + + + The balancing inside a set is done automatically by the module based on + the weight of each &rtp; proxy from the set. + + + The selection of the set is done from script prior using + rtpengine_delete(), rtpengine_offer() or rtpengine_answer() + functions - see the rtpengine_use_set() function. + + + Another way to select the set is to define setid_avp + module parameter and assign setid to the defined avp + before calling rtpengine_offer() or rtpengine_manage() + function. If forwarding of the requests fails and + there is another branch to try, remember to unset the + avp after calling rtpengine_delete() function. + + + For backward compatibility reasons, a set with no id take by default + the id 0. Also if no set is explicitly set before + rtpengine_delete(), rtpengine_offer() or rtpengine_answer() + the 0 id set will be used. + + + IMPORTANT: if you use multiple sets, take care and use the same set for + both rtpengine_offer()/rtpengine_answer() and rtpengine_delete()!! + If the set was selected using setid_avp, the avp needs to be + set only once before rtpengine_offer() or rtpengine_manage() call. + +
+ +
+ Dependencies +
+ &osips; Modules + + The following modules must be loaded before this module: + + + + tm module - (optional) if you want to + have rtpengine_manage() fully functional + + + + +
+
+ External Libraries or Applications + + The following libraries or applications must be installed before + running &osips; with this module loaded: + + + + None. + + + + +
+
+ +
+ Parameters +
+ <varname>rtpengine_sock</varname> (string) + + Definition of socket(s) used to connect to (a set) &rtp; proxy. It may + specify a UNIX socket or an IPv4/IPv6 UDP socket. + + + + Default value is NONE (disabled). + + + + Set <varname>rtpengine_sock</varname> parameter + +... +# single rtproxy +modparam("rtpengine", "rtpengine_sock", "udp:localhost:12221") +# multiple rtproxies for LB +modparam("rtpengine", "rtpengine_sock", + "udp:localhost:12221 udp:localhost:12222") +# multiple sets of multiple rtproxies +modparam("rtpengine", "rtpengine_sock", + "1 == udp:localhost:12221 udp:localhost:12222") +modparam("rtpengine", "rtpengine_sock", + "2 == udp:localhost:12225") +... + + +
+
+ <varname>rtpengine_disable_tout</varname> (integer) + + Once an &rtp; proxy was found unreachable and marked as disabled, the rtpengine + module will not attempt to establish communication to that &rtp; proxy for + rtpengine_disable_tout seconds. + + + + Default value is 60. + + + + Set <varname>rtpengine_disable_tout</varname> parameter + +... +modparam("rtpengine", "rtpengine_disable_tout", 20) +... + + +
+
+ <varname>rtpengine_tout</varname> (integer) + + Timeout value in waiting for reply from &rtp; proxy. + + + + Default value is 1. + + + + Set <varname>rtpengine_tout</varname> parameter + +... +modparam("rtpengine", "rtpengine_tout", 2) +... + + +
+
+ <varname>rtpengine_retr</varname> (integer) + + How many times the module should retry to send and receive after + timeout was generated. + + + + Default value is 5. + + + + Set <varname>rtpengine_retr</varname> parameter + +... +modparam("rtpengine", "rtpengine_retr", 2) +... + + +
+
+ <varname>extra_id_pv</varname> (string) + + The parameter sets the PV defination to use when the b + parameter is used on rtpengine_delete(), rtpengine_offer(), + rtpengine_answer() or rtpengine_manage() command. + + Default is empty, the b parameter may not be used then. + + + Set <varname>extra_id_pv</varname> parameter + +... +modparam("rtpengine", "extra_id_pv", "$avp(extra_id)") +... + + +
+ +
+ <varname>setid_avp</varname> (string) + + The parameter defines an AVP that, if set, + determines which &rtp; proxy set + rtpengine_offer(), rtpengine_answer(), + rtpengine_delete(), and rtpengine_manage() + functions use. + + + There is no default value. + + + Set <varname>setid_avp</varname> parameter + +... +modparam("rtpengine", "setid_avp", "$avp(setid)") +... + + +
+ +
+ +
+ Functions +
+ + <function moreinfo="none">rtpengine_use_set(setid)</function> + + + Sets the ID of the &rtp; proxy set to be used for the next + rtpengine_delete(), rtpengine_offer(), rtpengine_answer() + or rtpengine_manage() command. The parameter can be an integer or + a config variable holding an integer. + + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, + BRANCH_ROUTE. + + + <function>rtpengine_use_set</function> usage + +... +rtpengine_use_set("2"); +rtpengine_offer(); +... + + +
+
+ + <function moreinfo="none">rtpengine_offer([flags])</function> + + + Rewrites &sdp; body to ensure that media is passed through + an &rtp; proxy. To be invoked + on INVITE for the cases the SDPs are in INVITE and 200 OK and on 200 OK + when SDPs are in 200 OK and ACK. + + Meaning of the parameters is as follows: + + + + flags - flags to turn on some features. + + The flags string is a list of space-separated items. Each item + is either an individual token, or a token in key=value format. The + possible tokens are described below. + + + via-branch=... - Include the branch + value of one of the Via headers in the request to the + &rtp; proxy. Possible values are: + 1 - use the first Via header; + 2 - use the second Via header; + auto - use the first Via header if this is + a request, or the second one if this is a reply; + extra - don't take the value from a header, but instead use + the value of the extra_id_pv variable. + This can be used to create one media session per branch + on the &rtp; proxy. When sending a subsequent delete command to + the &rtp; proxy, you can then stop just the session for a specific branch when + passing the flag '1' or '2' in the rtpengine_delete, or stop + all sessions for a call when not passing one of those two flags there. This is + especially useful if you have serially forked call scenarios where the &rtp; proxy + gets an offer command for a new branch, and then a + delete command for the previous branch, which would otherwise + delete the full call, breaking the subsequent answer for the + new branch. This flag is only supported by the Sipwise rtpengine + &rtp; proxy at the moment! + + + asymmetric - flags that UA from which message is + received doesn't support symmetric RTP. (automatically sets the 'r' flag) + + + force-answer - force answer, that is, + only rewrite &sdp; when corresponding session already exists + in the &rtp; proxy. By default is on when the session is to be + completed. + + + internal, external - these flags specify the direction of + the SIP message. These flags only make sense when the &rtp; proxy is running + in bridge mode. internal corresponds to the proxy's first + interface, external corresponds to the &rtp; proxy's + second interface. You always have to specify two flags to define + the incoming network and the outgoing network. For example, internal + external should be + used for SIP message received from the local interface and sent out on the + external interface, and external internal vice versa. Other + options are internal internal and external + external. + So, for example if a SIP requests is processed with internal + external flags, the corresponding + response must be processed with internal external flags. + + + auto-bridge - this flag an alternative to the + internal and external flags + in order to do automatic bridging between IPv4 on the + "internal network" and IPv6 on the "external network". Instead of + explicitly instructing the &rtp; proxy to select a particular address + family, the distinction is done by the given IP in the SDP body by + the RTP proxy itself. Not supported by Sipwise rtpengine. + + + address-family=... - instructs the &rtp; proxy that the + recipient of this &sdp; body expects to see addresses of a particular family. + Possible values are IP4 and IP6. For example, + if the &sdp; body contains IPv4 addresses but the recipient only speaks IPv6, + you would use address-family=IP6 to bridge between the two + address families. + + Sipwise rtpengine remembers the address family preference of each party after + it has seen an &sdp; body from them. This means that normally it is only + necessary to explicitly specify the address family in the offer, + but not in the answer. + + Note: Please note, that this will only work properly with non-dual-stack user-agents or with + dual-stack clients according to RFC6157 (which suggest ICE for Dual-Stack implementations). + This short-cut will not work properly with RFC4091 (ANAT) compatible clients, which suggests + having different m-lines with different IP-protocols grouped together. + + + force - instructs the &rtp; proxy to ignore marks + inserted by another &rtp; proxy in transit to indicate that the + session is already goes through another proxy. Allows creating + a chain of proxies. Not supported and ignored by Sipwise rtpengine. + + + trust-address - flags that IP address in SDP should + be trusted. Without this flag, the &rtp; proxy ignores address in + the SDP and uses source address of the SIP message as media + address which is passed to the RTP proxy. + + + replace-origin - flags that IP from the origin + description (o=) should be also changed. + + + replace-session-connection - flags to change the session-level + SDP connection (c=) IP if media description also includes + connection information. + + + symmetric - flags that for the UA from which + message is received, support symmetric RTP must be forced. + + + repacketize=NN - requests the &rtp; proxy to perform + re-packetization of RTP traffic coming from the UA which + has sent the current message to increase or decrease payload + size per each RTP packet forwarded if possible. The NN is the + target payload size in ms, for the most codecs its value should + be in 10ms increments, however for some codecs the increment + could differ (e.g. 30ms for GSM or 20ms for G.723). The + &rtp; proxy would select the closest value supported by the codec. + This feature could be used for significantly reducing bandwith + overhead for low bitrate codecs, for example with G.729 going + from 10ms to 100ms saves two thirds of the network bandwith. + Not supported by Sipwise rtpengine. + + + ICE=... - controls the &rtp; proxy's behaviour + regarding ICE attributes within the &sdp; body. Possible values + are: force - + discard any ICE attributes already present in the &sdp; body + and then generate and insert new ICE data, leaving itself + as the only ICE candidates; + remove instructs the &rtp; proxy to discard + any ICE attributes and not insert any new ones into the &sdp;. + The default (if no ICE=... is given at all), + new ICE data will only be generated + if no ICE was present in the &sdp; originally; otherwise + the &rtp; proxy will only insert itself as an + additional ICE candidate. Other + &sdp; substitutions (c=, m=, etc) are unaffected by this flag. + + + RTP, SRTP, AVP, AVPF - These flags control the &rtp; + transport protocol that should be used towards the recipient of + the &sdp;. If none of them are specified, the protocol given in + the &sdp; is left untouched. Otherwise, the SRTP flag indicates that + SRTP should be used, while RTP indicates that SRTP should not be used. + AVPF indicates that the advanced RTCP profile with feedback messages + should be used, and AVP indicates that the regular RTCP profile + should be used. See also the next set of flags below. + + + RTP/AVP, RTP/SAVP, RTP/AVPF, RTP/SAVPF - these serve as + an alternative, more explicit way to select between the different &rtp; protocols + and profiles supported by the &rtp; proxy. For example, giving the flag + RTP/SAVPF has the same effect as giving the two flags + SRTP AVPF. + + + to-tag - force inclusion of the To tag. + Normally, the To tag is always included when present, except + for delete messages. Including the To tag in + a delete messages allows you to be more selective about which + dialogues within a call are being torn down. + + + rtcp-mux-demux - if rtcp-mux (RFC 5761) was + offered, make the &rtp; proxy accept the offer, but not offer it to the + recipient of this message. + + + rtcp-mux-reject - if rtcp-mux was offered, make the + &rtp; proxy reject the offer, but still offer it to the recipient. Can be + combined with rtcp-mux-offer to always offer it. + + + rtcp-mux-offer - make the &rtp; proxy offer rtcp-mux + to the recipient of this message, regardless of whether it was offered + originally or not. + + + rtcp-mux-accept - if rtcp-mux was offered, make the + &rtp; proxy accept the offer and also offer it to the recipient of this + message. Can be combined with rtcp-mux-offer to always offer it. + + + media-address=... - force a particular media address to + be used in the &sdp; body. Address family is detected automatically. + + + + + + This function can be used from ANY_ROUTE. + + + <function>rtpengine_offer</function> usage + +route { +... + if (is_method("INVITE")) { + if (has_body("application/sdp")) { + if (rtpengine_offer()) + t_on_reply("1"); + } else { + t_on_reply("2"); + } + } + if (is_method("ACK") && has_body("application/sdp")) + rtpengine_answer(); +... +} + +onreply_route[1] +{ +... + if (has_body("application/sdp")) + rtpengine_answer(); +... +} + +onreply_route[2] +{ +... + if (has_body("application/sdp")) + rtpengine_offer(); +... +} + + +
+
+ + <function moreinfo="none">rtpengine_answer([flags])</function> + + + Rewrites &sdp; body to ensure that media is passed through + an &rtp; proxy. To be invoked + on 200 OK for the cases the SDPs are in INVITE and 200 OK and on ACK + when SDPs are in 200 OK and ACK. + + + See rtpengine_offer() function description above for the meaning of the + parameters. + + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, + FAILURE_ROUTE, BRANCH_ROUTE. + + + <function>rtpengine_answer</function> usage + + See rtpengine_offer() function example above for example. + + +
+
+ + <function moreinfo="none">rtpengine_delete([flags])</function> + + + Tears down the RTPProxy session for the current call. + + + See rtpengine_offer() function description above for the meaning of the + parameters. Note that not all flags make sense for a delete. + + + This function can be used from ANY_ROUTE. + + + <function>rtpengine_delete</function> usage + +... +rtpengine_delete(); +... + + +
+ +
+ + <function moreinfo="none">rtpengine_manage([flags])</function> + + + Manage the RTPProxy session - it combines the functionality of + rtpengine_offer(), rtpengine_answer() and rtpengine_delete(), detecting + internally based on message type and method which one to execute. + + + It can take the same parameters as rtpengine_offer(). + The flags parameter to rtpengine_manage() can be a configuration variable + containing the flags as a string. + + + Functionality: + + + + + If INVITE with SDP, then do rtpengine_offer() + + + + + If INVITE with SDP, when the tm module is loaded, mark transaction with + internal flag FL_SDP_BODY to know that the 1xx and 2xx are for + rtpengine_answer() + + + + + If ACK with SDP, then do rtpengine_answer() + + + + + If BYE or CANCEL, or called within a FAILURE_ROUTE[], then do rtpengine_delete() + + + + + If reply to INVITE with code >= 300 do rtpengine_delete() + + + + + If reply with SDP to INVITE having code 1xx and 2xx, then + do rtpengine_answer() if the request had SDP or tm is not loaded, + otherwise do rtpengine_offer() + + + + + + This function can be used from ANY_ROUTE. + + + <function>rtpengine_manage</function> usage + +... +rtpengine_manage(); +... + + +
+ +
+ + <function moreinfo="none">rtpengine_start_recording()</function> + + + This function will send a signal to the &rtp; proxy to record + the RTP stream on the &rtp; proxy. + This function is not supported by Sipwise rtpengine at the moment! + + + This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE. + + + <function>rtpengine_start_recording</function> usage + +... +rtpengine_start_recording(); +... + + +
+ + +
+ +
+ Exported Pseudo Variables +
+ <function moreinfo="none">$rtpstat</function> + + Returns the &rtp; statistics from the &rtp; proxy. The &rtp; statistics from the &rtp; proxy + are provided as a string and it does contain several packet counters. The statistics + must be retrieved before the session is deleted (before rtpengine_delete()). + + + + $rtpstat Usage + +... + append_hf("X-RTP-Statistics: $rtpstat\r\n"); +... + + +
+ +
+ +
+ <acronym>MI</acronym> Commands +
+ <function moreinfo="none">rtpengine_enable</function> + + Enables a &rtp; proxy if parameter value is greater than 0. + Disables it if a zero value is given. + + + The first parameter is the &rtp; proxy url (exactly as defined in + the config file). + + + The second parameter value must be a number in decimal. + + + NOTE: if a &rtp; proxy is defined multiple times (in the same or + diferente sete), all of its instances will be enables/disabled. + + + + <function moreinfo="none">rtpengine_enable</function> usage + +... +$ opensipsctl fifo rtpengine_enable udp:192.168.2.133:8081 0 +... + + +
+ +
+ <function moreinfo="none">rtpengine_show</function> + + Displays all the &rtp; proxies and their information: set and + status (disabled or not, weight and recheck_ticks). + + + No parameter. + + + + <function moreinfo="none">rtpengine_show</function> usage + +... +$ opensipsctl fifo rtpengine_show +... + + +
+
+ +
+ diff --git a/modules/rtpengine/doc/rtpengine_faq.xml b/modules/rtpengine/doc/rtpengine_faq.xml new file mode 100644 index 00000000000..8c821ca776a --- /dev/null +++ b/modules/rtpengine/doc/rtpengine_faq.xml @@ -0,0 +1,94 @@ + + + + + &faqguide; + + + + How do I migrate from rtpproxy or rtpproxy-ng to + rtpengine? + + + + For the most part, only the names of the functions have changed, with + rtpproxy in each name replaced with rtpengine. + For example, rtpproxy_manage() has become + rtpengine_manage(). A few name duplications have also been resolved, + for example there is now a single rtpengine_delete() instead of + unforce_rtp_proxy() and the identical rtpproxy_destroy(). + + + The largest difference to the old module is how flags are passed to + rtpengine_offer(), rtpengine_answer(), + rtpengine_manage() and rtpengine_delete(). Instead of + having a string of single-letter flags, they now take a string of space-separated + items, with each item being either a single token (word) or a key=value + pair. + + + For example, if you had a call rtpproxy_offer("FRWOC+PS");, this would + then become: + + +rtpengine_offer("force trust-address symmetric replace-origin replace-session-connection ICE=force RTP/SAVPF"); + + + Finally, if you were using the second paramater (explicit media address) to any of + these functions, this has been replaced by the media-address=... + option within the first string of flags. + + + + + + Where can I find more about OpenSIPS? + + + + Take a look at &osipshomelink;. + + + + + + Where can I post a question about this module? + + + + First at all check if your question was already answered on one of + our mailing lists: + + + + User Mailing List - &osipsuserslink; + + + Developer Mailing List - &osipsdevlink; + + + + E-mails regarding any stable &osips; release should be sent to + &osipsusersmail; and e-mails regarding development versions + should be sent to &osipsdevmail;. + + + If you want to keep the mail private, send it to + &osipshelpmail;. + + + + + + How can I report a bug? + + + + Please follow the guidelines provided at: + &osipsbugslink;. + + + + + + diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c new file mode 100644 index 00000000000..d80d2dbc2a3 --- /dev/null +++ b/modules/rtpengine/rtpengine.c @@ -0,0 +1,1920 @@ +/* + * Copyright (C) 2003-2008 Sippy Software, Inc., http://www.sippysoft.com + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * --------- + * 2014-06-17 Imported from rtpproxy module + */ + +#include +#include +#include +#include +#include +#ifndef __USE_BSD +#define __USE_BSD +#endif +#include +#ifndef __FAVOR_BSD +#define __FAVOR_BSD +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../str.h" +#include "../../flags.h" +#include "../../sr_module.h" +#include "../../dprint.h" +#include "../../data_lump.h" +#include "../../data_lump_rpl.h" +#include "../../error.h" +#include "../../forward.h" +#include "../../mem/mem.h" +#include "../../parser/parse_from.h" +#include "../../parser/parse_to.h" +#include "../../parser/parse_uri.h" +#include "../../parser/parser_f.h" +#include "../../parser/sdp/sdp.h" +#include "../../resolve.h" +#include "../../timer.h" +#include "../../trim.h" +#include "../../ut.h" +#include "../../pt.h" +#include "../../pvar.h" +#include "../../msg_translator.h" +#include "../../usr_avp.h" +#include "../../socket_info.h" +#include "../../mod_fix.h" +#include "../../dset.h" +#include "../../route.h" +#include "../../modules/tm/tm_load.h" +#include "rtpengine.h" +#include "rtpengine_funcs.h" +#include "bencode.h" + +#if !defined(AF_LOCAL) +#define AF_LOCAL AF_UNIX +#endif +#if !defined(PF_LOCAL) +#define PF_LOCAL PF_UNIX +#endif + +#define DEFAULT_RTPE_SET_ID 0 + +#define MI_ENABLE_RTP_ENGINE "rtpengine_enable" +#define MI_MIN_RECHECK_TICKS 0 +#define MI_MAX_RECHECK_TICKS (unsigned int)-1 + +#define MI_SHOW_RTP_ENGINES "rtpengine_show" + +#define MI_RTP_ENGINE_NOT_FOUND "RTP engine not found" +#define MI_RTP_ENGINE_NOT_FOUND_LEN (sizeof(MI_RTP_ENGINE_NOT_FOUND)-1) +#define MI_SET "Set" +#define MI_SET_LEN (sizeof(MI_SET)-1) +#define MI_NODE "node" +#define MI_NODE_LEN (sizeof(MI_NODE)-1) +#define MI_INDEX "index" +#define MI_INDEX_LEN (sizeof(MI_INDEX)-1) +#define MI_DISABLED "disabled" +#define MI_DISABLED_LEN (sizeof(MI_DISABLED)-1) +#define MI_WEIGHT "weight" +#define MI_WEIGHT_LEN (sizeof(MI_WEIGHT)-1) +#define MI_RECHECK_TICKS "recheck_ticks" +#define MI_RECHECK_T_LEN (sizeof(MI_RECHECK_TICKS)-1) + + + +#define CPORT "22222" + +enum rtpe_operation { + OP_OFFER = 1, + OP_ANSWER, + OP_DELETE, + OP_START_RECORDING, + OP_QUERY, +}; + +struct ng_flags_parse { + int via, to, packetize, transport; + bencode_item_t *dict, *flags, *direction, *replace, *rtcp_mux; +}; + +static const char *command_strings[] = { + [OP_OFFER] = "offer", + [OP_ANSWER] = "answer", + [OP_DELETE] = "delete", + [OP_START_RECORDING] = "start recording", + [OP_QUERY] = "query", +}; + +static char *gencookie(); +static int rtpe_test(struct rtpe_node*, int, int); +static int start_recording_f(struct sip_msg *, char *, char *); +static int rtpengine_answer1_f(struct sip_msg *, char *, char *); +static int rtpengine_offer1_f(struct sip_msg *, char *, char *); +static int rtpengine_delete1_f(struct sip_msg *, char *, char *); +static int rtpengine_manage1_f(struct sip_msg *, char *, char *); + +static int parse_flags(struct ng_flags_parse *, struct sip_msg *, enum rtpe_operation *, const char *); + +static int rtpengine_offer_answer(struct sip_msg *msg, const char *flags, int op); +static int add_rtpengine_socks(struct rtpe_set * rtpe_list, char * rtpengine); +static int fixup_set_id(void ** param, int param_no); +static int set_rtpengine_set_f(struct sip_msg * msg, char * str1, char * str2); +static struct rtpe_set * select_rtpe_set(int id_set); +static struct rtpe_node *select_rtpe_node(str, int); +static char *send_rtpe_command(struct rtpe_node *, bencode_item_t *, int *); +static int get_extra_id(struct sip_msg* msg, str *id_str); + +static int rtpengine_set_store(modparam_t type, void * val); +static int rtpengine_add_rtpengine_set( char * rtp_proxies); + +static int mod_init(void); +static int child_init(int); +static void mod_destroy(void); + +/* Pseudo-Variables */ +static int pv_get_rtpstat_f(struct sip_msg *, pv_param_t *, pv_value_t *); + +/*mi commands*/ +static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, + void* param ); +static struct mi_root* mi_show_rtpengines(struct mi_root* cmd_tree, + void* param); + + +static int rtpengine_disable_tout = 60; +static int rtpengine_retr = 5; +static int rtpengine_tout = 1; +static pid_t mypid; +static unsigned int myseqn = 0; +static str extra_id_pv_param = {NULL, 0}; +static char *setid_avp_param = NULL; + +static char ** rtpe_strings=0; +static int rtpe_sets=0; /*used in rtpengine_set_store()*/ +static int rtpe_set_count = 0; +static unsigned int current_msg_id = (unsigned int)-1; +/* RTP proxy balancing list */ +struct rtpe_set_head * rtpe_set_list =0; +struct rtpe_set * selected_rtpe_set =0; +struct rtpe_set * default_rtpe_set=0; + +/* array with the sockets used by rtpengine (per process)*/ +static unsigned int rtpe_no = 0; +static int *rtpe_socks = 0; + +static int setid_avp_type; +static int_str setid_avp; + +typedef struct rtpe_set_link { + struct rtpe_set *rset; + pv_spec_t rpv; +} rtpe_set_link_t; + +/* tm */ +static struct tm_binds tmb; + +/*0-> disabled, 1 ->enabled*/ +unsigned int *natping_state=0; + +static pv_elem_t *extra_id_pv = NULL; + +#define ANY_ROUTE (REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE) +static cmd_export_t cmds[] = { + {"rtpengine_use_set", (cmd_function)set_rtpengine_set_f, 1, + fixup_set_id, 0, + ANY_ROUTE}, + {"rtpengine_start_recording", (cmd_function)start_recording_f, 0, + 0, 0, + ANY_ROUTE }, + {"rtpengine_offer", (cmd_function)rtpengine_offer1_f, 0, + 0, 0, + ANY_ROUTE}, + {"rtpengine_offer", (cmd_function)rtpengine_offer1_f, 1, + fixup_spve_null, 0, + ANY_ROUTE}, + {"rtpengine_answer", (cmd_function)rtpengine_answer1_f, 0, + 0, 0, + ANY_ROUTE}, + {"rtpengine_answer", (cmd_function)rtpengine_answer1_f, 1, + fixup_spve_null, 0, + ANY_ROUTE}, + {"rtpengine_manage", (cmd_function)rtpengine_manage1_f, 0, + 0, 0, + ANY_ROUTE}, + {"rtpengine_manage", (cmd_function)rtpengine_manage1_f, 1, + fixup_spve_null, 0, + ANY_ROUTE}, + {"rtpengine_delete", (cmd_function)rtpengine_delete1_f, 0, + 0, 0, + ANY_ROUTE}, + {"rtpengine_delete", (cmd_function)rtpengine_delete1_f, 1, + fixup_spve_null, 0, + ANY_ROUTE}, + {0, 0, 0, 0, 0, 0} +}; + +static pv_export_t mod_pvs[] = { + {{"rtpstat", (sizeof("rtpstat")-1)}, /* RTP-Statistics */ + 1000, pv_get_rtpstat_f, 0, 0, 0, 0, 0}, + {{0, 0}, 0, 0, 0, 0, 0, 0, 0} +}; + +static param_export_t params[] = { + {"rtpengine_sock", STR_PARAM|USE_FUNC_PARAM, + (void*)rtpengine_set_store }, + {"rtpengine_disable_tout", INT_PARAM, &rtpengine_disable_tout }, + {"rtpengine_retr", INT_PARAM, &rtpengine_retr }, + {"rtpengine_tout", INT_PARAM, &rtpengine_tout }, + {"extra_id_pv", STR_PARAM, &extra_id_pv_param.s }, + {"setid_avp", STR_PARAM, &setid_avp_param }, + {0, 0, 0} +}; + +static mi_export_t mi_cmds[] = { + {MI_ENABLE_RTP_ENGINE, 0, mi_enable_rtp_proxy, 0, 0, 0}, + {MI_SHOW_RTP_ENGINES, 0, mi_show_rtpengines, MI_NO_INPUT_FLAG, 0, 0}, + { 0, 0, 0, 0, 0, 0} +}; + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + +struct module_exports exports = { + "rtpengine", + MOD_TYPE_DEFAULT,/* class of this module */ + MODULE_VERSION, + DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ + cmds, + params, + 0, /* exported statistics */ + mi_cmds, /* exported MI functions */ + mod_pvs, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, + 0, /* reply processing */ + mod_destroy, /* destroy function */ + child_init +}; + +int msg_has_sdp(struct sip_msg *msg) +{ + str body; + struct part *p; + struct multi_body *m; + + if(parse_headers(msg, HDR_CONTENTLENGTH_F,0) < 0) { + LM_ERR("cannot parse cseq header"); + return 0; + } + + body.len = get_content_length(msg); + if (!body.len) + return 0; + + m = get_all_bodies(msg); + if (!m) { + LM_DBG("cannot parse body\n"); + return 0; + } + + for (p = m->first; p; p = p->next) { + if (p->content_type == ((TYPE_APPLICATION << 16) + SUBTYPE_SDP)) + return 1; + } + + return 0; +} + + + +static inline int str_eq(const str *p, const char *q) { + int l = strlen(q); + if (p->len != l) + return 0; + if (memcmp(p->s, q, l)) + return 0; + return 1; +} + + +static int rtpengine_set_store(modparam_t type, void * val){ + + char * p; + int len; + + p = (char* )val; + + if(p==0 || *p=='\0'){ + return 0; + } + + if(rtpe_sets==0){ + rtpe_strings = (char**)pkg_malloc(sizeof(char*)); + if(!rtpe_strings){ + LM_ERR("no pkg memory left\n"); + return -1; + } + } else {/*realloc to make room for the current set*/ + rtpe_strings = (char**)pkg_realloc(rtpe_strings, + (rtpe_sets+1)* sizeof(char*)); + if(!rtpe_strings){ + LM_ERR("no pkg memory left\n"); + return -1; + } + } + + /*allocate for the current set of urls*/ + len = strlen(p); + rtpe_strings[rtpe_sets] = (char*)pkg_malloc((len+1)*sizeof(char)); + + if(!rtpe_strings[rtpe_sets]){ + LM_ERR("no pkg memory left\n"); + return -1; + } + + memcpy(rtpe_strings[rtpe_sets], p, len); + rtpe_strings[rtpe_sets][len] = '\0'; + rtpe_sets++; + + return 0; +} + + +static int add_rtpengine_socks(struct rtpe_set * rtpe_list, + char * rtpengine){ + /* Make rtp proxies list. */ + char *p, *p1, *p2, *plim; + struct rtpe_node *pnode; + int weight; + + p = rtpengine; + plim = p + strlen(p); + + for(;;) { + weight = 1; + while (*p && isspace((int)*p)) + ++p; + if (p >= plim) + break; + p1 = p; + while (*p && !isspace((int)*p)) + ++p; + if (p <= p1) + break; /* may happen??? */ + /* Have weight specified? If yes, scan it */ + p2 = memchr(p1, '=', p - p1); + if (p2 != NULL) { + weight = strtoul(p2 + 1, NULL, 10); + } else { + p2 = p; + } + pnode = shm_malloc(sizeof(struct rtpe_node)); + if (pnode == NULL) { + LM_ERR("no shm memory left\n"); + return -1; + } + memset(pnode, 0, sizeof(*pnode)); + pnode->idx = rtpe_no++; + pnode->rn_recheck_ticks = 0; + pnode->rn_weight = weight; + pnode->rn_umode = 0; + pnode->rn_disabled = 0; + pnode->rn_url.s = shm_malloc(p2 - p1 + 1); + if (pnode->rn_url.s == NULL) { + shm_free(pnode); + LM_ERR("no shm memory left\n"); + return -1; + } + memmove(pnode->rn_url.s, p1, p2 - p1); + pnode->rn_url.s[p2 - p1] = 0; + pnode->rn_url.len = p2-p1; + + LM_DBG("url is %s, len is %i\n", pnode->rn_url.s, pnode->rn_url.len); + /* Leave only address in rn_address */ + pnode->rn_address = pnode->rn_url.s; + if (strncasecmp(pnode->rn_address, "udp:", 4) == 0) { + pnode->rn_umode = 1; + pnode->rn_address += 4; + } else if (strncasecmp(pnode->rn_address, "udp6:", 5) == 0) { + pnode->rn_umode = 6; + pnode->rn_address += 5; + } else if (strncasecmp(pnode->rn_address, "unix:", 5) == 0) { + pnode->rn_umode = 0; + pnode->rn_address += 5; + } + + if (rtpe_list->rn_first == NULL) { + rtpe_list->rn_first = pnode; + } else { + rtpe_list->rn_last->rn_next = pnode; + } + + rtpe_list->rn_last = pnode; + rtpe_list->rtpe_node_count++; + } + return 0; +} + + +/* 0-succes + * -1 - erorr + * */ +static int rtpengine_add_rtpengine_set( char * rtp_proxies) +{ + char *p,*p2; + struct rtpe_set * rtpe_list; + unsigned int my_current_id; + str id_set; + int new_list; + + /* empty definition? */ + p= rtp_proxies; + if(!p || *p=='\0'){ + return 0; + } + + for(;*p && isspace(*p);p++); + if(*p=='\0'){ + return 0; + } + + rtp_proxies = strstr(p, "=="); + if(rtp_proxies){ + if(*(rtp_proxies +2)=='\0'){ + LM_ERR("script error -invalid rtp proxy list!\n"); + return -1; + } + + *rtp_proxies = '\0'; + p2 = rtp_proxies-1; + for(;isspace(*p2); *p2 = '\0',p2--); + id_set.s = p; id_set.len = p2 - p+1; + + if(id_set.len <= 0 ||str2int(&id_set, &my_current_id)<0 ){ + LM_ERR("script error -invalid set_id value!\n"); + return -1; + } + + rtp_proxies+=2; + }else{ + rtp_proxies = p; + my_current_id = DEFAULT_RTPE_SET_ID; + } + + for(;*rtp_proxies && isspace(*rtp_proxies);rtp_proxies++); + + if(!(*rtp_proxies)){ + LM_ERR("script error -empty rtp_proxy list\n"); + return -1;; + } + + /*search for the current_id*/ + rtpe_list = rtpe_set_list ? rtpe_set_list->rset_first : 0; + while( rtpe_list != 0 && rtpe_list->id_set!=my_current_id) + rtpe_list = rtpe_list->rset_next; + + if(rtpe_list==NULL){ /*if a new id_set : add a new set of rtpe*/ + rtpe_list = shm_malloc(sizeof(struct rtpe_set)); + if(!rtpe_list){ + LM_ERR("no shm memory left\n"); + return -1; + } + memset(rtpe_list, 0, sizeof(struct rtpe_set)); + rtpe_list->id_set = my_current_id; + new_list = 1; + } else { + new_list = 0; + } + + if(add_rtpengine_socks(rtpe_list, rtp_proxies)!= 0){ + /*if this list will not be inserted, clean it up*/ + goto error; + } + + if (new_list) { + if(!rtpe_set_list){/*initialize the list of set*/ + rtpe_set_list = shm_malloc(sizeof(struct rtpe_set_head)); + if(!rtpe_set_list){ + LM_ERR("no shm memory left\n"); + return -1; + } + memset(rtpe_set_list, 0, sizeof(struct rtpe_set_head)); + } + + /*update the list of set info*/ + if(!rtpe_set_list->rset_first){ + rtpe_set_list->rset_first = rtpe_list; + }else{ + rtpe_set_list->rset_last->rset_next = rtpe_list; + } + + rtpe_set_list->rset_last = rtpe_list; + rtpe_set_count++; + + if(my_current_id == DEFAULT_RTPE_SET_ID){ + default_rtpe_set = rtpe_list; + } + } + + return 0; +error: + return -1; +} + + +static int fixup_set_id(void ** param, int param_no) +{ + int int_val, err; + struct rtpe_set* rtpe_list; + rtpe_set_link_t *rtpl = NULL; + str s; + + rtpl = (rtpe_set_link_t*)pkg_malloc(sizeof(rtpe_set_link_t)); + if(rtpl==NULL) { + LM_ERR("no more pkg memory\n"); + return -1; + } + memset(rtpl, 0, sizeof(rtpe_set_link_t)); + s.s = (char*)*param; + s.len = strlen(s.s); + + if(s.s[0] == PV_MARKER) { + if ( pv_parse_spec(&s, &rtpl->rpv) == NULL ) { + LM_ERR("invalid parameter %s\n", s.s); + return -1; + } + } else { + int_val = str2s(*param, strlen(*param), &err); + if (err == 0) { + pkg_free(*param); + if((rtpe_list = select_rtpe_set(int_val)) ==0){ + LM_ERR("rtpe_proxy set %i not configured\n", int_val); + return E_CFG; + } + rtpl->rset = rtpe_list; + } else { + LM_ERR("bad number <%s>\n", (char *)(*param)); + return E_CFG; + } + } + *param = (void*)rtpl; + return 0; +} + +static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, + void* param ) +{ struct mi_node* node; + str rtpe_url; + unsigned int enable; + struct rtpe_set * rtpe_list; + struct rtpe_node * crt_rtpe; + int found; + + found = 0; + + if(rtpe_set_list ==NULL) + goto end; + + node = cmd_tree->node.kids; + if(node == NULL) + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + + if(node->value.s == NULL || node->value.len ==0) + return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + + rtpe_url = node->value; + + node = node->next; + if(node == NULL) + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + + enable = 0; + if( strno2int( &node->value, &enable) <0) + goto error; + + for(rtpe_list = rtpe_set_list->rset_first; rtpe_list != NULL; + rtpe_list = rtpe_list->rset_next){ + + for(crt_rtpe = rtpe_list->rn_first; crt_rtpe != NULL; + crt_rtpe = crt_rtpe->rn_next){ + /*found a matching rtpe*/ + + if(crt_rtpe->rn_url.len == rtpe_url.len){ + + if(strncmp(crt_rtpe->rn_url.s, rtpe_url.s, rtpe_url.len) == 0){ + /*set the enabled/disabled status*/ + found = 1; + crt_rtpe->rn_recheck_ticks = + enable? MI_MIN_RECHECK_TICKS : MI_MAX_RECHECK_TICKS; + crt_rtpe->rn_disabled = enable?0:1; + } + } + } + } + +end: + if(found) + return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); + return init_mi_tree(404,MI_RTP_ENGINE_NOT_FOUND,MI_RTP_ENGINE_NOT_FOUND_LEN); +error: + return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); +} + + + +#define add_rtpe_node_int_info(_parent, _name, _name_len, _value, _attr,\ + _len, _string, _error)\ + do {\ + (_string) = int2str((_value), &(_len));\ + if((_string) == 0){\ + LM_ERR("cannot convert int value\n");\ + goto _error;\ + }\ + if(((_attr) = add_mi_attr((_parent), MI_DUP_VALUE, (_name), \ + (_name_len), (_string), (_len)) ) == 0)\ + goto _error;\ + }while(0); + +static struct mi_root* mi_show_rtpengines(struct mi_root* cmd_tree, + void* param) +{ + struct mi_node* node, *crt_node, *set_node; + struct mi_root* root; + struct mi_attr * attr; + struct rtpe_set * rtpe_list; + struct rtpe_node * crt_rtpe; + char * string, *id; + int id_len, len; + + string = id = 0; + + root = init_mi_tree(200, MI_OK_S, MI_OK_LEN); + if (!root) { + LM_ERR("the MI tree cannot be initialized!\n"); + return 0; + } + + if(rtpe_set_list ==NULL) + return root; + + node = &root->node; + node->flags |= MI_IS_ARRAY; + + for(rtpe_list = rtpe_set_list->rset_first; rtpe_list != NULL; + rtpe_list = rtpe_list->rset_next){ + + id = int2str(rtpe_list->id_set, &id_len); + if(!id){ + LM_ERR("cannot convert set id\n"); + goto error; + } + + if(!(set_node = add_mi_node_child(node, MI_IS_ARRAY|MI_DUP_VALUE, MI_SET, MI_SET_LEN, + id, id_len))) { + LM_ERR("cannot add the set node to the tree\n"); + goto error; + } + + for(crt_rtpe = rtpe_list->rn_first; crt_rtpe != NULL; + crt_rtpe = crt_rtpe->rn_next){ + + if(!(crt_node = add_mi_node_child(node, MI_DUP_VALUE, + MI_NODE, MI_NODE_LEN, + crt_rtpe->rn_url.s, crt_rtpe->rn_url.len)) ) { + LM_ERR("cannot add the child node to the tree\n"); + goto error; + } + + LM_DBG("adding node name %s \n",crt_rtpe->rn_url.s ); + + add_rtpe_node_int_info(crt_node, MI_INDEX, MI_INDEX_LEN, + crt_rtpe->idx, attr, len,string,error); + add_rtpe_node_int_info(crt_node, MI_DISABLED, MI_DISABLED_LEN, + crt_rtpe->rn_disabled, attr, len,string,error); + add_rtpe_node_int_info(crt_node, MI_WEIGHT, MI_WEIGHT_LEN, + crt_rtpe->rn_weight, attr, len, string,error); + add_rtpe_node_int_info(crt_node, MI_RECHECK_TICKS,MI_RECHECK_T_LEN, + crt_rtpe->rn_recheck_ticks, attr, len, string, error); + } + } + + return root; +error: + if (root) + free_mi_tree(root); + return 0; +} + + +static int +mod_init(void) +{ + int i; + pv_spec_t avp_spec; + unsigned short avp_flags; + str s; + + if(register_mi_mod(exports.name, mi_cmds)!=0) + { + LM_ERR("failed to register MI commands\n"); + return -1; + } + + /* any rtpengine configured? */ + if(rtpe_set_list) + default_rtpe_set = select_rtpe_set(DEFAULT_RTPE_SET_ID); + + /* storing the list of rtp proxy sets in shared memory*/ + for(i=0;i\n", + setid_avp_param); + return -1; + } + if (pv_get_avp_name(0, &(avp_spec.pvp), &(setid_avp.n), + &avp_flags) != 0) { + LM_ERR("invalid AVP definition <%s>\n", setid_avp_param); + return -1; + } + setid_avp_type = avp_flags; + } + + if (rtpe_strings) + pkg_free(rtpe_strings); + + if (load_tm_api( &tmb ) < 0) + { + LM_DBG("could not load the TM-functions - answer-offer model" + " auto-detection is disabled\n"); + memset(&tmb, 0, sizeof(struct tm_binds)); + } + + return 0; +} + + +static int +child_init(int rank) +{ + int n; + char *cp; + struct addrinfo hints, *res; + struct rtpe_set *rtpe_list; + struct rtpe_node *pnode; + + if(rtpe_set_list==NULL ) + return 0; + + /* Iterate known RTP proxies - create sockets */ + mypid = getpid(); + + rtpe_socks = (int*)pkg_malloc( sizeof(int)*rtpe_no ); + if (rtpe_socks==NULL) { + LM_ERR("no more pkg memory\n"); + return -1; + } + + for(rtpe_list = rtpe_set_list->rset_first; rtpe_list != 0; + rtpe_list = rtpe_list->rset_next){ + + for (pnode=rtpe_list->rn_first; pnode!=0; pnode = pnode->rn_next){ + char *hostname; + + if (pnode->rn_umode == 0) { + rtpe_socks[pnode->idx] = -1; + goto rptest; + } + + /* + * This is UDP or UDP6. Detect host and port; lookup host; + * do connect() in order to specify peer address + */ + hostname = (char*)pkg_malloc(sizeof(char) * (strlen(pnode->rn_address) + 1)); + if (hostname==NULL) { + LM_ERR("no more pkg memory\n"); + return -1; + } + strcpy(hostname, pnode->rn_address); + + cp = strrchr(hostname, ':'); + if (cp != NULL) { + *cp = '\0'; + cp++; + } + if (cp == NULL || *cp == '\0') + cp = CPORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = 0; + hints.ai_family = (pnode->rn_umode == 6) ? AF_INET6 : AF_INET; + hints.ai_socktype = SOCK_DGRAM; + if ((n = getaddrinfo(hostname, cp, &hints, &res)) != 0) { + LM_ERR("%s\n", gai_strerror(n)); + pkg_free(hostname); + return -1; + } + pkg_free(hostname); + + rtpe_socks[pnode->idx] = socket((pnode->rn_umode == 6) + ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); + if ( rtpe_socks[pnode->idx] == -1) { + LM_ERR("can't create socket\n"); + freeaddrinfo(res); + return -1; + } + + if (connect( rtpe_socks[pnode->idx], res->ai_addr, res->ai_addrlen) == -1) { + LM_ERR("can't connect to a RTP proxy\n"); + close( rtpe_socks[pnode->idx] ); + rtpe_socks[pnode->idx] = -1; + freeaddrinfo(res); + return -1; + } + freeaddrinfo(res); +rptest: + pnode->rn_disabled = rtpe_test(pnode, 0, 1); + } + } + + return 0; +} + + +static void mod_destroy(void) +{ + struct rtpe_set * crt_list, * last_list; + struct rtpe_node * crt_rtpe, *last_rtpe; + + /*free the shared memory*/ + if (natping_state) + shm_free(natping_state); + + if(rtpe_set_list == NULL) + return; + + for(crt_list = rtpe_set_list->rset_first; crt_list != NULL; ){ + + for(crt_rtpe = crt_list->rn_first; crt_rtpe != NULL; ){ + + if(crt_rtpe->rn_url.s) + shm_free(crt_rtpe->rn_url.s); + + last_rtpe = crt_rtpe; + crt_rtpe = last_rtpe->rn_next; + shm_free(last_rtpe); + } + + last_list = crt_list; + crt_list = last_list->rset_next; + shm_free(last_list); + } + + shm_free(rtpe_set_list); +} + + + +static char * gencookie(void) +{ + static char cook[34]; + + sprintf(cook, "%d_%u ", (int)mypid, myseqn); + myseqn++; + return cook; +} + + + +static const char *transports[] = { + [0x00] = "RTP/AVP", + [0x01] = "RTP/SAVP", + [0x02] = "RTP/AVPF", + [0x03] = "RTP/SAVPF", +}; + +static int parse_flags(struct ng_flags_parse *ng_flags, struct sip_msg *msg, enum rtpe_operation *op, + const char *flags_str) +{ + char *e; + const char *err; + str key, val; + + if (!flags_str) + return 0; + + while (1) { + while (*flags_str == ' ') + flags_str++; + + key.s = (void *) flags_str; + val.len = key.len = -1; + val.s = NULL; + + e = strpbrk(key.s, " ="); + if (!e) + e = key.s + strlen(key.s); + else if (*e == '=') { + key.len = e - key.s; + val.s = e + 1; + e = strchr(val.s, ' '); + if (!e) + e = val.s + strlen(val.s); + val.len = e - val.s; + } + + if (key.len == -1) + key.len = e - key.s; + if (!key.len) + break; + + /* XXX make this prettier */ + err = "unknown flag"; + switch (key.len) { + case 3: + if (str_eq(&key, "ICE")) { + err = "missing value"; + if (!val.s) + goto error; + err = "invalid value"; + if (str_eq(&val, "force") || str_eq(&val, "remove")) + bencode_dictionary_add_str(ng_flags->dict, "ICE", &val); + else + goto error; + } + else if (str_eq(&key, "RTP")) { + ng_flags->transport |= 0x100; + ng_flags->transport &= ~0x001; + } + else if (str_eq(&key, "AVP")) { + ng_flags->transport |= 0x100; + ng_flags->transport &= ~0x002; + } + else + goto error; + break; + + case 4: + if (str_eq(&key, "SRTP")) + ng_flags->transport |= 0x101; + else if (str_eq(&key, "AVPF")) + ng_flags->transport |= 0x102; + else + goto error; + break; + + case 5: + if (str_eq(&key, "force")) + bencode_list_add_string(ng_flags->flags, "force"); + else + goto error; + break; + + case 6: + if (str_eq(&key, "to-tag")) + ng_flags->to = 1; + else + goto error; + break; + + case 7: + if (str_eq(&key, "RTP/AVP")) + ng_flags->transport = 0x100; + else + goto error; + break; + + case 8: + if (str_eq(&key, "internal")) + bencode_list_add_string(ng_flags->direction, "internal"); + else if (str_eq(&key, "external")) + bencode_list_add_string(ng_flags->direction, "external"); + else if (str_eq(&key, "RTP/AVPF")) + ng_flags->transport = 0x102; + else if (str_eq(&key, "RTP/SAVP")) + ng_flags->transport = 0x101; + else + goto error; + break; + + case 9: + if (str_eq(&key, "symmetric")) + bencode_list_add_string(ng_flags->flags, "symmetric"); + else if (str_eq(&key, "RTP/SAVPF")) + ng_flags->transport = 0x103; + else + goto error; + break; + + case 10: + if (str_eq(&key, "via-branch")) { + err = "missing value"; + if (!val.s) + goto error; + err = "invalid value"; + if (*val.s == '1' || *val.s == '2') + ng_flags->via = *val.s - '0'; + else if (str_eq(&val, "auto")) + ng_flags->via = 3; + else if (str_eq(&val, "extra")) + ng_flags->via = -1; + else + goto error; + } + else if (str_eq(&key, "asymmetric")) + bencode_list_add_string(ng_flags->flags, "asymmetric"); + else + goto error; + break; + + case 11: + if (str_eq(&key, "auto-bridge")) + bencode_list_add_string(ng_flags->flags, "auto-bridge"); + else if (str_eq(&key, "repacketize")) { + err = "missing value"; + if (!val.s) + goto error; + ng_flags->packetize = 0; + while (isdigit(*val.s)) { + ng_flags->packetize *= 10; + ng_flags->packetize += *val.s - '0'; + val.s++; + } + err = "invalid value"; + if (!ng_flags->packetize) + goto error; + bencode_dictionary_add_integer(ng_flags->dict, "repacketize", ng_flags->packetize); + } + else + goto error; + break; + + case 12: + if (str_eq(&key, "force-answer")) { + err = "cannot force answer in non-offer command"; + if (*op != OP_OFFER) + goto error; + *op = OP_ANSWER; + } + else + goto error; + break; + case 13: + if (str_eq(&key, "trust-address")) + bencode_list_add_string(ng_flags->flags, "trust-address"); + else if (str_eq(&key, "media-address")) { + err = "missing value"; + if (!val.s) + goto error; + } + else + goto error; + break; + + case 14: + if (str_eq(&key, "replace-origin")) + bencode_list_add_string(ng_flags->replace, "origin"); + else if (str_eq(&key, "address-family")) { + err = "missing value"; + if (!val.s) + goto error; + err = "invalid value"; + if (str_eq(&val, "IP4") || str_eq(&val, "IP6")) + bencode_dictionary_add_str(ng_flags->dict, "address family", &val); + else + goto error; + } + else if (str_eq(&key, "rtcp-mux-demux")) + bencode_list_add_string(ng_flags->rtcp_mux, "demux"); + else if (str_eq(&key, "rtcp-mux-offer")) + bencode_list_add_string(ng_flags->rtcp_mux, "offer"); + else + goto error; + break; + + case 15: + if (str_eq(&key, "rtcp-mux-reject")) + bencode_list_add_string(ng_flags->rtcp_mux, "reject"); + else if (str_eq(&key, "rtcp-mux-accept")) + bencode_list_add_string(ng_flags->rtcp_mux, "accept"); + else + goto error; + break; + + case 26: + if (str_eq(&key, "replace-session-connection")) + bencode_list_add_string(ng_flags->replace, "session-connection"); + else + goto error; + break; + + default: + goto error; + } + + flags_str = e; + } + + return 0; + +error: + if (val.s) + LM_ERR("error processing flag `%.*s' (value '%.*s'): %s\n", key.len, key.s, + val.len, val.s, err); + else + LM_ERR("error processing flag `%.*s': %s\n", key.len, key.s, err); + return -1; +} + +static bencode_item_t *rtpe_function_call(bencode_buffer_t *bencbuf, struct sip_msg *msg, + enum rtpe_operation op, const char *flags_str, str *body_out) +{ + struct ng_flags_parse ng_flags; + bencode_item_t *item, *resp; + str callid, from_tag, to_tag, body, viabranch, error; + int ret; + struct rtpe_node *node; + char *cp; + + /*** get & init basic stuff needed ***/ + + memset(&ng_flags, 0, sizeof(ng_flags)); + + if (get_callid(msg, &callid) == -1 || callid.len == 0) { + LM_ERR("can't get Call-Id field\n"); + return NULL; + } + if (get_to_tag(msg, &to_tag) == -1) { + LM_ERR("can't get To tag\n"); + return NULL; + } + if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) { + LM_ERR("can't get From tag\n"); + return NULL; + } + if (bencode_buffer_init(bencbuf)) { + LM_ERR("could not initialize bencode_buffer_t\n"); + return NULL; + } + ng_flags.dict = bencode_dictionary(bencbuf); + + if (op == OP_OFFER || op == OP_ANSWER) { + ng_flags.flags = bencode_list(bencbuf); + ng_flags.direction = bencode_list(bencbuf); + ng_flags.replace = bencode_list(bencbuf); + ng_flags.rtcp_mux = bencode_list(bencbuf); + + if (extract_body(msg, &body) == -1) { + LM_ERR("can't extract body from the message\n"); + goto error; + } + bencode_dictionary_add_str(ng_flags.dict, "sdp", &body); + } + + /*** parse flags & build dictionary ***/ + + ng_flags.to = (op == OP_DELETE) ? 0 : 1; + + if (parse_flags(&ng_flags, msg, &op, flags_str)) + goto error; + + /* only add those if any flags were given at all */ + if (ng_flags.direction && ng_flags.direction->child) + bencode_dictionary_add(ng_flags.dict, "direction", ng_flags.direction); + if (ng_flags.flags && ng_flags.flags->child) + bencode_dictionary_add(ng_flags.dict, "flags", ng_flags.flags); + if (ng_flags.replace && ng_flags.replace->child) + bencode_dictionary_add(ng_flags.dict, "replace", ng_flags.replace); + if ((ng_flags.transport & 0x100)) + bencode_dictionary_add_string(ng_flags.dict, "transport-protocol", + transports[ng_flags.transport & 0x003]); + if (ng_flags.rtcp_mux && ng_flags.rtcp_mux->child) + bencode_dictionary_add(ng_flags.dict, "rtcp-mux", ng_flags.rtcp_mux); + + bencode_dictionary_add_str(ng_flags.dict, "call-id", &callid); + + if (ng_flags.via) { + if (ng_flags.via == 1 || ng_flags.via == 2) + ret = get_via_branch(msg, ng_flags.via, &viabranch); + else if (ng_flags.via == -1 && extra_id_pv) + ret = get_extra_id(msg, &viabranch); + else + ret = -1; + if (ret == -1 || viabranch.len == 0) { + LM_ERR("can't get Via branch/extra ID\n"); + goto error; + } + bencode_dictionary_add_str(ng_flags.dict, "via-branch", &viabranch); + } + + item = bencode_list(bencbuf); + bencode_dictionary_add(ng_flags.dict, "received-from", item); + bencode_list_add_string(item, (msg->rcv.src_ip.af == AF_INET) ? "IP4" : ( + (msg->rcv.src_ip.af == AF_INET6) ? "IP6" : + "?" + ) ); + bencode_list_add_string(item, ip_addr2a(&msg->rcv.src_ip)); + + if ((msg->first_line.type == SIP_REQUEST && op != OP_ANSWER) + || (msg->first_line.type == SIP_REPLY && op == OP_ANSWER)) + { + bencode_dictionary_add_str(ng_flags.dict, "from-tag", &from_tag); + if (ng_flags.to && to_tag.s && to_tag.len) + bencode_dictionary_add_str(ng_flags.dict, "to-tag", &to_tag); + } + else { + if (!to_tag.s || !to_tag.len) { + LM_ERR("No to-tag present\n"); + goto error; + } + bencode_dictionary_add_str(ng_flags.dict, "from-tag", &to_tag); + bencode_dictionary_add_str(ng_flags.dict, "to-tag", &from_tag); + } + + bencode_dictionary_add_string(ng_flags.dict, "command", command_strings[op]); + + /*** send it out ***/ + + if (bencbuf->error) { + LM_ERR("out of memory - bencode failed\n"); + goto error; + } + + if(msg->id != current_msg_id) + selected_rtpe_set = default_rtpe_set; + + do { + node = select_rtpe_node(callid, 1); + if (!node) { + LM_ERR("no available proxies\n"); + goto error; + } + + cp = send_rtpe_command(node, ng_flags.dict, &ret); + } while (cp == NULL); + LM_DBG("proxy reply: %.*s\n", ret, cp); + + /*** process reply ***/ + + resp = bencode_decode_expect(bencbuf, cp, ret, BENCODE_DICTIONARY); + if (!resp) { + LM_ERR("failed to decode bencoded reply from proxy: %.*s\n", ret, cp); + goto error; + } + if (!bencode_dictionary_get_strcmp(resp, "result", "error")) { + if (!bencode_dictionary_get_str(resp, "error-reason", &error)) + LM_ERR("proxy return error but didn't give an error reason: %.*s\n", ret, cp); + else + LM_ERR("proxy replied with error: %.*s\n", error.len, error.s); + goto error; + } + + if (body_out) + *body_out = body; + + return resp; + +error: + bencode_buffer_free(bencbuf); + return NULL; +} + +static int rtpe_function_call_simple(struct sip_msg *msg, enum rtpe_operation op, const char *flags_str) +{ + bencode_buffer_t bencbuf; + + if (!rtpe_function_call(&bencbuf, msg, op, flags_str, NULL)) + return -1; + + bencode_buffer_free(&bencbuf); + return 1; +} + +static bencode_item_t *rtpe_function_call_ok(bencode_buffer_t *bencbuf, struct sip_msg *msg, + enum rtpe_operation op, const char *flags_str, str *body) +{ + bencode_item_t *ret; + + ret = rtpe_function_call(bencbuf, msg, op, flags_str, body); + if (!ret) + return NULL; + + if (bencode_dictionary_get_strcmp(ret, "result", "ok")) { + LM_ERR("proxy didn't return \"ok\" result\n"); + bencode_buffer_free(bencbuf); + return NULL; + } + + return ret; +} + + + +static int +rtpe_test(struct rtpe_node *node, int isdisabled, int force) +{ + bencode_buffer_t bencbuf; + bencode_item_t *dict; + char *cp; + int ret; + + if(node->rn_recheck_ticks == MI_MAX_RECHECK_TICKS){ + LM_DBG("rtpe %s disabled for ever\n", node->rn_url.s); + return 1; + } + if (force == 0) { + if (isdisabled == 0) + return 0; + if (node->rn_recheck_ticks > get_ticks()) + return 1; + } + + if (bencode_buffer_init(&bencbuf)) { + LM_ERR("could not initialized bencode_buffer_t\n"); + return 1; + } + dict = bencode_dictionary(&bencbuf); + bencode_dictionary_add_string(dict, "command", "ping"); + if (bencbuf.error) + goto benc_error; + + cp = send_rtpe_command(node, dict, &ret); + if (!cp) { + LM_ERR("proxy did not respond to ping\n"); + goto error; + } + + dict = bencode_decode_expect(&bencbuf, cp, ret, BENCODE_DICTIONARY); + if (!dict || bencode_dictionary_get_strcmp(dict, "result", "pong")) { + LM_ERR("proxy responded with invalid response\n"); + goto error; + } + + LM_INFO("rtp proxy <%s> found, support for it %senabled\n", + node->rn_url.s, force == 0 ? "re-" : ""); + + bencode_buffer_free(&bencbuf); + return 0; + +benc_error: + LM_ERR("out of memory - bencode failed\n"); +error: + bencode_buffer_free(&bencbuf); + return 1; +} + +static char * +send_rtpe_command(struct rtpe_node *node, bencode_item_t *dict, int *outlen) +{ + struct sockaddr_un addr; + int fd, len, i, vcnt; + char *cp; + static char buf[0x10000]; + struct pollfd fds[1]; + struct iovec *v; + + v = bencode_iovec(dict, &vcnt, 1, 0); + if (!v) { + LM_ERR("error converting bencode to iovec\n"); + return NULL; + } + + len = 0; + cp = buf; + if (node->rn_umode == 0) { + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_LOCAL; + strncpy(addr.sun_path, node->rn_address, + sizeof(addr.sun_path) - 1); +#ifdef HAVE_SOCKADDR_SA_LEN + addr.sun_len = strlen(addr.sun_path); +#endif + + fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd < 0) { + LM_ERR("can't create socket\n"); + goto badproxy; + } + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(fd); + LM_ERR("can't connect to RTP proxy\n"); + goto badproxy; + } + + do { + len = writev(fd, v + 1, vcnt); + } while (len == -1 && errno == EINTR); + if (len <= 0) { + close(fd); + LM_ERR("can't send command to a RTP proxy\n"); + goto badproxy; + } + do { + len = read(fd, buf, sizeof(buf) - 1); + } while (len == -1 && errno == EINTR); + close(fd); + if (len <= 0) { + LM_ERR("can't read reply from a RTP proxy\n"); + goto badproxy; + } + } else { + fds[0].fd = rtpe_socks[node->idx]; + fds[0].events = POLLIN; + fds[0].revents = 0; + /* Drain input buffer */ + while ((poll(fds, 1, 0) == 1) && + ((fds[0].revents & POLLIN) != 0)) { + recv(rtpe_socks[node->idx], buf, sizeof(buf) - 1, 0); + fds[0].revents = 0; + } + v[0].iov_base = gencookie(); + v[0].iov_len = strlen(v[0].iov_base); + for (i = 0; i < rtpengine_retr; i++) { + do { + len = writev(rtpe_socks[node->idx], v, vcnt + 1); + } while (len == -1 && (errno == EINTR || errno == ENOBUFS)); + if (len <= 0) { + LM_ERR("can't send command to a RTP proxy\n"); + goto badproxy; + } + while ((poll(fds, 1, rtpengine_tout * 1000) == 1) && + (fds[0].revents & POLLIN) != 0) { + do { + len = recv(rtpe_socks[node->idx], buf, sizeof(buf)-1, 0); + } while (len == -1 && errno == EINTR); + if (len <= 0) { + LM_ERR("can't read reply from a RTP proxy\n"); + goto badproxy; + } + if (len >= (v[0].iov_len - 1) && + memcmp(buf, v[0].iov_base, (v[0].iov_len - 1)) == 0) { + len -= (v[0].iov_len - 1); + cp += (v[0].iov_len - 1); + if (len != 0) { + len--; + cp++; + } + goto out; + } + fds[0].revents = 0; + } + } + if (i == rtpengine_retr) { + LM_ERR("timeout waiting reply from a RTP proxy\n"); + goto badproxy; + } + } + +out: + cp[len] = '\0'; + *outlen = len; + return cp; +badproxy: + LM_ERR("proxy <%s> does not respond, disable it\n", node->rn_url.s); + node->rn_disabled = 1; + node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout; + + return NULL; +} + +/* + * select the set with the id_set id + */ + +static struct rtpe_set * select_rtpe_set(int id_set ){ + + struct rtpe_set * rtpe_list; + /*is it a valid set_id?*/ + + if(!rtpe_set_list || !rtpe_set_list->rset_first){ + LM_ERR("no rtp_proxy configured\n"); + return 0; + } + + for(rtpe_list=rtpe_set_list->rset_first; rtpe_list!=0 && + rtpe_list->id_set!=id_set; rtpe_list=rtpe_list->rset_next); + if(!rtpe_list){ + LM_ERR(" script error-invalid id_set to be selected\n"); + } + + return rtpe_list; +} +/* + * Main balancing routine. This does not try to keep the same proxy for + * the call if some proxies were disabled or enabled; proxy death considered + * too rare. Otherwise we should implement "mature" HA clustering, which is + * too expensive here. + */ +static struct rtpe_node * +select_rtpe_node(str callid, int do_test) +{ + unsigned sum, sumcut, weight_sum; + struct rtpe_node* node; + int was_forced; + + if(!selected_rtpe_set){ + LM_ERR("script error -no valid set selected\n"); + return NULL; + } + /* Most popular case: 1 proxy, nothing to calculate */ + if (selected_rtpe_set->rtpe_node_count == 1) { + node = selected_rtpe_set->rn_first; + if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) + node->rn_disabled = rtpe_test(node, 1, 0); + return node->rn_disabled ? NULL : node; + } + + /* XXX Use quick-and-dirty hashing algo */ + for(sum = 0; callid.len > 0; callid.len--) + sum += callid.s[callid.len - 1]; + sum &= 0xff; + + was_forced = 0; +retry: + weight_sum = 0; + for (node=selected_rtpe_set->rn_first; node!=NULL; node=node->rn_next) { + + if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()){ + /* Try to enable if it's time to try. */ + node->rn_disabled = rtpe_test(node, 1, 0); + } + if (!node->rn_disabled) + weight_sum += node->rn_weight; + } + if (weight_sum == 0) { + /* No proxies? Force all to be redetected, if not yet */ + if (was_forced) + return NULL; + was_forced = 1; + for(node=selected_rtpe_set->rn_first; node!=NULL; node=node->rn_next) { + node->rn_disabled = rtpe_test(node, 1, 1); + } + goto retry; + } + sumcut = sum % weight_sum; + /* + * sumcut here lays from 0 to weight_sum-1. + * Scan proxy list and decrease until appropriate proxy is found. + */ + for (node=selected_rtpe_set->rn_first; node!=NULL; node=node->rn_next) { + if (node->rn_disabled) + continue; + if (sumcut < node->rn_weight) + goto found; + sumcut -= node->rn_weight; + } + /* No node list */ + return NULL; +found: + if (do_test) { + node->rn_disabled = rtpe_test(node, node->rn_disabled, 0); + if (node->rn_disabled) + goto retry; + } + return node; +} + +static int +get_extra_id(struct sip_msg* msg, str *id_str) { + if(msg==NULL || extra_id_pv==NULL || id_str==NULL) { + LM_ERR("bad parameters\n"); + return -1; + } + if (pv_printf_s(msg, extra_id_pv, id_str)<0) { + LM_ERR("cannot print the additional id\n"); + return -1; + } + + return 1; + +} + +static int +set_rtpengine_set_from_avp(struct sip_msg *msg) +{ + struct usr_avp *avp; + int_str setid_val; + + if ((setid_avp_param == NULL) || + (avp = search_first_avp(setid_avp_type, setid_avp.n, &setid_val, 0)) + == NULL) + return 1; + + if (avp->flags&AVP_VAL_STR) { + LM_ERR("setid_avp must hold an integer value\n"); + return -1; + } + + selected_rtpe_set = select_rtpe_set(setid_val.n); + if(selected_rtpe_set == NULL) { + LM_ERR("could not locate rtpengine set %d\n", setid_val.n); + return -1; + } + + LM_DBG("using rtpengine set %d\n", setid_val.n); + + current_msg_id = msg->id; + + return 1; +} + +static int rtpengine_delete(struct sip_msg *msg, const char *flags) { + return rtpe_function_call_simple(msg, OP_DELETE, flags); +} + +static int +rtpengine_delete1_f(struct sip_msg* msg, char* str1, char* str2) +{ + str flags; + + if (set_rtpengine_set_from_avp(msg) == -1) + return -1; + + flags.s = NULL; + if (str1) + fixup_get_svalue(msg, (gparam_p)str1, &flags); + + return rtpengine_delete(msg, flags.s); +} + +/* This function assumes p points to a line of requested type. */ + +static int +set_rtpengine_set_f(struct sip_msg * msg, char * str1, char * str2) +{ + rtpe_set_link_t *rtpl; + pv_value_t val; + + rtpl = (rtpe_set_link_t*)str1; + + current_msg_id = 0; + selected_rtpe_set = 0; + + if(rtpl->rset != NULL) { + current_msg_id = msg->id; + selected_rtpe_set = rtpl->rset; + } else { + if(pv_get_spec_value(msg, &rtpl->rpv, &val)<0) { + LM_ERR("cannot evaluate pv param\n"); + return -1; + } + if(!(val.flags & PV_VAL_INT)) { + LM_ERR("pv param must hold an integer value\n"); + return -1; + } + selected_rtpe_set = select_rtpe_set(val.ri); + if(selected_rtpe_set==NULL) { + LM_ERR("could not locate rtpengine set %d\n", val.ri); + return -1; + } + current_msg_id = msg->id; + } + return 1; +} + +static int +rtpengine_manage(struct sip_msg *msg, const char *flags) +{ + int method; + int nosdp; + + if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) + || (msg->cseq==NULL))) + { + LM_ERR("no CSEQ header\n"); + return -1; + } + + method = get_cseq(msg)->method_id; + + if(!(method==METHOD_INVITE || method==METHOD_ACK || method==METHOD_CANCEL + || method==METHOD_BYE || method==METHOD_UPDATE)) + return -1; + + if(method==METHOD_CANCEL || method==METHOD_BYE) + return rtpengine_delete(msg, flags); + + if(msg_has_sdp(msg)) + nosdp = 0; + else + nosdp = parse_sdp(msg); + + if(msg->first_line.type == SIP_REQUEST) { + if(method==METHOD_ACK && nosdp==0) + return rtpengine_offer_answer(msg, flags, OP_ANSWER); + if(method==METHOD_UPDATE && nosdp==0) + return rtpengine_offer_answer(msg, flags, OP_OFFER); + if(method==METHOD_INVITE && nosdp==0) { + if(route_type==FAILURE_ROUTE) + return rtpengine_delete(msg, flags); + return rtpengine_offer_answer(msg, flags, OP_OFFER); + } + } else if(msg->first_line.type == SIP_REPLY) { + if(msg->first_line.u.reply.statuscode>=300) + return rtpengine_delete(msg, flags); + if(nosdp==0) { + if(method==METHOD_UPDATE) + return rtpengine_offer_answer(msg, flags, OP_ANSWER); + if(tmb.t_gett==NULL || tmb.t_gett()==NULL + || tmb.t_gett()==T_UNDEFINED) + return rtpengine_offer_answer(msg, flags, OP_ANSWER); + return rtpengine_offer_answer(msg, flags, OP_OFFER); + } + } + return -1; +} + +static int +rtpengine_manage1_f(struct sip_msg *msg, char *str1, char *str2) +{ + str flags; + + if (set_rtpengine_set_from_avp(msg) == -1) + return -1; + + flags.s = NULL; + if (str1) + fixup_get_svalue(msg, (gparam_p)str1, &flags); + + return rtpengine_manage(msg, flags.s); +} + +static int +rtpengine_offer1_f(struct sip_msg *msg, char *str1, char *str2) +{ + str flags; + + if (set_rtpengine_set_from_avp(msg) == -1) + return -1; + + flags.s = NULL; + if (str1) + fixup_get_svalue(msg, (gparam_p)str1, &flags); + return rtpengine_offer_answer(msg, flags.s, OP_OFFER); +} + +static int +rtpengine_answer1_f(struct sip_msg *msg, char *str1, char *str2) +{ + str flags; + + if (set_rtpengine_set_from_avp(msg) == -1) + return -1; + + if (msg->first_line.type == SIP_REQUEST) + if (msg->first_line.u.request.method_value != METHOD_ACK) + return -1; + + flags.s = NULL; + if (str1) + fixup_get_svalue(msg, (gparam_p)str1, &flags); + return rtpengine_offer_answer(msg, flags.s, OP_ANSWER); +} + +static int +rtpengine_offer_answer(struct sip_msg *msg, const char *flags, int op) +{ + bencode_buffer_t bencbuf; + bencode_item_t *dict; + str body, newbody; + struct lump *anchor; + + dict = rtpe_function_call_ok(&bencbuf, msg, op, flags, &body); + if (!dict) + return -1; + + if (!bencode_dictionary_get_str_dup(dict, "sdp", &newbody)) { + LM_ERR("failed to extract sdp body from proxy reply\n"); + goto error; + } + + anchor = del_lump(msg, body.s - msg->buf, body.len, 0); + if (!anchor) { + LM_ERR("del_lump failed\n"); + goto error_free; + } + if (!insert_new_lump_after(anchor, newbody.s, newbody.len, 0)) { + LM_ERR("insert_new_lump_after failed\n"); + goto error_free; + } + + bencode_buffer_free(&bencbuf); + return 1; + +error_free: + pkg_free(newbody.s); +error: + bencode_buffer_free(&bencbuf); + return -1; +} + + +static int +start_recording_f(struct sip_msg* msg, char *foo, char *bar) +{ + return rtpe_function_call_simple(msg, OP_START_RECORDING, NULL); +} + +/* + * Returns the current RTP-Statistics from the RTP-Proxy + */ +static int +pv_get_rtpstat_f(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res) +{ + bencode_buffer_t bencbuf; + bencode_item_t *dict, *tot, *in, *out; + static char buf[256]; + str ret; + + dict = rtpe_function_call_ok(&bencbuf, msg, OP_QUERY, NULL, NULL); + if (!dict) + return -1; + + tot = bencode_dictionary_get_expect(dict, "totals", BENCODE_DICTIONARY); + in = bencode_dictionary_get_expect(tot, "input", BENCODE_DICTIONARY); + in = bencode_dictionary_get_expect(in, "rtp", BENCODE_DICTIONARY); + out = bencode_dictionary_get_expect(tot, "output", BENCODE_DICTIONARY); + out = bencode_dictionary_get_expect(out, "rtp", BENCODE_DICTIONARY); + + if (!in || !out) + goto error; + + ret.s = buf; + ret.len = snprintf(buf, sizeof(buf), + "Input: %lli bytes, %lli packets, %lli errors; " + "Output: %lli bytes, %lli packets, %lli errors", + bencode_dictionary_get_integer(in, "bytes", -1), + bencode_dictionary_get_integer(in, "packets", -1), + bencode_dictionary_get_integer(in, "errors", -1), + bencode_dictionary_get_integer(out, "bytes", -1), + bencode_dictionary_get_integer(out, "packets", -1), + bencode_dictionary_get_integer(out, "errors", -1)); + + bencode_buffer_free(&bencbuf); + return pv_get_strval(msg, param, res, &ret); + +error: + bencode_buffer_free(&bencbuf); + return -1; +} + diff --git a/modules/rtpengine/rtpengine.h b/modules/rtpengine/rtpengine.h new file mode 100644 index 00000000000..24d124b0591 --- /dev/null +++ b/modules/rtpengine/rtpengine.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2003 Porta Software Ltd + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * --------- + * 2014-06-17 Imported from rtpproxy module +*/ + + +#ifndef _RTPENGINE_H +#define _RTPENGINE_H + +#include "bencode.h" +#include "../../str.h" + +struct rtpe_node { + unsigned int idx; /* overall index */ + str rn_url; /* unparsed, deletable */ + int rn_umode; + char *rn_address; /* substring of rn_url */ + int rn_disabled; /* found unaccessible? */ + unsigned rn_weight; /* for load balancing */ + unsigned int rn_recheck_ticks; + int rn_rep_supported; + int rn_ptl_supported; + struct rtpe_node *rn_next; +}; + + +struct rtpe_set{ + unsigned int id_set; + unsigned weight_sum; + unsigned int rtpe_node_count; + int set_disabled; + unsigned int set_recheck_ticks; + struct rtpe_node *rn_first; + struct rtpe_node *rn_last; + struct rtpe_set *rset_next; +}; + + +struct rtpe_set_head{ + struct rtpe_set *rset_first; + struct rtpe_set *rset_last; +}; + +#endif diff --git a/modules/rtpengine/rtpengine_funcs.c b/modules/rtpengine/rtpengine_funcs.c new file mode 100644 index 00000000000..83855524492 --- /dev/null +++ b/modules/rtpengine/rtpengine_funcs.c @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2001-2003 FhG Fokus + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-06-17 Imported from rtpproxy module + */ + +#include +#include +#include +#include +#include "rtpengine_funcs.h" +#include "../../dprint.h" +#include "../../config.h" +#include "../../ut.h" +#include "../../forward.h" +#include "../../resolve.h" +#include "../../globals.h" +#include "../../udp_server.h" +#include "../../pt.h" +#include "../../parser/msg_parser.h" +#include "../../trim.h" +#include "../../parser/parse_from.h" +#include "../../parser/contact/parse_contact.h" +#include "../../parser/parse_uri.h" +#include "../../parser/parse_content.h" +#include "../../parser/parser_f.h" +#include "../../parser/sdp/sdp_helpr_funcs.h" + +#define READ(val) \ + (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24)) +#define advance(_ptr,_n,_str,_error) \ + do{\ + if ((_ptr)+(_n)>(_str).s+(_str).len)\ + goto _error;\ + (_ptr) = (_ptr) + (_n);\ + }while(0); +#define one_of_16( _x , _t ) \ + (_x==_t[0]||_x==_t[15]||_x==_t[8]||_x==_t[2]||_x==_t[3]||_x==_t[4]\ + ||_x==_t[5]||_x==_t[6]||_x==_t[7]||_x==_t[1]||_x==_t[9]||_x==_t[10]\ + ||_x==_t[11]||_x==_t[12]||_x==_t[13]||_x==_t[14]) +#define one_of_8( _x , _t ) \ + (_x==_t[0]||_x==_t[7]||_x==_t[1]||_x==_t[2]||_x==_t[3]||_x==_t[4]\ + ||_x==_t[5]||_x==_t[6]) + + + +/** + * return: + * -1: error + * 1: text or sdp + * 2: multipart + */ +int check_content_type(struct sip_msg *msg) +{ + static unsigned int appl[16] = { + 0x6c707061/*appl*/,0x6c707041/*Appl*/,0x6c705061/*aPpl*/, + 0x6c705041/*APpl*/,0x6c507061/*apPl*/,0x6c507041/*ApPl*/, + 0x6c505061/*aPPl*/,0x6c505041/*APPl*/,0x4c707061/*appL*/, + 0x4c707041/*AppL*/,0x4c705061/*aPpL*/,0x4c705041/*APpL*/, + 0x4c507061/*apPL*/,0x4c507041/*ApPL*/,0x4c505061/*aPPL*/, + 0x4c505041/*APPL*/}; + static unsigned int icat[16] = { + 0x74616369/*icat*/,0x74616349/*Icat*/,0x74614369/*iCat*/, + 0x74614349/*ICat*/,0x74416369/*icAt*/,0x74416349/*IcAt*/, + 0x74414369/*iCAt*/,0x74414349/*ICAt*/,0x54616369/*icaT*/, + 0x54616349/*IcaT*/,0x54614369/*iCaT*/,0x54614349/*ICaT*/, + 0x54416369/*icAT*/,0x54416349/*IcAT*/,0x54414369/*iCAT*/, + 0x54414349/*ICAT*/}; + static unsigned int ion_[8] = { + 0x006e6f69/*ion_*/,0x006e6f49/*Ion_*/,0x006e4f69/*iOn_*/, + 0x006e4f49/*IOn_*/,0x004e6f69/*ioN_*/,0x004e6f49/*IoN_*/, + 0x004e4f69/*iON_*/,0x004e4f49/*ION_*/}; + static unsigned int sdp_[8] = { + 0x00706473/*sdp_*/,0x00706453/*Sdp_*/,0x00704473/*sDp_*/, + 0x00704453/*SDp_*/,0x00506473/*sdP_*/,0x00506453/*SdP_*/, + 0x00504473/*sDP_*/,0x00504453/*SDP_*/}; + str str_type; + unsigned int x; + char *p; + + if (!msg->content_type) + { + LM_WARN("the header Content-TYPE is absent!" + "let's assume the content is text/plain ;-)\n"); + return 1; + } + + trim_len(str_type.len,str_type.s,msg->content_type->body); + if (str_type.len>=15 && (*str_type.s=='m' || *str_type.s=='M') + && strncasecmp(str_type.s, "multipart/mixed", 15) == 0) { + return 2; + } + p = str_type.s; + advance(p,4,str_type,error_1); + x = READ(p-4); + if (!one_of_16(x,appl)) + goto other; + advance(p,4,str_type,error_1); + x = READ(p-4); + if (!one_of_16(x,icat)) + goto other; + advance(p,3,str_type,error_1); + x = READ(p-3) & 0x00ffffff; + if (!one_of_8(x,ion_)) + goto other; + + /* skip spaces and tabs if any */ + while (*p==' ' || *p=='\t') + advance(p,1,str_type,error_1); + if (*p!='/') + { + LM_ERR("no / found after primary type\n"); + goto error; + } + advance(p,1,str_type,error_1); + while ((*p==' ' || *p=='\t') && p+1 found valid\n", (int)(p-str_type.s), str_type.s); + return 1; + } else { + LM_ERR("bad end for type!\n"); + return -1; + } + +error_1: + LM_ERR("body ended :-(!\n"); +error: + return -1; +other: + LM_ERR("invalid type for a message\n"); + return -1; +} + + +/* + * Get message body and check Content-Type header field + */ +int extract_body(struct sip_msg *msg, str *body ) +{ + char c; + int ret; + str mpdel; + char *rest, *p1, *p2; + struct hdr_field hf; + unsigned int mime; + + if (get_body(msg,body)!=0 || body->len==0) { + LM_ERR("failed to get the message body\n"); + goto error; + } + + /* + * Better use the content-len value - no need of any explicit + * parcing as get_body() parsed all headers and Conten-Length + * body header is automaticaly parsed when found. + */ + if (msg->content_length==0) { + LM_ERR("failed to get the content length in message\n"); + goto error; + } + + body->len = get_content_length(msg); + if (body->len==0) { + LM_ERR("message body has length zero\n"); + goto error; + } + + if (body->len + body->s > msg->buf + msg->len) { + LM_ERR("content-length exceeds packet-length by %d\n", + (int)((body->len + body->s) - (msg->buf + msg->len))); + goto error; + } + + /* no need for parse_headers(msg, EOH), get_body will + * parse everything */ + /*is the content type correct?*/ + if((ret = check_content_type(msg))==-1) + { + LM_ERR("content type mismatching\n"); + goto error; + } + + if(ret!=2) + goto done; + + /* multipart body */ + if(get_mixed_part_delimiter(&msg->content_type->body,&mpdel) < 0) { + goto error; + } + p1 = find_sdp_line_delimiter(body->s, body->s+body->len, mpdel); + if (p1 == NULL) { + LM_ERR("empty multipart content\n"); + return -1; + } + p2=p1; + c = 0; + for(;;) + { + p1 = p2; + if (p1 == NULL || p1 >= body->s+body->len) + break; /* No parts left */ + p2 = find_next_sdp_line_delimiter(p1, body->s+body->len, + mpdel, body->s+body->len); + /* p2 is text limit for application parsing */ + rest = eat_line(p1 + mpdel.len + 2, p2 - p1 - mpdel.len - 2); + if ( rest > p2 ) { + LM_ERR("Unparsable <%.*s>\n", (int)(p1-p1), p1); + return -1; + } + while( rest>16) == TYPE_APPLICATION) + && ((mime&0x00ff) == SUBTYPE_SDP)) { + c = 1; + } + } + } /* end of while */ + if(c==1) + { + if (rest < p2 && *rest == '\r') rest++; + if (rest < p2 && *rest == '\n') rest++; + if (rest < p2 && p2[-1] == '\n') p2--; + if (rest < p2 && p2[-1] == '\r') p2--; + body->s = rest; + body->len = p2-rest; + goto done; + } + } + +error: + return -1; + +done: + /*LM_DBG("DEBUG:extract_body:=|%.*s|\n",body->len,body->s);*/ + return 1; +} + +/* + * ser_memmem() returns the location of the first occurrence of data + * pattern b2 of size len2 in memory block b1 of size len1 or + * NULL if none is found. Obtained from NetBSD. + */ +void * +ser_memmem(const void *b1, const void *b2, size_t len1, size_t len2) +{ + /* Initialize search pointer */ + char *sp = (char *) b1; + + /* Initialize pattern pointer */ + char *pp = (char *) b2; + + /* Initialize end of search address space pointer */ + char *eos = sp + len1 - len2; + + /* Sanity check */ + if(!(b1 && b2 && len1 && len2)) + return NULL; + + while (sp <= eos) { + if (*sp == *pp) + if (memcmp(sp, pp, len2) == 0) + return sp; + + sp++; + } + + return NULL; +} + +/* + * Some helper functions taken verbatim from tm module. + */ + +/* + * Extract Call-ID value + * assumes the callid header is already parsed + * (so make sure it is, before calling this function or + * it might fail even if the message _has_ a callid) + */ +int +get_callid(struct sip_msg* _m, str* _cid) +{ + + if ((parse_headers(_m, HDR_CALLID_F, 0) == -1)) { + LM_ERR("failed to parse call-id header\n"); + return -1; + } + + if (_m->callid == NULL) { + LM_ERR("call-id not found\n"); + return -1; + } + + _cid->s = _m->callid->body.s; + _cid->len = _m->callid->body.len; + trim(_cid); + return 0; +} + +/* + * Extract tag from To header field of a response + */ +int +get_to_tag(struct sip_msg* _m, str* _tag) +{ + + if (!_m->to && ((parse_headers(_m, HDR_TO_F, 0) == -1) || (!_m->to))) { + LM_ERR("To header field missing\n"); + return -1; + } + + if (get_to(_m)->tag_value.len) { + _tag->s = get_to(_m)->tag_value.s; + _tag->len = get_to(_m)->tag_value.len; + } else { + _tag->s = NULL; /* fixes gcc 4.0 warnings */ + _tag->len = 0; + } + + return 0; +} + +/* + * Extract tag from From header field of a request + */ +int +get_from_tag(struct sip_msg* _m, str* _tag) +{ + + if (parse_from_header(_m)<0) { + LM_ERR("failed to parse From header\n"); + return -1; + } + + if (get_from(_m)->tag_value.len) { + _tag->s = get_from(_m)->tag_value.s; + _tag->len = get_from(_m)->tag_value.len; + } else { + _tag->s = NULL; /* fixes gcc 4.0 warnings */ + _tag->len = 0; + } + + return 0; +} + +/* + * Extract URI from the Contact header field + */ +int +get_contact_uri(struct sip_msg* _m, struct sip_uri *uri, contact_t** _c) +{ + + if ((parse_headers(_m, HDR_CONTACT_F, 0) == -1) || !_m->contact) + return -1; + if (!_m->contact->parsed && parse_contact(_m->contact) < 0) { + LM_ERR("failed to parse Contact body\n"); + return -1; + } + *_c = ((contact_body_t*)_m->contact->parsed)->contacts; + if (*_c == NULL) + /* no contacts found */ + return -1; + + if (parse_uri((*_c)->uri.s, (*_c)->uri.len, uri) < 0 || uri->host.len <= 0) { + LM_ERR("failed to parse Contact URI [%.*s]\n", + (*_c)->uri.len, ((*_c)->uri.s)?(*_c)->uri.s:""); + return -1; + } + return 0; +} + +/* + * Extract branch from Via header + */ +int +get_via_branch(struct sip_msg* msg, int vianum, str* _branch) +{ + struct via_body *via; + struct via_param *p; + + if ((parse_headers(msg, (vianum == 1) ? HDR_VIA1_F : HDR_VIA2_F, 0) == -1) < 0) + return -1; + + via = (vianum == 1) ? msg->via1 : msg->via2; + for (p = via->param_lst; p; p = p->next) + { + if (p->name.len == strlen("branch") + && strncasecmp(p->name.s, "branch", strlen("branch")) == 0) { + _branch->s = p->value.s; + _branch->len = p->value.len; + return 0; + } + } + return -1; +} diff --git a/modules/rtpengine/rtpengine_funcs.h b/modules/rtpengine/rtpengine_funcs.h new file mode 100644 index 00000000000..1f07f2d56b2 --- /dev/null +++ b/modules/rtpengine/rtpengine_funcs.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2001-2003 FhG Fokus + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _RTPENGINE_FUNCS_H +#define _RTPENGINE_FUNCS_H + +#include "../../str.h" +#include "../../parser/msg_parser.h" +#include "../../parser/contact/contact.h" + +int extract_body(struct sip_msg * , str *); +int check_content_type(struct sip_msg * ); +void *ser_memmem(const void *, const void *, size_t, size_t); +int get_callid(struct sip_msg *, str *); +int get_to_tag(struct sip_msg *, str *); +int get_from_tag(struct sip_msg *, str *); +int get_contact_uri(struct sip_msg *, struct sip_uri *, contact_t **); +int get_via_branch(struct sip_msg *, int, str *); + +#endif diff --git a/modules/rtpproxy/README b/modules/rtpproxy/README index 80909b14c84..5528e84fdcc 100644 --- a/modules/rtpproxy/README +++ b/modules/rtpproxy/README @@ -16,8 +16,7 @@ Bogdan-Andrei Iancu Copyright © 2005 Voice Sistem SRL Revision History - Revision $Revision: 8740 $ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -49,18 +48,34 @@ Bogdan-Andrei Iancu 1.6. Exported Functions - 1.6.1. set_rtp_proxy_set() - 1.6.2. engage_rtp_proxy([flags [, ip_address]]) - 1.6.3. rtpproxy_offer([flags [, ip_address]]) - 1.6.4. rtpproxy_answer([flags [, ip_address]]) - 1.6.5. unforce_rtp_proxy() - 1.6.6. rtpproxy_stream2uac(prompt_name, count), - rtpproxy_stream2uas(prompt_name, count) + 1.6.1. engage_rtp_proxy([flags [, ip_address [, + set_id [, sock_pvar]]]]) - deprecated, + rtpproxy_engage([flags [, ip_address [, + set_id [, sock_pvar]]]]) - 1.6.7. rtpproxy_stop_stream2uac(), - rtpproxy_stop_stream2uas() + 1.6.2. rtpproxy_offer([flags [, ip_address [, set_id + [, sock_pvar]]]]) - 1.6.8. start_recording() + 1.6.3. rtpproxy_answer([flags [, ip_address [, + set_id [, sock_pvar]]]]) + + 1.6.4. unforce_rtp_proxy([set_id [, sock_pvar]]) - + deprecated, rtpproxy_unforce([set_id [, + sock_pvar]]) + + 1.6.5. rtpproxy_stream2uac(prompt_name, count [, + set_id [, sock_pvar]]), + rtpproxy_stream2uas(prompt_name, count [, + set_id [, sock_pvar]]) + + 1.6.6. rtpproxy_stop_stream2uac([set_id [, + sock_pvar]]), + rtpproxy_stop_stream2uas([set_id [, + sock_pvar]]) + + 1.6.7. start_recording([set_id [, sock_pvar]]) - + deprecated, rtpproxy_start_recording([set_id + [, sock_pvar]]) 1.7. MI Commands @@ -87,16 +102,15 @@ Bogdan-Andrei Iancu 1.9. Set rtpp_socket_col parameter 1.10. Set set_id parameter 1.11. Set rtpp_notify_socket parameter - 1.12. fix_nated_contact usage - 1.13. engage_rtp_proxy usage - 1.14. rtpproxy_offer usage - 1.15. rtpproxy_answer usage - 1.16. unforce_rtp_proxy usage - 1.17. rtpproxy_stream2xxx usage - 1.18. start_recording usage - 1.19. rtpproxy_enable usage - 1.20. rtpproxy_show usage - 1.21. rtpproxy_reload usage + 1.12. rtpproxy_engage usage + 1.13. rtpproxy_offer usage + 1.14. rtpproxy_answer usage + 1.15. rtpproxy_unforce usage + 1.16. rtpproxy_stream2xxx usage + 1.17. rtpproxy_start_recording usage + 1.18. rtpproxy_enable usage + 1.19. rtpproxy_show usage + 1.20. rtpproxy_reload usage Chapter 1. Admin Guide @@ -128,18 +142,16 @@ Chapter 1. Admin Guide rtpproxies (with a different weight value than 0) respond. Default weight is 1. - The selection of the set is done from script prior using - unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() - functions - see the set_rtp_proxy_set() function. + Starting with OpenSIPS 1.11, the set_rtp_proxy_set() function + has been removed. The set is now specified for each function. + If absend, the default set 0 is used. Also, engage_rtp_proxy(), + unforce_rtp_proxy() and start_recording() functions have been + deprecated and replaced by rtpproxy_engage(), + rtpproxy_unforce() and rtpproxy_start_recording() respectively. - For backward compatibility reasons, a set with no id take by - default the id 0. Also if no set is explicitly set before - unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() the - 0 id set will be used. - - IMPORTANT: if you use multiple sets, take care and use the same + IMPORTANT: if you use multiple sets, make sure you use the same set for both rtpproxy_offer()/rtpproxy_answer() and - unforce_rtpproxy()!! + rtpproxy_unforce()!! 1.3. RTPProxy timeout notifications @@ -170,7 +182,7 @@ Chapter 1. Admin Guide script. This is the socket where further notification will be received from rtpproxies. This socket must be a TCP or UNIX socket. Also, for all the calls that require notification, the - engage_rtp_proxy(), rtpproxy_offer() and rtpproxy_answer() + rtpproxy_engage(), rtpproxy_offer() and rtpproxy_answer() functions must be called with the “n” flag. Configure RTPProxy to use timeout notification by adding the @@ -209,7 +221,7 @@ Chapter 1. Admin Guide The following modules must be loaded before this module: * a database module - only if you want to load use a database table from where to load the rtp proxies sets. - * dialog module - if using the engage_rtp_proxy functions or + * dialog module - if using the rtpproxy_engage functions or RTPProxy timeout notifications. 1.4.2. External Libraries or Applications @@ -382,46 +394,41 @@ modparam("rtpproxy", "rtpp_notify_socket", "tcp:10.10.10.10:9999") 1.6. Exported Functions -1.6.1. set_rtp_proxy_set() - - Sets the Id of the rtpproxy set to be used for the next - unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() - command. - - Paramter can also be a pseudo-variable that contain (as string - or integer) the ID of the rtpproxy set to be used. - - This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, - BRANCH_ROUTE. - - Example 1.12. fix_nated_contact usage -... -set_rtp_proxy_set("2"); -rtpproxy_offer(); -... - -1.6.2. engage_rtp_proxy([flags [, ip_address]]) +1.6.1. engage_rtp_proxy([flags [, ip_address [, set_id [, +sock_pvar]]]]) - deprecated, rtpproxy_engage([flags [, ip_address [, +set_id [, sock_pvar]]]]) Rewrites SDP body to ensure that media is passed through an RTP proxy. It uses the dialog module facilities to keep track when the rtpproxy session must be updated. Function must only be called for the initial INVITE and internally takes care of - rewriting the body of 200 OKs and ACKs. + rewriting the body of 200 OKs and ACKs. Note that when used in + bridge mode, this function might advertise wrong interfaces in + SDP (due to the fact that OpenSIPS is not aware of the RTPProxy + configuration), so you might face an undefined behavior. Meaning of the parameters is as follows: - * flags - flags to turn on some features. + * flags(optional) - flags to turn on some features. + a - flags that UA from which message is received doesn't support symmetric RTP. + l - force “lookup”, that is, only rewrite SDP when corresponding session is already exists in the RTP proxy. By default is on when the session is to be completed (reply in non-swap or ACK in swap mode). - + i - flags that message is received from UA in the LAN - (internal network). Only makes sense when RTP proxy is - running in the bridge mode. - + e - flags that message is received from UA in the WAN - (external network). Only makes sense when RTP proxy is - running in the bridge mode. + + i/e - when RTPProxy is used in bridge mode, these + flags are used to indicate the direction of the media + flow for the current request/reply. 'i' refers to the + LAN (internal network) and corresponds to the first + interface of RTPProxy (as specified by the -l + parameter). 'e' refers to the WAN (external network) + and corresponds to the second interface of RTPProxy. + These flags should always be used together. For + example, an INVITE (offer) that comes from the + Internet (WAN) to goes to a local media server (LAN) + should use the 'ei' flags. The answer should use the + 'ie' flags. Depending on the scenario, the 'ii' and + 'ee' combination are also supported. Only makes sense + when RTPProxy is running in the bridge mode. + f - instructs rtpproxy to ignore marks inserted by another rtpproxy in transit to indicate that the session is already goes through another proxy. Allows @@ -452,33 +459,43 @@ rtpproxy_offer(); significantly reducing bandwith overhead for low bitrate codecs, for example with G.729 going from 10ms to 100ms saves two thirds of the network bandwith. - * ip_address - new SDP IP address. - - Both parmeters do accept variables in any combination. + * ip_address(optional) - new SDP IP address. + * set_id(optional) - the set used for this call. + * sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. Note that the variable will + only be populated in the initial request. This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.13. engage_rtp_proxy usage - ... - if (is_method("INVITE") && - has_totag()) {engage_rtp_proxy();}; - ... + Example 1.12. rtpproxy_engage usage +... +if (is_method("INVITE") && has_totag()) { + if ($var(setid) != 0) { + rtpproxy_engage(,,"$var(setid)", "$var(proxy)"); + xlog("SCRIPT: RTPProxy server used is $var(proxy)\n"); + } else { + rtpproxy_engage(); + xlog("SCRIPT: using default RTPProxy set\n"); + } +} +... -1.6.3. rtpproxy_offer([flags [, ip_address]]) +1.6.2. rtpproxy_offer([flags [, ip_address [, set_id [, +sock_pvar]]]]) Rewrites SDP body to ensure that media is passed through an RTP proxy. To be invoked on INVITE for the cases the SDPs are in INVITE and 200 OK and on 200 OK when SDPs are in 200 OK and ACK. - See engage_rtp_proxy() function description above for the + See rtpproxy_engage() function description above for the meaning of the parameters. This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.14. rtpproxy_offer usage + Example 1.13. rtpproxy_offer usage route { ... if (is_method("INVITE")) { @@ -510,36 +527,44 @@ onreply_route[2] ... } -1.6.4. rtpproxy_answer([flags [, ip_address]]) +1.6.3. rtpproxy_answer([flags [, ip_address [, set_id [, +sock_pvar]]]]) Rewrites SDP body to ensure that media is passed through an RTP proxy. To be invoked on 200 OK for the cases the SDPs are in INVITE and 200 OK and on ACK when SDPs are in 200 OK and ACK. - See engage_rtp_proxy() function description above for the + See rtpproxy_engage() function description above for the meaning of the parameters. This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.15. rtpproxy_answer usage + Example 1.14. rtpproxy_answer usage See rtpproxy_offer() function example above for example. -1.6.5. unforce_rtp_proxy() +1.6.4. unforce_rtp_proxy([set_id [, sock_pvar]]) - deprecated, +rtpproxy_unforce([set_id [, sock_pvar]]) Tears down the RTPProxy session for the current call. + Meaning of the parameters is as follows: + * set_id(optional) - the set used for this call. + * sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.16. unforce_rtp_proxy usage + Example 1.15. rtpproxy_unforce usage ... -unforce_rtp_proxy(); +rtpproxy_unforce(); ... -1.6.6. rtpproxy_stream2uac(prompt_name, count), -rtpproxy_stream2uas(prompt_name, count) +1.6.5. rtpproxy_stream2uac(prompt_name, count [, set_id [, +sock_pvar]]), rtpproxy_stream2uas(prompt_name, count [, set_id [, +sock_pvar]]) Instruct the RTPproxy to stream prompt/announcement pre-encoded with the makeann command from the RTPproxy distribution. The @@ -572,8 +597,11 @@ rtpproxy_stream2uas(prompt_name, count) value of -1 means that it will be streaming in loop indefinitely, until appropriate rtpproxy_stop_stream2xxx is issued. + * set_id(optional) - the set used for this call. + * sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. - Example 1.17. rtpproxy_stream2xxx usage + Example 1.16. rtpproxy_stream2xxx usage ... if (is_method("INVITE")) { rtpproxy_offer(); @@ -586,25 +614,37 @@ rtpproxy_stream2uas(prompt_name, count) }; ... -1.6.7. rtpproxy_stop_stream2uac(), rtpproxy_stop_stream2uas() +1.6.6. rtpproxy_stop_stream2uac([set_id [, sock_pvar]]), +rtpproxy_stop_stream2uas([set_id [, sock_pvar]]) Stop streaming of announcement/prompt/MOH started previously by the respective rtpproxy_stream2xxx. The uac/uas suffix selects whose announcement relatively to tha current transaction should be stopped - UAC or UAS. + Meaning of the parameters is as follows: + * set_id(optional) - the set used for this call. + * sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. + These functions can be used from REQUEST_ROUTE, ONREPLY_ROUTE. -1.6.8. start_recording() +1.6.7. start_recording([set_id [, sock_pvar]]) - deprecated, +rtpproxy_start_recording([set_id [, sock_pvar]]) This command will send a signal to the RTP-Proxy to record the RTP stream on the RTP-Proxy. + Meaning of the parameters is as follows: + * set_id(optional) - the set used for this call. + * sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. + This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE. - Example 1.18. start_recording usage + Example 1.17. rtpproxy_start_recording usage ... -start_recording(); +rtpproxy_start_recording(); ... 1.7. MI Commands @@ -617,14 +657,23 @@ start_recording(); The first parameter is the rtp proxy url (exactly as defined in the config file). - The second parameter value must be a number in decimal. + The next parameter (optional) is the rtpproxy set ID (used for + better indentification of the rtpproxy instance to be enabled, + for example when a rtpproxy is used in multiple sets). + + The last parameter must be a number in decimal representing the + new enabled/disabled state. NOTE: if a rtpproxy is defined multiple times (in the same or - diferente sete), all its instances will be enables/disabled. + diferente sete), all its instances will be enables/disabled IF + no set ID provided (as second param). - Example 1.19. rtpproxy_enable usage + Example 1.18. rtpproxy_enable usage ... +## disable a RTPProxy by URL only $ opensipsctl fifo rtpproxy_enable udp:192.168.2.133:8081 0 +## disable a RTPProxy by URL and set ID (3) +$ opensipsctl fifo rtpproxy_enable udp:192.168.2.133:8081 3 0 ... 1.7.2. rtpproxy_show @@ -634,7 +683,7 @@ $ opensipsctl fifo rtpproxy_enable udp:192.168.2.133:8081 0 No parameter. - Example 1.20. rtpproxy_show usage + Example 1.19. rtpproxy_show usage ... $ opensipsctl fifo rtpproxy_show ... @@ -648,7 +697,7 @@ $ opensipsctl fifo rtpproxy_show No parameter. - Example 1.21. rtpproxy_reload usage + Example 1.20. rtpproxy_reload usage ... $ opensipsctl fifo rtpproxy_reload ... @@ -703,4 +752,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/rtpproxy/doc/rtpproxy_admin.xml b/modules/rtpproxy/doc/rtpproxy_admin.xml index daf2c44cb91..f0811412bed 100644 --- a/modules/rtpproxy/doc/rtpproxy_admin.xml +++ b/modules/rtpproxy/doc/rtpproxy_admin.xml @@ -39,19 +39,16 @@ weight value than 0) respond. Default weight is 1. - The selection of the set is done from script prior using - unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() - functions - see the set_rtp_proxy_set() function. + Starting with &osips; 1.11, the set_rtp_proxy_set() function has + been removed. The set is now specified for each function. If + absend, the default set 0 is used. Also, engage_rtp_proxy(), + unforce_rtp_proxy() and start_recording() functions have been deprecated + and replaced by rtpproxy_engage(), rtpproxy_unforce() and + rtpproxy_start_recording() respectively. - For backward compatibility reasons, a set with no id take by default - the id 0. Also if no set is explicitly set before - unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() - the 0 id set will be used. - - - IMPORTANT: if you use multiple sets, take care and use the same set for - both rtpproxy_offer()/rtpproxy_answer() and unforce_rtpproxy()!! + IMPORTANT: if you use multiple sets, make sure you use the same set for + both rtpproxy_offer()/rtpproxy_answer() and rtpproxy_unforce()!!
@@ -84,7 +81,7 @@ module parameter in your configuration script. This is the socket where further notification will be received from rtpproxies. This socket must be a TCP or UNIX socket. Also, for all the calls that require notification, the - engage_rtp_proxy(), rtpproxy_offer() and rtpproxy_answer() functions must + rtpproxy_engage(), rtpproxy_offer() and rtpproxy_answer() functions must be called with the n flag.
@@ -167,7 +164,7 @@ - dialog module - if using the engage_rtp_proxy + dialog module - if using the rtpproxy_engage functions or RTPProxy timeout notifications. @@ -459,34 +456,8 @@ modparam("rtpproxy", "rtpp_notify_socket", "tcp:10.10.10.10:9999") Exported Functions
- <function moreinfo="none">set_rtp_proxy_set()</function> - - - Sets the Id of the rtpproxy set to be used for the next - unforce_rtp_proxy(), rtpproxy_offer() or rtpproxy_answer() - command. - - - Paramter can also be a pseudo-variable that contain (as string - or integer) the ID of the rtpproxy set to be used. - - - This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, - BRANCH_ROUTE. - - - <function>fix_nated_contact</function> usage - -... -set_rtp_proxy_set("2"); -rtpproxy_offer(); -... - - -
-
- - <function moreinfo="none">engage_rtp_proxy([flags [, ip_address]])</function> + <function moreinfo="none">engage_rtp_proxy([flags [, ip_address [, set_id [, sock_pvar]]]]) - deprecated</function>, + <function moreinfo="none">rtpproxy_engage([flags [, ip_address [, set_id [, sock_pvar]]]])</function> @@ -495,12 +466,15 @@ rtpproxy_offer(); when the rtpproxy session must be updated. Function must only be called for the initial INVITE and internally takes care of rewriting the body of 200 OKs and ACKs. + Note that when used in bridge mode, this function might advertise wrong + interfaces in &sdp; (due to the fact that &osips; is not aware of the RTPProxy + configuration), so you might face an undefined behavior. Meaning of the parameters is as follows: - flags - flags to turn on some features. + flags(optional) - flags to turn on some features. @@ -514,14 +488,18 @@ rtpproxy_offer(); completed (reply in non-swap or ACK in swap mode). - i - flags that message is received from - UA in the LAN (internal network). Only makes sense when - RTP proxy is running in the bridge mode. - - - e - flags that message is received from - UA in the WAN (external network). Only makes sense when RTP - proxy is running in the bridge mode. + i/e - when RTPProxy is used in bridge mode, + these flags are used to indicate the direction of the media flow + for the current request/reply. 'i' refers to the LAN (internal + network) and corresponds to the first interface of RTPProxy (as + specified by the -l parameter). 'e' refers to the WAN (external + network) and corresponds to the second interface of RTPProxy. + These flags should always be used together. For example, an + INVITE (offer) that comes from the Internet (WAN) to goes to a + local media server (LAN) should use the 'ei' flags. The answer + should use the 'ie' flags. Depending on the scenario, the 'ii' + and 'ee' combination are also supported. Only makes sense when + RTPProxy is running in the bridge mode. f - instructs rtpproxy to ignore marks @@ -568,29 +546,41 @@ rtpproxy_offer(); - ip_address - new SDP IP address. + ip_address(optional) - new SDP IP address. + + + set_id(optional) - the set used for this call. + + + sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. Note that the variable will only be populated in the + initial request. - Both parmeters do accept variables in any combination. - - This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - <function>engage_rtp_proxy</function> usage + <function>rtpproxy_engage</function> usage - ... - if (is_method("INVITE") && - has_totag()) {engage_rtp_proxy();}; - ... +... +if (is_method("INVITE") && has_totag()) { + if ($var(setid) != 0) { + rtpproxy_engage(,,"$var(setid)", "$var(proxy)"); + xlog("SCRIPT: RTPProxy server used is $var(proxy)\n"); + } else { + rtpproxy_engage(); + xlog("SCRIPT: using default RTPProxy set\n"); + } +} +...
- <function moreinfo="none">rtpproxy_offer([flags [, ip_address]])</function> + <function moreinfo="none">rtpproxy_offer([flags [, ip_address [, set_id [, sock_pvar]]]])</function> Rewrites &sdp; body to ensure that media is passed through @@ -599,7 +589,7 @@ rtpproxy_offer(); when SDPs are in 200 OK and ACK. - See engage_rtp_proxy() function description above for the meaning of the + See rtpproxy_engage() function description above for the meaning of the parameters. @@ -644,7 +634,7 @@ onreply_route[2]
- <function moreinfo="none">rtpproxy_answer([flags [, ip_address]])</function> + <function moreinfo="none">rtpproxy_answer([flags [, ip_address [, set_id [, sock_pvar]]]])</function> Rewrites &sdp; body to ensure that media is passed through @@ -653,7 +643,7 @@ onreply_route[2] when SDPs are in 200 OK and ACK. - See engage_rtp_proxy() function description above for the meaning of the + See rtpproxy_engage() function description above for the meaning of the parameters. @@ -669,27 +659,38 @@ onreply_route[2]
- <function moreinfo="none">unforce_rtp_proxy()</function> + <function moreinfo="none">unforce_rtp_proxy([set_id [, sock_pvar]]) - deprecated</function>, + <function moreinfo="none">rtpproxy_unforce([set_id [, sock_pvar]])</function> Tears down the RTPProxy session for the current call. + Meaning of the parameters is as follows: + + + set_id(optional) - the set used for this call. + + + sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - <function>unforce_rtp_proxy</function> usage + <function>rtpproxy_unforce</function> usage ... -unforce_rtp_proxy(); +rtpproxy_unforce(); ...
- <function>rtpproxy_stream2uac(prompt_name, count)</function>, - <function>rtpproxy_stream2uas(prompt_name, count)</function> + <function>rtpproxy_stream2uac(prompt_name, count [, set_id [, sock_pvar]])</function>, + <function>rtpproxy_stream2uas(prompt_name, count [, set_id [, sock_pvar]])</function> Instruct the RTPproxy to stream prompt/announcement pre-encoded with @@ -734,6 +735,13 @@ unforce_rtp_proxy(); rtpproxy_stop_stream2xxx is issued. + + set_id(optional) - the set used for this call. + + + sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. + <function>rtpproxy_stream2xxx</function> usage @@ -753,8 +761,8 @@ unforce_rtp_proxy();
- <function>rtpproxy_stop_stream2uac()</function>, - <function>rtpproxy_stop_stream2uas()</function> + <function>rtpproxy_stop_stream2uac([set_id [, sock_pvar]])</function>, + <function>rtpproxy_stop_stream2uas([set_id [, sock_pvar]])</function> Stop streaming of announcement/prompt/MOH started previously by the @@ -762,26 +770,47 @@ unforce_rtp_proxy(); suffix selects whose announcement relatively to tha current transaction should be stopped - UAC or UAS. + Meaning of the parameters is as follows: + + + set_id(optional) - the set used for this call. + + + sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. + + These functions can be used from REQUEST_ROUTE, ONREPLY_ROUTE.
- <function moreinfo="none">start_recording()</function> + <function moreinfo="none">start_recording([set_id [, sock_pvar]]) - deprecated</function>, + <function moreinfo="none">rtpproxy_start_recording([set_id [, sock_pvar]])</function> This command will send a signal to the RTP-Proxy to record the RTP stream on the RTP-Proxy. + Meaning of the parameters is as follows: + + + set_id(optional) - the set used for this call. + + + sock_pvar(optional) - pvar used to store the RTPProxy + socket chosen for this call. + + This function can be used from REQUEST_ROUTE and ONREPLY_ROUTE. - <function>start_recording</function> usage + <function>rtpproxy_start_recording</function> usage ... -start_recording(); +rtpproxy_start_recording(); ... @@ -803,18 +832,28 @@ start_recording(); the config file). - The second parameter value must be a number in decimal. + The next parameter (optional) is the rtpproxy set ID (used for better + indentification of the rtpproxy instance to be enabled, for example + when a rtpproxy is used in multiple sets). + + + The last parameter must be a number in decimal representing the new + enabled/disabled state. NOTE: if a rtpproxy is defined multiple times (in the same or - diferente sete), all its instances will be enables/disabled. + diferente sete), all its instances will be enables/disabled IF + no set ID provided (as second param). <function moreinfo="none">rtpproxy_enable</function> usage ... +## disable a RTPProxy by URL only $ opensipsctl fifo rtpproxy_enable udp:192.168.2.133:8081 0 +## disable a RTPProxy by URL and set ID (3) +$ opensipsctl fifo rtpproxy_enable udp:192.168.2.133:8081 3 0 ... diff --git a/modules/rtpproxy/nhelpr_funcs.c b/modules/rtpproxy/nhelpr_funcs.c index b6bd8cc3ea0..09fe11b4cfe 100644 --- a/modules/rtpproxy/nhelpr_funcs.c +++ b/modules/rtpproxy/nhelpr_funcs.c @@ -15,15 +15,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-11-06 body len is computed using the message len (it's * not taken any more from the msg. content-length) (andrei) - * 2008-08-30 body len is taken from Conent-length header as it is more + * 2008-08-30 body len is taken from Conent-length header as it is more * reliable (UDP packages may contain garbage at the end)(bogdan) */ @@ -157,13 +157,13 @@ int extract_body(struct sip_msg *msg, str *body ) { char c; int skip; - + if ( get_body(msg,body)!=0 || body->len==0) { LM_ERR("failed to get the message body\n"); goto error; } - - /* no need for parse_headers(msg, EOH), get_body will + + /* no need for parse_headers(msg, EOH), get_body will * parse everything */ /*is the content type correct?*/ if (check_content_type(msg)==-1) diff --git a/modules/rtpproxy/nhelpr_funcs.h b/modules/rtpproxy/nhelpr_funcs.h index 455f5b10156..bcb2660d468 100644 --- a/modules/rtpproxy/nhelpr_funcs.h +++ b/modules/rtpproxy/nhelpr_funcs.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/rtpproxy/rtpproxy.c b/modules/rtpproxy/rtpproxy.c index 76f467e3902..d14a387e79f 100644 --- a/modules/rtpproxy/rtpproxy.c +++ b/modules/rtpproxy/rtpproxy.c @@ -132,9 +132,9 @@ * (ancuta) * 2007-04-26 Added some MI commands: * nh_enable_rtpp used to enable or disable a specific rtp proxy - * nh_show_rtpp used to display information for all rtp proxies + * nh_show_rtpp used to display information for all rtp proxies * (ancuta) - * 2007-05-09 New function start_recording() allowing to start recording RTP + * 2007-05-09 New function start_recording() allowing to start recording RTP * session in the RTP proxy (Carsten Bock - ported from SER) * - obsolete by rtpproxy_offer/rtpproxy_answer * (osas) @@ -173,7 +173,6 @@ #include "../../parser/msg_parser.h" #include "../../parser/parse_multipart.h" #include "../../msg_callbacks.h" -#include "../../rw_locking.h" #include "../../evi/evi_modules.h" #include "../dialog/dlg_load.h" @@ -207,8 +206,10 @@ #define MI_RTP_PROXY_NOT_FOUND_LEN (sizeof(MI_RTP_PROXY_NOT_FOUND)-1) #define MI_PING_DISABLED "NATping disabled from script" #define MI_PING_DISABLED_LEN (sizeof(MI_PING_DISABLED)-1) -#define MI_SET "set" +#define MI_SET "Set" #define MI_SET_LEN (sizeof(MI_SET)-1) +#define MI_NODE "node" +#define MI_NODE_LEN (sizeof(MI_NODE)-1) #define MI_INDEX "index" #define MI_INDEX_LEN (sizeof(MI_INDEX)-1) #define MI_DISABLED "disabled" @@ -239,6 +240,9 @@ pv_spec_t param1_spec; static str param2_name = str_init("rtpproxy_2"); str param2_bavp_name = str_init("$bavp(5589966)"); pv_spec_t param2_spec; +static str param3_name = str_init("rtpproxy_3"); +str param3_bavp_name = str_init("$bavp(5589967)"); +pv_spec_t param3_spec; static str late_name = str_init("late_negociation"); /* parameters name for event signaling */ @@ -253,23 +257,28 @@ static int alter_mediaip(struct sip_msg *, str *, str *, int, str *, int, int); static char *gencookie(); static int rtpp_test(struct rtpp_node*, int, int); static int unforce_rtp_proxy_f(struct sip_msg *, char *, char *); -static int engage_rtp_proxy0_f(struct sip_msg *, char *, char *); -static int engage_rtp_proxy1_f(struct sip_msg *, char *, char *); -static int engage_rtp_proxy2_f(struct sip_msg *, char *, char *); +static int engage_rtp_proxy4_f(struct sip_msg *, char *, char *, char *, char *); static int fixup_engage(void **param,int param_no); -static int force_rtp_proxy(struct sip_msg *, char *, char *, int); +static int force_rtp_proxy(struct sip_msg *, char *, char *, char *, char *, int); static int start_recording_f(struct sip_msg *, char *, char *); -static int rtpproxy_answer2_f(struct sip_msg *, char *, char *); -static int rtpproxy_offer2_f(struct sip_msg *, char *, char *); +static int rtpproxy_answer4_f(struct sip_msg *, char *, char *, char *, char *); +static int rtpproxy_offer4_f(struct sip_msg *, char *, char *, char *, char *); static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, char * rtpproxy); -static int fixup_set_id(void ** param, int param_no); -static int set_rtp_proxy_set_f(struct sip_msg * msg, char * str1, char * str2); +static int fixup_set_id(void ** param); +static int fixup_stream(void ** param, int param_no); +static int fixup_offer_answer(void ** param, int param_no); +static int fixup_two_options(void ** param, int param_no); +static int fixup_unforce_warn(void ** param, int param_no); +static int fixup_engage_warn(void ** param, int param_no); +static int fixup_recording_warn(void ** param, int param_no); static struct rtpp_set * select_rtpp_set(int id_set); static int rtpproxy_set_store(modparam_t type, void * val); static int rtpproxy_add_rtpproxy_set( char * rtp_proxies, int set_id); static int _add_proxies_from_database(); +static int unforce_rtpproxy(struct sip_msg* msg, str callid, + str from_tag, str to_tag, char *pset, char *var); static int mod_init(void); static int child_init(int); @@ -286,6 +295,7 @@ static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree, static struct mi_root* mi_reload_rtpproxies(struct mi_root* cmd_tree, void* param); +void free_rtpp_nodes(struct rtpp_set *); void free_rtpp_sets(); int msg_has_sdp(struct sip_msg *msg); @@ -328,13 +338,11 @@ str rtpp_notify_socket = {0, 0}; int rtpp_notify_socket_un = 0; /* used in rtpproxy_set_store() */ -static int rtpp_sets=0; +static int rtpp_sets=0; static char **rtpp_strings=0; static int rtpp_set_count = 0; -static unsigned int current_msg_id = (unsigned int)-1; /* RTP proxy balancing list */ struct rtpp_set_head ** rtpp_set_list =0; -struct rtpp_set * selected_rtpp_set =0; struct rtpp_set ** default_rtpp_set=0; /* array with the sockets used by rtpporxy (per process)*/ @@ -354,74 +362,158 @@ static db_func_t db_functions; static event_id_t ei_id = EVI_ERROR; -static rw_lock_t *nh_lock=NULL; +rw_lock_t *nh_lock=NULL; static cmd_export_t cmds[] = { - {"set_rtp_proxy_set", (cmd_function)set_rtp_proxy_set_f, 1, - fixup_set_id, 0, - REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"unforce_rtp_proxy", (cmd_function)unforce_rtp_proxy_f, 0, + fixup_unforce_warn, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"unforce_rtp_proxy", (cmd_function)unforce_rtp_proxy_f, 1, + fixup_unforce_warn, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"unforce_rtp_proxy", (cmd_function)unforce_rtp_proxy_f, 2, + fixup_unforce_warn, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"engage_rtp_proxy", (cmd_function)engage_rtp_proxy4_f, 0, + fixup_engage_warn, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"engage_rtp_proxy", (cmd_function)engage_rtp_proxy4_f, 1, + fixup_engage_warn, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"engage_rtp_proxy", (cmd_function)engage_rtp_proxy4_f, 2, + fixup_engage_warn, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"engage_rtp_proxy", (cmd_function)engage_rtp_proxy4_f, 3, + fixup_engage_warn, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"engage_rtp_proxy", (cmd_function)engage_rtp_proxy4_f, 4, + fixup_engage_warn, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"start_recording", (cmd_function)start_recording_f, 0, + fixup_recording_warn, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"start_recording", (cmd_function)start_recording_f, 1, + fixup_recording_warn, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"start_recording", (cmd_function)start_recording_f, 2, + fixup_recording_warn, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"rtpproxy_unforce", (cmd_function)unforce_rtp_proxy_f, 0, 0, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"engage_rtp_proxy", (cmd_function)engage_rtp_proxy0_f, 0, + {"rtpproxy_unforce", (cmd_function)unforce_rtp_proxy_f, 1, + fixup_two_options, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"rtpproxy_unforce", (cmd_function)unforce_rtp_proxy_f, 2, + fixup_two_options, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"rtpproxy_engage", (cmd_function)engage_rtp_proxy4_f, 0, fixup_engage, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"engage_rtp_proxy", (cmd_function)engage_rtp_proxy1_f, 1, + {"rtpproxy_engage", (cmd_function)engage_rtp_proxy4_f, 1, fixup_engage, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"engage_rtp_proxy", (cmd_function)engage_rtp_proxy2_f, 2, + {"rtpproxy_engage", (cmd_function)engage_rtp_proxy4_f, 2, fixup_engage, 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"start_recording", (cmd_function)start_recording_f, 0, + {"rtpproxy_engage", (cmd_function)engage_rtp_proxy4_f, 3, + fixup_engage, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"rtpproxy_engage", (cmd_function)engage_rtp_proxy4_f, 4, + fixup_engage, 0, + REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"rtpproxy_start_recording", (cmd_function)start_recording_f, 0, 0, 0, - REQUEST_ROUTE | ONREPLY_ROUTE }, - {"rtpproxy_offer", (cmd_function)rtpproxy_offer2_f, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"rtpproxy_start_recording", (cmd_function)start_recording_f, 1, + fixup_two_options, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"rtpproxy_start_recording", (cmd_function)start_recording_f, 2, + fixup_two_options, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"rtpproxy_offer", (cmd_function)rtpproxy_offer4_f, 0, 0, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"rtpproxy_offer", (cmd_function)rtpproxy_offer2_f, 1, + {"rtpproxy_offer", (cmd_function)rtpproxy_offer4_f, 1, fixup_spve_null, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"rtpproxy_offer", (cmd_function)rtpproxy_offer2_f, 2, + {"rtpproxy_offer", (cmd_function)rtpproxy_offer4_f, 2, fixup_spve_spve, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"rtpproxy_answer", (cmd_function)rtpproxy_answer2_f, 0, + {"rtpproxy_offer", (cmd_function)rtpproxy_offer4_f, 3, + fixup_offer_answer, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"rtpproxy_offer", (cmd_function)rtpproxy_offer4_f, 4, + fixup_offer_answer, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"rtpproxy_answer", (cmd_function)rtpproxy_answer4_f, 0, 0, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"rtpproxy_answer", (cmd_function)rtpproxy_answer2_f, 1, + {"rtpproxy_answer", (cmd_function)rtpproxy_answer4_f, 1, fixup_spve_null, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"rtpproxy_answer", (cmd_function)rtpproxy_answer2_f, 2, + {"rtpproxy_answer", (cmd_function)rtpproxy_answer4_f, 2, fixup_spve_spve, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"rtpproxy_stream2uac",(cmd_function)rtpproxy_stream2uac2_f, 2, - fixup_var_str_int, 0, + {"rtpproxy_answer", (cmd_function)rtpproxy_answer4_f, 3, + fixup_offer_answer, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"rtpproxy_answer", (cmd_function)rtpproxy_answer4_f, 4, + fixup_offer_answer, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"rtpproxy_stream2uac",(cmd_function)rtpproxy_stream2uac4_f, 2, + fixup_stream, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, - {"rtpproxy_stream2uas",(cmd_function)rtpproxy_stream2uas2_f, 2, - fixup_var_str_int, 0, + {"rtpproxy_stream2uac",(cmd_function)rtpproxy_stream2uac4_f, 3, + fixup_stream, 0, + REQUEST_ROUTE | ONREPLY_ROUTE }, + {"rtpproxy_stream2uac",(cmd_function)rtpproxy_stream2uac4_f, 4, + fixup_stream, 0, + REQUEST_ROUTE | ONREPLY_ROUTE }, + {"rtpproxy_stream2uas",(cmd_function)rtpproxy_stream2uas4_f, 2, + fixup_stream, 0, + REQUEST_ROUTE | ONREPLY_ROUTE }, + {"rtpproxy_stream2uas",(cmd_function)rtpproxy_stream2uas4_f, 3, + fixup_stream, 0, + REQUEST_ROUTE | ONREPLY_ROUTE }, + {"rtpproxy_stream2uas",(cmd_function)rtpproxy_stream2uas4_f, 4, + fixup_stream, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, {"rtpproxy_stop_stream2uac",(cmd_function)rtpproxy_stop_stream2uac2_f,0, NULL, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, + {"rtpproxy_stop_stream2uac",(cmd_function)rtpproxy_stop_stream2uac2_f,1, + fixup_two_options, 0, + REQUEST_ROUTE | ONREPLY_ROUTE }, + {"rtpproxy_stop_stream2uac",(cmd_function)rtpproxy_stop_stream2uac2_f,2, + fixup_two_options, 0, + REQUEST_ROUTE | ONREPLY_ROUTE }, {"rtpproxy_stop_stream2uas",(cmd_function)rtpproxy_stop_stream2uas2_f,0, NULL, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, + {"rtpproxy_stop_stream2uas",(cmd_function)rtpproxy_stop_stream2uas2_f,1, + fixup_two_options, 0, + REQUEST_ROUTE | ONREPLY_ROUTE }, + {"rtpproxy_stop_stream2uas",(cmd_function)rtpproxy_stop_stream2uas2_f,2, + fixup_two_options, 0, + REQUEST_ROUTE | ONREPLY_ROUTE }, {0, 0, 0, 0, 0, 0} }; static param_export_t params[] = { - {"nortpproxy_str", STR_PARAM, &nortpproxy_str.s }, + {"nortpproxy_str", STR_PARAM, &nortpproxy_str.s }, {"rtpproxy_sock", STR_PARAM|USE_FUNC_PARAM, - (void*)rtpproxy_set_store }, - {"rtpproxy_disable_tout", INT_PARAM, &rtpproxy_disable_tout }, - {"rtpproxy_retr", INT_PARAM, &rtpproxy_retr }, - {"rtpproxy_tout", INT_PARAM, &rtpproxy_tout }, - {"rtpproxy_timeout", STR_PARAM, &rtpproxy_timeout }, - {"rtpproxy_autobridge", INT_PARAM, &rtpproxy_autobridge }, - {"db_url", STR_PARAM, &db_url.s }, - {"db_table", STR_PARAM, &table.s }, - {"rtpp_socket_col", STR_PARAM, &rtpp_sock_col.s }, - {"set_id_col", STR_PARAM, &set_id_col.s }, - {"rtpp_notify_socket", STR_PARAM, &rtpp_notify_socket.s }, + (void*)rtpproxy_set_store }, + {"rtpproxy_disable_tout", INT_PARAM, &rtpproxy_disable_tout }, + {"rtpproxy_retr", INT_PARAM, &rtpproxy_retr }, + {"rtpproxy_tout", INT_PARAM, &rtpproxy_tout }, + {"rtpproxy_timeout", STR_PARAM, &rtpproxy_timeout }, + {"rtpproxy_autobridge", INT_PARAM, &rtpproxy_autobridge }, + {"db_url", STR_PARAM, &db_url.s }, + {"db_table", STR_PARAM, &table.s }, + {"rtpp_socket_col", STR_PARAM, &rtpp_sock_col.s }, + {"set_id_col", STR_PARAM, &set_id_col.s }, + {"rtpp_notify_socket", STR_PARAM, &rtpp_notify_socket.s }, {0, 0, 0} }; @@ -438,11 +530,24 @@ static proc_export_t procs[] = { {0,0,0,0,0,0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "dialog", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_url", get_deps_sqldb_url }, + { NULL, NULL }, + }, +}; struct module_exports exports = { "rtpproxy", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, params, 0, /* exported statistics */ @@ -474,14 +579,14 @@ static int rtpproxy_set_store(modparam_t type, void * val){ return -1; } } else {/*realloc to make room for the current set*/ - rtpp_strings = (char**)pkg_realloc(rtpp_strings, + rtpp_strings = (char**)pkg_realloc(rtpp_strings, (rtpp_sets+1)* sizeof(char*)); if(!rtpp_strings){ LM_ERR("no pkg memory left\n"); return -1; } } - + /*allocate for the current set of urls*/ len = strlen(p); rtpp_strings[rtpp_sets] = (char*)pkg_malloc((len+1)*sizeof(char)); @@ -490,7 +595,7 @@ static int rtpproxy_set_store(modparam_t type, void * val){ LM_ERR("no pkg memory left\n"); return -1; } - + memcpy(rtpp_strings[rtpp_sets], p, len); rtpp_strings[rtpp_sets][len] = '\0'; rtpp_sets++; @@ -499,7 +604,7 @@ static int rtpproxy_set_store(modparam_t type, void * val){ } -static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, +static int add_rtpproxy_socks(struct rtpp_set * rtpp_list, char * rtpproxy){ /* Make rtp proxies list. */ char *p, *p1, *p2, *plim; @@ -606,17 +711,17 @@ static int rtpproxy_add_rtpproxy_set( char * rtp_proxies, int set_id) LM_ERR("script error -invalid rtp proxy list!\n"); return -1; } - + *rtp_proxies = '\0'; p2 = rtp_proxies-1; for(;isspace(*p2); *p2 = '\0',p2--); id_set.s = p; id_set.len = p2 - p+1; - + if(id_set.len <= 0 ||str2int(&id_set, &my_current_id)<0 ){ LM_ERR("script error -invalid set_id value!\n"); return -1; } - + rtp_proxies+=2; }else{ rtp_proxies = p; @@ -627,6 +732,7 @@ static int rtpproxy_add_rtpproxy_set( char * rtp_proxies, int set_id) rtp_proxies = p; my_current_id = set_id; } + LM_DBG("Adding proxy in setid %d [%s]\n", my_current_id, rtp_proxies); for(;*rtp_proxies && isspace(*rtp_proxies);rtp_proxies++); @@ -639,6 +745,7 @@ static int rtpproxy_add_rtpproxy_set( char * rtp_proxies, int set_id) rtpp_list = (*rtpp_set_list) ? (*rtpp_set_list)->rset_first : 0; while( rtpp_list != 0 && rtpp_list->id_set!=my_current_id) rtpp_list = rtpp_list->rset_next; + LM_DBG("List %sfound (%p) for id %d", rtpp_list ? "" : "not ", rtpp_list, my_current_id); if(rtpp_list==NULL){ /*if a new id_set : add a new set of rtpp*/ rtpp_list = shm_malloc(sizeof(struct rtpp_set)); @@ -685,8 +792,56 @@ static int rtpproxy_add_rtpproxy_set( char * rtp_proxies, int set_id) return -1; } +static void fixup_deprecated_warn(char *oldf, char *newf) +{ + LM_WARN("function %s() is now deprecated - use %s() instead\n", oldf, newf); +} + +static int fixup_unforce_warn(void ** param, int param_no) +{ + static int warned = 0; + if (!warned) { + fixup_deprecated_warn("unforce_rtp_proxy", "rtpproxy_unforce"); + warned = 1; + } + return param_no > 0 ? fixup_two_options(param, param_no) : 0; +} + +static int fixup_recording_warn(void ** param, int param_no) +{ + static int warned = 0; + if (!warned) { + fixup_deprecated_warn("start_recording", "rtpproxy_start_recording"); + warned = 1; + } + return param_no > 0 ? fixup_two_options(param, param_no) : 0; +} + +static int fixup_two_options(void ** param, int param_no) +{ + if (param_no == 1) + return fixup_set_id(param); + if (param_no == 2) + return fixup_pvar(param); + LM_ERR("Too many parameters %d\n", param_no); + return E_CFG; +} -static int fixup_set_id(void ** param, int param_no) +static int fixup_offer_answer(void ** param, int param_no) +{ + if (param_no < 1) + return 0; + if (param_no < 3) + return fixup_spve(param); + if (param_no == 3) + return fixup_set_id(param); + if (param_no == 4) + return fixup_pvar(param); + LM_ERR("Too many parameters %d\n", param_no); + return E_CFG; +} + +static int fixup_set_id(void ** param) { int int_val, err; struct rtpp_set* rtpp_list; @@ -700,12 +855,6 @@ static int fixup_set_id(void ** param, int param_no) } memset(pset, 0, sizeof(nh_set_param_t)); - if (param_no > 1) { - LM_ERR("set_rtp_proxy_set() takes only one parameter.\n"); - pkg_free(pset); - return E_CFG; - } - p = (char*) *param; if(*p != '$') { @@ -715,11 +864,14 @@ static int fixup_set_id(void ** param, int param_no) pkg_free(*param); rtpp_list = select_rtpp_set(int_val); if(rtpp_list ==0){ - LM_ERR("rtpp_proxy set %i not configured\n", int_val); - return E_CFG; + /* simply mark it as undefined and we search it one more time + * at runtime, after the database has been updated */ + pset->t = NH_VAL_SET_UNDEF; + pset->v.int_set = int_val; + } else { + pset->t = NH_VAL_SET_FIXED ; + pset->v.fixed_set = rtpp_list; } - pset->t = NH_VAL_SET_FIXED ; - pset->v.fixed_set = rtpp_list; *param = (void *) pset; return 0; } else { @@ -730,7 +882,7 @@ static int fixup_set_id(void ** param, int param_no) } else { /* proxyset is specified as an AVP */ str lstr; - + lstr.s = p; lstr.len = strlen(p); if ( pv_parse_spec( &lstr, &pset->v.var_set) == NULL ) { @@ -745,23 +897,68 @@ static int fixup_set_id(void ** param, int param_no) } } +static int fixup_stream(void **param, int param_no) +{ + int ret; + pv_elem_t *model; + str s; + + if (param_no == 1) { + model = NULL; + s.s = (char *)(*param); + s.len = strlen(s.s); + if (pv_parse_format(&s, &model) < 0) { + LM_ERR("wrong format[%s]!\n", (char *)(*param)); + return E_UNSPEC; + } + if (model == NULL) { + LM_ERR("empty parameter!\n"); + return E_UNSPEC; + } + *param = (void *)model; + } else if (param_no == 2) { + s.s = (char *)(*param); + s.len = strlen(s.s); + if (str2sint(&s, &ret) < 0) { + LM_ERR("bad number <%s>\n", (char *)(*param)); + return E_CFG; + } + pkg_free(*param); + *param = (void *)(long)ret; + } else if (param_no == 3) { + return fixup_set_id(param); + } else if (param_no == 4) { + return fixup_pvar(param); + } + return 0; +} +static int fixup_engage_warn(void ** param, int param_no) +{ + static int warned = 0; + if (!warned) { + fixup_deprecated_warn("engage_rtp_proxy", "rtpproxy_engage"); + warned = 1; + } + return param_no > 0 ? fixup_engage(param, param_no) : 0; +} static int fixup_engage(void** param, int param_no) { - if (!dlg_api.create_dlg) { + if (param_no < 2 && !dlg_api.create_dlg) { LM_ERR("Dialog module not loaded. Can't use engage_rtp_proxy function\n"); return -1; } - return 0; + return fixup_offer_answer(param, param_no); } -static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, +static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, void* param ) { struct mi_node* node; str rtpp_url; unsigned int enable; + unsigned int set_id; struct rtpp_set * rtpp_list; struct rtpp_node * crt_rtpp; int found; @@ -775,11 +972,13 @@ static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + /* RTPP URL node */ if(node->value.s == NULL || node->value.len ==0) return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); rtpp_url = node->value; + /* enable/disable node */ node = node->next; if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); @@ -788,19 +987,36 @@ static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, if( strno2int( &node->value, &enable) <0) goto error; - for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; + /* set id ?? */ + node = node->next; + if(node != NULL) { + /* shift params -> move enable over set id */ + set_id = enable; + /* read again the disable */ + enable = 0; + if( strno2int( &node->value, &enable) <0) + goto error; + } else { + set_id = (unsigned int)(-1); + } + + for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; rtpp_list = rtpp_list->rset_next){ + /* if set_id given, check only the list with the matching set_id */ + if ( (set_id!=(unsigned int)(-1)) && set_id!=rtpp_list->id_set ) + continue; + for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL; crt_rtpp = crt_rtpp->rn_next){ /*found a matching rtpp*/ - + if(crt_rtpp->rn_url.len == rtpp_url.len){ - + if(strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0){ /*set the enabled/disabled status*/ found = 1; - crt_rtpp->rn_recheck_ticks = + crt_rtpp->rn_recheck_ticks = enable? MI_MIN_RECHECK_TICKS : MI_MAX_RECHECK_TICKS; crt_rtpp->rn_disabled = enable?0:1; raise_rtpproxy_event(crt_rtpp, crt_rtpp->rn_disabled); @@ -818,7 +1034,7 @@ static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, } -#define add_rtpp_node_int_info(_parent, _name, _name_len, _value, _child,\ +#define add_rtpp_node_int_info(_parent, _name, _name_len, _value, _attr,\ _len, _string, _error)\ do {\ (_string) = int2str((_value), &(_len));\ @@ -826,13 +1042,14 @@ static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, LM_ERR("cannot convert int value\n");\ goto _error;\ }\ - if(((_child) = add_mi_node_child((_parent), MI_DUP_VALUE, (_name), \ + if(((_attr) = add_mi_attr((_parent), MI_DUP_VALUE, (_name), \ (_name_len), (_string), (_len)) ) == 0)\ goto _error;\ }while(0); static struct mi_root* mi_reload_rtpproxies(struct mi_root* cmd_tree, void* param) { + struct rtpp_set *it; if(db_url.s == NULL) { LM_ERR("Dynamic loading of rtpproxies not enabled\n"); return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); @@ -840,7 +1057,8 @@ static struct mi_root* mi_reload_rtpproxies(struct mi_root* cmd_tree, void* para lock_start_write( nh_lock ); if(*rtpp_set_list) { - free_rtpp_sets(); + for (it = (*rtpp_set_list)->rset_first; it; it = it->rset_next) + free_rtpp_nodes(it); } *rtpp_no = 0; (*list_version)++; @@ -859,13 +1077,13 @@ static struct mi_root* mi_reload_rtpproxies(struct mi_root* cmd_tree, void* para if (rtpp_notify_h) lock_release( rtpp_notify_h->lock ); - + if (update_rtpp_proxies()) goto error; /* update pointer to default_rtpp_set*/ *default_rtpp_set = select_rtpp_set(DEFAULT_RTPP_SET_ID); - + /* release the readers */ lock_stop_write( nh_lock ); @@ -875,10 +1093,10 @@ static struct mi_root* mi_reload_rtpproxies(struct mi_root* cmd_tree, void* para return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN); } -static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree, +static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree, void* param) { - struct mi_node* node, *crt_node, *child; + struct mi_node* node, *crt_node, *set_node; struct mi_root* root; struct mi_attr * attr; struct rtpp_set * rtpp_list; @@ -898,41 +1116,43 @@ static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree, return root; node = &root->node; + node->flags |= MI_IS_ARRAY; - for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; + for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; rtpp_list = rtpp_list->rset_next){ + id = int2str(rtpp_list->id_set, &id_len); + if(!id){ + LM_ERR("cannot convert set id\n"); + goto error; + } + + if(!(set_node = add_mi_node_child(node, MI_IS_ARRAY|MI_DUP_VALUE, MI_SET, MI_SET_LEN, + id, id_len))) { + LM_ERR("cannot add the set node to the tree\n"); + goto error; + } + for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL; crt_rtpp = crt_rtpp->rn_next){ - id = int2str(rtpp_list->id_set, &id_len); - if(!id){ - LM_ERR("cannot convert set id\n"); - goto error; - } - - if(!(crt_node = add_mi_node_child(node, 0, crt_rtpp->rn_url.s, - crt_rtpp->rn_url.len, 0,0)) ) { + if(!(crt_node = add_mi_node_child(set_node, MI_DUP_VALUE, + MI_NODE, MI_NODE_LEN, + crt_rtpp->rn_url.s, crt_rtpp->rn_url.len)) ) { LM_ERR("cannot add the child node to the tree\n"); goto error; } LM_DBG("adding node name %s \n",crt_rtpp->rn_url.s ); - if((attr = add_mi_attr(crt_node, MI_DUP_VALUE, MI_SET, MI_SET_LEN, - id, id_len))== 0){ - LM_ERR("cannot add attributes to the node\n"); - goto error; - } - add_rtpp_node_int_info(crt_node, MI_INDEX, MI_INDEX_LEN, - crt_rtpp->idx, child, len,string,error); + crt_rtpp->idx, attr, len,string,error); add_rtpp_node_int_info(crt_node, MI_DISABLED, MI_DISABLED_LEN, - crt_rtpp->rn_disabled, child, len,string,error); + crt_rtpp->rn_disabled, attr, len,string,error); add_rtpp_node_int_info(crt_node, MI_WEIGHT, MI_WEIGHT_LEN, - crt_rtpp->rn_weight, child, len, string,error); + crt_rtpp->rn_weight, attr, len, string,error); add_rtpp_node_int_info(crt_node, MI_RECHECK_TICKS,MI_RECHECK_T_LEN, - crt_rtpp->rn_recheck_ticks, child, len, string, error); + crt_rtpp->rn_recheck_ticks, attr, len, string, error); } } @@ -957,7 +1177,7 @@ inline static int parse_bavp(str *s, pv_spec_t *bavp) return -1; } return 0; - + } static int @@ -967,7 +1187,8 @@ mod_init(void) float timeout; if (rtpproxy_autobridge != 0) { - LM_WARN("Auto bridging does not properly function when doing serial/parallel forking\n"); + LM_WARN("Auto bridging does not properly function when doing " + "serial/parallel forking\n"); } if (nortpproxy_str.s==NULL || nortpproxy_str.s[0]==0) { @@ -987,7 +1208,7 @@ mod_init(void) *rtpp_no = 0; *list_version = 0; my_version = 0; - + if(!rtpp_no || !list_version) { LM_ERR("No more shared memory\n"); return -1; @@ -1029,7 +1250,7 @@ mod_init(void) if(db_bind_mod(&db_url, &db_functions) == -1) { LM_ERR("Failed bind to database\n"); return -1; - } + } if (!DB_CAPABILITY(db_functions, DB_CAP_ALL)) { @@ -1054,7 +1275,7 @@ mod_init(void) if(_add_proxies_from_database() != 0) { return -1; } - + db_functions.close(db_connection); db_connection = NULL; if ((nh_lock = lock_init_rw()) == NULL) { @@ -1062,7 +1283,7 @@ mod_init(void) return -1; } } - + default_rtpp_set = (struct rtpp_set**)shm_malloc(sizeof(struct rtpp_set*)); if(default_rtpp_set == NULL) { @@ -1098,13 +1319,14 @@ mod_init(void) LM_DBG("dialog module not loaded.\n"); memset(&tm_api, 0, sizeof(struct tm_binds)); if (load_tm_api(&tm_api)!=0) - LM_DBG("can't load TM API - check if tm module was loaded\n"); + LM_DBG("TM modules was not found\n"); if (parse_bavp(¶m1_bavp_name, ¶m1_spec) < 0 || - parse_bavp(¶m2_bavp_name, ¶m2_spec) < 0) - LM_DBG("cannot parse bavp's\n"); + parse_bavp(¶m2_bavp_name, ¶m2_spec) < 0 || + parse_bavp(¶m3_bavp_name, ¶m3_spec) < 0) + LM_DBG("cannot parse bavps\n"); - if(rtpp_notify_socket.s) { + if(rtpp_notify_socket.s) { if (strncmp("tcp:", rtpp_notify_socket.s, 4) == 0) { rtpp_notify_socket.s += 4; } else { @@ -1112,13 +1334,13 @@ mod_init(void) rtpp_notify_socket.s += 5; rtpp_notify_socket_un = 1; } - /* check if the notify socket parameter is set */ - rtpp_notify_socket.len = strlen(rtpp_notify_socket.s); - if(dlg_api.get_dlg == 0) { - LM_ERR("You need to load dialog module if you want to use the" - " timeout notification feature\n"); - return -1; - } + /* check if the notify socket parameter is set */ + rtpp_notify_socket.len = strlen(rtpp_notify_socket.s); + if(dlg_api.get_dlg == 0) { + LM_ERR("You need to load dialog module if you want to use the" + " timeout notification feature\n"); + return -1; + } rtpp_notify_h = (struct rtpp_notify_head *) shm_malloc(sizeof(struct rtpp_notify_head)); @@ -1142,13 +1364,11 @@ mod_init(void) LM_ERR("cannot find any valid rtpproxy to use\n"); return -1; } - } - else - { - exports.procs = 0; - } + } else { + exports.procs = 0; + } - ei_id = evi_publish_event(event_name); + ei_id = evi_publish_event(event_name); if (ei_id == EVI_ERROR) LM_ERR("cannot register event\n"); @@ -1165,7 +1385,7 @@ static int mi_child_init(void) if(!db_url.s) return 0; - + if (db_functions.init==0) { LM_CRIT("database not bound\n"); @@ -1177,7 +1397,7 @@ static int mi_child_init(void) LM_ERR("Failed to connect to database"); return -1; } - + LM_DBG("Database connection opened successfully\n"); return 0; @@ -1226,7 +1446,7 @@ static int _add_proxies_from_database(void) { } for(rowCount=0; rowCount < RES_ROW_N(result); rowCount++) { - + row= &result->rows[rowCount]; row_vals = ROW_VALUES(row); @@ -1246,7 +1466,7 @@ static int _add_proxies_from_database(void) { } db_functions.free_result(db_connection, result); - + return 0; error: @@ -1354,6 +1574,7 @@ int connect_rtpproxies(void) } } + LM_DBG("successfully updated proxy sets\n"); return 0; } @@ -1370,28 +1591,33 @@ int update_rtpp_proxies(void) { return connect_rtpproxies(); } - -void free_rtpp_sets(void) -{ - struct rtpp_set * crt_list, * last_list; +void free_rtpp_nodes(struct rtpp_set *list) +{ struct rtpp_node * crt_rtpp, *last_rtpp; - for(crt_list = (*rtpp_set_list)->rset_first; crt_list != NULL; ){ + for(crt_rtpp = list->rn_first; crt_rtpp != NULL; ){ - for(crt_rtpp = crt_list->rn_first; crt_rtpp != NULL; ){ + if(crt_rtpp->rn_url.s) + shm_free(crt_rtpp->rn_url.s); - if(crt_rtpp->rn_url.s) - shm_free(crt_rtpp->rn_url.s); + last_rtpp = crt_rtpp; + crt_rtpp = last_rtpp->rn_next; + shm_free(last_rtpp); + } + list->rn_first = NULL; + list->rtpp_node_count = 0; +} - last_rtpp = crt_rtpp; - crt_rtpp = last_rtpp->rn_next; - shm_free(last_rtpp); - } +void free_rtpp_sets(void) +{ + struct rtpp_set * crt_list, * last_list; + + for(crt_list = (*rtpp_set_list)->rset_first; crt_list != NULL; ){ + free_rtpp_nodes(crt_list); last_list = crt_list; crt_list = last_list->rset_next; shm_free(last_list); - last_list = NULL; } (*rtpp_set_list)->rset_first = NULL; (*rtpp_set_list)->rset_last = NULL; @@ -1458,7 +1684,7 @@ isnulladdr(str *sx, int pf) #define AOLDMEDPRT_LEN (sizeof(AOLDMEDPRT) - 1) -static inline int +static inline int replace_sdp_ip(struct sip_msg* msg, str *org_body, char *line, str *ip) { str body1, oldip, newip; @@ -1595,7 +1821,7 @@ extract_mediainfo(str *body, str *mediaport, str *payload_types) static int alter_rtcp(struct sip_msg *msg,str * body1, str *newip, int newpf ,str* newport, char * line_start ) -{ +{ static const str field = str_init("a=rtcp:"); @@ -1604,7 +1830,7 @@ static int alter_rtcp(struct sip_msg *msg,str * body1, str *newip, int newpf ,st int offset; struct lump* anchor; str body, value; - + body.s = line_start; body.len = body1->s + body1->len - line_start; @@ -1678,7 +1904,7 @@ alter_mediaip(struct sip_msg *msg, str *body, str *oldip, int oldpf, return 0; if (preserve != 0) { - anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0, 0); + anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0); if (anchor == NULL) { LM_ERR("anchor_lump failed\n"); return -1; @@ -1778,7 +2004,7 @@ alter_mediaport(struct sip_msg *msg, str *body, str *oldport, str *newport, #endif if (preserve != 0) { - anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0, 0); + anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0); if (anchor == NULL) { LM_ERR("anchor_lump failed\n"); return -1; @@ -1992,7 +2218,7 @@ send_rtpp_command(struct rtpp_node *node, struct iovec *v, int vcnt) v[i].iov_base = buf; /* finally solve the problem */ vcnt = IOV_MAX; - + } #endif @@ -2099,17 +2325,18 @@ send_rtpp_command(struct rtpp_node *node, struct iovec *v, int vcnt) * select the set with the id_set id */ -static struct rtpp_set * select_rtpp_set(int id_set ){ +static struct rtpp_set * select_rtpp_set(int id_set){ struct rtpp_set * rtpp_list; /*is it a valid set_id?*/ - + LM_DBG("Looking for set_id %d\n", id_set); + if(!(*rtpp_set_list) || !(*rtpp_set_list)->rset_first){ LM_ERR("no rtp_proxy configured\n"); return 0; } - for(rtpp_list=(*rtpp_set_list)->rset_first; rtpp_list!=0 && + for(rtpp_list=(*rtpp_set_list)->rset_first; rtpp_list!=0 && rtpp_list->id_set!=id_set; rtpp_list=rtpp_list->rset_next); if(!rtpp_list){ LM_ERR(" script error-invalid id_set to be selected\n"); @@ -2124,28 +2351,34 @@ static struct rtpp_set * select_rtpp_set(int id_set ){ * too expensive here. */ struct rtpp_node * -select_rtpp_node(str callid, int do_test) +select_rtpp_node(struct sip_msg * msg, + str callid, struct rtpp_set *set, pv_spec_p spec, int do_test) { unsigned sum, weight_sum; struct rtpp_node* node; int was_forced, sumcut, found, constant_weight_sum; + pv_value_t val; /* check last list version */ if (my_version != *list_version && update_rtpp_proxies() < 0) { LM_ERR("cannot update rtpp proxies list\n"); return 0; } - - if(!selected_rtpp_set){ - LM_ERR("script error -no valid set selected\n"); - return NULL; + + if (!set) { + LM_ERR("no set specified\n"); + return 0; } + /* Most popular case: 1 proxy, nothing to calculate */ - if (selected_rtpp_set->rtpp_node_count == 1) { - node = selected_rtpp_set->rn_first; + if (set->rtpp_node_count == 1) { + node = set->rn_first; if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) node->rn_disabled = rtpp_test(node, 1, 0); - return node->rn_disabled ? NULL : node; + if (node->rn_disabled) + return NULL; + + goto done; } /* XXX Use quick-and-dirty hashing algo */ @@ -2158,7 +2391,7 @@ select_rtpp_node(str callid, int do_test) weight_sum = 0; constant_weight_sum = 0; found = 0; - for (node=selected_rtpp_set->rn_first; node!=NULL; node=node->rn_next) { + for (node=set->rn_first; node!=NULL; node=node->rn_next) { if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()){ /* Try to enable if it's time to try. */ @@ -2175,7 +2408,7 @@ select_rtpp_node(str callid, int do_test) if (was_forced) return NULL; was_forced = 1; - for(node=selected_rtpp_set->rn_first; node!=NULL; node=node->rn_next) { + for(node=set->rn_first; node!=NULL; node=node->rn_next) { node->rn_disabled = rtpp_test(node, 1, 1); } goto retry; @@ -2186,14 +2419,14 @@ select_rtpp_node(str callid, int do_test) * Scan proxy list and decrease until appropriate proxy is found. */ was_forced = 0; - for (node=selected_rtpp_set->rn_first; node!=NULL;) { + for (node=set->rn_first; node!=NULL;) { if (sumcut < (int)node->rn_weight) { if (!node->rn_disabled) goto found; if (was_forced == 0) { /* appropriate proxy is disabled : redistribute on enabled ones */ sumcut = weight_sum ? sum % weight_sum : -1; - node = selected_rtpp_set->rn_first; + node = set->rn_first; was_forced = 1; continue; } @@ -2209,16 +2442,23 @@ select_rtpp_node(str callid, int do_test) if (node->rn_disabled) goto retry; } +done: + /* Store rtpproxy used */ + if (spec) { + memset(&val, 0, sizeof(pv_value_t)); + val.flags = PV_VAL_STR; + val.rs = node->rn_url; + if(pv_set_value(msg, spec, (int)EQ_T, &val)<0) + LM_ERR("setting PV failed\n"); + } + return node; } static int -unforce_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2) +unforce_rtp_proxy_f(struct sip_msg* msg, char* pset, char *var) { str callid, from_tag, to_tag; - struct rtpp_node *node; - struct iovec v[1 + 4 + 3] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}}; - /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 1 */ if (!msg || msg == FAKED_REPLY) return 1; @@ -2236,6 +2476,17 @@ unforce_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2) LM_ERR("can't get From tag\n"); return -1; } + + return unforce_rtpproxy(msg, callid, from_tag, to_tag, pset, var); +} + +static int unforce_rtpproxy(struct sip_msg* msg, str callid, + str from_tag, str to_tag, char *pset, char *var) +{ + struct rtpp_node *node; + struct rtpp_set *set; + struct iovec v[1 + 4 + 3] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}}; + /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 1 */ STR2IOVEC(callid, v[3]); STR2IOVEC(from_tag, v[5]); STR2IOVEC(to_tag, v[7]); @@ -2244,11 +2495,13 @@ unforce_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2) lock_start_read( nh_lock ); } - if(msg->id != current_msg_id){ - selected_rtpp_set = *default_rtpp_set; + set = get_rtpp_set(msg, (nh_set_param_t *)pset); + if (!set) { + LM_ERR("could not find rtpproxy set\n"); + goto error; } - - node = select_rtpp_node(callid, 1); + + node = select_rtpp_node(msg, callid, set, (pv_spec_p)var, 1); if (!node) { LM_ERR("no available proxies\n"); goto error; @@ -2274,54 +2527,55 @@ unforce_rtp_proxy_f(struct sip_msg* msg, char* str1, char* str2) -static int -set_rtp_proxy_set_f(struct sip_msg * msg, char * str1, char * str2) +struct rtpp_set * get_rtpp_set(struct sip_msg * msg, nh_set_param_t *pset) { - nh_set_param_t * pset; pv_value_t value; int int_val; int err; - struct rtpp_set * rtpp_list; + struct rtpp_set *set; - current_msg_id = msg->id; - pset = (nh_set_param_t *) str1; + if (!pset) + return *default_rtpp_set; - if (pset->t == NH_VAL_SET_FIXED) { - selected_rtpp_set = pset->v.fixed_set; - return 1; - } + if (pset->t == NH_VAL_SET_FIXED) + return pset->v.fixed_set; - if ( pv_get_spec_value(msg,&pset->v.var_set,&value)!=0 || - value.flags & PV_VAL_NULL || value.flags&PV_VAL_EMPTY ) { - LM_ERR("no PV or NULL value specified for proxy set " - "(error in scripts)\n"); - return -1; - } + if (pset->t == NH_VAL_SET_SPEC) { - if ( value.flags & PV_VAL_STR ) { - int_val = str2s(value.rs.s, value.rs.len, &err); - if (err != 0) { - LM_ERR("Invalid value %s specified in PV as RTP proxy set.\n", - value.rs.s ); - return -1; + if ( pv_get_spec_value(msg,&pset->v.var_set,&value)!=0 || + value.flags & PV_VAL_NULL || value.flags&PV_VAL_EMPTY ) { + LM_ERR("no PV or NULL value specified for proxy set " + "(error in scripts)\n"); + return NULL; } - } else if ( value.flags & PV_VAL_INT ) { - int_val = value.ri; - } else { - LM_ERR("Unsupported PV value type for RTP ptoxy set.i\n"); - return -1; - } - - LM_DBG("Variable proxy set %d specified.\n", int_val); - rtpp_list = select_rtpp_set(int_val); + if ( value.flags & PV_VAL_STR ) { + int_val = str2s(value.rs.s, value.rs.len, &err); + if (err != 0) { + LM_ERR("Invalid value %s specified in PV as RTP proxy set.\n", + value.rs.s ); + return NULL; + } + } else if ( value.flags & PV_VAL_INT ) { + int_val = value.ri; + } else { + LM_ERR("Unsupported PV value type for RTP ptoxy set.i\n"); + return NULL; + } + LM_DBG("Variable proxy set %d specified.\n", int_val); - if (rtpp_list != NULL) { - selected_rtpp_set = rtpp_list; - return 1; + return select_rtpp_set(int_val); } else { - LM_ERR("RTP Proxy set ID %d is not configured.\n", int_val); - return -2; + int_val = pset->v.int_set; + LM_DBG("Checking proxy set %d\n", int_val); + + set = select_rtpp_set(int_val); + if (set) { + LM_DBG("Updating proxy set %d\n", int_val); + pset->v.fixed_set = set; + pset->t = NH_VAL_SET_FIXED; + } + return set; } } @@ -2362,10 +2616,9 @@ static int rtpp_get_var_svalue(struct sip_msg *msg, gparam_p gp, str *val, int n } static int -rtpproxy_offer2_f(struct sip_msg *msg, char *param1, char *param2) +rtpproxy_offer4_f(struct sip_msg *msg, char *param1, char *param2, char *param3, char *param4) { - str flag_str; - str ip_str; + str aux_str; if(rtpp_notify_socket.s) { @@ -2379,42 +2632,51 @@ rtpproxy_offer2_f(struct sip_msg *msg, char *param1, char *param2) dlg_api.create_dlg(msg,0); } - if (rtpp_get_var_svalue(msg, (gparam_p)param1, &flag_str, 0)<0) { - LM_ERR("bogus flags parameter\n"); - return -1; + if (param1) { + if (rtpp_get_var_svalue(msg, (gparam_p)param1, &aux_str, 0)<0) { + LM_ERR("bogus flags parameter\n"); + return -1; + } + param1 = aux_str.s; } - if (param2!=NULL) { - if (rtpp_get_var_svalue(msg, (gparam_p)param2, &ip_str,1)<0) { + + if (param2) { + if (rtpp_get_var_svalue(msg, (gparam_p)param2, &aux_str, 1)<0) { LM_ERR("bogus IP addr parameter\n"); return -1; } - return force_rtp_proxy(msg, flag_str.s, ip_str.s, 1); + param2 = aux_str.s; } - return force_rtp_proxy(msg, flag_str.s, NULL, 1); + + return force_rtp_proxy(msg, param1, param2, param3, param4, 1); } static int -rtpproxy_answer2_f(struct sip_msg *msg, char *param1, char *param2) +rtpproxy_answer4_f(struct sip_msg *msg, char *param1, char *param2, char *param3, char *param4) { - str flag_str; - str ip_str; + str aux_str; if (msg->first_line.type == SIP_REQUEST) if (msg->first_line.u.request.method_value != METHOD_ACK) return -1; - if (rtpp_get_var_svalue(msg, (gparam_p)param1, &flag_str, 0)<0) { - LM_ERR("bogus flags parameter\n"); - return -1; + if (param1) { + if (rtpp_get_var_svalue(msg, (gparam_p)param1, &aux_str, 0)<0) { + LM_ERR("bogus flags parameter\n"); + return -1; + } + param1 = aux_str.s; } - if (param2!=NULL) { - if (rtpp_get_var_svalue(msg, (gparam_p)param2, &ip_str,1)<0) { + + if (param2) { + if (rtpp_get_var_svalue(msg, (gparam_p)param2, &aux_str, 1)<0) { LM_ERR("bogus IP addr parameter\n"); return -1; } - return force_rtp_proxy(msg, flag_str.s, ip_str.s, 0); + param2 = aux_str.s; } - return force_rtp_proxy(msg, flag_str.s, param2, 0); + + return force_rtp_proxy(msg, param1, param2, param3, param4, 0); } static void engage_callback(struct dlg_cell *dlg, int type, @@ -2430,11 +2692,24 @@ static void engage_callback(struct dlg_cell *dlg, int type, static void engage_close_callback(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { + str value; + static nh_set_param_t param; + if (!dlg || !_params) return; LM_DBG("engage close called\n"); - if (unforce_rtp_proxy_f(_params->msg, NULL, NULL) < 0) { + if (dlg_api.fetch_dlg_value(dlg, ¶m3_name, &value, 0) < 0) { + LM_DBG("third param not found\n"); + param.v.int_set = DEFAULT_RTPP_SET_ID; + } else { + param.v.int_set = *(int *)(value.s); + } + param.t = NH_VAL_SET_UNDEF; + + if (unforce_rtpproxy(_params->msg, dlg->callid, + dlg->legs[DLG_CALLER_LEG].tag, dlg->legs[callee_idx(dlg)].tag, + (char *)¶m, NULL) < 0) { LM_ERR("cannot unforce rtp proxy\n"); } } @@ -2442,71 +2717,106 @@ static void engage_close_callback(struct dlg_cell *dlg, int type, /* moves parameters from branch avps to dialog values * returns the values moved */ -static int move_bavp2dlg(struct sip_msg *msg, struct dlg_cell *dlg, str *rval1, str *rval2) +static int move_bavp2dlg(struct sip_msg *msg, struct dlg_cell *dlg, str *rval1, str *rval2, int *setid) { unsigned int code = 0; - pv_value_t val1, val2; + unsigned int flags_found = 0; + unsigned int ip_found = 0; + unsigned int set_found = 0; + pv_value_t val1, val2, val3; if (!msg || !dlg || msg->first_line.type != SIP_REPLY) goto not_moved; /* check to see if there are avps stored */ - if (pv_get_spec_value(msg, ¶m1_spec, &val1) < 0) { - LM_DBG("bavp not found!\n"); - goto not_moved; - } - if (!(val1.flags & PV_VAL_STR)) { - LM_DBG("bug - invalid bavp type [%x]\n", val1.flags); - goto not_moved; - } - if (pv_get_spec_value(msg, ¶m2_spec, &val2) < 0) { - LM_DBG("bavp not found!\n"); + if (pv_get_spec_value(msg, ¶m1_spec, &val1) < 0 || + (val1.flags & PV_VAL_NULL)) + LM_DBG("flags bavp not found!\n"); + else + flags_found = 1; + + if (pv_get_spec_value(msg, ¶m2_spec, &val2) < 0 || + (val2.flags & PV_VAL_NULL)) + LM_DBG("ip bavp not found!\n"); + else + ip_found = 1; + + if (pv_get_spec_value(msg, ¶m3_spec, &val3) < 0 || + (val3.flags & PV_VAL_NULL)) + LM_DBG("set bavp not found!\n"); + else + set_found = 1; + + if ((flags_found|ip_found|set_found) == 0) goto not_moved; - } code = msg->first_line.u.reply.statuscode; /* only move branch avps if a final response has come */ if (code >= 200 && code < 300) { - if (dlg_api.store_dlg_value(dlg, ¶m1_name, &val1.rs) < 0) { - LM_ERR("cannot store value\n"); - goto error; + if (flags_found) { + if (dlg_api.store_dlg_value(dlg, ¶m1_name, &val1.rs) < 0) { + LM_ERR("cannot store value\n"); + goto error; + } + } else { + val1.rs.len = 0; + val1.rs.s = 0; } if (rval1) { rval1->len = val1.rs.len; rval1->s = val1.rs.s; } - if (!(val2.flags & PV_VAL_STR)) { - LM_DBG("param2 not found\n"); - return 1; - } - if (dlg_api.store_dlg_value(dlg, ¶m2_name, &val2.rs) < 0) { - LM_ERR("cannot store value\n"); - goto error; + if (ip_found) { + if (dlg_api.store_dlg_value(dlg, ¶m2_name, &val2.rs) < 0) { + LM_ERR("cannot store value\n"); + goto error; + } + } else { + val2.rs.len = 0; + val2.rs.s = 0; } if (rval2) { rval2->len = val2.rs.len; rval2->s = val2.rs.s; } - LM_DBG("moved <%s> and <%s> from branch avp list in dlg\n", + if (set_found) { + if (dlg_api.store_dlg_value(dlg, ¶m3_name, &val3.rs) < 0) { + LM_ERR("cannot store setid value\n"); + goto error; + } + } else { + val3.ri = DEFAULT_RTPP_SET_ID; + } + if (setid) + *setid = val3.ri; + + LM_DBG("moved <%s> and <%s> from branch avp list in dlg\n", param1_name.s,param2_name.s); return 1; } else if (code < 200) { + if (!flags_found) { + val1.rs.len = 0; + val1.rs.s = 0; + } if (rval1) { rval1->len = val1.rs.len; rval1->s = val1.rs.s; } + if (!ip_found) { + val2.rs.len = 0; + val2.rs.s = 0; + } if (rval2) { - if (val2.flags & PV_VAL_STR) { - rval2->len = val2.rs.len; - rval2->s = val2.rs.s; - } else { - rval2->len = 0; - rval2->s = 0; - } + rval2->len = val2.rs.len; + rval2->s = val2.rs.s; } + if (!set_found) + val3.ri = DEFAULT_RTPP_SET_ID; + if (setid) + *setid = val3.ri; return 1; } @@ -2514,6 +2824,7 @@ static int move_bavp2dlg(struct sip_msg *msg, struct dlg_cell *dlg, str *rval1, LM_DBG("nothing moved - message type %d\n", msg->first_line.type); if (rval1) rval1->len = 0; if (rval2) rval2->len = 0; + if (setid) *setid = DEFAULT_RTPP_SET_ID; return 0; error: return -1; @@ -2523,8 +2834,11 @@ static int move_bavp2dlg(struct sip_msg *msg, struct dlg_cell *dlg, str *rval1, static int engage_force_rtpproxy(struct dlg_cell *dlg, struct sip_msg *msg) { int offer = 1; + int setid; str param1_val,param2_val,value; int method_id, has_sdp, alloc = 0; + int moved; + static nh_set_param_t param = { .t = NH_VAL_SET_UNDEF }; LM_DBG("engage callback called\n"); if (!msg) @@ -2537,7 +2851,7 @@ static int engage_force_rtpproxy(struct dlg_cell *dlg, struct sip_msg *msg) goto done; } } - + if (!dlg) { LM_ERR("null dialog\n"); goto error; @@ -2585,47 +2899,67 @@ static int engage_force_rtpproxy(struct dlg_cell *dlg, struct sip_msg *msg) LM_DBG("handling 200 OK? - %d\n", msg->first_line.u.reply.statuscode); } - param1_val.len = param2_val.len = 0; - param1_val.s = param2_val.s = 0; - /* try to move values */ - if (move_bavp2dlg(msg, dlg, ¶m1_val, ¶m2_val) < 0) { + if ((moved = move_bavp2dlg(msg, dlg, ¶m1_val, ¶m2_val, &setid)) < 0) { LM_ERR("error while moving branch avps\n"); goto error; } /* don't have them, try to get them from the dialog */ - if (!param1_val.len) { + if (moved == 0) { /* nothing moved - the values should be in dialog already */ - if (dlg_api.fetch_dlg_value(dlg, ¶m1_name, &value, 0) < 0) { - LM_ERR("cannot fetch first parameter\n"); - goto error; + if (dlg_api.fetch_dlg_value(dlg, ¶m1_name, &value, 0) >= 0) { + param1_val.s = pkg_malloc(value.len + 1); + if (!param1_val.s) { + LM_ERR("no more pkg mem\n"); + goto error; + } + alloc = 1; + memcpy(param1_val.s, value.s, value.len); + param1_val.s[value.len] = '\0'; + param1_val.len = value.len; + } else { + LM_DBG("flags param not found\n"); + param1_val.s = NULL; } - - alloc = 1; - param1_val.s = pkg_malloc(value.len); - if (!param1_val.s) { - LM_ERR("no more pkg mem\n"); - goto error; + if (dlg_api.fetch_dlg_value(dlg, ¶m2_name, &value, 0) >= 0) { + param2_val.s = pkg_malloc(value.len + 1); + if (!param2_val.s) { + LM_ERR("no more pkg mem\n"); + goto error; + } + alloc = 1; + memcpy(param2_val.s, value.s, value.len); + param2_val.s[value.len] = '\0'; + param2_val.len = value.len; + } else { + LM_DBG("ip param not found\n"); + param2_val.s = NULL; } - memcpy(param1_val.s,value.s,value.len); - param1_val.len = value.len; - /* can hold the value in the buffer - might be not found */ - if (dlg_api.fetch_dlg_value(dlg, ¶m2_name, ¶m2_val, 0) < 0) { - LM_DBG("second param not found\n"); - param2_val.s = 0; - param2_val.len = 0; + if (dlg_api.fetch_dlg_value(dlg, ¶m3_name, &value, 0) < 0) { + LM_DBG("third param not found\n"); + setid = DEFAULT_RTPP_SET_ID; + } else { + setid = *(int *)(value.s); } - LM_DBG("fetched: param1 <%s> param2 <%s> - offer? %s\n", - param1_val.s, param2_val.s ? param2_val.s : "null", offer? "yes":"no"); + LM_DBG("fetched: param1 <%s> param2 <%s> set <%d> - offer? %s\n", + param1_val.s ? param1_val.s : "none", + param2_val.s ? param2_val.s : "none", + setid, offer? "yes":"no"); } - - force_rtp_proxy(msg, param1_val.s, param2_val.s ? param2_val.s : NULL, offer); + param.v.int_set = setid; + param.t = NH_VAL_SET_UNDEF; + + force_rtp_proxy(msg, param1_val.s, param2_val.s, (char *)¶m, NULL, offer); - if (alloc && param1_val.s) - pkg_free(param1_val.s); + if (alloc) { + if (param1_val.s) + pkg_free(param1_val.s); + if (param2_val.s) + pkg_free(param2_val.s); + } done: return 0; error: @@ -2671,15 +3005,19 @@ int msg_has_sdp(struct sip_msg *msg) return 0; } -static int -engage_rtp_proxy2_f(struct sip_msg *msg, char *param1, char *param2) +static int +engage_rtp_proxy4_f(struct sip_msg *msg, char *param1, char *param2, char *param3, char *param4) { str param1_val,param2_val; struct to_body *pto; struct dlg_cell *dlg; + struct rtpp_set *set = NULL; pv_value_t val1, val2; + str aux_str; + + LM_DBG("engage called from script 1:%p 2:%p 3:%p 4:%p\n", + param1, param2, param3, param4); - LM_DBG("engage called from script\n"); if (!(msg->first_line.type == SIP_REQUEST && msg->first_line.u.request.method_value == METHOD_INVITE)) { LM_ERR("this function can only be called from invite\n"); @@ -2715,41 +3053,72 @@ engage_rtp_proxy2_f(struct sip_msg *msg, char *param1, char *param2) return -1; } + if (param1) { + if (rtpp_get_var_svalue(msg, (gparam_p)param1, &aux_str, 0)<0) { + LM_ERR("bogus flags parameter\n"); + return -1; + } + param1 = aux_str.s; + } + + if (param2) { + if (rtpp_get_var_svalue(msg, (gparam_p)param2, &aux_str, 1)<0) { + LM_ERR("bogus IP addr parameter\n"); + return -1; + } + param2 = aux_str.s; + } + /* is this a late negociation scenario? */ if (msg_has_sdp(msg)) { LM_DBG("message has sdp body -> forcing rtp proxy\n"); - if(force_rtp_proxy(msg,param1,param2,1) < 0) { + if(force_rtp_proxy(msg,param1,param2,param3,param4,1) < 0) { LM_ERR("error forcing rtp proxy"); return -1; } } else { - if ( dlg_api.store_dlg_value(dlg, &late_name, &late_name) < 0) { + if (dlg_api.store_dlg_value(dlg, &late_name, &late_name) < 0) { LM_ERR("cannot store late_negociation param into dialog\n"); return -1; } } - param1_val.s = param1; - param1_val.len = strlen(param1)+1; + if (param1) { + param1_val.s = param1; + param1_val.len = strlen(param1)+1; + } if (param2) { param2_val.s = param2; param2_val.len = strlen(param2)+1; } + if (param3) { + /* get the setid */ + set = get_rtpp_set(msg, (nh_set_param_t *)param3); + if (!set) { + LM_CRIT("set no longer here - forcing the default one!\n"); + set = *default_rtpp_set; + } + } else { + set = *default_rtpp_set; + } + if (route_type & BRANCH_ROUTE) { /* store the value into branch avps */ - val1.flags = AVP_VAL_STR; - val1.rs = param1_val; + if (param1) { + val1.flags = AVP_VAL_STR; + val1.rs = param1_val; - if (pv_set_value(msg, ¶m1_spec, EQ_T, &val1) < 0) { - LM_ERR("cannot store <%.*s> param", param1_name.len, param1_name.s); - return -1; - } + if (pv_set_value(msg, ¶m1_spec, EQ_T, &val1) < 0) { + LM_ERR("cannot store <%.*s> param", param1_name.len, param1_name.s); + return -1; + } - if (!val1.rs.len) { - LM_ERR("cannot store first parameter in branch avp\n"); - return -1; + if (!val1.rs.len) { + LM_ERR("cannot store flags parameter in branch avp\n"); + return -1; + } } if (param2) { @@ -2760,23 +3129,36 @@ engage_rtp_proxy2_f(struct sip_msg *msg, char *param1, char *param2) LM_ERR("cannot store <%.*s> param", param2_name.len, param2_name.s); return -1; } + } + + if (param3) { + val2.flags = PV_TYPE_INT; + val2.ri = set->id_set; - if (!val2.rs.len) { - LM_ERR("cannot store second parameter in branch avp\n"); + if (pv_set_value(msg, ¶m3_spec, EQ_T, &val2) < 0) { + LM_ERR("cannot store set param"); return -1; } } LM_DBG("stored values in bavp\n"); } else { - if ( dlg_api.store_dlg_value(dlg, ¶m1_name, ¶m1_val) < 0) { - LM_ERR("cannot store first param into dialog\n"); + if ( param1 && dlg_api.store_dlg_value(dlg, ¶m1_name, ¶m1_val) < 0) { + LM_ERR("cannot store flags param into dialog\n"); return -1; } if ( param2 && dlg_api.store_dlg_value(dlg, ¶m2_name, ¶m2_val) < 0) { - LM_ERR("cannot store second param into dialog\n"); + LM_ERR("cannot store ip param into dialog\n"); return -1; } + if (param3) { + param2_val.s = (char*)&set->id_set; + param2_val.len = sizeof(unsigned int); + if (dlg_api.store_dlg_value(dlg, ¶m3_name, ¶m2_val) < 0) { + LM_ERR("cannot store set param into dialog\n"); + return -1; + } + } LM_DBG("stored values in dialog\n"); } /* callbacks setup - only once */ @@ -2875,7 +3257,7 @@ free_opts(struct options *op1, struct options *op2, struct options *op3) } while (0); static int -force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer) +force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, char *setid, char *var, int offer) { struct multi_body *m; struct part * p; @@ -2883,7 +3265,8 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer) struct force_rtpp_args *ap; union sockaddr_union to; struct ip_addr ip; - + struct cell *trans; + memset(&args, '\0', sizeof(args)); m = get_all_bodies(msg); @@ -2894,21 +3277,13 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer) } LM_DBG("force rtp proxy with param1 <%s> and param2 <%s>\n", - str1, str2 ? str2 : "none"); + str1 ? str1 : "none", str2 ? str2 : "none"); if (get_callid(msg, &args.callid) == -1 || args.callid.len == 0) { LM_ERR("can't get Call-Id field\n"); return (-1); } - if (msg->id != current_msg_id) { - selected_rtpp_set = *default_rtpp_set; - } - args.node = select_rtpp_node(args.callid, 1); - if (args.node == NULL) { - LM_ERR("no available proxies\n"); - return (-1); - } args.arg1 = str1; args.arg2 = str2; @@ -2917,16 +3292,36 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer) for (p = m->first; p != NULL; p = p->next) { int ret = 0; - if (p->content_type == ((TYPE_APPLICATION << 16) + SUBTYPE_SDP)) - { - args.body = p->body; + if (p->content_type != ((TYPE_APPLICATION << 16) + SUBTYPE_SDP)) + continue; + if (p->body.len == 0) { + LM_WARN("empty body\n"); + continue; + } + args.body = p->body; - if (args.body.len == 0) - { - LM_WARN("empty body\n"); + /* there is not a problem if the set is not got under lock, since + * after we have it, we will never delete/change it */ + args.set = get_rtpp_set(msg, (nh_set_param_t *)setid); + if (!args.set) { + LM_ERR("cannot find RTPProxy set\n"); + return -1; + } - } else { - if (rtpproxy_autobridge && args.node->abr_supported && msg->first_line.type == SIP_REQUEST) { + if (rtpproxy_autobridge) { + + if (nh_lock) + lock_start_read(nh_lock); + + args.node = select_rtpp_node(msg, args.callid, args.set, (pv_spec_p)var, 1); + if (args.node == NULL) { + LM_ERR("no available proxies\n"); + goto error_with_lock; + } + + /* XXX: here we assume that all nodes in a set should be similar */ + if (args.node->abr_supported) { + if (msg->first_line.type == SIP_REQUEST) { ap = pkg_malloc(sizeof(*ap)); if (ap == NULL) { LM_ERR("can't allocate memory\n"); @@ -2951,34 +3346,57 @@ force_rtp_proxy(struct sip_msg* msg, char* str1, char* str2, int offer) return (-1); } } + /* we don't remember the node, since it might not be + * available later when we execute the callback */ + ap->node = NULL; msg_callback_add(msg, REQ_PRE_FORWARD, rtpproxy_pre_fwd, ap); msg_callback_add(msg, MSG_DESTROY, rtpproxy_pre_fwd_free, ap); + if (nh_lock) + lock_stop_read(nh_lock); continue; - } - if (rtpproxy_autobridge && args.node->abr_supported && msg->first_line.type == SIP_REPLY) { - if (parse_headers(msg, HDR_VIA2_F, 0) != -1 && - (msg->via2 != NULL) && (msg->via2->error == PARSE_OK) && - update_sock_struct_from_via(&to, msg, msg->via2) != -1) { + } else { + /* first try to get the destination of this reply from the + * transaction (as the source of the request) */ + if (tm_api.t_gett && (trans=tm_api.t_gett())!=0 && + trans!=T_UNDEFINED && trans->uas.request ) { + /* we have the request from the transaction this + * reply belongs to */ + args.raddr.s = ip_addr2a(&trans->uas.request->rcv.src_ip); + args.raddr.len = strlen(args.raddr.s); + } else if (parse_headers(msg, HDR_VIA2_F, 0) != -1 && + (msg->via2 != NULL) && (msg->via2->error == PARSE_OK) && + update_sock_struct_from_via(&to, msg, msg->via2)!=-1) { su2ip_addr(&ip, &to); args.raddr.s = ip_addr2a(&ip); args.raddr.len = strlen(args.raddr.s); } else { - LM_ERR("can't extract 2nd via found reply\n"); + LM_ERR("can't extract reply destination from " + "transaction/reply_via2\n"); } } - - - LM_DBG("Forcing body:\n[%.*s]\n", args.body.len, args.body.s); - ret = force_rtp_proxy_body(msg, &args); } } + LM_DBG("Forcing body:\n[%.*s]\n", args.body.len, args.body.s); + ret = force_rtp_proxy_body(msg, &args, (pv_spec_p)var); + + if (rtpproxy_autobridge) { + if (nh_lock) + lock_stop_read(nh_lock); + args.node = NULL; + } + if (ret < 0) return ret; } return 1; -}; + +error_with_lock: + if (nh_lock) + lock_stop_read(nh_lock); + return -1; +} static inline int rtpp_get_error(char *command) { @@ -2997,13 +3415,13 @@ static inline int rtpp_get_error(char *command) } int -force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) +force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args, pv_spec_p var) { str body1, oldport, oldip, newport, newip ,nextport; str from_tag, to_tag, tmp, payload_types; int create, port, len, asymmetric, flookup, argc, proxied, real; int orgip, commip, enable_notification; - int pf, pf1, force, err; + int pf, pf1, force, err, locked = 0; struct options opts, rep_opts, pt_opts; char *cp, *cp1; char *cpend, *next; @@ -3079,10 +3497,9 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) case 'l': case 'L': - if (args->offer == 0) { - FORCE_RTP_PROXY_RET (-1); + if (args->offer != 0) { + flookup = 1; } - flookup = 1; break; case 'f': @@ -3225,10 +3642,6 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) v2p = v1p; medianum = 0; - if (nh_lock) { - lock_start_read( nh_lock ); - } - opts.s.s[0] = (create == 0) ? 'L' : 'U'; v[1].iov_base = opts.s.s; v[1].iov_len = opts.oidx; @@ -3355,7 +3768,22 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) v[12].iov_len = v[13].iov_len = 0; v[16].iov_len = v[17].iov_len = 0; } + if (!args->node && nh_lock) { + locked = 1; + lock_start_read(nh_lock); + } do { + + /* if not successfull choose a different rtpproxy */ + if (!args->node) { + args->node = select_rtpp_node(msg, args->callid, args->set, var, 0); + if (!args->node) { + LM_ERR("no available proxies\n"); + goto error; + } + LM_DBG("trying new rtpproxy node %s\n", args->node->rn_address); + } + /* if we don't have, we should choose a new node */ if (rep_opts.oidx > 0) { if (args->node->rn_rep_supported == 0) { LM_WARN("re-packetization is requested but is not " @@ -3404,12 +3832,12 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) v[3].iov_len = 0; } if(enable_notification && opts.s.s[0] == 'U') - vcnt = 22; - else - { - vcnt = (to_tag.len > 0) ? 18 : 14; - } - cp = send_rtpp_command(args->node, v, vcnt); + vcnt = 22; + else + { + vcnt = (to_tag.len > 0) ? 18 : 14; + } + cp = send_rtpp_command(args->node, v, vcnt); if (!cp && !create) { LM_ERR("cannot lookup a session on a different RTPProxy\n"); goto error; @@ -3418,25 +3846,21 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) /* check internal errors */ if (err >= 7 && err <= 10) { cp = NULL; - args->node->rn_disabled = 1; + args->node->rn_disabled = 1; args->node->rn_recheck_ticks = get_ticks() + - rtpproxy_disable_tout; + rtpproxy_disable_tout; raise_rtpproxy_event(args->node, 0); } else { LM_ERR("unhandled rtpproxy error: %d\n", err); goto error; } } - /* if not successfull choose a different rtpproxy */ - if (!cp) { - args->node = select_rtpp_node(args->callid, 0); - if (!args->node) { - LM_ERR("no available proxies\n"); - goto error; - } - LM_DBG("trying new rtpproxy node %s\n", args->node->rn_address); - } + args->node = NULL; } while (cp == NULL); + if (locked) { + locked = 0; + lock_stop_read(nh_lock); + } LM_DBG("proxy reply: %s\n", cp); /* Parse proxy reply to */ argc = 0; @@ -3480,7 +3904,7 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) * 2) no second argument, rtpproxy response contains ip (argv[1]) * 3) no ip in rtpproxy response (started using unix socket and no -l param) * must revert to default of proxy ip - */ + */ newip.s = args->arg2 ? args->arg2 : argv[1] ? argv[1] : ip_addr2a(&msg->rcv.dst_ip); newip.len = strlen(newip.s); } @@ -3505,7 +3929,7 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) if( r2p ) if (alter_rtcp(msg, &body1, &newip, pf1, &nextport, r2p) < 0 ) goto error; - + /* * Alter IP. Don't alter IP common for the session * more than once. @@ -3554,12 +3978,6 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) } /* Iterate sessions */ free_opts(&opts, &rep_opts, &pt_opts); - if(nh_lock) - { - /* we are done reading -> unref the data */ - lock_stop_read( nh_lock ); - } - if (proxied == 0 && nortpproxy_str.len) { cp = pkg_malloc((nortpproxy_str.len + CRLF_LEN) * sizeof(char)); if (cp == NULL) { @@ -3571,7 +3989,7 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) while( cp1>args->body.s && !(*(cp1-1)=='\n' && *(cp1-2)=='\r') ) cp1--; if (cp1==args->body.s) cp1=args->body.s + args->body.len; - anchor = anchor_lump(msg, cp1 - msg->buf, 0, 0); + anchor = anchor_lump(msg, cp1 - msg->buf, 0); if (anchor == NULL) { LM_ERR("anchor_lump failed\n"); pkg_free(cp); @@ -3589,7 +4007,7 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) return 1; error: - if(!nh_lock) + if(!locked) FORCE_RTP_PROXY_RET (-1); /* we are done reading -> unref the data */ @@ -3599,27 +4017,15 @@ force_rtp_proxy_body(struct sip_msg* msg, struct force_rtpp_args *args) } -static int engage_rtp_proxy1_f(struct sip_msg* msg,char* str1,char* str2) -{ - return engage_rtp_proxy2_f(msg,str1,str2); -} - -static int engage_rtp_proxy0_f(struct sip_msg* msg,char *str1,char* str2) -{ - - static const char * arg = ""; - return engage_rtp_proxy1_f(msg,(char*)arg,NULL); -} - - -static int start_recording_f(struct sip_msg* msg, char *foo, char *bar) +static int start_recording_f(struct sip_msg* msg, char *setid, char *var) { int nitems; str callid = {0, 0}; str from_tag = {0, 0}; str to_tag = {0, 0}; struct rtpp_node *node; + struct rtpp_set *set; struct iovec v[1 + 4 + 3] = {{NULL, 0}, {"R", 1}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}}; /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ /* 6 */ /* 1 */ @@ -3638,29 +4044,13 @@ static int start_recording_f(struct sip_msg* msg, char *foo, char *bar) return -1; } - STR2IOVEC(callid, v[3]); STR2IOVEC(from_tag, v[5]); STR2IOVEC(to_tag, v[7]); - - if (nh_lock) { - lock_start_read( nh_lock ); - } - - if(msg->id != current_msg_id){ - selected_rtpp_set = *default_rtpp_set; - } - - node = select_rtpp_node(callid, 1); - if (!node) { - LM_ERR("no available proxies\n"); - goto error; - } - nitems = 8; if (msg->first_line.type == SIP_REPLY) { if (to_tag.len == 0) - goto error; + return -1; STR2IOVEC(to_tag, v[5]); STR2IOVEC(from_tag, v[7]); } else { @@ -3669,6 +4059,23 @@ static int start_recording_f(struct sip_msg* msg, char *foo, char *bar) if (to_tag.len <= 0) nitems = 6; } + + set = get_rtpp_set(msg, (nh_set_param_t *)setid); + if (!set) { + LM_ERR("could not find rtpproxy set\n"); + return 0; + } + + if (nh_lock) { + lock_start_read( nh_lock ); + } + + node = select_rtpp_node(msg, callid, set, (pv_spec_p)var, 1); + if (!node) { + LM_ERR("no available proxies\n"); + goto error; + } + send_rtpp_command(node, v, nitems); if(nh_lock) diff --git a/modules/rtpproxy/rtpproxy.h b/modules/rtpproxy/rtpproxy.h index 64175d78883..db862900875 100644 --- a/modules/rtpproxy/rtpproxy.h +++ b/modules/rtpproxy/rtpproxy.h @@ -30,6 +30,7 @@ #include "../../str.h" #include "../../pvar.h" #include "../dialog/dlg_load.h" +#include "../../rw_locking.h" /* Handy macros */ #define STR2IOVEC(sx, ix) do {(ix).iov_base = (sx).s; (ix).iov_len = (sx).len;} while(0) @@ -73,6 +74,7 @@ struct force_rtpp_args { int offer; str body; str callid; + struct rtpp_set *set; struct rtpp_node *node; str raddr; }; @@ -95,17 +97,20 @@ struct rtpp_notify_head { /* parameter type for set_rtp_proxy_set() */ -#define NH_VAL_SET_FIXED 0 +#define NH_VAL_SET_FIXED 0 #define NH_VAL_SET_SPEC 1 +#define NH_VAL_SET_UNDEF 2 typedef struct rtpp_set_param{ int t; union { struct rtpp_set * fixed_set; pv_spec_t var_set; + int int_set; } v; } nh_set_param_t; +extern rw_lock_t *nh_lock; extern str rtpp_notify_socket; extern int rtpp_notify_socket_un; extern struct dlg_binds dlg_api; @@ -116,8 +121,9 @@ int init_rtpp_notify_list(); void timeout_listener_process(int rank); /* Functions from nathelper */ -struct rtpp_node *select_rtpp_node(str, int); +struct rtpp_set *get_rtpp_set(struct sip_msg *, nh_set_param_t *); +struct rtpp_node *select_rtpp_node(struct sip_msg *, str, struct rtpp_set *, pv_spec_p, int); char *send_rtpp_command(struct rtpp_node *, struct iovec *, int); -int force_rtp_proxy_body(struct sip_msg *, struct force_rtpp_args *); +int force_rtp_proxy_body(struct sip_msg *, struct force_rtpp_args *, pv_spec_p); #endif diff --git a/modules/rtpproxy/rtpproxy_callbacks.c b/modules/rtpproxy/rtpproxy_callbacks.c index 9c842ec7611..5e76f8c28a5 100644 --- a/modules/rtpproxy/rtpproxy_callbacks.c +++ b/modules/rtpproxy/rtpproxy_callbacks.c @@ -63,7 +63,7 @@ rtpproxy_pre_fwd(struct sip_msg *msg, cb_type_t cb_type, void *mod_args, void *c } sprintf(args->raddr.s, "[%s]", cp); } - force_rtp_proxy_body(msg, args); + force_rtp_proxy_body(msg, args, NULL); } void diff --git a/modules/rtpproxy/rtpproxy_stream.c b/modules/rtpproxy/rtpproxy_stream.c index 07fa9dee527..ae3a76e5408 100644 --- a/modules/rtpproxy/rtpproxy_stream.c +++ b/modules/rtpproxy/rtpproxy_stream.c @@ -37,45 +37,14 @@ #include "rtpproxy.h" #include "nhelpr_funcs.h" -int -fixup_var_str_int(void **param, int param_no) -{ - int ret; - pv_elem_t *model; - str s; - - if (param_no == 1) { - model = NULL; - s.s = (char *)(*param); - s.len = strlen(s.s); - if (pv_parse_format(&s, &model) < 0) { - LM_ERR("wrong format[%s]!\n", (char *)(*param)); - return E_UNSPEC; - } - if (model == NULL) { - LM_ERR("empty parameter!\n"); - return E_UNSPEC; - } - *param = (void *)model; - } else if (param_no == 2) { - s.s = (char *)(*param); - s.len = strlen(s.s); - if (str2sint(&s, &ret) < 0) { - LM_ERR("bad number <%s>\n", (char *)(*param)); - return E_CFG; - } - pkg_free(*param); - *param = (void *)(long)ret; - } - return 0; -} static int -rtpproxy_stream(struct sip_msg* msg, str *pname, int count, int stream2uac) +rtpproxy_stream(struct sip_msg* msg, str *pname, int count, char *setid, char *var, int stream2uac) { - int nitems; + int nitems, ret = -1; str callid, from_tag, to_tag; struct rtpp_node *node; + struct rtpp_set *set; char cbuf[16]; struct iovec v[] = { {NULL, 0}, @@ -106,17 +75,7 @@ rtpproxy_stream(struct sip_msg* msg, str *pname, int count, int stream2uac) v[1].iov_len = sprintf(cbuf, "P%d", count); STR2IOVEC(callid, v[3]); STR2IOVEC(*pname, v[5]); - node = select_rtpp_node(callid, 1); - if (!node) { - LM_ERR("no available proxies\n"); - return -1; - } - if (node->rn_ptl_supported == 0) { - LM_ERR("required functionality is not " - "supported by the version of the RTPproxy running on the selected " - "node. Please upgrade the RTPproxy and try again.\n"); - return -1; - } + nitems = 11; if (stream2uac == 0) { if (to_tag.len == 0) @@ -128,42 +87,70 @@ rtpproxy_stream(struct sip_msg* msg, str *pname, int count, int stream2uac) STR2IOVEC(to_tag, v[9]); if (to_tag.len <= 0) nitems -= 2; + } + if (nh_lock) { + lock_start_read( nh_lock ); + } + + set = get_rtpp_set(msg, (nh_set_param_t *)setid); + if (!set) { + LM_ERR("no set found\n"); + goto end; + } + + node = select_rtpp_node(msg, callid, set, (pv_spec_p)var, 1); + if (!node) { + LM_ERR("no available proxies\n"); + goto end; + } + + if (node->rn_ptl_supported == 0) { + LM_ERR("required functionality is not " + "supported by the version of the RTPproxy running on the selected " + "node. Please upgrade the RTPproxy and try again.\n"); + goto end; } send_rtpp_command(node, v, nitems); - return 1; + ret = 1; +end: + if (nh_lock) { + lock_stop_read( nh_lock ); + } + return ret; } static int -rtpproxy_stream2_f(struct sip_msg *msg, char *str1, int count, int stream2uac) +rtpproxy_stream4_f(struct sip_msg *msg, char *str1, int count, char *setid, char *var, int stream2uac) { str pname; if (str1 == NULL || pv_printf_s(msg, (pv_elem_p)str1, &pname) != 0) return -1; - return rtpproxy_stream(msg, &pname, count, stream2uac); + return rtpproxy_stream(msg, &pname, count, setid, var, stream2uac); } int -rtpproxy_stream2uac2_f(struct sip_msg* msg, char* str1, char* str2) +rtpproxy_stream2uac4_f(struct sip_msg* msg, char* str1, char* str2, char *str3, char *str4) { - return rtpproxy_stream2_f(msg, str1, (int)(long)str2, 1); + return rtpproxy_stream4_f(msg, str1, (int)(long)str2, str3, str4, 1); } int -rtpproxy_stream2uas2_f(struct sip_msg* msg, char* str1, char* str2) +rtpproxy_stream2uas4_f(struct sip_msg* msg, char* str1, char* str2, char *str3, char *str4) { - return rtpproxy_stream2_f(msg, str1, (int)(long)str2, 0); + return rtpproxy_stream4_f(msg, str1, (int)(long)str2, str3, str4, 0); } static int -rtpproxy_stop_stream(struct sip_msg* msg, int stream2uac) +rtpproxy_stop_stream(struct sip_msg* msg, char *setid, char *var, int stream2uac) { - int nitems; + int nitems, ret = -1; str callid, from_tag, to_tag; struct rtpp_node *node; + struct rtpp_set *set; struct iovec v[] = { {NULL, 0}, {"S", 1}, /* 1 */ @@ -189,17 +176,6 @@ rtpproxy_stop_stream(struct sip_msg* msg, int stream2uac) return -1; } STR2IOVEC(callid, v[3]); - node = select_rtpp_node(callid, 1); - if (!node) { - LM_ERR("no available proxies\n"); - return -1; - } - if (node->rn_ptl_supported == 0) { - LM_ERR("required functionality is not " - "supported by the version of the RTPproxy running on the selected " - "node. Please upgrade the RTPproxy and try again.\n"); - return -1; - } nitems = 9; if (stream2uac == 0) { if (to_tag.len == 0) @@ -212,21 +188,49 @@ rtpproxy_stop_stream(struct sip_msg* msg, int stream2uac) if (to_tag.len <= 0) nitems -= 2; } + + if (nh_lock) { + lock_start_read( nh_lock ); + } + + + set = get_rtpp_set(msg, (nh_set_param_t *)setid); + if (!set) { + LM_ERR("no set found\n"); + goto end; + } + + node = select_rtpp_node(msg, callid, set, (pv_spec_p)var, 1); + if (!node) { + LM_ERR("no available proxies\n"); + goto end; + } + if (node->rn_ptl_supported == 0) { + LM_ERR("required functionality is not " + "supported by the version of the RTPproxy running on the selected " + "node. Please upgrade the RTPproxy and try again.\n"); + goto end; + } send_rtpp_command(node, v, nitems); - return 1; + ret = 1; +end: + if (nh_lock) { + lock_stop_read( nh_lock ); + } + return ret; } int -rtpproxy_stop_stream2uac2_f(struct sip_msg* msg, char* str1, char* str2) +rtpproxy_stop_stream2uac2_f(struct sip_msg* msg, char* str1, char *str2) { - return rtpproxy_stop_stream(msg, 1); + return rtpproxy_stop_stream(msg, str1, str2, 1); } int -rtpproxy_stop_stream2uas2_f(struct sip_msg* msg, char* str1, char* str2) +rtpproxy_stop_stream2uas2_f(struct sip_msg* msg, char* str1, char *str2) { - return rtpproxy_stop_stream(msg, 0); + return rtpproxy_stop_stream(msg, str1, str2, 0); } diff --git a/modules/rtpproxy/rtpproxy_stream.h b/modules/rtpproxy/rtpproxy_stream.h index aa155cbbcf3..9a6c5a13052 100644 --- a/modules/rtpproxy/rtpproxy_stream.h +++ b/modules/rtpproxy/rtpproxy_stream.h @@ -28,9 +28,8 @@ #ifndef _RTPPROXY_STREAM_H #define _RTPPROXY_STREAM_H -int fixup_var_str_int(void **, int); -int rtpproxy_stream2uac2_f(struct sip_msg *, char *, char *); -int rtpproxy_stream2uas2_f(struct sip_msg *, char *, char *); +int rtpproxy_stream2uac4_f(struct sip_msg *, char *, char *, char *, char *); +int rtpproxy_stream2uas4_f(struct sip_msg *, char *, char *, char *, char *); int rtpproxy_stop_stream2uac2_f(struct sip_msg *, char *, char *); int rtpproxy_stop_stream2uas2_f(struct sip_msg *, char *, char *); diff --git a/modules/rtpproxy/timeout_process.c b/modules/rtpproxy/timeout_process.c index ac5832fcbec..c0f2073deba 100644 --- a/modules/rtpproxy/timeout_process.c +++ b/modules/rtpproxy/timeout_process.c @@ -77,6 +77,7 @@ void timeout_listener_process(int rank) int optval = 1; struct sockaddr rtpp_info; struct rtpp_notify_node *rtpp_lst; + str terminate_reason = str_init("RTPProxy Timeout"); if (init_child(PROC_MODULE) != 0) { LM_ERR("cannot init child process"); @@ -339,7 +340,7 @@ void timeout_listener_process(int rank) id.s = ++p; /* go to end or to next non-digit */ for (; (p < buffer + len ) && IS_DIGIT(*p); ++p); - + id.len = p - id.s; if(str2int(&id, &h_id)< 0) { LM_ERR("Wrong formated message received from rtpproxy - invalid" @@ -348,7 +349,7 @@ void timeout_listener_process(int rank) } LM_DBG("hentry = %u, h_id = %u\n", h_entry, h_id); - if(dlg_api.terminate_dlg(h_entry, h_id)< 0) + if(dlg_api.terminate_dlg(h_entry, h_id,&terminate_reason)< 0) LM_ERR("Failed to terminate dialog h_entry=[%u], h_id=[%u]\n", h_entry, h_id); /* go to end or to next digit */ @@ -419,7 +420,7 @@ int init_rtpp_notify_list(void) return 0; } - for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; + for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; rtpp_list = rtpp_list->rset_next) { for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL; crt_rtpp = crt_rtpp->rn_next) { @@ -483,7 +484,7 @@ void update_rtpproxy_list(void) LM_DBG("updating rtppproxy list\n"); /* add new rtppproxies */ - for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; + for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; rtpp_list = rtpp_list->rset_next) { for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL; crt_rtpp = crt_rtpp->rn_next) { @@ -517,7 +518,7 @@ void update_rtpproxy_list(void) /* don't update for unix sockets */ if (rtpp_lst->mode == 0) goto loop; - for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; + for(rtpp_list = (*rtpp_set_list)->rset_first; rtpp_list != NULL; rtpp_list = rtpp_list->rset_next) { for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL; crt_rtpp = crt_rtpp->rn_next) { diff --git a/modules/script_helper/Makefile b/modules/script_helper/Makefile new file mode 100644 index 00000000000..81ce913416a --- /dev/null +++ b/modules/script_helper/Makefile @@ -0,0 +1,10 @@ +# $Id$ +# +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=script_helper.so +LIBS= + +include ../../Makefile.modules diff --git a/modules/script_helper/README b/modules/script_helper/README new file mode 100644 index 00000000000..0b578dc0108 --- /dev/null +++ b/modules/script_helper/README @@ -0,0 +1,127 @@ +Script Helper Module + +Liviu Chircu + + OpenSIPS Solutions + +Edited by + +Liviu Chircu + + Copyright © 2014 www.opensips-solutions.com + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. How it works + 1.3. Dependencies + + 1.3.1. OpenSIPS Modules + 1.3.2. External Libraries or Applications + + 1.4. Exported Parameters + + 1.4.1. use_dialog (integer) + 1.4.2. create_dialog_flags (string) + 1.4.3. sequential_route (string) + + 1.5. Known Issues + + List of Examples + + 1.1. Setting use_dialog + 1.2. Setting create_dialog_flags + 1.3. Setting sequential_route + +Chapter 1. Admin Guide + +1.1. Overview + + The purpose of the Script Helper module is to simplify the + scripting process in OpenSIPS when doing basic scenarios. At + the same time, it is useful to script writers as it contains + basic SIP routing logic, and thus it allows them to focus more + on the particular aspects of their OpenSIPS routing code. + +1.2. How it works + + By simply loading the module, the following default logic will + be embedded: + * for initial SIP requests, the module will perform record + routing before running the main request route + * sequential SIP requests will be transparently handled - the + module will perform loose routing, and the request route + will not be run at all + + Currently, the module may be further configured to embed the + following optional logic: + * dialog support (dialog module dependency - must be loaded + before this module) + * an additional route to be run before relaying sequential + requests + +1.3. Dependencies + +1.3.1. OpenSIPS Modules + + The following modules must be loaded before this module: + * dialog (only if use_dialog is enabled). + +1.3.2. External Libraries or Applications + + The following libraries or applications must be installed + before running OpenSIPS with this module loaded: + * None. + +1.4. Exported Parameters + +1.4.1. use_dialog (integer) + + Enables dialog support. Note that the dialog module must be + loaded before this module when setting this parameter. + + Default value is 0 (disabled) + + Example 1.1. Setting use_dialog +... +modparam("script_helper", "use_dialog", 1) +... + +1.4.2. create_dialog_flags (string) + + Flags used when creating dialogs. For details on these flags, + please refer to the create_dialog() function of the dialog + module. + + Default value is "" (no flags are set) + + Example 1.2. Setting create_dialog_flags +... +modparam("script_helper", "create_dialog_flags", "PpB") +... + +1.4.3. sequential_route (string) + + Optional route to be run just before sequential requests are + relayed. If the exit script statement is used inside this + route, the module assumes that the relaying logic has been + handled. + + By default, this parameter is not set + + Example 1.3. Setting sequential_route +... +modparam("script_helper", "sequential_route", "sequential_handling") +... +route [sequential_handling] +{ +... +} +... + +1.5. Known Issues + + The Max-Forwards header is currently not handled at all. diff --git a/modules/script_helper/doc/script_helper.xml b/modules/script_helper/doc/script_helper.xml new file mode 100644 index 00000000000..75ae8ce8ee9 --- /dev/null +++ b/modules/script_helper/doc/script_helper.xml @@ -0,0 +1,44 @@ + + + + + +%docentities; + +]> + + + + Script Helper Module + &osipsname; + + + Liviu + Chircu + OpenSIPS Solutions +
+ liviu@opensips.org +
+
+ + Liviu + Chircu +
+ liviu@opensips.org +
+
+
+ + 2014 + &osipssol; + +
+ + + &admin; + +
diff --git a/modules/script_helper/doc/script_helper_admin.xml b/modules/script_helper/doc/script_helper_admin.xml new file mode 100644 index 00000000000..a8320f813a1 --- /dev/null +++ b/modules/script_helper/doc/script_helper_admin.xml @@ -0,0 +1,167 @@ + + + + + &adminguide; + +
+ Overview + + The purpose of the Script Helper module + is to simplify the scripting process in OpenSIPS when doing basic scenarios. + At the same time, it is useful to script writers as it contains basic SIP + routing logic, and thus it allows them to focus more on the particular aspects + of their OpenSIPS routing code. + +
+ +
+ How it works + + By simply loading the module, the following + default logic will be embedded: + + + + + for initial SIP requests, the module will perform record routing + before running the main request route + + + + + sequential SIP requests will be transparently handled - the module will perform + loose routing, and the request route will not be run at all + + + + + + Currently, the module may be further configured to embed the following + optional logic: + + + + + dialog support (dialog module dependency - must be loaded before this module) + + + + + an additional route to be run before relaying sequential requests + + + + +
+ +
+ Dependencies +
+ &osips; Modules + + The following modules must be loaded before this module: + + + + dialog (only if is enabled). + + + + +
+ +
+ External Libraries or Applications + + The following libraries or applications must be installed before running + &osips; with this module loaded: + + + + None. + + + + +
+
+ +
+ Exported Parameters + +
+ <varname>use_dialog</varname> (integer) + + Enables dialog support. Note that the dialog module must be loaded before + this module when setting this parameter. + + + Default value is 0 (disabled) + + + Setting <varname>use_dialog</varname> + +... +modparam("script_helper", "use_dialog", 1) +... + + +
+ +
+ <varname>create_dialog_flags</varname> (string) + + Flags used when creating dialogs. For details on these flags, please refer + to the create_dialog() function of the dialog module. + + + Default value is "" (no flags are set) + + + Setting <varname>create_dialog_flags</varname> + +... +modparam("script_helper", "create_dialog_flags", "PpB") +... + + +
+ +
+ <varname>sequential_route</varname> (string) + + Optional route to be run just before sequential requests are relayed. + If the exit script statement is used inside this route, + the module assumes that the relaying logic has been handled. + + + By default, this parameter is not set + + + Setting <varname>sequential_route</varname> + +... +modparam("script_helper", "sequential_route", "sequential_handling") +... +route [sequential_handling] +{ +... +} +... + + +
+ +
+ +
+ Known Issues + + + The Max-Forwards header is currently not handled at all. + + +
+
+ diff --git a/modules/script_helper/script_helper.c b/modules/script_helper/script_helper.c new file mode 100644 index 00000000000..81b27001dcf --- /dev/null +++ b/modules/script_helper/script_helper.c @@ -0,0 +1,249 @@ +/** + * script_helper module - embedded scripting logic + * > record routing + * > dialog creation, matching and message validation + * > sequential request routing + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2014-03-01 initial version (liviu) + */ + +#include + +#include "../../sr_module.h" +#include "../../route.h" +#include "../../script_cb.h" +#include "../tm/tm_load.h" +#include "../dialog/dlg_load.h" +#include "../sl/sl_api.h" +#include "../rr/api.h" + +static int use_dialog; +static int create_dialog_flags; +static char *seq_route; +static int seq_route_id; + +struct tm_binds tm_api; +struct dlg_binds dlg_api; +struct rr_binds rr_api; +struct sl_binds sl_api; + +int run_helper_logic(struct sip_msg *msg, void *param); +int parse_dlg_flags(modparam_t type, void *val); + +int mod_init(void); + +static cmd_export_t cmds[] = +{ + { NULL, NULL, 0, NULL, NULL, 0 }, +}; + +static param_export_t params[] = +{ + { "sequential_route", STR_PARAM, &seq_route }, + { "use_dialog", INT_PARAM, &use_dialog }, + { "create_dialog_flags", STR_PARAM|USE_FUNC_PARAM, parse_dlg_flags }, + { NULL, 0, NULL }, +}; + +static module_dependency_t *get_deps_use_dialog(param_export_t *param) +{ + if (*(int *)param->param_pointer == 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_DEFAULT, "dialog", DEP_ABORT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "rr", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "sl", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "use_dialog", get_deps_use_dialog }, + { NULL, NULL }, + }, +}; + +struct module_exports exports = +{ + "script_helper", + MOD_TYPE_DEFAULT, /* class of this module */ + MODULE_VERSION, + DEFAULT_DLFLAGS, + &deps, /* OpenSIPS module dependencies */ + cmds, + params, + NULL, + NULL, + NULL, + NULL, + mod_init, + NULL, + NULL, + NULL, +}; + +int mod_init(void) +{ + LM_DBG("initializing module...\n"); + + if (seq_route) { + seq_route_id = get_script_route_ID_by_name(seq_route, rlist, RT_NO); + if (seq_route_id == -1) + LM_ERR("route \"%s\" does not exist! ignoring\n", seq_route); + } + + if (load_tm_api(&tm_api) != 0) { + LM_ERR("failed to load tm API\n"); + return -1; + } + + if (use_dialog && load_dlg_api(&dlg_api) != 0) { + LM_ERR("failed to load dialog API\n"); + return -1; + } + + if (load_rr_api(&rr_api) != 0) { + LM_ERR("failed to load rr API\n"); + return -1; + } + + if (load_sl_api(&sl_api) != 0) { + LM_ERR("failed to load sl API\n"); + return -1; + } + + if (__register_script_cb(run_helper_logic, + PRE_SCRIPT_CB|REQ_TYPE_CB, NULL, -1) != 0) { + LM_ERR("cannot register script callback"); + return -1; + } + + return 0; +} + +int run_helper_logic(struct sip_msg *msg, void *param) +{ + str totag; + str status_404 = str_init("Not Here"); + str status_500 = str_init("Server Internal Error"); + int rc, seq_request = 0; + + LM_DBG("running script helper for <%.*s>\n", + msg->first_line.u.request.method.len, + msg->first_line.u.request.method.s); + + if (parse_headers(msg, HDR_TO_F|HDR_CALLID_F, 0) == -1) { + LM_ERR("failed to parse To header\n"); + return SCB_DROP_MSG; + } + + totag = get_to(msg)->tag_value; + + /* sequential request */ + if (totag.s && totag.len > 0) { + seq_request = 1; + + if (msg->REQ_METHOD == METHOD_INVITE) + rr_api.record_route(msg, NULL); + + /* if not RR_DRIVEN */ + if (rr_api.loose_route(msg) < 0) { + + /* attempt a full dialog search (not the usual quick did lookup) */ + if (use_dialog && dlg_api.match_dialog(msg) < 0) + LM_DBG("failed to match dialog for <%.*s>, ci '%.*s'\n", + msg->first_line.u.request.method.len, + msg->first_line.u.request.method.s, + msg->callid->body.len, msg->callid->body.s); + + if (msg->REQ_METHOD == METHOD_ACK) { + rc = tm_api.t_check_trans(msg, NULL, NULL, NULL, NULL, NULL, NULL); + if (rc > 0) + tm_api.t_relay(msg, NULL, NULL, NULL, NULL, NULL, NULL); + + return SCB_RUN_POST_CBS; + } + + sl_api.reply(msg, 404, &status_404); + return SCB_RUN_POST_CBS; + } + } + + if (msg->REQ_METHOD == METHOD_CANCEL) { + seq_request = 1; + + rc = tm_api.t_check_trans(msg, NULL, NULL, NULL, NULL, NULL, NULL); + if (rc > 0) + tm_api.t_relay(msg, NULL, NULL, NULL, NULL, NULL, NULL); + + return SCB_RUN_POST_CBS; + } + + if (tm_api.t_check_trans(msg, NULL, NULL, NULL, NULL, NULL, NULL) == 0) + return SCB_RUN_POST_CBS; + + /** + * for sequential requests: + * - optionally run a given route + * - relay them and do not trigger the request route at all + */ + if (seq_request) { + if (seq_route_id > 0) { + LM_DBG("running seq route '%s'\n", seq_route); + if (run_top_route(rlist[seq_route_id].a, msg) & ACT_FL_DROP) { + LM_DBG("script exited in the seq route\n"); + + return SCB_RUN_POST_CBS; + } + } + + if (tm_api.t_relay(msg, NULL, NULL, NULL, NULL, NULL, NULL) < 0) + sl_api.reply(msg, 500, &status_500); + + return SCB_RUN_POST_CBS; + } + + /* record-routing for initial requests */ + if (!(msg->REQ_METHOD & (METHOD_REGISTER|METHOD_MESSAGE))) + rr_api.record_route(msg, NULL); + + if (use_dialog && msg->REQ_METHOD & METHOD_INVITE) + dlg_api.create_dlg(msg, create_dialog_flags); + + return SCB_RUN_ALL; +} + +int parse_dlg_flags(modparam_t type, void *val) +{ + str input; + + input.s = val; + input.len = strlen(val); + + create_dialog_flags = parse_create_dlg_flags(input); + + return 1; +} diff --git a/modules/seas/cluster.c b/modules/seas/cluster.c index 5d963173db0..9fa16ff8127 100644 --- a/modules/seas/cluster.c +++ b/modules/seas/cluster.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -35,13 +35,13 @@ char *cluster_cfg; /** - * Parses the PING configuration string. Its format is + * Parses the PING configuration string. Its format is * "ping_period:pings_lost:ping_timeout" * ping_period : time between pings * pings_lost: number of lost pings before failure * ping_timeout: time to consider a ping failed * - * returns + * returns * 0 if no clusters present * -1 if config is malformed (unable to parse); * 1 if config is successfully set @@ -130,13 +130,13 @@ int parse_cluster_cfg(void) LM_DBG("%.*s\n",tmp->name.len,tmp->name.s); entry=&(tmp->next); for(tmp=as_list;tmp;tmp=tmp->next){ - if (tmp->type!=CLUSTER_TYPE) + if (tmp->type!=CLUSTER_TYPE) continue; LM_DBG("cluster:[%.*s]\n",tmp->name.len,tmp->name.s); for(k=0;ku.cs.num;k++){ LM_DBG("\tAS:[%.*s]\n",tmp->u.cs.as_names[k].len,tmp->u.cs.as_names[k].s); for (tmp2=as_list;tmp2;tmp2=tmp2->next) { - if (tmp2->type== AS_TYPE && tmp->u.cs.as_names[k].len == tmp2->name.len && + if (tmp2->type== AS_TYPE && tmp->u.cs.as_names[k].len == tmp2->name.len && !memcmp(tmp->u.cs.as_names[k].s,tmp2->name.s,tmp2->name.len)) { tmp->u.cs.servers[k]=&tmp2->u.as; break; diff --git a/modules/seas/cluster.h b/modules/seas/cluster.h index fbefcefb395..f68769737f9 100644 --- a/modules/seas/cluster.h +++ b/modules/seas/cluster.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_allow.c b/modules/seas/encode_allow.c index e09a97bf2a8..c1ad45b41f5 100644 --- a/modules/seas/encode_allow.c +++ b/modules/seas/encode_allow.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================== - * + * * Filename: encode_allow.c - * + * * Description: [en|de]code allow header - * + * * Version: 1.0 * Created: 21/11/05 20:40:25 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ====================================================================== */ diff --git a/modules/seas/encode_allow.h b/modules/seas/encode_allow.h index 28878878f00..36cb14cae1e 100644 --- a/modules/seas/encode_allow.h +++ b/modules/seas/encode_allow.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_contact.c b/modules/seas/encode_contact.c index 30f4ded9f83..a4eff6e28c9 100644 --- a/modules/seas/encode_contact.c +++ b/modules/seas/encode_contact.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: encode_contact.c - * + * * Description: functions to encode/decode/print the contact header - * + * * Version: 1.0 * Created: 20/11/05 04:24:55 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ @@ -59,7 +59,7 @@ * encoding is: * 1: flags * 0x01 this is a star contact (*) - *[ + *[ * 1: number of contacts present * N: fore each contact present, the length of the contact structure * N*M: the contact structures concatenated diff --git a/modules/seas/encode_contact.h b/modules/seas/encode_contact.h index c2c30808bf6..07cfcc4e6f5 100644 --- a/modules/seas/encode_contact.h +++ b/modules/seas/encode_contact.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_content_disposition.c b/modules/seas/encode_content_disposition.c index e0ec0767278..97558432766 100644 --- a/modules/seas/encode_content_disposition.c +++ b/modules/seas/encode_content_disposition.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: encode_content_disposition.c - * + * * Description: [en|de]encodes content disposition - * + * * Version: 1.0 * Created: 21/11/05 20:36:19 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ diff --git a/modules/seas/encode_content_disposition.h b/modules/seas/encode_content_disposition.h index 7b2d6fd2748..c071574f996 100644 --- a/modules/seas/encode_content_disposition.h +++ b/modules/seas/encode_content_disposition.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_content_length.c b/modules/seas/encode_content_length.c index 80bf0069bdb..93164b560e4 100644 --- a/modules/seas/encode_content_length.c +++ b/modules/seas/encode_content_length.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: encode_content_length.c - * + * * Description: Function to encode content-length headers. - * + * * Version: 1.0 * Created: 21/11/05 02:02:58 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ diff --git a/modules/seas/encode_content_length.h b/modules/seas/encode_content_length.h index 97446408ba0..28297a22529 100644 --- a/modules/seas/encode_content_length.h +++ b/modules/seas/encode_content_length.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_content_type.c b/modules/seas/encode_content_type.c index 1f75ea064e1..9d9c022fae7 100644 --- a/modules/seas/encode_content_type.c +++ b/modules/seas/encode_content_type.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: encode_content_type.c - * + * * Description: [en|de]code content type - * + * * Version: 1.0 * Created: 21/11/05 20:40:25 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ diff --git a/modules/seas/encode_content_type.h b/modules/seas/encode_content_type.h index 01638988c22..d53be093097 100644 --- a/modules/seas/encode_content_type.h +++ b/modules/seas/encode_content_type.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_cseq.c b/modules/seas/encode_cseq.c index c66d9d203fe..dd501c94054 100644 --- a/modules/seas/encode_cseq.c +++ b/modules/seas/encode_cseq.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: xaddress.c - * + * * Description: Address manipulation tools - * + * * Version: 1.0 * Created: 17/11/05 02:09:44 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ #define _GNU_SOURCE @@ -60,7 +60,7 @@ int encode_cseq(char *hdrstart,int hdrlen,struct cseq_body *body,unsigned char * unsigned int cseqnum; unsigned char i; - /*which is the first bit set to 1 ? if i==0, the first bit, + /*which is the first bit set to 1 ? if i==0, the first bit, * if i==31, the last, if i==32, none*/ for(i=0;(!(body->method_id & (0x01<next,i++){ if((k=encode_route(hdr,hdrlen,myroute,&tmp[route_offset]))<0){ LM_ERR("parsing route number %d\n",i); diff --git a/modules/seas/encode_route.h b/modules/seas/encode_route.h index 2f65363ad1e..03646c32300 100644 --- a/modules/seas/encode_route.h +++ b/modules/seas/encode_route.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_to_body.c b/modules/seas/encode_to_body.c index 534d77a008a..2951f69bdff 100644 --- a/modules/seas/encode_to_body.c +++ b/modules/seas/encode_to_body.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: xaddress.c - * + * * Description: Address manipulation tools - * + * * Version: 1.0 * Created: 17/11/05 02:09:44 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ #define _GNU_SOURCE diff --git a/modules/seas/encode_to_body.h b/modules/seas/encode_to_body.h index 76b2ed4f2da..67e4769a952 100644 --- a/modules/seas/encode_to_body.h +++ b/modules/seas/encode_to_body.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_uri.c b/modules/seas/encode_uri.c index e60745a701a..3619f25d72c 100644 --- a/modules/seas/encode_uri.c +++ b/modules/seas/encode_uri.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: xuri.c - * + * * Description: first trial to implement xuri - * + * * Version: 1.0 * Created: 16/11/05 18:07:24 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ @@ -63,9 +63,9 @@ * * 1: The first byte of the structure, is a * HEADER_START-based pointer to the beginning of the URI - * (including the "sip:"). - * 1: The next byte is the length of the uri, so URIMAX - * is 256 (enough...) + * (including the "sip:"). + * 1: The next byte is the length of the uri, so URIMAX + * is 256 (enough...) * 2: Flags specifying the parts that are present in the URI * * as follows: @@ -102,14 +102,14 @@ * The reason to have the OTHER and HEADERS flags at the * beginning(just after the strictly-uri stuff), is that it * will be necessary to know the length of the parameters - * section and the headers section. + * section and the headers section. * * The parameters can * appear in an arbitrary order, so they won't be following * the convention of transport-ttl-user-method-maddr-lr, so * we can't rely on the next pointer to compute the length - * of the previous pointer field, as the ttl param can - * appear before the transport param. so the parameter + * of the previous pointer field, as the ttl param can + * appear before the transport param. so the parameter * pointers must have 2 bytes: pointer+length. * */ @@ -226,7 +226,7 @@ int encode_uri2(char *hdr,int hdrlen,str uri_str, struct sip_uri *uri_parsed,uns flags1 |= SECURE_F; } }else goto error; - + payload[2]=flags1; payload[3]=flags2; j=i; @@ -321,7 +321,7 @@ int print_uri_junit_tests(char *hdrstart,int hdrlen,unsigned char *payload,int p char *ch_uriptr,*aux,*aux2,*aux3,*uritype=NULL,*secure=NULL; FILE *fp; - if ( (fp = fdopen(fd, "w*")) == NULL) + if ( (fp = fdopen(fd, "w*")) == NULL) return -1; uriidx=payload[0]; @@ -346,7 +346,7 @@ int print_uri_junit_tests(char *hdrstart,int hdrlen,unsigned char *payload,int p if(flags1 & USER_F){ fprintf(fp,"%.*s\n",(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; - }else + }else fprintf(fp,"(null)\n"); fprintf(fp,"%sgetUserPassword=(S)",prefix); if(flags1 & PASSWORD_F){ @@ -378,12 +378,12 @@ int print_uri_junit_tests(char *hdrstart,int hdrlen,unsigned char *payload,int p fprintf(fp,"%.*s=;",(int)(aux3-aux+k),aux); aux2=NULL;/*resets the parameterValue-start pointer*/ aux=aux3+1+k;/*points to the next parameter*/ - }else + }else if((aux3[k]==';'||(k==m)) && aux2!=NULL){ fprintf(fp,"%.*s=%.*s;",(int)(aux2-aux),aux,(int)(aux3-aux2-1+k),aux2+1); aux2=NULL; aux=aux3+1+k; - } else + } else if(aux3[k]=='='){ aux2=aux3+k; } @@ -402,12 +402,12 @@ int print_uri_junit_tests(char *hdrstart,int hdrlen,unsigned char *payload,int p fprintf(fp,"%.*s=;",(int)(aux3-aux+k),aux); aux2=NULL;/*resets the parameterValue-start pointer*/ aux=aux3+1+k;/*points to the next parameter*/ - }else + }else if((aux3[k]==';'||(k==m)) && aux2!=NULL){ fprintf(fp,"%.*s=%.*s;",(int)(aux2-aux),aux,(int)(aux3-aux2-1+k),aux2+1); aux2=NULL; aux=aux3+1+k; - } else + } else if(aux3[k]=='='){ aux2=aux3+k; } diff --git a/modules/seas/encode_uri.h b/modules/seas/encode_uri.h index 61b7d00fc27..52492276acf 100644 --- a/modules/seas/encode_uri.h +++ b/modules/seas/encode_uri.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/encode_via.c b/modules/seas/encode_via.c index 8d27626f9f9..98e6f9cd221 100644 --- a/modules/seas/encode_via.c +++ b/modules/seas/encode_via.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: encode_via.c - * + * * Description: functions to encode VIA headers - * + * * Version: 1.0 * Created: 21/11/05 02:30:50 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ diff --git a/modules/seas/encode_via.h b/modules/seas/encode_via.h index 91b18e21325..27e668b9638 100644 --- a/modules/seas/encode_via.h +++ b/modules/seas/encode_via.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/event_dispatcher.c b/modules/seas/event_dispatcher.c index b13d751d38e..e536b4067f1 100644 --- a/modules/seas/event_dispatcher.c +++ b/modules/seas/event_dispatcher.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -81,7 +81,7 @@ static int open_server_sockets(struct ip_addr *address,unsigned short port,int * /** Main loop for the Event Dispatcher process. - * + * */ int dispatcher_main_loop(void) { @@ -137,7 +137,7 @@ int dispatcher_main_loop(void) }else if (WIFSIGNALED(chld_status)) { LM_INFO("child process %d exited by a signal %d\n", chld,WTERMSIG(chld_status)); - }else if (WIFSTOPPED(chld_status)) + }else if (WIFSTOPPED(chld_status)) LM_INFO("child process %d stopped by a signal %d\n", chld,WSTOPSIG(chld_status)); for (as=as_list;as;as=as->next) { @@ -336,7 +336,7 @@ int dispatcher_main_loop(void) /** - * opens the server socket, which attends (accepts) the clients, that is: + * opens the server socket, which attends (accepts) the clients, that is: * params: * address: * address to which to listen @@ -405,7 +405,7 @@ union helper{ }; /** - * Sends event + * Sends event * * returns * 0 OK @@ -487,7 +487,7 @@ static int dispatch_relay(void) if(jlen) goto write_again; }else if(i==0){ - if (tries++ > MAX_WRITE_TRIES) { + if (tries++ > MAX_WRITE_TRIES) { LM_ERR("MAX WRITE TRIES !!!\n"); goto error; }else @@ -543,7 +543,7 @@ static inline int add_new_as(int event_idx,int action_idx,struct as_entry *as) } } } - /*TODO attention, this is pkg_malloc because only the Event_Dispatcher process + /*TODO attention, this is pkg_malloc because only the Event_Dispatcher process * has to use it !!*/ if(!(the_as->ev_buffer.s = pkg_malloc(AS_BUF_SIZE))){ LM_ERR("unable to alloc pkg mem for the event buffer\n"); @@ -556,8 +556,8 @@ static inline int add_new_as(int event_idx,int action_idx,struct as_entry *as) if(tmp->type==AS_TYPE) continue; for (j=0;ju.cs.num;j++) { - if (tmp->u.cs.as_names[j].len == the_as->name.len && - !memcmp(tmp->u.cs.as_names[j].s,the_as->name.s,the_as->name.len)) { + if (tmp->u.cs.as_names[j].len == the_as->name.len && + !memcmp(tmp->u.cs.as_names[j].s,the_as->name.s,the_as->name.len)) { if(tmp->u.cs.num==tmp->u.cs.registered){ LM_ERR("AS %.*s belongs to cluster %.*s which is already completed\n", the_as->name.len,the_as->name.s,tmp->name.len,tmp->name.s); @@ -738,14 +738,14 @@ static int handle_as_data(int fd) /** * This function processess the Application Server buffer. We do buffered * processing because it increases performance quite a bit. Any message - * sent from the AS comes with the first 2 bytes as an NBO unsigned short int + * sent from the AS comes with the first 2 bytes as an NBO unsigned short int * which says the length of the following message (header and payload). * This way, we avoid multiple small reads() to the socket, which (as we know), consumes * far more processor because of the kernel read(2) system call. The drawback * is the added complexity of mantaining a buffer, the bytes read, and looking * if there is a complete message already prepared. * - * Actions are supposed to be small, that's why BUF_SIZE is 2000 bytes length. + * Actions are supposed to be small, that's why BUF_SIZE is 2000 bytes length. * Most of the actions will be that size or less. That is why the 4 bytes telling the * length of the Action payload are included in its size. This way you can use a fixed size * buffer to receive the Actions and not need to be pkb_malloc'ing for each new event. @@ -853,9 +853,9 @@ int process_bind_action(as_p as,char *payload,int len) goto error; } for(si=xxx_listen;si;si=si->next){ - if(my_addr.af==si->address.af && - my_addr.len==si->address.len && - !memcmp(si->address.u.addr,my_addr.u.addr,my_addr.len) && + if(my_addr.af==si->address.af && + my_addr.len==si->address.len && + !memcmp(si->address.u.addr,my_addr.u.addr,my_addr.len) && port == si->port_no){ as->binds[i]=si; as->bound_processor[i]=processor_id; @@ -956,13 +956,13 @@ static int handle_unc_as_data(int fd) return -2; } unc_as_t[i].flags |= HAS_NAME; - /* the loop's upper bound, + /* the loop's upper bound, * if 'i' is in the lower part, then look for an unc_as in the upper part*/ k=(i>=MAX_UNC_AS_NR?MAX_UNC_AS_NR:2*MAX_UNC_AS_NR); /* the loop's lower bound */ for(j=(i>=MAX_UNC_AS_NR?0:MAX_UNC_AS_NR);jas=the_as; aping->msg=the_ping; aping->len=pinglen; - + lock_get(the_as->u.as.jain_pings.mutex); { if(the_as->u.as.jain_pings.count==the_as->u.as.jain_pings.size){ @@ -327,7 +327,7 @@ inline int init_pingtable(struct ha *table,int timeout,int maxpings) if (!(table->mutex=lock_alloc())){ LM_ERR("Unable to allocate a lock for the ping table\n"); goto error; - }else + }else lock_init(table->mutex); LM_ERR("alloc'ing %d bytes for %d pings\n",(int)(maxpings*sizeof(struct ping)),maxpings); if (0==(table->pings=shm_malloc(maxpings*sizeof(struct ping)))){ @@ -356,13 +356,13 @@ inline void destroy_pingtable(struct ha *table) /** * event_length(4) UNSIGNED INT includes the length 4 bytes itself - * type(1), + * type(1), * processor_id(1), 0 means nobody, 0xFF means everybody, 0next)) { - if (len== (*entry)->name.len && + if (len== (*entry)->name.len && !memcmp((*entry)->name.s,parameter,len)) { pkg_free(*param); *param=*entry; @@ -244,7 +256,7 @@ static int w_as_relay_t(struct sip_msg *msg, char *entry, char *foo) /** * returns <0 on error * 1 if (new transaction was created) or if (ACK for locally replied 200 with totag) or if (ACK for code>=300) - * 0 if it was a retransmission + * 0 if it was a retransmission */ new_tran = seas_f.tmb.t_newtran(msg); if(new_tran<0) { @@ -388,7 +400,7 @@ static int w_as_relay_sl(struct sip_msg *msg, char *as_name, char *foo) } //this shouln't be here, because it will remove the transaction from memory, but //if transaction isn't unref'ed iw will be released anyway at t_unref if kr (killreason)==0 - // a wait timer will be put to run with WT_TIME_OUT (5 seconds, within which the AS should respond) + // a wait timer will be put to run with WT_TIME_OUT (5 seconds, within which the AS should respond) // this is a bug !!! I think this is why we lose calls at high load !! //t_release(msg, 0, 0); seas_f.tmb.t_setkr(REQ_FWDED); @@ -406,17 +418,17 @@ static int w_as_relay_sl(struct sip_msg *msg, char *as_name, char *foo) /** * creates an as_event in shared memory and returns its address or NULL if error. * event_length(4) UNSIGNED INT includes the length 4 bytes itself - * type(1), + * type(1), * flags(4), * transport(1). - * src_ip_len(1), - * src_ip(4 or 16), - * dst_ip_len(1), - * dst_ip(4 or 16), - * src_port(2), - * dst_port(2), - * hash index(4), - * label(4), + * src_ip_len(1), + * src_ip(4 or 16), + * dst_ip_len(1), + * dst_ip(4 or 16), + * src_port(2), + * dst_port(2), + * hash index(4), + * label(4), * [cancelled hash_index,label] * */ @@ -529,16 +541,16 @@ char * create_as_event_t(struct cell *t,struct sip_msg *msg,char processor_id,in /** * creates an as_event in shared memory and returns its address or NULL if error. * event_length(4) UNSIGNED INT includes the length 4 bytes itself - * type(1), - * processor_id(4), + * type(1), + * processor_id(4), * flags(4), * transport(1). - * src_ip_len(1), - * src_ip(4 or 16), - * dst_ip_len(1), - * dst_ip(4 or 16), - * src_port(2), - * dst_port(2), + * src_ip_len(1), + * src_ip(4 or 16), + * dst_ip_len(1), + * dst_ip(4 or 16), + * src_port(2), + * dst_port(2), * */ char * create_as_event_sl(struct sip_msg *msg,char processor_id,int *evt_len,int flags) @@ -738,7 +750,7 @@ static int seas_exit(void) /** * search within a given AS, if any of the registered processors is bound - * to the receive_info structure passed. If there is one, it returns its + * to the receive_info structure passed. If there is one, it returns its * identifier (number between 0 and 128), otherwise it returns -1; */ char get_processor_id(struct receive_info *rcv,as_p as) diff --git a/modules/seas/seas.h b/modules/seas/seas.h index 8f1a6ec719e..0aa2e4a8b30 100644 --- a/modules/seas/seas.h +++ b/modules/seas/seas.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -127,7 +127,7 @@ struct cluster{ * when one matches, they will put the as pointer inside the event that should process * that event. * If eventually the as becomes unavailable, the dispatcher will set valid=false, which should be - * atomic operation. This way, we prevent having to put a mutex on the array, which would make + * atomic operation. This way, we prevent having to put a mutex on the array, which would make * it slower , as only one process could be accessing it at a time. */ struct as_entry{ @@ -143,7 +143,7 @@ struct as_entry{ extern struct as_entry *my_as; -extern struct seas_functions seas_f; +extern struct seas_functions seas_f; extern struct as_entry *as_list; typedef struct as_msg { diff --git a/modules/seas/seas_action.c b/modules/seas/seas_action.c index e850805a585..8691588c497 100644 --- a/modules/seas/seas_action.c +++ b/modules/seas/seas_action.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -203,7 +203,7 @@ static inline int process_input(int fd) * with all the SER processes. With a this ring buffer, the lock_get/release only * involve the SEAS processes. * This function scans the ping structures in the buffer, computing the elapsed time - * from when the ping was sent, so if the ping has timed out, it increases the + * from when the ping was sent, so if the ping has timed out, it increases the * timed_out_pings counter. All the timed-out pings are removed from the buffer (the * begin index is incremented). Because the pings are added always at the end * of the buffer, they will always be ordered in increasing time, so when we find one ping @@ -241,7 +241,7 @@ static inline int process_pings(struct ha *the_table) return 0; } -/* Because TransactionModule organizes statistics based on process_no, +/* Because TransactionModule organizes statistics based on process_no, * and process_no are only assigned to SER processes (not to Action dispatchers like us ;) * we have to simulate we are the FIFO process, so TM thinks that the transactions WE put * are put by the fifo process... @@ -381,13 +381,13 @@ int process_pong(struct ha *the_table,unsigned int seqno) * @param the_as Application Server structure which sent this action * @param action action payload * @param len the length of the payload - * + * * This function cancels a previously initiated UAC Transaction. * it receives the HashIndex and Label of the cell being cancelled - * and invokes t_cancel_uac from the transactionModule API which + * and invokes t_cancel_uac from the transactionModule API which * cancels the transaction. * - * Returns: + * Returns: * */ int ac_cancel(as_p the_as,char *action,int len) @@ -978,7 +978,7 @@ int ac_uac_req(as_p the_as,char *action,int len) LM_ERR("Headers missing (to,from,call-id,cseq)?"); goto error; } - if(!(get_from(my_msg)) || !(get_from(my_msg)->tag_value.s) || + if(!(get_from(my_msg)) || !(get_from(my_msg)->tag_value.s) || !(get_from(my_msg)->tag_value.len)){ as_action_fail_resp(uac_id,SE_UAC,"From tag missing",0); LM_ERR("From tag missing"); @@ -1411,7 +1411,7 @@ void uac_cleanup_cb(struct cell* t, int type, struct tmcb_params *rcvd_params) ev_info=(struct as_uac_param*)*rcvd_params->param; - if(ev_info) { + if(ev_info) { shm_free(ev_info); *rcvd_params->param=NULL; } @@ -1419,8 +1419,8 @@ void uac_cleanup_cb(struct cell* t, int type, struct tmcb_params *rcvd_params) /** * This function will be called from a SER process when a reply is received for - * the transaction. The SER processes only have acces to the EventDispatcher - * fifo (not to the ActionDispatcher) so EventDispatcher will be the one who + * the transaction. The SER processes only have acces to the EventDispatcher + * fifo (not to the ActionDispatcher) so EventDispatcher will be the one who * will send the event to the AppServer. * TODO WARNING !!! there's a clear MEMORY LEAK here, see exit: at the bottom of * the function... it should free ev_info !!!!!!!! diff --git a/modules/seas/seas_action.h b/modules/seas/seas_action.h index 1d4b6629438..e49aab9769d 100644 --- a/modules/seas/seas_action.h +++ b/modules/seas/seas_action.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/seas_error.h b/modules/seas/seas_error.h index 149c8355598..a5d80e645ff 100644 --- a/modules/seas/seas_error.h +++ b/modules/seas/seas_error.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/statistics.c b/modules/seas/statistics.c index bac136d2476..6f2adb9ef2f 100644 --- a/modules/seas/statistics.c +++ b/modules/seas/statistics.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -212,7 +212,7 @@ inline void action_stat(struct cell *t) * stats socket sould be an IP_address:port or unix://path/to_file * TODO handling unix sockets and IPv6 !! * - * returns + * returns * 0 if no stats * 1 if stats properly started * -1 if error @@ -298,7 +298,7 @@ int start_stats_server(char *stats_socket) * stats socket sould be an IP_address:port or unix://path/to_file * TODO handling unix sockets and IPv6 !! * - * returns + * returns * 0 if no stats * 1 if stats properly started * -1 if error @@ -341,7 +341,7 @@ void serve_stats(int fd) if(errno==EINTR){ continue; }else{ - LM_ERR("unknown error reading from socket\n"); + LM_ERR("unknown error reading from socket\n"); close(sock); /** and continue accept()'ing*/ break; diff --git a/modules/seas/statistics.h b/modules/seas/statistics.h index dfc22b29cf4..7a6e2b553fd 100644 --- a/modules/seas/statistics.h +++ b/modules/seas/statistics.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/utils.c b/modules/seas/utils.c index cdbd9681fa0..67b8f327142 100644 --- a/modules/seas/utils.c +++ b/modules/seas/utils.c @@ -14,26 +14,26 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * ===================================================================================== - * + * * Filename: utils.c - * - * Description: - * + * + * Description: + * * Version: 1.0 * Created: 19/01/06 15:50:33 CET * Revision: none * Compiler: gcc - * + * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com - * + * * ===================================================================================== */ #include diff --git a/modules/seas/utils.h b/modules/seas/utils.h index 132b417d79c..d6007f0a03a 100644 --- a/modules/seas/utils.h +++ b/modules/seas/utils.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/seas/xaddress.h b/modules/seas/xaddress.h index 1bb74dd8569..f4f68064b88 100644 --- a/modules/seas/xaddress.h +++ b/modules/seas/xaddress.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/signaling/README b/modules/signaling/README index ac9f562651b..fb1eabdba84 100644 --- a/modules/signaling/README +++ b/modules/signaling/README @@ -8,8 +8,7 @@ Anca-Maria Vamanu Copyright © 2008 FhG FOKUS Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -39,7 +38,7 @@ Chapter 1. Admin Guide and offers one function to be called by the modules that want to send a reply. - The logic behind th emodule is to first search if a transaction + The logic behind the module is to first search if a transaction is created and if so, send a state full reply, using tm module, otherwise send a stateless reply with the function exported by sl. In this way, the script writer still has the call on how diff --git a/modules/signaling/doc/signaling_admin.xml b/modules/signaling/doc/signaling_admin.xml index 9e24e9239c5..c02f56a01fc 100644 --- a/modules/signaling/doc/signaling_admin.xml +++ b/modules/signaling/doc/signaling_admin.xml @@ -12,7 +12,7 @@ that want to send a reply. - The logic behind th emodule is to first search if a transaction is + The logic behind the module is to first search if a transaction is created and if so, send a state full reply, using tm module, otherwise send a stateless reply with the function exported by sl. In this way, the script writer still has the call on how the transaction diff --git a/modules/signaling/signaling.c b/modules/signaling/signaling.c index c4557d49417..bab05ca16bc 100644 --- a/modules/signaling/signaling.c +++ b/modules/signaling/signaling.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -61,11 +61,24 @@ static cmd_export_t cmds[]= {0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_SILENT }, + { MOD_TYPE_DEFAULT, "sl", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports= { "signaling", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ 0, /* exported parameters */ 0, /* exported statistics */ @@ -88,10 +101,10 @@ static int mod_init(void) LM_NOTICE("initializing module ...\n"); /* load TM API*/ - if ( (load_tm=(load_tm_f)find_export("load_tm", 0, 0))) + if ( (load_tm=(load_tm_f)find_export("load_tm", 0, 0))) { if (load_tm( &tmb )==-1) - { + { LM_ERR("failed to load tm api\n"); return -1; } @@ -111,16 +124,16 @@ static int mod_init(void) if(!tm_loaded && !sl_loaded) { - LM_ERR("nighter 'tm' nor 'sl' module loaded! Sipreply module requires" + LM_ERR("neither 'tm' nor 'sl' module loaded! Sipreply module requires" " loading at least one of these two\n"); return -1; } - + return 0; } /* - * sig_send_reply - function to be called from script to send appropiate + * sig_send_reply - function to be called from script to send appropiate * replies (statefull or stateless) * */ int sig_send_reply(struct sip_msg* msg, char* str1, char* str2) @@ -137,7 +150,7 @@ int sig_send_reply(struct sip_msg* msg, char* str1, char* str2) } else { code_i = ((pv_elem_p)str1)->spec.pvp.pvn.u.isname.name.n; } - + if(((pv_elem_p)str2)->spec.getf!=NULL) { if(pv_printf_s(msg, (pv_elem_p)str2, &code_s)!=0 || code_s.len <=0) @@ -206,8 +219,8 @@ int sig_send_reply_mod(struct sip_msg* msg, int code, str* reason, str* to_tag) return 1; } -/* * - * fixup_sig_send_reply +/* * + * fixup_sig_send_reply */ static int fixup_sig_send_reply(void** param, int param_no) { diff --git a/modules/signaling/signaling.h b/modules/signaling/signaling.h index 2abd93a10e4..2d7292ea720 100644 --- a/modules/signaling/signaling.h +++ b/modules/signaling/signaling.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/sipcapture/README b/modules/sipcapture/README index f11be98bd46..8eeda57f6c3 100644 --- a/modules/sipcapture/README +++ b/modules/sipcapture/README @@ -30,7 +30,7 @@ Alexandr Dubovikov 1.3.1. db_url (str) 1.3.2. table_name (str) 1.3.3. capture_on (integer) - 1.3.4. duplicate_with_hep (integer) + 1.3.4. hep_capture_on (integer) 1.3.5. raw_ipip_capture_on (integer) 1.3.6. raw_moni_capture_on (integer) 1.3.7. raw_socket_listen (string) @@ -52,7 +52,7 @@ Alexandr Dubovikov 1.1. Set db_url parameter 1.2. Set sip_capture parameter 1.3. Set capture_on parameter - 1.4. Set duplicate_with_hep parameter + 1.4. Set hep_capture_on parameter 1.5. Set raw_ipip_capture_on parameter 1.6. Set raw_moni_capture_on parameter 1.7. Set raw_socket_listen parameter @@ -129,15 +129,15 @@ modparam("sipcapture", "table_name", "homer_capture") modparam("sipcapture", "capture_on", 1) ... -1.3.4. duplicate_with_hep (integer) +1.3.4. hep_capture_on (integer) Parameter to enable/disable capture of HEP (on(1)/off(0)) Default value is "0". - Example 1.4. Set duplicate_with_hep parameter + Example 1.4. Set hep_capture_on parameter ... -modparam("sipcapture", "duplicate_with_hep", 1) +modparam("sipcapture", "hep_capture_on", 1) ... 1.3.5. raw_ipip_capture_on (integer) diff --git a/modules/sipcapture/doc/sipcapture_admin.xml b/modules/sipcapture/doc/sipcapture_admin.xml index e8b2b7a425d..52819039fdd 100644 --- a/modules/sipcapture/doc/sipcapture_admin.xml +++ b/modules/sipcapture/doc/sipcapture_admin.xml @@ -132,7 +132,7 @@ modparam("sipcapture", "capture_on", 1)
- <varname>duplicate_with_hep</varname> (integer) + <varname>hep_capture_on</varname> (integer) Parameter to enable/disable capture of HEP (on(1)/off(0)) @@ -142,10 +142,10 @@ modparam("sipcapture", "capture_on", 1) - Set <varname>duplicate_with_hep</varname> parameter + Set <varname>hep_capture_on</varname> parameter ... -modparam("sipcapture", "duplicate_with_hep", 1) +modparam("sipcapture", "hep_capture_on", 1) ... diff --git a/modules/sipcapture/sipcapture.c b/modules/sipcapture/sipcapture.c index b764ef8e3ab..c5f823b8ada 100644 --- a/modules/sipcapture/sipcapture.c +++ b/modules/sipcapture/sipcapture.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * sipcapture module - helper module to capture sip messages * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -116,8 +116,8 @@ struct _sipcapture_object { str rtp_stat; int type; long long tmstamp; - str node; - str msg; + str node; + str msg; #ifdef STATISTICS stat_var *stat; #endif @@ -148,42 +148,42 @@ static str table_name = str_init("sip_capture"); static str id_column = str_init("id"); static str date_column = str_init("date"); static str micro_ts_column = str_init("micro_ts"); -static str method_column = str_init("method"); -static str reply_reason_column = str_init("reply_reason"); -static str ruri_column = str_init("ruri"); -static str ruri_user_column = str_init("ruri_user"); -static str from_user_column = str_init("from_user"); -static str from_tag_column = str_init("from_tag"); +static str method_column = str_init("method"); +static str reply_reason_column = str_init("reply_reason"); +static str ruri_column = str_init("ruri"); +static str ruri_user_column = str_init("ruri_user"); +static str from_user_column = str_init("from_user"); +static str from_tag_column = str_init("from_tag"); static str to_user_column = str_init("to_user"); -static str to_tag_column = str_init("to_tag"); +static str to_tag_column = str_init("to_tag"); static str pid_user_column = str_init("pid_user"); static str contact_user_column = str_init("contact_user"); -static str auth_user_column = str_init("auth_user"); +static str auth_user_column = str_init("auth_user"); static str callid_column = str_init("callid"); static str callid_aleg_column = str_init("callid_aleg"); -static str via_1_column = str_init("via_1"); -static str via_1_branch_column = str_init("via_1_branch"); -static str cseq_column = str_init("cseq"); -static str diversion_column = str_init("diversion_user"); -static str reason_column = str_init("reason"); -static str content_type_column = str_init("content_type"); -static str authorization_column = str_init("authorization"); +static str via_1_column = str_init("via_1"); +static str via_1_branch_column = str_init("via_1_branch"); +static str cseq_column = str_init("cseq"); +static str diversion_column = str_init("diversion_user"); +static str reason_column = str_init("reason"); +static str content_type_column = str_init("content_type"); +static str authorization_column = str_init("authorization"); static str user_agent_column = str_init("user_agent"); -static str source_ip_column = str_init("source_ip"); -static str source_port_column = str_init("source_port"); +static str source_ip_column = str_init("source_ip"); +static str source_port_column = str_init("source_port"); static str dest_ip_column = str_init("destination_ip"); -static str dest_port_column = str_init("destination_port"); -static str contact_ip_column = str_init("contact_ip"); +static str dest_port_column = str_init("destination_port"); +static str contact_ip_column = str_init("contact_ip"); static str contact_port_column = str_init("contact_port"); -static str orig_ip_column = str_init("originator_ip"); -static str orig_port_column = str_init("originator_port"); -static str rtp_stat_column = str_init("rtp_stat"); -static str proto_column = str_init("proto"); -static str family_column = str_init("family"); -static str type_column = str_init("type"); -static str node_column = str_init("node"); -static str msg_column = str_init("msg"); -static str capture_node = str_init("homer01"); +static str orig_ip_column = str_init("originator_ip"); +static str orig_port_column = str_init("originator_port"); +static str rtp_stat_column = str_init("rtp_stat"); +static str proto_column = str_init("proto"); +static str family_column = str_init("family"); +static str type_column = str_init("type"); +static str node_column = str_init("node"); +static str msg_column = str_init("msg"); +static str capture_node = str_init("homer01"); int raw_sock_desc = -1; /* raw socket used for ip packets */ @@ -229,7 +229,7 @@ struct hep_timehdr* heptime; * Exported functions */ static cmd_export_t cmds[] = { - {"sip_capture", (cmd_function)sip_capture, 0, 0, 0, + {"sip_capture", (cmd_function)sip_capture, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {0, 0, 0, 0, 0, 0} }; @@ -247,7 +247,7 @@ static param_export_t params[] = { {"db_url", STR_PARAM, &db_url.s }, {"table_name", STR_PARAM, &table_name.s }, {"id_column", STR_PARAM, &id_column.s }, - {"date_column", STR_PARAM, &date_column.s }, + {"date_column", STR_PARAM, &date_column.s }, {"micro_ts_column", STR_PARAM, µ_ts_column.s }, {"method_column", STR_PARAM, &method_column.s }, {"reply_reason_column", STR_PARAM, &reply_reason_column.s }, @@ -256,7 +256,7 @@ static param_export_t params[] = { {"from_user_column", STR_PARAM, &from_user_column.s }, {"from_tag_column", STR_PARAM, &from_tag_column.s }, {"to_user_column", STR_PARAM, &to_user_column.s }, - {"to_tag_column", STR_PARAM, &to_tag_column.s }, + {"to_tag_column", STR_PARAM, &to_tag_column.s }, {"pid_user_column", STR_PARAM, &pid_user_column.s }, {"contact_user_column", STR_PARAM, &contact_user_column.s }, {"auth_user_column", STR_PARAM, &auth_user_column.s }, @@ -271,9 +271,9 @@ static param_export_t params[] = { {"authorization_column", STR_PARAM, &authorization_column.s }, {"user_agent_column", STR_PARAM, &user_agent_column.s }, {"source_ip_column", STR_PARAM, &source_ip_column.s }, - {"source_port_column", STR_PARAM, &source_port_column.s}, + {"source_port_column", STR_PARAM, &source_port_column.s}, {"destination_ip_column", STR_PARAM, &dest_ip_column.s }, - {"destination_port_column", STR_PARAM, &dest_port_column.s }, + {"destination_port_column", STR_PARAM, &dest_port_column.s }, {"contact_ip_column", STR_PARAM, &contact_ip_column.s }, {"contact_port_column", STR_PARAM, &contact_port_column.s }, {"originator_ip_column", STR_PARAM, &orig_ip_column.s }, @@ -286,14 +286,14 @@ static param_export_t params[] = { {"msg_column", STR_PARAM, &msg_column.s }, {"capture_on", INT_PARAM, &capture_on }, {"capture_node", STR_PARAM, &capture_node.s }, - {"raw_sock_children", INT_PARAM, &raw_sock_children }, - {"hep_capture_on", INT_PARAM, &hep_capture_on }, - {"raw_socket_listen", STR_PARAM, &raw_socket_listen.s }, - {"raw_ipip_capture_on", INT_PARAM, &ipip_capture_on }, - {"raw_moni_capture_on", INT_PARAM, &moni_capture_on }, + {"raw_sock_children", INT_PARAM, &raw_sock_children }, + {"hep_capture_on", INT_PARAM, &hep_capture_on }, + {"raw_socket_listen", STR_PARAM, &raw_socket_listen.s }, + {"raw_ipip_capture_on", INT_PARAM, &ipip_capture_on }, + {"raw_moni_capture_on", INT_PARAM, &moni_capture_on }, {"raw_interface", STR_PARAM, &raw_interface.s }, - {"promiscious_on", INT_PARAM, &promisc_on }, - {"raw_moni_bpf_on", INT_PARAM, &bpf_on }, + {"promiscious_on", INT_PARAM, &promisc_on }, + {"raw_moni_bpf_on", INT_PARAM, &bpf_on }, {0, 0, 0} }; @@ -317,14 +317,23 @@ stat_export_t sipcapture_stats[] = { }; #endif - - +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /*! \brief module exports */ struct module_exports exports = { - "sipcapture", + "sipcapture", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /*!< dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /*!< Exported functions */ params, /*!< Exported parameters */ #ifdef STATISTICS @@ -347,6 +356,8 @@ static int mod_init(void) { struct ip_addr *ip = NULL; + init_db_url(db_url, 0); + #ifdef STATISTICS /* register statistics */ if (register_module_stats(exports.name, sipcapture_stats)!=0) @@ -370,45 +381,45 @@ static int mod_init(void) { date_column.len = strlen(date_column.s); id_column.len = strlen(id_column.s); micro_ts_column.len = strlen(micro_ts_column.s); - method_column.len = strlen(method_column.s); - reply_reason_column.len = strlen(reply_reason_column.s); - ruri_column.len = strlen(ruri_column.s); - ruri_user_column.len = strlen(ruri_user_column.s); - from_user_column.len = strlen(from_user_column.s); - from_tag_column.len = strlen(from_tag_column.s); + method_column.len = strlen(method_column.s); + reply_reason_column.len = strlen(reply_reason_column.s); + ruri_column.len = strlen(ruri_column.s); + ruri_user_column.len = strlen(ruri_user_column.s); + from_user_column.len = strlen(from_user_column.s); + from_tag_column.len = strlen(from_tag_column.s); to_user_column.len = strlen(to_user_column.s); pid_user_column.len = strlen(pid_user_column.s); contact_user_column.len = strlen(contact_user_column.s); - auth_user_column.len = strlen(auth_user_column.s); + auth_user_column.len = strlen(auth_user_column.s); callid_column.len = strlen(callid_column.s); - via_1_column.len = strlen(via_1_column.s); - via_1_branch_column.len = strlen(via_1_branch_column.s); - cseq_column.len = strlen(cseq_column.s); - diversion_column.len = strlen(diversion_column.s); - reason_column.len = strlen(reason_column.s); - content_type_column.len = strlen(content_type_column.s); - authorization_column.len = strlen(authorization_column.s); + via_1_column.len = strlen(via_1_column.s); + via_1_branch_column.len = strlen(via_1_branch_column.s); + cseq_column.len = strlen(cseq_column.s); + diversion_column.len = strlen(diversion_column.s); + reason_column.len = strlen(reason_column.s); + content_type_column.len = strlen(content_type_column.s); + authorization_column.len = strlen(authorization_column.s); user_agent_column.len = strlen(user_agent_column.s); - source_ip_column.len = strlen(source_ip_column.s); - source_port_column.len = strlen(source_port_column.s); + source_ip_column.len = strlen(source_ip_column.s); + source_port_column.len = strlen(source_port_column.s); dest_ip_column.len = strlen(dest_ip_column.s); - dest_port_column.len = strlen(dest_port_column.s); - contact_ip_column.len = strlen(contact_ip_column.s); + dest_port_column.len = strlen(dest_port_column.s); + contact_ip_column.len = strlen(contact_ip_column.s); contact_port_column.len = strlen(contact_port_column.s); - orig_ip_column.len = strlen(orig_ip_column.s); - orig_port_column.len = strlen(orig_port_column.s); - proto_column.len = strlen(proto_column.s); - family_column.len = strlen(family_column.s); - type_column.len = strlen(type_column.s); - rtp_stat_column.len = strlen(rtp_stat_column.s); - node_column.len = strlen(node_column.s); - msg_column.len = strlen(msg_column.s); - capture_node.len = strlen(capture_node.s); - - if(raw_socket_listen.s) - raw_socket_listen.len = strlen(raw_socket_listen.s); + orig_ip_column.len = strlen(orig_ip_column.s); + orig_port_column.len = strlen(orig_port_column.s); + proto_column.len = strlen(proto_column.s); + family_column.len = strlen(family_column.s); + type_column.len = strlen(type_column.s); + rtp_stat_column.len = strlen(rtp_stat_column.s); + node_column.len = strlen(node_column.s); + msg_column.len = strlen(msg_column.s); + capture_node.len = strlen(capture_node.s); + + if(raw_socket_listen.s) + raw_socket_listen.len = strlen(raw_socket_listen.s); if(raw_interface.s) - raw_interface.len = strlen(raw_interface.s); + raw_interface.len = strlen(raw_interface.s); /* Find a database module */ if (db_bind_mod(&db_url, &db_funcs)) @@ -424,18 +435,18 @@ static int mod_init(void) { } /*Check the table name*/ - if(!table_name.len) { + if(!table_name.len) { LM_ERR("table_name is not defined or empty\n"); return -1; } - + capture_on_flag = (int*)shm_malloc(sizeof(int)); if(capture_on_flag==NULL) { LM_ERR("no more shm memory left\n"); return -1; - } - + } + *capture_on_flag = capture_on; /* register DGRAM event IPv4 */ @@ -443,41 +454,41 @@ static int mod_init(void) { LM_ERR("failed to install failed to register homer recv callback IPv4\n"); return -1; } - + /* register DGRAM event IPv6 */ if (register_udprecv_cb(&hep_msg_received, 0, 40, 10) != 0) { LM_ERR("failed to install failed to register homer recv callback IPv6\n"); return -1; } - + if(ipip_capture_on && moni_capture_on) { LM_ERR("only one RAW mode is supported. Please disable ipip_capture_on or moni_capture_on\n"); - return -1; + return -1; } - + /* raw processes for IPIP encapsulation */ if (ipip_capture_on || moni_capture_on) { - + if(extract_host_port() && (((ip=str2ip(&raw_socket_listen)) == NULL) #ifdef USE_IPV6 && ((ip=str2ip6(&raw_socket_listen)) == NULL) #endif - )) - { - LM_ERR("bad RAW IP: %.*s\n", raw_socket_listen.len, raw_socket_listen.s); + )) + { + LM_ERR("bad RAW IP: %.*s\n", raw_socket_listen.len, raw_socket_listen.s); return -1; - } - + } + if(moni_capture_on && !moni_port_start) { LM_ERR("Please define port/portrange in 'raw_socket_listen', before \ activate monitoring capture\n"); - return -1; - } - - raw_sock_desc = raw_capture_socket(raw_socket_listen.len ? ip : 0, raw_interface.len ? &raw_interface : 0, - moni_port_start, moni_port_end , ipip_capture_on ? IPPROTO_IPIP : htons(0x0800)); - + return -1; + } + + raw_sock_desc = raw_capture_socket(raw_socket_listen.len ? ip : 0, raw_interface.len ? &raw_interface : 0, + moni_port_start, moni_port_end , ipip_capture_on ? IPPROTO_IPIP : htons(0x0800)); + if(raw_sock_desc < 0) { LM_ERR("could not initialize raw udp socket:" " %s (%d)\n", strerror(errno), errno); @@ -485,8 +496,8 @@ static int mod_init(void) { LM_ERR("could not initialize raw socket on startup" " due to inadequate permissions, please" " restart as root or with CAP_NET_RAW\n"); - - return -1; + + return -1; } if(promisc_on && raw_interface.len) { @@ -495,30 +506,30 @@ static int mod_init(void) { memcpy(ifr.ifr_name, raw_interface.s, raw_interface.len); -#ifdef __OS_linux +#ifdef __OS_linux if(ioctl(raw_sock_desc, SIOCGIFFLAGS, &ifr) < 0) { LM_ERR("could not get flags from interface [%.*s]:" - " %s (%d)\n", raw_interface.len, raw_interface.s, strerror(errno), errno); + " %s (%d)\n", raw_interface.len, raw_interface.s, strerror(errno), errno); goto error; } - - ifr.ifr_flags |= IFF_PROMISC; - + + ifr.ifr_flags |= IFF_PROMISC; + if (ioctl(raw_sock_desc, SIOCSIFFLAGS, &ifr) < 0) { LM_ERR("could not set PROMISC flag to interface [%.*s]:" - " %s (%d)\n", raw_interface.len, raw_interface.s, strerror(errno), errno); - goto error; + " %s (%d)\n", raw_interface.len, raw_interface.s, strerror(errno), errno); + goto error; } #endif - - } + + } } return 0; -#ifdef __OS_linux +#ifdef __OS_linux error: if(raw_sock_desc) close(raw_sock_desc); - return -1; + return -1; #endif } @@ -528,10 +539,10 @@ int extract_host_port(void) if(raw_socket_listen.len) { char *p1,*p2; p1 = raw_socket_listen.s; - + if( (p1 = strrchr(p1, ':')) != 0 ) { *p1 = '\0'; - p1++; + p1++; p2=p1; if((p2 = strrchr(p2, '-')) != 0 ) { p2++; @@ -540,7 +551,7 @@ int extract_host_port(void) } moni_port_start = atoi(p1); raw_socket_listen.len = strlen(raw_socket_listen.s); - } + } return 1; } return 0; @@ -552,41 +563,41 @@ static int child_init(int rank) if (rank==PROC_MAIN || rank==PROC_TCP_MAIN) return 0; /* do nothing for the main process */ - + if (db_url.s) return sipcapture_db_init(&db_url); - + LM_ERR("db_url is empty"); - + return 0; } int sipcapture_db_init(const str* db_url) { - - if(db_funcs.init == 0) { - LM_CRIT("null dbf \n"); - goto error; + + if(db_funcs.init == 0) { + LM_CRIT("null dbf\n"); + goto error; } - + db_con = db_funcs.init(db_url); if (!db_con) { LM_ERR("unable to connect database\n"); return -1; - } - + } + if (db_funcs.use_table(db_con, &table_name) < 0) { LM_ERR("use_table failed\n"); return -1; } - + heptime = (struct hep_timehdr*)pkg_malloc(sizeof(struct hep_timehdr)); if(heptime==NULL) { LM_ERR("no more pkg memory left\n"); return -1; - } - + } + return 0; @@ -600,8 +611,8 @@ void sipcapture_db_close(void) db_funcs.close(db_con); db_con=0; } - - if(heptime) pkg_free(heptime); + + if(heptime) pkg_free(heptime); } static void raw_socket_process(int rank) @@ -610,12 +621,12 @@ static void raw_socket_process(int rank) LM_ERR("unable to open database connection\n"); return; } - + raw_capture_rcv_loop(raw_sock_desc, moni_port_start, moni_port_end, moni_capture_on ? 0 : 1); /* Destroy DB socket */ - sipcapture_db_close(); + sipcapture_db_close(); } @@ -625,8 +636,8 @@ static void destroy(void) sipcapture_db_close(); if (capture_on_flag) - shm_free(capture_on_flag); - + shm_free(capture_on_flag); + if(raw_sock_desc > 0) { if(promisc_on && raw_interface.len) { #ifdef __OS_linux @@ -636,10 +647,10 @@ static void destroy(void) LM_ERR("could not remove PROMISC flag from interface [%.*s]:" " %s (%d)\n", raw_interface.len, raw_interface.s, strerror(errno), errno); } -#endif - } - close(raw_sock_desc); - } +#endif + } + close(raw_sock_desc); + } } /** @@ -665,8 +676,8 @@ int hep_msg_received(int sockfd, struct receive_info *ri, str *msg, void* param) if(!hep_capture_on) { LM_ERR("HEP is not enabled\n"); - return 0; - } + return 0; + } buf = msg->s; @@ -744,14 +755,14 @@ int hep_msg_received(int sockfd, struct receive_info *ri, str *msg, void* param) return 0; } - /* timming */ + /* timming */ if(heph->hp_v == 2) { offset+=sizeof(struct hep_timehdr); - heptime_tmp = (struct hep_timehdr*) hep_payload; + heptime_tmp = (struct hep_timehdr*) hep_payload; heptime->tv_sec = heptime_tmp->tv_sec; - heptime->tv_usec = heptime_tmp->tv_usec; - heptime->captid = heptime_tmp->captid; + heptime->tv_usec = heptime_tmp->tv_usec; + heptime->captid = heptime_tmp->captid; } /* fill ip from the packet to dst_ip && to */ @@ -784,9 +795,9 @@ int hep_msg_received(int sockfd, struct receive_info *ri, str *msg, void* param) /* cut off the offset */ msg->len -= offset; p = buf + offset; - + memmove(buf, p, BUF_SIZE+1); - + return -1; } @@ -798,7 +809,7 @@ static int sip_capture_prepare(struct sip_msg* msg) LM_ERR("cannot parse headers\n"); return -1; } - + return 0; } @@ -813,42 +824,42 @@ static int sip_capture_store(struct _sipcapture_object *sco) LM_DBG("invalid parameter\n"); return -1; } - - db_keys[0] = &id_column; + + db_keys[0] = &id_column; db_vals[0].type = DB_INT; db_vals[0].val.int_val = 0; - + db_keys[1] = &date_column; db_vals[1].type = DB_DATETIME; - db_vals[1].val.time_val = time(NULL); + db_vals[1].val.time_val = time(NULL); - db_keys[2] = µ_ts_column; - db_vals[2].type = DB_BIGINT; + db_keys[2] = µ_ts_column; + db_vals[2].type = DB_BIGINT; db_vals[2].val.bigint_val = sco->tmstamp; - + db_keys[3] = &method_column; db_vals[3].type = DB_STR; - db_vals[3].val.str_val = sco->method; - + db_vals[3].val.str_val = sco->method; + db_keys[4] = &reply_reason_column; db_vals[4].type = DB_STR; - db_vals[4].val.str_val = sco->reply_reason; - + db_vals[4].val.str_val = sco->reply_reason; + db_keys[5] = &ruri_column; db_vals[5].type = DB_STR; - db_vals[5].val.str_val = sco->ruri; - + db_vals[5].val.str_val = sco->ruri; + db_keys[6] = &ruri_user_column; db_vals[6].type = DB_STR; - db_vals[6].val.str_val = sco->ruri_user; - + db_vals[6].val.str_val = sco->ruri_user; + db_keys[7] = &from_user_column; db_vals[7].type = DB_STR; - db_vals[7].val.str_val = sco->from_user; - + db_vals[7].val.str_val = sco->from_user; + db_keys[8] = &from_tag_column; db_vals[8].type = DB_STR; - db_vals[8].val.str_val = sco->from_tag; + db_vals[8].val.str_val = sco->from_tag; db_keys[9] = &to_user_column; db_vals[9].type = DB_STR; @@ -857,19 +868,19 @@ static int sip_capture_store(struct _sipcapture_object *sco) db_keys[10] = &to_tag_column; db_vals[10].type = DB_STR; db_vals[10].val.str_val = sco->to_tag; - + db_keys[11] = &pid_user_column; db_vals[11].type = DB_STR; db_vals[11].val.str_val = sco->pid_user; db_keys[12] = &contact_user_column; db_vals[12].type = DB_STR; - db_vals[12].val.str_val = sco->contact_user; + db_vals[12].val.str_val = sco->contact_user; db_keys[13] = &auth_user_column; db_vals[13].type = DB_STR; db_vals[13].val.str_val = sco->auth_user; - + db_keys[14] = &callid_column; db_vals[14].type = DB_STR; db_vals[14].val.str_val = sco->callid; @@ -877,23 +888,23 @@ static int sip_capture_store(struct _sipcapture_object *sco) db_keys[15] = &callid_aleg_column; db_vals[15].type = DB_STR; db_vals[15].val.str_val = sco->callid_aleg; - + db_keys[16] = &via_1_column; db_vals[16].type = DB_STR; db_vals[16].val.str_val = sco->via_1; - + db_keys[17] = &via_1_branch_column; db_vals[17].type = DB_STR; db_vals[17].val.str_val = sco->via_1_branch; db_keys[18] = &cseq_column; db_vals[18].type = DB_STR; - db_vals[18].val.str_val = sco->cseq; - + db_vals[18].val.str_val = sco->cseq; + db_keys[19] = &reason_column; db_vals[19].type = DB_STR; db_vals[19].val.str_val = sco->reason; - + db_keys[20] = &content_type_column; db_vals[20].type = DB_STR; db_vals[20].val.str_val = sco->content_type; @@ -905,81 +916,81 @@ static int sip_capture_store(struct _sipcapture_object *sco) db_keys[22] = &user_agent_column; db_vals[22].type = DB_STR; db_vals[22].val.str_val = sco->user_agent; - + db_keys[23] = &source_ip_column; db_vals[23].type = DB_STR; db_vals[23].val.str_val = sco->source_ip; - - db_keys[24] = &source_port_column; + + db_keys[24] = &source_port_column; db_vals[24].type = DB_INT; db_vals[24].val.int_val = sco->source_port; - + db_keys[25] = &dest_ip_column; db_vals[25].type = DB_STR; db_vals[25].val.str_val = sco->destination_ip; - - db_keys[26] = &dest_port_column; + + db_keys[26] = &dest_port_column; db_vals[26].type = DB_INT; - db_vals[26].val.int_val = sco->destination_port; - + db_vals[26].val.int_val = sco->destination_port; + db_keys[27] = &contact_ip_column; db_vals[27].type = DB_STR; db_vals[27].val.str_val = sco->contact_ip; - - db_keys[28] = &contact_port_column; + + db_keys[28] = &contact_port_column; db_vals[28].type = DB_INT; db_vals[28].val.int_val = sco->contact_port; - + db_keys[29] = &orig_ip_column; db_vals[29].type = DB_STR; db_vals[29].val.str_val = sco->originator_ip; - - db_keys[30] = &orig_port_column; + + db_keys[30] = &orig_port_column; db_vals[30].type = DB_INT; - db_vals[30].val.int_val = sco->originator_port; - - db_keys[31] = &proto_column; + db_vals[30].val.int_val = sco->originator_port; + + db_keys[31] = &proto_column; db_vals[31].type = DB_INT; - db_vals[31].val.int_val = sco->proto; + db_vals[31].val.int_val = sco->proto; - db_keys[32] = &family_column; + db_keys[32] = &family_column; db_vals[32].type = DB_INT; - db_vals[32].val.int_val = sco->family; - - db_keys[33] = &rtp_stat_column; + db_vals[32].val.int_val = sco->family; + + db_keys[33] = &rtp_stat_column; db_vals[33].type = DB_STR; - db_vals[33].val.str_val = sco->rtp_stat; - - db_keys[34] = &type_column; + db_vals[33].val.str_val = sco->rtp_stat; + + db_keys[34] = &type_column; db_vals[34].type = DB_INT; - db_vals[34].val.int_val = sco->type; + db_vals[34].val.int_val = sco->type; db_keys[35] = &node_column; db_vals[35].type = DB_STR; db_vals[35].val.str_val = sco->node; - + db_keys[36] = &msg_column; db_vals[36].type = DB_BLOB; - db_vals[36].val.blob_val = sco->msg; - + db_vals[36].val.blob_val = sco->msg; + /* no field can be null */ for (i=0;istat, 1); -#endif +#endif return 1; error: @@ -990,15 +1001,15 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) { struct _sipcapture_object sco; struct sip_uri from, to, pai, contact; - struct hdr_field *hook1 = NULL; - struct hdr_field *tmphdr[4]; - contact_body_t* cb=0; + struct hdr_field *hook1 = NULL; + struct hdr_field *tmphdr[4]; + contact_body_t* cb=0; char buf_ip[IP_ADDR_MAX_STR_SIZE+12]; char *port_str = NULL, *tmp = NULL; struct timeval tvb; struct timezone tz; char tmp_node[100]; - + gettimeofday( &tvb, &tz ); if(msg==NULL) { @@ -1012,16 +1023,16 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) LM_DBG("capture off...\n"); return -1; } - + if(sip_capture_prepare(msg)<0) return -1; if(heptime && heptime->tv_sec != 0) { - sco.tmstamp = (unsigned long long)heptime->tv_sec*1000000+heptime->tv_usec; /* micro ts */ + sco.tmstamp = (unsigned long long)heptime->tv_sec*1000000+heptime->tv_usec; /* micro ts */ snprintf(tmp_node, 100, "%.*s:%i", capture_node.len, capture_node.s, heptime->captid); sco.node.s = tmp_node; sco.node.len = strlen(tmp_node); } - else { + else { sco.tmstamp = (unsigned long long)tvb.tv_sec*1000000+tvb.tv_usec; /* micro ts */ sco.node = capture_node; } @@ -1029,28 +1040,28 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) if(msg->first_line.type == SIP_REQUEST) { if (parse_sip_msg_uri(msg)<0) return -1; - + sco.method = msg->first_line.u.request.method; EMPTY_STR(sco.reply_reason); - + sco.ruri = msg->first_line.u.request.uri; - sco.ruri_user = msg->parsed_uri.user; + sco.ruri_user = msg->parsed_uri.user; } else if(msg->first_line.type == SIP_REPLY) { sco.method = msg->first_line.u.reply.status; sco.reply_reason = msg->first_line.u.reply.reason; EMPTY_STR(sco.ruri); - EMPTY_STR(sco.ruri_user); + EMPTY_STR(sco.ruri_user); } - else { - LM_ERR("unknow type [%i]\n", msg->first_line.type); + else { + LM_ERR("unknow type [%i]\n", msg->first_line.type); EMPTY_STR(sco.method); EMPTY_STR(sco.reply_reason); EMPTY_STR(sco.ruri); EMPTY_STR(sco.ruri_user); } - + /* Parse FROM */ if(msg->from) { @@ -1063,9 +1074,9 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) LM_ERR("bad from dropping"" packet\n"); return -1; } - + sco.from_user = from.user; - sco.from_tag = get_from(msg)->tag_value; + sco.from_tag = get_from(msg)->tag_value; } else { EMPTY_STR(sco.from_user); @@ -1079,21 +1090,21 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) LM_ERR("bad to dropping"" packet\n"); return -1; } - + sco.to_user = to.user; - if(get_to(msg)->tag_value.len) - sco.to_tag = get_to(msg)->tag_value; + if(get_to(msg)->tag_value.len) + sco.to_tag = get_to(msg)->tag_value; else { EMPTY_STR(sco.to_tag); } } - else { + else { EMPTY_STR(sco.to_user); EMPTY_STR(sco.to_tag); } - + /* Call-id */ if(msg->callid) sco.callid = msg->callid->body; else { EMPTY_STR(sco.callid); } - + /* P-Asserted-Id */ if(msg->pai && (parse_pai_header(msg) == 0)) { @@ -1102,11 +1113,11 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) } else { LM_DBG("PARSE PAI: (%.*s)\n",get_pai(msg)->uri.len, get_pai(msg)->uri.s); - sco.pid_user = pai.user; + sco.pid_user = pai.user; } - } + } else if(msg->ppi && (parse_ppi_header(msg) == 0)) { - + if (parse_uri(get_ppi(msg)->uri.s, get_ppi(msg)->uri.len, &pai)<0){ LM_DBG("bad ppi: method:[%.*s] CID: [%.*s]\n", sco.method.len, sco.method.s, sco.callid.len, sco.callid.s); } @@ -1115,13 +1126,13 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) } } else { EMPTY_STR(sco.pid_user); } - + /* Auth headers */ if(msg->proxy_auth != NULL) hook1 = msg->proxy_auth; else if(msg->authorization != NULL) hook1 = msg->authorization; if(hook1) { - if(parse_credentials(hook1) == 0) sco.auth_user = ((auth_body_t*)(hook1->parsed))->digest.username.user; + if(parse_credentials(hook1) == 0) sco.auth_user = ((auth_body_t*)(hook1->parsed))->digest.username.user; else { EMPTY_STR(sco.auth_user); } } else { EMPTY_STR(sco.auth_user);} @@ -1149,47 +1160,47 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) sco.callid_aleg = tmphdr[0]->body; } else { EMPTY_STR(sco.callid_aleg);} - + /* VIA 1 */ sco.via_1 = msg->h_via1->body; /* Via branch */ if(msg->via1->branch) sco.via_1_branch = msg->via1->branch->value; else { EMPTY_STR(sco.via_1_branch); } - - /* CSEQ */ + + /* CSEQ */ if(msg->cseq) sco.cseq = msg->cseq->body; else { EMPTY_STR(sco.cseq); } - - /* Reason */ + + /* Reason */ if((tmphdr[1] = get_header_by_static_name(msg,"Reason")) != NULL) { sco.reason = tmphdr[1]->body; - } + } else { EMPTY_STR(sco.reason); } - /* Diversion */ + /* Diversion */ if(msg->diversion) sco.diversion = msg->diversion->body; else { EMPTY_STR(sco.diversion);} - - /* Content-type */ + + /* Content-type */ if(msg->content_type) sco.content_type = msg->content_type->body; else { EMPTY_STR(sco.content_type);} - - /* User-Agent */ + + /* User-Agent */ if(msg->user_agent) sco.user_agent = msg->user_agent->body; else { EMPTY_STR(sco.user_agent);} - /* Contact */ + /* Contact */ if(msg->contact && cb) { sco.contact_ip = contact.host; str2int(&contact.port, (unsigned int*)&sco.contact_port); } else { - EMPTY_STR(sco.contact_ip); + EMPTY_STR(sco.contact_ip); sco.contact_port = 0; } - - /* X-OIP */ + + /* X-OIP */ if((tmphdr[2] = get_header_by_static_name(msg,"X-OIP")) != NULL) { sco.originator_ip = tmphdr[2]->body; /* Originator port. Should be parsed from XOIP header as ":" param */ @@ -1199,56 +1210,56 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) port_str = tmp + 1; sco.originator_port = strtol(port_str, NULL, 10); } - else sco.originator_port = 0; + else sco.originator_port = 0; } else { EMPTY_STR(sco.originator_ip); sco.originator_port = 0; - } - - /* X-RTP-Stat */ + } + + /* X-RTP-Stat */ if((tmphdr[3] = get_header_by_static_name(msg,"X-RTP-Stat")) != NULL) { sco.rtp_stat = tmphdr[3]->body; - } - /* P-RTP-Stat */ + } + /* P-RTP-Stat */ else if((tmphdr[3] = get_header_by_static_name(msg,"P-RTP-Stat")) != NULL) { sco.rtp_stat = tmphdr[3]->body; - } - else { EMPTY_STR(sco.rtp_stat); } - - + } + else { EMPTY_STR(sco.rtp_stat); } + + /* PROTO TYPE */ sco.proto = msg->rcv.proto; - + /* FAMILY TYPE */ sco.family = msg->rcv.src_ip.af; - + /* MESSAGE TYPE */ sco.type = msg->first_line.type; - - /* MSG */ + + /* MSG */ sco.msg.s = msg->buf; - sco.msg.len = msg->len; + sco.msg.len = msg->len; //EMPTY_STR(sco.msg); - + /* IP source and destination */ - + strcpy(buf_ip, ip_addr2a(&msg->rcv.src_ip)); sco.source_ip.s = buf_ip; sco.source_ip.len = strlen(buf_ip); - sco.source_port = msg->rcv.src_port; + sco.source_port = msg->rcv.src_port; /*source ip*/ sco.destination_ip.s = ip_addr2a(&msg->rcv.dst_ip); sco.destination_ip.len = strlen(sco.destination_ip.s); sco.destination_port = msg->rcv.dst_port; - + LM_DBG("src_ip: [%.*s]\n", sco.source_ip.len, sco.source_ip.s); LM_DBG("dst_ip: [%.*s]\n", sco.destination_ip.len, sco.destination_ip.s); - + LM_DBG("dst_port: [%d]\n", sco.destination_port); LM_DBG("src_port: [%d]\n", sco.source_port); - + #ifdef STATISTICS if(msg->first_line.type==SIP_REPLY) { sco.stat = sipcapture_rpl; @@ -1274,9 +1285,9 @@ static int sip_capture(struct sip_msg *msg, char *s1, char *s2) static struct mi_root* sip_capture_mi(struct mi_root* cmd_tree, void* param ) { struct mi_node* node; - - struct mi_node *rpl; - struct mi_root *rpl_tree ; + + struct mi_node *rpl; + struct mi_root *rpl_tree ; node = cmd_tree->node.kids; if(node == NULL) { @@ -1315,7 +1326,7 @@ static struct mi_root* sip_capture_mi(struct mi_root* cmd_tree, void* param ) int raw_capture_socket(struct ip_addr* ip, str* iface, int port_start, int port_end, int proto) { - int sock = -1; + int sock = -1; union sockaddr_union su; #ifdef __OS_linux @@ -1323,7 +1334,7 @@ int raw_capture_socket(struct ip_addr* ip, str* iface, int port_start, int port_ char short_ifname[sizeof(int)]; int ifname_len; char* ifname; -#endif +#endif //0x0003 - all packets if(proto == IPPROTO_IPIP) { sock = socket(PF_INET, SOCK_RAW, proto); @@ -1335,9 +1346,9 @@ int raw_capture_socket(struct ip_addr* ip, str* iface, int port_start, int port_ #endif else { LM_ERR("LSF currently suppoted only on linux\n"); - goto error; + goto error; } - + if (sock==-1) goto error; @@ -1371,7 +1382,7 @@ int raw_capture_socket(struct ip_addr* ip, str* iface, int port_start, int port_ pf.filter = (struct sock_filter *) BPF_code; if(!port_end) port_end = port_start; - + /* Start PORT */ BPF_code[5] = (struct sock_filter)BPF_JUMP(0x35, port_start, 0, 1); BPF_code[8] = (struct sock_filter)BPF_JUMP(0x35, port_start, 11, 13); @@ -1379,13 +1390,13 @@ int raw_capture_socket(struct ip_addr* ip, str* iface, int port_start, int port_ BPF_code[19] = (struct sock_filter)BPF_JUMP(0x35, port_start, 0, 2); /* Stop PORT */ BPF_code[6] = (struct sock_filter)BPF_JUMP(0x25, port_end, 0, 14); - BPF_code[17] = (struct sock_filter)BPF_JUMP(0x25, port_end, 0, 3); - BPF_code[20] = (struct sock_filter)BPF_JUMP(0x25, port_end, 1, 0); - + BPF_code[17] = (struct sock_filter)BPF_JUMP(0x25, port_end, 0, 3); + BPF_code[20] = (struct sock_filter)BPF_JUMP(0x25, port_end, 1, 0); + /* Attach the filter to the socket */ if(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) < 0 ) { LM_ERR("setsockopt filter: [%s] [%d]\n", strerror(errno), errno); - } + } } #endif @@ -1399,11 +1410,11 @@ int raw_capture_socket(struct ip_addr* ip, str* iface, int port_start, int port_ } return sock; - + error: if (sock!=-1) close(sock); - return -1; - + return -1; + } /* Local raw receive loop */ @@ -1419,7 +1430,7 @@ int raw_capture_rcv_loop(int rsock, int port1, int port2, int ipip) { struct udphdr *udph; char* udph_start; unsigned short udp_len; - int offset = 0; + int offset = 0; char* end; unsigned short dst_port; unsigned short src_port; @@ -1443,25 +1454,25 @@ int raw_capture_rcv_loop(int rsock, int port1, int port2, int ipip) { } end=buf+len; - + offset = ipip ? sizeof(struct ip) : ETHHDR; - + if (len < (sizeof(struct ip)+sizeof(struct udphdr) + offset)) { LM_DBG("received small packet: %d. Ignore it\n",len); continue; } - - iph = (struct ip*) (buf + offset); + + iph = (struct ip*) (buf + offset); offset+=iph->ip_hl*4; udph_start = buf+offset; - + udph = (struct udphdr*) udph_start; offset +=sizeof(struct udphdr); if ((buf+offset)>end){ - continue; + continue; } udp_len=ntohs(udph->uh_ulen); @@ -1473,7 +1484,7 @@ int raw_capture_rcv_loop(int rsock, int port1, int port2, int ipip) { continue; } } - + /*FIL IPs*/ dst_ip.af=AF_INET; dst_ip.len=4; @@ -1488,13 +1499,13 @@ int raw_capture_rcv_loop(int rsock, int port1, int port2, int ipip) { src_ip.u.addr32[0]=iph->ip_src.s_addr; ip_addr2su(&from, &src_ip, src_port); su_setport(&from, src_port); - + ri.src_su=from; su2ip_addr(&ri.src_ip, &from); ri.src_port=src_port; su2ip_addr(&ri.dst_ip, &to); ri.dst_port=dst_port; - ri.proto=PROTO_UDP; + ri.proto=PROTO_UDP; /* cut off the offset */ len -= offset; @@ -1505,17 +1516,17 @@ int raw_capture_rcv_loop(int rsock, int port1, int port2, int ipip) { } LM_DBG("PORT: [%d] and [%d]\n", port1, port2); - - if((!port1 && !port2) - || (src_port >= port1 && src_port <= port2) || (dst_port >= port1 && dst_port <= port2) + + if((!port1 && !port2) + || (src_port >= port1 && src_port <= port2) || (dst_port >= port1 && dst_port <= port2) || (!port2 && (src_port == port1 || dst_port == port1))) receive_msg(buf+offset, len, &ri); } - + return 0; error: return -1; - + } diff --git a/modules/sipcapture/sipcapture.h b/modules/sipcapture/sipcapture.h index 75cdec75560..f8d478dd6be 100644 --- a/modules/sipcapture/sipcapture.h +++ b/modules/sipcapture/sipcapture.h @@ -46,7 +46,7 @@ struct hep_hdr{ struct hep_timehdr{ u_int32_t tv_sec; /* seconds */ u_int32_t tv_usec; /* useconds */ - u_int16_t captid; /* Capture ID node */ + u_int16_t captid; /* Capture ID node */ }; struct hep_iphdr{ diff --git a/modules/sipmsgops/README b/modules/sipmsgops/README index ac572c8ffb5..61c9147e980 100644 --- a/modules/sipmsgops/README +++ b/modules/sipmsgops/README @@ -31,8 +31,7 @@ Razvan Crainea Copyright © 2003 FhG FOKUS Revision History - Revision $Revision: 7480 $ $Date: 2010-12-07 19:37:12 +0200 - (Tue, 07 Dec 2010) $ + Revision $Revision: 7480 $ $Date$ __________________________________________________________ Table of Contents @@ -63,7 +62,7 @@ Razvan Crainea 1.3.14. is_privacy(privacy_type) 1.3.15. strip_body(), strip_body(mime) 1.3.16. add_body(body_text, new_content_type) - 1.3.17. sipmsg_validate([flags]) + 1.3.17. sipmsg_validate([flags[,result_pvar]]) 1.3.18. codec_exists (name [,clock] ) 1.3.19. codec_delete (name [,clock] ) 1.3.20. codec_move_up (name [,clock] ) @@ -503,7 +502,7 @@ d in multipart add_body("Hello World!", "text/plain"); ... -1.3.17. sipmsg_validate([flags]) +1.3.17. sipmsg_validate([flags[,result_pvar]]) The function returns true if the SIP message is properly built according to SIP RFC3261. It verifies if the mandatory headers @@ -517,16 +516,47 @@ add_body("Hello World!", "text/plain"); * 'm' - don't check the Max-Forwards header. * 'r' - checks the R-URI and whether the domain contains valid characters. + * 'f' - checks the URI of the 'From' field and whether the + domain contains valid characters. + * 't' - checks the URI of the 'To' field and whether the + domain contains valid characters. + * 'c' - checks the URI of the 'Contact' field. + + The result_pvar parameter sets resulting pvar with text error + reason in case of negative result ( easy for logging or + propagating the rejection reason back to the bogus UA ) This function can return the following codes: * 1 - the message is RFC3261 compliant and has been successfully validated. - * -1 - the message is not RFC3261 compliant. - * -2 - signals a parsing error. - * -3 - invalid SDP body. - * -4 - invalid headers body. - * -5 - invalid R-URI. - * -6 - invalid R-URI domain. + * -1 - No SIP message + * -2 - Header Parsing error + * -3 - No Call-ID header + * -4 - No Content-Length header for transports that require + it ( eg. TCP ) + * -5 - Invalid Content-Length, other from the size of the + actual body + * -6 - SDP body parsing error. + * -7 - No Cseq header. + * -8 - No From header. + * -9 - No To header. + * -10 - No Via header. + * -11 - Request URI parse error. + * -12 - Bad hostname in R-URI. + * -13 - No Max-Forward header. + * -14 - No Contact header. + * -15 - Path user for non-Register request. + * -16 - No allow header in 405 reply. + * -17 - No Min-Expire header in 423 reply. + * -18 - No Proxy-Authorize header in 407 reply. + * -19 - No Unsupported header in 420 reply. + * -20 - No WWW-Authorize header in 401 reply. + * -21 - No Content-Type header + * -22 - To header parse error + * -23 - From header parse error + * -24 - Bad hostname in To header + * -25 - Bad hostname in From header + * -26 - Contact header parse error * -255 - undefined errors. This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, diff --git a/modules/sipmsgops/codecs.c b/modules/sipmsgops/codecs.c index e5021401927..96a18667c8d 100644 --- a/modules/sipmsgops/codecs.c +++ b/modules/sipmsgops/codecs.c @@ -70,7 +70,7 @@ int fixup_codec(void** param, int param_no) int fixup_codec_regexp(void** param, int param_no) { - return fixup_regexp_null(param, param_no); + return fixup_regexp_dynamic_null(param, param_no); } @@ -122,7 +122,7 @@ static int create_codec_lumps(struct sip_msg * msg) cur_cell->payloads.len,0); lumps[count] = l; - + if( l == NULL) { LM_ERR("Error adding delete lump for m=\n"); @@ -561,6 +561,15 @@ static int stream_process(struct sip_msg * msg, struct sdp_stream_cell *cell, found.len++; } + /* when trimming the very last payload, avoid trailing ws */ + if (cur == lmp->u.value + lmp->len) { + tmp = found.s; + while (*(--tmp) == ' ') { + found.s--; + found.len++; + } + } + /* delete the string and update iterators */ for(tmp=found.s ; tmp< lmp->u.value + lmp->len ; tmp++ ) *tmp = *(tmp+found.len); @@ -688,11 +697,24 @@ int codec_find (struct sip_msg* msg, char* str1 ) int codec_find_re (struct sip_msg* msg, char* str1 ) { + regex_t *re; + int do_free; - if( do_for_all_streams(msg, NULL, NULL, (regex_t*)str1, - FIND, DESC_REGEXP) == 0) + re = fixup_get_regex(msg,(gparam_p)str1,&do_free); + if (!re) { + LM_ERR("Failed to get regular expression \n"); return -1; + } + if( do_for_all_streams(msg, NULL, NULL, re, + FIND, DESC_REGEXP) == 0) { + if (do_free) + fixup_free_regexp((void **)&re); + return -1; + } + + if (do_free) + fixup_free_regexp((void **)&re); return 1; } @@ -745,18 +767,48 @@ int codec_delete (struct sip_msg* msg, char* str1 ) int codec_delete_re (struct sip_msg* msg, char* str1 ) { - if( do_for_all_streams( msg, NULL, NULL, (regex_t*) str1, - DELETE, DESC_REGEXP) == 0) + regex_t *re; + int do_free; + + re = fixup_get_regex(msg,(gparam_p)str1,&do_free); + if (!re) { + LM_ERR("Failed to get regular expression \n"); return -1; + } + + if( do_for_all_streams( msg, NULL, NULL, re, + DELETE, DESC_REGEXP) == 0) { + if (do_free) + fixup_free_regexp((void **)&re); + return -1; + } + + if (do_free) + fixup_free_regexp((void **)&re); return 1; } int codec_delete_except_re (struct sip_msg* msg, char* str1 ) { - if( do_for_all_streams( msg, NULL, NULL, (regex_t*) str1, - DELETE, DESC_REGEXP_COMPLEMENT) == 0) + regex_t *re; + int do_free; + + re = fixup_get_regex(msg,(gparam_p)str1,&do_free); + if (!re) { + LM_ERR("Failed to get regular expression \n"); + return -1; + } + + if( do_for_all_streams( msg, NULL, NULL, re, + DELETE, DESC_REGEXP_COMPLEMENT) == 0) { + if (do_free) + fixup_free_regexp((void **)&re); return -1; + } + + if (do_free) + fixup_free_regexp((void **)&re); return 1; } @@ -808,9 +860,24 @@ int codec_move_up (struct sip_msg* msg, char* str1) int codec_move_up_re (struct sip_msg* msg, char* str1) { - if( do_for_all_streams( msg, NULL, NULL, (regex_t*)str1, - ADD_TO_FRONT, DESC_REGEXP) == 0) + regex_t *re; + int do_free; + + re = fixup_get_regex(msg,(gparam_p)str1,&do_free); + if (!re) { + LM_ERR("Failed to get regular expression \n"); + return -1; + } + + if( do_for_all_streams( msg, NULL, NULL, re, + ADD_TO_FRONT, DESC_REGEXP) == 0) { + if (do_free) + fixup_free_regexp((void **)&re); return -1; + } + + if (do_free) + fixup_free_regexp((void **)&re); return 1; } @@ -862,9 +929,24 @@ int codec_move_down (struct sip_msg* msg, char* str1) int codec_move_down_re (struct sip_msg* msg, char* str1) { - if( do_for_all_streams( msg, NULL, NULL, (regex_t*)str1, - ADD_TO_BACK, DESC_REGEXP) == 0) + regex_t *re; + int do_free; + + re = fixup_get_regex(msg,(gparam_p)str1,&do_free); + if (!re) { + LM_ERR("Failed to get regular expression \n"); return -1; + } + + if( do_for_all_streams( msg, NULL, NULL, re, + ADD_TO_BACK, DESC_REGEXP) == 0) { + if (do_free) + fixup_free_regexp((void **)&re); + return -1; + } + + if (do_free) + fixup_free_regexp((void **)&re); return 1; } @@ -991,15 +1073,41 @@ static int handle_streams(struct sip_msg* msg, regex_t* re, int delete) } -int stream_find (struct sip_msg* msg, char* re ) +int stream_find (struct sip_msg* msg, char* str1 ) { - return handle_streams(msg, (regex_t*)re, 0); + regex_t *re; + int do_free,ret; + + re = fixup_get_regex(msg,(gparam_p)str1,&do_free); + if (!re) { + LM_ERR("Failed to get regular expression \n"); + return -1; + } + + ret = handle_streams(msg, re, 0); + if (do_free) + fixup_free_regexp((void **)&re); + + return ret; } -int stream_delete (struct sip_msg* msg, char* re ) +int stream_delete (struct sip_msg* msg, char* str1 ) { - return handle_streams(msg, (regex_t*)re, 1); + regex_t *re; + int do_free,ret; + + re = fixup_get_regex(msg,(gparam_p)str1,&do_free); + if (!re) { + LM_ERR("Failed to get regular expression \n"); + return -1; + } + + ret = handle_streams(msg, re, 1); + if (do_free) + fixup_free_regexp((void **)&re); + + return ret; } diff --git a/modules/sipmsgops/doc/sipmsgops_admin.xml b/modules/sipmsgops/doc/sipmsgops_admin.xml index b08df4b5dd8..2ffd7c58523 100644 --- a/modules/sipmsgops/doc/sipmsgops_admin.xml +++ b/modules/sipmsgops/doc/sipmsgops_admin.xml @@ -699,7 +699,7 @@ add_body("Hello World!", "text/plain");
- <function moreinfo="none">sipmsg_validate([flags])</function> + <function moreinfo="none">sipmsg_validate([flags[,result_pvar]])</function> The function returns true if the SIP message @@ -722,27 +722,76 @@ add_body("Hello World!", "text/plain"); 'r' - checks the R-URI and whether the domain contains valid characters. + 'f' - checks the URI of the 'From' field + and whether the domain contains valid characters. + + 't' - checks the URI of the 'To' field + and whether the domain contains valid characters. + + 'c' - checks the URI of the 'Contact' field. + + The result_pvar parameter sets resulting pvar with text error reason in case of + negative result ( easy for logging or propagating the rejection reason back to the + bogus UA ) + This function can return the following codes: 1 - the message is RFC3261 compliant and has been successfully validated. - -1 - the message is not - RFC3261 compliant. + -1 - No SIP message + + -2 - Header Parsing error + + -3 - No Call-ID header + + -4 - No Content-Length header for transports that require it ( eg. TCP ) + + -5 - Invalid Content-Length, other from the size of the actual body + + -6 - SDP body parsing error. + + -7 - No Cseq header. + + -8 - No From header. + + -9 - No To header. + + -10 - No Via header. + + -11 - Request URI parse error. + + -12 - Bad hostname in R-URI. + + -13 - No Max-Forward header. + + -14 - No Contact header. + + -15 - Path user for non-Register request. + + -16 - No allow header in 405 reply. + + -17 - No Min-Expire header in 423 reply. + + -18 - No Proxy-Authorize header in 407 reply. + + -19 - No Unsupported header in 420 reply. + + -20 - No WWW-Authorize header in 401 reply. + + -21 - No Content-Type header - -2 - signals a parsing - error. + -22 - To header parse error - -3 - invalid SDP body. + -23 - From header parse error - -4 - invalid headers - body. + -24 - Bad hostname in To header - -5 - invalid R-URI. + -25 - Bad hostname in From header - -6 - invalid R-URI domain. + -26 - Contact header parse error -255 - undefined errors. diff --git a/modules/sipmsgops/sipmsgops.c b/modules/sipmsgops/sipmsgops.c index bc9e17b0727..691c1430cf9 100644 --- a/modules/sipmsgops/sipmsgops.c +++ b/modules/sipmsgops/sipmsgops.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -42,7 +42,7 @@ * 2004-07-06 subst_user added (like subst_uri but only for user) (sobomax) * 2004-11-12 subst_user changes (old serdev mails) (andrei) * 2005-07-05 is_method("name") to check method using id (ramona) - * 2006-03-17 applied patch from Marc Haisenko + * 2006-03-17 applied patch from Marc Haisenko * for adding has_body() function (bogdan) * 2009-07-23 added methods for sdp codec manipulation(andreidragus) * 2012-02-21 add change_reply_status (idea from kamailio/textopsx) (rpedraza) @@ -102,7 +102,7 @@ static str header_body = {0, 0}; %a -- abbreviated week of day name (locale), %d day of month as decimal number, %b abbreviated month name (locale), %Y year with century, %T time in 24h notation -*/ + */ #define TIME_FORMAT "Date: %a, %d %b %Y %H:%M:%S GMT" #define MAX_TIME 64 @@ -128,7 +128,7 @@ static int strip_body_f2(struct sip_msg *msg, char *str1, char *str2 ); static int add_body_f_1(struct sip_msg *msg, char *str1, char *str2 ); static int add_body_f_2(struct sip_msg *msg, char *str1, char *str2 ); static int is_audio_on_hold_f(struct sip_msg *msg, char *str1, char *str2 ); -static int w_sip_validate(struct sip_msg *msg, char *flags_s); +static int w_sip_validate(struct sip_msg *msg, char *flags_s, char* pv_result); static int hname_fixup(void** param, int param_no); static int free_hname_fixup(void** param, int param_no); @@ -157,10 +157,10 @@ static cmd_export_t cmds[]={ {"append_hf", (cmd_function)append_hf_2, 2, add_header_fixup, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"insert_hf", (cmd_function)insert_hf_1, 1, + {"insert_hf", (cmd_function)insert_hf_1, 1, add_header_fixup, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"insert_hf", (cmd_function)insert_hf_2, 2, + {"insert_hf", (cmd_function)insert_hf_2, 2, add_header_fixup, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"append_urihf", (cmd_function)append_urihf, 2, @@ -187,7 +187,7 @@ static cmd_export_t cmds[]={ {"has_body", (cmd_function)has_body_f, 0, 0, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"has_body", (cmd_function)has_body_f, 1, + {"has_body", (cmd_function)has_body_f, 1, fixup_body_type, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"is_privacy", (cmd_function)is_privacy_f, 1, @@ -199,10 +199,10 @@ static cmd_export_t cmds[]={ {"strip_body", (cmd_function)strip_body_f2, 1, fixup_body_type, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE }, - {"add_body", (cmd_function)add_body_f_1, 1, + {"add_body", (cmd_function)add_body_f_1, 1, fixup_spve_null, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"add_body", (cmd_function)add_body_f_2, 2, + {"add_body", (cmd_function)add_body_f_2, 2, add_header_fixup, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"codec_exists", (cmd_function)codec_find, 1, @@ -253,13 +253,16 @@ static cmd_export_t cmds[]={ {"sipmsg_validate", (cmd_function)w_sip_validate, 1, fixup_sip_validate, 0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE}, + {"sipmsg_validate", (cmd_function)w_sip_validate, 2, + fixup_sip_validate, 0, + REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE}, {"change_reply_status", (cmd_function)change_reply_status_f, 2, change_reply_status_fixup, 0, ONREPLY_ROUTE }, {"stream_exists", (cmd_function)stream_find, 1, - fixup_regexp_null,0, + fixup_regexp_dynamic_null,0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"stream_delete", (cmd_function)stream_delete, 1, - fixup_regexp_null,0, + fixup_regexp_dynamic_null,0, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {0,0,0,0,0,0} }; @@ -267,8 +270,10 @@ static cmd_export_t cmds[]={ struct module_exports exports= { "sipmsgops", /* module name*/ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ 0, /* module parameters */ 0, /* exported statistics */ @@ -289,40 +294,40 @@ static int mod_init(void) } static inline int find_line_start(char *text, unsigned int text_len, - char **buf, unsigned int *buf_len) + char **buf, unsigned int *buf_len) { - char *ch, *start; - unsigned int len; + char *ch, *start; + unsigned int len; - start = *buf; - len = *buf_len; + start = *buf; + len = *buf_len; - while (text_len <= len) { - if (strncmp(text, start, text_len) == 0) { - *buf = start; - *buf_len = len; - return 1; - } - if ((ch = memchr(start, 13, len - 1))) { - if (*(ch + 1) != 10) { - LM_ERR("No LF after CR\n"); - return 0; - } - len = len - (ch - start + 2); - start = ch + 2; - } else { - LM_ERR("No CRLF found\n"); - return 0; + while (text_len <= len) { + if (strncmp(text, start, text_len) == 0) { + *buf = start; + *buf_len = len; + return 1; + } + if ((ch = memchr(start, 13, len - 1))) { + if (*(ch + 1) != 10) { + LM_ERR("No LF after CR\n"); + return 0; + } + len = len - (ch - start + 2); + start = ch + 2; + } else { + LM_ERR("No CRLF found\n"); + return 0; + } } - } - return 0; + return 0; } /* Filters multipart body by leaving out everything else except * first body part of given content type. */ static int filter_body_f(struct sip_msg* msg, char* _content_type, - char* ignored) + char* ignored) { char *start; unsigned int len; @@ -332,53 +337,53 @@ static int filter_body_f(struct sip_msg* msg, char* _content_type, LM_DBG("message body has zero length\n"); return -1; } - + content_type = (str *)_content_type; start = body.s; len = body.len; - + while (find_line_start("Content-Type: ", 14, &start, &len)) { - start = start + 14; - len = len - 14; - if (len > content_type->len + 2) { - if (strncasecmp(start, content_type->s, content_type->len) - == 0) { - start = start + content_type->len; - len = len - content_type->len; - if ((*start != 13) || (*(start + 1) != 10)) { - LM_ERR("No CRLF found after content type\n"); - return -1; - } - while ((len > 3) && !(*start == 13 && *(start+1) == 10 && *(start+2) == 13 && *(start+3) == 10)) { - len = len - 1; - start = start + 1; - } - while ((len > 0) && ((*start == 13) || (*start == 10))) { - len = len - 1; - start = start + 1; - } - if (del_lump(msg, body.s - msg->buf, start - body.s, 0) - == 0) { - LM_ERR("Deleting lump <%.*s> failed\n", - (int)(start - body.s), body.s); - return -1; - } - if (find_line_start("--Boundary", 10, &start, &len)) { - if (del_lump(msg, start - msg->buf, len, 0) == 0) { - LM_ERR("Deleting lump <%.*s> failed\n", - len, start); - return -1; - } else { - return 1; + start = start + 14; + len = len - 14; + if (len > content_type->len + 2) { + if (strncasecmp(start, content_type->s, content_type->len) + == 0) { + start = start + content_type->len; + len = len - content_type->len; + if ((*start != 13) || (*(start + 1) != 10)) { + LM_ERR("No CRLF found after content type\n"); + return -1; + } + while ((len > 3) && !(*start == 13 && *(start+1) == 10 && *(start+2) == 13 && *(start+3) == 10)) { + len = len - 1; + start = start + 1; + } + while ((len > 0) && ((*start == 13) || (*start == 10))) { + len = len - 1; + start = start + 1; + } + if (del_lump(msg, body.s - msg->buf, start - body.s, 0) + == 0) { + LM_ERR("Deleting lump <%.*s> failed\n", + (int)(start - body.s), body.s); + return -1; + } + if (find_line_start("--Boundary", 10, &start, &len)) { + if (del_lump(msg, start - msg->buf, len, 0) == 0) { + LM_ERR("Deleting lump <%.*s> failed\n", + len, start); + return -1; + } else { + return 1; + } + } else { + LM_ERR("Boundary not found after content\n"); + return -1; + } } - } else { - LM_ERR("Boundary not found after content\n"); + } else { return -1; - } } - } else { - return -1; - } } return -1; } @@ -388,7 +393,7 @@ int parse_pvs_header(struct sip_msg *msg, gparam_p gp) pv_value_t pval; struct hdr_field hdr; int hdr_len; - + if (pv_get_spec_value(msg, gp->v.pvs, &pval) != 0 || pval.flags & PV_VAL_NULL) { LM_ERR("no valid PV value found!\n"); @@ -412,8 +417,8 @@ int parse_pvs_header(struct sip_msg *msg, gparam_p gp) header_body.s[pval.rs.len] = ':'; LM_DBG("Parsing %.*s\n", hdr_len, header_body.s); - if (parse_hname2(header_body.s, header_body.s + - (hdr_len < 4 ? 4 : hdr_len), &hdr) == 0) + if (parse_hname2(header_body.s, header_body.s + + (hdr_len < 4 ? 4 : hdr_len), &hdr) == 0) { LM_ERR("error parsing header name\n"); pkg_free(gp); @@ -437,6 +442,19 @@ int parse_pvs_header(struct sip_msg *msg, gparam_p gp) return 0; } +static int hf_already_removed(struct sip_msg* msg, unsigned int offset, + unsigned int len, enum _hdr_types_t type) +{ + struct lump *it; + /* parse only the msg headers, not the body */ + for (it = msg->add_rm; it; it = it->next) { + if (it->op == LUMP_DEL && it->type == type && + it->u.offset == offset && it->len == len) + return 1; + } + return 0; +} + static int remove_hf_f(struct sip_msg* msg, char* str_hf, char* foo) { struct hdr_field *hf; @@ -448,7 +466,7 @@ static int remove_hf_f(struct sip_msg* msg, char* str_hf, char* foo) cnt=0; if (gp->type == GPARAM_TYPE_PVS && - parse_pvs_header(msg, gp) != 0) + parse_pvs_header(msg, gp) != 0) { LM_ERR("Parse pvs header failed!\n"); return -1; @@ -457,8 +475,8 @@ static int remove_hf_f(struct sip_msg* msg, char* str_hf, char* foo) /* we need to be sure we have seen all HFs */ parse_headers(msg, HDR_EOH_F, 0); for (hf=msg->headers; hf; hf=hf->next) { - /* for well known header names str_hf->s will be set to NULL - during parsing of opensips.cfg and str_hf->len contains + /* for well known header names str_hf->s will be set to NULL + during parsing of opensips.cfg and str_hf->len contains the header type */ if(gp->type==GPARAM_TYPE_INT) { @@ -472,7 +490,11 @@ static int remove_hf_f(struct sip_msg* msg, char* str_hf, char* foo) if (strncasecmp(hf->name.s, gp->v.sval.s, hf->name.len)!=0) continue; } - l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0); + /* check to see if the header was already removed */ + if (hf_already_removed(msg, hf->name.s-msg->buf, hf->len, + hf->type)) + continue; + l=del_lump(msg, hf->name.s-msg->buf, hf->len, hf->type); if (l==0) { LM_ERR("no memory\n"); return -1; @@ -502,29 +524,34 @@ static int remove_hf_match_f(struct sip_msg* msg, char* pattern, char* regex_or_ return -1; } for (hf=msg->headers; hf; hf=hf->next) { - tmp = *(hf->name.s+hf->name.len); - *(hf->name.s+hf->name.len) = 0; - if( matchtype == 'g' ) { /* GLOB */ - if(fnmatch(pat->s, hf->name.s, 0) !=0 ){ - *(hf->name.s+hf->name.len) = tmp; - continue; - } - } else if( matchtype == 'r' ){ /* REGEX */ - if(regexec(re, hf->name.s, 1, &pmatch, 0)!=0){ - *(hf->name.s+hf->name.len) = tmp; - continue; - } - } else { - LM_ERR("Unknow match type. Supported types are r (regex) and g (glob)"); - return -1; + tmp = *(hf->name.s+hf->name.len); + *(hf->name.s+hf->name.len) = 0; + if( matchtype == 'g' ) { /* GLOB */ + if(fnmatch(pat->s, hf->name.s, 0) !=0 ){ + *(hf->name.s+hf->name.len) = tmp; + continue; } - *(hf->name.s+hf->name.len) = tmp; - l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0); - if (l==0) { - LM_ERR("no memory\n"); - return -1; + } else if( matchtype == 'r' ){ /* REGEX */ + if(regexec(re, hf->name.s, 1, &pmatch, 0)!=0){ + *(hf->name.s+hf->name.len) = tmp; + continue; } - cnt++; + } else { + LM_ERR("Unknow match type. Supported types are r (regex) and g (glob)"); + return -1; + } + *(hf->name.s+hf->name.len) = tmp; + + /* check to see if the header was already removed */ + if (hf_already_removed(msg, hf->name.s-msg->buf, hf->len, + hf->type)) + continue; + l=del_lump(msg, hf->name.s-msg->buf, hf->len, hf->type); + if (l==0) { + LM_ERR("no memory\n"); + return -1; + } + cnt++; } return cnt==0 ? -1 : 1; } @@ -538,7 +565,7 @@ static int is_present_hf_f(struct sip_msg* msg, char* str_hf, char* foo) gp = (gparam_p)str_hf; if (gp->type == GPARAM_TYPE_PVS && - parse_pvs_header(msg, gp) != 0) + parse_pvs_header(msg, gp) != 0) { LM_ERR("Parse pvs header failed!\n"); return -1; @@ -617,7 +644,7 @@ static int append_to_reply_f(struct sip_msg* msg, char* key, char* str0) LM_ERR("cannot print the format\n"); return -1; } - + if ( add_lump_rpl( msg, s0.s, s0.len, LUMP_RPL_HDR)==0 ) { LM_ERR("unable to add lump_rl\n"); @@ -643,7 +670,7 @@ static int add_hf_helper(struct sip_msg* msg, str *str1, str *str2, LM_ERR("error while parsing message\n"); return -1; } - + hf = 0; if(hfanc!=NULL) { for (hf=msg->headers; hf; hf=hf->next) { @@ -665,15 +692,15 @@ static int add_hf_helper(struct sip_msg* msg, str *str1, str *str2, if(mode == 0) { /* append */ if(hf==0) { /* after last header */ - anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0); + anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0); } else { /* after hf */ - anchor = anchor_lump(msg, hf->name.s + hf->len - msg->buf, 0, 0); + anchor = anchor_lump(msg, hf->name.s + hf->len - msg->buf, 0); } } else { /* insert */ if(hf==0) { /* before first header */ - anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0, 0); + anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0); } else { /* before hf */ - anchor = anchor_lump(msg, hf->name.s - msg->buf, 0, 0); + anchor = anchor_lump(msg, hf->name.s - msg->buf, 0); } } @@ -696,7 +723,7 @@ static int add_hf_helper(struct sip_msg* msg, str *str1, str *str2, s0.s = 0; } } - + len=s0.len; if (str2) len+= str2->len + REQ_LINE(msg).uri.len; @@ -738,7 +765,7 @@ static int insert_hf_1(struct sip_msg *msg, char *str1, char *str2 ) static int insert_hf_2(struct sip_msg *msg, char *str1, char *str2 ) { - return add_hf_helper(msg, 0, 0, (gparam_p)str1, 1, + return add_hf_helper(msg, 0, 0, (gparam_p)str1, 1, (gparam_p)str2); } @@ -760,7 +787,7 @@ static int is_method_f(struct sip_msg *msg, char *meth, char *str2 ) return (msg->first_line.u.request.method_value==METHOD_OTHER && msg->first_line.u.request.method.len==m->len && (strncasecmp(msg->first_line.u.request.method.s, m->s, - m->len)==0))?1:-1; + m->len)==0))?1:-1; } if(parse_headers(msg, HDR_CSEQ_F, 0)!=0 || msg->cseq==NULL) { @@ -773,7 +800,7 @@ static int is_method_f(struct sip_msg *msg, char *meth, char *str2 ) return (get_cseq(msg)->method_id==METHOD_OTHER && get_cseq(msg)->method.len==m->len && (strncasecmp(get_cseq(msg)->method.s, m->s, - m->len)==0))?1:-1; + m->len)==0))?1:-1; } @@ -799,18 +826,18 @@ static int hname_fixup(void** param, int param_no) c = gp->v.sval.s[gp->v.sval.len]; gp->v.sval.s[gp->v.sval.len] = ':'; gp->v.sval.len++; - + if (parse_hname2(gp->v.sval.s, gp->v.sval.s - + ((gp->v.sval.len<4)?4:gp->v.sval.len), &hdr)==0) + + ((gp->v.sval.len<4)?4:gp->v.sval.len), &hdr)==0) { LM_ERR("error parsing header name\n"); pkg_free(gp); return E_UNSPEC; } - + gp->v.sval.len--; gp->v.sval.s[gp->v.sval.len] = c; - + if (hdr.type!=HDR_OTHER_T && hdr.type!=HDR_ERROR_T) { LM_INFO("using hdr type (%d) instead of <%.*s>\n", @@ -868,7 +895,7 @@ static int hname_match_fixup(void** param, int param_no) /* regex fixup code here */ LM_DBG("processing param1: %s as regex\n", *(char**)param); fixup_regexp_null(param, param_no); - }else if(type == 'g'){ + }else if(type == 'g'){ /* glob fixup code here */ LM_DBG("processing param1: %s as glob\n", *(char**)param); fixup_str(param); @@ -924,7 +951,7 @@ static int fixup_method(void** param, int param_no) char *p; int m; unsigned int method; - + s = (str*)pkg_malloc(sizeof(str)); if (!s) { LM_ERR("no pkg memory left\n"); @@ -962,7 +989,7 @@ static int fixup_method(void** param, int param_no) if(method==METHOD_UNDEF || method&METHOD_OTHER) { LM_ERR("unknown method in list [%.*s/%d] - must be only defined methods\n", - s->len, s->s, method); + s->len, s->s, method); return E_UNSPEC; } LM_DBG("using id for methods [%.*s/%d]\n", @@ -973,12 +1000,12 @@ static int fixup_method(void** param, int param_no) if(method!=METHOD_UNDEF && method!=METHOD_OTHER) { LM_DBG("using id for method [%.*s/%d]\n", - s->len, s->s, method); + s->len, s->s, method); s->s = 0; s->len = method; } else LM_DBG("name for method [%.*s/%d]\n", - s->len, s->s, method); + s->len, s->s, method); } *param = (void*)s; @@ -990,24 +1017,24 @@ static int fixup_method(void** param, int param_no) */ static int fixup_privacy(void** param, int param_no) { - str p; - unsigned int val; - - p.s = (char*)*param; - p.len = strlen(p.s); - - if (p.len == 0) { - LM_ERR("empty privacy value\n"); - return E_UNSPEC; - } - - if (parse_priv_value(p.s, p.len, &val) != p.len) { - LM_ERR("invalid privacy value\n"); - return E_UNSPEC; - } - - *param = (void *)(long)val; - return 0; + str p; + unsigned int val; + + p.s = (char*)*param; + p.len = strlen(p.s); + + if (p.len == 0) { + LM_ERR("empty privacy value\n"); + return E_UNSPEC; + } + + if (parse_priv_value(p.s, p.len, &val) != p.len) { + LM_ERR("invalid privacy value\n"); + return E_UNSPEC; + } + + *param = (void *)(long)val; + return 0; } static int add_header_fixup(void** param, int param_no) @@ -1060,7 +1087,7 @@ static int has_body_f(struct sip_msg *msg, char *type, char *str2 ) /* parse content len hdr */ if ( msg->content_length==NULL && - (parse_headers(msg,HDR_CONTENTLENGTH_F, 0)==-1||msg->content_length==NULL)) + (parse_headers(msg,HDR_CONTENTLENGTH_F, 0)==-1||msg->content_length==NULL)) return -1; if (get_content_length (msg)==0) { @@ -1106,17 +1133,17 @@ static int has_body_f(struct sip_msg *msg, char *type, char *str2 ) return 1; p = p->next; } - + return -1; } static int is_privacy_f(struct sip_msg *msg, char *_privacy, char *str2 ) { - if (parse_privacy(msg) == -1) - return -1; + if (parse_privacy(msg) == -1) + return -1; - return get_privacy_values(msg) & ((unsigned int)(long)_privacy) ? 1 : -1; + return get_privacy_values(msg) & ((unsigned int)(long)_privacy) ? 1 : -1; } @@ -1133,9 +1160,9 @@ static int strip_body_f(struct sip_msg *msg, char *str1, char *str2 ) LM_DBG("message body has zero length\n"); return -1; } - + /* delete all body lumps from the list */ - /* NOTE: do not delete the SHM lumps (which are primarily stored in TM + /* NOTE: do not delete the SHM lumps (which are primarily stored in TM Such lumps need to skipped and only detached - bogdan */ del_notflaged_lumps( &msg->body_lumps, LUMPFLAG_SHMEM ); msg->body_lumps = NULL; @@ -1161,11 +1188,11 @@ static int strip_body_f2(struct sip_msg *msg, char *type, char *str2 ) struct multi_body * m; struct part * p; int deleted = 0,mime; - + /* parse content len hdr */ if ( msg->content_length==NULL && - (parse_headers(msg,HDR_CONTENTLENGTH_F, 0)==-1||msg->content_length==NULL)) + (parse_headers(msg,HDR_CONTENTLENGTH_F, 0)==-1||msg->content_length==NULL)) return -1; if (get_content_length (msg)==0) { @@ -1178,7 +1205,7 @@ static int strip_body_f2(struct sip_msg *msg, char *type, char *str2 ) if( ( ((int)(long)type )>>16) == TYPE_MULTIPART || (mime >>16) != TYPE_MULTIPART) { - + if( mime == ((int)(long)type ) ) { @@ -1187,7 +1214,7 @@ static int strip_body_f2(struct sip_msg *msg, char *type, char *str2 ) return -1; } - + m = get_all_bodies(msg); @@ -1213,15 +1240,15 @@ static int strip_body_f2(struct sip_msg *msg, char *type, char *str2 ) if( p->content_type == ((int)(long)type ) ) { if( del_lump( msg, p->all_data.s - msg->buf - 4 - m->boundary.len, - p->all_data.len + 6 + m->boundary.len, 0 ) == 0 ) + p->all_data.len + 6 + m->boundary.len, 0 ) == 0 ) { LM_ERR("Failed to add body lump\n"); return -1; } - + deleted = 1; } - + p = p->next; } @@ -1282,7 +1309,7 @@ static int add_body_f(struct sip_msg *msg, gparam_p nbody, gparam_p ctype ) } /* add an add body lump */ - anchor = anchor_lump(msg, offset, 0, 0); + anchor = anchor_lump(msg, offset, 0); if(anchor == 0) { LM_ERR("failed to insert an add new body anchor"); return -1; @@ -1300,13 +1327,13 @@ static int add_body_f(struct sip_msg *msg, gparam_p nbody, gparam_p ctype ) pkg_free(value); return -1; } - + if(ctype) { if(fixup_get_svalue(msg, ctype, &content_type)!=0) { LM_ERR("cannot print the format\n"); return -1; } - + if(msg->content_type) { /* verify if the parameter has the same value */ if(content_type.len == msg->content_type->body.len && @@ -1316,15 +1343,15 @@ static int add_body_f(struct sip_msg *msg, gparam_p nbody, gparam_p ctype ) } if(del_lump(msg, msg->content_type->name.s- msg->buf, msg->content_type->len, - HDR_CONTENTTYPE_T) == 0) { + HDR_CONTENTTYPE_T) == 0) { LM_ERR("failed to add lump to delete content type header\n"); return -1; } } /* add new Content-Type header */ - + /* construct header */ - + ctype_hf.len = strlen("Content-Type: ") + content_type.len+ CRLF_LEN; ctype_hf.s = (char*)pkg_malloc(ctype_hf.len); if(ctype_hf.s == NULL) { @@ -1333,7 +1360,7 @@ static int add_body_f(struct sip_msg *msg, gparam_p nbody, gparam_p ctype ) } sprintf(ctype_hf.s, "Content-Type: %.*s%s", content_type.len, content_type.s, CRLF); - + if( add_hf_helper(msg, &ctype_hf, 0, 0, 0, 0)< 0) { LM_ERR("failed to add content type header\n"); pkg_free(ctype_hf.s); @@ -1372,8 +1399,8 @@ static int is_audio_on_hold_f(struct sip_msg *msg, char *str1, char *str2 ) sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num); if(!sdp_stream) break; if(sdp_stream->media.len==AUDIO_STR_LEN && - strncmp(sdp_stream->media.s,AUDIO_STR,AUDIO_STR_LEN)==0 && - sdp_stream->is_on_hold) + strncmp(sdp_stream->media.s,AUDIO_STR,AUDIO_STR_LEN)==0 && + sdp_stream->is_on_hold) return 1; sdp_stream_num++; } @@ -1388,54 +1415,83 @@ static int is_audio_on_hold_f(struct sip_msg *msg, char *str1, char *str2 ) #define SIP_PARSE_HDR 0x2 #define SIP_PARSE_NOMF 0x4 #define SIP_PARSE_RURI 0x8 +#define SIP_PARSE_TO 0x10 +#define SIP_PARSE_FROM 0x20 +#define SIP_PARSE_CONTACT 0x40 static int fixup_sip_validate(void** param, int param_no) { char *flags_s, *end; unsigned long flags = 0; + pv_elem_t *pvar; + str s; - if (param_no != 1) { - LM_ERR("invalid parameter number %d\n", param_no); - return E_UNSPEC; - } - if (!param) { - goto end; - } + if (param_no==1) { + if (!param) { + goto end; + } + flags_s = (char*)*param; + end = flags_s + strlen(flags_s); + + for ( ; flags_s < end; flags_s++) { + switch (*flags_s) { + case 's': + case 'S': + flags |= SIP_PARSE_SDP; + break; - flags_s = (char*)*param; - end = flags_s + strlen(flags_s); + case 'h': + case 'H': + flags |= SIP_PARSE_HDR; + break; - for ( ; flags_s < end; flags_s++) { - switch (*flags_s) { - case 's': - case 'S': - flags |= SIP_PARSE_SDP; - break; + case 'm': + case 'M': + flags |= SIP_PARSE_NOMF; + break; - case 'h': - case 'H': - flags |= SIP_PARSE_HDR; - break; + case 'r': + case 'R': + flags |= SIP_PARSE_RURI; + break; - case 'm': - case 'M': - flags |= SIP_PARSE_NOMF; - break; + case 't': + case 'T': + flags |= SIP_PARSE_TO; + break; - case 'r': - case 'R': - flags |= SIP_PARSE_RURI; - break; + case 'f': + case 'F': + flags |= SIP_PARSE_FROM; + break; - default: - LM_DBG("unknown option \'%c\'\n", *flags_s); - break; + case 'c': + case 'C': + flags |= SIP_PARSE_CONTACT; + break; + + default: + LM_DBG("unknown option \'%c\'\n", *flags_s); + break; + } } - } - end: - *param = (void *)(unsigned long)flags; - return 0; + *param = (void *)(unsigned long)flags; + return 0; + } else if (param_no==2) { + s.s = (char*)(*param); + s.len = strlen(s.s); + if (pv_parse_format(&s, &pvar)<0) + { + LM_ERR( "wrong format[%s]\n",(char*)(*param)); + return E_UNSPEC; + } + *param = (void*)pvar; + return 0; + } else { + LM_ERR("invalid parameter number %d\n", param_no); + return E_UNSPEC; + } } static int sip_validate_hdrs(struct sip_msg *msg) @@ -1450,25 +1506,25 @@ static int sip_validate_hdrs(struct sip_msg *msg) unsigned u_aux; int i_aux; - #define CHECK_HDR_EMPTY() \ - do { \ - str_aux = hf->body; \ - trim_len( str_aux.len , str_aux.s , hf->body ); \ - if (str_aux.len <= 0) { \ - LM_DBG("header '%.*s' has invalid value %d\n", \ - hf->name.len, hf->name.s, str_aux.len); \ - goto failed; \ - } \ - } while (0) - - #define CHECK_HDR_FUNC(_f, _o) \ - do { \ - if (_f(_o) < 0) { \ - LM_DBG("cannot parse '%.*s' header\n", \ - hf->name.len, hf->name.s); \ - goto failed; \ - } \ - } while (0) +#define CHECK_HDR_EMPTY() \ + do { \ + str_aux = hf->body; \ + trim_len( str_aux.len , str_aux.s , hf->body ); \ + if (str_aux.len <= 0) { \ + LM_DBG("header '%.*s' has invalid value %d\n", \ + hf->name.len, hf->name.s, str_aux.len); \ + goto failed; \ + } \ + } while (0) + +#define CHECK_HDR_FUNC(_f, _o) \ + do { \ + if (_f(_o) < 0) { \ + LM_DBG("cannot parse '%.*s' header\n", \ + hf->name.len, hf->name.s); \ + goto failed; \ + } \ + } while (0) /* skip via, cseq, to and content length * = we can be sure that they have been properly parsed = @@ -1498,13 +1554,13 @@ static int sip_validate_hdrs(struct sip_msg *msg) /* it seams we have to parse it! :-( */ e_aux = hf->body.s + hf->body.len; if ((s_aux = decode_mime_type(hf->body.s, e_aux , - &u_aux, cont)) == 0) { + &u_aux, cont)) == 0) { pkg_free(cont); goto failed; } if (e_aux != s_aux) { LM_DBG("the header CONTENT_TYPE contains " - "more then one mime type :-(!\n"); + "more than one mime type :-(!\n"); pkg_free(cont); goto failed; } @@ -1539,7 +1595,7 @@ static int sip_validate_hdrs(struct sip_msg *msg) case HDR_CONTENTDISPOSITION_T: if (!(disp = (struct disposition*) - pkg_malloc(sizeof(struct disposition)))) { + pkg_malloc(sizeof(struct disposition)))) { LM_ERR("no more pkg memory\n"); goto failed; } @@ -1554,7 +1610,7 @@ static int sip_validate_hdrs(struct sip_msg *msg) } break; - /* to-style headers */ + /* to-style headers */ case HDR_FROM_T: case HDR_PPI_T: case HDR_PAI_T: @@ -1683,9 +1739,9 @@ static int sip_validate_hdrs(struct sip_msg *msg) } #define IS_ALPHANUM(_c) ( \ - ((_c) >= 'a' && (_c) <= 'z') || \ - ((_c) >= 'A' && (_c) <= 'Z') || \ - ((_c) >= '0' && (_c) <= '9') ) + ((_c) >= 'a' && (_c) <= 'z') || \ + ((_c) >= 'A' && (_c) <= 'Z') || \ + ((_c) >= '0' && (_c) <= '9') ) static int check_hostname(str *domain) { @@ -1736,35 +1792,79 @@ static int check_hostname(str *domain) } \ } while (0) +#define MAX_REASON 256 + +enum sip_validation_failures { + SV_NO_MSG=-1, + SV_HDR_PARSE_ERROR=-2, + SV_NO_CALLID=-3, + SV_NO_CONTENT_LENGTH=-4, + SV_INVALID_CONTENT_LENGTH=-5, + SV_PARSE_SDP=-6, + SV_NO_CSEQ=-7, + SV_NO_FROM=-8, + SV_NO_TO=-9, + SV_NO_VIA1=-10, + SV_RURI_PARSE_ERROR=-11, + SV_BAD_HOSTNAME=-12, + SV_NO_MF=-13, + SV_NO_CONTACT=-14, + SV_PATH_NONREGISTER=-15, + SV_NOALLOW_405=-16, + SV_NOMINEXP_423=-17, + SV_NO_PROXY_AUTH=-18, + SV_NO_UNSUPPORTED=-19, + SV_NO_WWW_AUTH=-20, + SV_NO_CONTENT_TYPE=-21, + SV_TO_PARSE_ERROR=-22, + SV_TO_DOMAIN_ERROR=-23, + SV_FROM_PARSE_ERROR=-24, + SV_FROM_DOMAIN_ERROR=-25, + SV_CONTACT_PARSE_ERROR=-26, + SV_GENERIC_FAILURE=-255 +}; - -static int w_sip_validate(struct sip_msg *msg, char *flags_s) +static int w_sip_validate(struct sip_msg *msg, char *flags_s, char* pv_result) { unsigned int hdrs_len; int method; str body; + struct hdr_field * ptr; + contact_t * contacts; + struct sip_uri test_contacts; struct cseq_body * cbody; + struct to_body *from, *to; unsigned long flags; - - if (!msg) - return -1; + pv_elem_t* pv_res = (pv_elem_t*)pv_result; + pv_value_t pv_val; + char reason[MAX_REASON]; + int ret = -SV_GENERIC_FAILURE; + + if (!msg) { + strcpy(reason, "no message object"); + ret = SV_NO_MSG; + goto failed; + } /* try to check the whole SIP msg */ if (parse_headers(msg, HDR_EOH_F, 0) < 0) { - LM_DBG("message parsing failed\n"); - return -2; + strcpy(reason, "message parsing failed"); + ret = SV_HDR_PARSE_ERROR; + goto failed; } /* any message has to have a call-id */ if (!msg->callid) { - LM_DBG("message doesn't have callid\n"); + strcpy(reason, "message doesn't have callid"); + ret = SV_NO_CALLID; goto failed; } /* content length should be present if protocol is not UDP */ if (msg->rcv.proto != PROTO_UDP && !msg->content_length) { - LM_DBG("message doesn't have Content Length header for proto %d\n", + snprintf(reason, MAX_REASON-1, "message doesn't have Content Length header for proto %d", msg->rcv.proto); + ret = SV_NO_CONTENT_LENGTH; goto failed; } @@ -1776,8 +1876,9 @@ static int w_sip_validate(struct sip_msg *msg, char *flags_s) /* if not CANCEL, check if it has body */ if (msg->first_line.type!=SIP_REQUEST || msg->REQ_METHOD!=METHOD_CANCEL) { if (!msg->unparsed) { - LM_DBG("Invalid parsing \n"); - return -2; + strcpy(reason, "invalid parsing"); + ret = SV_HDR_PARSE_ERROR; + goto failed; } hdrs_len=(unsigned int)(msg->unparsed-msg->buf); @@ -1797,33 +1898,95 @@ static int w_sip_validate(struct sip_msg *msg, char *flags_s) body.len = msg->buf + msg->len - body.s; if (get_content_length(msg) != body.len) { - LM_DBG("invalid body - content length %ld different then actual body %d\n", + snprintf(reason, MAX_REASON-1, "invalid body - content length %ld different than actual body %d", get_content_length(msg), body.len); + ret = SV_INVALID_CONTENT_LENGTH; goto failed; } /* if has body, check for SDP */ if (body.s && body.len && (flags & SIP_PARSE_SDP) && - parse_content_type_hdr(msg)==(TYPE_APPLICATION<<16 | SUBTYPE_SDP) ) { + parse_content_type_hdr(msg)==(TYPE_APPLICATION<<16 | SUBTYPE_SDP) ) { if (parse_sdp(msg) < 0) { - LM_DBG("failed to parse SDP message\n"); - return -3; + strcpy(reason, "failed to parse SDP message"); + ret = SV_PARSE_SDP; + goto failed; } } } + /* set reason to empty (covers cases where we + * exit via CHECK_HEADER) */ + reason[0] = 0; + /* Cseq */ + ret = SV_NO_CSEQ; CHECK_HEADER("", cseq); /* From */ + ret = SV_NO_FROM; CHECK_HEADER("", from); /* To */ + ret = SV_NO_TO; CHECK_HEADER("", to); /* check only if Via1 is present */ + ret = SV_NO_VIA1; CHECK_HEADER("", via1); + /* test to header uri */ + if(flags & SIP_PARSE_TO) { + if(!msg->to->parsed) { + if(parse_to_header(msg) < 0) { + strcpy(reason, "failed to parse 'To' header"); + ret = SV_TO_PARSE_ERROR; + goto failed; + } + } + + to = (struct to_body*)msg->to->parsed; + + if(parse_uri(to->uri.s, to->uri.len, &to->parsed_uri) < 0) { + strcpy(reason, "failed to parse 'To' header"); + ret = SV_TO_PARSE_ERROR; + goto failed; + } + + /* check for valid domain format */ + if(check_hostname(&to->parsed_uri.host) < 0) { + strcpy(reason, "invalid domain for 'To' header"); + ret = SV_TO_DOMAIN_ERROR; + goto failed; + } + } + + /* test from header uri */ + if(flags & SIP_PARSE_FROM) { + if(!msg->from->parsed) { + if(parse_from_header(msg) < 0) { + strcpy(reason, "failed to parse 'From' header"); + ret = SV_FROM_PARSE_ERROR; + goto failed; + } + } + + from = (struct to_body*)msg->from->parsed; + + if(parse_uri(from->uri.s, from->uri.len, &from->parsed_uri) < 0) { + strcpy(reason, "failed to parse 'From' header"); + ret = SV_FROM_PARSE_ERROR; + goto failed; + } + + /* check for valid domain format */ + if(check_hostname(&from->parsed_uri.host) < 0) { + strcpy(reason, "invalid domain for 'From' header"); + ret = SV_FROM_DOMAIN_ERROR; + goto failed; + } + } + /* request or reply */ switch (msg->first_line.type) { case SIP_REQUEST: @@ -1831,24 +1994,60 @@ static int w_sip_validate(struct sip_msg *msg, char *flags_s) /* check R-URI */ if (flags & SIP_PARSE_RURI) { if(msg->parsed_uri_ok==0 && parse_sip_msg_uri(msg) < 0) { - LM_DBG("failed to parse R-URI\n"); - return -5; + strcpy(reason, "failed to parse R-URI"); + ret = SV_RURI_PARSE_ERROR; + goto failed; } if (check_hostname(&msg->parsed_uri.host) < 0) { - LM_DBG("invalid domain\n"); - return -6; + strcpy(reason, "invalid domain for R-URI"); + ret = SV_BAD_HOSTNAME; + goto failed; } } /* Max-Forwards */ - if (!(flags & SIP_PARSE_NOMF)) + if (!(flags & SIP_PARSE_NOMF)) { + ret = SV_NO_MF; CHECK_HEADER("", maxforwards); + } if (msg->REQ_METHOD == METHOD_INVITE) { + ret = SV_NO_CONTACT; CHECK_HEADER("INVITE", contact); + if(flags & SIP_PARSE_CONTACT) { + /* iterate through Contact headers */ + for(ptr = msg->contact; ptr; ptr = ptr->sibling) { + /* parse Contact header */ + if(!ptr->parsed && (parse_contact(ptr) < 0 + || !ptr->parsed)) { + strcpy(reason, "failed to parse 'Contact' header"); + ret = SV_CONTACT_PARSE_ERROR; + goto failed; + } + contacts = ((contact_body_t*)ptr->parsed)->contacts; + /* empty contacts header - something must be wrong */ + if(contacts == NULL) { + strcpy(reason, "emtpy body for 'Contact' header"); + ret = SV_CONTACT_PARSE_ERROR; + goto failed; + } + /* iterate through URIs and check validty */ + for(; contacts; contacts = contacts->next) { + if(parse_uri(contacts->uri.s, contacts->uri.len, + &test_contacts) < 0 + || test_contacts.host.len < 0) { + strcpy(reason, "failed to parse 'Contact' header"); + ret = SV_CONTACT_PARSE_ERROR; + goto failed; + } + } + } + + } } if (msg->REQ_METHOD != METHOD_REGISTER && msg->path) { - LM_DBG("PATH header supported only for REGISTERs\n"); + strcpy(reason, "PATH header supported only for REGISTERs"); + ret = SV_PATH_NONREGISTER; goto failed; } @@ -1860,46 +2059,55 @@ static int w_sip_validate(struct sip_msg *msg, char *flags_s) /* checking the reply's message type */ cbody = (struct cseq_body *)msg->cseq->parsed; if (!cbody) { - LM_DBG("Cseq not parsed properly\n"); + strcpy(reason, "cseq not parsed properly"); + ret = SV_NO_CSEQ; goto failed; } method = cbody->method_id; if (method != METHOD_CANCEL) { switch (msg->first_line.u.reply.statuscode) { - case 405: - CHECK_HEADER("", allow); - break; - - case 423: - if (method == METHOD_REGISTER) - CHECK_HEADER("REGISTER", min_expires); - break; - - case 407: - CHECK_HEADER("", proxy_authenticate); - break; - - case 420: - CHECK_HEADER("", unsupported); - break; - - case 401: - CHECK_HEADER("", www_authenticate); - break; + case 405: + ret = SV_NOALLOW_405; + CHECK_HEADER("", allow); + break; + + case 423: + if (method == METHOD_REGISTER) { + ret = SV_NOMINEXP_423; + CHECK_HEADER("REGISTER", min_expires); + } + break; + + case 407: + ret = SV_NO_PROXY_AUTH; + CHECK_HEADER("", proxy_authenticate); + break; + + case 420: + ret = SV_NO_UNSUPPORTED; + CHECK_HEADER("", unsupported); + break; + + case 401: + ret = SV_NO_WWW_AUTH; + CHECK_HEADER("", www_authenticate); + break; } } break; default: - LM_DBG("invalid message type\n"); - return -255; + strcpy(reason, "invalid message type"); + ret = SV_GENERIC_FAILURE; + goto failed; } /* check for body */ if (method != METHOD_CANCEL) { if (!msg->unparsed) { - LM_DBG("Invalid parsing \n"); - return -2; + strcpy(reason, "invalid parsing"); + ret = SV_HDR_PARSE_ERROR; + goto failed; } hdrs_len=(unsigned int)(msg->unparsed-msg->buf); @@ -1918,26 +2126,41 @@ static int w_sip_validate(struct sip_msg *msg, char *flags_s) body.len = msg->buf + msg->len - body.s; if (get_content_length(msg) != body.len) { - LM_DBG("invalid body - content length %ld different then " + snprintf(reason, MAX_REASON-1, "invalid body - content length %ld different than " "actual body %d\n", get_content_length(msg), body.len); + ret = SV_INVALID_CONTENT_LENGTH; goto failed; } if (body.len && body.s) { /* if it really has body, check for content type */ + ret = SV_NO_CONTENT_TYPE; CHECK_HEADER("", content_type); } } if ((flags & SIP_PARSE_HDR) && sip_validate_hdrs(msg) < 0) { - LM_DBG("failed to parse headers\n"); - return -4; + strcpy(reason, "failed to parse headers"); + ret = SV_HDR_PARSE_ERROR; + goto failed; } return 1; failed: - LM_DBG("message does not comply with SIP RFC3261\n"); - return -1; + LM_DBG("message does not comply with SIP RFC3261 : (%s)\n", reason); + + if (pv_result != NULL) + { + pv_val.rs.len = strlen(reason); + pv_val.rs.s = reason; + pv_val.flags = PV_VAL_STR; + if (pv_set_value(msg, &pv_res->spec, 0, &pv_val) != 0) + { + LM_ERR("cannot populate parameter\n"); + return SV_GENERIC_FAILURE; + } + } + return ret; } #undef CHECK_HEADER @@ -1980,7 +2203,7 @@ static int change_reply_status_f(struct sip_msg* msg, char* str1, char* str2) } if (((code_i < 300) || (msg->REPLY_STATUS < 300)) - && (code_i/100 != msg->REPLY_STATUS/100)) { + && (code_i/100 != msg->REPLY_STATUS/100)) { LM_ERR("the class of provisional or positive final replies" " cannot be changed\n"); return -1; @@ -1993,9 +2216,9 @@ static int change_reply_status_f(struct sip_msg* msg, char* str1, char* str2) msg->first_line.u.reply.status.s[0] = code_i + '0'; l = del_lump(msg, - msg->first_line.u.reply.reason.s - msg->buf, - msg->first_line.u.reply.reason.len, - 0); + msg->first_line.u.reply.reason.s - msg->buf, + msg->first_line.u.reply.reason.len, + 0); if (!l) { LM_ERR("Failed to add del lump\n"); return -1; diff --git a/modules/siptrace/README b/modules/siptrace/README index c41139d64a9..d2bdeb7cb60 100644 --- a/modules/siptrace/README +++ b/modules/siptrace/README @@ -12,8 +12,7 @@ Daniel-Constantin Mierla Copyright © 2006 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -182,7 +181,7 @@ modparam("siptrace", "traced_user_avp", "$avp(user)") The name of the AVP storing the name of the table where to store the SIP messages. If it is not set, the value of 'table' parameter is used. In this way one can select dynamically where - to store the traced messages. The table must exists, and must + to store the traced messages. The table must exist, and must have the same structure as 'sip_trace' table. Default value is "NULL" (feature disabled). @@ -207,17 +206,36 @@ modparam("siptrace", "duplicate_uri", "sip:10.1.1.1:5888") 1.3.8. trace_local_ip (str) - The address to be used in fromip field for local generated - messages. If not set, the module sets it to the address of the - socket that will be used to send the message. + The address to be used in the fields that specify the source + address (protocol, ip and port) for locally generated messages. + If not set, the module sets it to the address of the socket + that will be used to send the message. Protocol and/or port are + optional and if omitted will take the default values: udp and + 5060. Default value is "NULL". Example 1.8. Set trace_local_ip parameter ... +#Resulting address: udp:10.1.1.1:5064 modparam("siptrace", "trace_local_ip", "10.1.1.1:5064") ... +... +#Resulting address: tcp:10.1.1.1:5060 +modparam("siptrace, "trace_local_ip", "tcp:10.1.1.1") +... + +... +#Resulting address: tcp:10.1.1.1:5064 +modparam("siptrace", "trace_local_ip", "tcp:10.1.1.1:5064") +... + +... +#Resulting address: udp:10.1.1.1:5060 +modparam("siptrace", "trace_local_ip", "10.1.1.1") +... + 1.3.9. table (str) Name of the table where to store the SIP messages. diff --git a/modules/siptrace/doc/siptrace_admin.xml b/modules/siptrace/doc/siptrace_admin.xml index e747e2bb4a5..ca545a8f693 100644 --- a/modules/siptrace/doc/siptrace_admin.xml +++ b/modules/siptrace/doc/siptrace_admin.xml @@ -1,9 +1,9 @@ - + &adminguide; - +
Overview @@ -190,7 +190,7 @@ modparam("siptrace", "traced_user_avp", "$avp(user)") store the SIP messages. If it is not set, the value of 'table' parameter is used. In this way one can select dynamically where to store the traced messages. The table - must exists, and must have the same structure as 'sip_trace' + must exist, and must have the same structure as 'sip_trace' table. @@ -231,9 +231,11 @@ modparam("siptrace", "duplicate_uri", "sip:10.1.1.1:5888")
<varname>trace_local_ip</varname> (str) - The address to be used in fromip field for local generated - messages. If not set, the module sets it to the address - of the socket that will be used to send the message. + The address to be used in the fields that specify the source address + (protocol, ip and port) for locally generated messages. If not set, + the module sets it to the address of the socket that will be used to send + the message. Protocol and/or port are optional and if omitted will take + the default values: udp and 5060. @@ -244,8 +246,24 @@ modparam("siptrace", "duplicate_uri", "sip:10.1.1.1:5888") Set <varname>trace_local_ip</varname> parameter ... +#Resulting address: udp:10.1.1.1:5064 modparam("siptrace", "trace_local_ip", "10.1.1.1:5064") ... + +... +#Resulting address: tcp:10.1.1.1:5060 +modparam("siptrace, "trace_local_ip", "tcp:10.1.1.1") +... + +... +#Resulting address: tcp:10.1.1.1:5064 +modparam("siptrace", "trace_local_ip", "tcp:10.1.1.1:5064") +... + +... +#Resulting address: udp:10.1.1.1:5060 +modparam("siptrace", "trace_local_ip", "10.1.1.1") +...
@@ -269,7 +287,7 @@ modparam("siptrace", "table", "strace")
- +
Exported Functions
@@ -298,7 +316,7 @@ sip_trace(); The function triggers the tracing of all messages belonging to a - dialog. The function must be called for the initial request (that + dialog. The function must be called for the initial request (that starts the dialog) and it will automatically take care of tracing evertyhing related to that dialog. @@ -368,7 +386,7 @@ modparam("siptrace", "duplicate_with_hep", 1)
<varname>hep_version</varname> (integer) - The parameter indicate the version of HEP protocol. + The parameter indicate the version of HEP protocol. Can be 1 or 2. In HEPv2 the timestamp and capture agent ID will be included to HEP header. @@ -385,11 +403,11 @@ modparam("siptrace", "hep_version", 2) ... -
+
<varname>hep_capture_id</varname> (integer) - The parameter indicate the capture agent ID for HEPv2 protocol. + The parameter indicate the capture agent ID for HEPv2 protocol. Limitation: 16-bit integer. @@ -407,7 +425,7 @@ modparam("siptrace", "hep_capture_id", 234)
- +
@@ -427,11 +445,11 @@ modparam("siptrace", "hep_capture_id", 234) trace_mode : turns on/off SIP message tracing. Possible values are: - on + on off The parameter is optional - if missing, the command will - return the status of the SIP message tracing (as string + return the status of the SIP message tracing (as string on or off ) without changing anything. @@ -461,13 +479,13 @@ modparam("siptrace", "hep_capture_id", 234) trace_to_db_mode : turns on/off SIP message tracing into DB. Possible values are: - on + on off The parameter is optional - if missing, the command will - return the status of the SIP message tracing (as string + return the status of the SIP message tracing (as string on or off ) without changing - anything. The parameter can be switched from off to on, + anything. The parameter can be switched from off to on, if db connection was before inizialized @@ -482,18 +500,18 @@ modparam("siptrace", "hep_capture_id", 234)
- +
- +
Database setup - Before running &osips; with siptrace, you have to setup the database - tables where the module will store the data. For that, if the + Before running &osips; with siptrace, you have to setup the database + tables where the module will store the data. For that, if the table were not created by the installation script or you choose to install everything by yourself you can use the siptrace-create.sql - SQL script in the database directories in the - opensips/scripts folder as template. + SQL script in the database directories in the + opensips/scripts folder as template. You can also find the complete database documentation on the project webpage, &osipsdbdocslink;. @@ -506,6 +524,6 @@ modparam("siptrace", "hep_capture_id", 234) flag, use sip_trace().
- + diff --git a/modules/siptrace/siptrace.c b/modules/siptrace/siptrace.c index f402993019d..9b033fc32e7 100644 --- a/modules/siptrace/siptrace.c +++ b/modules/siptrace/siptrace.c @@ -44,10 +44,12 @@ #include "../dialog/dlg_load.h" #include "../sl/sl_cb.h" #include "../../str.h" +#include "../../script_cb.h" #include "../sipcapture/sipcapture.h" -#define NR_KEYS 10 +#define NR_KEYS 14 +#define SIPTRACE_TABLE_VERSION 4 /* trace is completly disabled */ #define trace_is_off() \ @@ -97,9 +99,15 @@ static void trace_msg_out_w(struct sip_msg* req, str *buffer, static struct mi_root* sip_trace_mi(struct mi_root* cmd, void* param ); static struct mi_root* trace_to_database_mi(struct mi_root* cmd, void* param ); -static int trace_send_hep_duplicate(str *body, const char *fromip, const char *toip); -static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int *proto); +static int trace_send_hep_duplicate(str *body, str *fromproto, str *fromip, + unsigned short fromport, str *toproto, str *toip, unsigned short toport); +static int pipport2su (str *sproto, str *ip, unsigned short port, + union sockaddr_union *tmp_su, unsigned int *proto); +static int do_dlg_siptrace = 0; +static void siptrace_dlg_created(struct dlg_cell *did, int type,struct dlg_cb_params * params); +static int siptrace_cleanup( struct sip_msg *msg, void *param ); +static void siptrace_dlg_cancel(struct cell* t, int type, struct tmcb_params *param); static str db_url = {NULL, 0}; static str siptrace_table = str_init("sip_trace"); @@ -109,10 +117,14 @@ static str traced_user_column = str_init("traced_user"); /* 02 */ static str msg_column = str_init("msg"); /* 03 */ static str method_column = str_init("method"); /* 04 */ static str status_column = str_init("status"); /* 05 */ -static str fromip_column = str_init("fromip"); /* 06 */ -static str toip_column = str_init("toip"); /* 07 */ -static str fromtag_column = str_init("fromtag"); /* 08 */ -static str direction_column = str_init("direction"); /* 09 */ +static str fromproto_column = str_init("from_proto"); /* 06 */ +static str fromip_column = str_init("from_ip"); /* 07 */ +static str fromport_column = str_init("from_port"); /* 08 */ +static str toproto_column = str_init("to_proto"); /* 09 */ +static str toip_column = str_init("to_ip"); /* 10 */ +static str toport_column = str_init("to_port"); /* 11 */ +static str fromtag_column = str_init("fromtag"); /* 12 */ +static str direction_column = str_init("direction"); /* 13 */ static char *trace_flag_str = 0; int trace_flag = -1; @@ -136,7 +148,9 @@ static unsigned short trace_table_avp_type = 0; static int trace_table_avp; static str trace_table_avp_str = {NULL, 0}; +static str trace_local_proto = {NULL, 0}; static str trace_local_ip = {NULL, 0}; +static unsigned short trace_local_port = 0; static unsigned int enable_ack_trace = 0; @@ -172,8 +186,12 @@ static param_export_t params[] = { {"msg_column", STR_PARAM, &msg_column.s }, {"method_column", STR_PARAM, &method_column.s }, {"status_column", STR_PARAM, &status_column.s }, + {"fromproto_column", STR_PARAM, &fromproto_column.s }, {"fromip_column", STR_PARAM, &fromip_column.s }, + {"fromport_column", STR_PARAM, &fromport_column.s }, + {"toproto_column", STR_PARAM, &toproto_column.s }, {"toip_column", STR_PARAM, &toip_column.s }, + {"toport_column", STR_PARAM, &toport_column.s }, {"fromtag_column", STR_PARAM, &fromtag_column.s }, {"direction_column", STR_PARAM, &direction_column.s }, {"trace_flag", STR_PARAM, &trace_flag_str }, @@ -211,11 +229,25 @@ static stat_export_t siptrace_stats[] = { }; #endif +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "sl", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /* module exports */ struct module_exports exports = { "siptrace", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ #ifdef STATISTICS @@ -241,10 +273,103 @@ static int fixup_trace_dialog(void** param, int param_no) return -1; } + if (dlgb.register_dlgcb(NULL, DLGCB_CREATED, siptrace_dlg_created, NULL, NULL) < 0) { + LM_ERR("Failed to register dialog created callback \n"); + return -1; + } + + if (register_script_cb( siptrace_cleanup, POST_SCRIPT_CB|REQ_TYPE_CB,0)<0) { + LM_ERR("Failed to register postcript cleanup cb\n"); + return -1; + } + return 0; } +static int parse_trace_local_ip(void){ + /* We tokenize the trace_local_ip from proto:ip:port to three fields */ + + trace_local_ip.len = strlen(trace_local_ip.s); + unsigned int port_no; + char *c = strchr(trace_local_ip.s, ':'); + if (c == NULL) { + /* Only ip is specified */ + trace_local_port = SIP_PORT; + trace_local_proto.s = "udp"; + trace_local_proto.len = sizeof("udp") -1; + } + else { + str first_token = {c + 1, + trace_local_ip.len - (c - trace_local_ip.s) - 1}; + + if (str2int(&first_token, &port_no) == 0){ + + /* The first token is the port, so no proto */ + if (port_no > 65535 || port_no == 0){ + LM_WARN("trace local_ip: port is out of range (%d). " + "Will consider it to be %d\n", port_no, SIP_PORT); + trace_local_port = SIP_PORT; + } + else + trace_local_port = (unsigned short) port_no; + + trace_local_proto.s = "udp"; + trace_local_proto.len = sizeof("udp") - 1; + trace_local_ip.len = c - trace_local_ip.s; + } + else { + + /* The first token is the protocol */ + trace_local_proto.s = trace_local_ip.s; + trace_local_proto.len = c - trace_local_ip.s; + + if (trace_local_proto.len > 4){ + /* Too many letters for the protocol. Avoiding overflow */ + LM_ERR("trace_local_ip : wrong protocol\n"); + return -1; + } else if (trace_local_proto.len == 0){ + trace_local_proto.s = "udp"; + trace_local_proto.len = sizeof("udp") - 1; + } + + char *c2 = strchr(c + 1, ':'); + + if (c2 != NULL){ + + /* We have a second token */ + str second_token; + second_token.s = c2 + 1; + second_token.len = trace_local_ip.len - + (c2 - trace_local_ip.s) - 1; + + if (str2int(&second_token, &port_no) != 0) { + trace_local_port = SIP_PORT; + LM_WARN("trace_local_ip: port is wrongly defined. " + "Will consider it as %hd\n", trace_local_port); + } + else if (port_no > 65535 || port_no == 0){ + LM_WARN("trace local_ip: port is out of range (%d). " + "Will consider it to be %d\n", + port_no, SIP_PORT); + trace_local_port = SIP_PORT; + } + else + trace_local_port = (unsigned short) port_no; + trace_local_ip.s = c + 1; + trace_local_ip.len = c2 - c - 1; + } + else { + trace_local_port = SIP_PORT; + trace_local_ip.len -= c - trace_local_ip.s + 1; + trace_local_ip.s = c + 1; + } + } + } + + return 0; +} + static int mod_init(void) { pv_spec_t avp_spec; @@ -258,8 +383,12 @@ static int mod_init(void) msg_column.len = strlen(msg_column.s); method_column.len = strlen(method_column.s); status_column.len = strlen(status_column.s); + fromproto_column.len = strlen(fromproto_column.s); fromip_column.len = strlen(fromip_column.s); + fromport_column.len = strlen(fromport_column.s); + toproto_column.len = strlen(toproto_column.s); toip_column.len = strlen(toip_column.s); + toport_column.len = strlen(toport_column.s); fromtag_column.len = strlen(fromtag_column.s); direction_column.len = strlen(direction_column.s); if (traced_user_avp_str.s) @@ -268,12 +397,13 @@ static int mod_init(void) trace_table_avp_str.len = strlen(trace_table_avp_str.s); if (dup_uri_str.s) dup_uri_str.len = strlen(dup_uri_str.s); + if (trace_local_ip.s) - trace_local_ip.len = strlen(trace_local_ip.s); + parse_trace_local_ip(); LM_INFO("initializing...\n"); - fix_flag_name(&trace_flag_str, trace_flag); + fix_flag_name(trace_flag_str, trace_flag); trace_flag = get_flag_id_by_name(FLAG_TYPE_MSG, trace_flag_str); @@ -288,7 +418,7 @@ static int mod_init(void) *trace_to_database_flag = trace_to_database; - if(trace_to_database_flag!=NULL && *trace_to_database_flag!=0) { + if(trace_to_database_flag!=NULL && *trace_to_database_flag!=0) { /* Find a database module */ if (db_bind_mod(&db_url, &db_funcs)) { @@ -300,6 +430,20 @@ static int mod_init(void) LM_ERR("database modules does not provide all functions needed by module\n"); return -1; } + + if ((db_con = db_funcs.init(&db_url)) == 0) { + LM_CRIT("Cannot connect to DB\n"); + return -1; + } + + if(db_check_table_version(&db_funcs, db_con, + &siptrace_table, SIPTRACE_TABLE_VERSION) < 0) { + LM_ERR("error during table version check.\n"); + return -1; + } + + db_funcs.close(db_con); + db_con = 0; } trace_on_flag = (int*)shm_malloc(sizeof(int)); @@ -415,12 +559,16 @@ static int mod_init(void) db_keys[1] = &callid_column; db_keys[2] = &method_column; db_keys[3] = &status_column; - db_keys[4] = &fromip_column; - db_keys[5] = &toip_column; - db_keys[6] = &date_column; - db_keys[7] = &direction_column; - db_keys[8] = &fromtag_column; - db_keys[9] = &traced_user_column; + db_keys[4] = &fromproto_column; + db_keys[5] = &fromip_column; + db_keys[6] = &fromport_column; + db_keys[7] = &toproto_column; + db_keys[8] = &toip_column; + db_keys[9] = &toport_column; + db_keys[10] = &date_column; + db_keys[11] = &direction_column; + db_keys[12] = &fromtag_column; + db_keys[13] = &traced_user_column; /* init DB values info which is constant ( type, null ) */ db_vals[0].type = DB_BLOB; @@ -429,10 +577,14 @@ static int mod_init(void) db_vals[3].type = DB_STR; db_vals[4].type = DB_STR; db_vals[5].type = DB_STR; - db_vals[6].type = DB_DATETIME; - db_vals[7].type = DB_STRING; + db_vals[6].type = DB_INT; + db_vals[7].type = DB_STR; db_vals[8].type = DB_STR; - db_vals[9].type = DB_STR; + db_vals[9].type = DB_INT; + db_vals[10].type = DB_DATETIME; + db_vals[11].type = DB_STRING; + db_vals[12].type = DB_STR; + db_vals[13].type = DB_STR; /* no field can be null */ for (i=0;imsg; + t = tmb.t_gett(); + + // we also want to catch the incoming cancel + if ( tmb.register_tmcb( req, t,TMCB_TRANS_CANCELLED, + siptrace_dlg_cancel, NULL, NULL)<0 ) { + LM_ERR("failed to register trans cancelled TMCB\n"); + return; + } + } +} + +static void siptrace_dlg_cancel(struct cell* t, int type, struct tmcb_params *param) +{ + struct sip_msg *req; + req = param->req; + + LM_DBG("Tracing incoming cancel due to trace_dialog() \n"); + + /* set the flag */ + req->flags |= trace_flag; + req->msg_flags |= FL_USE_SIPTRACE; + /* trace current request */ + sip_trace(req); +} static inline int siptrace_copy_proto(int proto, char *buf) { @@ -742,19 +939,32 @@ static int sip_trace_w(struct sip_msg *msg) return sip_trace(msg); } -#define set_sock_column( _col,_buff, _ip, _port, _proto) \ +#define set_sock_columns( _col_proto, _col_ip, _col_port, _buff, _ip, _port, _proto) \ + do { \ + char *nbuff = proto2str( _proto, _buff); \ + _col_proto.val.str_val.s = _buff; \ + _col_proto.val.str_val.len = nbuff - _buff; \ + strcpy(nbuff, ip_addr2a(_ip)); \ + _col_ip.val.str_val.s = nbuff; \ + _col_ip.val.str_val.len = strlen(nbuff); \ + _col_port.val.int_val = _port; \ + } while (0) + +#define set_columns_to_any( _col_proto, _col_ip, _col_port) \ do { \ - char *p, *q; \ - int len; \ - p = proto2str( _proto, _buff); *(p++) = ':' ; \ - q = ip_addr2a( _ip ); len = strlen(q); \ - memcpy( p, q, len); p += len; *(p++) = ':' ; \ - q = int2str(_port, &len ); \ - memcpy( p, q, len); p += len; \ - _col.val.str_val.s = _buff; \ - _col.val.str_val.len = (int)(p - _buff); \ + _col_proto.val.str_val.s = "any"; \ + _col_proto.val.str_val.len = sizeof("any") - 1; \ + _col_ip.val.str_val.s = "255.255.255.255"; \ + _col_ip.val.str_val.len = sizeof("255.255.255.255") - 1; \ + _col_port.val.int_val = 9; \ } while (0) +#define set_columns_to_trace_local_ip( _col_proto, _col_ip, _col_port) \ + do { \ + db_vals[4].val.str_val = trace_local_proto; \ + db_vals[5].val.str_val = trace_local_ip; \ + db_vals[6].val.int_val = trace_local_port; \ + } while (0) static int sip_trace(struct sip_msg *msg) { @@ -818,18 +1028,18 @@ static int sip_trace(struct sip_msg *msg) db_vals[3].val.str_val.len = 0; } - set_sock_column( db_vals[4], fromip_buff, &msg->rcv.src_ip, - msg->rcv.src_port, msg->rcv.proto); + set_sock_columns( db_vals[4], db_vals[5], db_vals[6], fromip_buff, + &msg->rcv.src_ip, msg->rcv.src_port, msg->rcv.proto); - set_sock_column( db_vals[5], toip_buff, &msg->rcv.dst_ip, - msg->rcv.dst_port, msg->rcv.proto); + set_sock_columns( db_vals[7], db_vals[8], db_vals[9], toip_buff, + &msg->rcv.dst_ip, msg->rcv.dst_port, msg->rcv.proto); - db_vals[6].val.time_val = time(NULL); + db_vals[10].val.time_val = time(NULL); - db_vals[7].val.string_val = "in"; + db_vals[11].val.string_val = "in"; - db_vals[8].val.str_val.s = get_from(msg)->tag_value.s; - db_vals[8].val.str_val.len = get_from(msg)->tag_value.len; + db_vals[12].val.str_val.s = get_from(msg)->tag_value.s; + db_vals[12].val.str_val.len = get_from(msg)->tag_value.len; if (save_siptrace(msg,avp,&avp_value,db_keys,db_vals) < 0) { LM_ERR("failed to save siptrace\n"); @@ -1021,34 +1231,37 @@ static void trace_msg_out(struct sip_msg* msg, str *sbuf, memset(&to_ip, 0, sizeof(struct ip_addr)); - if (trace_local_ip.s && trace_local_ip.len > 0) - db_vals[4].val.str_val = trace_local_ip; + if (trace_local_ip.s && trace_local_ip.len > 0){ + set_columns_to_trace_local_ip( db_vals[4], db_vals[5], db_vals[6]); + } else { if(send_sock==0 || send_sock->sock_str.s==0) { - set_sock_column( db_vals[4], fromip_buff, &msg->rcv.dst_ip, - msg->rcv.dst_port, msg->rcv.proto); + set_sock_columns( db_vals[4], db_vals[5], db_vals[6], fromip_buff, + &msg->rcv.dst_ip, msg->rcv.dst_port, msg->rcv.proto); } else { - db_vals[4].val.str_val = send_sock->sock_str; + db_vals[4].val.str_val.s = proto2str(send_sock->proto,fromip_buff); + db_vals[4].val.str_val.len = strlen(db_vals[4].val.str_val.s); + db_vals[5].val.str_val = send_sock->sock_str; + db_vals[6].val.int_val = send_sock->port_no; } } if(to==0) { - db_vals[5].val.str_val.s = "any:255.255.255.255"; - db_vals[5].val.str_val.len = sizeof("any:255.255.255.255")-1; + set_columns_to_any(db_vals[7], db_vals[8], db_vals[9]); } else { su2ip_addr(&to_ip, to); - set_sock_column( db_vals[5], toip_buff, &to_ip, - (unsigned long)su_getport(to), proto); + set_sock_columns( db_vals[7], db_vals[8], db_vals[9], toip_buff, + &to_ip, (unsigned short)su_getport(to), proto); } - db_vals[6].val.time_val = time(NULL); + db_vals[10].val.time_val = time(NULL); - db_vals[7].val.string_val = "out"; + db_vals[11].val.string_val = "out"; - db_vals[8].val.str_val.s = get_from(msg)->tag_value.s; - db_vals[8].val.str_val.len = get_from(msg)->tag_value.len; + db_vals[12].val.str_val.s = get_from(msg)->tag_value.s; + db_vals[12].val.str_val.len = get_from(msg)->tag_value.len; if (save_siptrace(msg,avp,&avp_value,db_keys,db_vals) < 0) { LM_ERR("failed to save siptrace\n"); @@ -1133,22 +1346,23 @@ static void trace_onreply_in(struct cell* t, int type, struct tmcb_params *ps) db_vals[3].val.str_val.s = statusbuf; db_vals[3].val.str_val.len = len; - set_sock_column( db_vals[4], fromip_buff, &msg->rcv.src_ip, - msg->rcv.src_port, msg->rcv.proto); + set_sock_columns( db_vals[4], db_vals[5], db_vals[6], fromip_buff, + &msg->rcv.src_ip, msg->rcv.src_port, msg->rcv.proto); - if(trace_local_ip.s && trace_local_ip.len > 0) - db_vals[5].val.str_val = trace_local_ip; + if(trace_local_ip.s && trace_local_ip.len > 0){ + set_columns_to_trace_local_ip(db_vals[7], db_vals[8], db_vals[9]); + } else { - set_sock_column( db_vals[5], toip_buff, &msg->rcv.dst_ip, - msg->rcv.dst_port, msg->rcv.proto); + set_sock_columns( db_vals[7], db_vals[8], db_vals[9], toip_buff, + &msg->rcv.dst_ip, msg->rcv.dst_port, msg->rcv.proto); } - db_vals[6].val.time_val = time(NULL); + db_vals[10].val.time_val = time(NULL); - db_vals[7].val.string_val = "in"; + db_vals[11].val.string_val = "in"; - db_vals[8].val.str_val.s = get_from(msg)->tag_value.s; - db_vals[8].val.str_val.len = get_from(msg)->tag_value.len; + db_vals[12].val.str_val.s = get_from(msg)->tag_value.s; + db_vals[12].val.str_val.len = get_from(msg)->tag_value.len; if (save_siptrace(req,avp,&avp_value,db_keys,db_vals) < 0) { LM_ERR("failed to save siptrace\n"); @@ -1254,11 +1468,12 @@ static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps) db_vals[2].val.str_val.len = t->method.len; - if(trace_local_ip.s && trace_local_ip.len > 0) - db_vals[4].val.str_val = trace_local_ip; + if(trace_local_ip.s && trace_local_ip.len > 0){ + set_columns_to_trace_local_ip(db_vals[4], db_vals[5], db_vals[6]); + } else { - set_sock_column( db_vals[4], fromip_buff, &msg->rcv.dst_ip, - msg->rcv.dst_port, msg->rcv.proto); + set_sock_columns( db_vals[4], db_vals[5], db_vals[6], fromip_buff, + &msg->rcv.dst_ip, msg->rcv.dst_port, msg->rcv.proto); } strcpy(statusbuf, int2str(ps->code, &len)); @@ -1269,20 +1484,19 @@ static void trace_onreply_out(struct cell* t, int type, struct tmcb_params *ps) dst = (struct dest_info*)ps->extra2; if(dst==0) { - db_vals[5].val.str_val.s = "any:255.255.255.255"; - db_vals[5].val.str_val.len = sizeof("any:255.255.255.255")-1; + set_columns_to_any( db_vals[7], db_vals[8], db_vals[9]); } else { su2ip_addr(&to_ip, &dst->to); - set_sock_column( db_vals[5], toip_buff, &to_ip, - (unsigned long)su_getport(&dst->to), dst->proto); + set_sock_columns( db_vals[7], db_vals[8], db_vals[9], toip_buff, + &to_ip, (unsigned long)su_getport(&dst->to), dst->proto); } - db_vals[6].val.time_val = time(NULL); + db_vals[10].val.time_val = time(NULL); - db_vals[7].val.string_val = "out"; + db_vals[11].val.string_val = "out"; - db_vals[8].val.str_val.s = get_from(msg)->tag_value.s; - db_vals[8].val.str_val.len = get_from(msg)->tag_value.len; + db_vals[12].val.str_val.s = get_from(msg)->tag_value.s; + db_vals[12].val.str_val.len = get_from(msg)->tag_value.len; if (save_siptrace(req,avp,&avp_value,db_keys,db_vals) < 0) { LM_ERR("failed to save siptrace\n"); @@ -1371,11 +1585,12 @@ static void trace_sl_onreply_out( unsigned int types, struct sip_msg* req, db_vals[2].val.str_val.s = msg->first_line.u.request.method.s; db_vals[2].val.str_val.len = msg->first_line.u.request.method.len; - if(trace_local_ip.s && trace_local_ip.len > 0) - db_vals[4].val.str_val = trace_local_ip; + if(trace_local_ip.s && trace_local_ip.len > 0){ + set_columns_to_trace_local_ip( db_vals[4], db_vals[5], db_vals[6]); + } else { - set_sock_column( db_vals[4], fromip_buff, &msg->rcv.dst_ip, - msg->rcv.dst_port, msg->rcv.proto); + set_sock_columns( db_vals[4], db_vals[5], db_vals[6], fromip_buff, + &msg->rcv.dst_ip, msg->rcv.dst_port, msg->rcv.proto); } strcpy(statusbuf, int2str(sl_param->code, &len)); @@ -1385,20 +1600,19 @@ static void trace_sl_onreply_out( unsigned int types, struct sip_msg* req, memset(&to_ip, 0, sizeof(struct ip_addr)); if(sl_param->dst==0) { - db_vals[5].val.str_val.s = "any:255.255.255.255"; - db_vals[5].val.str_val.len = sizeof("any:255.255.255.255")-1; + set_columns_to_any(db_vals[7], db_vals[8], db_vals[9]); } else { su2ip_addr(&to_ip, sl_param->dst); - set_sock_column( db_vals[5], toip_buff, &to_ip, - (unsigned long)su_getport(sl_param->dst), req->rcv.proto); + set_sock_columns( db_vals[7], db_vals[8],db_vals[9], toip_buff, &to_ip, + (unsigned short)su_getport(sl_param->dst), req->rcv.proto); } - db_vals[6].val.time_val = time(NULL); + db_vals[10].val.time_val = time(NULL); - db_vals[7].val.string_val = "out"; + db_vals[11].val.string_val = "out"; - db_vals[8].val.str_val.s = get_from(msg)->tag_value.s; - db_vals[8].val.str_val.len = get_from(msg)->tag_value.len; + db_vals[12].val.str_val.s = get_from(msg)->tag_value.s; + db_vals[12].val.str_val.len = get_from(msg)->tag_value.len; if (save_siptrace(msg,avp,&avp_value,db_keys,db_vals) < 0) { LM_ERR("failed to save siptrace\n"); @@ -1573,7 +1787,8 @@ static int trace_send_duplicate(char *buf, int len) return ret; } -static int trace_send_hep_duplicate(str *body, const char *fromip, const char *toip) +static int trace_send_hep_duplicate(str *body, str *fromproto, str *fromip, + unsigned short fromport, str *toproto, str *toip, unsigned short toport) { struct proxy_l * p=NULL /* make gcc happy */; void* buffer = NULL; @@ -1616,7 +1831,8 @@ static int trace_send_hep_duplicate(str *body, const char *fromip, const char *t } /* Convert proto:ip:port to sockaddress union SRC IP */ - if (pipport2su((char *)fromip, &from_su, &proto)==-1 || (pipport2su((char *)toip, &to_su, &proto)==-1)) + if (pipport2su(fromproto, fromip, fromport, &from_su, &proto)==-1 || + (pipport2su(toproto, toip, toport, &to_su, &proto)==-1)) goto error; /* check if from and to are in the same family*/ @@ -1764,81 +1980,65 @@ static int trace_send_hep_duplicate(str *body, const char *fromip, const char *t * \param proto uint protocol type * \return success / unsuccess */ -static int pipport2su (char *pipport, union sockaddr_union *tmp_su, unsigned int *proto) +static int pipport2su (str *sproto, str *ip, unsigned short port, + union sockaddr_union *tmp_su, unsigned int *proto) { - unsigned int port_no, cutlen = 4; - struct ip_addr *ip; - char *p, *host_s; - str port_str, host_uri; - unsigned len = 0; + struct ip_addr *ip_a; + str host_uri; /*parse protocol */ - if(strncmp(pipport, "udp:",4) == 0) *proto = IPPROTO_UDP; - else if(strncmp(pipport, "tcp:",4) == 0) *proto = IPPROTO_TCP; - else if(strncmp(pipport, "tls:",4) == 0) *proto = IPPROTO_IDP; /* fake proto type */ + if(strncmp(sproto->s, "udp:",4) == 0) *proto = IPPROTO_UDP; + else if(strncmp(sproto->s, "tcp:",4) == 0) *proto = IPPROTO_TCP; + else if(strncmp(sproto->s, "tls:",4) == 0) *proto = IPPROTO_IDP; /* fake proto type */ #ifdef USE_SCTP - else if(strncmp(pipport, "sctp:",5) == 0) cutlen = 5, *proto = IPPROTO_SCTP; + else if(strncmp(sproto->s, "sctp:",5) == 0) cutlen = 5, *proto = IPPROTO_SCTP; #endif - else if(strncmp(pipport, "any:",4) == 0) *proto = IPPROTO_UDP; + else if(strncmp(sproto->s, "any:",4) == 0) *proto = IPPROTO_UDP; else { - LM_ERR("bad protocol %s\n", pipport); + LM_ERR("bad protocol %.*s\n", sproto->len, sproto->s); return -1; } - /*separate proto and host */ - p = pipport+cutlen; - if( (*(p)) == '\0') { + /*check if ip is not null*/ + if (ip->len == 0) { LM_ERR("malformed ip address\n"); return -1; } - host_s=p; - if( (p = strrchr(p+1, ':')) == 0 ) { - LM_ERR("no port specified\n"); - return -1; + if (port == 0) { + port = SIP_PORT; } + else{ /*the address contains a port number*/ - *p = '\0'; - p++; - port_str.s = p; - port_str.len = strlen(p); - LM_DBG("the port string is %s\n", p); - if(str2int(&port_str, &port_no) != 0 ) { - LM_ERR("there is not a valid number port\n"); - return -1; - } - *p = '\0'; - if (port_no<1024 || port_no>65536) - { - LM_ERR("invalid port number; must be in [1024,65536]\n"); - return -1; + if (port_no<1024 || port_no>65536) + { + LM_ERR("invalid port number; must be in [1024,65536]\n"); + return -1; + } } + LM_DBG("proto %d, host %.*s , port %d \n",*proto, ip->len, ip->s, port); /* now IPv6 address has no brakets. It should be fixed! */ - if (host_s[0] == '[') { - len = strlen(host_s + 1) - 1; - if(host_s[len+1] != ']') { + host_uri = *ip; + if (host_uri.s[0] == '[') { + if(host_uri.s[host_uri.len-1] != ']') { LM_ERR("bracket not closed\n"); return -1; } - memmove(host_s, host_s + 1, len); - host_s[len] = '\0'; + host_uri.s++; + host_uri.len -= 2; } - host_uri.s = host_s; - host_uri.len = strlen(host_s); - - /* check if it's an ip address */ - if (((ip=str2ip(&host_uri))!=0) + if (((ip_a = str2ip(&host_uri)) != 0) #ifdef USE_IPV6 - || ((ip=str2ip6(&host_uri))!=0) + || ((ip_a = str2ip6 (&host_uri)) != 0) #endif - ) { - ip_addr2su(tmp_su, ip, ntohs(port_no)); + ) { + ip_addr2su(tmp_su, ip_a, ntohs(port)); return 0; - } + LM_ERR("host <%.*s> is not an IP\n",host_uri.len,host_uri.s); return -1; } diff --git a/modules/sl/README b/modules/sl/README index 77ce4a950fb..40e9957e966 100644 --- a/modules/sl/README +++ b/modules/sl/README @@ -8,8 +8,7 @@ Bogdan Iancu Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/sl/sl.c b/modules/sl/sl.c index 79d3a76d4a9..d47de58db24 100644 --- a/modules/sl/sl.c +++ b/modules/sl/sl.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -110,8 +110,10 @@ struct module_exports sl_exports = { struct module_exports exports= { #endif "sl", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ mod_params, /* param exports */ mod_stats, /* exported statistics */ @@ -232,7 +234,7 @@ static int w_sl_send_reply(struct sip_msg* msg, char* str1, char* str2) } else { code_i = ((pv_elem_p)str1)->spec.pvp.pvn.u.isname.name.n; } - + if(((pv_elem_p)str2)->spec.getf!=NULL) { if(pv_printf_s(msg, (pv_elem_p)str2, &code_s)!=0 || code_s.len <=0) diff --git a/modules/sl/sl.h b/modules/sl/sl.h index d434342bcab..a7e2dcfa386 100644 --- a/modules/sl/sl.h +++ b/modules/sl/sl.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/sl/sl_api.h b/modules/sl/sl_api.h index 2f75a1645ab..931c08dd3d8 100644 --- a/modules/sl/sl_api.h +++ b/modules/sl/sl_api.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/sl/sl_funcs.c b/modules/sl/sl_funcs.c index aceb5737e7e..53147dbfabf 100644 --- a/modules/sl/sl_funcs.c +++ b/modules/sl/sl_funcs.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -55,6 +55,7 @@ #include "../../action.h" #include "../../config.h" #include "../../tags.h" +#include "../../script_cb.h" #include "sl.h" #include "sl_funcs.h" #include "sl_cb.h" @@ -105,12 +106,12 @@ int sl_get_totag(struct sip_msg *msg, str *totag) /* Take care of the statistics associated with numerical codes and replies */ -static inline void update_sl_reply_stat(int code) +static inline void update_sl_reply_stat(int code) { stat_var *numerical_stat; /* If stats aren't enabled, just skip over this. */ - if (!sl_enable_stats) + if (!sl_enable_stats) return; /* OpenSIPS already kept track of the total number of 1xx, 2xx, replies. @@ -165,7 +166,7 @@ int sl_send_reply_helper(struct sip_msg *msg ,int code, str *text) /* add a to-tag if there is a To header field without it */ if ( code>=180 && (msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to)) - && (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) + && (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) { calc_crc_suffix( msg, tag_suffix ); buf.s = build_res_buf_from_sip_req( code, text, &sl_tag, msg, @@ -220,7 +221,7 @@ int sl_reply_error(struct sip_msg *msg ) str text; int ret; - ret = err2reason_phrase( prev_ser_error, &sip_error, + ret = err2reason_phrase( prev_ser_error, &sip_error, err_buf, sizeof(err_buf), "SL"); if (ret<=0) { LM_ERR("err2reason failed\n"); @@ -262,26 +263,27 @@ int sl_filter_ACK(struct sip_msg *msg, void *bar ) if (parse_headers( msg, HDR_TO_F, 0 )==-1) { LM_ERR("unable to parse To header\n"); - return -1; + return SCB_RUN_ALL; } if (msg->to) { tag_str = &(get_to(msg)->tag_value); if ( tag_str->len==TOTAG_VALUE_LEN ) { - /* calculate the variable part of to-tag */ + /* calculate the variable part of to-tag */ calc_crc_suffix(msg, tag_suffix); /* test whether to-tag equal now */ if (memcmp(tag_str->s,sl_tag.s,sl_tag.len)==0) { LM_DBG("local ACK found -> dropping it!\n"); if_update_stat( sl_enable_stats, rcv_acks, 1); run_sl_callbacks( SLCB_ACK_IN, msg, 0, 0, 0, 0 ); - return 0; + + return SCB_DROP_MSG; } } } pass_it: - return 1; + return SCB_RUN_ALL; } diff --git a/modules/sl/sl_funcs.h b/modules/sl/sl_funcs.h index f8efabfc1fb..c1ae7c6755f 100644 --- a/modules/sl/sl_funcs.h +++ b/modules/sl/sl_funcs.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/sms/README b/modules/sms/README index 296e143205e..9e4c166aee7 100644 --- a/modules/sms/README +++ b/modules/sms/README @@ -8,8 +8,7 @@ Bogdan-Andrei Iancu Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/sms/libsms_charset.c b/modules/sms/libsms_charset.c index 7a59e938548..2e0c29fd67a 100644 --- a/modules/sms/libsms_charset.c +++ b/modules/sms/libsms_charset.c @@ -3,7 +3,7 @@ SMS Server Tools Copyright (C) 2000 Stefan Frings This program is free software unless you got it under another license directly -from the author. You can redistribute it and/or modify it under the terms of +from the author. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. Either version 2 of the License, or (at your option) any later version. @@ -14,7 +14,7 @@ mailto:s.frings@mail.isis.de #include "libsms_charset.h" -#define noc 183 +#define noc 183 // non existent character // iso 8859-1 @@ -35,7 +35,7 @@ unsigned char charset[128] ={ 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' , 228 , 246 , 241 , 252 , 224 }; - + char ascii2sms(const char c) { char found='*'; // replacement for nonexistent characters diff --git a/modules/sms/libsms_charset.h b/modules/sms/libsms_charset.h index e39a4d82def..9fe01096d2c 100644 --- a/modules/sms/libsms_charset.h +++ b/modules/sms/libsms_charset.h @@ -3,7 +3,7 @@ SMS Server Tools Copyright (C) 2000 Stefan Frings This program is free software unless you got it under another license directly -from the author. You can redistribute it and/or modify it under the terms of +from the author. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. Either version 2 of the License, or (at your option) any later version. diff --git a/modules/sms/libsms_getsms.c b/modules/sms/libsms_getsms.c index 1f93368e77c..84876d5d1ec 100644 --- a/modules/sms/libsms_getsms.c +++ b/modules/sms/libsms_getsms.c @@ -171,7 +171,7 @@ static int fetchsms(struct modem *mdm, int sim, char* pdu) position=strstr(answer,"+CMGR:"); } - /* keine SMS empfangen, weil Modem nicht mit +CMGR + /* keine SMS empfangen, weil Modem nicht mit +CMGR oder +CMGL geantwortet hat */ if (position==0) return 0; @@ -220,7 +220,7 @@ int check_memory(struct modem *mdm, int flag) int err,foo; int j, out; - for(out=0,j=0;!out && j<10; j++) + for(out=0,j=0;!out && j<10; j++) { if (put_command(mdm,"AT+CPMS?\r",9,answer,sizeof(answer),50,0) && (posi=strstr(answer,"+CPMS:"))!=0 ) @@ -359,7 +359,7 @@ static int split_type_0( char* Pointer,struct incame_sms *sms) /* Subroutine for splitpdu() for messages type 2 (Staus Report) - Returns the length of the ascii string. In binary mode ascii + Returns the length of the ascii string. In binary mode ascii contains the binary SMS */ static int split_type_2( char* position, struct incame_sms *sms) { diff --git a/modules/sms/libsms_modem.h b/modules/sms/libsms_modem.h index feeb6acac9b..7a1d49ef538 100644 --- a/modules/sms/libsms_modem.h +++ b/modules/sms/libsms_modem.h @@ -3,7 +3,7 @@ SMS Server Tools Copyright (C) 2000 Stefan Frings This program is free software unless you got it under another license directly -from the author. You can redistribute it and/or modify it under the terms of +from the author. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. Either version 2 of the License, or (at your option) any later version. diff --git a/modules/sms/sms.c b/modules/sms/sms.c index f480c689924..34c5dab9f1a 100644 --- a/modules/sms/sms.c +++ b/modules/sms/sms.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -86,13 +86,22 @@ static proc_export_t sms_procs[] = { static cmd_export_t cmds[]={ - {"sms_send_msg_to_net", (cmd_function)w_sms_send_msg_to_net, 1, + {"sms_send_msg_to_net", (cmd_function)w_sms_send_msg_to_net, 1, fixup_sms_send_msg_to_net, 0, REQUEST_ROUTE}, - {"sms_send_msg", (cmd_function)w_sms_send_msg, 0, + {"sms_send_msg", (cmd_function)w_sms_send_msg, 0, 0, 0, REQUEST_ROUTE}, {0,0,0,0,0,0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; static param_export_t params[]={ {"networks", STR_PARAM, &networks_config }, @@ -109,8 +118,10 @@ static param_export_t params[]={ struct module_exports exports= { "sms", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, params, 0, /* exported statistics */ @@ -497,12 +508,12 @@ int parse_config_lines(void) return 0; parse_error: - LM_ERR("SMS %s config: parse error before chr %d [%.*s]\n", + LM_ERR("SMS %s config: parse error before chr %d [%.*s]\n", (step==1)?"modems":(step==2?"networks":"links"), (int)(p - ((step==1)?modems_config: (step==2?networks_config:links_config))), (*p==0)?4:1,(*p==0)?"NULL":p ); - + error: return -1; } diff --git a/modules/sms/sms_funcs.c b/modules/sms/sms_funcs.c index 92f28502183..f3587e1b75a 100644 --- a/modules/sms/sms_funcs.c +++ b/modules/sms/sms_funcs.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -138,7 +138,7 @@ int push_on_network(struct sip_msg *msg, int net) goto error; } - /* we try to get the user name (phone number) first from the RURI + /* we try to get the user name (phone number) first from the RURI (in our case means from new_uri or from first_line.u.request.uri); if it's missing there (like in requests generated by MSN MESSENGER), we go for "to" header @@ -515,7 +515,7 @@ int send_sms_as_sip( struct incame_sms *sms ) sms->ascii); goto error; } - + } /* lets get the address */ if (p[0]!='s' || p[1]!='i' || p[2]!='p' || p[3]!=':') { @@ -762,7 +762,7 @@ void modem_process(struct modem *mdm) sms.userdatalength,sms.ascii); if (!sms.is_statusreport) send_sms_as_sip(&sms); - else + else check_sms_report(&sms); } } diff --git a/modules/sms/sms_funcs.h b/modules/sms/sms_funcs.h index fe3ad0ab01d..ec8940d93df 100644 --- a/modules/sms/sms_funcs.h +++ b/modules/sms/sms_funcs.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/sms/sms_report.c b/modules/sms/sms_report.c index 3c62fd26051..16bbc3e09e3 100644 --- a/modules/sms/sms_report.c +++ b/modules/sms/sms_report.c @@ -276,12 +276,12 @@ str* get_error_str(int status) START_ERR_MSG"Error, remote procedure error"END_ERR_MSG; err_str.len = 29 + START_ERR_MSG_LEN + END_ERR_MSG_LEN; break; - case 65: + case 65: err_str.s = START_ERR_MSG"Error,incompatible destination"END_ERR_MSG; err_str.len = 30 + START_ERR_MSG_LEN + END_ERR_MSG_LEN; break; - case 66: + case 66: err_str.s = START_ERR_MSG"Error,connection rejected by SME"END_ERR_MSG; err_str.len = 32 + START_ERR_MSG_LEN + END_ERR_MSG_LEN; diff --git a/modules/sngtc/Makefile b/modules/sngtc/Makefile new file mode 100644 index 00000000000..f3dc00a6e35 --- /dev/null +++ b/modules/sngtc/Makefile @@ -0,0 +1,8 @@ +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen = +NAME = sngtc.so +LIBS = -lsngtc_node + +include ../../Makefile.modules diff --git a/modules/sngtc/README b/modules/sngtc/README new file mode 100644 index 00000000000..600d5d639c4 --- /dev/null +++ b/modules/sngtc/README @@ -0,0 +1,171 @@ +sngtc Module + +Liviu Chircu + + OpenSIPS Solutions + +Edited by + +Liviu Chircu + + Copyright © 2013 www.opensips-solutions.com + __________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1.1. Overview + 1.2. How it works + 1.3. Dependencies + + 1.3.1. OpenSIPS Modules + 1.3.2. External Libraries or Applications + + 1.4. Exported Functions + + 1.4.1. sngtc_offer() + 1.4.2. sngtc_callee_answer([listen_if_A[, + listen_if_B]]) + + 1.4.3. sngtc_caller_answer() + + List of Examples + + 1.1. sngtc_offer usage + 1.2. sngtc_callee_answer usage + 1.3. sngtc_caller_answer usage + +Chapter 1. Admin Guide + +1.1. Overview + + The Sangoma transcoding module offers the possibility of + performing voice transcoding with the D-series transcoding + cards manufactured by Sangoma. The module makes use of the + Sangoma Transcoding API in order to manage transcoding sessions + on the dedicated equipment. For the cards in the network to be + detected, the Sangoma SOAP server must be up and running + (sngtc_server daemon). + +1.2. How it works + + The module performs several modifications in the SDP body of + SIP INVITE, 200 OK and ACK messages. In all transcoding + scenarios, the UAC performs early SDP negotiation, while the + UAS does late negotiation. This way, OpenSIPS becomes + responsible for intersecting the codec offer and answer, + together with the management of transcoding sessions on the + Sangoma cards. + + This scenario brings about a couple of restrictions: + * UACs MUST only perform early SDP negotiation + * UASs MUST support late SDP negotiation (rfc 3261 + requirement) + + Since the sngtc_node library performs several memory + allocations with each newly created transcoding session, the + module uses a dedicated process, responsible for the management + of the above-mentioned sessions. The sangoma_worker process + communicates with the OpenSIPS UDP receivers through a series + of pipes. + +1.3. Dependencies + +1.3.1. OpenSIPS Modules + + The following modules must be loaded before this module: + * dialog. + +1.3.2. External Libraries or Applications + + The following libraries or applications must be installed + before running OpenSIPS with this module loaded: + * sngtc_node library. + * sngtc_server up and running. + +1.4. Exported Functions + +1.4.1. sngtc_offer() + + The function strips off the SDP offer from a SIP INVITE, thus + asking for another SDP offer from the opposite endpoint (late + negotiation). + + The following error codes may be returned: + * -1 - SDP parsing error + * -3 - internal error / no more memory + + The function can be used from REQUEST_ROUTE, ONREPLY_ROUTE. + + Example 1.1. sngtc_offer usage +... + if (is_method("INVITE")) { + t_newtran(); + create_dialog(); + sngtc_offer(); + } +... + +1.4.2. sngtc_callee_answer([listen_if_A[, listen_if_B]]) + + Handles the SDP offer from 200 OK responses, intersects both + offers with the capabilities of the transcoding card and + creates a new transcoding session on the card only if + necessary. It then rewrites the 200 OK SDP so that it contains + the information resulted from the codec intersection. + + Parameters explained: + + Since the D-series transcoding cards are connected through + either a PCI slot or simply an Ethernet connector, they cannot + be assigned global IPs. Consequently, the module will write the + local, private IP of the card in the SDP answers sent to each + of the endpoints. Since this will not work with non-local UAs, + the optional parameters force the RTP listen interface for each + UA. This way, the script writer can enforce a global IP for the + incoming RTP (which can be port forwarded to a transcoding + card). + * listen_if_A - the interface where the UAC (the caller) will + send RTP after the call is established (IP from the 'c=' + SDP line(s)) + * listen_if_B - the interface where the UAS (the callee) will + send RTP after the call is established (IP from the 'c=' + SDP line(s)) + + The following error codes may be returned: + * -1 - SDP parsing error + * -2 - failed to create transcoding session + * -3 - internal error / no more memory + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE. + + Example 1.2. sngtc_callee_answer usage +... +onreply_route[1] { + if ($rs == 200) + sngtc_callee_answer("11.12.13.14", "11.12.13.14"); +} +... + +1.4.3. sngtc_caller_answer() + + Attaches an SDP body to the caller's ACK request, so that it + matches the late SDP negotiation done by the UAS. + + The following error codes may be returned: + * -3 - internal error / no more memory + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE. + + Example 1.3. sngtc_caller_answer usage +... + if (has_totag()) { + if (loose_route()) { + ... + if (is_method("ACK")) + sngtc_caller_answer(); + } + ... + } +... diff --git a/modules/sngtc/doc/sngtc.xml b/modules/sngtc/doc/sngtc.xml new file mode 100644 index 00000000000..89bfcdbb42e --- /dev/null +++ b/modules/sngtc/doc/sngtc.xml @@ -0,0 +1,44 @@ + + + + + +%docentities; + +]> + + + + sngtc Module + &osipsname; + + + Liviu + Chircu + OpenSIPS Solutions +
+ liviu@opensips.org +
+
+ + Liviu + Chircu +
+ liviu@opensips.org +
+
+
+ + 2013 + &osipssol; + +
+ + + &admin; + +
diff --git a/modules/sngtc/doc/sngtc_admin.xml b/modules/sngtc/doc/sngtc_admin.xml new file mode 100644 index 00000000000..61d02cc167a --- /dev/null +++ b/modules/sngtc/doc/sngtc_admin.xml @@ -0,0 +1,243 @@ + + + + + &adminguide; + +
+ Overview + + The Sangoma transcoding module offers the possibility of performing + voice transcoding with the D-series transcoding cards manufactured by + Sangoma. The module makes use of the Sangoma Transcoding API in order to + manage transcoding sessions on the dedicated equipment. For the cards + in the network to be detected, the Sangoma SOAP server must be up and + running (sngtc_server daemon). + +
+ +
+ How it works + + The module performs several modifications in the SDP body of SIP INVITE, + 200 OK and ACK messages. In all transcoding scenarios, the UAC performs early + SDP negotiation, while the UAS does late negotiation. This way, OpenSIPS + becomes responsible for intersecting the codec offer and answer, together with + the management of transcoding sessions on the Sangoma cards. + + + + This scenario brings about a couple of + restrictions: + + + + UACs MUST only perform early SDP negotiation + + + + + UASs MUST support late SDP negotiation (rfc 3261 requirement) + + + + + + + Since the sngtc_node library performs several memory + allocations with each newly created transcoding session, the module uses a + dedicated process, responsible for the management of the above-mentioned sessions. The + sangoma_worker process communicates with the OpenSIPS + UDP receivers through a series of pipes. + +
+ +
+ Dependencies +
+ &osips; Modules + + The following modules must be loaded before this module: + + + + dialog. + + + + +
+ +
+ External Libraries or Applications + + The following libraries or applications must be installed before running + &osips; with this module loaded: + + + + sngtc_node library. + + + + + sngtc_server up and running. + + + + +
+
+ +
+ Exported Functions +
+ + <function moreinfo="none">sngtc_offer()</function> + + + The function strips off the SDP offer from a SIP INVITE, thus + asking for another SDP offer from the opposite endpoint (late negotiation). + + + + The following error codes may be returned: + + + -1 - SDP parsing error + + + + -3 - internal error / no more memory + + + + + + + The function can be used from REQUEST_ROUTE, ONREPLY_ROUTE. + + + <function moreinfo="none">sngtc_offer</function> usage + +... + if (is_method("INVITE")) { + t_newtran(); + create_dialog(); + sngtc_offer(); + } +... + + +
+ +
+ + <function moreinfo="none">sngtc_callee_answer([listen_if_A[, listen_if_B]]) + </function> + + + Handles the SDP offer from 200 OK responses, intersects both offers with + the capabilities of the transcoding card and creates a new transcoding + session on the card only if necessary. It then rewrites the 200 OK SDP so that it + contains the information resulted from the codec intersection. + + + Parameters explained: + + Since the D-series transcoding cards are connected through either a + PCI slot or simply an Ethernet connector, they cannot be assigned + global IPs. Consequently, the module will write the local, private IP of the + card in the SDP answers sent to each of the endpoints. Since this will not + work with non-local UAs, the optional parameters force the RTP listen + interface for each UA. This way, the script writer can enforce a global IP + for the incoming RTP (which can be port forwarded to a transcoding card). + + + listen_if_A - the interface where the UAC (the caller) will send RTP after the call is established (IP from the 'c=' SDP line(s)) + + + + listen_if_B - the interface where the UAS (the callee) will send RTP after the call is established (IP from the 'c=' SDP line(s)) + + + + + + + The following error codes may be returned: + + + -1 - SDP parsing error + + + + -2 - failed to create transcoding session + + + + -3 - internal error / no more memory + + + + + + + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE. + + + <function moreinfo="none">sngtc_callee_answer</function> usage + +... +onreply_route[1] { + if ($rs == 200) + sngtc_callee_answer("11.12.13.14", "11.12.13.14"); +} +... + + +
+ +
+ + <function moreinfo="none">sngtc_caller_answer()</function> + + + Attaches an SDP body to the caller's ACK request, so that it matches + the late SDP negotiation done by the UAS. + + + + The following error codes may be returned: + + + -3 - internal error / no more memory + + + + + + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE. + + + <function moreinfo="none">sngtc_caller_answer</function> usage + +... + if (has_totag()) { + if (loose_route()) { + ... + if (is_method("ACK")) + sngtc_caller_answer(); + } + ... + } +... + + +
+ +
+
+ diff --git a/modules/sngtc/sngtc.c b/modules/sngtc/sngtc.c new file mode 100644 index 00000000000..b905db0ebf8 --- /dev/null +++ b/modules/sngtc/sngtc.c @@ -0,0 +1,1465 @@ +/** + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History + * ------- + * 2013-06-05 created (liviu) + * + */ + +#include +#include + +#include "../../sr_module.h" +#include "../../dprint.h" +#include "../../error.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../../parser/sdp/sdp.h" +#include "../../data_lump.h" +#include "../../ut.h" +#include "../../pt.h" +#include "../../mod_fix.h" +#include "../dialog/dlg_load.h" + +#include + +#include "sngtc.h" +#include "sngtc_proc.h" + +static struct codec_mapping codec_str_mappings[] = { + { {"AMR", 3}, 8000, 0, SNGTC_CODEC_AMR_475 }, + { {"AMR", 3}, 8000, 1, SNGTC_CODEC_AMR_515 }, + { {"AMR", 3}, 8000, 2, SNGTC_CODEC_AMR_590 }, + { {"AMR", 3}, 8000, 3, SNGTC_CODEC_AMR_670 }, + { {"AMR", 3}, 8000, 4, SNGTC_CODEC_AMR_740 }, + { {"AMR", 3}, 8000, 5, SNGTC_CODEC_AMR_795 }, + { {"AMR", 3}, 8000, 6, SNGTC_CODEC_AMR_1020 }, + { {"AMR", 3}, 8000, 7, SNGTC_CODEC_AMR_1220 }, + { {"G722", 4}, 8000, -1, SNGTC_CODEC_G722 }, + { {"G723", 4}, 8000, -1, SNGTC_CODEC_G723_1 }, + { {"G723", 4}, 8000, -1, SNGTC_CODEC_G723_1 }, + { {"G726-16", 7}, 8000, -1, SNGTC_CODEC_G726_16 }, + { {"G726-24", 7}, 8000, -1, SNGTC_CODEC_G726_24 }, + { {"G726-32", 7}, 8000, -1, SNGTC_CODEC_G726_32 }, + { {"G726-40", 7}, 8000, -1, SNGTC_CODEC_G726_40 }, + { {"G729", 4}, 8000, -1, SNGTC_CODEC_G729AB }, + { { "GSM", 3}, 8000, -1, SNGTC_CODEC_GSM_FR }, + { {"iLBC", 4}, 8000, -1, SNGTC_CODEC_ILBC }, + { { "L16", 3}, 44100, -1, SNGTC_CODEC_L16_2 }, + { { "L16", 3}, 44100, -1, SNGTC_CODEC_L16_1 }, + { {"PCMA", 4}, 8000, -1, SNGTC_CODEC_PCMA }, + { {"PCMA", 4}, 8000, -1, SNGTC_CODEC_PCMA }, + { {"PCMU", 4}, 8000, -1, SNGTC_CODEC_PCMU }, + { {"SIREN", 5}, 16000, -1, SNGTC_CODEC_SIREN7_24 }, + { { 0, 0 }, -1, -1, -1 } +}; + +/* Mappings of standard payload types and Sangoma codecs */ +static struct codec_mapping codec_int_mappings[] = { + { { "0", 1}, 8000, -1, SNGTC_CODEC_PCMU }, + { { "3", 1}, 8000, -1, SNGTC_CODEC_GSM_FR }, + { { "4", 1}, 8000, -1, SNGTC_CODEC_G723_1 }, + { { "8", 1}, 8000, -1, SNGTC_CODEC_PCMA }, + { { "9", 1}, 8000, -1, SNGTC_CODEC_G722 }, + { { "10",2}, 44100, -1, SNGTC_CODEC_L16_2 }, + { { "11",2}, 44100, -1, SNGTC_CODEC_L16_1 }, + { { "18",2}, 8000, -1, SNGTC_CODEC_G729AB }, + { { "0", 0}, -1, -1, -1 } +}; + +/* internal module variables */ +static str dlg_key_sngtc_info = str_init("SngTc"); + +static str sdp_buffer = { NULL, 0 }; + +/* results of matchings on all streams of two endpoints */ +static struct codec_pair codec_matches[MAX_STREAMS]; + +/* force a certain IP for the transcoding card (most often a public IP) */ +static str card_ip_a, card_ip_b; + +/* index of the current SIP UDP receiver's pipe */ +static int pipe_index; + +/* one R+W pipe for each SIP UDP receiver process */ +int *udp_receiver_pipes; + +/* pipe for the sangoma worker */ +int sangoma_pipe[2]; + +static int *proc_counter; +gen_lock_t *index_lock; + +/* generic module functions */ +static int mod_init(void); +static int child_init(int rank); +static void mod_destroy(void); + +static sngtc_init_cfg_t sngtc_init_cfg; +static struct dlg_binds dlg_binds; + + +/* module specific functions */ +static int sngtc_offer(struct sip_msg *msg); +static int w_sngtc_callee_answer(struct sip_msg *msg, + char *gp_ip_a, char *gp_ip_b); +static int sngtc_callee_answer(struct sip_msg *msg); +static int sngtc_caller_answer(struct sip_msg *msg); + +static int sng_logger(int level, char *fmt, ...); + +static proc_export_t procs[] = { + { "sangoma_worker", NULL, NULL, sangoma_worker_loop, 1, 0 }, + { 0, 0, 0, 0, 0, 0 }, +}; + +static param_export_t params[] = { + { 0, 0, 0 } +}; + +static cmd_export_t cmds[] = { + { "sngtc_offer", (cmd_function)sngtc_offer, 0, 0, 0, + REQUEST_ROUTE|ONREPLY_ROUTE }, + { "sngtc_callee_answer", (cmd_function)w_sngtc_callee_answer, 0, 0, 0, + REQUEST_ROUTE|ONREPLY_ROUTE }, + { "sngtc_callee_answer", (cmd_function)w_sngtc_callee_answer, 1, + fixup_sgp_null, 0, REQUEST_ROUTE|ONREPLY_ROUTE }, + { "sngtc_callee_answer", (cmd_function)w_sngtc_callee_answer, 2, + fixup_sgp_sgp, 0, REQUEST_ROUTE|ONREPLY_ROUTE }, + { "sngtc_caller_answer", (cmd_function)sngtc_caller_answer, 0, 0, 0, + REQUEST_ROUTE|ONREPLY_ROUTE }, + { 0, 0, 0, 0, 0, 0 } +}; + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "dialog", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + +struct module_exports exports= { + "sngtc", + MOD_TYPE_DEFAULT,/* class of this module */ + MODULE_VERSION, + DEFAULT_DLFLAGS, + &deps, /* OpenSIPS module dependencies */ + cmds, + params, + 0, + 0, + 0, + procs, + mod_init, + (response_function) 0, + (destroy_function)mod_destroy, + child_init +}; + +int sng_create_rtp(void * usr_priv, sngtc_codec_request_leg_t *codec_reg_leg, + sngtc_codec_reply_leg_t* codec_reply_leg, void **rtp_fd) +{ + LM_DBG("create_rtp callback\n"); + + return 0; +} + +int sng_create_rtp_port(void * usr_priv, uint32_t host_ip, uint32_t *rtp_port, + void **rtp_fd) +{ + LM_DBG("create_rtp_port callback\n"); + + return 0; +} + +int sng_destroy_rtp(void * usr_priv, void *fd) +{ + LM_DBG("destroy_rtp callback\n"); + + return 0; +} + +int sng_release_rtp_port(void * usr_priv, uint32_t host_ip, uint32_t rtp_port, + void *rtp_fd) +{ + LM_DBG("release_rtp_port callback\n"); + + return 0; +} + +void free_transcoding_sessions(struct sngtc_session_list *first) +{ + struct sngtc_session_list *session, *aux; + struct sngtc_request req; + int rc; + + req.type = REQ_FREE_SESSION; + req.response_fd = udp_receiver_pipes[pipe_index + WRITE_END]; + + for (session = first; session; ) { + + LM_DBG("freeing transcoding session %p\n", session->reply); + sngtc_print_reply(L_DBG, session->reply); + + req.sng_reply = session->reply; + + if (write(sangoma_pipe[WRITE_END], &req, sizeof(req)) < 0) { + LM_ERR("failed to write on sangoma pipe fd %d (%d: %s)\n", + sangoma_pipe[WRITE_END], errno, strerror(errno)); + goto free_mem; + } + + if (read(udp_receiver_pipes[pipe_index + READ_END], &rc, sizeof(rc)) < 0) { + LM_ERR("failed to read sangoma worker reply on pipe fd %d (%d: %s)\n", + udp_receiver_pipes[pipe_index + READ_END], errno, + strerror(errno)); + goto free_mem; + } + + if (rc != 0) { + LM_ERR("failed to free transcoding session\n"); + sngtc_print_reply(L_ERR, session->reply); + } + + LM_DBG("successfully freed transcoding session\n"); + +free_mem: + aux = session; + session = session->next; + + shm_free(aux); + } +} + +/** + * sngtc_dlg_terminated (callback) - completely free the struct sngtc_info * + * attached to the dialog. + * + * Also releases the ongoing transcoding session(s) at card level + */ +void sngtc_dlg_terminated(struct dlg_cell *dlg, int type, + struct dlg_cb_params *params) +{ + str info_ptr; + struct sngtc_info *info; + + LM_DBG("freeing the sdp buffer\n"); + + if (dlg_binds.fetch_dlg_value(dlg, &dlg_key_sngtc_info, &info_ptr, 0) != 0) { + LM_ERR("failed to fetch caller sdp\n"); + return; + } + + info = *(struct sngtc_info **)info_ptr.s; + LM_DBG("Info ptr: %p\n", info); + + free_transcoding_sessions(info->sessions); + + if (info->caller_sdp.s) + shm_free(info->caller_sdp.s); + if (info->modified_caller_sdp.s) + shm_free(info->modified_caller_sdp.s); + + shm_free(info); +} + +static int mod_init(void) +{ + int i, udp_receiver_no; + + LM_INFO("initializing module\n"); + + memset(&dlg_binds, 0, sizeof(dlg_binds)); + if (load_dlg_api(&dlg_binds) != 0) { + LM_ERR("failed to load dlg api\n"); + return -1; + } + + sdp_buffer.s = pkg_malloc(SDP_BUFFER_SIZE); + if (!sdp_buffer.s) { + LM_ERR("insufficient pkg memory\n"); + return -1; + } + + udp_receiver_no = count_init_children(0); + + if (!dont_fork) { + +#ifdef USE_TCP + udp_receiver_no -= !tcp_disable ? tcp_children_no : 0; +#endif + + udp_receiver_no--; /* MAIN */ + } + + udp_receiver_no -= 2; /* TIMER, SANGOMA WORKER */ + + LM_DBG("Children: %d\n", udp_receiver_no); + + udp_receiver_pipes = pkg_malloc(2 * udp_receiver_no * + sizeof(*udp_receiver_pipes)); + if (!udp_receiver_pipes) { + LM_ERR("Not enough pkg mem\n"); + return -1; + } + + index_lock = shm_malloc(sizeof(*index_lock)); + if (!index_lock) { + LM_ERR("No more shm mem\n"); + return -1; + } + + if (!lock_init(index_lock)) { + LM_ERR("Failed to init lock\n"); + return -1; + } + + proc_counter = shm_malloc(sizeof(*proc_counter)); + if (!proc_counter) { + LM_ERR("Not enough shm mem\n"); + return -1; + } + + *proc_counter = 0; + + if (pipe(sangoma_pipe) != 0) { + LM_ERR("Failed to create sangoma worker pipe\n"); + return -1; + } + + LM_DBG("Sangoma pipe: [%d %d]\n", sangoma_pipe[0], sangoma_pipe[1]); + + for (i = 0; i < udp_receiver_no; i++) { + if (pipe(udp_receiver_pipes + 2 * i) != 0) { + LM_ERR("Failed to create pipe for UDP receiver %d\n", i); + return -1; + } + + LM_DBG("SIP pipe: [%d %d]\n", udp_receiver_pipes[2 * i], + udp_receiver_pipes[2 * i + 1]); + } + + sngtc_init_cfg.operation_mode = SNGTC_MODE_SOAP_CLIENT; + sngtc_init_cfg.log = sng_logger; + sngtc_init_cfg.create_rtp = sng_create_rtp; + sngtc_init_cfg.create_rtp_port = sng_create_rtp_port; + sngtc_init_cfg.destroy_rtp = sng_destroy_rtp; + sngtc_init_cfg.release_rtp_port = sng_release_rtp_port; + + if (sngtc_detect_init_modules(&sngtc_init_cfg, &i) != 0) { + LM_ERR("failed to detect vocallo modules\n"); + return -1; + } + + LM_DBG("Detected %d vocallo modules\n", i); + + if (sngtc_activate_modules(&sngtc_init_cfg, &i) != 0) { + LM_ERR("failed to activate vocallo modules\n"); + return -1; + } + + LM_DBG("Activated %d vocallo modules\n", i); + + return 0; +} + +static int child_init(int rank) +{ + LM_DBG("init child\n"); + + if (rank <= PROC_MAIN) + return 0; + + lock_get(index_lock); + + pipe_index = 2 * (*proc_counter)++; + + close(udp_receiver_pipes[pipe_index + WRITE_END]); + + lock_release(index_lock); + + LM_DBG("proc index: %d\n", pipe_index / 2); + + return 0; +} + +static void mod_destroy(void) +{ + LM_INFO("destroying module\n"); +} + +static int sng_logger(int level, char *fmt, ...) +{ + va_list args; + static char buffer[256]; + + va_start(args, fmt); + + vsnprintf(buffer, 256, fmt, args); + + switch (level) { + case SNGTC_LOGLEVEL_DEBUG: + LM_GEN1(L_DBG, fmt, args); + LM_DBG("%s\n", buffer); + break; + case SNGTC_LOGLEVEL_WARN: + LM_GEN1(L_WARN, fmt, args); + LM_WARN("%s\n", buffer); + break; + case SNGTC_LOGLEVEL_INFO: + LM_GEN1(L_INFO, fmt, args); + LM_INFO("%s\n", buffer); + break; + case SNGTC_LOGLEVEL_STATS: + LM_GEN1(L_INFO, fmt, args); + LM_INFO("%s\n", buffer); + break; + case SNGTC_LOGLEVEL_ERROR: + LM_GEN1(L_ERR, fmt, args); + LM_ERR("%s\n", buffer); + break; + case SNGTC_LOGLEVEL_CRIT: + LM_GEN1(L_CRIT, fmt, args); + LM_CRIT("%s\n", buffer); + break; + + default: + LM_GEN1(L_WARN, fmt, args); + } + + va_end(args); + + return 0; +} + +/** + * store_sngtc_info - stores the caller's SDP body in the current dialog + * in a struct sngtc_info * + */ +int store_sngtc_info(struct dlg_cell *dlg, str *body) +{ + struct sngtc_info *info; + str st; + + /* duplicate the body in shm and store the pointer in the dialog */ + info = shm_malloc(sizeof(*info)); + if (!info) { + LM_ERR("no more shm\n"); + return -1; + } + + memset(info, 0, sizeof(*info)); + + lock_init(&info->lock); + info->caller_sdp.s = shm_malloc(body->len + 2); + if (!info->caller_sdp.s) { + LM_ERR("no more shm\n"); + goto exit; + } + + info->caller_sdp.len = body->len + 2; /* SDP parser needs starting CRLF */ + memcpy(info->caller_sdp.s, body->s - 2, info->caller_sdp.len); + + st.s = (void *)&info; + st.len = sizeof(void *); + LM_DBG("storing info ptr: %p\n", (void *) st.s); + if (dlg_binds.store_dlg_value(dlg, &dlg_key_sngtc_info, &st) != 0) { + LM_ERR("failed to store msg body in dialog\n"); + goto exit; + } + + LM_DBG("CALLER SDP: '%.*s' [%d]\n", info->caller_sdp.len, + info->caller_sdp.s, info->caller_sdp.len); + + return 0; + +exit: + if (info) { + if (info->caller_sdp.s) + shm_free(info->caller_sdp.s); + shm_free(info); + } + + return -1; +} + +/** + * sngtc_offer - will remove the SDP body of an early negotiation INVITE and + * store it in the newly created dialog as a dlg_val. + * + * @return: 1 on success, negative on failure + */ +static int sngtc_offer(struct sip_msg *msg) +{ + struct hdr_field *hf; + struct lump *lump; + struct dlg_cell *dlg; + struct sngtc_info *info = NULL; + str body, totag, st; + + if (dlg_binds.create_dlg(msg, 0) < 0) { + LM_ERR("failed to create dialog\n"); + return SNGTC_ERR; + } + + dlg = dlg_binds.get_dlg(); + if (!dlg) { + LM_ERR("failed to fetch current dialog\n"); + return SNGTC_ERR; + } + + if (get_body(msg, &body) != 0 || body.len <= 0) { + LM_ERR("can only do transcoding for early negotiation INVITES\n"); + return SNGTC_SDP_ERR; + } + + totag = get_to(msg)->tag_value; + + /* INVITE retransmissions will skip this part */ + if (dlg_binds.fetch_dlg_value(dlg, &dlg_key_sngtc_info, &st, 0) != 0) { + + if (store_sngtc_info(dlg, &body) != 0) { + LM_ERR("failed to create sngtc info struct\n"); + return SNGTC_ERR; + } + + /* register a callback to free the above */ + if (dlg_binds.register_dlgcb(dlg, + DLGCB_EXPIRED|DLGCB_FAILED|DLGCB_TERMINATED, + sngtc_dlg_terminated, NULL, NULL) != 0) { + + LM_ERR("failed to register dialog callback\n"); + return SNGTC_ERR; + } + + /* for re-INVITES, just recreate the struct sngtc_info */ + } else if (totag.s && totag.len != 0) { + info = *(struct sngtc_info **)(st.s); + + free_transcoding_sessions(info->sessions); + if (info->caller_sdp.s) + shm_free(info->caller_sdp.s); + if (info->modified_caller_sdp.s) + shm_free(info->modified_caller_sdp.s); + + if (store_sngtc_info(dlg, &body) != 0) { + LM_ERR("failed to create sngtc info struct\n"); + return SNGTC_ERR; + } + + shm_free(info); + } + + LM_DBG("SDP body:\n"); + LM_DBG("%.*s\n", body.len, body.s); + + hf = msg->content_type; + + /* delete the Content-Type header, we're setting up late negotiation */ + lump = del_lump(msg, hf->name.s - msg->buf, hf->len, HDR_OTHER_T); + if (!lump) { + LM_ERR("no more pkg mem\n"); + return SNGTC_ERR; + } + + /* trim the entire SDP body */ + lump = del_lump(msg, body.s - msg->buf, body.len, HDR_OTHER_T); + if (!lump) { + LM_ERR("no more pkg mem\n"); + return SNGTC_ERR; + } + + return 1; +} + +/** + * sngtc_get_codec_str - obtains the sngtc mapping for the given encoding name + * + * @return: on success: enum sngtc_codec_definition + * on failure: -1 + * + * TODO: optimize: binary search (5 iterations instead of 25?) + */ +static int sngtc_get_codec_str(str *encode) +{ + int i; + + for (i = 0; codec_str_mappings[i].bitrate != -1; i++) + if (codec_str_mappings[i].name.len == encode->len && + str_strcasecmp(&codec_str_mappings[i].name, encode) == 0) + return codec_str_mappings[i].sng_codec; + + return -1; +} + +/** + * sngtc_get_codec_int - obtains the sngtc mapping for the given payload type + * + * @return: on success: enum sngtc_codec_definition + * on failure: -1 + * + * TODO: optimize: binary search (3 iterations instead of 8?) + */ +static int sngtc_get_codec_int(str *payload) +{ + int i; + + for (i = 0; codec_int_mappings[i].bitrate != -1; i++) + if (codec_int_mappings[i].name.len == payload->len && + str_strcasecmp(&codec_int_mappings[i].name, payload) == 0) + return codec_int_mappings[i].sng_codec; + + return -1; +} + +/** + * remove_sdp_stream_attrs - removes all attributes from the specified stream + * + * @return: struct lump * with the removed information + */ +static struct lump *remove_sdp_stream_attrs(struct sip_msg *msg, + struct sdp_stream_cell *stream) +{ + struct lump *lump; + char *attrs_end = NULL; + + LM_DBG("Removing all %d codecs from SDP stream: |%.*s|\n", + stream->payloads_num, stream->payloads.len, stream->payloads.s); + + /* find the last parsed structure of the last attribute */ + if (stream->payload_attr->fmtp_string.len > 0) { + attrs_end = stream->payload_attr->fmtp_string.s + + stream->payload_attr->fmtp_string.len; + } else if (stream->payload_attr->rtp_params.len > 0) { + attrs_end = stream->payload_attr->rtp_params.s + + stream->payload_attr->rtp_params.len; + } else if (stream->payload_attr->rtp_clock.len > 0) { + attrs_end = stream->payload_attr->rtp_clock.s + + stream->payload_attr->rtp_clock.len; + } + + if (!attrs_end) { + LM_ERR("invalid SDP stream received\n"); + print_sdp_stream(stream, L_ERR); + return NULL; + } + + lump = del_lump(msg, stream->payloads.s - msg->buf, + attrs_end - stream->payloads.s, HDR_OTHER_T); + if (!lump) { + LM_ERR("failed to add del lump\n"); + return NULL; + } + + return lump; +} + +int replace_sdp_stream_port(struct sip_msg *msg, struct sdp_stream_cell *stream, + unsigned int transcoder_port) +{ + struct lump *lump; + char *p; + + lump = del_lump(msg, stream->port.s - msg->buf, + stream->port.len, HDR_OTHER_T); + if (!lump) { + LM_ERR("failed to add del lump\n"); + return -1; + } + + p = pkg_malloc(6); + if (!p) { + LM_ERR("no more pkg mem\n"); + return -1; + } + + sprintf(p, "%d", transcoder_port); + + if (!insert_new_lump_after(lump, p, strlen(p), HDR_OTHER_T)) { + LM_ERR("no more pkg mem\n"); + return -1; + } + + return 0; +} + +/** + * write_sdp_stream_attr - writes a single attribute in the SDP stream, after + * all the attributes had been previously wiped off with a del_lump operation + * + * If @reply is non-NULL, a 'c=IN IP4 X.X.X.X' line is added to the stream, + * containing the transcoder card IP + * + * @return: 0 on success, negative on failure + */ +static int write_sdp_stream_attr(struct sip_msg *msg, struct lump *del_lump, + struct sdp_payload_attr *attr, + struct sngtc_codec_reply *reply) +{ + char *buf; + int len = 0; + struct in_addr addr; + + len += 2 * attr->rtp_payload.len + A_LINE_PREFIX_LEN + INET_ADDRSTRLEN + + attr->rtp_enc.len + 1 + 1 + attr->rtp_clock.len + 2 + C_LINE_LEN + + 2 * CRLF_LEN; + + buf = pkg_malloc(len); + if (!buf) { + LM_ERR("no more pkg memory\n"); + return SNGTC_ERR; + } + + if (reply) { + + len = sprintf(buf, "%.*s%s" + "c=IN IP4 ", attr->rtp_payload.len, + attr->rtp_payload.s, CRLF); + + if (card_ip_b.s) + len += sprintf(buf + len, "%.*s%s" + "a=rtpmap:%.*s %.*s/%.*s", + card_ip_b.len, card_ip_b.s, CRLF, + attr->rtp_payload.len, attr->rtp_payload.s, + attr->rtp_enc.len, attr->rtp_enc.s, + attr->rtp_clock.len, attr->rtp_clock.s); + else { + addr.s_addr = ntohl(reply->a.codec_ip); + + if (!inet_ntop(AF_INET, &addr, buf + len, INET_ADDRSTRLEN)) { + LM_ERR("Failed to convert IP from binary to string\n"); + return SNGTC_ERR; + } + + while (buf[len]) + len++; + + len += sprintf(buf + len, "%s" + "a=rtpmap:%.*s %.*s/%.*s", CRLF, + attr->rtp_payload.len, attr->rtp_payload.s, + attr->rtp_enc.len, attr->rtp_enc.s, + attr->rtp_clock.len, attr->rtp_clock.s); + } + } else + len = sprintf(buf, "%.*s%s" + "a=rtpmap:%.*s %.*s/%.*s", + attr->rtp_payload.len, attr->rtp_payload.s, CRLF, + attr->rtp_payload.len, attr->rtp_payload.s, + attr->rtp_enc.len, attr->rtp_enc.s, + attr->rtp_clock.len, attr->rtp_clock.s); + + if (!insert_new_lump_after(del_lump, buf, len, HDR_OTHER_T)) { + LM_ERR("failed to insert lump with codec result\n"); + return SNGTC_ERR; + } + + return 0; +} + +/** + * create_transcoding_session - creates a new Sangoma transcoding session and + * adds it to the current dialog's list of ongoing transcoding sessions + * + * @info : output parameter, holds a list with all tc sessions on the card + */ +static struct sngtc_codec_reply *create_transcoding_session( + struct sngtc_codec_request *request, struct sngtc_info *info) +{ + struct sngtc_codec_reply *reply; + struct sngtc_session_list *session; + struct sngtc_request req; + int rc; + + session = shm_malloc(sizeof(*session) + sizeof(*reply)); + if (!session) { + LM_ERR("no more shm mem\n"); + return NULL; + } + + reply = (struct sngtc_codec_reply *)(session + 1); + session->next = NULL; + session->reply = reply; + + LM_DBG("creating sng transcoding session\n"); + + req.type = REQ_CREATE_SESSION; + req.response_fd = udp_receiver_pipes[pipe_index + WRITE_END]; + req.sng_req = *request; + req.sng_reply = reply; + + if (write(sangoma_pipe[WRITE_END], &req, sizeof(req)) < 0) { + LM_ERR("failed to write on sangoma pipe fd %d (%d: %s)\n", + sangoma_pipe[WRITE_END], errno, strerror(errno)); + goto out_free; + } + + if (read(udp_receiver_pipes[pipe_index + READ_END], &rc, sizeof(rc)) < 0) { + LM_ERR("failed to read sangoma worker reply on pipe fd %d (%d: %s)\n", + udp_receiver_pipes[pipe_index + READ_END], errno, strerror(errno)); + goto out_free; + } + + if (rc != 0) { + LM_ERR("failed to create sangoma transcoding session\n"); + goto out_free; + } + + LM_DBG("created new transcoding session\n"); + sngtc_print_reply(L_DBG, reply); + + if (!info->sessions) + info->sessions = info->last_session = session; + else { + info->last_session->next = session; + info->last_session = session; + } + + return reply; + +out_free: + free_transcoding_sessions(info->sessions); + shm_free(session); + return NULL; +} + +/** + * match_codecs - intersects the attributes of SDP streams @s1 and @s2 and + * stores the results in the @pair parameter + * + * @return: + * SNGTC_ON - streams are incompatible, transcoding will be performed + * SNGTC_OFF - streams have at least 1 common codec + * SNGTC_UNSUP_CODECS - card cannot transcode from/into any codecs + * SNGTC_BAD_SDP - one stream has no attributes at all + */ +static int match_codecs(struct sdp_stream_cell *s1, + struct sdp_stream_cell *s2, struct codec_pair *pair) +{ + struct sdp_payload_attr *att1, *att2, *tatt1, *tatt2; + int common_codec, tc1, tc2; + int c1, c2; + int i, j; + + common_codec = tc1 = tc2 = 0; + att1 = att2 = tatt1 = tatt2 = NULL; + + LM_DBG("stream 1: %d codecs\n", s1->payloads_num); + for (i = 0; i < s1->payloads_num && !common_codec; i++) { + att1 = s1->p_payload_attr[i]; + + LM_DBG("Codec: '%.*s'\n", att1->rtp_enc.len, att1->rtp_enc.s); + + if (att1->rtp_enc.len != 0) + c1 = sngtc_get_codec_str(&att1->rtp_enc); + else + c1 = sngtc_get_codec_int(&att1->rtp_payload); + + if (!tc1 && c1 > 0) { + tatt1 = att1; + tc1 = c1; + } + + LM_DBG("stream 2: %d codecs\n", s2->payloads_num); + for (j = 0; j < s2->payloads_num; j++) { + att2 = s2->p_payload_attr[j]; + + LM_DBG("Codec: '%.*s'\n", att2->rtp_enc.len, att2->rtp_enc.s); + + /* if the attribute has a 'a=rtpmap' line, get that enc, + * otherwise use the default one for the payload type + */ + if (att2->rtp_enc.len != 0) + c2 = sngtc_get_codec_str(&att2->rtp_enc); + else + c2 = sngtc_get_codec_int(&att2->rtp_payload); + + if (!tc2 && c2 > 0) { + tatt2 = att2; + tc2 = c2; + } + + if (c1 == c2 && c1 != -1) { + common_codec = 1; + break; + } + } + } + + if (!att1 || !att2) { + LM_ERR("received bogus sdp with no attributes\n"); + + LM_ERR("caller:\n"); + print_sdp_stream(s1, L_ERR); + + LM_ERR("callee:\n"); + print_sdp_stream(s2, L_ERR); + pair->status = SNGTC_BAD_SDP; + + return SNGTC_BAD_SDP; + } + + if (!tc1 || !tc2) { + LM_ERR("endpoints have no common codecs and at least one side " + "contains only unsupported Sangoma codecs\n"); + + LM_ERR("caller:\n"); + print_sdp_stream(s1, L_ERR); + + LM_ERR("callee:\n"); + print_sdp_stream(s2, L_ERR); + pair->status = SNGTC_UNSUP_CODECS; + + return SNGTC_UNSUP_CODECS; + } + + if (!common_codec) { + pair->att1 = tatt1; + pair->att2 = tatt2; + pair->tc1 = tc1; + pair->tc2 = tc2; + pair->status = SNGTC_ON; + return SNGTC_ON; + } + + pair->att1 = att1; + pair->att2 = att2; + pair->status = SNGTC_OFF; + + return SNGTC_OFF; +} + +static int process_stream(struct sdp_stream_cell *s1, struct sdp_stream_cell *s2, + str *src, str *dst, unsigned char idx) +{ + int rc = 0, len; + struct sdp_payload_attr *att = codec_matches[idx].att2; + struct in_addr addr; + + if (s1->next && s2->next) + rc = process_stream(s1->next, s2->next, src, dst, idx - 1); + else if (s1->next || s2->next) + LM_ERR("found different number of SDP streams - choosing min\n"); + + /* check if attribute port must be rewritten */ + if (codec_matches[idx].status == SNGTC_ON) { + + LM_DBG("codec tc status: TC ON\n"); + + len = s1->port.s - src->s; + memcpy(dst->s + dst->len, src->s, len); + dst->len += len; + dst->len += sprintf(dst->s + dst->len, "%d", + codec_matches[idx].reply->b.codec_udp_port); + src->s += len + s1->port.len; + } else + LM_DBG("codec tc status: TC OFF\n"); + + /* copy everything up to the rtp payload list (0 3 101 ...) */ + len = s1->p_payload_attr[0]->rtp_payload.s - src->s; + memcpy(dst->s + dst->len, src->s, len); + dst->len += len; + src->s += len; + + if (codec_matches[idx].status == SNGTC_ON) { + + dst->len += sprintf(dst->s + dst->len, "%.*s%s" + "c=IN IP4 ", + att->rtp_payload.len, att->rtp_payload.s, CRLF); + + if (card_ip_a.s) + dst->len += sprintf(dst->s + dst->len, "%.*s%s" + "a=rtpmap:%.*s %.*s/%.*s", + card_ip_a.len, card_ip_a.s, CRLF, + att->rtp_payload.len, att->rtp_payload.s, + att->rtp_enc.len, att->rtp_enc.s, + att->rtp_clock.len, att->rtp_clock.s); + else { + addr.s_addr = ntohl(codec_matches[idx].reply->b.codec_ip); + if (!inet_ntop(AF_INET, &addr, dst->s + dst->len, INET_ADDRSTRLEN)) { + LM_ERR("Failed to convert IP from binary to string\n"); + return SNGTC_ERR; + } + + while (dst->s[dst->len]) + dst->len++; + + dst->len += sprintf(dst->s + dst->len, "%s" + "a=rtpmap:%.*s %.*s/%.*s", CRLF, + att->rtp_payload.len, att->rtp_payload.s, + att->rtp_enc.len, att->rtp_enc.s, + att->rtp_clock.len, att->rtp_clock.s); + } + } else + dst->len += sprintf(dst->s + dst->len, "%.*s%s" + "a=rtpmap:%.*s %.*s/%.*s", + att->rtp_payload.len, att->rtp_payload.s, CRLF, + att->rtp_payload.len, att->rtp_payload.s, + att->rtp_enc.len, att->rtp_enc.s, + att->rtp_clock.len, att->rtp_clock.s); + + return rc; +} + +/** + * performs the following operations at 200 OK time (early neg <-> late neg): + * + * - alters the callee's 200 OK message (adds the final decided codec) + * - alters the caller's SDP (in memory), so it can be attached @ ACK + * - opens transcoding sessions on the card if necessary + * + * Note: assumes all streams are on corresponding positions in both SDPs + */ +static int process_session(struct sip_msg *msg, struct sngtc_info *info, str *src, + str *dst, struct sdp_session_cell *s1, + struct sdp_session_cell *s2) +{ + struct sdp_stream_cell *sm1, *sm2; + struct sngtc_session_list *tc_session; + struct sngtc_codec_request request; + struct sngtc_codec_reply *reply = NULL; + struct codec_pair pair; + struct lump *lump, *nl; + struct in_addr addr; + int rc = 0, ret, tc_on = 0; + int idx; + char buf[INET_ADDRSTRLEN]; + str repl; + + if (s1->next && s2->next) + rc = process_session(msg, info, src, dst, s1->next, s2->next); + else if (s1->next || s2->next) + LM_ERR("endpoints have a different number of SDP sessions" + " - choosing min number\n"); + + if (rc != 0) + goto out; + + tc_session = info->sessions; + for (idx = MAX_STREAMS - 1, sm1 = s1->streams, sm2 = s2->streams; sm1 && sm2; + sm1 = sm1->next, sm2 = sm2->next, idx--) { + + ret = match_codecs(sm1, sm2, &pair); + codec_matches[idx] = pair; + + switch (ret) { + + case SNGTC_OFF: + + LM_DBG("NO NEED FOR TRANSCODING\n"); + + /* delete codecs from 200 OK; write endpoint A codec */ + /* ip and port stay the same */ + lump = remove_sdp_stream_attrs(msg, sm2); + if (!lump) { + LM_ERR("failed to clear sdp codecs\n"); + return SNGTC_SDP_ERR; + } + + LM_DBG("sdp stream:\n"); + print_sdp_stream(sm2, L_DBG); + + ret = write_sdp_stream_attr(msg, lump, pair.att2, NULL); + if (ret != 0) { + LM_ERR("failed to write sdp stream codec\n"); + return ret; + } + + break; + + case SNGTC_ON: + + tc_on = 1; + + if (is_processed(info)) + goto use_existing_sessions; + + LM_DBG("TRANSCODING ([%d] %.*s:%.*s <--> [%d] %.*s:%.*s)\n", + pair.tc1, s1->ip_addr.len, s1->ip_addr.s, sm1->port.len, + sm1->port.s, pair.tc2, s2->ip_addr.len, s2->ip_addr.s, + sm2->port.len, sm2->port.s); + + memset(&request, 0, sizeof(request)); + + request.usr_priv = NULL; + + /* Codec, ms, IP and port for side A */ + request.a.codec_id = pair.tc1; + request.a.ms = 0; + sprintf(buf, "%.*s", s1->ip_addr.len, s1->ip_addr.s); + ret = inet_pton(AF_INET, buf, &addr); + if (ret != 1) { + LM_ERR("failed to convert ip %s to binary form (%d)\n", + s1->ip_addr.s, ret); + return SNGTC_ERR; + } + request.a.host_ip = htonl(addr.s_addr); + request.a.host_netmask = (unsigned int)-1; + if (str2int(&sm1->port, &request.a.host_udp_port) != 0) + LM_ERR("Failed to parse integer stored in port str '%.*s'\n", + sm1->port.len, sm1->port.s); + + /* Codec, ms, IP and port for side B */ + request.b.codec_id = pair.tc2; + request.b.ms = 0; + sprintf(buf, "%.*s", s2->ip_addr.len, s2->ip_addr.s); + ret = inet_pton(AF_INET, buf, &addr); + if (ret != 1) { + LM_ERR("failed to convert ip %.*s to binary form (%d)\n", + s2->ip_addr.len, s2->ip_addr.s, ret); + return SNGTC_ERR; + } + request.b.host_ip = htonl(addr.s_addr); + request.b.host_netmask = (unsigned int)-1; + if (str2int(&sm2->port, &request.b.host_udp_port) != 0) + LM_ERR("Failed to parse integer stored in port str '%.*s'\n", + sm2->port.len, sm2->port.s); + + LM_DBG("Transcoding request: %d:%d <--> %d:%d\n", request.a.host_ip, + request.a.host_udp_port, request.b.host_ip, + request.b.host_udp_port); + + reply = create_transcoding_session(&request, info); + if (!reply) { + LM_ERR("Failed to create a transcoding session on the card\n"); + return SNGTC_TC_ERR; + } + +use_existing_sessions: + + LM_DBG("NEW TC SESSION!\n"); + + if (is_processed(info)) { + reply = tc_session->reply; + tc_session = tc_session->next; + } + + codec_matches[idx].reply = reply; + + /** + * delete codecs from 200 OK + * write the common codec + * replace IP with ip of Sangoma card + * replace port with endpoint A newly opened port on card + */ + lump = remove_sdp_stream_attrs(msg, sm2); + if (!lump) { + LM_ERR("failed to clear sdp codecs\n"); + return SNGTC_SDP_ERR; + } + + nl = del_lump(msg, s2->ip_addr.s - msg->buf, s2->ip_addr.len, 0); + if (!nl) { + LM_ERR("failed to add del lump\n"); + return SNGTC_ERR; + } + + if (pkg_str_dup(&repl, &card_ip_b) != 0) { + LM_ERR("failed to dup in pkg mem\n"); + return SNGTC_ERR; + } + + if (!insert_new_lump_after(nl, repl.s, repl.len, HDR_OTHER_T)) { + LM_ERR("failed to insert lump with codec result\n"); + return SNGTC_ERR; + } + + if (replace_sdp_stream_port(msg, sm2, + reply->a.codec_udp_port) != 0) { + LM_ERR("failed to rewrite sdp stream port\n"); + return SNGTC_ERR; + } + + if (write_sdp_stream_attr(msg, lump, pair.att1, reply) != 0) { + LM_ERR("failed to write sdp stream codecs\n"); + return SNGTC_ERR; + } + + break; + + case SNGTC_UNSUP_CODECS: + + LM_ERR("endpoints have no common codecs and at least one side " + "contains only unsupported Sangoma codecs\n"); + + LM_ERR("caller:\n"); + print_sdp_stream(sm1, L_ERR); + + LM_ERR("callee:\n"); + print_sdp_stream(sm2, L_ERR); + return SNGTC_SDP_ERR; + + case SNGTC_BAD_SDP: + + LM_ERR("received bogus sdp with no attributes\n"); + + LM_ERR("caller:\n"); + print_sdp_stream(sm1, L_ERR); + + LM_ERR("callee:\n"); + print_sdp_stream(sm2, L_ERR); + return SNGTC_SDP_ERR; + } + } + + if (tc_on) { + LM_DBG("transcoding: ON\n"); + + memcpy(dst->s + dst->len, src->s, s1->ip_addr.s - src->s); + dst->len += s1->ip_addr.s - src->s; + dst->len += sprintf(dst->s + dst->len, "%.*s", + card_ip_a.len, card_ip_a.s); + src->s += s1->ip_addr.s - src->s + s1->ip_addr.len; + } else + LM_DBG("transcoding: OFF\n"); + + rc |= process_stream(s1->streams, s2->streams, src, dst, MAX_STREAMS - 1); +out: + return rc; +} + +static int w_sngtc_callee_answer(struct sip_msg *msg, + char *gp_ip_a, char *gp_ip_b) +{ + if (!gp_ip_a) { + card_ip_a.s = card_ip_b.s = NULL; + goto out; + } + + if (fixup_get_svalue(msg, (gparam_p)gp_ip_a, &card_ip_a) != 0) { + LM_ERR("failed to get fixup value for caller: bad pvar\n"); + return SNGTC_ERR; + } + + if (!gp_ip_b) { + card_ip_b.s = NULL; + goto out; + } + + if (fixup_get_svalue(msg, (gparam_p)gp_ip_b, &card_ip_b) != 0) { + LM_ERR("failed to get fixup value for callee: bad pvar\n"); + return SNGTC_ERR; + } + +out: + return sngtc_callee_answer(msg); +} + +/** + * sngtc_callee_answer - handles the SDP offer of the callee + * + * At this point, we have both offers of the endpoints, and can decide whether + * transcoding is needed or not. + */ +static int sngtc_callee_answer(struct sip_msg *msg) +{ + struct dlg_cell *dlg; + struct sngtc_info *info; + str caller_sdp, dst; + sdp_info_t sdp; + str *sdp_ptr; + int rc; + + LM_DBG("sngtc_callee_answer\n"); + + dlg = dlg_binds.get_dlg(); + if (!dlg) { + LM_ERR("failed to fetch current dialog\n"); + return SNGTC_ERR; + } + + /* get the pointer to the SDP body of the caller */ + if (dlg_binds.fetch_dlg_value(dlg, &dlg_key_sngtc_info, &dst, 0) != 0) { + LM_ERR("failed to fetch caller sdp\n"); + return SNGTC_ERR; + } + + info = *(struct sngtc_info **)(dst.s); + sdp_ptr = &info->caller_sdp; + + LM_DBG("ptrs: %p %p\n", sdp_ptr, info->caller_sdp.s); + + caller_sdp.len = sdp_ptr->len; + caller_sdp.s = sdp_ptr->s; + + lock_get(&info->lock); + + LM_DBG("FETCHED CALLER SDP: '%.*s' [%d]\n", caller_sdp.len, caller_sdp.s, + caller_sdp.len); + + memset(&sdp, 0, sizeof(sdp)); + if (parse_sdp_session(&caller_sdp, 0, NULL, &sdp) != 0) { + LM_ERR("failed to parse caller sdp body\n"); + rc = SNGTC_SDP_ERR; + goto out_free; + } + + if (parse_sdp(msg) != 0) { + LM_ERR("failed to parse callee sdp body\n"); + rc = SNGTC_SDP_ERR; + goto out_free; + } + + dst.s = sdp_buffer.s; + dst.len = 0; + + /* perform all 200 OK SDP changes and pre-compute the ACK SDP body */ + rc = process_session(msg, info, &caller_sdp, &dst, sdp.sessions, + msg->sdp->sessions); + if (rc != 0) { + LM_ERR("failed to rewrite SDP bodies of the endpoints\n"); + goto out_free; + } + + if (!is_processed(info)) { + dst.s = sdp_buffer.s; + LM_DBG("caller ACK SDP: '%.*s'\n", dst.len, dst.s); + + info->modified_caller_sdp.s = shm_malloc(dst.len); + if (!info->modified_caller_sdp.s) { + LM_ERR("no more shm memory\n"); + rc = SNGTC_ERR; + goto out_free; + } + + memcpy(info->modified_caller_sdp.s, dst.s, dst.len); + info->modified_caller_sdp.len = dst.len; + } + + info->flags |= PROCESSED_FLAG; + lock_release(&info->lock); + + if (sdp.sessions) + __free_sdp(&sdp); + + return 1; + +out_free: + free_transcoding_sessions(info->sessions); + lock_release(&info->lock); + + if (sdp.sessions) + __free_sdp(&sdp); + + return rc; +} + +/** + * sngtc_caller_answer - attaches an SDP body to ACK requests + */ +static int sngtc_caller_answer(struct sip_msg *msg) +{ + char *p; + str body; + struct dlg_cell *dlg; + struct lump *lump; + struct sngtc_info *info; + int len; + + LM_DBG("processing ACK\n"); + + if (get_body(msg, &body) != 0 || body.len > 0) { + LM_ERR("ACK should not contain a SDP body\n"); + return SNGTC_ERR; + } + + dlg = dlg_binds.get_dlg(); + if (!dlg) { + LM_ERR("failed to fetch current dialog\n"); + return SNGTC_ERR; + } + + /* get the SDP body from the INVITE which was mangled at 200 OK */ + if (dlg_binds.fetch_dlg_value(dlg, &dlg_key_sngtc_info, &body, 0) != 0) { + LM_ERR("failed to fetch caller sdp\n"); + return SNGTC_ERR; + } + + info = *(struct sngtc_info **)(body.s); + + /* duplicate the SDP in pkg mem for the lumps mechanism */ + if (pkg_str_dup(&body, &info->modified_caller_sdp) != 0) { + LM_ERR("failed to dup in pkg mem\n"); + return SNGTC_ERR; + } + + LM_DBG("Duplicated SDP: '%.*s'\n", body.len, body.s); + + lump = anchor_lump(msg, msg->content_length->name.s - msg->buf, 0); + if (!lump) { + LM_ERR("failed to insert anchor lump\n"); + return SNGTC_ERR; + } + + p = pkg_malloc(SDP_CONTENT_TYPE_LEN); + if (!p) { + LM_ERR("no more pkg memory\n"); + return SNGTC_ERR; + } + + /* add the Content-Type header */ + + memcpy(p, "Content-Type: application/sdp\r\n", SDP_CONTENT_TYPE_LEN); + + if (!insert_new_lump_before(lump, p, SDP_CONTENT_TYPE_LEN, 0)) { + LM_ERR("failed to insert Content-Type lump\n"); + return SNGTC_ERR; + } + + LM_DBG("blen: %d\n", msg->content_length->body.len); + + lump = del_lump(msg, msg->content_length->body.s - msg->buf, + msg->content_length->body.len, HDR_OTHER_T); + if (!lump) { + LM_ERR("failed to insert del lump for the content length\n"); + return SNGTC_ERR; + } + + p = pkg_malloc(CONTENT_LEN_DIGITS); + if (!p) { + LM_ERR("no more pkg memory\n"); + return SNGTC_ERR; + } + + LM_DBG("len: %d\n", body.len); + + len = sprintf(p, "%d", body.len); + + if (!insert_new_lump_after(lump, p, len, HDR_OTHER_T)) { + LM_ERR("failed to insert Content-Length lump\n"); + return SNGTC_ERR; + } + + lump = anchor_lump(msg, msg->len - CRLF_LEN, 0); + if (!lump) { + LM_ERR("failed to insert anchor lump\n"); + return SNGTC_ERR; + } + + if (!insert_new_lump_before(lump, body.s, body.len, 0)) { + LM_ERR("failed to insert SDP body lump\n"); + return SNGTC_ERR; + } + + return 1; +} + diff --git a/modules/sngtc/sngtc.h b/modules/sngtc/sngtc.h new file mode 100644 index 00000000000..651ebb9567c --- /dev/null +++ b/modules/sngtc/sngtc.h @@ -0,0 +1,147 @@ +/** + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History + * ------- + * 2013-06-05 created (liviu) + * + */ + +#ifndef __SNGTC_H__ +#define __SNGTC_H__ + +#include + +#define SDP_CONTENT_TYPE_LEN (sizeof("Content-Type: application/sdp\r\n") - 1) +#define A_LINE_PREFIX_LEN (sizeof("a=rtpmap:" - 1)) +#define C_LINE_LEN (sizeof("c=IN IP4 xxx.xxx.xxx.xxx\r\n") - 1) +#define SDP_BUFFER_SIZE 4096 +#define MAX_STREAMS 30 +#define CONTENT_LEN_DIGITS 5 + +#define PROCESSED_FLAG (1 << 0) + +#define READ_END 0 +#define WRITE_END 1 + +#define is_processed(_info) (_info->flags & PROCESSED_FLAG) + +/** + * @_level: OpenSIPS debug level + * @_l: struct sngtc_codec_request_leg + * @_start: string identifier of the leg + */ +#define sngtc_print_request_leg(_level, _l, _start) \ + do { \ + LM_GEN1(_level, "%s: [Codec: %d][ms: %d][ip: %d][nm: %d][port: %d]\n", \ + _start, _l.codec_id, _l.ms, _l.host_ip, _l.host_netmask, \ + _l.host_udp_port); \ + } while (0) + +/** + * @_level: OpenSIPS debug level + * @_l: struct sngtc_codec_reply_leg + * @_start: string identifier of the leg + */ +#define sngtc_print_reply_leg(_level, _l, _start) \ + do { \ + LM_GEN1(_level, "%s: [IP: %d][nm: %d][port: %d]\n", \ + _start, _l.codec_ip, _l.codec_netmask, _l.codec_udp_port); \ + LM_GEN1(_level, "%s: [Host IP: %d][nm: %d][port: %d][iana: %d]\n", \ + _start, _l.host_ip, _l.host_netmask, _l.host_udp_port, \ + _l.iana_code); \ + } while (0) + +/** + * @_level: OpenSIPS debug level + * @_r: struct sngtc_codec_request + */ +#define sngtc_print_request(_level, _r) \ + do { \ + LM_GEN1(_level, "sngtc_codec_request with rtcp: %d\n", _r.rtcp_enable); \ + sngtc_print_request_leg(_level, (_r).a, "A"); \ + sngtc_print_request_leg(_level, (_r).b, "B"); \ + } while (0) + +/** + * @_level: OpenSIPS debug level + * @_r: struct sngtc_codec_reply * + */ +#define sngtc_print_reply(_level, _r) \ + do { \ + LM_GEN1(_level, "sngtc_codec_reply with [mod_session: %d]" \ + "[rtp_session: %d]\n", (_r)->codec_module_session_idx, \ + (_r)->codec_rtp_session_idx); \ + sngtc_print_reply_leg(_level, (_r)->a, "A"); \ + sngtc_print_reply_leg(_level, (_r)->b, "B"); \ + } while (0) + +#define SNGTC_SDP_ERR -1 +#define SNGTC_TC_ERR -2 +#define SNGTC_ERR -3 + +enum sng_module_status { + SNGTC_UNSUP_CODECS = -2, + SNGTC_BAD_SDP, + SNGTC_OFF, + SNGTC_ON, +}; + +struct sngtc_session_list { + struct sngtc_codec_reply *reply; + struct sngtc_session_list *next; +}; + +struct sngtc_info { + str caller_sdp; + str modified_caller_sdp; + + gen_lock_t lock; + + /* various session-related flags */ + int flags; + + /* optional, used if transcoding is needed */ + struct sngtc_session_list *sessions; + struct sngtc_session_list *last_session; +}; + +struct codec_pair { + struct sdp_payload_attr *att1; + struct sdp_payload_attr *att2; + + enum sngtc_codec_definition tc1; + enum sngtc_codec_definition tc2; + + enum sng_module_status status; + + struct sngtc_codec_reply *reply; +}; + +struct codec_mapping { + str name; + int bitrate; + + int mode; + + int sng_codec; +}; + +#endif /* __SNGTC_H__ */ + diff --git a/modules/sngtc/sngtc_proc.c b/modules/sngtc/sngtc_proc.c new file mode 100644 index 00000000000..5cc7b2fbde8 --- /dev/null +++ b/modules/sngtc/sngtc_proc.c @@ -0,0 +1,84 @@ +/** + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History + * ------- + * 2013-06-05 created (liviu) + * + */ + +#include + +#include "../../str.h" +#include "../../pt.h" + +#include "sngtc.h" +#include "sngtc_proc.h" + +void sangoma_worker_loop(int proc_no) +{ + struct sngtc_request req; + int rc; + + close(sangoma_pipe[WRITE_END]); + + for (;;) { + rc = 0; + + LM_DBG("reading from pipe\n"); + if (read(sangoma_pipe[READ_END], &req, sizeof(req)) < 0) { + LM_ERR("failed to read from pipe (%d - %s)\n", errno, + strerror(errno)); + continue; + } + + switch (req.type) { + case REQ_CREATE_SESSION: + LM_DBG("CREATE request\n"); + + if (sngtc_create_transcoding_session(&req.sng_req, req.sng_reply, 0) + != 0) { + LM_ERR("failed to create sng transcoding session\n"); + sngtc_print_request(L_ERR, req.sng_req); + rc = 1; + } + break; + + case REQ_FREE_SESSION: + LM_DBG("FREE request\n"); + sngtc_print_reply(L_DBG, req.sng_reply); + + if (sngtc_free_transcoding_session(req.sng_reply) != 0) { + LM_ERR("failed to free sng transcoding session\n"); + sngtc_print_reply(L_ERR, req.sng_reply); + rc = 1; + } + break; + + default: + LM_ERR("dropping invalid sangoma request: %d\n", req.type); + rc = 1; + } + + if (write(req.response_fd, &rc, sizeof(rc)) < 0) + LM_ERR("failed to write in response pipe fd %d (%d: %s)\n", + req.response_fd, errno, strerror(errno)); + } +} + diff --git a/modules/sngtc/sngtc_proc.h b/modules/sngtc/sngtc_proc.h new file mode 100644 index 00000000000..f497464a8fc --- /dev/null +++ b/modules/sngtc/sngtc_proc.h @@ -0,0 +1,44 @@ +/** + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History + * ------- + * 2013-06-05 created (liviu) + * + */ + +#include + +enum request_type { REQ_CREATE_SESSION, REQ_FREE_SESSION }; + +/* information needed to make a request to the sangoma worker */ +struct sngtc_request { + enum request_type type; + + /* pipe descriptor used to send the response */ + int response_fd; + + struct sngtc_codec_request sng_req; + struct sngtc_codec_reply *sng_reply; +}; + +extern int sangoma_pipe[2]; + +void sangoma_worker_loop(int proc_no); + diff --git a/modules/snmpstats/README b/modules/snmpstats/README index d0f768483ac..923b05f2281 100644 --- a/modules/snmpstats/README +++ b/modules/snmpstats/README @@ -11,8 +11,7 @@ Jeffrey Magder Copyright © 2006 SOMA Networks, Inc. Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -691,4 +690,4 @@ theTableName How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/snmpstats/alarm_checks.c b/modules/snmpstats/alarm_checks.c index 765c7e7bd62..93bfda4de83 100644 --- a/modules/snmpstats/alarm_checks.c +++ b/modules/snmpstats/alarm_checks.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,7 +25,7 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * This file groups together alarm checking and handling */ @@ -42,7 +42,7 @@ /* Returns the number of bytes currently waiting in the msg queue if they exceed * the threshold, and zero otherwise. If threshold_to_compare_to is < 0, then * no check will be performed and zero always returned. */ -int check_msg_queue_alarm(int threshold_to_compare_to) +int check_msg_queue_alarm(int threshold_to_compare_to) { int bytesWaiting = 0; @@ -50,8 +50,8 @@ int check_msg_queue_alarm(int threshold_to_compare_to) { return 0; } - - bytesWaiting = get_total_bytes_waiting(PROTO_NONE); + + bytesWaiting = get_total_bytes_waiting(PROTO_NONE); if (bytesWaiting > threshold_to_compare_to) { @@ -64,18 +64,18 @@ int check_msg_queue_alarm(int threshold_to_compare_to) /* Returns the number of active dialogs if they exceed the threshold, and zero * otherwise. */ -int check_dialog_alarm(int threshold_to_compare_to) +int check_dialog_alarm(int threshold_to_compare_to) { int num_dialogs; - if (threshold_to_compare_to < 0) + if (threshold_to_compare_to < 0) { return 0; } num_dialogs = get_statistic("active_dialogs"); - if (num_dialogs > threshold_to_compare_to) + if (num_dialogs > threshold_to_compare_to) { return num_dialogs; } @@ -86,21 +86,21 @@ int check_dialog_alarm(int threshold_to_compare_to) /* This function will be called periodically from an OpenSIPS timer. The first * time it is called, it will query OPENSER-MIB for configured thresholds. */ -void run_alarm_check(unsigned int ticks, void * attr) +void run_alarm_check(unsigned int ticks, void * attr) { static int msg_queue_minor_threshold; - static int msg_queue_major_threshold; + static int msg_queue_major_threshold; static int dialog_minor_threshold; static int dialog_major_threshold; static char firstRun = 1; - + int bytesInMsgQueue; int numActiveDialogs; /* We only need to retrieve our thresholds the first time around */ - if (firstRun) + if (firstRun) { register_with_master_agent(ALARM_AGENT_NAME); @@ -112,11 +112,11 @@ void run_alarm_check(unsigned int ticks, void * attr) firstRun = 0; } - + /* We need to have this here in case the master agent fails and is * restarted. Without it, we won't be able to re-establish or AgentX * connection */ - agent_check_and_process(0); + agent_check_and_process(0); /* Check for MsgQueue alarm conditions */ @@ -125,18 +125,18 @@ void run_alarm_check(unsigned int ticks, void * attr) * of bytes will be returned. */ bytesInMsgQueue = check_msg_queue_alarm(msg_queue_minor_threshold); - if (bytesInMsgQueue != 0) + if (bytesInMsgQueue != 0) { - send_openserMsgQueueDepthMinorEvent_trap(bytesInMsgQueue, + send_openserMsgQueueDepthMinorEvent_trap(bytesInMsgQueue, msg_queue_minor_threshold); } bytesInMsgQueue = check_msg_queue_alarm(msg_queue_major_threshold); - if (bytesInMsgQueue != 0) + if (bytesInMsgQueue != 0) { - send_openserMsgQueueDepthMajorEvent_trap(bytesInMsgQueue, + send_openserMsgQueueDepthMajorEvent_trap(bytesInMsgQueue, msg_queue_major_threshold); } @@ -149,7 +149,7 @@ void run_alarm_check(unsigned int ticks, void * attr) send_openserDialogLimitMinorEvent_trap(numActiveDialogs, dialog_minor_threshold); } - + numActiveDialogs = check_dialog_alarm(dialog_major_threshold); if (numActiveDialogs != 0) diff --git a/modules/snmpstats/alarm_checks.h b/modules/snmpstats/alarm_checks.h index 415c3c7774b..99a9394aa99 100644 --- a/modules/snmpstats/alarm_checks.h +++ b/modules/snmpstats/alarm_checks.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * diff --git a/modules/snmpstats/hashTable.c b/modules/snmpstats/hashTable.c index 91804792f5d..bfe07c83198 100644 --- a/modules/snmpstats/hashTable.c +++ b/modules/snmpstats/hashTable.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -31,7 +31,7 @@ * For an overview of its structures, please see hashTable.h * * Potential Performance Improvements: Pass the length of the aor strings around - * everywhere, so we don't have to calculate it ourselves. + * everywhere, so we don't have to calculate it ourselves. * */ @@ -51,7 +51,7 @@ /* Calculates and returns a hash index to a hash table. The index is calculated * by summing up all the characters specified with theString, and using the * hashTableSize as the modulus. */ -int calculateHashSlot(char *theString, int hashTableSize) +int calculateHashSlot(char *theString, int hashTableSize) { char *currentCharacter = theString; int runningTotal = 0; @@ -66,13 +66,13 @@ int calculateHashSlot(char *theString, int hashTableSize) /* Searches the hash table specified as theTable, of size 'size', for a record * indexed with 'aor'. If a match is found, then an aorToIndextStruct_t - * structure is returned. + * structure is returned. * - * This function is called to discover the map between OpenSER's "aor" + * This function is called to discover the map between OpenSER's "aor" * (Address of Records) indexing scheme, and the SNMPStats modules integer - * indexing scheme for its contact/user data. + * indexing scheme for its contact/user data. * - * Returns: the aorToIndexStruct_t mapping structure if a match was found, + * Returns: the aorToIndexStruct_t mapping structure if a match was found, * or NULL otherwise. */ aorToIndexStruct_t *findHashRecord(hashSlot_t *theTable, char *aor, int size) @@ -83,7 +83,7 @@ aorToIndexStruct_t *findHashRecord(hashSlot_t *theTable, char *aor, int size) aorToIndexStruct_t *currentRecord = theTable[hashIndex].first; while (currentRecord != NULL) { - + /* If the strings are the same length and the same in every * other way, then return the given record. */ if (currentRecord->aorLength == aorStringLength && @@ -101,7 +101,7 @@ aorToIndexStruct_t *findHashRecord(hashSlot_t *theTable, char *aor, int size) /* Returns a chunk of memory large enough to store 'size' hashSlot's. The * table will contain mappings between OpenSER's "aor" user/contact indexing * scheme, and SNMPStats integer indexing scheme */ -hashSlot_t *createHashTable(int size) +hashSlot_t *createHashTable(int size) { hashSlot_t *hashTable = NULL; int numberOfBytes = sizeof(hashSlot_t)*size; @@ -121,8 +121,8 @@ hashSlot_t *createHashTable(int size) /* Inserts the record specified with 'theRecord' into our hash table. */ -void insertHashRecord(hashSlot_t *theTable, aorToIndexStruct_t *theRecord, - int size) +void insertHashRecord(hashSlot_t *theTable, aorToIndexStruct_t *theRecord, + int size) { int hashIndex = calculateHashSlot(theRecord->aor, size); @@ -133,12 +133,12 @@ void insertHashRecord(hashSlot_t *theTable, aorToIndexStruct_t *theRecord, /* This is the first record in the hash table, so assign the first and * last pointers to this record. */ if (theTable[hashIndex].last == NULL) { - + theTable[hashIndex].last = theRecord; theTable[hashIndex].first = theRecord; } else { - + /* Make the element that was previously the last element point * to this new record, as its next element. */ theTable[hashIndex].last->next = theRecord; @@ -147,12 +147,12 @@ void insertHashRecord(hashSlot_t *theTable, aorToIndexStruct_t *theRecord, theTable[hashIndex].last = theRecord; } - + } /* * This function will search the provided hash table for an entry indexed by - * 'aor'. If an entry is found then: + * 'aor'. If an entry is found then: * * - Its numContacts counter will be decremented. * - If its numContacts counter reaches zero, then the entry will be removed @@ -164,7 +164,6 @@ void deleteUser(hashSlot_t *theTable, char *aor, int hashTableSize) int hashIndex = calculateHashSlot(aor, hashTableSize); int searchStringLength = strlen(aor); - aorToIndexStruct_t *previousRecord = theTable[hashIndex].first; aorToIndexStruct_t *currentRecord = theTable[hashIndex].first; while (currentRecord != NULL) { @@ -179,7 +178,7 @@ void deleteUser(hashSlot_t *theTable, char *aor, int hashTableSize) /* There are still contacts relying on this user, so * don't delete anything. */ - if (currentRecord->numContacts > 0) + if (currentRecord->numContacts > 0) { return; } @@ -191,7 +190,7 @@ void deleteUser(hashSlot_t *theTable, char *aor, int hashTableSize) /* Maintenance of the hash table */ - if (currentRecord->prev == NULL) + if (currentRecord->prev == NULL) { /* Edge Case: First element in list was just deleted, so set * up the first element to point to the one after the one @@ -226,7 +225,6 @@ void deleteUser(hashSlot_t *theTable, char *aor, int hashTableSize) } /* Advance to the next records. */ - previousRecord = currentRecord; currentRecord = currentRecord->next; } @@ -235,13 +233,13 @@ void deleteUser(hashSlot_t *theTable, char *aor, int hashTableSize) /* Returns a aorToIndexStruct_t, holding the given 'userIndex' and 'aor'. The * structure is used to map between the "aor" (OpenSER's way of indexing - * users/contacts), and the SNMPStats user and contact integer indexes. + * users/contacts), and the SNMPStats user and contact integer indexes. * * NOTE: that this record does not make a copy of aor, but instead points * directly to the parameter. Therefore make sure that aor is not on the stack, - * and is not going to disappear before this record is deleted. + * and is not going to disappear before this record is deleted. */ -aorToIndexStruct_t *createHashRecord(int userIndex, char *aor) +aorToIndexStruct_t *createHashRecord(int userIndex, char *aor) { int aorLength =strlen(aor); @@ -269,14 +267,14 @@ aorToIndexStruct_t *createHashRecord(int userIndex, char *aor) /* Debugging function. Prints off an entire hash slot. */ -void printHashSlot(hashSlot_t *theTable, int index) +void printHashSlot(hashSlot_t *theTable, int index) { aorToIndexStruct_t *currentRecord = theTable[index].first; LM_ERR("dumping Hash Slot #%d\n", index); while (currentRecord != NULL) { - LM_ERR( "\tString: %s - Index: %d\n", + LM_ERR( "\tString: %s - Index: %d\n", currentRecord->aor, currentRecord->userIndex); currentRecord = currentRecord->next; } diff --git a/modules/snmpstats/hashTable.h b/modules/snmpstats/hashTable.h index 44283fdb5a2..c5676705153 100644 --- a/modules/snmpstats/hashTable.h +++ b/modules/snmpstats/hashTable.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,14 +25,14 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Hash Stuff; * * This file describes several structure. In general, it was necessary to map * between OpenSER's "aor" (Address of Record) and string indexing mechanisms, * and the SNMPStats modules integer indexing scheme for users and contacts. * While it would have been a more natural fit to use string indexes in the - * SNMPStats module, SNMP limitations precluded this. + * SNMPStats module, SNMP limitations precluded this. * * aorToIndexStruct: maps an aor to: * - a userIndex, to uniquely identify each RegUserTable SNMP row @@ -52,11 +52,11 @@ #ifndef HASHSLOT_H #define HASHSLOT_H -/* +/* * Used to map between a 'contact' name (OpenSER's index) and a contact index. - * (SNMPStats Index) + * (SNMPStats Index) */ -typedef struct contactToIndexStruct +typedef struct contactToIndexStruct { char *contactName; @@ -70,9 +70,9 @@ typedef struct contactToIndexStruct /* * Used to map between an 'aor' (OpenSIPS index) and a user index. (SNMPStats * index). Since each user can have multiple contacts, the structure also has a - * 'contactIndex', and a reference to the contactToIndexStruct list. + * 'contactIndex', and a reference to the contactToIndexStruct list. */ -typedef struct aorToIndexStruct +typedef struct aorToIndexStruct { /* Pointer to the actual address record in the given SNMP row. */ char *aor; @@ -105,20 +105,20 @@ typedef struct aorToIndexStruct } aorToIndexStruct_t; -typedef struct hashSlot +typedef struct hashSlot { /* Number of elements in this list. */ int numberOfElements; /* First element in the list. */ - struct aorToIndexStruct* first; + struct aorToIndexStruct* first; /* Last element in the list. This is here for optimization purposes. * It stands to reason that things added later will need to be deleted * later. So they should be added to the end of the list. This way, * things that are to be deleted sooner will be at the front of the * list. */ - struct aorToIndexStruct* last; + struct aorToIndexStruct* last; } hashSlot_t; @@ -128,11 +128,11 @@ typedef struct hashSlot /* Returns a aorToIndexStruct_t, holding the given 'userIndex' and 'aor'. The * structure is used to map between the "aor" (OpenSER's way of indexing - * users/contacts), and the SNMPStats user and contact integer indexes. + * users/contacts), and the SNMPStats user and contact integer indexes. * * NOTE: that this record does not make a copy of aor, but instead points * directly to the parameter. Therefore make sure that aor is not on the stack, - * and is not going to disappear before this record is deleted. + * and is not going to disappear before this record is deleted. */ aorToIndexStruct_t *createHashRecord(int userIndex, char *aor); @@ -151,20 +151,20 @@ int calculateHashSlot(char *theString, int hashTableSize); /* Searches the hash table specified as theTable, of size 'size', for a record * indexed with 'aor'. If a match is found, then an aorToIndextStruct_t - * structure is returned. + * structure is returned. * - * This function is called to discover the map between OpenSER's "aor" + * This function is called to discover the map between OpenSER's "aor" * (Address of Records) indexing scheme, and the SNMPStats modules integer - * indexing scheme for its contact/user data. + * indexing scheme for its contact/user data. * - * Returns: the aorToIndexStruct_t mapping structure if a match was found, + * Returns: the aorToIndexStruct_t mapping structure if a match was found, * or NULL otherwise. */ aorToIndexStruct_t *findHashRecord(hashSlot_t *theTable, char *aor, int size); /* Inserts theRecord into an appropriate place in theTable, when size is given. */ -void insertHashRecord(hashSlot_t *theTable, aorToIndexStruct_t *theRecord, int size); +void insertHashRecord(hashSlot_t *theTable, aorToIndexStruct_t *theRecord, int size); /* Debugging function. Prints off an entire hash slot. */ @@ -173,11 +173,11 @@ void printHashSlot(hashSlot_t *theTable, int index); /* If a record is found with string aor in theTable, it is deleted and its * SNMPStats user integer index is returned. */ -int deleteHashRecord(hashSlot_t *theTable, char *aor, int hashTableSize); +int deleteHashRecord(hashSlot_t *theTable, char *aor, int hashTableSize); /* * This function will search the provided hash table for an entry indexed by - * 'aor'. If an entry is found then: + * 'aor'. If an entry is found then: * * - Its numContacts counter will be decremented. * - If its numContacts counter reaches zero, then the entry will be removed diff --git a/modules/snmpstats/interprocess_buffer.c b/modules/snmpstats/interprocess_buffer.c index 06da1ed58d3..a9ab2cd84ee 100644 --- a/modules/snmpstats/interprocess_buffer.c +++ b/modules/snmpstats/interprocess_buffer.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -28,8 +28,8 @@ * * This file implements the interprocess buffer, used for marshalling data * exchange from the usrloc module to the openserSIPRegUserTable, - * openserSIPContactTable, and indirectly the openserSIPRegUserLookupTable. - + * openserSIPContactTable, and indirectly the openserSIPRegUserLookupTable. + * Details on why the interprocess buffer is needed can be found in the comments * at the top of interprocess_buffer.h */ @@ -52,7 +52,7 @@ * * 1) maps all aor's to snmp's UserIndex for help in deleting SNMP Rows. * - * 2) maps a given aor to a contact list. + * 2) maps a given aor to a contact list. */ hashSlot_t *hashTable; @@ -64,10 +64,10 @@ interprocessBuffer_t *endRegUserTableBuffer = NULL; * the buffer while it is being consumed */ gen_lock_t *interprocessCBLock; -/* +/* * This function takes an element of the interprocess buffer passed to it, and * handles populating the respective user and contact tables with its contained - * data. + * data. */ static void executeInterprocessBufferCmd(interprocessBuffer_t *currentBuffer); @@ -75,13 +75,13 @@ static void executeInterprocessBufferCmd(interprocessBuffer_t *currentBuffer); * Initialize shared memory used to buffer communication between the usrloc * module and the SNMPStats module. (Specifically, the user and contact tables) */ -int initInterprocessBuffers(void) +int initInterprocessBuffers(void) { /* Initialize the shared memory that will be used to buffer messages * over the usrloc module to RegUserTable callback. */ frontRegUserTableBuffer = shm_malloc(sizeof(interprocessBuffer_t)); endRegUserTableBuffer = shm_malloc(sizeof(interprocessBuffer_t)); - + if(frontRegUserTableBuffer == NULL || endRegUserTableBuffer == NULL) { LM_ERR("no more shared memory\n"); @@ -136,14 +136,14 @@ int setInterprocessBuffersAlarm(void) * The callback type will be passed in 'type', and the contact the callback * applies to will be supplied in 'contactInfo. This information will be copied * into the interprocess buffer. The interprocess buffer will be consumed at a - * later time, when consumeInterprocessBuffer() is called. + * later time, when consumeInterprocessBuffer() is called. * * This callback is thread safe with respect to the consumeInterprocessBuffer() * function. Specifically, the interprocess buffer should not be corrupted by * any race conditions between this function and the consumeInterprocessBuffer() * function. */ -void handleContactCallbacks(ucontact_t *contactInfo, int type, void *param) +void handleContactCallbacks(ucontact_t *contactInfo, int type, void *param) { char *p; @@ -162,7 +162,7 @@ void handleContactCallbacks(ucontact_t *contactInfo, int type, void *param) p = (char*)(currentBufferElement + 1 ); /* We need to maintain our own copies of the AOR and contact address to - * prevent the corruption of our internal data structures. + * prevent the corruption of our internal data structures. * * If we do not maintain our own copies, then the AOR and contact adress * pointed to could be removed and reallocated to another thread before @@ -193,15 +193,15 @@ void handleContactCallbacks(ucontact_t *contactInfo, int type, void *param) } else { endRegUserTableBuffer->next->next = currentBufferElement; } - + endRegUserTableBuffer->next = currentBufferElement; lock_release(interprocessCBLock); - + return; error: - LM_ERR("Not enough shared memory for openserSIPRegUserTable insert." + LM_ERR("Not enough shared memory for openserSIPRegUserTable insert." " (%s)\n", contactInfo->c.s); } @@ -217,19 +217,19 @@ void handleContactCallbacks(ucontact_t *contactInfo, int type, void *param) * Note: This function is believed to be thread safe. Specifically, it protects * corruption of the interprocess buffer through the interprocessCBLock. * This ensures no corruption of the buffer by race conditions. The lock - * has been designed to be occupied for as short a period as possible, so - * as to prevent long waits. Specifically, once we start consumption of + * has been designed to be occupied for as short a period as possible, so + * as to prevent long waits. Specifically, once we start consumption of * the list, other processes are free to continue even before we are done. * This is made possible by simply changing the head of the interprocess - * buffer, and then releasing the lock. + * buffer, and then releasing the lock. */ -void consumeInterprocessBuffer(void) +void consumeInterprocessBuffer(void) { interprocessBuffer_t *previousBuffer; interprocessBuffer_t *currentBuffer; - + /* There is nothing to consume, so just exit. */ - if (frontRegUserTableBuffer->next == NULL) + if (frontRegUserTableBuffer->next == NULL) { return; } @@ -242,7 +242,7 @@ void consumeInterprocessBuffer(void) lock_get(interprocessCBLock); currentBuffer = frontRegUserTableBuffer->next; - + frontRegUserTableBuffer->next = NULL; endRegUserTableBuffer->next = NULL; @@ -265,20 +265,20 @@ void consumeInterprocessBuffer(void) } -/* +/* * This function takes an element of the interprocess buffer passed to it, and * handles populating the respective user and contact tables with its contained - * data. + * data. */ -static void executeInterprocessBufferCmd(interprocessBuffer_t *currentBuffer) +static void executeInterprocessBufferCmd(interprocessBuffer_t *currentBuffer) { int delContactIndex; aorToIndexStruct_t *currentUser; - if (currentBuffer->callbackType == UL_CONTACT_INSERT) + if (currentBuffer->callbackType == UL_CONTACT_INSERT) { - /* Add the user if the user doesn't exist, or increment its + /* Add the user if the user doesn't exist, or increment its * contact index otherwise. */ updateUser(currentBuffer->stringName); } @@ -300,23 +300,23 @@ static void executeInterprocessBufferCmd(interprocessBuffer_t *currentBuffer) /* This should never happen. This is more of a sanity check. */ if (currentUser == NULL) { LM_NOTICE("Received a request for contact: %s for user: %s who doesn't " - "exists\n", currentBuffer->stringName, + "exists\n", currentBuffer->stringName, currentBuffer->stringContact); return; - } + } /* This buffer element specified that we need to add a contact. So lets * add them */ if (currentBuffer->callbackType == UL_CONTACT_INSERT) { /* Increment the contact index, which will be used to generate - * our new row. */ + * our new row. */ currentUser->contactIndex++; /* We should do this after we create the row in the snmptable. * Its easier to delete the SNMP Row than the contact record. */ - if(!insertContactRecord(&(currentUser->contactList), - currentUser->contactIndex, + if(!insertContactRecord(&(currentUser->contactList), + currentUser->contactIndex, currentBuffer->stringContact)) { LM_ERR("openserSIPRegUserTable was unable to allocate memory for " @@ -326,16 +326,16 @@ static void executeInterprocessBufferCmd(interprocessBuffer_t *currentBuffer) /* We didn't use the index, so decrement it so we can * use it next time around. */ currentUser->contactIndex--; - + return; } - - if (!createContactRow(currentUser->userIndex, + + if (!createContactRow(currentUser->userIndex, currentUser->contactIndex, - currentBuffer->stringContact, + currentBuffer->stringContact, currentBuffer->contactInfo)) { - - deleteContactRecord(&(currentUser->contactList), + + deleteContactRecord(&(currentUser->contactList), currentBuffer->stringContact); } @@ -343,20 +343,20 @@ static void executeInterprocessBufferCmd(interprocessBuffer_t *currentBuffer) } else { - delContactIndex = - deleteContactRecord(&(currentUser->contactList), + delContactIndex = + deleteContactRecord(&(currentUser->contactList), currentBuffer->stringContact); /* This should never happen. But its probably wise to check and * to print out debug messages in case there is a hidden bug. */ if(delContactIndex == 0) { - + LM_ERR("Received a request to delete contact: %s for user: %s" " who doesn't exist\n", currentBuffer->stringName, currentBuffer->stringContact); return; - } + } deleteContactRow(currentUser->userIndex, delContactIndex); diff --git a/modules/snmpstats/interprocess_buffer.h b/modules/snmpstats/interprocess_buffer.h index 5391f32eb76..57dfa786c82 100644 --- a/modules/snmpstats/interprocess_buffer.h +++ b/modules/snmpstats/interprocess_buffer.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,7 +25,7 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * The SNMPStats module exposes user information through openserSIPRegUserTable, * openserSIPContactTable, and openserSIPRegUserLookupTable. These tables are * populated through callback mechanisms from the usrloc module. Unfortunately @@ -33,11 +33,11 @@ * amounts of data. Because we don't want to experience a performance hit when * registering users, we make use of the interprocess buffer. Specifically, * instead of adding/removing users/contacts from the SNMP tables directly, the - * callbacks add an add/delete command to the interprocessBuffer. - + * callbacks add an add/delete command to the interprocessBuffer. + * When an snmp request is recieved by the SNMPStats sub-process, it will * consume this interprocess buffer, adding and deleting users. When it is - * finished, it can service the SNMP request. + * finished, it can service the SNMP request. * * This doesn't remove the NetSNMP inefficiency of course, but it does move it * to a non-critical path. Such an approach allows SNMP support with almost no @@ -56,7 +56,7 @@ #include "../usrloc/ucontact.h" /* Represents an element of the interprocess buffer. */ -typedef struct interprocessBuffer +typedef struct interprocessBuffer { char *stringName; char *stringContact; @@ -93,7 +93,7 @@ int setInterprocessBuffersAlarm(void); * The callback type will be passed in 'type', and the contact the callback * applies to will be supplied in 'contactInfo. This information will be copied * into the interprocess buffer. The interprocess buffer will beconsumed at a - * later time, when consumeInterprocessBuffer() is called. + * later time, when consumeInterprocessBuffer() is called. * * This callback is thread safe with respect to the consumeInterprocessBuffer() * function. Specifically, the interprocess buffer should not be corrupted by @@ -114,11 +114,11 @@ void handleContactCallbacks(ucontact_t *contactInfo, int type, void *param); * Note: This function is believed to be thread safe. Specifically, it protects * corruption of the interprocess buffer through the interprocessCBLock. * This ensures no corruption of the buffer by race conditions. The lock - * has been designed to be occupied for as short a period as possible, so - * as to prevent long waits. Specifically, once we start consumption of + * has been designed to be occupied for as short a period as possible, so + * as to prevent long waits. Specifically, once we start consumption of * the list, other processes are free to continue even before we are done. * This is made possible by simply changing the head of the interprocess - * buffer, and then releasing the lock. + * buffer, and then releasing the lock. */ void consumeInterprocessBuffer(); diff --git a/modules/snmpstats/openserMIBNotifications.c b/modules/snmpstats/openserMIBNotifications.c index 1fbd209b209..26d99ebd557 100644 --- a/modules/snmpstats/openserMIBNotifications.c +++ b/modules/snmpstats/openserMIBNotifications.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,14 +25,14 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * : mib2c.notify.conf,v 5.3 2004/04/15 12:29:19 dts12 Exp $ * * This file contains functions for sending all traps supported by the SNMPStats - * module. + * module. */ #include @@ -45,7 +45,7 @@ static oid snmptrap_oid[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0}; -/* +/* * Sends off an openserMsgQueueDepthMinorEvent trap to the master agent, * assigning the following variable bindings: * @@ -53,36 +53,36 @@ static oid snmptrap_oid[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0}; * - openserMsgQueueMinorThreshold = minorThreshold * */ -int send_openserMsgQueueDepthMinorEvent_trap(int msgQueueDepth, +int send_openserMsgQueueDepthMinorEvent_trap(int msgQueueDepth, int minorThreshold) { netsnmp_variable_list *var_list = NULL; - - oid openserMsgQueueDepthMinorEvent_oid[] = { + + oid openserMsgQueueDepthMinorEvent_oid[] = { OPENSER_OID,3,1,3,2,0,1 }; - oid openserMsgQueueDepth_oid[] = { + oid openserMsgQueueDepth_oid[] = { OPENSER_OID,3,1,3,1,2,3,1,0 }; - oid openserMsgQueueMinorThreshold_oid[] = { + oid openserMsgQueueMinorThreshold_oid[] = { OPENSER_OID,3,1,3,1,2,3,2,0 }; snmp_varlist_add_variable(&var_list, - snmptrap_oid, + snmptrap_oid, OID_LENGTH(snmptrap_oid), ASN_OBJECT_ID, - (u_char *)openserMsgQueueDepthMinorEvent_oid, + (u_char *)openserMsgQueueDepthMinorEvent_oid, (int)sizeof(openserMsgQueueDepthMinorEvent_oid)); - + snmp_varlist_add_variable(&var_list, - openserMsgQueueDepth_oid, + openserMsgQueueDepth_oid, OID_LENGTH(openserMsgQueueDepth_oid), ASN_GAUGE, - (u_char *)&msgQueueDepth, + (u_char *)&msgQueueDepth, sizeof(msgQueueDepth)); snmp_varlist_add_variable(&var_list, - openserMsgQueueMinorThreshold_oid, + openserMsgQueueMinorThreshold_oid, OID_LENGTH(openserMsgQueueMinorThreshold_oid), ASN_INTEGER, (u_char *)&minorThreshold, @@ -102,32 +102,32 @@ int send_openserMsgQueueDepthMinorEvent_trap(int msgQueueDepth, * - openserMsgQueueMajorThreshold = majorThreshold * */ -int send_openserMsgQueueDepthMajorEvent_trap(int msgQueueDepth, +int send_openserMsgQueueDepthMajorEvent_trap(int msgQueueDepth, int majorThreshold) { netsnmp_variable_list *var_list = NULL; - oid openserMsgQueueDepthMajorEvent_oid[] = { + oid openserMsgQueueDepthMajorEvent_oid[] = { OPENSER_OID,3,1,3,2,0,2 }; oid openserMsgQueueDepth_oid[] = { OPENSER_OID,3,1,3,1,2,3,1,0 }; - oid openserMsgQueueMajorThreshold_oid[] = { + oid openserMsgQueueMajorThreshold_oid[] = { OPENSER_OID,3,1,3,1,2,3,3,0 }; - snmp_varlist_add_variable(&var_list, + snmp_varlist_add_variable(&var_list, snmptrap_oid, - OID_LENGTH(snmptrap_oid), + OID_LENGTH(snmptrap_oid), ASN_OBJECT_ID, (u_char *)openserMsgQueueDepthMajorEvent_oid, (int)sizeof(openserMsgQueueDepthMajorEvent_oid)); - - snmp_varlist_add_variable(&var_list, + + snmp_varlist_add_variable(&var_list, openserMsgQueueDepth_oid, OID_LENGTH(openserMsgQueueDepth_oid), ASN_GAUGE, - (u_char *)&msgQueueDepth, + (u_char *)&msgQueueDepth, sizeof(msgQueueDepth)); snmp_varlist_add_variable(&var_list, @@ -156,31 +156,31 @@ int send_openserDialogLimitMinorEvent_trap(int numDialogs, int threshold) { netsnmp_variable_list *var_list = NULL; - oid openserDialogLimitMinorEvent_oid[] = { + oid openserDialogLimitMinorEvent_oid[] = { OPENSER_OID,3,1,3,2,0,3 }; - - oid openserCurNumDialogs_oid[] = { + + oid openserCurNumDialogs_oid[] = { OPENSER_OID,3,1,3,1,3,2,1, 0 }; - - oid openserDialogLimitMinorThreshold_oid[] = { + + oid openserDialogLimitMinorThreshold_oid[] = { OPENSER_OID,3,1,3,1,3,2,5, 0 }; snmp_varlist_add_variable(&var_list, snmptrap_oid, - OID_LENGTH(snmptrap_oid), + OID_LENGTH(snmptrap_oid), ASN_OBJECT_ID, (u_char *)openserDialogLimitMinorEvent_oid, (int)sizeof(openserDialogLimitMinorEvent_oid)); - + snmp_varlist_add_variable(&var_list, - openserCurNumDialogs_oid, + openserCurNumDialogs_oid, OID_LENGTH(openserCurNumDialogs_oid), ASN_GAUGE, (u_char *)&numDialogs, sizeof(numDialogs)); snmp_varlist_add_variable(&var_list, - openserDialogLimitMinorThreshold_oid, + openserDialogLimitMinorThreshold_oid, OID_LENGTH(openserDialogLimitMinorThreshold_oid), ASN_INTEGER, (u_char *)&threshold, @@ -205,31 +205,31 @@ int send_openserDialogLimitMajorEvent_trap(int numDialogs, int threshold) { netsnmp_variable_list *var_list = NULL; - oid openserDialogLimitMajorEvent_oid[] = { + oid openserDialogLimitMajorEvent_oid[] = { OPENSER_OID,3,1,3,2,0,4 }; - oid openserCurNumDialogs_oid[] = { + oid openserCurNumDialogs_oid[] = { OPENSER_OID,3,1,3,1,3,2,1, 0 }; - oid openserDialogLimitMajorThreshold_oid[] = { + oid openserDialogLimitMajorThreshold_oid[] = { OPENSER_OID,3,1,3,1,3,2,6, 0 }; snmp_varlist_add_variable(&var_list, - snmptrap_oid, + snmptrap_oid, OID_LENGTH(snmptrap_oid), ASN_OBJECT_ID, - (u_char *)openserDialogLimitMajorEvent_oid, + (u_char *)openserDialogLimitMajorEvent_oid, (int)sizeof(openserDialogLimitMajorEvent_oid)); - + snmp_varlist_add_variable(&var_list, - openserCurNumDialogs_oid, + openserCurNumDialogs_oid, OID_LENGTH(openserCurNumDialogs_oid), ASN_GAUGE, (u_char *)&numDialogs, sizeof(numDialogs)); snmp_varlist_add_variable(&var_list, - openserDialogLimitMajorThreshold_oid, + openserDialogLimitMajorThreshold_oid, OID_LENGTH(openserDialogLimitMajorThreshold_oid), ASN_INTEGER, (u_char *)&threshold, diff --git a/modules/snmpstats/openserMIBNotifications.h b/modules/snmpstats/openserMIBNotifications.h index 265ac60c9ae..e90dc969cf5 100644 --- a/modules/snmpstats/openserMIBNotifications.h +++ b/modules/snmpstats/openserMIBNotifications.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,12 +25,12 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * : mib2c.notify.conf,v 5.3 2004/04/15 12:29:19 dts12 Exp $ * * This file contains function prototypes for sending all traps supported by the - * SNMPStats module. + * SNMPStats module. * */ @@ -38,7 +38,7 @@ #define OPENSERMIBNOTIFICATIONS_H -/* +/* * Sends off an openserMsgQueueDepthMinorEvent trap to the master agent, * assigning the following variable bindings: * @@ -46,7 +46,7 @@ * - openserMsgQueueMinorThreshold = minorThreshold * */ -int send_openserMsgQueueDepthMinorEvent_trap(int msgQueueDepth, +int send_openserMsgQueueDepthMinorEvent_trap(int msgQueueDepth, int minorThreshold); /* @@ -57,7 +57,7 @@ int send_openserMsgQueueDepthMinorEvent_trap(int msgQueueDepth, * - openserMsgQueueMajorThreshold = majorThreshold * */ -int send_openserMsgQueueDepthMajorEvent_trap(int msgQueueDepth, +int send_openserMsgQueueDepthMajorEvent_trap(int msgQueueDepth, int majorThreshold); /* diff --git a/modules/snmpstats/openserObjects.c b/modules/snmpstats/openserObjects.c index 50d887f8a6c..ed3725944b3 100644 --- a/modules/snmpstats/openserObjects.c +++ b/modules/snmpstats/openserObjects.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,9 +25,9 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * : mib2c.scalar.conf,v 1.9 2005/01/07 09:37:18 dts12 Exp $ * @@ -49,7 +49,7 @@ #include "utilities.h" #include "alarm_checks.h" -/* +/* * Initializes the openserObjects module. This involves: * * - Registering all OID's @@ -59,52 +59,52 @@ */ void init_openserObjects(void) { - static oid openserMsgQueueDepth_oid[] = + static oid openserMsgQueueDepth_oid[] = { OPENSER_OID,3,1,3,1,2,3,1 }; - static oid openserMsgQueueMinorThreshold_oid[] = + static oid openserMsgQueueMinorThreshold_oid[] = { OPENSER_OID,3,1,3,1,2,3,2 }; - static oid openserMsgQueueMajorThreshold_oid[] = + static oid openserMsgQueueMajorThreshold_oid[] = { OPENSER_OID,3,1,3,1,2,3,3 }; - static oid openserMsgQueueDepthAlarmStatus_oid[] = + static oid openserMsgQueueDepthAlarmStatus_oid[] = { OPENSER_OID,3,1,3,1,2,4,1 }; - - static oid openserMsgQueueDepthMinorAlarm_oid[] = + + static oid openserMsgQueueDepthMinorAlarm_oid[] = { OPENSER_OID,3,1,3,1,2,4,2 }; - static oid openserMsgQueueDepthMajorAlarm_oid[] = + static oid openserMsgQueueDepthMajorAlarm_oid[] = { OPENSER_OID,3,1,3,1,2,4,3 }; - static oid openserCurNumDialogs_oid[] = + static oid openserCurNumDialogs_oid[] = { OPENSER_OID,3,1,3,1,3,2,1 }; - static oid openserCurNumDialogsInProgress_oid[] = + static oid openserCurNumDialogsInProgress_oid[] = { OPENSER_OID,3,1,3,1,3,2,2 }; - static oid openserCurNumDialogsInSetup_oid[] = + static oid openserCurNumDialogsInSetup_oid[] = { OPENSER_OID,3,1,3,1,3,2,3 }; - static oid openserTotalNumFailedDialogSetups_oid[] = + static oid openserTotalNumFailedDialogSetups_oid[] = { OPENSER_OID,3,1,3,1,3,2,4 }; - static oid openserDialogLimitMinorThreshold_oid[] = + static oid openserDialogLimitMinorThreshold_oid[] = { OPENSER_OID,3,1,3,1,3,2,5 }; - static oid openserDialogLimitMajorThreshold_oid[] = + static oid openserDialogLimitMajorThreshold_oid[] = { OPENSER_OID,3,1,3,1,3,2,6 }; - static oid openserDialogUsageState_oid[] = + static oid openserDialogUsageState_oid[] = { OPENSER_OID,3,1,3,1,3,3,1 }; - static oid openserDialogLimitAlarmStatus_oid[] = + static oid openserDialogLimitAlarmStatus_oid[] = { OPENSER_OID,3,1,3,1,3,4,1 }; - static oid openserDialogLimitMinorAlarm_oid[] = + static oid openserDialogLimitMinorAlarm_oid[] = { OPENSER_OID,3,1,3,1,3,4,2 }; - static oid openserDialogLimitMajorAlarm_oid[] = + static oid openserDialogLimitMajorAlarm_oid[] = { OPENSER_OID,3,1,3,1,3,4,3 }; @@ -112,162 +112,162 @@ void init_openserObjects(void) netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserMsgQueueDepth", + "openserMsgQueueDepth", handle_openserMsgQueueDepth, - openserMsgQueueDepth_oid, + openserMsgQueueDepth_oid, OID_LENGTH(openserMsgQueueDepth_oid), HANDLER_CAN_RONLY) ); netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserMsgQueueMinorThreshold", + "openserMsgQueueMinorThreshold", handle_openserMsgQueueMinorThreshold, - openserMsgQueueMinorThreshold_oid, + openserMsgQueueMinorThreshold_oid, OID_LENGTH(openserMsgQueueMinorThreshold_oid), HANDLER_CAN_RONLY) ); netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserMsgQueueMajorThreshold", + "openserMsgQueueMajorThreshold", handle_openserMsgQueueMajorThreshold, - openserMsgQueueMajorThreshold_oid, + openserMsgQueueMajorThreshold_oid, OID_LENGTH(openserMsgQueueMajorThreshold_oid), HANDLER_CAN_RONLY) ); netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserMsgQueueDepthAlarmStatus", + "openserMsgQueueDepthAlarmStatus", handle_openserMsgQueueDepthAlarmStatus, - openserMsgQueueDepthAlarmStatus_oid, + openserMsgQueueDepthAlarmStatus_oid, OID_LENGTH(openserMsgQueueDepthAlarmStatus_oid), HANDLER_CAN_RONLY) ); netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserMsgQueueDepthMinorAlarm", + "openserMsgQueueDepthMinorAlarm", handle_openserMsgQueueDepthMinorAlarm, - openserMsgQueueDepthMinorAlarm_oid, + openserMsgQueueDepthMinorAlarm_oid, OID_LENGTH(openserMsgQueueDepthMinorAlarm_oid), HANDLER_CAN_RONLY) ); - + netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserMsgQueueDepthMajorAlarm", + "openserMsgQueueDepthMajorAlarm", handle_openserMsgQueueDepthMajorAlarm, - openserMsgQueueDepthMajorAlarm_oid, + openserMsgQueueDepthMajorAlarm_oid, OID_LENGTH(openserMsgQueueDepthMajorAlarm_oid), HANDLER_CAN_RONLY) ); netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserCurNumDialogs", + "openserCurNumDialogs", handle_openserCurNumDialogs, - openserCurNumDialogs_oid, + openserCurNumDialogs_oid, OID_LENGTH(openserCurNumDialogs_oid), HANDLER_CAN_RONLY) ); - + netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserCurNumDialogsInProgress", + "openserCurNumDialogsInProgress", handle_openserCurNumDialogsInProgress, - openserCurNumDialogsInProgress_oid, + openserCurNumDialogsInProgress_oid, OID_LENGTH(openserCurNumDialogsInProgress_oid), HANDLER_CAN_RONLY) ); - + netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserCurNumDialogsInSetup", + "openserCurNumDialogsInSetup", handle_openserCurNumDialogsInSetup, - openserCurNumDialogsInSetup_oid, + openserCurNumDialogsInSetup_oid, OID_LENGTH(openserCurNumDialogsInSetup_oid), HANDLER_CAN_RONLY) ); - + netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserTotalNumFailedDialogSetups", + "openserTotalNumFailedDialogSetups", handle_openserTotalNumFailedDialogSetups, - openserTotalNumFailedDialogSetups_oid, + openserTotalNumFailedDialogSetups_oid, OID_LENGTH(openserTotalNumFailedDialogSetups_oid), HANDLER_CAN_RONLY) ); - + netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserDialogLimitMinorThreshold", + "openserDialogLimitMinorThreshold", handle_openserDialogLimitMinorThreshold, - openserDialogLimitMinorThreshold_oid, + openserDialogLimitMinorThreshold_oid, OID_LENGTH(openserDialogLimitMinorThreshold_oid), HANDLER_CAN_RONLY) ); netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserDialogLimitMajorThreshold", + "openserDialogLimitMajorThreshold", handle_openserDialogLimitMajorThreshold, - openserDialogLimitMajorThreshold_oid, + openserDialogLimitMajorThreshold_oid, OID_LENGTH(openserDialogLimitMajorThreshold_oid), HANDLER_CAN_RONLY) ); netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserDialogUsageState", + "openserDialogUsageState", handle_openserDialogUsageState, - openserDialogUsageState_oid, + openserDialogUsageState_oid, OID_LENGTH(openserDialogUsageState_oid), HANDLER_CAN_RONLY) ); - + netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserDialogLimitAlarmStatus", + "openserDialogLimitAlarmStatus", handle_openserDialogLimitAlarmStatus, - openserDialogLimitAlarmStatus_oid, + openserDialogLimitAlarmStatus_oid, OID_LENGTH(openserDialogLimitAlarmStatus_oid), HANDLER_CAN_RONLY) ); - + netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserDialogLimitMinorAlarm", + "openserDialogLimitMinorAlarm", handle_openserDialogLimitMinorAlarm, - openserDialogLimitMinorAlarm_oid, + openserDialogLimitMinorAlarm_oid, OID_LENGTH(openserDialogLimitMinorAlarm_oid), HANDLER_CAN_RONLY) ); - + netsnmp_register_scalar( netsnmp_create_handler_registration( - "openserDialogLimitMajorAlarm", + "openserDialogLimitMajorAlarm", handle_openserDialogLimitMajorAlarm, - openserDialogLimitMajorAlarm_oid, + openserDialogLimitMajorAlarm_oid, OID_LENGTH(openserDialogLimitMajorAlarm_oid), HANDLER_CAN_RONLY) ); } -/* +/* * The following are thresholds used by: - * - * - The alarm monitoring process, to decide when to send out traps. - * - All scalars involving alarm status's and thresholds. + * + * - The alarm monitoring process, to decide when to send out traps. + * - All scalars involving alarm status's and thresholds. * * By default they are initialized to -1, which disables alarm checks. * These are set through the opensips.cfg file with the following modparams to * the snmpstats module: * - * - dlg_minor_threshold - * - dlg_major_threshold + * - dlg_minor_threshold + * - dlg_major_threshold * * - MsgQueueMinorThreshold * - MsgQueueMajorThreshold @@ -286,7 +286,7 @@ int handle_openserMsgQueueDepth(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int bytesWaiting; - + bytesWaiting = get_total_bytes_waiting(PROTO_NONE); if (reqinfo->mode == MODE_GET) { @@ -307,7 +307,7 @@ int handle_openserMsgQueueMinorThreshold(netsnmp_mib_handler *handler, snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &msgQueueMinorThreshold, sizeof(int)); return SNMP_ERR_NOERROR; - } + } return SNMP_ERR_GENERR; } @@ -337,7 +337,7 @@ int handle_openserMsgQueueDepthAlarmStatus(netsnmp_mib_handler *handler, * this means that no bits are toggled. So we set the state to zero by * default */ unsigned int state = 0; - + if (check_msg_queue_alarm(msgQueueMinorThreshold)) { state |= TC_ALARM_STATUS_MINOR; } @@ -362,7 +362,7 @@ int handle_openserMsgQueueDepthMinorAlarm(netsnmp_mib_handler *handler, { int x731AlarmState = TC_ALARM_STATE_CLEAR; - if (check_msg_queue_alarm(msgQueueMinorThreshold)) { + if (check_msg_queue_alarm(msgQueueMinorThreshold)) { x731AlarmState = TC_ALARM_STATE_MINOR; } @@ -382,10 +382,10 @@ int handle_openserMsgQueueDepthMajorAlarm(netsnmp_mib_handler *handler, { int x731AlarmState = TC_ALARM_STATE_CLEAR; - if (check_msg_queue_alarm(msgQueueMajorThreshold)) { + if (check_msg_queue_alarm(msgQueueMajorThreshold)) { x731AlarmState = TC_ALARM_STATE_MAJOR; } - + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &x731AlarmState, sizeof(int)); @@ -421,10 +421,10 @@ int handle_openserCurNumDialogsInProgress(netsnmp_mib_handler *handler, /* This scalar is defined as the number of dialogs in the CONFIRMED * state only. active_dialogs includes both confirmed and early, so * we subtract out early_dialogs from active_dialogs. */ - int result = + int result = get_statistic("active_dialogs") - get_statistic("early_dialogs"); - + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &result, sizeof(int)); @@ -442,7 +442,7 @@ int handle_openserCurNumDialogsInSetup(netsnmp_mib_handler *handler, /* This scalar is defined as the number of dialogs in the EARLY state. * */ int result = get_statistic("early_dialogs"); - + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &result, sizeof(int)); @@ -458,7 +458,7 @@ int handle_openserTotalNumFailedDialogSetups(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int result = get_statistic("failed_dialogs"); - + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); @@ -501,7 +501,7 @@ int handle_openserDialogUsageState(netsnmp_mib_handler *handler, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { - /* Return value follows the X731UsageState Textual Convention + /* Return value follows the X731UsageState Textual Convention * * We default to 'unknown' */ int usage_state = TC_USAGE_STATE_UNKNOWN; @@ -514,11 +514,11 @@ int handle_openserDialogUsageState(netsnmp_mib_handler *handler, usage_state = TC_USAGE_STATE_ACTIVE; } - if ((dialog_major_threshold > -1) && (num_dialogs > + if ((dialog_major_threshold > -1) && (num_dialogs > dialog_major_threshold)) { usage_state = TC_USAGE_STATE_BUSY; } - + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &usage_state, sizeof(int)); @@ -539,7 +539,7 @@ int handle_openserDialogLimitAlarmStatus(netsnmp_mib_handler *handler, * this means that no bits are toggled. So we set the state to zero by * default */ unsigned int state = 0; - + if (check_dialog_alarm(dialog_minor_threshold)) { state |= TC_ALARM_STATUS_MINOR; } @@ -548,7 +548,7 @@ int handle_openserDialogLimitAlarmStatus(netsnmp_mib_handler *handler, state |= TC_ALARM_STATUS_MAJOR; } - + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &state, 1); @@ -571,7 +571,7 @@ int handle_openserDialogLimitMinorAlarm(netsnmp_mib_handler *handler, { x731AlarmState = TC_ALARM_STATE_MINOR; } - + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &x731AlarmState, sizeof(int)); @@ -592,7 +592,7 @@ int handle_openserDialogLimitMajorAlarm(netsnmp_mib_handler *handler, { x731AlarmState = TC_ALARM_STATE_MAJOR; } - + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &x731AlarmState, sizeof(int)); @@ -604,8 +604,8 @@ int handle_openserDialogLimitMajorAlarm(netsnmp_mib_handler *handler, /* If a proper integer is passed that is >= -1, then newValue will be set to * val, and 0 returned. Otherwise -1 is returned. */ -static int set_if_valid_threshold(modparam_t type, void *val, char *varStr, - int *newVal) +static int set_if_valid_threshold(modparam_t type, void *val, char *varStr, + int *newVal) { if (val==0) { LM_ERR("%s called with a null value!\n", varStr); @@ -617,22 +617,22 @@ static int set_if_valid_threshold(modparam_t type, void *val, char *varStr, varStr, type, INT_PARAM); return -1; } - + int new_threshold = (int)(long)(int *)val; if (new_threshold < -1) { LM_ERR("%s called with an invalid threshold=%d!\n", - varStr, new_threshold); + varStr, new_threshold); return -1; } - + *newVal = new_threshold; return 0; } -/* - * Paramater Configuration Functions +/* + * Paramater Configuration Functions */ /* Handles setting of the message queue minor alarm threshold */ @@ -651,23 +651,23 @@ int set_queue_major_threshold(modparam_t type, void *val) { /* Handles setting of the dialog minor threshold */ int set_dlg_minor_threshold(modparam_t type, void *val) { - return set_if_valid_threshold(type, val, "set_dlg_minor_threshold", + return set_if_valid_threshold(type, val, "set_dlg_minor_threshold", &dialog_minor_threshold); } /* Handles setting of the dialog major threshold */ int set_dlg_major_threshold(modparam_t type, void *val) { - return set_if_valid_threshold(type, val, "set_dlg_major_threshold", + return set_if_valid_threshold(type, val, "set_dlg_major_threshold", &dialog_major_threshold); } -int get_msg_queue_minor_threshold(void) +int get_msg_queue_minor_threshold(void) { return msgQueueMinorThreshold; } -int get_msg_queue_major_threshold(void) +int get_msg_queue_major_threshold(void) { return msgQueueMajorThreshold; } diff --git a/modules/snmpstats/openserObjects.h b/modules/snmpstats/openserObjects.h index 59084e1c70e..ac321cc279f 100644 --- a/modules/snmpstats/openserObjects.h +++ b/modules/snmpstats/openserObjects.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,7 +25,7 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * : mib2c.scalar.conf,v 1.9 2005/01/07 09:37:18 dts12 Exp $ * diff --git a/modules/snmpstats/openserSIPCommonObjects.c b/modules/snmpstats/openserSIPCommonObjects.c index f67907c6505..bc0ae32a636 100644 --- a/modules/snmpstats/openserSIPCommonObjects.c +++ b/modules/snmpstats/openserSIPCommonObjects.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,9 +25,9 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * : mib2c.scalar.conf,v 1.9 2005/01/07 09:37:18 dts12 Exp $ * @@ -54,7 +54,7 @@ static char *openserVersion = "SIP/2.0"; static unsigned int openserEntityType = TC_SIP_ENTITY_ROLE_OTHER; -/* +/* * Initializes the openserSIPCommonObjects MIB elements. This involves: * * - Registering all OID's @@ -97,7 +97,7 @@ void init_openserSIPCommonObjects(void) static oid openserSIPNumUnsupportedMethods_oid[] = { OPENSER_OID,3,1,1,1,8,2 }; - static oid openserSIPOtherwiseDiscardedMsgs_oid[] = + static oid openserSIPOtherwiseDiscardedMsgs_oid[] = { OPENSER_OID,3,1,1,1,8,3 }; DEBUGMSGTL(("openserSIPCommonObjects", "Initializing\n")); @@ -108,7 +108,7 @@ void init_openserSIPCommonObjects(void) handle_openserSIPProtocolVersion, openserSIPProtocolVersion_oid, OID_LENGTH(openserSIPProtocolVersion_oid), - HANDLER_CAN_RONLY)); + HANDLER_CAN_RONLY)); netsnmp_register_scalar( netsnmp_create_handler_registration( @@ -196,7 +196,7 @@ void init_openserSIPCommonObjects(void) handle_openserSIPOtherwiseDiscardedMsgs, openserSIPOtherwiseDiscardedMsgs_oid, OID_LENGTH(openserSIPOtherwiseDiscardedMsgs_oid), - HANDLER_CAN_RONLY)); + HANDLER_CAN_RONLY)); } @@ -204,7 +204,7 @@ int handle_openserSIPProtocolVersion(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) -{ +{ if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) openserVersion, 7); @@ -214,10 +214,10 @@ int handle_openserSIPProtocolVersion(netsnmp_mib_handler *handler, return SNMP_ERR_GENERR; } -/* +/* * The scalar represents what sysUpTime was when OpenSIPS first started. This * data was stored in a file when SNMPStats first started up, as a result of a - * call to spawn_sysUpTime_child() + * call to spawn_sysUpTime_child() */ int handle_openserSIPServiceStartTime(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, @@ -256,12 +256,12 @@ int handle_openserSIPServiceStartTime(netsnmp_mib_handler *handler, fclose(theFile); } - if (reqinfo->mode == MODE_GET) { + if (reqinfo->mode == MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_TIMETICKS, (u_char *) &elapsedTime, sizeof(elapsedTime)); return SNMP_ERR_NOERROR; } - + return SNMP_ERR_GENERR; } @@ -287,7 +287,7 @@ int handle_openserSIPSummaryInRequests(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int numRequests = get_statistic("rcv_requests"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &numRequests, sizeof(int)); @@ -302,8 +302,8 @@ int handle_openserSIPSummaryOutRequests(netsnmp_mib_handler *handler, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { - int out_requests = get_statistic("fwd_requests"); - + int out_requests = get_statistic("fwd_requests"); + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &out_requests, sizeof(int)); @@ -318,8 +318,8 @@ int handle_openserSIPSummaryInResponses(netsnmp_mib_handler *handler, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { - int result = get_statistic("rcv_replies"); - + int result = get_statistic("rcv_replies"); + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); @@ -337,19 +337,19 @@ int handle_openserSIPSummaryOutResponses(netsnmp_mib_handler *handler, /* We can find the number of outbound responses sent by adding three * sources * - * 1) fwd_replies from core_stats - * 2) local_replies and relayed_replies from the tm module - * 3) sent_replies from the sl module. + * 1) fwd_replies from core_stats + * 2) local_replies and relayed_replies from the tm module + * 3) sent_replies from the sl module. */ - + int fwd_replies = get_statistic("fwd_replies"); int local_replies = get_statistic("local_replies"); int relayed_replies = get_statistic("relayed_replies"); int sent_replies = get_statistic("sent_replies"); - int result = + int result = fwd_replies + local_replies + relayed_replies + sent_replies; - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); @@ -364,12 +364,12 @@ int handle_openserSIPSummaryTotalTransactions(netsnmp_mib_handler *handler, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { - /* We can find the total number of transactions by summing + /* We can find the total number of transactions by summing * UAC_transactions and UAS_transactions. We don't need to add * inuse_transactions because this will already be accounted for in the * two other statistics. */ - int result = - get_statistic("UAS_transactions") + + int result = + get_statistic("UAS_transactions") + get_statistic("UAC_transactions"); if (reqinfo->mode==MODE_GET) { @@ -387,7 +387,7 @@ int handle_openserSIPCurrentTransactions(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int result = get_statistic("inuse_transactions"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &result, sizeof(int)); @@ -403,7 +403,7 @@ int handle_openserSIPNumUnsupportedUris(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int result = get_statistic("bad_URIs_rcvd"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); @@ -419,7 +419,7 @@ int handle_openserSIPNumUnsupportedMethods(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int result = get_statistic("unsupported_methods"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); @@ -436,12 +436,12 @@ int handle_openserSIPOtherwiseDiscardedMsgs(netsnmp_mib_handler *handler, { /* We should be able to get this number from existing stats layed out in * the following equation: */ - int result = + int result = get_statistic("err_requests") + get_statistic("err_replies") + get_statistic("drop_requests") + - get_statistic("drop_replies"); - + get_statistic("drop_replies"); + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); @@ -452,19 +452,19 @@ int handle_openserSIPOtherwiseDiscardedMsgs(netsnmp_mib_handler *handler, } /* - * Parameter Setting Functions + * Parameter Setting Functions */ /* If type==STR_PARAM and stringParam is valid, this function will overwrite - * openserEntityType with a bit value corresponding to the IETF's RFC for + * openserEntityType with a bit value corresponding to the IETF's RFC for * the SIP MIB. (Textual Convention SipEntityRole). Anything else is * considered an error. * - * Returns 0 on success, -1 on failure. + * Returns 0 on success, -1 on failure. */ -int handleSipEntityType( modparam_t type, void* val) +int handleSipEntityType( modparam_t type, void* val) { - + /* By default we start off as "other". */ static char firstTime = 1; @@ -480,20 +480,20 @@ int handleSipEntityType( modparam_t type, void* val) if (firstTime) { firstTime = 0; openserEntityType = 0; - } + } /* Begin our string comparison. This isn't the most efficient approach, * but we don't expect this function to be called anywhere other than at - * startup. So our inefficiency is outweiged by simplicity + * startup. So our inefficiency is outweiged by simplicity */ if (strcasecmp(strEntityType, "other") == 0) { openserEntityType |= TC_SIP_ENTITY_ROLE_OTHER; } else if (strcasecmp(strEntityType, "userAgent") == 0) { - openserEntityType |= TC_SIP_ENTITY_ROLE_USER_AGENT; + openserEntityType |= TC_SIP_ENTITY_ROLE_USER_AGENT; } else if (strcasecmp(strEntityType, "proxyServer") == 0) { - openserEntityType |= TC_SIP_ENTITY_ROLE_PROXY_SERVER; + openserEntityType |= TC_SIP_ENTITY_ROLE_PROXY_SERVER; } else if (strcasecmp(strEntityType, "redirectServer") == 0) { openserEntityType |= TC_SIP_ENTITY_ROLE_REDIRECT_SERVER; diff --git a/modules/snmpstats/openserSIPCommonObjects.h b/modules/snmpstats/openserSIPCommonObjects.h index 9dc446bb41f..7d54a8a16c7 100644 --- a/modules/snmpstats/openserSIPCommonObjects.h +++ b/modules/snmpstats/openserSIPCommonObjects.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,7 +25,7 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * : mib2c.scalar.conf,v 1.9 2005/01/07 09:37:18 dts12 Exp $ * diff --git a/modules/snmpstats/openserSIPContactTable.c b/modules/snmpstats/openserSIPContactTable.c index e18eac79fd5..d5364f73d41 100644 --- a/modules/snmpstats/openserSIPContactTable.c +++ b/modules/snmpstats/openserSIPContactTable.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,9 +25,9 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Note: this file originally auto-generated by mib2c using - * mib2c.array-user.conf + * mib2c.array-user.conf * * This file contains the implementation of the openserSIPContact Table. For a * full description of this structure, please see the OPENSER-SIP-SERVER-MIB. @@ -37,29 +37,29 @@ * We require OpenSERs usrloc module to inform us when a contact is * added/removed. The general callback process works as follows: * - * 1) On startup, we register handleContactCallbacks() for USRLOC callbacks, so - * we can be informed whenever a contact is added/removed from the system. - * This registration happens with a call to registerForUSRLOCCallbacks(). + * 1) On startup, we register handleContactCallbacks() for USRLOC callbacks, so + * we can be informed whenever a contact is added/removed from the system. + * This registration happens with a call to registerForUSRLOCCallbacks(). * (This is actually called when the SNMPStats module is initialized) * - * 2) Whenever we receive a contact callback, handleContactCallbacks() will + * 2) Whenever we receive a contact callback, handleContactCallbacks() will * quickly add the contact information and operation type to the - * interprocess buffer. + * interprocess buffer. * * 3) When we receive an SNMP request for user/contact information, we consume * the interprocess buffer with consumeInterprocessBuffer(). The function * will add/delete rows to the tables, and then service the SNMP request. * - * Notes: + * Notes: * * - The interprocess buffer was necessary, because NetSNMP's containers can be * very inefficient at adding large amounts of data at a time, such as when * OpenSIPS first starts up. It was decided its better to make an SNMP manager * wait for data, instead of slowing down the rest of OpenSIPS while the - * sub-agent processes the data. + * sub-agent processes the data. * * - It is important to send periodic SNMP requests to this table (or the user - * table), to make sure the process buffer doesn't get too large. + * table), to make sure the process buffer doesn't get too large. * */ @@ -89,19 +89,19 @@ static netsnmp_table_array_callbacks cb; oid openserSIPContactTable_oid[] = { openserSIPContactTable_TABLE_OID }; size_t openserSIPContactTable_oid_len = OID_LENGTH(openserSIPContactTable_oid); -/* +/* * This function adds a new contactToIndexStruct_t record to the front of - * 'contactRecord'. + * 'contactRecord'. * * The structure is used to map a contact name to the SNMPStats modules integer * indexing scheme. It will be used later when a delete command comes in, and * we need to find out which SNMP row the information is stored under. */ int insertContactRecord( - contactToIndexStruct_t **contactRecord, int index, char *name) + contactToIndexStruct_t **contactRecord, int index, char *name) { int nameLength =strlen(name); - + contactToIndexStruct_t *newContactRecord = (contactToIndexStruct_t *) pkg_malloc(sizeof(contactToIndexStruct_t) +(nameLength+1)* sizeof(char)); @@ -127,7 +127,7 @@ int insertContactRecord( * This function will remove the contactToIndexStruct_T record matching * 'contactName' from the users contactToIndexStruct_t linked-list, and return * the records index. In the event that the record could not be found, 0 will - * be returned. + * be returned. */ int deleteContactRecord(contactToIndexStruct_t **contactRecord,char *contactName) { @@ -137,7 +137,7 @@ int deleteContactRecord(contactToIndexStruct_t **contactRecord,char *contactName while (currentContact != NULL) { - if (strcmp(currentContact->contactName, contactName) == 0) + if (strcmp(currentContact->contactName, contactName) == 0) { /* This means that this is the first element. Link up * the pointer to the next element */ @@ -161,14 +161,14 @@ int deleteContactRecord(contactToIndexStruct_t **contactRecord,char *contactName } -/* +/* * Creates an SNMP row and inserts it into the contact table. This function * should only be called when the interprocess buffer is being consumed. * - * Returns: 1 on success, and 0 otherwise. + * Returns: 1 on success, and 0 otherwise. */ -int createContactRow(int userIndex, int contactIndex, char *contactName, - ucontact_t *contactInfo) +int createContactRow(int userIndex, int contactIndex, char *contactName, + ucontact_t *contactInfo) { openserSIPContactTable_context *theRow; @@ -223,11 +223,11 @@ int createContactRow(int userIndex, int contactIndex, char *contactName, } -/* +/* * Removes the row indexed by userIndex and contactIndex, and free's up the * memory allocated to it. If the row could not be found, then nothing is done. */ -void deleteContactRow(int userIndex, int contactIndex) +void deleteContactRow(int userIndex, int contactIndex) { openserSIPContactTable_context *theRow; @@ -250,7 +250,7 @@ void deleteContactRow(int userIndex, int contactIndex) pkg_free(theRow->openserSIPContactURI); pkg_free(theRow->index.oids); free(theRow); - } + } } /* @@ -299,7 +299,7 @@ void initialize_table_openserSIPContactTable(void) openserSIPContactTable_oid, openserSIPContactTable_oid_len, HANDLER_CAN_RONLY); - + if (!my_handler || !table_info) { snmp_log(LOG_ERR, "malloc failed in initialize_table_openser" "SIPContactTable_handler\n"); @@ -320,12 +320,12 @@ void initialize_table_openserSIPContactTable(void) cb.get_value = openserSIPContactTable_get_value; cb.container = netsnmp_container_find("openserSIPContactTable_primary:" "openserSIPContactTable:" "table_container"); - + DEBUGMSGTL(("initialize_table_openserSIPContactTable", "Registering table openserSIPContactTable " "as a table array\n")); - - netsnmp_table_container_register(my_handler, table_info, &cb, + + netsnmp_table_container_register(my_handler, table_info, &cb, cb.container, 1); } @@ -348,7 +348,7 @@ int openserSIPContactTable_get_value( /* Needs to be large enough to hold the null terminated string "-0.01". */ - char contactPreference[6]; + char contactPreference[6]; float preferenceAsFloat = -1; char *retrievedExpiry; @@ -360,17 +360,17 @@ int openserSIPContactTable_get_value( netsnmp_variable_list *var = request->requestvb; - openserSIPContactTable_context *context = + openserSIPContactTable_context *context = (openserSIPContactTable_context *)item; - switch(table_info->colnum) + switch(table_info->colnum) { case COLUMN_OPENSERSIPCONTACTDISPLAYNAME: /* FIXME: WHERE DO WE FIND THIS?? Setting to the same * thing as contact uri for now. */ - snmp_set_var_typed_value(var, ASN_OCTET_STR, + snmp_set_var_typed_value(var, ASN_OCTET_STR, (unsigned char*) context->openserSIPContactURI, context->openserSIPContactURI_len); @@ -383,14 +383,14 @@ int openserSIPContactTable_get_value( context->openserSIPContactURI, context->openserSIPContactURI_len); break; - + case COLUMN_OPENSERSIPCONTACTLASTUPDATED: - - if (context->contactInfo != NULL) + + if (context->contactInfo != NULL) { - timeValue = + timeValue = localtime(&(context->contactInfo->last_modified)); - retrievedExpiry = + retrievedExpiry = convertTMToSNMPDateAndTime(timeValue); } else { retrievedExpiry = defaultExpiry; @@ -401,15 +401,15 @@ int openserSIPContactTable_get_value( retrievedExpiry, 8); break; - + case COLUMN_OPENSERSIPCONTACTEXPIRY: - if (context->contactInfo != NULL) + if (context->contactInfo != NULL) { - timeValue = + timeValue = localtime(&(context->contactInfo->expires)); - retrievedExpiry = + retrievedExpiry = convertTMToSNMPDateAndTime(timeValue); } else { retrievedExpiry = defaultExpiry; @@ -419,7 +419,7 @@ int openserSIPContactTable_get_value( retrievedExpiry, 8); break; - + case COLUMN_OPENSERSIPCONTACTPREFERENCE: if (context->contactInfo != NULL) { @@ -441,7 +441,7 @@ int openserSIPContactTable_get_value( contactPreference, 5); break; - + default: /** We shouldn't get here */ snmp_log(LOG_ERR, "unknown column in " "openserSIPContactTable_get_value\n"); @@ -451,8 +451,8 @@ int openserSIPContactTable_get_value( return SNMP_ERR_NOERROR; } -/* - * openserSIPContactTable_get_by_idx is an auto-generated function. +/* + * openserSIPContactTable_get_by_idx is an auto-generated function. */ const openserSIPContactTable_context * openserSIPContactTable_get_by_idx(netsnmp_index * hdr) diff --git a/modules/snmpstats/openserSIPContactTable.h b/modules/snmpstats/openserSIPContactTable.h index e29a9c8e15e..dd5e8f12911 100644 --- a/modules/snmpstats/openserSIPContactTable.h +++ b/modules/snmpstats/openserSIPContactTable.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,9 +25,9 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Note: this file was originally auto-generated by mib2c using * mib2c.array-user.conf * @@ -39,29 +39,29 @@ * We require OpenSERs usrloc module to inform us when a contact is * added/removed. The general callback process works as follows: * - * 1) On startup, we register handleContactCallbacks() for USRLOC callbacks, so - * we can be informed whenever a contact is added/removed from the system. - * This registration happens with a call to registerForUSRLOCCallbacks(). + * 1) On startup, we register handleContactCallbacks() for USRLOC callbacks, so + * we can be informed whenever a contact is added/removed from the system. + * This registration happens with a call to registerForUSRLOCCallbacks(). * (This is actually called when the SNMPStats module is initialized) * - * 2) Whenever we receive a contact callback, handleContactCallbacks() will + * 2) Whenever we receive a contact callback, handleContactCallbacks() will * quickly add the contact information and operation type to the - * interprocess buffer. + * interprocess buffer. * * 3) When we receive an SNMP request for user/contact information, we consume * the interprocess buffer with consumeInterprocessBuffer(). The function * will add/delete rows to the tables, and then service the SNMP request. * - * Notes: + * Notes: * * - The interprocess buffer was necessary, because NetSNMP's containers can be * very inefficient at adding large amounts of data at a time, such as when * OpenSIPS first starts up. It was decided its better to make an SNMP manager * wait for data, instead of slowing down the rest of OpenSIPS while the - * sub-agent processes the data. + * sub-agent processes the data. * * - It is important to send periodic SNMP requests to this table (or the user - * table), to make sure the process buffer doesn't get too large. + * table), to make sure the process buffer doesn't get too large. */ #ifndef OPENSERSIPCONTACTTABLE_H @@ -71,7 +71,7 @@ extern "C" { #endif - + #include #include #include @@ -87,7 +87,7 @@ extern "C" { * was done because the values change over time. Therefore we retrieve the data * only when it is requested for, instead of storing stale data. */ -typedef struct openserSIPContactTable_context_s +typedef struct openserSIPContactTable_context_s { netsnmp_index index; /** THIS MUST BE FIRST!!! */ @@ -109,40 +109,40 @@ typedef struct openserSIPContactTable_context_s /* Customized SNMP Prototypes */ /******************************/ -/* +/* * Creates an SNMP row and inserts it into the contact table. This function * should only be called when the interprocess buffer is being consumed. * - * Returns: 1 on success, and 0 otherwise. + * Returns: 1 on success, and 0 otherwise. */ int createContactRow(int userIndex, int contactIndex, char *contactName, ucontact_t *contactInfo); -/* +/* * Removes the row indexed by userIndex and contactIndex, and free's up the * memory allocated to it. If the row could not be found, then nothing is done. */ void deleteContactRow(int userIndex, int contactIndex); -/* +/* * This function adds a new contactToIndexStruct_t record to the front of - * 'contactRecord'. + * 'contactRecord'. * * The structure is used to map a contact name to the SNMPStats modules integer * indexing scheme. It will be used later when a delete command comes in, and * we need to find out which SNMP row the information is stored under. */ -int insertContactRecord(contactToIndexStruct_t **contactRecord, int index, +int insertContactRecord(contactToIndexStruct_t **contactRecord, int index, char *name); /* * This function will remove the contactToIndexStruct_T record matching * 'contactName' from the users contactToIndexStruct_t linked-list, and return * the records index. In the event that the record could not be found, 0 will - * be returned. + * be returned. */ -int deleteContactRecord(contactToIndexStruct_t **contactRecord, +int deleteContactRecord(contactToIndexStruct_t **contactRecord, char *contactName); @@ -185,7 +185,7 @@ extern oid openserSIPContactTable_oid[]; extern size_t openserSIPContactTable_oid_len; #define openserSIPContactTable_TABLE_OID OPENSER_OID,3,1,2,1,5,7 - + /************************************************************* * column number definitions for table openserSIPContactTable */ diff --git a/modules/snmpstats/openserSIPMethodSupportedTable.c b/modules/snmpstats/openserSIPMethodSupportedTable.c index a21284fab88..568f639784f 100644 --- a/modules/snmpstats/openserSIPMethodSupportedTable.c +++ b/modules/snmpstats/openserSIPMethodSupportedTable.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,14 +25,14 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Originally Generated with mib2c using mib2c.array-user.conf * * The file implements the openserSIPMethodSupportedTable. The table is * populated by looking to see which modules are loaded, and guessing what SIP * Methods they provide. It is quite possible that this initial implementation * is not very good at guessing. This should be fixed in future releases as - * more information becomes available. + * more information becomes available. * * For full details, please see the OPENSER-SIP-COMMON-MIB. * @@ -52,10 +52,10 @@ static netsnmp_handler_registration *my_handler = NULL; static netsnmp_table_array_callbacks cb; -oid openserSIPMethodSupportedTable_oid[] = +oid openserSIPMethodSupportedTable_oid[] = { openserSIPMethodSupportedTable_TABLE_OID }; -size_t openserSIPMethodSupportedTable_oid_len = +size_t openserSIPMethodSupportedTable_oid_len = OID_LENGTH(openserSIPMethodSupportedTable_oid); @@ -109,7 +109,7 @@ void createRow(int index, char *stringToRegister) { } -/* Initializes the openserSIPMethodSupportedTable, and populates the tables +/* Initializes the openserSIPMethodSupportedTable, and populates the tables * contents */ void init_openserSIPMethodSupportedTable(void) { @@ -134,11 +134,11 @@ void init_openserSIPMethodSupportedTable(void) * * We should keep these indices fixed. For example if we don't support * METHOD_REGISTER but we do support METHOD_MESSAGE, then METHOD_MESSAGE - * should still be at index 9. + * should still be at index 9. * * NOTE: My way of checking what METHODS we support is probably wrong. * Please feel free to correct it! */ - + if (module_loaded("sl")) { createRow(1, "METHOD_INVITE"); createRow(2, "METHOD_CANCEL"); @@ -191,18 +191,18 @@ void initialize_table_openserSIPMethodSupportedTable(void) /** create the table structure itself */ table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); - my_handler = + my_handler = netsnmp_create_handler_registration( "openserSIPMethodSupportedTable", netsnmp_table_array_helper_handler, openserSIPMethodSupportedTable_oid, openserSIPMethodSupportedTable_oid_len, HANDLER_CAN_RONLY); - + if (!my_handler || !table_info) { snmp_log(LOG_ERR, "malloc failed in initialize_table_openser" "SIPMethodSupportedTable_handler\n"); - return; + return; } netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED); @@ -214,11 +214,11 @@ void initialize_table_openserSIPMethodSupportedTable(void) * registering the table with the master agent */ cb.get_value = openserSIPMethodSupportedTable_get_value; - cb.container = + cb.container = netsnmp_container_find("openserSIPMethodSupportedTable_primary:" "openserSIPMethodSupportedTable:" "table_container"); - - DEBUGMSGTL(("initialize_table_openserSIPMethodSupportedTable", + + DEBUGMSGTL(("initialize_table_openserSIPMethodSupportedTable", "Registering table openserSIPMethodSupportedTable" "as a table array\n")); @@ -227,10 +227,10 @@ void initialize_table_openserSIPMethodSupportedTable(void) } -/* +/* * This routine is called to process get requests for elements of the table. * - * The function is pretty much left as is from the auto-generated code. + * The function is pretty much left as is from the auto-generated code. */ int openserSIPMethodSupportedTable_get_value( netsnmp_request_info *request, @@ -239,10 +239,10 @@ int openserSIPMethodSupportedTable_get_value( { netsnmp_variable_list *var = request->requestvb; - openserSIPMethodSupportedTable_context *context = + openserSIPMethodSupportedTable_context *context = (openserSIPMethodSupportedTable_context *)item; - switch(table_info->colnum) + switch(table_info->colnum) { case COLUMN_OPENSERSIPMETHODNAME: @@ -252,7 +252,7 @@ int openserSIPMethodSupportedTable_get_value( context->openserSIPMethodName, context->openserSIPMethodName_len ); break; - + default: /** We shouldn't get here */ snmp_log(LOG_ERR, "unknown column in openserSIPMethod" "SupportedTable_get_value\n"); diff --git a/modules/snmpstats/openserSIPMethodSupportedTable.h b/modules/snmpstats/openserSIPMethodSupportedTable.h index 7ed962394b1..70960ad44b4 100644 --- a/modules/snmpstats/openserSIPMethodSupportedTable.h +++ b/modules/snmpstats/openserSIPMethodSupportedTable.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,11 +25,11 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Originally Generated with Mib2c using mib2c.array-user.conf. - * + * * This file defines the prototypes used to define the * openserSIPMethodSupportedTable. For full details, please see the * OPENSER-SIP-COMMON-MIB. @@ -42,16 +42,16 @@ extern "C" { #endif - + #include #include #include #include "../../config.h" -/* +/* * This strucutre represents a single row in the SNMP table, and is mostly - * auto-generated. + * auto-generated. */ typedef struct openserSIPMethodSupportedTable_context_s { @@ -62,7 +62,7 @@ typedef struct openserSIPMethodSupportedTable_context_s { /** SnmpAdminString = ASN_OCTET_STR */ unsigned char *openserSIPMethodName; - + long openserSIPMethodName_len; void * data; @@ -70,7 +70,7 @@ typedef struct openserSIPMethodSupportedTable_context_s { } openserSIPMethodSupportedTable_context; -/* Initializes the openserSIPMethodSupportedTable, and populates the tables +/* Initializes the openserSIPMethodSupportedTable, and populates the tables * contents */ void init_openserSIPMethodSupportedTable(void); @@ -78,18 +78,18 @@ void init_openserSIPMethodSupportedTable(void); void initialize_table_openserSIPMethodSupportedTable(void); -/* +/* * This routine is called to process get requests for elements of the table. * - * The function is pretty much left as is from the auto-generated code. + * The function is pretty much left as is from the auto-generated code. */ -int openserSIPMethodSupportedTable_get_value(netsnmp_request_info *, +int openserSIPMethodSupportedTable_get_value(netsnmp_request_info *, netsnmp_index *, netsnmp_table_request_info *); -const openserSIPMethodSupportedTable_context * +const openserSIPMethodSupportedTable_context * openserSIPMethodSupportedTable_get_by_idx(netsnmp_index *); -const openserSIPMethodSupportedTable_context * +const openserSIPMethodSupportedTable_context * openserSIPMethodSupportedTable_get_by_idx_rs(netsnmp_index *, int row_status); @@ -100,7 +100,7 @@ extern oid openserSIPMethodSupportedTable_oid[]; extern size_t openserSIPMethodSupportedTable_oid_len; #define openserSIPMethodSupportedTable_TABLE_OID OPENSER_OID,3,1,1,1,1,7 - + /* * column number definitions for table openserSIPMethodSupportedTable */ diff --git a/modules/snmpstats/openserSIPPortTable.c b/modules/snmpstats/openserSIPPortTable.c index f95cb304b0b..6905e933683 100644 --- a/modules/snmpstats/openserSIPPortTable.c +++ b/modules/snmpstats/openserSIPPortTable.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,7 +25,7 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Originally Generated with mib2c using mib2c.array-user.conf * * This file implements the openserSIPPortTable. For a full description of the table, @@ -57,12 +57,12 @@ size_t openserSIPPortTable_oid_len = OID_LENGTH(openserSIPPortTable_oid); * * ipType.NUM_IP_OCTETS.ipAddress[0].ipAddress[1]...ipAddress[NUM_IP_OCTETS].portNumber * - * sizeOfOID will be assigned the length of the oid. - * + * sizeOfOID will be assigned the length of the oid. + * * Note: This function returns a newly allocated block of memory. Make sure to - * deallocate the memory when you no longer need it. + * deallocate the memory when you no longer need it. */ -oid *createIndex(int ipType, int *ipAddress, int *sizeOfOID) +oid *createIndex(int ipType, int *ipAddress, int *sizeOfOID) { oid *currentOIDIndex; int i; @@ -84,7 +84,7 @@ oid *createIndex(int ipType, int *ipAddress, int *sizeOfOID) /* Assign the OID Index */ currentOIDIndex[0] = ipType; currentOIDIndex[1] = NUM_IP_OCTETS; - + for (i = 0; i < NUM_IP_OCTETS; i++) { currentOIDIndex[i+2] = ipAddress[i]; } @@ -100,9 +100,9 @@ oid *createIndex(int ipType, int *ipAddress, int *sizeOfOID) * return a new one otherwise. If the row is new, then the provided index will be * assigned to the new row. * - * Note: NULL will be returned on an error + * Note: NULL will be returned on an error */ -openserSIPPortTable_context *getRow(int ipType, int *ipAddress) +openserSIPPortTable_context *getRow(int ipType, int *ipAddress) { int lengthOfOID; oid *currentOIDIndex = createIndex(ipType, ipAddress, &lengthOfOID); @@ -121,10 +121,10 @@ openserSIPPortTable_context *getRow(int ipType, int *ipAddress) /* Lets check to see if there is an existing row. */ rowToReturn = CONTAINER_FIND(cb.container, &theIndex); - + /* We found an existing row, so there is no need to create a new one. * Let's return it to the caller. */ - if (rowToReturn != NULL) + if (rowToReturn != NULL) { /* We don't need the index we allocated anymore, because the * existing row already has its own copy, so free the memory */ @@ -132,7 +132,7 @@ openserSIPPortTable_context *getRow(int ipType, int *ipAddress) return rowToReturn; } - + /* If we are here then the row doesn't exist yet. So lets create it. */ rowToReturn = SNMP_MALLOC_TYPEDEF(openserSIPPortTable_context); @@ -161,22 +161,22 @@ openserSIPPortTable_context *getRow(int ipType, int *ipAddress) * can point to any integer >= zero. All rows created by this function will be * indexed starting at snmpIndex++. The parameter is implemented as a pointer * to an integer so that if the function is called again with another - * 'protocol', we can continue from the last index. + * 'protocol', we can continue from the last index. */ -void createRowsFromIPList(int *theList, int listSize, int protocol, +void createRowsFromIPList(int *theList, int listSize, int protocol, int *snmpIndex) { openserSIPPortTable_context *currentRow; - + int curIndexOfIP; int curSocketIdx; int valueToAssign; - if (protocol == PROTO_UDP) + if (protocol == PROTO_UDP) { valueToAssign = TC_TRANSPORT_PROTOCOL_UDP; } - else if (protocol == PROTO_TCP) + else if (protocol == PROTO_TCP) { valueToAssign = TC_TRANSPORT_PROTOCOL_TCP; } @@ -184,16 +184,16 @@ void createRowsFromIPList(int *theList, int listSize, int protocol, { valueToAssign = TC_TRANSPORT_PROTOCOL_TLS; } - else + else { valueToAssign = TC_TRANSPORT_PROTOCOL_OTHER; } - + /* Create all rows with respect to the given protocol */ for (curSocketIdx=0; curSocketIdx < listSize; curSocketIdx++) { curIndexOfIP = (NUM_IP_OCTETS + 1) * curSocketIdx; - + /* Retrieve an existing row, or a new row if one doesn't * allready exist. */ currentRow = getRow(1, &theList[curIndexOfIP]); @@ -210,7 +210,7 @@ void createRowsFromIPList(int *theList, int listSize, int protocol, } /* - * Initializes the openserSIPPortTable module. + * Initializes the openserSIPPortTable module. * * Specifically, this function will define the tables structure, and then * populate it with the ports and transports that OpenSIPS is listening on. @@ -227,9 +227,9 @@ void init_openserSIPPortTable(void) int *TLSList = NULL; int numUDPSockets; - int numTCPSockets; + int numTCPSockets; int numTLSSockets; - + /* Retrieve the list of the number of UDP and TCP sockets. */ numUDPSockets = get_socket_list_from_proto(&UDPList, PROTO_UDP); numTCPSockets = get_socket_list_from_proto(&TCPList, PROTO_TCP); @@ -239,14 +239,14 @@ void init_openserSIPPortTable(void) createRowsFromIPList(UDPList, numUDPSockets, PROTO_UDP, &curSNMPIndex); curSNMPIndex = 0; - + createRowsFromIPList(TCPList, numTCPSockets, PROTO_TCP, &curSNMPIndex); curSNMPIndex = 0; createRowsFromIPList(TLSList, numTLSSockets, PROTO_TLS, &curSNMPIndex); } - + /* Initialize the openserSIPPortTable table by defining how it is structured */ void initialize_table_openserSIPPortTable(void) { @@ -268,7 +268,7 @@ void initialize_table_openserSIPPortTable(void) openserSIPPortTable_oid, openserSIPPortTable_oid_len, HANDLER_CAN_RONLY); - + if (!my_handler || !table_info) { snmp_log(LOG_ERR, "malloc failed in " "initialize_table_openserSIPPortTable_handler\n"); @@ -276,7 +276,7 @@ void initialize_table_openserSIPPortTable(void) } /* Set up the table's structural definition */ - + /* index: openserSIPPortIndex */ netsnmp_table_helper_add_index(table_info, ASN_OCTET_STR); @@ -289,11 +289,11 @@ void initialize_table_openserSIPPortTable(void) "openserSIPPortTable:" "table_container"); - + DEBUGMSGTL(("initialize_table_openserSIPPortTable", "Registering table openserSIPPortTable " "as a table array\n")); - + netsnmp_table_container_register(my_handler, table_info, &cb, cb.container, 1); } @@ -301,20 +301,20 @@ void initialize_table_openserSIPPortTable(void) /* * This routine is called to process get requests for elements of the table. * - * The function is mostly left in its auto-generated form + * The function is mostly left in its auto-generated form */ -int openserSIPPortTable_get_value(netsnmp_request_info *request, +int openserSIPPortTable_get_value(netsnmp_request_info *request, netsnmp_index *item, netsnmp_table_request_info *table_info ) { netsnmp_variable_list *var = request->requestvb; - openserSIPPortTable_context *context = + openserSIPPortTable_context *context = (openserSIPPortTable_context *)item; - switch(table_info->colnum) + switch(table_info->colnum) { - + case COLUMN_OPENSERSIPTRANSPORTRCV: /** OpenSERSIPTransportProtocol = ASN_OCTET_STR */ snmp_set_var_typed_value(var, ASN_OCTET_STR, diff --git a/modules/snmpstats/openserSIPPortTable.h b/modules/snmpstats/openserSIPPortTable.h index d4e09c88eba..f894e7c85ca 100644 --- a/modules/snmpstats/openserSIPPortTable.h +++ b/modules/snmpstats/openserSIPPortTable.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,9 +25,9 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Originally Generated with Mib2c using mib2c.array-user.conf. * * This file defines the openserSIPPortTable prototypes. For a full description @@ -50,11 +50,11 @@ extern "C" { #define SIP_PORT_TABLE_STR_INDEX_SIZE 10 /* This strucutre represents a single row in the table. */ -typedef struct openserSIPPortTable_context_s +typedef struct openserSIPPortTable_context_s { - netsnmp_index index; - + netsnmp_index index; + unsigned char openserSIPStringIndex[SIP_PORT_TABLE_STR_INDEX_SIZE]; unsigned long openserSIPStringIndex_len; @@ -67,7 +67,7 @@ typedef struct openserSIPPortTable_context_s /* - * Initializes the openserSIPPortTable module. + * Initializes the openserSIPPortTable module. * * Specifically, this function will define the tables structure, and then * populate it with the ports and transports that OpenSIPS is listening on. @@ -82,9 +82,9 @@ void initialize_table_openserSIPPortTable(void); /* * This routine is called to process get requests for elements of the table. - * The function is mostly left in its auto-generated form + * The function is mostly left in its auto-generated form */ -int openserSIPPortTable_get_value(netsnmp_request_info *, netsnmp_index *, +int openserSIPPortTable_get_value(netsnmp_request_info *, netsnmp_index *, netsnmp_table_request_info *); const openserSIPPortTable_context * openserSIPPortTable_get_by_idx( @@ -100,7 +100,7 @@ extern oid openserSIPPortTable_oid[]; extern size_t openserSIPPortTable_oid_len; #define openserSIPPortTable_TABLE_OID OPENSER_OID,3,1,1,1,1,5 - + /* * column number definitions for table openserSIPPortTable */ diff --git a/modules/snmpstats/openserSIPRegUserLookupTable.c b/modules/snmpstats/openserSIPRegUserLookupTable.c index 1b2b84e7e97..cae872d6b48 100644 --- a/modules/snmpstats/openserSIPRegUserLookupTable.c +++ b/modules/snmpstats/openserSIPRegUserLookupTable.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,8 +25,8 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * - * Note: this file originally auto-generated by mib2c using + * + * Note: this file originally auto-generated by mib2c using * mib2c.array-user.conf * * This file implements the openserSIPRegUserLookupTable. For a full @@ -40,14 +40,14 @@ * The functions that have been modified to implement this table are the * following: * - * 1) openserSIPRegUserLookupTable_extract_index() + * 1) openserSIPRegUserLookupTable_extract_index() * * - Modified to fail if the index is invalid. The index is invalid if it * does not match up with the global userLookupCounter. * * 2) openserSIPRegUserLookupTable_can_[activate|deactivate|delete]() - * - * - Simplified to always allow activation/deactivation/deletion. + * + * - Simplified to always allow activation/deactivation/deletion. * * 3) openserSIPRegUserLookupTable_set_reserve1() * @@ -61,9 +61,9 @@ * - The function was modified to populate the row with the userIndex of the * supplied URI if that URI was found on the system, and set the rowStatus * to 'active'. If the URI was not found, the rowStatus is set to - * 'notInService' + * 'notInService' * - * You can safely ignore the other functions. + * You can safely ignore the other functions. */ #include @@ -80,17 +80,17 @@ static netsnmp_handler_registration *my_handler = NULL; static netsnmp_table_array_callbacks cb; -oid openserSIPRegUserLookupTable_oid[] = { +oid openserSIPRegUserLookupTable_oid[] = { openserSIPRegUserLookupTable_TABLE_OID }; -size_t openserSIPRegUserLookupTable_oid_len = +size_t openserSIPRegUserLookupTable_oid_len = OID_LENGTH(openserSIPRegUserLookupTable_oid); /* * Initializes the openserSIPRegUserLookupTable table. This step is easier * than in the other tables because there is no table population. All table - * population takes place during run time. + * population takes place during run time. */ void init_openserSIPRegUserLookupTable(void) { @@ -106,8 +106,8 @@ static int openserSIPRegUserLookupTable_row_copy( { return 1; } - - + + /* copy index, if provided */ if(dst->index.oids) { @@ -121,19 +121,19 @@ static int openserSIPRegUserLookupTable_row_copy( } dst->index.len = src->index.len; - + /* Copy out almost all components of the structure. We don't copy out * the openserSIPRegUSerLookupURI (or its length). */ dst->openserSIPRegUserLookupIndex = src->openserSIPRegUserLookupIndex; dst->openserSIPRegUserIndex = src->openserSIPRegUserIndex; - dst->openserSIPRegUserLookupRowStatus = + dst->openserSIPRegUserLookupRowStatus = src->openserSIPRegUserLookupRowStatus; return 0; } /* - * the *_extract_index routine. (Mostly auto-generated) + * the *_extract_index routine. (Mostly auto-generated) * * This routine is called when a set request is received for an index * that was not found in the table container. Here, we parse the oid @@ -148,7 +148,7 @@ static int openserSIPRegUserLookupTable_row_copy( * */ int openserSIPRegUserLookupTable_extract_index( - openserSIPRegUserLookupTable_context * ctx, + openserSIPRegUserLookupTable_context * ctx, netsnmp_index * hdr) { /* @@ -172,7 +172,7 @@ int openserSIPRegUserLookupTable_extract_index( } /* Set up the index */ - memset(&var_openserSIPRegUserLookupIndex, 0x00, + memset(&var_openserSIPRegUserLookupIndex, 0x00, sizeof(var_openserSIPRegUserLookupIndex)); var_openserSIPRegUserLookupIndex.type = ASN_UNSIGNED; @@ -180,21 +180,21 @@ int openserSIPRegUserLookupTable_extract_index( /* parse the oid into the individual index components */ - err = parse_oid_indexes( hdr->oids, hdr->len, + err = parse_oid_indexes( hdr->oids, hdr->len, &var_openserSIPRegUserLookupIndex ); if (err == SNMP_ERR_NOERROR) { - + /* copy index components into the context structure */ - ctx->openserSIPRegUserLookupIndex = + ctx->openserSIPRegUserLookupIndex = *var_openserSIPRegUserLookupIndex.val.integer; - /* + /* * Check to make sure that the index corresponds to the - * global_userLookupCounter, as per the MIB specifications. + * global_userLookupCounter, as per the MIB specifications. */ - if (*var_openserSIPRegUserLookupIndex.val.integer != - global_UserLookupCounter || + if (*var_openserSIPRegUserLookupIndex.val.integer != + global_UserLookupCounter || *var_openserSIPRegUserLookupIndex.val.integer < 1) { err = -1; } @@ -208,10 +208,10 @@ int openserSIPRegUserLookupTable_extract_index( } /* - * This is an auto-generated function. In general the *_can_activate routine + * This is an auto-generated function. In general the *_can_activate routine * is called when a row is changed to determine if all the values set are * consistent with the row's rules for a row status of ACTIVE. If not, then 0 - * can be returned to prevent the row status from becomming final. + * can be returned to prevent the row status from becomming final. * * For our purposes, we have no need for this check, so we always return 1. */ @@ -223,7 +223,7 @@ int openserSIPRegUserLookupTable_can_activate( return 1; } -/* +/* * This is an auto-generated function. In general the *_can_deactivate routine * is called when a row that is currently ACTIVE is set to a state other than * ACTIVE. If there are conditions in which a row should not be allowed to @@ -245,10 +245,10 @@ int openserSIPRegUserLookupTable_can_deactivate( * This is an auto-generated function. In general the *_can_delete routine is * called to determine if a row can be deleted. This usually involved checking * if it can be deactivated, and if it can be, then checking for other - * conditions. + * conditions. * * Since this table ha no reason why row deletion shouldn't be allowed, we - * always return 1, unless we can't deactivate. + * always return 1, unless we can't deactivate. */ int openserSIPRegUserLookupTable_can_delete( openserSIPRegUserLookupTable_context *undo_ctx, @@ -257,20 +257,20 @@ int openserSIPRegUserLookupTable_can_delete( { if(openserSIPRegUserLookupTable_can_deactivate(undo_ctx,row_ctx,rg) != 1) return 0; - + return 1; } /* - * This is an auto-generated function. + * This is an auto-generated function. * * The *_create_row routine is called by the table handler to create a new row * for a given index. This is the first stage of the row creation process. The * *_set_reserve_* functions can be used to prevent the row from being inserted - * into the table even if the row passes any preliminary checks set here. + * into the table even if the row passes any preliminary checks set here. * * Returns a newly allocated openserSIPRegUserLookupTable_context structure (a - * row in the table) if the indexes are legal. NULL will be returned otherwise. + * row in the table) if the indexes are legal. NULL will be returned otherwise. */ openserSIPRegUserLookupTable_context * openserSIPRegUserLookupTable_create_row( netsnmp_index* hdr) @@ -278,17 +278,17 @@ openserSIPRegUserLookupTable_create_row( netsnmp_index* hdr) openserSIPRegUserLookupTable_context * ctx = SNMP_MALLOC_TYPEDEF(openserSIPRegUserLookupTable_context); - if (!ctx) + if (!ctx) { return NULL; } - - /* + + /* * Extract the index. The function has been modified from its original * auto-generated version in that the function will fail if index is - * somehow invalid. + * somehow invalid. */ - if(openserSIPRegUserLookupTable_extract_index( ctx, hdr )) + if(openserSIPRegUserLookupTable_extract_index( ctx, hdr )) { if (NULL != ctx->index.oids) @@ -309,11 +309,11 @@ openserSIPRegUserLookupTable_create_row( netsnmp_index* hdr) return ctx; } -/* +/* * Auto-generated function. The *_duplicate row routine */ openserSIPRegUserLookupTable_context * -openserSIPRegUserLookupTable_duplicate_row( +openserSIPRegUserLookupTable_duplicate_row( openserSIPRegUserLookupTable_context * row_ctx) { openserSIPRegUserLookupTable_context * dup; @@ -324,7 +324,7 @@ openserSIPRegUserLookupTable_duplicate_row( dup = SNMP_MALLOC_TYPEDEF(openserSIPRegUserLookupTable_context); if(!dup) return NULL; - + if(openserSIPRegUserLookupTable_row_copy(dup,row_ctx)) { free(dup); dup = NULL; @@ -333,12 +333,12 @@ openserSIPRegUserLookupTable_duplicate_row( return dup; } -/* +/* * The *_delete_row method is auto-generated, and is called to delete a row. * * This will not be called if earlier checks said that this row can't be * deleted. However, in our implementation there is never a reason why this - * function can't be called. + * function can't be called. */ netsnmp_index * openserSIPRegUserLookupTable_delete_row( openserSIPRegUserLookupTable_context * ctx ) @@ -349,7 +349,7 @@ netsnmp_index * openserSIPRegUserLookupTable_delete_row( } - if (ctx->openserSIPRegUserLookupURI != NULL) + if (ctx->openserSIPRegUserLookupURI != NULL) { pkg_free(ctx->openserSIPRegUserLookupURI); } @@ -364,20 +364,20 @@ netsnmp_index * openserSIPRegUserLookupTable_delete_row( * Large parts of this function have been auto-generated. The functions purpose * is to check to make sure all SNMP set values for the given row, have been * valid. If not, then the process is supposed to be aborted. Otherwise, we - * pass on to the *_reserve2 function. + * pass on to the *_reserve2 function. * * For our purposes, our only check is to make sure that either of the following - * conditions are true: + * conditions are true: * * 1) If this row already exists, then the SET request is setting the rowStatus * column to 'destroy'. * - * 2) If this row does not already exist, then the SET request is setting the - * rowStatus to 'createAndGo'. + * 2) If this row does not already exist, then the SET request is setting the + * rowStatus to 'createAndGo'. * * Since the MIB specified there are to be no other modifications to the row, * any other condition is considered illegal, and will result in an SNMP error - * being returned. + * being returned. */ void openserSIPRegUserLookupTable_set_reserve1( netsnmp_request_group *rg ) { @@ -395,19 +395,19 @@ void openserSIPRegUserLookupTable_set_reserve1( netsnmp_request_group *rg ) var = current->ri->requestvb; rc = SNMP_ERR_NOERROR; - switch(current->tri->colnum) + switch(current->tri->colnum) { case COLUMN_OPENSERSIPREGUSERLOOKUPURI: if (row_ctx->openserSIPRegUserLookupRowStatus == 0 || - row_ctx->openserSIPRegUserLookupRowStatus == + row_ctx->openserSIPRegUserLookupRowStatus == TC_ROWSTATUS_NOTREADY) { } else { rc = SNMP_ERR_BADVALUE; } - + break; case COLUMN_OPENSERSIPREGUSERLOOKUPROWSTATUS: @@ -416,24 +416,24 @@ void openserSIPRegUserLookupTable_set_reserve1( netsnmp_request_group *rg ) rc = netsnmp_check_vb_type_and_size(var, ASN_INTEGER, sizeof( row_ctx->openserSIPRegUserLookupRowStatus)); - + /* Want to make sure that if it already exists that it * is setting it to 'destroy', or if it doesn't exist, * that it is setting it to 'createAndGo' */ - if (row_ctx->openserSIPRegUserLookupRowStatus == 0 && - *var->val.integer != TC_ROWSTATUS_CREATEANDGO) + if (row_ctx->openserSIPRegUserLookupRowStatus == 0 && + *var->val.integer != TC_ROWSTATUS_CREATEANDGO) { rc = SNMP_ERR_BADVALUE; - } - + } + else if (row_ctx->openserSIPRegUserLookupRowStatus == - TC_ROWSTATUS_ACTIVE && - *var->val.integer != - TC_ROWSTATUS_DESTROY) + TC_ROWSTATUS_ACTIVE && + *var->val.integer != + TC_ROWSTATUS_DESTROY) { rc = SNMP_ERR_BADVALUE; } - + break; default: /** We shouldn't get here */ @@ -442,7 +442,7 @@ void openserSIPRegUserLookupTable_set_reserve1( netsnmp_request_group *rg ) "UserLookupTable_set_reserve1\n"); } - if (rc) + if (rc) { netsnmp_set_mode_request_error( MODE_SET_BEGIN, current->ri, rc ); @@ -460,36 +460,33 @@ void openserSIPRegUserLookupTable_set_reserve1( netsnmp_request_group *rg ) */ void openserSIPRegUserLookupTable_set_reserve2( netsnmp_request_group *rg ) { - openserSIPRegUserLookupTable_context *undo_ctx = + openserSIPRegUserLookupTable_context *undo_ctx = (openserSIPRegUserLookupTable_context *)rg->undo_info; netsnmp_request_group_item *current; - netsnmp_variable_list *var; - int rc; rg->rg_void = rg->list->ri; for( current = rg->list; current; current = current->next ) { - var = current->ri->requestvb; rc = SNMP_ERR_NOERROR; - switch(current->tri->colnum) + switch(current->tri->colnum) { case COLUMN_OPENSERSIPREGUSERLOOKUPURI: break; case COLUMN_OPENSERSIPREGUSERLOOKUPROWSTATUS: - + /** RowStatus = ASN_INTEGER */ rc = netsnmp_check_vb_rowstatus(current->ri->requestvb, - undo_ctx ? + undo_ctx ? undo_ctx->openserSIPRegUserLookupRowStatus:0); rg->rg_void = current->ri; - + break; default: /** We shouldn't get here */ @@ -507,7 +504,7 @@ void openserSIPRegUserLookupTable_set_reserve2( netsnmp_request_group *rg ) /* * This function is called only when all the *_reserve[1|2] functions were * succeful. Its purpose is to make any changes to the row before it is - * inserted into the table. + * inserted into the table. * * In the case of this table, this involves looking up the index of the * requested user in the URI to userIndex mapping hash table. If the result is @@ -517,7 +514,7 @@ void openserSIPRegUserLookupTable_set_reserve2( netsnmp_request_group *rg ) * All other handling is auto-generated. */ void openserSIPRegUserLookupTable_set_action( netsnmp_request_group *rg ) -{ +{ /* First things first, we need to consume the interprocess buffer, in * case something has changed. We want to return the freshest data. */ consumeInterprocessBuffer(); @@ -526,10 +523,10 @@ void openserSIPRegUserLookupTable_set_action( netsnmp_request_group *rg ) netsnmp_variable_list *var; - openserSIPRegUserLookupTable_context *row_ctx = + openserSIPRegUserLookupTable_context *row_ctx = (openserSIPRegUserLookupTable_context *)rg->existing_row; - openserSIPRegUserLookupTable_context *undo_ctx = + openserSIPRegUserLookupTable_context *undo_ctx = (openserSIPRegUserLookupTable_context *)rg->undo_info; netsnmp_request_group_item *current; @@ -541,47 +538,47 @@ void openserSIPRegUserLookupTable_set_action( netsnmp_request_group *rg ) var = current->ri->requestvb; - switch(current->tri->colnum) + switch(current->tri->colnum) { case COLUMN_OPENSERSIPREGUSERLOOKUPURI: - row_ctx->openserSIPRegUserLookupURI = + row_ctx->openserSIPRegUserLookupURI = pkg_malloc(sizeof(char)*(var->val_len + 1)); memcpy(row_ctx->openserSIPRegUserLookupURI, var->val.string, var->val_len); - + /* Usually NetSNMP won't terminate strings with '\0'. * The hash function expect them to be terminated * though, so we have to add this on to the end. The +1 * in the malloc makes sure of the extra space for us. - */ + */ row_ctx->openserSIPRegUserLookupURI[var->val_len] = '\0'; row_ctx->openserSIPRegUserLookupURI_len = var->val_len; - + /* Do the lookup. If we could find the record, then set * the index and the row status to active. Otherwise, * set the row to notInService */ - hashRecord = - findHashRecord(hashTable, + hashRecord = + findHashRecord(hashTable, (char *) row_ctx->openserSIPRegUserLookupURI, HASH_SIZE); - if (hashRecord == NULL) + if (hashRecord == NULL) { - row_ctx->openserSIPRegUserIndex = 0; - row_ctx->openserSIPRegUserLookupRowStatus = + row_ctx->openserSIPRegUserIndex = 0; + row_ctx->openserSIPRegUserLookupRowStatus = TC_ROWSTATUS_NOTINSERVICE; - } - else + } + else { - row_ctx->openserSIPRegUserIndex = + row_ctx->openserSIPRegUserIndex = hashRecord->userIndex; - row_ctx->openserSIPRegUserLookupRowStatus = + row_ctx->openserSIPRegUserLookupRowStatus = TC_ROWSTATUS_ACTIVE; } @@ -589,22 +586,22 @@ void openserSIPRegUserLookupTable_set_action( netsnmp_request_group *rg ) case COLUMN_OPENSERSIPREGUSERLOOKUPROWSTATUS: - row_ctx->openserSIPRegUserLookupRowStatus = + row_ctx->openserSIPRegUserLookupRowStatus = *var->val.integer; - if (*var->val.integer == TC_ROWSTATUS_CREATEANDGO) + if (*var->val.integer == TC_ROWSTATUS_CREATEANDGO) { rg->row_created = 1; /* Set to NOT READY until the lookup URI has * been supplied. */ row_ctx->openserSIPRegUserLookupRowStatus = - TC_ROWSTATUS_NOTREADY; + TC_ROWSTATUS_NOTREADY; } - else if (*var->val.integer == TC_ROWSTATUS_DESTROY) + else if (*var->val.integer == TC_ROWSTATUS_DESTROY) { rg->row_deleted = 1; } - else + else { /* We should never be here, because the RESERVE * functions should have taken care of all other @@ -659,7 +656,7 @@ void openserSIPRegUserLookupTable_set_commit( netsnmp_request_group *rg ) * This function is called if the *_reserve[1|2] calls failed. Its supposed to * free up any resources allocated earlier. However, we already take care of * all these resources in earlier functions. So for our purposes, the function - * body is empty. + * body is empty. */ void openserSIPRegUserLookupTable_set_free( netsnmp_request_group *rg ) { @@ -667,10 +664,10 @@ void openserSIPRegUserLookupTable_set_free( netsnmp_request_group *rg ) } -/* +/* * This function is called if an ACTION phase fails, to do extra clean-up work. * We don't have anything complicated enough to warrant putting anything in this - * function. Therefore, its just left with an empty function body. + * function. Therefore, its just left with an empty function body. */ void openserSIPRegUserLookupTable_set_undo( netsnmp_request_group *rg ) { @@ -680,7 +677,7 @@ void openserSIPRegUserLookupTable_set_undo( netsnmp_request_group *rg ) /* * Initialize the openserSIPRegUserLookupTable table by defining how it is - * structured. + * structured. * * This function is mostly auto-generated. */ @@ -705,7 +702,7 @@ void initialize_table_openserSIPRegUserLookupTable(void) openserSIPRegUserLookupTable_oid, openserSIPRegUserLookupTable_oid_len, HANDLER_CAN_RWRITE); - + if (!my_handler || !table_info) { snmp_log(LOG_ERR, "malloc failed in " "initialize_table_openserSIPRegUserLookup" @@ -732,13 +729,13 @@ void initialize_table_openserSIPRegUserLookupTable(void) "table_container"); cb.can_set = 1; - cb.create_row = + cb.create_row = (UserRowMethod*)openserSIPRegUserLookupTable_create_row; - cb.duplicate_row = + cb.duplicate_row = (UserRowMethod*)openserSIPRegUserLookupTable_duplicate_row; - cb.delete_row = + cb.delete_row = (UserRowMethod*)openserSIPRegUserLookupTable_delete_row; - cb.row_copy = + cb.row_copy = (Netsnmp_User_Row_Operation *) openserSIPRegUserLookupTable_row_copy; @@ -759,14 +756,14 @@ void initialize_table_openserSIPRegUserLookupTable(void) DEBUGMSGTL(("initialize_table_openserSIPRegUserLookupTable", "Registering table openserSIPRegUserLookupTable " "as a table array\n")); - - netsnmp_table_container_register(my_handler, table_info, &cb, + + netsnmp_table_container_register(my_handler, table_info, &cb, cb.container, 1); } -/* +/* * This function was auto-generated and didn't need modifications from its - * auto-generation. It is called to handle an SNMP GET request. + * auto-generation. It is called to handle an SNMP GET request. */ int openserSIPRegUserLookupTable_get_value( netsnmp_request_info *request, @@ -778,16 +775,16 @@ int openserSIPRegUserLookupTable_get_value( openserSIPRegUserLookupTable_context *context = (openserSIPRegUserLookupTable_context *)item; - switch(table_info->colnum) + switch(table_info->colnum) { case COLUMN_OPENSERSIPREGUSERLOOKUPURI: /** SnmpAdminString = ASN_OCTET_STR */ - snmp_set_var_typed_value(var, ASN_OCTET_STR, + snmp_set_var_typed_value(var, ASN_OCTET_STR, (unsigned char*) context->openserSIPRegUserLookupURI, context->openserSIPRegUserLookupURI_len); break; - + case COLUMN_OPENSERSIPREGUSERINDEX: /** UNSIGNED32 = ASN_UNSIGNED */ snmp_set_var_typed_value(var, ASN_UNSIGNED, @@ -795,7 +792,7 @@ int openserSIPRegUserLookupTable_get_value( &context->openserSIPRegUserIndex, sizeof(context->openserSIPRegUserIndex)); break; - + case COLUMN_OPENSERSIPREGUSERLOOKUPROWSTATUS: /** RowStatus = ASN_INTEGER */ snmp_set_var_typed_value(var, ASN_INTEGER, @@ -804,7 +801,7 @@ int openserSIPRegUserLookupTable_get_value( sizeof( context->openserSIPRegUserLookupRowStatus)); break; - + default: /** We shouldn't get here */ snmp_log(LOG_ERR, "unknown column in " "openserSIPRegUserLookupTable_get_value\n"); diff --git a/modules/snmpstats/openserSIPRegUserLookupTable.h b/modules/snmpstats/openserSIPRegUserLookupTable.h index f478488bcf2..5a14fb16f84 100644 --- a/modules/snmpstats/openserSIPRegUserLookupTable.h +++ b/modules/snmpstats/openserSIPRegUserLookupTable.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,22 +25,22 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * - * Note: this file originally auto-generated by mib2c using + * + * Note: this file originally auto-generated by mib2c using * mib2c.array-user.conf, * * This file implements the openserSIPRegUserLookupTable. For a full * description of the table, please see the OPENSER-SIP-SERVER-MIB. * - * This file consists of many more functions than the other header files. + * This file consists of many more functions than the other header files. * This is because this table is writable, bringing a lot of SNMP overhead. * * Most of the contents are auto-generated (aside from white space and comment * changes), and can be ignored. The functions that have been modified are: * - * 1) openserSIPRegUserLookupTable_extract_index() + * 1) openserSIPRegUserLookupTable_extract_index() * * 2) openserSIPRegUserLookupTable_can_[activate|deactivate|delete]() * @@ -49,7 +49,7 @@ * 4) openserSIPRegUserLookupTable_set_action() * * Full details can be found in openserSIPRegUserLookupTable.c. You can safely - * ignore the other functions. + * ignore the other functions. */ #ifndef OPENSERSIPREGUSERLOOKUPTABLE_H @@ -59,7 +59,7 @@ extern "C" { #endif - + #include #include #include @@ -68,9 +68,9 @@ extern "C" { /* This structure represnts a row in the table */ -typedef struct openserSIPRegUserLookupTable_context_s +typedef struct openserSIPRegUserLookupTable_context_s { - netsnmp_index index; + netsnmp_index index; /** UNSIGNED32 = ASN_UNSIGNED */ unsigned long openserSIPRegUserLookupIndex; @@ -92,32 +92,32 @@ typedef struct openserSIPRegUserLookupTable_context_s /* * Initializes the openserSIPRegUserLookupTable table. This step is easier * than in the other tables because there is no table population. All table - * population takes place during run time. + * population takes place during run time. */ void init_openserSIPRegUserLookupTable(void); /* * Initialize the openserSIPRegUserLookupTable table by defining how it is - * structured. + * structured. * * This function is mostly auto-generated. */ void initialize_table_openserSIPRegUserLookupTable(void); -/* +/* * This function was auto-generated and didn't need modifications from its - * auto-generation. It is called to handle an SNMP GET request. + * auto-generation. It is called to handle an SNMP GET request. */ -int openserSIPRegUserLookupTable_get_value(netsnmp_request_info *, +int openserSIPRegUserLookupTable_get_value(netsnmp_request_info *, netsnmp_index *, netsnmp_table_request_info *); -const openserSIPRegUserLookupTable_context * +const openserSIPRegUserLookupTable_context * openserSIPRegUserLookupTable_get_by_idx(netsnmp_index *); -const openserSIPRegUserLookupTable_context * +const openserSIPRegUserLookupTable_context * openserSIPRegUserLookupTable_get_by_idx_rs( - netsnmp_index *, + netsnmp_index *, int row_status); /* oid declarations */ @@ -139,7 +139,7 @@ extern size_t openserSIPRegUserLookupTable_oid_len; /* Handles index extraction for row creation */ -int openserSIPRegUserLookupTable_extract_index( +int openserSIPRegUserLookupTable_extract_index( openserSIPRegUserLookupTable_context *ctx, netsnmp_index *hdr); /* Handle RESERVE1 and RESERVE2 phases of an SNMP SET */ @@ -155,14 +155,14 @@ void openserSIPRegUserLookupTable_set_commit(netsnmp_request_group *); void openserSIPRegUserLookupTable_set_free(netsnmp_request_group *); void openserSIPRegUserLookupTable_set_undo(netsnmp_request_group *); -openserSIPRegUserLookupTable_context * +openserSIPRegUserLookupTable_context * openserSIPRegUserLookupTable_duplicate_row( openserSIPRegUserLookupTable_context*); netsnmp_index * openserSIPRegUserLookupTable_delete_row( openserSIPRegUserLookupTable_context*); -/* Used to check if there is a reason why a row can't be activated +/* Used to check if there is a reason why a row can't be activated * (There is no reason in our implementation) */ int openserSIPRegUserLookupTable_can_activate( @@ -170,7 +170,7 @@ int openserSIPRegUserLookupTable_can_activate( openserSIPRegUserLookupTable_context *row_ctx, netsnmp_request_group * rg); -/* Used to check if there is a reason why a row can't be deactivated +/* Used to check if there is a reason why a row can't be deactivated * (There is no reason in our implementation) */ int openserSIPRegUserLookupTable_can_deactivate( @@ -185,7 +185,7 @@ int openserSIPRegUserLookupTable_can_delete( openserSIPRegUserLookupTable_context *undo_ctx, openserSIPRegUserLookupTable_context *row_ctx, netsnmp_request_group * rg); - + /* Basic structural setups of the new row */ openserSIPRegUserLookupTable_context * openserSIPRegUserLookupTable_create_row( netsnmp_index*); diff --git a/modules/snmpstats/openserSIPRegUserTable.c b/modules/snmpstats/openserSIPRegUserTable.c index eda12b30d87..3859d93ebb7 100644 --- a/modules/snmpstats/openserSIPRegUserTable.c +++ b/modules/snmpstats/openserSIPRegUserTable.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -41,7 +41,7 @@ * * 2) We need a quick way of mapping usrloc indices to our integer indices. For * this reason a string indexed Hash Table was created, with each entry mapping - * to an integer user index. + * to an integer user index. * * This hash table is used by the openserSIPContactTable (the hash table also * maps a user to its contacts), as well as the openserSIPRegUserLookupTable. @@ -54,19 +54,19 @@ * process. Specifically: * * - It can take a long time for the NetSNMP code base to populate a table with - * a large number of records. + * a large number of records. * - * - We rely on callbacks for updated user information. + * - We rely on callbacks for updated user information. * * Clearly, using the SNMPStats module in this situation could lead to some * big performance loses if we don't find another way to deal with this. The - * solution was to use an interprocess communications buffer. + * solution was to use an interprocess communications buffer. * * Instead of adding the record directly to the table, the callback functions * now adds either an add/delete command to the interprocessBuffer. When an * snmp request is recieved by the SNMPStats sub-process, it will consume * this interprocess buffer, adding and deleting users. When it is finished, - * it can service the SNMP request. + * it can service the SNMP request. * * This doesn't remove the NetSNMP inefficiency, but instead moves it to a * non-critical path. Such an approach allows SNMP support with almost no @@ -101,7 +101,7 @@ size_t openserSIPRegUserTable_oid_len = OID_LENGTH(openserSIPRegUserTable_oid); * callback for UL_CONTACT_INSERT and UL_CONTACT_EXPIRE. * * Returns 1 on success, and zero otherwise. */ -int registerForUSRLOCCallbacks(void) +int registerForUSRLOCCallbacks(void) { bind_usrloc_t bind_usrloc; usrloc_api_t ul; @@ -119,9 +119,9 @@ int registerForUSRLOCCallbacks(void) } ul.register_ulcb(UL_CONTACT_INSERT, handleContactCallbacks, NULL); - + ul.register_ulcb(UL_CONTACT_EXPIRE, handleContactCallbacks, NULL); - + ul.register_ulcb(UL_CONTACT_DELETE, handleContactCallbacks, NULL); return 1; @@ -136,14 +136,14 @@ int registerForUSRLOCCallbacks(void) /* Removes an SNMP row indexed by userIndex, and frees the string and index it * pointed to. */ -void deleteRegUserRow(int userIndex) +void deleteRegUserRow(int userIndex) { - + openserSIPRegUserTable_context *theRow; netsnmp_index indexToRemove; oid indexToRemoveOID; - + indexToRemoveOID = userIndex; indexToRemove.oids = &indexToRemoveOID; indexToRemove.len = 1; @@ -166,22 +166,22 @@ void deleteRegUserRow(int userIndex) * Adds or updates a user: * * - If a user with the name userName exists, its 'number of contacts' count - * will be incremented. + * will be incremented. * - If the user doesn't exist, the user will be added to the table, and its - * number of contacts' count set to 1. + * number of contacts' count set to 1. */ -void updateUser(char *userName) +void updateUser(char *userName) { - int userIndex; + int userIndex; aorToIndexStruct_t *newRecord; - aorToIndexStruct_t *existingRecord = + aorToIndexStruct_t *existingRecord = findHashRecord(hashTable, userName, HASH_SIZE); /* We found an existing record, so we need to update its 'number of * contacts' count. */ - if (existingRecord != NULL) + if (existingRecord != NULL) { existingRecord->numContacts++; return; @@ -191,7 +191,7 @@ void updateUser(char *userName) * structures */ userIndex = createRegUserRow(userName); - if (userIndex == 0) + if (userIndex == 0) { LM_ERR("openserSIPRegUserTable ran out of memory." " Not able to add user: %s", userName); @@ -199,7 +199,7 @@ void updateUser(char *userName) } newRecord = createHashRecord(userIndex, userName); - + /* If we couldn't create a record in the hash table, then we won't be * able to access this row properly later. So remove the row from the * table and fail. */ @@ -209,26 +209,26 @@ void updateUser(char *userName) " User not added to this table\n", userName); return; } - + /* Insert the new record of the mapping data structure into the hash * table */ /*insertHashRecord(hashTable, - createHashRecord(userIndex, userName), + createHashRecord(userIndex, userName), HASH_SIZE);*/ - + insertHashRecord(hashTable, - newRecord, + newRecord, HASH_SIZE); } -/* Creates a row and inserts it. +/* Creates a row and inserts it. * * Returns: The rows userIndex on success, and 0 otherwise. */ -int createRegUserRow(char *stringToRegister) +int createRegUserRow(char *stringToRegister) { int static index = 0; - + index++; openserSIPRegUserTable_context *theRow; @@ -269,7 +269,7 @@ int createRegUserRow(char *stringToRegister) } memcpy(theRow->openserSIPUserUri, stringToRegister, stringLength); - + theRow->openserSIPUserUri_len = stringLength; theRow->openserSIPUserAuthenticationFailures = 0; @@ -287,7 +287,7 @@ void init_openserSIPRegUserTable(void) /* We need to create a default row, so create DefaultUser */ static char *defaultUser = "DefaultUser"; - + createRegUserRow(defaultUser); } @@ -312,10 +312,10 @@ void initialize_table_openserSIPRegUserTable(void) /* create the table structure itself */ table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); - my_handler = + my_handler = netsnmp_create_handler_registration( "openserSIPRegUserTable", - netsnmp_table_array_helper_handler, + netsnmp_table_array_helper_handler, openserSIPRegUserTable_oid, openserSIPRegUserTable_oid_len, HANDLER_CAN_RONLY); @@ -339,7 +339,7 @@ void initialize_table_openserSIPRegUserTable(void) "Registering table openserSIPRegUserTable " "as a table array\n")); - netsnmp_table_container_register(my_handler, table_info, &cb, + netsnmp_table_container_register(my_handler, table_info, &cb, cb.container, 1); } @@ -356,10 +356,10 @@ int openserSIPRegUserTable_get_value( netsnmp_variable_list *var = request->requestvb; - openserSIPRegUserTable_context *context = + openserSIPRegUserTable_context *context = (openserSIPRegUserTable_context *)item; - switch(table_info->colnum) + switch(table_info->colnum) { case COLUMN_OPENSERSIPUSERURI: @@ -368,7 +368,7 @@ int openserSIPRegUserTable_get_value( (unsigned char*)context->openserSIPUserUri, context->openserSIPUserUri_len ); break; - + case COLUMN_OPENSERSIPUSERAUTHENTICATIONFAILURES: /** COUNTER = ASN_COUNTER */ snmp_set_var_typed_value(var, ASN_COUNTER, @@ -377,7 +377,7 @@ int openserSIPRegUserTable_get_value( sizeof( context->openserSIPUserAuthenticationFailures)); break; - + default: /** We shouldn't get here */ snmp_log(LOG_ERR, "unknown column in " "openserSIPRegUserTable_get_value\n"); diff --git a/modules/snmpstats/openserSIPRegUserTable.h b/modules/snmpstats/openserSIPRegUserTable.h index dc03df16213..efbbbed6769 100644 --- a/modules/snmpstats/openserSIPRegUserTable.h +++ b/modules/snmpstats/openserSIPRegUserTable.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,9 +25,9 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * mib2c.array-user.conf * @@ -43,7 +43,7 @@ * * 2) We need a quick way of mapping usrloc indices to our integer indices. For * this reason a string indexed Hash Table was created, with each entry mapping - * to an integer user index. + * to an integer user index. * * This hash table is used by the openserSIPContactTable (the hash table also * maps a user to its contacts), as well as the openserSIPRegUserLookupTable. @@ -56,19 +56,19 @@ * process. Specifically: * * - It can take a long time for the NetSNMP code base to populate a table with - * a large number of records. + * a large number of records. * - * - We rely on callbacks for updated user information. + * - We rely on callbacks for updated user information. * * Clearly, using the SNMPStats module in this situation could lead to some * big performance loses if we don't find another way to deal with this. The - * solution was to use an interprocess communications buffer. + * solution was to use an interprocess communications buffer. * * Instead of adding the record directly to the table, the callback functions * now adds either an add/delete command to the interprocessBuffer. When an * snmp request is recieved by the SNMPStats sub-process, it will consume * this interprocess buffer, adding and deleting users. When it is finished, - * it can service the SNMP request. + * it can service the SNMP request. * * This doesn't remove the NetSNMP inefficiency, but instead moves it to a * non-critical path. Such an approach allows SNMP support with almost no @@ -89,9 +89,9 @@ extern "C" { #include "../../config.h" /* Defines what each SNMP Row is made of. */ -typedef struct openserSIPRegUserTable_context_s +typedef struct openserSIPRegUserTable_context_s { - netsnmp_index index; + netsnmp_index index; unsigned long openserSIPUserIndex; @@ -114,15 +114,15 @@ typedef struct openserSIPRegUserTable_context_s /* If the usrloc module is loaded, this function will grab hooks into its * callback registration function, and add handleContactCallbacks() as the - * callback for UL_CONTACT_INSERT and UL_CONTACT_EXPIRE. + * callback for UL_CONTACT_INSERT and UL_CONTACT_EXPIRE. * * Returns 1 on success, and zero otherwise */ int registerForUSRLOCCallbacks(); /* - * Creates a row and inserts it. + * Creates a row and inserts it. * - * Returns: The rows userIndex on success, and 0 otherwise. + * Returns: The rows userIndex on success, and 0 otherwise. */ int createRegUserRow(char *stringToRegister); @@ -139,9 +139,9 @@ void pushUserIntoHashTable(int userIndex, char *stringName); * Adds or updates a user: * * - If a user with the name userName exists, its 'number of contacts' count - * will be incremented. + * will be incremented. * - If the user doesn't exist, the user will be added to the table, and its - * number of contacts' count set to 1. + * number of contacts' count set to 1. */ void updateUser(char *userName); @@ -166,8 +166,8 @@ const openserSIPRegUserTable_context * openserSIPRegUserTable_get_by_idx_rs( /* Handles SNMP GET requests. */ int openserSIPRegUserTable_get_value( - netsnmp_request_info *, - netsnmp_index *, + netsnmp_request_info *, + netsnmp_index *, netsnmp_table_request_info *); /* OID Declarations. */ @@ -175,7 +175,7 @@ extern oid openserSIPRegUserTable_oid[]; extern size_t openserSIPRegUserTable_oid_len; #define openserSIPRegUserTable_TABLE_OID OPENSER_OID,3,1,2,1,5,6 - + /* Column Definitions */ #define COLUMN_OPENSERSIPUSERINDEX 1 #define COLUMN_OPENSERSIPUSERURI 2 diff --git a/modules/snmpstats/openserSIPServerObjects.c b/modules/snmpstats/openserSIPServerObjects.c index 7578c425fe8..9975eee85c4 100644 --- a/modules/snmpstats/openserSIPServerObjects.c +++ b/modules/snmpstats/openserSIPServerObjects.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,9 +25,9 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * : mib2c.scalar.conf,v 1.9 2005/01/07 09:37:18 dts12 Exp $ * @@ -55,7 +55,7 @@ unsigned int global_UserLookupCounter; -/* Initializes the openserSIPServerObjects module. This involves: +/* Initializes the openserSIPServerObjects module. This involves: * * - Registering all OID's * - Setting up handlers for all OID's @@ -196,7 +196,7 @@ int handle_openserSIPProxyStatefulness(netsnmp_mib_handler *handler, { int statefullness; - if (module_loaded("dialog")) + if (module_loaded("dialog")) { statefullness = PROXY_STATEFULNESS_CALL_STATEFUL; } @@ -232,7 +232,7 @@ int handle_openserSIPProxyRecordRoute(netsnmp_mib_handler *handler, { supportRecordRoute = TC_TRUE; } - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) &supportRecordRoute, sizeof(int)); @@ -250,12 +250,12 @@ int handle_openserSIPProxyAuthMethod(netsnmp_mib_handler *handler, /* The result needs to be returned as an SNMP bit field. */ unsigned int auth_bitfield = SIP_AUTH_METHOD_NONE; - + if (module_loaded("tls")) { auth_bitfield |= SIP_AUTH_METHOD_TLS; auth_bitfield &= ~SIP_AUTH_METHOD_NONE; } - + /* We can have both tls and auth loaded simultaneously. Therefore we * use an if instead of a else/else-if. */ if (module_loaded("auth")) { @@ -277,8 +277,8 @@ int handle_openserSIPNumProxyRequireFailures(netsnmp_mib_handler *handler, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { - int result = get_statistic("bad_msg_hdr"); - + int result = get_statistic("bad_msg_hdr"); + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); @@ -294,7 +294,7 @@ int handle_openserSIPRegMaxContactExpiryDuration(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int result = get_statistic("max_expires"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) &result, sizeof(int)); @@ -313,8 +313,8 @@ int handle_openserSIPRegMaxUsers(netsnmp_mib_handler *handler, /* OpenSER doesn't currently have a parameterized maximum number of * users. So we return the maximum value an unsigned32 SNMP datatype * can hold. */ - unsigned int result = 0xffffffff; - + unsigned int result = 0xffffffff; + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) &result, sizeof(unsigned int)); @@ -332,7 +332,7 @@ int handle_openserSIPRegCurrentUsers(netsnmp_mib_handler *handler, int max_users = 0; max_users = get_statistic("registered_users"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &max_users, sizeof(int)); @@ -348,7 +348,7 @@ int handle_openserSIPRegDfltRegActiveInterval(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int result = get_statistic("default_expire"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) &result, sizeof(int)); @@ -368,7 +368,7 @@ int handle_openserSIPRegUserLookupCounter(netsnmp_mib_handler *handler, /* If we have had so many requests that we've hit our maximum index, * then we reset our counter back to 1. For this not to cause problems, - * it will be required that old rows belonging to the table + * it will be required that old rows belonging to the table * openserSIPRegUserLookupTable are eventually deleted. */ if (global_UserLookupCounter > MAX_USER_LOOKUP_COUNTER) { global_UserLookupCounter = 1; @@ -389,7 +389,7 @@ int handle_openserSIPRegAcceptedRegistrations(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int result = get_statistic("accepted_regs"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); @@ -405,7 +405,7 @@ int handle_openserSIPRegRejectedRegistrations(netsnmp_mib_handler *handler, netsnmp_request_info *requests) { int result = get_statistic("rejected_regs"); - + if (reqinfo->mode==MODE_GET) { snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &result, sizeof(int)); diff --git a/modules/snmpstats/openserSIPServerObjects.h b/modules/snmpstats/openserSIPServerObjects.h index 517cfb3602f..9b0fcf74440 100644 --- a/modules/snmpstats/openserSIPServerObjects.h +++ b/modules/snmpstats/openserSIPServerObjects.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,11 +25,11 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * : mib2c.scalar.conf,v 1.9 2005/01/07 09:37:18 dts12 Exp $ * - * This file implements all scalars defined in the OPENSER-SIP-SERVER-MIB. + * This file implements all scalars defined in the OPENSER-SIP-SERVER-MIB. * For a full description of the scalars, please see OPENSER-SIP-SERVER-MIB. * */ diff --git a/modules/snmpstats/openserSIPStatusCodesTable.c b/modules/snmpstats/openserSIPStatusCodesTable.c index 77553da3690..6335b47f05a 100644 --- a/modules/snmpstats/openserSIPStatusCodesTable.c +++ b/modules/snmpstats/openserSIPStatusCodesTable.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -31,7 +31,7 @@ * * The file implements the openserSIPStatusCodesTable. For a full description * of the table, please see the OPENSER-SIP-COMMON-MIB. - * + * * This file is much larger and more complicated than the files for other * tables. This is because the table is settable, bringing a lot of SNMP * overhead. Most of the file consists of the original auto-generated @@ -44,17 +44,17 @@ * * - The row structure has been modified from its default to store the * number of messages that have been recieved and sent with a certain - * status code, at the time this row was created. This function - * populates that data. + * status code, at the time this row was created. This function + * populates that data. * - * 2) openserSIPStatusCodesTable_extract_index() + * 2) openserSIPStatusCodesTable_extract_index() * * - Modified to fail if the index is invalid. The index is invalid if it * does not match up with the global userLookupCounter. * * 3) openserSIPStatusCodesTable_can_[activate|deactivate|delete]() - * - * - Simplified to always allow activation/deactivation/deletion. + * + * - Simplified to always allow activation/deactivation/deletion. * * 4) openserSIPStatusCodesTable_set_reserve1() * @@ -67,12 +67,12 @@ * 5) openserSIPStatusCodesTable_get_value() * * - Instead of returning a variable binding to either - * openserSIPStatusCodeIns or openserSIPStatusCodeOuts, the function - * returns a variable binding equal to the current value as per the + * openserSIPStatusCodeIns or openserSIPStatusCodeOuts, the function + * returns a variable binding equal to the current value as per the * statistics framework, minus either openserSIPStatusCodeIns or * openserSIPStatusCodeOuts * - * You can safely ignore the other functions. + * You can safely ignore the other functions. * */ @@ -88,17 +88,17 @@ static netsnmp_handler_registration *my_handler = NULL; static netsnmp_table_array_callbacks cb; -oid openserSIPStatusCodesTable_oid[] = { +oid openserSIPStatusCodesTable_oid[] = { openserSIPStatusCodesTable_TABLE_OID }; -size_t openserSIPStatusCodesTable_oid_len = +size_t openserSIPStatusCodesTable_oid_len = OID_LENGTH(openserSIPStatusCodesTable_oid); -/* +/* * Initializes the openserSIPStatusCodesTable module. This step is easier * than in the other tables because there is no table population. All table - * population takes place during run time. + * population takes place during run time. */ void init_openserSIPStatusCodesTable(void) { @@ -113,23 +113,23 @@ static int openserSIPStatusCodesTable_row_copy( { if(!dst||!src) return 1; - - + + /* copy index, if provided */ if(dst->index.oids) { free(dst->index.oids); } - if(snmp_clone_mem( (void*)&dst->index.oids, src->index.oids, - src->index.len * sizeof(oid) )) + if(snmp_clone_mem( (void*)&dst->index.oids, src->index.oids, + src->index.len * sizeof(oid) )) { dst->index.oids = NULL; return 1; } dst->index.len = src->index.len; - + /* copy components into the context structure */ dst->openserSIPStatusCodeMethod = src->openserSIPStatusCodeMethod; @@ -144,16 +144,16 @@ static int openserSIPStatusCodesTable_row_copy( /* * the *_extract_index routine (Mostly auto-generated) * - * This routine is called when a set request is received for an index that + * This routine is called when a set request is received for an index that * was not found in the table container. Here, we parse the oid in the - * individual index components and copy those indexes to the context. Then + * individual index components and copy those indexes to the context. Then * we make sure the indexes for the new row are valid. * * It has been modified from its original form in that the indexes aren't - * returned if they are invalid. An index is invalid if it is not between + * returned if they are invalid. An index is invalid if it is not between * 100 and 699 (Inclusive). */ -int openserSIPStatusCodesTable_extract_index( +int openserSIPStatusCodesTable_extract_index( openserSIPStatusCodesTable_context * ctx, netsnmp_index * hdr) { @@ -172,11 +172,11 @@ int openserSIPStatusCodesTable_extract_index( */ if(hdr) { netsnmp_assert(ctx->index.oids == NULL); - if((hdr->len > MAX_OID_LEN) || - snmp_clone_mem( + if((hdr->len > MAX_OID_LEN) || + snmp_clone_mem( (void*)&ctx->index.oids, hdr->oids, - hdr->len * sizeof(oid))) + hdr->len * sizeof(oid))) { return -1; } @@ -186,33 +186,33 @@ int openserSIPStatusCodesTable_extract_index( /* Initialize the two variables responsible for holding our two indices. */ - memset(&var_openserSIPStatusCodeMethod, 0x00, + memset(&var_openserSIPStatusCodeMethod, 0x00, sizeof(var_openserSIPStatusCodeMethod)); - memset( &var_openserSIPStatusCodeValue, 0x00, + memset( &var_openserSIPStatusCodeValue, 0x00, sizeof(var_openserSIPStatusCodeValue) ); - var_openserSIPStatusCodeMethod.type = ASN_UNSIGNED; + var_openserSIPStatusCodeMethod.type = ASN_UNSIGNED; var_openserSIPStatusCodeValue.type = ASN_UNSIGNED; - var_openserSIPStatusCodeMethod.next_variable = + var_openserSIPStatusCodeMethod.next_variable = &var_openserSIPStatusCodeValue; var_openserSIPStatusCodeValue.next_variable = NULL; /* parse the oid into the individual index components */ - err = parse_oid_indexes( hdr->oids, hdr->len, + err = parse_oid_indexes( hdr->oids, hdr->len, &var_openserSIPStatusCodeMethod ); if (err == SNMP_ERR_NOERROR) { /* copy index components into the context structure */ - ctx->openserSIPStatusCodeMethod = + ctx->openserSIPStatusCodeMethod = *var_openserSIPStatusCodeMethod.val.integer; - ctx->openserSIPStatusCodeValue = + ctx->openserSIPStatusCodeValue = *var_openserSIPStatusCodeValue.val.integer; - - + + if (*var_openserSIPStatusCodeMethod.val.integer < 1) { err = -1; @@ -225,7 +225,7 @@ int openserSIPStatusCodesTable_extract_index( } - + /* parsing may have allocated memory. free it. */ snmp_reset_var_buffers( &var_openserSIPStatusCodeMethod ); @@ -234,10 +234,10 @@ int openserSIPStatusCodesTable_extract_index( /* - * This is an auto-generated function. In general the *_can_activate routine + * This is an auto-generated function. In general the *_can_activate routine * is called when a row is changed to determine if all the values set are * consistent with the row's rules for a row status of ACTIVE. If not, then 0 - * can be returned to prevent the row status from becomming final. + * can be returned to prevent the row status from becomming final. * * For our purposes, we have no need for this check, so we always return 1. */ @@ -250,7 +250,7 @@ int openserSIPStatusCodesTable_can_activate( } -/* +/* * This is an auto-generated function. In general the *_can_deactivate routine * is called when a row that is currently ACTIVE is set to a state other than * ACTIVE. If there are conditions in which a row should not be allowed to @@ -273,10 +273,10 @@ int openserSIPStatusCodesTable_can_deactivate( * This is an auto-generated function. In general the *_can_delete routine is * called to determine if a row can be deleted. This usually involved checking * if it can be deactivated, and if it can be, then checking for other - * conditions. + * conditions. * * Since this table ha no reason why row deletion shouldn't be allowed, we - * always return 1, unless we can't deactivate. + * always return 1, unless we can't deactivate. */ int openserSIPStatusCodesTable_can_delete( openserSIPStatusCodesTable_context *undo_ctx, @@ -285,17 +285,17 @@ int openserSIPStatusCodesTable_can_delete( { if(openserSIPStatusCodesTable_can_deactivate(undo_ctx,row_ctx,rg) != 1) return 0; - + return 1; } /* - * (Mostly auto-generated function) + * (Mostly auto-generated function) * * The *_create_row routine is called by the table handler to create a new row * for a given index. This is the first stage of the row creation process. The * *_set_reserve_* functions can be used to prevent the row from being inserted - * into the table even if the row passes any preliminary checks set here. + * into the table even if the row passes any preliminary checks set here. * * Returns a newly allocated openserSIPRegUserLookupTable_context structure (a * row in the table) if the indexes are legal. NULL will be returned otherwise. @@ -303,10 +303,10 @@ int openserSIPStatusCodesTable_can_delete( * The function has been modified from its original form, in that it will store * the number of messages 'in' to the system, and the number of messages 'out' * of the system, that had a status code matching this rows status code, at the - * time this row was created. + * time this row was created. * * This value will be used in the future to calculate the delta between now and - * the time this row has been read. + * the time this row has been read. * */ openserSIPStatusCodesTable_context * openserSIPStatusCodesTable_create_row( netsnmp_index* hdr) @@ -318,7 +318,7 @@ openserSIPStatusCodesTable_create_row( netsnmp_index* hdr) SNMP_MALLOC_TYPEDEF(openserSIPStatusCodesTable_context); if(!ctx) return NULL; - + /* The *_extract_index funtion already validates the indices, so we * don't need to do any further evaluations here. */ if(openserSIPStatusCodesTable_extract_index( ctx, hdr )) { @@ -346,12 +346,12 @@ openserSIPStatusCodesTable_create_row( netsnmp_index* hdr) in_status_code = get_stat_var_from_num_code(codeIndex, 0); out_status_code = get_stat_var_from_num_code(codeIndex, 1); - if (in_status_code != NULL) + if (in_status_code != NULL) { ctx->startingInStatusCodeValue = *(long *)in_status_code->u.val; } - if (out_status_code != NULL) + if (out_status_code != NULL) { ctx->startingOutStatusCodeValue = *(long *)out_status_code->u.val; } @@ -360,11 +360,11 @@ openserSIPStatusCodesTable_create_row( netsnmp_index* hdr) } -/* +/* * Auto-generated function. The *_duplicate row routine */ openserSIPStatusCodesTable_context * -openserSIPStatusCodesTable_duplicate_row( +openserSIPStatusCodesTable_duplicate_row( openserSIPStatusCodesTable_context * row_ctx) { openserSIPStatusCodesTable_context * dup; @@ -375,7 +375,7 @@ openserSIPStatusCodesTable_duplicate_row( dup = SNMP_MALLOC_TYPEDEF(openserSIPStatusCodesTable_context); if(!dup) return NULL; - + if(openserSIPStatusCodesTable_row_copy(dup,row_ctx)) { free(dup); dup = NULL; @@ -385,14 +385,14 @@ openserSIPStatusCodesTable_duplicate_row( } -/* +/* * The *_delete_row method is auto-generated, and is called to delete a row. * * This will not be called if earlier checks said that this row can't be * deleted. However, in our implementation there is never a reason why this - * function can't be called. + * function can't be called. */ -netsnmp_index * openserSIPStatusCodesTable_delete_row( +netsnmp_index * openserSIPStatusCodesTable_delete_row( openserSIPStatusCodesTable_context * ctx ) { if(ctx->index.oids) @@ -408,20 +408,20 @@ netsnmp_index * openserSIPStatusCodesTable_delete_row( * Large parts of this function have been auto-generated. The functions purpose * is to check to make sure all SNMP set values for the given row, have been * valid. If not, then the process is supposed to be aborted. Otherwise, we - * pass on to the *_reserve2 function. + * pass on to the *_reserve2 function. * * For our purposes, our only check is to make sure that either of the following - * conditions are true: + * conditions are true: * * 1) If this row already exists, then the SET request is setting the rowStatus * column to 'destroy'. * - * 2) If this row does not already exist, then the SET request is setting the - * rowStatus to 'createAndGo'. + * 2) If this row does not already exist, then the SET request is setting the + * rowStatus to 'createAndGo'. * * Since the MIB specified there are to be no other modifications to the row, * any other condition is considered illegal, and will result in an SNMP error - * being returned. + * being returned. */ void openserSIPStatusCodesTable_set_reserve1( netsnmp_request_group *rg ) { @@ -440,33 +440,33 @@ void openserSIPStatusCodesTable_set_reserve1( netsnmp_request_group *rg ) var = current->ri->requestvb; rc = SNMP_ERR_NOERROR; - switch(current->tri->colnum) + switch(current->tri->colnum) { case COLUMN_OPENSERSIPSTATUSCODEROWSTATUS: /** RowStatus = ASN_INTEGER */ - rc = netsnmp_check_vb_type_and_size(var, + rc = netsnmp_check_vb_type_and_size(var, ASN_INTEGER, sizeof( row_ctx->openserSIPStatusCodeRowStatus)); - + /* Want to make sure that if it already exists that it * is setting it to 'destroy', or if it doesn't exist, * that it is setting it to 'createAndGo' */ - if (row_ctx->openserSIPStatusCodeRowStatus == 0 && - *var->val.integer != TC_ROWSTATUS_CREATEANDGO) + if (row_ctx->openserSIPStatusCodeRowStatus == 0 && + *var->val.integer != TC_ROWSTATUS_CREATEANDGO) { rc = SNMP_ERR_BADVALUE; - } + } else if (row_ctx->openserSIPStatusCodeRowStatus == - TC_ROWSTATUS_ACTIVE && - *var->val.integer != - TC_ROWSTATUS_DESTROY) + TC_ROWSTATUS_ACTIVE && + *var->val.integer != + TC_ROWSTATUS_DESTROY) { rc = SNMP_ERR_BADVALUE; } - + break; @@ -478,7 +478,7 @@ void openserSIPStatusCodesTable_set_reserve1( netsnmp_request_group *rg ) if (rc) { - netsnmp_set_mode_request_error(MODE_SET_BEGIN, + netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc ); } @@ -494,11 +494,10 @@ void openserSIPStatusCodesTable_set_reserve1( netsnmp_request_group *rg ) */ void openserSIPStatusCodesTable_set_reserve2( netsnmp_request_group *rg ) { - openserSIPStatusCodesTable_context *undo_ctx = + openserSIPStatusCodesTable_context *undo_ctx = (openserSIPStatusCodesTable_context *)rg->undo_info; netsnmp_request_group_item *current; - netsnmp_variable_list *var; int rc; @@ -506,16 +505,15 @@ void openserSIPStatusCodesTable_set_reserve2( netsnmp_request_group *rg ) for( current = rg->list; current; current = current->next ) { - var = current->ri->requestvb; rc = SNMP_ERR_NOERROR; - switch(current->tri->colnum) + switch(current->tri->colnum) { case COLUMN_OPENSERSIPSTATUSCODEROWSTATUS: /** RowStatus = ASN_INTEGER */ rc = netsnmp_check_vb_rowstatus(current->ri->requestvb, - undo_ctx ? + undo_ctx ? undo_ctx->openserSIPStatusCodeRowStatus:0); rg->rg_void = current->ri; @@ -527,7 +525,7 @@ void openserSIPStatusCodesTable_set_reserve2( netsnmp_request_group *rg ) if (rc) { - netsnmp_set_mode_request_error(MODE_SET_BEGIN, + netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc); } } @@ -537,19 +535,19 @@ void openserSIPStatusCodesTable_set_reserve2( netsnmp_request_group *rg ) /* * This function is called only when all the *_reserve[1|2] functions were * succeful. Its purpose is to make any changes to the row before it is - * inserted into the table. + * inserted into the table. * * In our case, we don't require any changes. So we leave the original - * auto-generated code as is. + * auto-generated code as is. */ void openserSIPStatusCodesTable_set_action( netsnmp_request_group *rg ) { netsnmp_variable_list *var; - openserSIPStatusCodesTable_context *row_ctx = + openserSIPStatusCodesTable_context *row_ctx = (openserSIPStatusCodesTable_context *)rg->existing_row; - openserSIPStatusCodesTable_context *undo_ctx = + openserSIPStatusCodesTable_context *undo_ctx = (openserSIPStatusCodesTable_context *)rg->undo_info; netsnmp_request_group_item *current; @@ -558,16 +556,16 @@ void openserSIPStatusCodesTable_set_action( netsnmp_request_group *rg ) /* Depending on what the snmpset was, set the row to be created or * deleted. */ - for( current = rg->list; current; current = current->next ) + for( current = rg->list; current; current = current->next ) { var = current->ri->requestvb; - switch(current->tri->colnum) + switch(current->tri->colnum) { case COLUMN_OPENSERSIPSTATUSCODEROWSTATUS: - + /** RowStatus = ASN_INTEGER */ - row_ctx->openserSIPStatusCodeRowStatus = + row_ctx->openserSIPStatusCodeRowStatus = *var->val.integer; if (*var->val.integer == TC_ROWSTATUS_CREATEANDGO) @@ -598,7 +596,7 @@ void openserSIPStatusCodesTable_set_action( netsnmp_request_group *rg ) */ #ifndef openserSIPStatusCodesTable_CAN_MODIFY_ACTIVE_ROW if( undo_ctx && RS_IS_ACTIVE(undo_ctx->openserSIPStatusCodeRowStatus) && - row_ctx && RS_IS_ACTIVE(row_ctx->openserSIPStatusCodeRowStatus)) + row_ctx && RS_IS_ACTIVE(row_ctx->openserSIPStatusCodeRowStatus)) { row_err = 1; } @@ -607,10 +605,10 @@ void openserSIPStatusCodesTable_set_action( netsnmp_request_group *rg ) /* * check activation/deactivation */ - row_err = netsnmp_table_array_check_row_status(&cb, rg, - row_ctx ? + row_err = netsnmp_table_array_check_row_status(&cb, rg, + row_ctx ? &row_ctx->openserSIPStatusCodeRowStatus : NULL, - undo_ctx ? + undo_ctx ? &undo_ctx->openserSIPStatusCodeRowStatus : NULL); if(row_err) { netsnmp_set_mode_request_error(MODE_SET_BEGIN, @@ -635,7 +633,7 @@ void openserSIPStatusCodesTable_set_commit( netsnmp_request_group *rg ) * This function is called if the *_reserve[1|2] calls failed. Its supposed to * free up any resources allocated earlier. However, we already take care of * all these resources in earlier functions. So for our purposes, the function - * body is empty. + * body is empty. */ void openserSIPStatusCodesTable_set_free( netsnmp_request_group *rg ) { @@ -643,10 +641,10 @@ void openserSIPStatusCodesTable_set_free( netsnmp_request_group *rg ) } -/* +/* * This function is called if an ACTION phase fails, to do extra clean-up work. * We don't have anything complicated enough to warrant putting anything in this - * function. Therefore, its just left with an empty function body. + * function. Therefore, its just left with an empty function body. */ void openserSIPStatusCodesTable_set_undo( netsnmp_request_group *rg ) { @@ -657,7 +655,7 @@ void openserSIPStatusCodesTable_set_undo( netsnmp_request_group *rg ) /* * Initialize the openserSIPStatusCodesTable table by defining how it is - * structured. + * structured. * * This function is mostly auto-generated. */ @@ -682,7 +680,7 @@ void initialize_table_openserSIPStatusCodesTable(void) openserSIPStatusCodesTable_oid, openserSIPStatusCodesTable_oid_len, HANDLER_CAN_RWRITE); - + if (!my_handler || !table_info) { snmp_log(LOG_ERR, "malloc failed in initialize_table_openserSIP" "StatusCodesTable_handler\n"); @@ -702,7 +700,7 @@ void initialize_table_openserSIPStatusCodesTable(void) */ cb.get_value = openserSIPStatusCodesTable_get_value; - cb.container = + cb.container = netsnmp_container_find("openserSIPStatusCodesTable_primary:" "openserSIPStatusCodesTable:" "table_container"); @@ -721,10 +719,10 @@ void initialize_table_openserSIPStatusCodesTable(void) cb.create_row = (UserRowMethod*)openserSIPStatusCodesTable_create_row; - cb.duplicate_row = + cb.duplicate_row = (UserRowMethod*)openserSIPStatusCodesTable_duplicate_row; - cb.delete_row = + cb.delete_row = (UserRowMethod*)openserSIPStatusCodesTable_delete_row; cb.row_copy = (Netsnmp_User_Row_Operation *) @@ -736,38 +734,38 @@ void initialize_table_openserSIPStatusCodesTable(void) cb.can_deactivate = (Netsnmp_User_Row_Action *) openserSIPStatusCodesTable_can_deactivate; - cb.can_delete = + cb.can_delete = (Netsnmp_User_Row_Action *)openserSIPStatusCodesTable_can_delete; cb.set_reserve1 = openserSIPStatusCodesTable_set_reserve1; cb.set_reserve2 = openserSIPStatusCodesTable_set_reserve2; - + cb.set_action = openserSIPStatusCodesTable_set_action; cb.set_commit = openserSIPStatusCodesTable_set_commit; - + cb.set_free = openserSIPStatusCodesTable_set_free; cb.set_undo = openserSIPStatusCodesTable_set_undo; - + DEBUGMSGTL(("initialize_table_openserSIPStatusCodesTable", "Registering table openserSIPStatusCodesTable " "as a table array\n")); - + netsnmp_table_container_register(my_handler, table_info, &cb, cb.container, 1); } /* - * This function is called to handle SNMP GET requests. + * This function is called to handle SNMP GET requests. * * The row which this function is called with, will store a message code. The * function will retrieve the 'number of messages in' and 'number of messages * out' statistic for this particular message code from the statistics - * framework. + * framework. * * The function will then subtract from this value the value it was initialized * with when the row was first created. In this sense, the row shows how many * ins and how many outs have been received (With respect to the message code) - * since this row was created. + * since this row was created. */ int openserSIPStatusCodesTable_get_value( netsnmp_request_info *request, @@ -778,14 +776,14 @@ int openserSIPStatusCodesTable_get_value( netsnmp_variable_list *var = request->requestvb; - openserSIPStatusCodesTable_context *context = + openserSIPStatusCodesTable_context *context = (openserSIPStatusCodesTable_context *)item; /* Retrieve the statusCodeIdx so we can calculate deltas between current * values and previous values. */ int statusCodeIdx = context->openserSIPStatusCodeValue; - switch(table_info->colnum) + switch(table_info->colnum) { case COLUMN_OPENSERSIPSTATUSCODEINS: @@ -793,11 +791,11 @@ int openserSIPStatusCodesTable_get_value( the_stat = get_stat_var_from_num_code(statusCodeIdx, 0); - if (the_stat != NULL) + if (the_stat != NULL) { /* Calculate the Delta */ context->openserSIPStatusCodeIns = - *(long *)the_stat->u.val - + *(long *)the_stat->u.val - context->startingInStatusCodeValue; } @@ -806,9 +804,9 @@ int openserSIPStatusCodesTable_get_value( &context->openserSIPStatusCodeIns, sizeof(context->openserSIPStatusCodeIns)); break; - + case COLUMN_OPENSERSIPSTATUSCODEOUTS: - + context->openserSIPStatusCodeOuts = 0; the_stat = get_stat_var_from_num_code(statusCodeIdx, 1); @@ -817,7 +815,7 @@ int openserSIPStatusCodesTable_get_value( { /* Calculate the Delta */ context->openserSIPStatusCodeOuts = - *(long *)the_stat->u.val - + *(long *)the_stat->u.val - context->startingOutStatusCodeValue; } snmp_set_var_typed_value(var, ASN_COUNTER, @@ -825,7 +823,7 @@ int openserSIPStatusCodesTable_get_value( &context->openserSIPStatusCodeOuts, sizeof(context->openserSIPStatusCodeOuts) ); break; - + case COLUMN_OPENSERSIPSTATUSCODEROWSTATUS: /** RowStatus = ASN_INTEGER */ snmp_set_var_typed_value(var, ASN_INTEGER, @@ -833,7 +831,7 @@ int openserSIPStatusCodesTable_get_value( &context->openserSIPStatusCodeRowStatus, sizeof(context->openserSIPStatusCodeRowStatus) ); break; - + default: /** We shouldn't get here */ snmp_log(LOG_ERR, "unknown column in " "openserSIPStatusCodesTable_get_value\n"); diff --git a/modules/snmpstats/openserSIPStatusCodesTable.h b/modules/snmpstats/openserSIPStatusCodesTable.h index ac609d01db4..b5291e01bb3 100644 --- a/modules/snmpstats/openserSIPStatusCodesTable.h +++ b/modules/snmpstats/openserSIPStatusCodesTable.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,16 +25,16 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * 2007-02-16 Moved all OID registrations from the experimental branch to + * 2007-02-16 Moved all OID registrations from the experimental branch to * OpenSER's IANA assigned enterprise branch. (jmagder) - * + * * Note: this file originally auto-generated by mib2c using * mib2c.array-user.conf * * The file implements the openserSIPStatusCodesTable. For a full description * of the table, please see the OPENSER-SIP-COMMON-MIB. * - * This file consists of many more functions than the other header files. + * This file consists of many more functions than the other header files. * This is because this table is writable, bringing a lot of SNMP overhead. * * Most of the contents are auto-generated (aside from white space and comment @@ -42,10 +42,10 @@ * * 1) openserSIPStatusCodesTable_create_row() * - * 2) openserSIPStatusCodesTable_extract_index() + * 2) openserSIPStatusCodesTable_extract_index() * * 3) openserSIPStatusCodesTable_can_[activate|deactivate|delete]() - * + * * 4) openserSIPStatusCodesTable_set_reserve1() * * 5) openserSIPStatusCodesTable_get_value() @@ -62,22 +62,22 @@ extern "C" { #endif - + #include #include #include #include "../../config.h" -/* +/* * The structure has been mostly auto-generated, but its semantics have been - * changed. + * changed. * * Specifically, the openserSIPStatusCodeIns and openserSIPStatusCodeOuts * variables don't store the total number of messages sent or received from the * system at the time of a SNMP GET request. Instead, they store the number of * messages in or out (with respect to the message code specified by - * openserSIPStatusCodeValue) at the time of the rows *creation*. + * openserSIPStatusCodeValue) at the time of the rows *creation*. * * When the get request is received, the statistics framework will be queried, * and these values subtracted from that query. This effectively gives us how @@ -85,26 +85,26 @@ extern "C" { * insead of since OpenSIPS first loaded up. */ typedef struct openserSIPStatusCodesTable_context_s { - + /* The container interface requires that this be first. */ - netsnmp_index index; + netsnmp_index index; /* The first index. */ unsigned long openserSIPStatusCodeMethod; - + /* The second index, specifying which status code to monitor */ unsigned long openserSIPStatusCodeValue; - /* Stores the current status code value - startingInStatusCodeValue + /* Stores the current status code value - startingInStatusCodeValue * (at the time this row was created) */ unsigned long openserSIPStatusCodeIns; - /* Stores the current status code value - startingOutStatusCodeValue + /* Stores the current status code value - startingOutStatusCodeValue * (at the time this row was created) */ unsigned long openserSIPStatusCodeOuts; /* Initialized to zero at startup to signify uninitialized. This can - * only be assigned createAndGo(4) at this point. It can also be + * only be assigned createAndGo(4) at this point. It can also be * assigned destroy(6), but only if the value is in the active(1) state. */ long openserSIPStatusCodeRowStatus; @@ -117,42 +117,42 @@ typedef struct openserSIPStatusCodesTable_context_s { } openserSIPStatusCodesTable_context; -/* +/* * Initializes the openserSIPStatusCodesTable module. This step is easier * than in the other tables because there is no table population. All table - * population takes place during run time. + * population takes place during run time. */ void init_openserSIPStatusCodesTable(void); /* * Initialize the openserSIPStatusCodesTable table by defining how it is - * structured. + * structured. * * This function is mostly auto-generated. */ void initialize_table_openserSIPStatusCodesTable(void); /* - * This function is called to handle SNMP GET requests. + * This function is called to handle SNMP GET requests. * * The row which this function is called with, will store a message code. The * function will retrieve the 'number of messages in' and 'number of messages * out' statistic for this particular message code from the statistics - * framework. + * framework. * * The function will then subtract from this value the value it was initialized * with when the row was first created. In this sense, the row shows how many * ins and how many outs have been received (With respect to the message code) - * since this row was created. + * since this row was created. */ -int openserSIPStatusCodesTable_get_value(netsnmp_request_info *, +int openserSIPStatusCodesTable_get_value(netsnmp_request_info *, netsnmp_index *, netsnmp_table_request_info *); -const openserSIPStatusCodesTable_context * +const openserSIPStatusCodesTable_context * openserSIPStatusCodesTable_get_by_idx(netsnmp_index *); -const openserSIPStatusCodesTable_context * - openserSIPStatusCodesTable_get_by_idx_rs(netsnmp_index *, +const openserSIPStatusCodesTable_context * + openserSIPStatusCodesTable_get_by_idx_rs(netsnmp_index *, int row_status); /* oid declarations */ @@ -160,7 +160,7 @@ extern oid openserSIPStatusCodesTable_oid[]; extern size_t openserSIPStatusCodesTable_oid_len; #define openserSIPStatusCodesTable_TABLE_OID OPENSER_OID,3,1,1,1,5,1 - + /* column number definitions for table openserSIPStatusCodesTable */ #define COLUMN_OPENSERSIPSTATUSCODEMETHOD 1 #define COLUMN_OPENSERSIPSTATUSCODEVALUE 2 @@ -172,7 +172,7 @@ extern size_t openserSIPStatusCodesTable_oid_len; #define openserSIPStatusCodesTable_COL_MAX 5 /* Handles index extraction for row creation */ -int openserSIPStatusCodesTable_extract_index( +int openserSIPStatusCodesTable_extract_index( openserSIPStatusCodesTable_context * ctx, netsnmp_index * hdr ); /* Handle RESERVE1 and RESERVE2 phases of an SNMP SET */ @@ -192,10 +192,10 @@ openserSIPStatusCodesTable_context * openserSIPStatusCodesTable_duplicate_row( openserSIPStatusCodesTable_context* ); -netsnmp_index * openserSIPStatusCodesTable_delete_row( +netsnmp_index * openserSIPStatusCodesTable_delete_row( openserSIPStatusCodesTable_context* ); -/* Used to check if there is a reason why a row can't be activated +/* Used to check if there is a reason why a row can't be activated * (There is no reason in our implementation) */ int openserSIPStatusCodesTable_can_activate( @@ -203,7 +203,7 @@ int openserSIPStatusCodesTable_can_activate( openserSIPStatusCodesTable_context *row_ctx, netsnmp_request_group * rg); -/* Used to check if there is a reason why a row can't be deactivated +/* Used to check if there is a reason why a row can't be deactivated * (There is no reason in our implementation) */ int openserSIPStatusCodesTable_can_deactivate( @@ -218,9 +218,9 @@ int openserSIPStatusCodesTable_can_delete( openserSIPStatusCodesTable_context *undo_ctx, openserSIPStatusCodesTable_context *row_ctx, netsnmp_request_group * rg); - - -openserSIPStatusCodesTable_context * + + +openserSIPStatusCodesTable_context * openserSIPStatusCodesTable_create_row( netsnmp_index* ); diff --git a/modules/snmpstats/snmpstats.c b/modules/snmpstats/snmpstats.c index 4118794ee6b..aaf6ac6e6c9 100644 --- a/modules/snmpstats/snmpstats.c +++ b/modules/snmpstats/snmpstats.c @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,14 +25,14 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * There are some important points to understanding the SNMPStat modules * architecture. * * 1) The SNMPStats module will fork off a new process in mod_child_init when * the rank is equal to PROC_MAIN_PROCESS. The sub-process will be * responsible for registering with a master agent (the source of snmp - * requests), and handling all received requests. + * requests), and handling all received requests. * * 2) The Module will register a periodic alarm checking function with a sip * timer using register_timer(). This function checks for alarm conditions, @@ -44,7 +44,7 @@ * spawning a short-lived process. For this reason, the module temporarily * installs a new SIGCHLD handler to deal specifically with this process. It * does not change the normal SIGCHLD behaviour for any process except for - * this short lived sysUpTime process. + * this short lived sysUpTime process. * * 4) mod_init() will initialize some interprocess communication buffers, as * well as callback mechanisms for the usrloc module. To understand what the @@ -82,11 +82,11 @@ /* Required in every OpenSIPS Module. */ -/* +/* * The module will fork off a child process to run an snmp command via execve(). * We need a customized handler to ignore the SIGCHLD when the execve() * finishes. We keep around the child process's pid for the customized - * handler. + * handler. * * Specifically, If the process that generated the SIGCHLD doesn't match this * pid, we call OpenSER's default handlers. Otherwise, we just ignore SIGCHLD. @@ -102,7 +102,7 @@ static int spawn_sysUpTime_child(); char *snmpget_path = NULL; char *snmp_community = NULL; -/* +/* * This module replaces the default SIGCHLD handler with our own, as explained * in the documentation for sysUpTime_pid above. This structure holds the old * handler so we can call and restore OpenSER's usual handler when appropriate @@ -110,36 +110,36 @@ char *snmp_community = NULL; static struct sigaction old_sigchld_handler; /* The following message codes are from Wikipedia at: - * - * http://en.wikipedia.org/wiki/SIP_Responses + * + * http://en.wikipedia.org/wiki/SIP_Responses * * If there are more message codes added at a later time, they should be added - * here, and to out_message_code_names below. + * here, and to out_message_code_names below. * * The array is used to register the statistics keeping track of the number of * messages received with the response code X. */ -char *in_message_code_names[] = +char *in_message_code_names[] = { - "100_in", "180_in", "181_in", "182_in", "183_in", - - "200_in", "202_in", - + "100_in", "180_in", "181_in", "182_in", "183_in", + + "200_in", "202_in", + "300_in", "301_in", "302_in", "305_in", "380_in", - - "400_in", "401_in", "402_in", "403_in", "404_in", "405_in", "406_in", - "407_in", "408_in", "410_in", "413_in", "414_in", "415_in", "416_in", - "420_in", "421_in", "423_in", "480_in", "481_in", "482_in", "483_in", - "484_in", "485_in", "486_in", "487_in", "488_in", "491_in", "492_in", - "494_in", - + + "400_in", "401_in", "402_in", "403_in", "404_in", "405_in", "406_in", + "407_in", "408_in", "410_in", "413_in", "414_in", "415_in", "416_in", + "420_in", "421_in", "423_in", "480_in", "481_in", "482_in", "483_in", + "484_in", "485_in", "486_in", "487_in", "488_in", "491_in", "492_in", + "494_in", + "500_in", "501_in", "502_in", "503_in", "504_in", "505_in", "513_in", "600_in", "603_in", "604_in", "606_in" }; /* The following message codes are from Wikipedia at: - * - * http://en.wikipedia.org/wiki/SIP_Responses + * + * http://en.wikipedia.org/wiki/SIP_Responses * * If there are more message codes added at a later time, they should be added * here, and to in_message_code_names above. @@ -147,20 +147,20 @@ char *in_message_code_names[] = * The array is used to register the statistics keeping track of the number of * messages send out with the response code X. */ -char *out_message_code_names[] = +char *out_message_code_names[] = { - "100_out", "180_out", "181_out", "182_out", "183_out", - - "200_out", "202_out", - + "100_out", "180_out", "181_out", "182_out", "183_out", + + "200_out", "202_out", + "300_out", "301_out", "302_out", "305_out", "380_out", - - "400_out", "401_out", "402_out", "403_out", "404_out", "405_out", "406_out", - "407_out", "408_out", "410_out", "413_out", "414_out", "415_out", "416_out", - "420_out", "421_out", "423_out", "480_out", "481_out", "482_out", "483_out", - "484_out", "485_out", "486_out", "487_out", "488_out", "491_out", "492_out", - "494_out", - + + "400_out", "401_out", "402_out", "403_out", "404_out", "405_out", "406_out", + "407_out", "408_out", "410_out", "413_out", "414_out", "415_out", "416_out", + "420_out", "421_out", "423_out", "480_out", "481_out", "482_out", "483_out", + "484_out", "485_out", "486_out", "487_out", "488_out", "491_out", "492_out", + "494_out", + "500_out", "501_out", "502_out", "503_out", "504_out", "505_out", "513_out", "600_out", "603_out", "604_out", "606_out" }; @@ -172,23 +172,23 @@ stat_var **in_message_code_stats = NULL; stat_var **out_message_code_stats = NULL; /* Adds the message code statistics to the statistics framework */ -static int register_message_code_statistics(void) +static int register_message_code_statistics(void) { int i; - int number_of_message_codes = + int number_of_message_codes = sizeof(in_message_code_names) / sizeof(char *); - in_message_code_stats = + in_message_code_stats = shm_malloc(sizeof(stat_var) * number_of_message_codes); - out_message_code_stats = + out_message_code_stats = shm_malloc(sizeof(stat_var) * number_of_message_codes); /* We can only proceed if we had enough memory to allocate the * statistics. Note that we don't free the memory, but we don't care * because the system is going to shut down */ - if (in_message_code_stats == NULL || + if (in_message_code_stats == NULL || out_message_code_stats == NULL) { return -1; @@ -198,11 +198,11 @@ static int register_message_code_statistics(void) memset(in_message_code_stats, 0, number_of_message_codes); memset(out_message_code_stats, 0, number_of_message_codes); - for (i = 0; i < number_of_message_codes; i++) + for (i = 0; i < number_of_message_codes; i++) { - register_stat(SNMPSTATS_MODULE_NAME, in_message_code_names[i], + register_stat(SNMPSTATS_MODULE_NAME, in_message_code_names[i], &in_message_code_stats[i], 0); - register_stat(SNMPSTATS_MODULE_NAME, out_message_code_names[i], + register_stat(SNMPSTATS_MODULE_NAME, out_message_code_names[i], &out_message_code_stats[i], 0); } @@ -213,11 +213,11 @@ static int register_message_code_statistics(void) * This call must always return a value as soon as possible. If it were not to * return, then OpenSIPS would not be able to initialize any of the other * modules. */ -static int mod_init(void) +static int mod_init(void) { LM_INFO("Starting up the SNMPStats Module\n"); - if (register_message_code_statistics() < 0) + if (register_message_code_statistics() < 0) { return -1; } @@ -225,31 +225,31 @@ static int mod_init(void) /* Initialize shared memory used to buffer communication between the * usrloc module and the snmpstats module. */ initInterprocessBuffers(); - + /* We need to register for callbacks with usrloc module, for whenever a * contact is added or removed from the system. We need to do it now * before OpenSER's functions get a chance to load up old user data from * the database. That load will happen if a lookup() function is come * across in openser.cfg. */ - if (!registerForUSRLOCCallbacks()) + if (!registerForUSRLOCCallbacks()) { /* Originally there were descriptive error messages here to help * the operator debug problems. Turns out this may instead * alarm them about problems they don't need to worry about. So * the messages are commented out for now */ - + /* - LM_ERR("snmpstats module was unable to register callbacks" + LM_ERR("snmpstats module was unable to register callbacks" " with the usrloc module\n"); LM_ERR("Are you sure that the usrloc module was loaded" " before the snmpstats module in "); LM_ERR("openser.cfg? openserSIPRegUserTable will not be " "updated."); */ - } + } + - /* Register the alarm checking function to run periodically */ register_timer( "snmp-alarm", run_alarm_check, 0, ALARM_AGENT_FREQUENCY_IN_SECONDS); @@ -261,7 +261,7 @@ static int mod_init(void) /* This function is called when OpenSIPS has finished creating all instances of * itself. It is at this point that we want to create our AgentX sub-agent * process, and register a handler for any state changes of our child. */ -static int mod_child_init(int rank) +static int mod_child_init(int rank) { /* We only want to setup a single process, under the first SIP worker, which will exist all the time */ @@ -277,7 +277,7 @@ static int mod_child_init(int rank) /* This function is called when OpenSIPS is shutting down. When this happens, we * log a useful message and kill the AgentX Sub-Agent child process */ -static void mod_destroy(void) +static void mod_destroy(void) { LM_INFO("The SNMPStats module got the kill signal\n"); @@ -288,8 +288,8 @@ static void mod_destroy(void) /* The SNMPStats module forks off a child process to run an snmp command via - * execve(). We need a customized handler to catch and ignore its SIGCHLD when - * it terminates. We also need to make sure to forward other processes + * execve(). We need a customized handler to catch and ignore its SIGCHLD when + * it terminates. We also need to make sure to forward other processes * SIGCHLD's to OpenSER's usual SIGCHLD handler. We do this by resetting back * OpenSER's own signal handlers after we caught our appropriate SIGCHLD. */ static void sigchld_handler(int signal) @@ -301,7 +301,7 @@ static void sigchld_handler(int signal) * sysUpTime child process, and ignore it. If the SIGCHLD is * from another process, we need to call OpenSER's usual * handlers */ - pid_of_signalled_process = + pid_of_signalled_process = waitpid(-1, &pid_of_signalled_process_status, WNOHANG); if (pid_of_signalled_process == sysUpTime_pid) @@ -311,7 +311,7 @@ static void sigchld_handler(int signal) * SNMPStats process. This means that we can restore OpenSER's * original handlers. */ sigaction(SIGCHLD, &old_sigchld_handler, NULL); - } else + } else { /* We need this 'else-block' in case another OpenSER process dies @@ -337,11 +337,11 @@ static void sigchld_handler(int signal) * handler to ignore the SIGCHLD for only this process. (See sigchld_handler * above). * - * NOTE: sysUpTime is a scalar provided by netsnmp. It is not the same thing as + * NOTE: sysUpTime is a scalar provided by netsnmp. It is not the same thing as * a normal system uptime. Support for this has been provided to try to - * match the IETF Draft SIP MIBs as closely as possible. + * match the IETF Draft SIP MIBs as closely as possible. */ -static int spawn_sysUpTime_child(void) +static int spawn_sysUpTime_child(void) { struct sigaction new_sigchld_handler; @@ -377,7 +377,7 @@ static int spawn_sysUpTime_child(void) /* If we are here, then we are the child process. Lets set up the file * descriptors so we can capture the output of snmpget. */ - int snmpget_fd = + int snmpget_fd = open(SNMPGET_TEMP_FILE, O_CREAT|O_TRUNC|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); @@ -389,7 +389,7 @@ static int spawn_sysUpTime_child(void) } /* Redirect Standard Output to our temporary file. */ - dup2(snmpget_fd, 1); + dup2(snmpget_fd, 1); if (snmp_community != NULL) { snmp_community_string = snmp_community; @@ -398,32 +398,32 @@ static int spawn_sysUpTime_child(void) " Defaulting to %s\n", snmp_community_string); } - char *args[] = {"-Ov", "-c", snmp_community_string, "localhost", + char *args[] = {"-Ov", "-c", snmp_community_string, "localhost", SYSUPTIME_OID, (char *) 0}; /* Make sure we have a path to snmpget, so we can retrieve the * sysUpTime. */ - if (snmpget_path == NULL) + if (snmpget_path == NULL) { LM_DBG("An snmpgetPath parameter was not specified." " Defaulting to %s\n", local_path_to_snmpget); } - else + else { local_path_to_snmpget = snmpget_path; } int local_path_to_snmpget_length = strlen(local_path_to_snmpget); int snmpget_binary_name_length = strlen(snmpget_binary_name); - + /* Allocate enough memory to hold the path, the binary name, and the * null character. We don't use pkg_memory here. */ - full_path_to_snmpget = - malloc(sizeof(char) * - (local_path_to_snmpget_length + + full_path_to_snmpget = + malloc(sizeof(char) * + (local_path_to_snmpget_length + snmpget_binary_name_length + 1)); - if (full_path_to_snmpget == NULL) + if (full_path_to_snmpget == NULL) { LM_ERR("Ran out of memory while trying to retrieve sysUpTime. "); LM_ERR( " openserSIPServiceStartTime is " @@ -434,7 +434,7 @@ static int spawn_sysUpTime_child(void) { /* Make a new string containing the full path to the binary. */ strcpy(full_path_to_snmpget, local_path_to_snmpget); - strcpy(&full_path_to_snmpget[local_path_to_snmpget_length], + strcpy(&full_path_to_snmpget[local_path_to_snmpget_length], snmpget_binary_name); } @@ -447,7 +447,7 @@ static int spawn_sysUpTime_child(void) free(full_path_to_snmpget); exit(-1); } - + /* We should never be able to get here, because execve() is never * supposed to return. */ free(full_path_to_snmpget); @@ -457,7 +457,7 @@ static int spawn_sysUpTime_child(void) /* This function is called whenever the opensips.cfg file specifies the * snmpgetPath parameter. The function will set the snmpget_path parameter. */ -int set_snmpget_path( modparam_t type, void *val) +int set_snmpget_path( modparam_t type, void *val) { if (!stringHandlerSanityCheck(type, val, "snmpgetPath" )) { return -1; diff --git a/modules/snmpstats/snmpstats.h b/modules/snmpstats/snmpstats.h index a6c4394c7a8..ed2b5426534 100644 --- a/modules/snmpstats/snmpstats.h +++ b/modules/snmpstats/snmpstats.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,7 +25,7 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * Structure and prototype definitions for the SNMPStats module. * * There are some important points to understanding the SNMPStat modules @@ -34,7 +34,7 @@ * 1) The SNMPStats module will fork off a new process in mod_child_init when * the rank is equal to PROC_MAIN_PROCESS. The sub-process will be * responsible for registering with a master agent (the source of snmp - * requests), and handling all received requests. + * requests), and handling all received requests. * * 2) The Module will register a periodic alarm checking function with a sip * timer using register_timer(). This function checks for alarm conditions, @@ -46,7 +46,7 @@ * spawning a short-lived process. For this reason, the module temporarily * installs a new SIGCHLD handler to deal specifically with this process. It * does not change the normal SIGCHLD behaviour for any process except for - * this short lived sysUpTime process. + * this short lived sysUpTime process. * * 4) mod_init() will initialize some interprocess communication buffers, as * well as callback mechanisms for the usrloc module. To understand what the @@ -97,16 +97,16 @@ static proc_export_t mod_procs[] = { /* * This structure defines the SNMPStats parameters that can be configured - * through the opensips.cfg configuration file. + * through the opensips.cfg configuration file. */ -static param_export_t mod_params[] = +static param_export_t mod_params[] = { { "sipEntityType", STR_PARAM|USE_FUNC_PARAM, (void *)handleSipEntityType }, { "MsgQueueMinorThreshold", INT_PARAM|USE_FUNC_PARAM, - (void *)set_queue_minor_threshold }, + (void *)set_queue_minor_threshold }, { "MsgQueueMajorThreshold", INT_PARAM|USE_FUNC_PARAM, - (void *)set_queue_major_threshold }, + (void *)set_queue_major_threshold }, { "dlg_minor_threshold", INT_PARAM|USE_FUNC_PARAM, (void *)set_dlg_minor_threshold }, { "dlg_major_threshold", INT_PARAM|USE_FUNC_PARAM, @@ -114,16 +114,28 @@ static param_export_t mod_params[] = { "snmpgetPath", STR_PARAM|USE_FUNC_PARAM, (void *)set_snmpget_path }, { "snmpCommunity", STR_PARAM|USE_FUNC_PARAM, - (void *)set_snmp_community }, + (void *)set_snmp_community }, { 0,0,0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "usrloc", DEP_SILENT }, + { MOD_TYPE_DEFAULT, "dialog", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; -struct module_exports exports = +struct module_exports exports = { SNMPSTATS_MODULE_NAME, /* module's name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module's version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ 0, /* exported functions */ mod_params, /* param exports */ 0, /* exported statistics */ diff --git a/modules/snmpstats/snmpstats_globals.h b/modules/snmpstats/snmpstats_globals.h index fbe0bafced7..9ce11a58d1c 100644 --- a/modules/snmpstats/snmpstats_globals.h +++ b/modules/snmpstats/snmpstats_globals.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -102,7 +102,7 @@ #define TC_ROWSTATUS_NOTINSERVICE 2 #define TC_ROWSTATUS_NOTREADY 3 #define TC_ROWSTATUS_CREATEANDGO 4 -#define TC_ROWSTATUS_CREATEANDWAIT 5 +#define TC_ROWSTATUS_CREATEANDWAIT 5 #define TC_ROWSTATUS_DESTROY 6 /* * Textual Conventions for INTEGER types - ends diff --git a/modules/snmpstats/sub_agent.c b/modules/snmpstats/sub_agent.c index 61db0dbff04..c8802cf9dad 100644 --- a/modules/snmpstats/sub_agent.c +++ b/modules/snmpstats/sub_agent.c @@ -4,7 +4,7 @@ * 2006-11-23 initial version (jmagder) * * This file defines all functions required to establish a relationship with a - * master agent. + * master agent. */ #include @@ -39,7 +39,7 @@ static int keep_running; /* The function handles Handles shutting down of the sub_agent process. */ -static void sigterm_handler(int signal) +static void sigterm_handler(int signal) { /* Just exit. The master agent will clean everything up for us */ exit(0); @@ -50,16 +50,16 @@ static void sigterm_handler(int signal) * 1) Registers itself with the Master Agent * * 2) Initializes all of the SNMPStats modules scalars and tables, while - * simultaneously registering their respective SNMP OID's and handlers + * simultaneously registering their respective SNMP OID's and handlers * with the master agent. * * 3) Repeatedly checks for new SNMP messages to process * - * Note: This function never returns, so it should always be called from a - * sub-process. + * Note: This function never returns, so it should always be called from a + * sub-process. * */ -static int initialize_agentx(void) +static int initialize_agentx(void) { /* We register with a master agent */ register_with_master_agent(AGENT_PROCESS_NAME); @@ -121,7 +121,7 @@ void agentx_child(int rank) sigaction(SIGINT, &default_handlers, NULL); sigaction(SIGHUP, &default_handlers, NULL); sigaction(SIGUSR1, &default_handlers, NULL); - /* SIGUSR2 must be handled by OpenSIPS as it is used for + /* SIGUSR2 must be handled by OpenSIPS as it is used for collecting info on pkg memory */ /*sigaction(SIGUSR2, &default_handlers, NULL);*/ @@ -146,7 +146,7 @@ void agentx_child(int rank) /* This function opens up a connection with the master agent specified in * the snmpstats modules configuration file */ -void register_with_master_agent(char *name_to_register_under) +void register_with_master_agent(char *name_to_register_under) { /* Set ourselves up as an AgentX Client. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); diff --git a/modules/snmpstats/sub_agent.h b/modules/snmpstats/sub_agent.h index 0253a8821ad..704b3f24e9d 100644 --- a/modules/snmpstats/sub_agent.h +++ b/modules/snmpstats/sub_agent.h @@ -1,7 +1,7 @@ /* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,9 +25,9 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * This file defines all functions required to establish a relationship with a - * master agent. + * master agent. */ #ifndef _SNMPSTATS_SUB_AGENT_ diff --git a/modules/snmpstats/utilities.c b/modules/snmpstats/utilities.c index 660d431031d..2360c78b660 100644 --- a/modules/snmpstats/utilities.c +++ b/modules/snmpstats/utilities.c @@ -1,7 +1,7 @@ -/* +/* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,7 +25,7 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * This file was created to group together utility functions that were useful * throughout the SNMPStats module, without belonging to any file in particular. */ @@ -43,7 +43,7 @@ /* Silently returns 1 if the supplied parameters are sane. Otherwise, an error * message is logged for parameterName, and 0 returned. */ -int stringHandlerSanityCheck( modparam_t type, void *val, char *parameterName) +int stringHandlerSanityCheck( modparam_t type, void *val, char *parameterName) { char *theString = (char *)val; @@ -56,8 +56,8 @@ int stringHandlerSanityCheck( modparam_t type, void *val, char *parameterName) /* An empty string was supplied. We consider this illegal */ if (theString==0 || (theString[0])==0) { - LM_ERR("the %s parameter was specified with an empty string\n", - parameterName); + LM_ERR("the %s parameter was specified with an empty string\n", + parameterName); return 0; } @@ -66,12 +66,12 @@ int stringHandlerSanityCheck( modparam_t type, void *val, char *parameterName) -/* +/* * This function is a wrapper around the standard statistic framework. It will * return the value of the statistic denoted with statName, or zero if the - * statistic was not found. + * statistic was not found. */ -int get_statistic(char *statName) +int get_statistic(char *statName) { int result = 0; @@ -81,7 +81,7 @@ int get_statistic(char *statName) theStr.len = strlen(statName); stat_var *theVar = get_stat(&theStr); - + if (theVar==0) { LM_INFO("failed to retrieve statistics for %s\n", statName); } else { @@ -94,7 +94,7 @@ int get_statistic(char *statName) /* Returns a pointer to an SNMP DateAndTime OCTET STRING representation of the * time structure. Note that the pointer is to static data, so it shouldn't be * counted on to be around if this function is called again. */ -char * convertTMToSNMPDateAndTime(struct tm *timeStructure) +char * convertTMToSNMPDateAndTime(struct tm *timeStructure) { static char dateAndTime[8]; diff --git a/modules/snmpstats/utilities.h b/modules/snmpstats/utilities.h index 1f6c9d7631a..0f9ee79699d 100644 --- a/modules/snmpstats/utilities.h +++ b/modules/snmpstats/utilities.h @@ -1,7 +1,7 @@ -/* +/* * $Id$ * - * SNMPStats Module + * SNMPStats Module * Copyright (C) 2006 SOMA Networks, INC. * Written by: Jeffrey Magder (jmagder@somanetworks.com) * @@ -25,7 +25,7 @@ * History: * -------- * 2006-11-23 initial version (jmagder) - * + * * This file was created to group together utility functions that were useful * throughout the SNMPStats module, without belonging to any file in particular. */ @@ -42,10 +42,10 @@ * file parameter handler. */ int stringHandlerSanityCheck( modparam_t type, void *val, char *parameterName); -/* +/* * This function is a wrapper around the standard statistic framework. It will * return the value of the statistic denoted with statName, or zero if the - * statistic was not found. + * statistic was not found. */ int get_statistic(char *statName); diff --git a/modules/speeddial/README b/modules/speeddial/README index 8fe4f801e7b..6779d630780 100644 --- a/modules/speeddial/README +++ b/modules/speeddial/README @@ -12,8 +12,7 @@ Elena-Ramona Modroiu Copyright © 2004 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/speeddial/sdlookup.c b/modules/speeddial/sdlookup.c index fced007d2fc..ab0e035bad1 100644 --- a/modules/speeddial/sdlookup.c +++ b/modules/speeddial/sdlookup.c @@ -21,7 +21,7 @@ * * History: * --------- - * + * */ @@ -67,7 +67,7 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _owner) /* init */ nr_keys = 0; db_cols[0]=&new_uri_column; - + if(_owner) { memset(&turi, 0, sizeof(struct sip_uri)); @@ -91,7 +91,7 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _owner) goto err_server; } } - + db_keys[nr_keys]=&user_column; db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; @@ -107,7 +107,7 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _owner) db_vals[nr_keys].val.str_val.s = puri->host.s; db_vals[nr_keys].val.str_val.len = puri->host.len; nr_keys++; - + if (dstrip_s.s!=NULL && dstrip_s.len>0 && dstrip_s.lenhost.len && strncasecmp(puri->host.s,dstrip_s.s,dstrip_s.len)==0) @@ -122,14 +122,14 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _owner) LM_ERR("failed to parsing Request-URI\n"); goto err_server; } - + db_keys[nr_keys]=&sd_user_column; db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = _msg->parsed_uri.user.s; db_vals[nr_keys].val.str_val.len = _msg->parsed_uri.user.len; nr_keys++; - + if(use_domain>=2) { db_keys[nr_keys]=&sd_domain_column; @@ -138,7 +138,7 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _owner) db_vals[nr_keys].val.str_val.s = _msg->parsed_uri.host.s; db_vals[nr_keys].val.str_val.len = _msg->parsed_uri.host.len; nr_keys++; - + if (dstrip_s.s!=NULL && dstrip_s.len>0 && dstrip_s.len<_msg->parsed_uri.host.len && strncasecmp(_msg->parsed_uri.host.s,dstrip_s.s,dstrip_s.len)==0) @@ -168,21 +168,21 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _owner) user_s.s = useruri_buf+4; switch(RES_ROWS(db_res)[0].values[0].type) - { + { case DB_STRING: - strcpy(user_s.s, + strcpy(user_s.s, (char*)RES_ROWS(db_res)[0].values[0].val.string_val); user_s.len = strlen(user_s.s); break; case DB_STR: - strncpy(user_s.s, + strncpy(user_s.s, (char*)RES_ROWS(db_res)[0].values[0].val.str_val.s, RES_ROWS(db_res)[0].values[0].val.str_val.len); user_s.len = RES_ROWS(db_res)[0].values[0].val.str_val.len; user_s.s[user_s.len] = '\0'; break; case DB_BLOB: - strncpy(user_s.s, + strncpy(user_s.s, (char*)RES_ROWS(db_res)[0].values[0].val.blob_val.s, RES_ROWS(db_res)[0].values[0].val.blob_val.len); user_s.len = RES_ROWS(db_res)[0].values[0].val.blob_val.len; @@ -195,7 +195,7 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _owner) } goto err_server; } - + /* check 'sip:' */ if(user_s.len<4 || strncasecmp(user_s.s, "sip:", 4)) { diff --git a/modules/speeddial/sdlookup.h b/modules/speeddial/sdlookup.h index 9ab1f62e17b..4814d57f125 100644 --- a/modules/speeddial/sdlookup.h +++ b/modules/speeddial/sdlookup.h @@ -21,7 +21,7 @@ * * History: * --------- - * + * */ diff --git a/modules/speeddial/speeddial.c b/modules/speeddial/speeddial.c index 0d2bf8ebd56..120b8744520 100644 --- a/modules/speeddial/speeddial.c +++ b/modules/speeddial/speeddial.c @@ -21,7 +21,7 @@ * * History: * --------- - * + * */ @@ -90,12 +90,23 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /* Module interface */ struct module_exports exports = { - "speeddial", + "speeddial", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ diff --git a/modules/speeddial/speeddial.h b/modules/speeddial/speeddial.h index 16f5160ddf9..7184aece979 100644 --- a/modules/speeddial/speeddial.h +++ b/modules/speeddial/speeddial.h @@ -21,7 +21,7 @@ * * History: * --------- - * + * */ diff --git a/modules/sst/README b/modules/sst/README index 54fde80847d..6e0b665a999 100644 --- a/modules/sst/README +++ b/modules/sst/README @@ -10,8 +10,7 @@ Ron Winacott Copyright © 2006 SOMA Networks, Inc. Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -30,9 +29,8 @@ Ron Winacott 1.4.1. enable_stats (integer) 1.4.2. min_se (integer) 1.4.3. sst_interval (integer) - 1.4.4. timeout_avp (string) - 1.4.5. reject_to_small (integer) - 1.4.6. sst_flag (string/integer) + 1.4.4. reject_to_small (integer) + 1.4.5. sst_flag (string/integer) 1.5. Exported Functions @@ -42,18 +40,15 @@ Ron Winacott 1.6.1. expired_sst - 1.7. Installation and Running - List of Examples 1.1. Session timer call flow 1.2. Set enable_stats parameter 1.3. Set min_se parameter 1.4. Set sst_interval parameter - 1.5. Set timeout_avp parameter - 1.6. Set reject_to_small parameter - 1.7. Set sst_flag parameter - 1.8. sstCheckMin usage + 1.5. Set reject_to_small parameter + 1.6. Set sst_flag parameter + 1.7. sstCheckMin usage Chapter 1. Admin Guide @@ -74,8 +69,7 @@ Chapter 1. Admin Guide The sst module uses the dialog module to be notified of any new or updated dialogs. It will then look for and extract the session-expire: header value (if there is one) and override the - dialog expire timer value for the current context dialog by - setting the avp value. + dialog expire timer value for the current context dialog. You flag any call setup INVITE that you want to cause a timed session to be established. This will cause OpenSIPS to request @@ -198,25 +192,7 @@ modparam("sst", "min_se", 2400) modparam("sst", "sst_interval", 2400) ... -1.4.4. timeout_avp (string) - - This parameter MUST be set to the same value as the dialog - parameter of the same name. If this parameter is NOT set, the - sst module will not do anything! - - This is how the sst module knows which avp in the dialog module - to change with the new expire value. - - Default value is “NULL!” it is not set by default. - - Example 1.5. Set timeout_avp parameter -... -modparam("dialog", "timeout_avp", "$avp(10)") -# Set the sst modules timeout_avp to be the same value -modparam("sst", "timeout_avp", "$avp(10)") -... - -1.4.5. reject_to_small (integer) +1.4.4. reject_to_small (integer) In the initial INVITE if the UAC has requested a Session-Expire: and it's value is smaller then our local @@ -231,12 +207,12 @@ modparam("sst", "timeout_avp", "$avp(10)") Default value is “1” (true/on). - Example 1.6. Set reject_to_small parameter + Example 1.5. Set reject_to_small parameter ... modparam("sst", "reject_to_small", 0) ... -1.4.6. sst_flag (string/integer) +1.4.5. sst_flag (string/integer) Keeping with OpenSIPS, the module will not do anything to any message unless instructed to do so via the opensips.cfg script. @@ -257,7 +233,7 @@ modparam("sst", "reject_to_small", 0) Default value is “Not set!”. - Example 1.7. Set sst_flag parameter + Example 1.6. Set sst_flag parameter ... modparam("sst", "sst_flag", "SST_FLAG") ... @@ -288,13 +264,10 @@ route { * min_allowed - The value to compare the MIN_SE header value to. - Example 1.8. sstCheckMin usage + Example 1.7. sstCheckMin usage -... -modparam("dialog", "timeout_avp", "$avp(4242)") ... modparam("sst", "sst_flag", 6) -modparam("sst", "timeout_avp", "$avp(4242)") modparam("sst", "min_se", 2400) # Must be >= 90 ... @@ -332,7 +305,3 @@ route { 1.6.1. expired_sst Number of dialogs which got expired session timer. - -1.7. Installation and Running - - just load the module and remember to set the timeout_avp value. diff --git a/modules/sst/doc/sst_admin.xml b/modules/sst/doc/sst_admin.xml index eecc5cad756..74d19283602 100644 --- a/modules/sst/doc/sst_admin.xml +++ b/modules/sst/doc/sst_admin.xml @@ -27,7 +27,7 @@ any new or updated dialogs. It will then look for and extract the session-expire: header value (if there is one) and override the dialog expire timer value for the current context - dialog by setting the avp value.
+ dialog.
You flag any call setup INVITE that you want to cause a timed session to be established. This will cause OpenSIPS to @@ -211,32 +211,6 @@ modparam("sst", "sst_interval", 2400)
-
- <varname>timeout_avp</varname> (string) - - This parameter MUST be set to the same value as the - dialog parameter of the same name. If this parameter is - NOT set, the sst module will not do anything! - - This is how the sst module knows which avp in the - dialog module to change with the new expire value. - - - - Default value is NULL! it is not set by default. - - - - Set <varname>timeout_avp</varname> parameter - -... -modparam("dialog", "timeout_avp", "$avp(10)") -# Set the sst modules timeout_avp to be the same value -modparam("sst", "timeout_avp", "$avp(10)") -... - - -
<varname>reject_to_small</varname> (integer) @@ -344,11 +318,8 @@ route { <function>sstCheckMin</function> usage -... -modparam("dialog", "timeout_avp", "$avp(4242)") ... modparam("sst", "sst_flag", 6) -modparam("sst", "timeout_avp", "$avp(4242)") modparam("sst", "min_se", 2400) # Must be >= 90 ... @@ -394,9 +365,5 @@ route {
-
- Installation and Running - just load the module and remember to set the timeout_avp value. -
diff --git a/modules/sst/sst.c b/modules/sst/sst.c index ce84ca515b1..49b40b2f0f3 100644 --- a/modules/sst/sst.c +++ b/modules/sst/sst.c @@ -48,27 +48,18 @@ static int mod_init(void); struct sig_binds sigb; /* - * statistic variables + * statistic variables */ int sst_enable_stats = 1; stat_var *expired_sst = 0; -/* - * The name of the AVP the dialog module will use to hold the timeout - * value so we can set the AVP in the dialog callbacks so the dialog - * code will set the dialog lifetime when it returns from the INVITE - * and IN_ROUTE callbacks. - */ -pv_spec_t timeout_avp; -static char* timeout_spec = 0; /* Place holder for the passed in name */ - /* * The default or script parameter for the requested MIN-SE: value for * this proxy. (in seconds) If the passed in value is 0, then this * proxy will except any value from the UAC as its min-SE value. If * the value is NOT set then the default will be asserted. */ -unsigned int sst_minSE = 90; +unsigned int sst_minSE = 90; /* * Should the PROXY (us) reject (with a 422 reply) and SE < sst_minSE @@ -80,11 +71,11 @@ unsigned int sst_reject = 1; static int sst_flag = -1; static char *sst_flag_str = 0; -/* +/* * The sst minimum interval in Session-Expires header if OpenSIPS * request the use of session times. The used value will be the * maximum value between OpenSIPS minSE, UAS minSE and this value -*/ +*/ unsigned int sst_interval = 0; /* @@ -107,7 +98,6 @@ static cmd_export_t cmds[]={ static param_export_t mod_params[]={ { "enable_stats", INT_PARAM, &sst_enable_stats }, { "min_se", INT_PARAM, &sst_minSE }, - { "timeout_avp", STR_PARAM, &timeout_spec }, { "reject_to_small", INT_PARAM, &sst_reject }, { "sst_flag", STR_PARAM, &sst_flag_str }, { "sst_flag", INT_PARAM, &sst_flag }, @@ -123,10 +113,28 @@ static stat_export_t mod_stats[] = { {0,0,0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "signaling", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "dialog", DEP_ABORT }, + /* + * FIXME: silent module load ordering, due to Session-Expires updates from sst + * proper fix should involve dialog callback ordering + */ + { MOD_TYPE_DEFAULT, "pua_dialoginfo", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + struct module_exports exports= { "sst", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ mod_params, /* param exports */ mod_stats, /* exported statistics */ @@ -149,9 +157,8 @@ struct module_exports exports= { * @return 0 to continue to load the OpenSIPS, -1 to stop the loading * and abort OpenSIPS. */ -static int mod_init(void) +static int mod_init(void) { - str s; LM_INFO("SIP Session Timer module - initializing\n"); /* * if statistics are disabled, prevent their registration to core. @@ -160,30 +167,19 @@ static int mod_init(void) exports.stats = 0; } - fix_flag_name(&sst_flag_str, sst_flag); + fix_flag_name(sst_flag_str, sst_flag); sst_flag = get_flag_id_by_name(FLAG_TYPE_MSG, sst_flag_str); if (sst_flag == -1) { LM_ERR("no sst flag set!!\n"); return -1; - } + } else if (sst_flag > MAX_FLAG) { LM_ERR("invalid sst flag %d!!\n", sst_flag); return -1; } - if (timeout_spec != NULL) { - LM_DBG("Dialog AVP is %s", timeout_spec); - s.s = timeout_spec; s.len = strlen(s.s); - if (pv_parse_spec(&s, &timeout_avp)==0 - && (timeout_avp.type != PVT_AVP)){ - LM_ERR("malformed or non AVP timeout AVP definition in '%s'\n", - timeout_spec); - return -1; - } - } - /* load SIGNALING API */ if(load_sig_api(&sigb)< 0) { LM_ERR("can't load signaling functions\n"); @@ -193,8 +189,7 @@ static int mod_init(void) /* * Init the handlers */ - sst_handler_init((timeout_spec?&timeout_avp:0), sst_minSE, - sst_flag, sst_reject,sst_interval); + sst_handler_init(sst_minSE, sst_flag, sst_reject,sst_interval); /* * Register the main (static) dialog call back. @@ -207,6 +202,12 @@ static int mod_init(void) /* Load dialog hooks */ dialog_st.register_dlgcb(NULL, DLGCB_CREATED, sst_dialog_created_CB, NULL, NULL); + if (dialog_st.register_dlgcb(NULL, DLGCB_LOADED, sst_dialog_loaded_CB, + NULL, NULL) != 0) { + LM_ERR("cannot register dialog_loaded callback\n"); + return -1; + } + /* * We are GOOD-TO-GO. */ diff --git a/modules/sst/sst_handlers.c b/modules/sst/sst_handlers.c index 7a83905356c..b46c6042eb4 100644 --- a/modules/sst/sst_handlers.c +++ b/modules/sst/sst_handlers.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: sst_handlers.c 7046 2010-07-22 14:07:23Z bogdan_iancu $ * * Copyright (C) 2006 SOMA Networks, Inc. * Written by Ron Winacott (karwin) @@ -62,6 +62,7 @@ #include "../../dprint.h" #include "../../sr_module.h" /* Needed for find_export() */ #include "../signaling/signaling.h" +#include "../dialog/dlg_vals.h" #include "sst_handlers.h" #include "sst_mi.h" @@ -85,6 +86,8 @@ } \ } +#define SST_DIALOG_FLAG (1 << 3) + #ifndef MIN #define MIN(a, b) (ab?a:b) #endif +#define CHECK_AND_UPDATE_SST_INFO(info, field, value, dirty) \ + do {\ + if (info-> field != value) { \ + info-> field = value; \ + dirty = 1;\ + }\ + } while (0) + +#define CHECK_AND_UPDATE_SST_INFO_TMP(info, field, value, dirty, tmp) \ + do {\ + tmp.field = value; \ + CHECK_AND_UPDATE_SST_INFO(info, field, tmp.field, dirty); \ + } while (0) + /** * The binding to the dialog module functions. Most importantly the @@ -128,9 +145,9 @@ static int send_response(struct sip_msg *request, int code, str *reason, char *header, int header_len); static int append_header(struct sip_msg *msg, const char *header); static int remove_minse_header(struct sip_msg *msg); -static int set_timeout_avp(struct sip_msg *msg, unsigned int value); static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo); static int send_reject(struct sip_msg *msg, unsigned int min_se); +static void set_dialog_lifetime(struct dlg_cell *dlg, unsigned int value); static void setup_dialog_callbacks(struct dlg_cell *did, sst_info_t *info); /** @@ -139,11 +156,6 @@ static void setup_dialog_callbacks(struct dlg_cell *did, sst_info_t *info); */ extern struct sig_binds sigb; -/** - * The dialog modules timeout AVP spac. - */ -static pv_spec_t *timeout_avp = 0; - /** * Our Min-SE: header field value and test. */ @@ -161,12 +173,13 @@ static unsigned int sst_reject = 1; static int sst_flag = 0; /** - * Our Session-Expire minimum interval + * Our Session-Expire minimum interval */ static unsigned int sst_interval = 0; static str sst_422_rpl = str_init("Session Timer Too Small"); +static str info_val_name = str_init("sst_info"); /** @@ -183,10 +196,9 @@ static str sst_422_rpl = str_init("Session Timer Too Small"); * @param interval - The minimum session expire value used by this * PROXY */ -void sst_handler_init(pv_spec_t *timeout_avp_p, unsigned int min_se, - int flag, unsigned int reject, unsigned int interval) +void sst_handler_init(unsigned int min_se, int flag, unsigned int reject, + unsigned int interval) { - timeout_avp = timeout_avp_p; sst_min_se = min_se; sst_flag = 1 << flag; sst_reject = reject; @@ -208,7 +220,7 @@ void sst_handler_init(pv_spec_t *timeout_avp_p, unsigned int min_se, * the state tracking to figure out if and who supports SST. * * As per RFC4028: Request handling: - * + * * - The proxy may insert a SE header if none found. * - The SE value can be anything >= Min-SE (if found) * - The proxy MUST NOT add a refresher parameter to the SE. @@ -250,7 +262,7 @@ void sst_dialog_created_CB(struct dlg_cell *did, int type, return; } - /* + /* * look only at INVITE */ if (msg->first_line.type != SIP_REQUEST || @@ -275,18 +287,18 @@ void sst_dialog_created_CB(struct dlg_cell *did, int type, * later */ if (minfo.se != 0) { - /* + /* * There is a SE already there, this is good, we just need to * check the values out a little before passing it along. */ if (minfo.se < sst_min_se) { - /* + /* * Problem, the requested Session-Expires is too small for * our local policy. We need to fix it, or reject it or * ignore it. */ if (!minfo.supported) { - /* + /* * Increase the Min-SE: value in the request and * forward it. */ @@ -315,7 +327,7 @@ void sst_dialog_created_CB(struct dlg_cell *did, int type, } } else { - /* + /* * No Session-Expire: stated in request. */ char buf[80]; @@ -330,7 +342,7 @@ void sst_dialog_created_CB(struct dlg_cell *did, int type, /* What to do? Let is slide, we can still work */ } } - + info->interval = MAX(info->interval, sst_interval); info->requester = SST_PXY; snprintf(buf, 80, "Session-Expires: %d\r\n", info->interval); @@ -341,11 +353,46 @@ void sst_dialog_created_CB(struct dlg_cell *did, int type, return; /* Nothing we can do! */ } } + /* We keep the sst_info in the dialog's vals in case of restarting */ + /* No const here because of store_dlg_value's definition */ + str raw_info = {(char*)info, sizeof(sst_info_t)}; + if (dlg_binds->store_dlg_value(did, &info_val_name, &raw_info) != 0) { + LM_ERR("No sst_info can be added to the dialog." + "This dialog won't be considered after restart!\n"); + } + + dlg_binds->set_mod_flag(did, SST_DIALOG_FLAG); + setup_dialog_callbacks(did, info); - set_timeout_avp(msg, info->interval); + /* Early setup of default timeout */ + set_dialog_lifetime(did, info->interval); return; } +void sst_dialog_loaded_CB(struct dlg_cell *did, int type, + struct dlg_cb_params *params){ + + /* Check if this is previously marked by sst module */ + if (!dlg_binds->is_mod_flag_set(did, SST_DIALOG_FLAG)) + return; + + /* We try to get the original sst info back */ + sst_info_t *info = (sst_info_t *)shm_malloc(sizeof(sst_info_t)); + + if (info == NULL) { + LM_ERR ("No more shared memory!\n"); + return; + } + + str raw_info = {(char*)info, sizeof(sst_info_t)}; + if (dlg_binds->fetch_dlg_value(did, &info_val_name, &raw_info, 1) != 0){ + LM_ERR ("No sst_info found!\n"); + return; + } + + setup_dialog_callbacks(did, info); +} + #ifdef USE_CONFIRM_CALLBACK /** * Play time. Please ignore this call. @@ -418,38 +465,45 @@ static void sst_dialog_request_within_CB(struct dlg_cell* did, int type, struct dlg_cb_params * params) { sst_info_t *info = (sst_info_t *)*(params->param); + sst_info_t tmp_info; sst_msg_info_t minfo = {0,0,0,0}; struct sip_msg* msg = params->msg; + short info_dirty = 0; if (msg->first_line.type == SIP_REQUEST) { if ((msg->first_line.u.request.method_value == METHOD_INVITE || msg->first_line.u.request.method_value == METHOD_UPDATE)) { - LM_DBG("Update by a REQUEST. %.*s\n", - msg->first_line.u.request.method.len, + LM_DBG("Update by a REQUEST. %.*s\n", + msg->first_line.u.request.method.len, msg->first_line.u.request.method.s); if (parse_msg_for_sst_info(msg, &minfo)) { // FIXME: need an error message here return; } /* Early resetting of the value here */ - set_timeout_avp(msg, minfo.se); - info->interval = minfo.se; + if (minfo.se > 0) { + if (sst_interval > minfo.min_se) + CHECK_AND_UPDATE_SST_INFO(info, interval, sst_interval, info_dirty); + else + CHECK_AND_UPDATE_SST_INFO_TMP(info, interval, + MAX(minfo.se, sst_min_se), info_dirty, tmp_info); + } + CHECK_AND_UPDATE_SST_INFO_TMP(info, supported, + (minfo.supported?SST_UAC:SST_UNDF), info_dirty, tmp_info); + set_dialog_lifetime(did, info->interval); } - else if (msg->first_line.u.request.method_value == METHOD_PRACK) { + else if (msg->first_line.u.request.method_value == METHOD_PRACK + || msg->first_line.u.request.method_value == METHOD_ACK) { /* Special case here. The PRACK will cause the dialog * module to reset the timeout value to the ldg->lifetime * value and look for the new AVP value bound to the * 1XX/PRACK/200OK/ACK transaction and not to the * INVITE/200OK avp value. So we need to set the AVP - * again! I think this is a bug in the dialog module, - * either it should ignore PRACK like it ignored ACK, or - * the setting of the timeout value when returning to the - * confiremed callback code should look for the new AVP - * value, which is does not. + * again! */ - LM_DBG("PRACK workaround applied!\n"); - set_timeout_avp(msg, info->interval); + LM_DBG("ACK/PRACK workaround applied!%d\n", info->interval); + set_dialog_lifetime(did, info->interval); } } else if (msg->first_line.type == SIP_REPLY) { @@ -459,16 +513,25 @@ static void sst_dialog_request_within_CB(struct dlg_cell* did, int type, * To spec (RFC) the internal time out value so not be reset * until here. */ - LM_DBG("Update by a REPLY %d %.*s\n", + LM_DBG("Update by a REPLY %d %.*s\n", msg->first_line.u.reply.statuscode, - msg->first_line.u.reply.reason.len, + msg->first_line.u.reply.reason.len, msg->first_line.u.reply.reason.s); if (parse_msg_for_sst_info(msg, &minfo)) { // FIXME: need an error message here return; } - set_timeout_avp(msg, minfo.se); - info->interval = minfo.se; + set_dialog_lifetime(did, minfo.se); + CHECK_AND_UPDATE_SST_INFO_TMP(info, supported, + (minfo.supported?SST_UAC:SST_UNDF), info_dirty, tmp_info); + CHECK_AND_UPDATE_SST_INFO(info, interval, minfo.se, info_dirty); + } + } + + if (info_dirty){ + str raw_info = {(char*)info, sizeof(sst_info_t)}; + if (dlg_binds->store_dlg_value(did, &info_val_name, &raw_info) != 0) { + LM_ERR("sst_info can't be updated\n"); } } } @@ -483,96 +546,127 @@ static void sst_dialog_request_within_CB(struct dlg_cell* did, int type, * @param params - The sst information */ static void sst_dialog_response_fwded_CB(struct dlg_cell* did, int type, - struct dlg_cb_params * params) + struct dlg_cb_params * params) { struct sip_msg* msg = params->msg; + int *param; + short info_dirty = 0; /* * This test to see if the message is a response sould ALWAYS be * true. This callback should not get called for requests. But * lets be safe. */ - if (msg->first_line.type == SIP_REPLY) { - sst_msg_info_t minfo = {0,0,0,0}; - sst_info_t *info = (sst_info_t *)*(params->param); - - LM_DBG("Dialog seen REPLY %d %.*s\n", - msg->first_line.u.reply.statuscode, - msg->first_line.u.reply.reason.len, - msg->first_line.u.reply.reason.s); - /* - * Need to check to see if it is a 422 response. If it is, - * make sure our Min-SE: for this dialog is set at least as - * large as in the Min-SE: in the reply 422 message. If not, - * we will create an INVITE, 422 loop. - */ - if (msg->first_line.u.reply.statuscode == 422) { - if (parse_msg_for_sst_info(msg, &minfo)) { - LM_ERR("failed to prase sst information for thr 422 reply\n"); - return; - } - /* Make sure we do not try to use anything smaller */ - info->interval = MAX(info->interval, minfo.min_se); - return; /* There is nothing else to do with this */ + + if (msg->first_line.type != SIP_REPLY) + return; + + sst_msg_info_t minfo = {0,0,0,0}; + sst_info_t *info = (sst_info_t *)*(params->param); + sst_info_t tmp_info; + + LM_DBG("Dialog seen REPLY %d %.*s\n", + msg->first_line.u.reply.statuscode, + msg->first_line.u.reply.reason.len, + msg->first_line.u.reply.reason.s); + /* + * Need to check to see if it is a 422 response. If it is, + * make sure our Min-SE: for this dialog is set at least as + * large as in the Min-SE: in the reply 422 message. If not, + * we will create an INVITE, 422 loop. + */ + if (msg->first_line.u.reply.statuscode == 422) { + if (parse_msg_for_sst_info(msg, &minfo)) { + LM_ERR("failed to prase sst information for thr 422 reply\n"); + return; } - /* - * We need to get the method this reply is for from the CSEQ - * body. The RFC states we can only play with 2XX from the - * INVITE or reINVTE/UPDATE. - */ - if (!msg->cseq && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || !msg->cseq)) { - LM_ERR("failed to parse CSeq\n"); + /* Make sure we do not try to use anything smaller */ + if (info->interval < minfo.min_se) + CHECK_AND_UPDATE_SST_INFO(info, interval, minfo.min_se, info_dirty); + + goto update_info; /* There is nothing else to do with this */ + } + /* + * We need to get the method this reply is for from the CSEQ + * body. The RFC states we can only play with 2XX from the + * INVITE or reINVTE/UPDATE. + */ + if (!msg->cseq && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || !msg->cseq)) { + LM_ERR("failed to parse CSeq\n"); + return; + } + + /* 2XX replies to INVITES only !*/ + if (msg->first_line.u.reply.statuscode > 199 && + msg->first_line.u.reply.statuscode < 300 && + (get_cseq(msg)->method_id == METHOD_INVITE || + get_cseq(msg)->method_id == METHOD_UPDATE)) { + if (parse_msg_for_sst_info(msg, &minfo)) { + LM_ERR("failed to parse sst information for the 2XX reply\n"); return; } - - /* 2XX replies to INVITES only !*/ - if (msg->first_line.u.reply.statuscode > 199 && - msg->first_line.u.reply.statuscode < 300 && - (get_cseq(msg)->method_id == METHOD_INVITE || - get_cseq(msg)->method_id == METHOD_UPDATE)) { - if (parse_msg_for_sst_info(msg, &minfo)) { - LM_ERR("failed to parse sst information for the 2XX reply\n"); - return; - } + LM_DBG("parsing 200 OK response %d / %d\n", minfo.supported, minfo.se); + if (info->supported != SST_UAC) { + CHECK_AND_UPDATE_SST_INFO_TMP(info, supported, + (minfo.supported?SST_UAS:SST_UNDF),info_dirty, tmp_info); + } + if (minfo.se != 0) { + if (sst_interval > minfo.min_se) + CHECK_AND_UPDATE_SST_INFO(info, interval, sst_interval, info_dirty); + else + CHECK_AND_UPDATE_SST_INFO_TMP(info, interval, + MAX(minfo.se, sst_min_se), info_dirty, tmp_info); + LM_DBG("UAS supports timer\n"); + set_dialog_lifetime(did, info->interval); + } + else { + /* no se header found, we want to resquest it. */ + if (info->supported == SST_UAC) { + char se_buf[80]; - if (minfo.se != 0) { - if (set_timeout_avp(msg, info->interval)) { - // FIXME: need an error message here + LM_DBG("UAC supports timer\n"); + LM_DBG("appending the Session-Expires: header to the 2XX reply." + " UAC will deal with it.\n"); + /* + * GOOD! we can just insert the Session-Expires: + * header and forward back to the UAC and it will + * deal with refreshing the session. + */ + if (sst_interval > minfo.min_se) + CHECK_AND_UPDATE_SST_INFO(info, interval, sst_interval, + info_dirty); + else + CHECK_AND_UPDATE_SST_INFO_TMP(info, interval, + MAX(minfo.se, sst_min_se), info_dirty, tmp_info); + snprintf(se_buf, 80, "Session-Expires: %d;refresher=uac\r\n", + info->interval); + if (append_header(msg, se_buf)) { + LM_ERR("failed to append Session-Expires header\n"); return; } + /* Set the dialog timeout HERE */ + set_dialog_lifetime(did, info->interval); } else { - /* no se header found, we want to resquest it. */ - if (info->requester == SST_PXY || info->supported == SST_UAC) { - char se_buf[80]; - - LM_DBG("appending the Session-Expires: header to the 2XX reply." - " UAC will deal with it.\n"); - /* - * GOOD! we can just insert the Session-Expires: - * header and forward back to the UAC and it will - * deal with refreshing the session. - */ - snprintf(se_buf, 80, "Session-Expires: %d;refresher=uac\r\n", - info->interval); - if (append_header(msg, se_buf)) { - LM_ERR("failed to append Session-Expires header\n"); - return; - } - /* Set the dialog timeout HERE */ - if (set_timeout_avp(msg, info->interval)) { - return; - } - } - else { - /* We are sunk, uac did not request it, and it - * does not support it */ - LM_DBG("UAC and UAS do not support timers!" - " No session timers for this session.\n"); - } + /* We are sunk, uac did not request it, and it + * does not support it */ + LM_DBG("UAC and UAS do not support timers!" + " No session timers for this session.\n"); + param = find_param_export("dialog", "default_timeout", INT_PARAM); + CHECK_AND_UPDATE_SST_INFO_TMP(info, interval, + param?*param:12*3600, info_dirty, tmp_info); + set_dialog_lifetime(did, info->interval); } - } /* End of 2XX for an INVITE */ - } /* If the msg is a repsonse and not a request */ + } + } /* End of 2XX for an INVITE */ + +update_info: + if (info_dirty){ + str raw_info = {(char*)info, sizeof(sst_info_t)}; + if (dlg_binds->store_dlg_value(did, &info_val_name, &raw_info) != 0) { + LM_ERR("sst_info can't be updated\n"); + } + } } /** @@ -639,7 +733,7 @@ int sst_check_min(struct sip_msg *msg, char *flag, char *str2) * not parse it. */ LM_ERR("failed to parse MIN-SE header.\n"); - return -1; + return -1; } /* * If not stated, use the value from the session-expires @@ -648,7 +742,7 @@ int sst_check_min(struct sip_msg *msg, char *flag, char *str2) LM_DBG("No MIN-SE header found.\n"); minse = 90 /*this is the recommended value*/ /*se.interval*/; } - + LM_DBG("Session-Expires: %d; MIN-SE: %d\n", se.interval, minse); /* @@ -697,7 +791,7 @@ int sst_check_min(struct sip_msg *msg, char *flag, char *str2) * @return 0 on success, none-zero on an error. */ static int send_response(struct sip_msg *request, int code, str *reason, - char *header, int header_len) + char *header, int header_len) { if (sigb.reply != 0) { @@ -742,7 +836,7 @@ static int append_header(struct sip_msg *msg, const char *header) return(1); } - if ((anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0)) == 0) { + if ((anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0)) == 0) { LM_ERR("failed to get anchor to append header\n"); return(1); } @@ -797,45 +891,16 @@ static int remove_minse_header(struct sip_msg *msg) * Set the dialog's AVP value so the dialog module will use this value * and not the default when returning from the dialog callback. * - * @param msg The current message to bind the AVP to. + * @param dlg The current dialog * @param value The value you want to set the AVP to. - * - * @return 0 on success, -1 on an error. */ -static int set_timeout_avp(struct sip_msg *msg, unsigned int value) +static void set_dialog_lifetime(struct dlg_cell *dlg, unsigned int value) { - int rtn = -1; /* assume failure */ - pv_value_t pv_val; - int result = 0; - /* Set the dialog timeout HERE */ - if (timeout_avp) { - if ((result = pv_get_spec_value(msg, timeout_avp, &pv_val)) == 0) { - /* We now hold a reference to the AVP */ - if (pv_val.flags & PV_VAL_INT && pv_val.ri == value) { - /* INT AVP with the same value */ - LM_DBG("Current timeout value already set to %d\n", - value); - rtn = 0; - } else { - /* AVP not found or non-INT value -> add a new one*/ - pv_val.flags = PV_VAL_INT|PV_TYPE_INT; - pv_val.ri = value; - if (pv_set_value(msg,timeout_avp,EQ_T,&pv_val)!=0) { - LM_ERR("failed to set new dialog timeout value\n"); - } else { - rtn = 0; - } - } - } - else { - LM_ERR("SST not reset. get avp result is %d\n", result); - } - } - else { - LM_ERR("SST needs to know the name of the dialog timeout AVP!\n"); - } - return(rtn); + dlg->lifetime = value; + dlg->lifetime_dirty = 1; + + LM_DBG("set dialog timeout value to %d\n", value); } /** @@ -855,8 +920,8 @@ static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo) if (!msg || !minfo) { return (-1); } - - /* + + /* * parse the supported infor */ minfo->supported = 0; /*Clear it */ @@ -869,12 +934,10 @@ static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo) * if not found or an error parsing the one it did find! So assume * it is not found if unsuccessfull. */ - if ((rtn = parse_supported(msg)) == 0) { - if ((((struct supported_body*)msg->supported->parsed)->supported_all - & F_SUPPORTED_TIMER)) { + if (msg->supported && parse_supported(msg) == 0 && + (get_supported(msg) & F_SUPPORTED_TIMER)) minfo->supported = 1; - } - } + /* * Parse the Min-SE: header next. */ @@ -898,7 +961,7 @@ static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo) * * @return 0 on success, -1 on error. */ -static int send_reject(struct sip_msg *msg, unsigned int min_se) +static int send_reject(struct sip_msg *msg, unsigned int min_se) { char tmp[2]; /* to find the length */ int hdr_len = 0; @@ -941,23 +1004,25 @@ static void setup_dialog_callbacks(struct dlg_cell *did, sst_info_t *info) LM_DBG("Adding callback " "DLGCB_FAILED|DLGCB_TERMINATED|DLGCB_EXPIRED\n"); - dlg_binds->register_dlgcb(did, + if (dlg_binds->register_dlgcb(did, DLGCB_FAILED|DLGCB_TERMINATED|DLGCB_EXPIRED, - sst_dialog_terminate_CB, (void *)info, NULL); + sst_dialog_terminate_CB, (void *)info, NULL) != 0) + LM_ERR("could not add the DLGCB_TERMINATED callback\n"); + LM_DBG("Adding callback DLGCB_REQ_WITHIN\n"); /* This is for the reINVITE/UPDATE requests */ dlg_binds->register_dlgcb(did, DLGCB_REQ_WITHIN, sst_dialog_request_within_CB, info, NULL); - /* + /* * This is for the final configuration of who will do SST for * us. In the DLGCB_CONFIRMED callback the message is * immutable! we must do all the real work in the DLGCB_FRD * callback were we can change the message. */ - LM_DBG("Adding callback DLGCB_RESPONSE_FWDED\n"); - dlg_binds->register_dlgcb(did, DLGCB_RESPONSE_FWDED, + LM_DBG("Adding callback DLGCB_RESPONSE_FWDED|DLGCB_RESPONSE_WITHIN\n"); + dlg_binds->register_dlgcb(did, DLGCB_RESPONSE_FWDED|DLGCB_RESPONSE_WITHIN, sst_dialog_response_fwded_CB, info, NULL); - + LM_DBG("Adding mi handler\n"); dlg_binds->register_dlgcb(did, DLGCB_MI_CONTEXT, sst_dialog_mi_context_CB, info, NULL); diff --git a/modules/sst/sst_handlers.h b/modules/sst/sst_handlers.h index 4588c110f29..035d0b1f25b 100644 --- a/modules/sst/sst_handlers.h +++ b/modules/sst/sst_handlers.h @@ -60,9 +60,12 @@ typedef struct sst_info_st { /** * The static (opening) callback function for all dialog creations */ -void sst_dialog_created_CB(struct dlg_cell *did, int type, +void sst_dialog_created_CB(struct dlg_cell *did, int type, struct dlg_cb_params * params); +void sst_dialog_loaded_CB(struct dlg_cell *did, int type, + struct dlg_cb_params *params); + /** * The script function */ @@ -71,7 +74,7 @@ int sst_check_min(struct sip_msg *msg, char *str1, char *str2); /** * The handlers initializer function */ -void sst_handler_init(pv_spec_t *timeout_avp, unsigned int minSE, - int flag, unsigned int reject, unsigned int interval); +void sst_handler_init(unsigned int minSE, int flag, unsigned int reject, + unsigned int interval); #endif /* _SST_HANDLERS_H_ */ diff --git a/modules/statistics/README b/modules/statistics/README index 8561dc3e722..a2c00b221ad 100644 --- a/modules/statistics/README +++ b/modules/statistics/README @@ -8,8 +8,7 @@ Bogdan Iancu Copyright © 2006 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/statistics/statistics.c b/modules/statistics/statistics.c index 3768f46d27c..1187cef401d 100644 --- a/modules/statistics/statistics.c +++ b/modules/statistics/statistics.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -95,8 +95,10 @@ static pv_export_t mod_items[] = { struct module_exports exports= { "statistics", /* module's name */ - MODULE_VERSION, + MOD_TYPE_DEFAULT,/* class of this module */ + MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ mod_params, /* param exports */ 0, /* exported statistics */ @@ -145,7 +147,7 @@ static int fixup_stat(void** param, int param_no) /* reference to the statistic name */ sp = (struct stat_param *)pkg_malloc(sizeof(struct stat_param)); if (sp==NULL) { - LM_ERR("no more pkg mem (%ld)\n",sizeof(struct stat_param)); + LM_ERR("no more pkg mem (%d)\n", (int)sizeof(struct stat_param)); return E_OUT_OF_MEM; } memset( sp, 0 , sizeof(struct stat_param) ); @@ -425,7 +427,7 @@ int pv_set_stat(struct sip_msg* msg, pv_param_t *param, int op, if (val != 0) LM_WARN("non-zero value - setting value to 0\n"); - + reset_stat( stat ); return 0; diff --git a/modules/statistics/stats_funcs.c b/modules/statistics/stats_funcs.c index c943fd4e225..a9399c02e27 100644 --- a/modules/statistics/stats_funcs.c +++ b/modules/statistics/stats_funcs.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/statistics/stats_funcs.h b/modules/statistics/stats_funcs.h index d58015e10c7..45b190d4cbe 100644 --- a/modules/statistics/stats_funcs.h +++ b/modules/statistics/stats_funcs.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/stun/README b/modules/stun/README index 24d21fc4a90..a0ee30c6d8f 100644 --- a/modules/stun/README +++ b/modules/stun/README @@ -12,7 +12,7 @@ Razvan Pistolea Copyright © 2009 Voice Sistem SRL Revision History - Revision $Revision:$ $Date:$ + Revision $Revision:$ $Date$ __________________________________________________________ Table of Contents @@ -55,7 +55,9 @@ Chapter 1. Admin Guide A stun server working with the same port as SIP (5060) in order to gain accurate information. The benefit would be an exact external address in the case of NATs translating differently - when given different destination ports. + when given different destination ports. The server may also + advertise different network addresses than the ones it is + actually listening on. 1.1.2. Basic Operation @@ -115,43 +117,78 @@ Chapter 1. Admin Guide 1.3.1. primary_ip (str) - The ip of the an interface configured as UDP SIP listener in - OpenSIPS. It is a mandatory paramter, by default empty. + The IP of an interface which is configured as an UDP SIP + listener in OpenSIPS. This is a mandatory parameter. + + Syntax: "ip [/ advertised_ip] + + By default, the primary_ip and the advertised primary_ip will + be identical. This may be changed with an optional "/ + xxx.xxx.xxx.xxx" string. Example 1.1. Set primary_ip parameter ... -modparam("stun","primary_ip","192.168.0.100") +modparam("stun", "primary_ip", "192.168.0.100") + +# Example of a STUN server within OpenSIPS which is behind NAT +modparam("stun", "primary_ip", "192.168.0.100 / 64.50.46.78") ... 1.3.2. primary_port (str) The port configured (together with the primary_ip) as an UDP - SIP listener in OpenSIPS. It is a mandatory paramter, by - default 5060. + SIP listener in OpenSIPS. The default value is 5060. + + Syntax: "port [/ advertised_port] + + By default, the primary_port and the advertised primary_port + will be identical. This may be changed with an optional "/ + adv_port" string. Example 1.2. Set primary_port parameter ... -modparam("stun","primary_port","5060") +modparam("stun", "primary_port", "5060") + +# Listening on a primary port, but advertising a different one +modparam("stun", "primary_port", "5060 / 5062") ... 1.3.3. alternate_ip (str) - Another ip from another interface. It is mandatory to be set, - default is empty (not set). + Another IP from another interface. This is a mandatory + parameter. + + Syntax: "ip [/ advertised_ip] + + By default, the alternate_ip and the advertised alternate_ip + will be identical. This may be changed with an optional "/ + xxx.xxx.xxx.xxx" string. Example 1.3. Set alternate_ip parameter ... modparam("stun","alternate_ip","11.22.33.44") + +# Example of a STUN server within OpenSIPS which is behind NAT +modparam("stun", "alternate_ip", "192.168.0.100 / 64.78.46.50") ... 1.3.4. alternate_port (str) - Another port used by STUN. It is mandatory to be set, default - value is 3478 (default STUN port). + The port used by the STUN server for the second interface. The + default value is 3478 (default STUN port). + + Syntax: "port [/ advertised_port] + + By default, the alternate_port and the advertised + alternate_port will be identical. This may be changed with an + optional "/ adv_port" string. Example 1.4. Set alternate_port parameter ... modparam("stun","alternate_port","3479") + +# Listening on an alternate port, but advertising a different one +modparam("stun", "alternate_port", "5060 / 5062") ... 1.4. Exported MI Functions diff --git a/modules/stun/doc/stun_admin.xml b/modules/stun/doc/stun_admin.xml index ee40ecfb208..9301ef82262 100644 --- a/modules/stun/doc/stun_admin.xml +++ b/modules/stun/doc/stun_admin.xml @@ -13,7 +13,8 @@ A stun server working with the same port as SIP (5060) in order to gain accurate information. The benefit would be an exact external address in the case of NATs translating differently when given - different destination ports. + different destination ports. The server may also advertise different + network addresses than the ones it is actually listening on.
@@ -110,8 +111,16 @@ primary_ip (str) - The ip of the an interface configured as UDP SIP listener - in &osips;. It is a mandatory paramter, by default empty. + The IP of an interface which is configured as an UDP SIP listener + in &osips;. This is a mandatory parameter. + + + Syntax: "ip [/ advertised_ip] + + + By default, the primary_ip and the advertised + primary_ip will be identical. + This may be changed with an optional "/ xxx.xxx.xxx.xxx" string. Set @@ -119,7 +128,10 @@ ... -modparam("stun","primary_ip","192.168.0.100") +modparam("stun", "primary_ip", "192.168.0.100") + +# Example of a STUN server within OpenSIPS which is behind NAT +modparam("stun", "primary_ip", "192.168.0.100 / 64.50.46.78") ... @@ -130,27 +142,45 @@ modparam("stun","primary_ip","192.168.0.100") primary_port (str) - The port configured (together with the primary_ip) as an UDP SIP - listener in &osips;. It is a mandatory paramter, by default 5060. + The port configured (together with the primary_ip) as an UDP SIP + listener in &osips;. The default value is 5060. + + + Syntax: "port [/ advertised_port] + + + By default, the primary_port and the advertised + primary_port will be identical. + This may be changed with an optional "/ adv_port" string. Set <varname>primary_port</varname> parameter ... -modparam("stun","primary_port","5060") +modparam("stun", "primary_port", "5060") + +# Listening on a primary port, but advertising a different one +modparam("stun", "primary_port", "5060 / 5062") ...
- +
<varname>alternate_ip</varname> (str) - Another ip from another interface. It is mandatory to be set, - default is empty (not set). + Another IP from another interface. This is a mandatory parameter. + + + Syntax: "ip [/ advertised_ip] + + + By default, the alternate_ip and the advertised + alternate_ip will be identical. + This may be changed with an optional "/ xxx.xxx.xxx.xxx" string. Set @@ -159,6 +189,9 @@ modparam("stun","primary_port","5060") <programlisting format="linespecific"> ... modparam("stun","alternate_ip","11.22.33.44") + +# Example of a STUN server within OpenSIPS which is behind NAT +modparam("stun", "alternate_ip", "192.168.0.100 / 64.78.46.50") ... </programlisting> </example> @@ -169,8 +202,16 @@ modparam("stun","alternate_ip","11.22.33.44") <varname>alternate_port</varname> (str) - Another port used by STUN. It is mandatory to be set, default - value is 3478 (default STUN port). + The port used by the STUN server for the second interface. + The default value is 3478 (default STUN port). + + + Syntax: "port [/ advertised_port] + + + By default, the alternate_port and the advertised + alternate_port will be identical. + This may be changed with an optional "/ adv_port" string. Set @@ -179,6 +220,9 @@ modparam("stun","alternate_ip","11.22.33.44") <programlisting format="linespecific"> ... modparam("stun","alternate_port","3479") + +# Listening on an alternate port, but advertising a different one +modparam("stun", "alternate_port", "5060 / 5062") ... </programlisting> </example> diff --git a/modules/stun/stun.c b/modules/stun/stun.c index 88075a72783..3d6f1557ff6 100644 --- a/modules/stun/stun.c +++ b/modules/stun/stun.c @@ -23,6 +23,7 @@ * History: * -------- * 2009-09-03 initial version (razvan) + * 2014-03-04 added advertised IPs and ports (liviu) */ #include "../../sr_module.h" /* param_export_t, proc_export_t */ @@ -30,17 +31,10 @@ #include "../../socket_info.h" /* grep_sock_info() */ #include "../../ip_addr.h" /* struct socket_info */ #include "../../str.h" /* str */ +#include "../../trim.h" #include "stun.h" -/* Exported parameters */ -char* primary_ip = NULL; -char* primary_port = "5060"; - -char* alternate_ip = NULL; -char* alternate_port= "3478"; - - /* Globals */ struct socket_info* grep1 = NULL; struct socket_info* grep2 = NULL; @@ -54,17 +48,30 @@ int sockfd3=-1; /* ip2 port1 */ int sockfd4=-1; /* ip2 port2 */ int ip1, ip2; -int port1, port2; +int port1 = 5060, port2 = 3478; /* default SIP and STUN ports */ + +/* dot representation of the above IPs - for socket matching and printing */ +char *primary_ip, *alternate_ip; + +/* different advertised IPs and ports, in case we're behind NAT */ +int adv_ip1 = -1, adv_ip2 = -1; +int adv_port1, adv_port2; + +/* Fixup functions */ +int parse_primary_ip(modparam_t type, void *val); +int parse_primary_port(modparam_t type, void *val); +int parse_alternate_ip(modparam_t type, void *val); +int parse_alternate_port(modparam_t type, void *val); /* * Exported parameters ip, port */ static param_export_t params[] = { - {"primary_ip", STR_PARAM, (void*) &primary_ip}, - {"primary_port", STR_PARAM, (void*) &primary_port}, - {"alternate_ip", STR_PARAM, (void*) &alternate_ip}, - {"alternate_port", STR_PARAM, (void*) &alternate_port}, - {0, 0, 0} + {"primary_ip", STR_PARAM | USE_FUNC_PARAM, parse_primary_ip }, + {"primary_port", STR_PARAM | USE_FUNC_PARAM, parse_primary_port }, + {"alternate_ip", STR_PARAM | USE_FUNC_PARAM, parse_alternate_ip }, + {"alternate_port", STR_PARAM | USE_FUNC_PARAM, parse_alternate_port }, + { 0, 0, 0} }; /* Extra proces for listening loop */ @@ -75,8 +82,10 @@ static proc_export_t mod_procs[] = { struct module_exports exports = { "stun", /* module's name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ 0, /* exported functions */ params, /* module parameters */ 0, /* exported statistics */ @@ -89,8 +98,6 @@ struct module_exports exports = { child_init /* per-child init function */ }; - - /* init */ int bind_ip_port(int ip, int port, int* sockfd){ @@ -124,38 +131,21 @@ static int stun_mod_init(void) { str s; - if (primary_ip==NULL || primary_ip[0]==0) { + if (!primary_ip || primary_ip[0] == '\0') { LM_ERR("Primary IP was not configured!\n"); return -1; } - if (inet_pton(AF_INET, primary_ip, &ip1) < 1) { - LM_ERR("Invalid ip1 %s : %s\n",primary_ip, strerror(errno)); - return -1; - } - if (alternate_ip==NULL || alternate_ip[0]==0) { - LM_ERR("Primary IP was not configured!\n"); + if (!alternate_ip || alternate_ip[0] == '\0') { + LM_ERR("Alternate IP was not configured!\n"); return -1; } - if (inet_pton(AF_INET, alternate_ip, &ip2) < 1) { - LM_ERR("Invalid ip2 %s : %s\n",alternate_ip, strerror(errno)); - return -1; - } - - ip1 = ntohl(ip1); - ip2 = ntohl(ip2); - port1 = atoi(primary_port); - if(!(0<port1 && port1< 65536)){ - LM_ERR("Invalid port1 %s\n",primary_port); - return -1; - } + if (adv_ip1 != -1 && adv_port1 == 0) + adv_port1 = port1; - port2 = atoi(alternate_port); - if(!(0<port2 && port2< 65536)){ - LM_ERR("Invalid port2 %s\n",alternate_port); - return -1; - } + if (adv_ip2 != -1 && adv_port2 == 0) + adv_port1 = port2; s.s = primary_ip; s.len = strlen(primary_ip); grep1 = grep_sock_info(&s, (unsigned short)port1, PROTO_UDP); @@ -251,6 +241,7 @@ void stun_loop(int rank) memset( &ri, 0, sizeof(ri) ); for(;;){ + LM_DBG("READING\n"); read_set = all_set; nready = select(maxfd+1, &read_set, NULL, NULL, NULL); @@ -320,15 +311,15 @@ int receive(int sockfd, struct receive_info *ri, str *msg, void* param) /* info & checks*/ if(sockfd == sockfd1) - sprintf(s, "%i %s %s", sockfd1, primary_ip, primary_port); + sprintf(s, "%i %s %d", sockfd1, primary_ip, port1); else if(sockfd == sockfd2) - sprintf(s, "%i %s %s", sockfd2, primary_ip, alternate_port); + sprintf(s, "%i %s %d", sockfd2, primary_ip, port2); else if(sockfd == sockfd3) - sprintf(s, "%i %s %s", sockfd3, alternate_ip, primary_port); + sprintf(s, "%i %s %d", sockfd3, alternate_ip, port1); else if(sockfd == sockfd4) - sprintf(s, "%i %s %s", sockfd4, alternate_ip, alternate_port); + sprintf(s, "%i %s %d", sockfd4, alternate_ip, port2); else{ - sprintf(s, "%i unknown %s %s", sockfd, alternate_ip, alternate_port); + sprintf(s, "%i unknown %s %d", sockfd, alternate_ip, port2); LM_DBG("Received: on [%s] from [%s %i]; drop msg\n", s, inet_ntoa(client->sin_addr), ntohs(client->sin_port)); return -1; @@ -374,13 +365,13 @@ int receive(int sockfd, struct receive_info *ri, str *msg, void* param) /* send */ if(ctl.sock_outbound == sockfd1) - sprintf(s, "%i %s %s", sockfd1, primary_ip, primary_port); + sprintf(s, "%i %s %d", sockfd1, primary_ip, port1); else if(ctl.sock_outbound == sockfd2) - sprintf(s, "%i %s %s", sockfd2, primary_ip, alternate_port); + sprintf(s, "%i %s %d", sockfd2, primary_ip, port2); else if(ctl.sock_outbound == sockfd3) - sprintf(s, "%i %s %s", sockfd3, alternate_ip, primary_port); + sprintf(s, "%i %s %d", sockfd3, alternate_ip, port1); else if(ctl.sock_outbound == sockfd4) - sprintf(s, "%i %s %s", sockfd4, alternate_ip, alternate_port); + sprintf(s, "%i %s %d", sockfd4, alternate_ip, port2); else sprintf(s, "%i unknown", ctl.sock_outbound); @@ -471,7 +462,7 @@ int getTlvAttribute(IN_OUT Buffer* buf, IN_OUT StunMsg* msg){ msg->hasResponceAddress = TRUE; msg->responceAddress = (StunAddr*) pkg_malloc(sizeof(StunAddr)); if(!msg->responceAddress) - return -6; + return -6; memset(msg->responceAddress, 0, sizeof(StunAddr)); msg->responceAddress->unused = *(char*) b; @@ -513,13 +504,13 @@ int getTlvAttribute(IN_OUT Buffer* buf, IN_OUT StunMsg* msg){ msg->hmac = (Buffer*) pkg_malloc(sizeof(Buffer)); if(!msg->hmac) return -6; - + memset(msg->hmac, 0, sizeof(Buffer)); /* allocate 20 bytes */ msg->hmac->buffer = (char*)pkg_malloc(20 * sizeof(char)); if(!msg->hmac->buffer) - return -6; + return -6; msg->hmac->size = 20; /* copy the 20 bytes */ @@ -555,7 +546,7 @@ int getTlvAttribute(IN_OUT Buffer* buf, IN_OUT StunMsg* msg){ msg->unknownAttributes = (Buffer*) pkg_malloc( sizeof(Buffer)); if(!msg->unknownAttributes) - return -6; + return -6; memset(msg->unknownAttributes, 0, sizeof(Buffer)); /* allocate array of unknownAttributes (12 should suffice)*/ @@ -565,7 +556,7 @@ int getTlvAttribute(IN_OUT Buffer* buf, IN_OUT StunMsg* msg){ return -6; memset(msg->unknownAttributes->buffer, 0, MAX_UNKNOWN_ATTRIBUTES * sizeof(T16)); - + /* size reprezents the serializable size of attributes*/ msg->unknownAttributes->size = 0; @@ -575,7 +566,7 @@ int getTlvAttribute(IN_OUT Buffer* buf, IN_OUT StunMsg* msg){ b2 = (T16*) msg->unknownAttributes->buffer; if(msg->unknownAttributes->size / sizeof(T16) < MAX_UNKNOWN_ATTRIBUTES){ - b2[msg->unknownAttributes->size] = type; + b2[msg->unknownAttributes->size / sizeof(T16)] = type; msg->unknownAttributes->size += sizeof(T16); } }else{ @@ -729,17 +720,17 @@ int addTlvAttribute(IN_OUT StunMsg* msg , IN StunMsg* srs_msg, msg->sourceAddress->family = 0x01; if(ctl->sock_outbound == sockfd1){ - msg->sourceAddress->ip4 = ip1; - msg->sourceAddress->port = port1; + msg->sourceAddress->ip4 = ADV_IP(ip1, adv_ip1); + msg->sourceAddress->port = ADV_PORT(port1, adv_port1); }else if(ctl->sock_outbound == sockfd2){ - msg->sourceAddress->ip4 = ip1; - msg->sourceAddress->port = port2; + msg->sourceAddress->ip4 = ADV_IP(ip1, adv_ip1); + msg->sourceAddress->port = ADV_PORT(port2, adv_port2); }else if(ctl->sock_outbound == sockfd3){ - msg->sourceAddress->ip4 = ip2; - msg->sourceAddress->port = port1; + msg->sourceAddress->ip4 = ADV_IP(ip2, adv_ip2); + msg->sourceAddress->port = ADV_PORT(port1, adv_port1); }else if(ctl->sock_outbound == sockfd4){ - msg->sourceAddress->ip4 = ip2; - msg->sourceAddress->port = port2; + msg->sourceAddress->ip4 = ADV_IP(ip2, adv_ip2); + msg->sourceAddress->port = ADV_PORT(port2, adv_port2); } return 2 + 2 + 8; @@ -765,17 +756,17 @@ int addTlvAttribute(IN_OUT StunMsg* msg , IN StunMsg* srs_msg, 1 >< 4 ; 2 >< 3 */ if(ctl->sock_inbound == sockfd1){ - msg->changedAddress->ip4 = ip2; - msg->changedAddress->port = port2; + msg->changedAddress->ip4 = ADV_IP(ip2, adv_ip2); + msg->changedAddress->port = ADV_PORT(port2, adv_port2); }else if(ctl->sock_inbound == sockfd2){ - msg->changedAddress->ip4 = ip2; - msg->changedAddress->port = port1; + msg->changedAddress->ip4 = ADV_IP(ip2, adv_ip2); + msg->changedAddress->port = ADV_PORT(port1, adv_port1); }else if(ctl->sock_inbound == sockfd3){ - msg->changedAddress->ip4 = ip1; - msg->changedAddress->port = port2; + msg->changedAddress->ip4 = ADV_IP(ip1, adv_ip1); + msg->changedAddress->port = ADV_PORT(port2, adv_port2); }else if(ctl->sock_inbound == sockfd4){ - msg->changedAddress->ip4 = ip1; - msg->changedAddress->port = port1; + msg->changedAddress->ip4 = ADV_IP(ip1, adv_ip1); + msg->changedAddress->port = ADV_PORT(port1, adv_port1); } return 2 + 2 + 8; @@ -998,7 +989,7 @@ StunMsg* process(IN StunMsg* msg, IN_OUT StunCtl* ctl){ /* swap ports - mentain ips */ swap(&t1, &t2); swap(&t3, &t4); - + } /* LM_DBG("process()3 t1=%i t2=%i t3=%i t4=%i\n", t1, t2, t3, t4); */ ctl->sock_outbound = t1; @@ -1031,7 +1022,7 @@ StunMsg* process(IN StunMsg* msg, IN_OUT StunCtl* ctl){ LM_DBG("error at UNKNOWN_ATTRIBUTES\n"); goto error; } - rmsg->len+=rc; + rmsg->len+=rc; } /* even if it has CHANGE_REQUEST, * the error response is send to source */ @@ -1080,7 +1071,7 @@ StunMsg* process(IN StunMsg* msg, IN_OUT StunCtl* ctl){ goto error; } rmsg->len+=rc; - + }else{ pkg_free(rmsg); return NULL; @@ -1416,3 +1407,131 @@ void print_hex(IN char* buffer, IN int size){ } LM_DBG("\n"); } + +/** + * @buf: a "ip[ / advertised_ip]" type of string + * @rcv_ip: IP of a receiving interface (dot representation) + * @rcv_ip_int: same as above (integer representation) + * @adv_ip: IP of an advertised interface (integer representation) + */ +static int parse_ip_modparam(char *buf, char **rcv_ip, int *rcv_ip_int, + int *adv_ip) +{ + char *p; + str ip; + + p = strchr(buf, '/'); + + if (p) { + ip.s = buf; + ip.len = p - ip.s; + } else { + ip.s = buf; + ip.len = strlen(buf); + } + + trim(&ip); + + if (p) + ip.s[ip.len] = '\0'; + + *rcv_ip = ip.s; + + if (inet_pton(AF_INET, ip.s, rcv_ip_int) < 1) { + LM_ERR("Invalid ip %s : %s\n", ip.s, strerror(errno)); + return -1; + } + + *rcv_ip_int = ntohl(*rcv_ip_int); + + LM_DBG("Parsed IP: %s %d\n", *rcv_ip, *rcv_ip_int); + + if (!p || !adv_ip) + return 0; + + ip.s = p + 1; + ip.len = strlen(ip.s); + trim(&ip); + + if (inet_pton(AF_INET, ip.s, adv_ip) < 1) { + LM_ERR("Invalid advertised ip %s : %s\n", ip.s, strerror(errno)); + return -1; + } + + *adv_ip = ntohl(*adv_ip); + + LM_DBG("Parsed advertised IP: %.*s %d\n", ip.len, ip.s, *adv_ip); + + return 0; +} + +/** + * @buf: a "port[ / advertised_port]" type of string + * @port: STUN listening port + * @adv_port: STUN advertised port + */ +static int parse_port_modparam(char *buf, int *port, int *adv_port) +{ + char *p; + str st; + + p = strchr(buf, '/'); + + if (p) { + st.s = buf; + st.len = p - buf; + } else { + st.s = buf; + st.len = strlen(buf); + } + + trim(&st); + + if (p) + st.s[st.len] = '\0'; + + *port = atoi(st.s); + if (!(0 < *port && *port < 65536)) { + LM_ERR("Invalid port %.*s\n", st.len, st.s); + return -1; + } + + LM_DBG("Parsed port: %d\n", *port); + + if (!p || !adv_port) + return 0; + + st.s = p + 1; + st.len = strlen(st.s); + trim(&st); + + *adv_port = atoi(st.s); + if (!(0 < *adv_port && *adv_port < 65536)) { + LM_ERR("Invalid port %.*s\n", st.len, st.s); + return -1; + } + + LM_DBG("Parsed advertised port: %d\n", *adv_port); + + return 0; +} + +int parse_primary_ip(modparam_t type, void *val) +{ + return parse_ip_modparam(val, &primary_ip, &ip1, &adv_ip1); +} + +int parse_primary_port(modparam_t type, void *val) +{ + return parse_port_modparam(val, &port1, &adv_port1); +} + +int parse_alternate_ip(modparam_t type, void *val) +{ + return parse_ip_modparam(val, &alternate_ip, &ip2, &adv_ip2); +} + +int parse_alternate_port(modparam_t type, void *val) +{ + return parse_port_modparam(val, &port2, &adv_port2); +} diff --git a/modules/stun/stun.h b/modules/stun/stun.h index f7336b05197..bc63db50507 100644 --- a/modules/stun/stun.h +++ b/modules/stun/stun.h @@ -47,6 +47,9 @@ #define IN_OUT #define MAX_UNKNOWN_ATTRIBUTES 12 +#define ADV_IP(ip, adv_ip) (adv_ip != -1 ? adv_ip : ip) +#define ADV_PORT(port, adv_port) (adv_port ? adv_port : port) + /* types */ typedef char Bool; typedef char T8; @@ -57,7 +60,7 @@ typedef uint32_t T32; typedef enum { FALSE = 0, TRUE =1 - + } Boolean; typedef enum { @@ -131,13 +134,13 @@ typedef struct stun_message{ StunAddr* mappedAddress; /* host order */ Bool hasResponceAddress; - StunAddr* responceAddress; + StunAddr* responceAddress; Bool hasSourceAddress; - StunAddr* sourceAddress; + StunAddr* sourceAddress; Bool hasChangedAddress; - StunAddr* changedAddress; + StunAddr* changedAddress; Bool hasReflectedFrom; StunAddr* reflectedFromAddress; diff --git a/modules/textops/README b/modules/textops/README index 00a4bb6728b..ab4aa2a78c0 100644 --- a/modules/textops/README +++ b/modules/textops/README @@ -25,8 +25,7 @@ Ovidiu Sas Copyright © 2003 FhG FOKUS Revision History - Revision $Revision$ $Date: 2010-12-07 19:37:12 +0200 - (Tue, 07 Dec 2010) $ + Revision $Revision: 7480 $ $Date$ __________________________________________________________ Table of Contents @@ -268,7 +267,7 @@ if(has_body() && replace_body_atonce("^.+$", "")) (match newline don't treat it as end of line). 're' - is regular expresion 'repl' - is replacement string - may contain - pseudo-varibales + pseudo-variables 'flags' - substitution flags (i - ignore case, g - global) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, @@ -297,7 +296,7 @@ if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1$avp(sip_address)\ (match newline don't treat it as end of line). 're' - is regular expresion 'repl' - is replacement string - may contain - pseudo-varibales + pseudo-variables 'flags' - substitution flags (i - ignore case, g - global) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, @@ -328,7 +327,7 @@ if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:$avp(uri_prefix)\1@\2;orig_uri=\ (match newline don't treat it as end of line). 're' - is regular expresion 'repl' - is replacement string - may contain - pseudo-varibales + pseudo-variables 'flags' - substitution flags (i - ignore case, g - global) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, @@ -356,7 +355,7 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$ (match newline don't treat it as end of line). 're' - is regular expresion 'repl' - is replacement string - may contain - pseudo-varibales + pseudo-variables 'flags' - substitution flags (i - ignore case, g - global) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, diff --git a/modules/textops/doc/textops_admin.xml b/modules/textops/doc/textops_admin.xml index 0a01324c762..c07d20dcc09 100644 --- a/modules/textops/doc/textops_admin.xml +++ b/modules/textops/doc/textops_admin.xml @@ -371,7 +371,7 @@ if(has_body() && replace_body_atonce("^.+$", "")) 're' - is regular expresion </para> <para> - 'repl' - is replacement string - may contain pseudo-varibales + 'repl' - is replacement string - may contain pseudo-variables </para> <para> 'flags' - substitution flags (i - ignore case, g - global) @@ -416,7 +416,7 @@ if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1$avp(sip_address)\2/ig') ) 're' - is regular expresion </para> <para> - 'repl' - is replacement string - may contain pseudo-varibales + 'repl' - is replacement string - may contain pseudo-variables </para> <para> 'flags' - substitution flags (i - ignore case, g - global) @@ -463,7 +463,7 @@ if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:$avp(uri_prefix)\1@\2;orig_uri=\0/i')){$ 're' - is regular expresion </para> <para> - 'repl' - is replacement string - may contain pseudo-varibales + 'repl' - is replacement string - may contain pseudo-variables </para> <para> 'flags' - substitution flags (i - ignore case, g - global) @@ -508,7 +508,7 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$ 're' - is regular expresion </para> <para> - 'repl' - is replacement string - may contain pseudo-varibales + 'repl' - is replacement string - may contain pseudo-variables </para> <para> 'flags' - substitution flags (i - ignore case, g - global) diff --git a/modules/textops/textops.c b/modules/textops/textops.c index 1efd3e48769..cfb3e6b7361 100644 --- a/modules/textops/textops.c +++ b/modules/textops/textops.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -97,7 +97,7 @@ static cmd_export_t cmds[]={ fixup_regexp_none,fixup_free_regexp_none, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"search_append_body", (cmd_function)search_append_body_f, 2, - fixup_regexp_none, fixup_free_regexp_none, + fixup_regexp_none, fixup_free_regexp_none, REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"replace", (cmd_function)replace_f, 2, fixup_regexp_none, fixup_free_regexp_none, @@ -132,8 +132,10 @@ static cmd_export_t cmds[]={ struct module_exports exports= { "textops", /* module name*/ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ 0, /* module parameters */ 0, /* exported statistics */ @@ -200,7 +202,7 @@ static int search_append_f(struct sip_msg* msg, char* key, char* str2) if (regexec((regex_t*) key, begin, 1, &pmatch, 0)!=0) return -1; if (pmatch.rm_so!=-1){ - if ((l=anchor_lump(msg, off+pmatch.rm_eo, 0, 0))==0) + if ((l=anchor_lump(msg, off+pmatch.rm_eo, 0))==0) return -1; len=strlen(str2); s=pkg_malloc(len); @@ -208,7 +210,7 @@ static int search_append_f(struct sip_msg* msg, char* key, char* str2) LM_ERR("memory allocation failure\n"); return -1; } - memcpy(s, str2, len); + memcpy(s, str2, len); if (insert_new_lump_after(l, s, len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(s); @@ -237,7 +239,7 @@ static int search_append_body_f(struct sip_msg* msg, char* key, char* str2) if (regexec((regex_t*) key, body.s, 1, &pmatch, 0)!=0) return -1; if (pmatch.rm_so!=-1){ - if ((l=anchor_lump(msg, off+pmatch.rm_eo, 0, 0))==0) + if ((l=anchor_lump(msg, off+pmatch.rm_eo, 0))==0) return -1; len=strlen(str2); s=pkg_malloc(len); @@ -245,7 +247,7 @@ static int search_append_body_f(struct sip_msg* msg, char* key, char* str2) LM_ERR("memory allocation failure\n"); return -1; } - memcpy(s, str2, len); + memcpy(s, str2, len); if (insert_new_lump_after(l, s, len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(s); @@ -273,7 +275,7 @@ static int replace_all_f(struct sip_msg* msg, char* key, char* str2) len=strlen(str2); eflags=0; /* match ^ at the beginning of the string*/ - while (begin<msg->buf+msg->len + while (begin<msg->buf+msg->len && regexec((regex_t*) key, begin, 1, &pmatch, eflags)==0) { off=begin-msg->buf; if (pmatch.rm_so==-1){ @@ -294,7 +296,7 @@ static int replace_all_f(struct sip_msg* msg, char* key, char* str2) LM_ERR("memory allocation failure\n"); return -1; } - memcpy(s, str2, len); + memcpy(s, str2, len); if (insert_new_lump_after(l, s, len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(s); @@ -334,7 +336,7 @@ static int do_replace_body_f(struct sip_msg* msg, char* key, char* str2, int nob len=strlen(str2); eflags=0; /* match ^ at the beginning of the string*/ - while (begin<msg->buf+msg->len + while (begin<msg->buf+msg->len && regexec((regex_t*) key, begin, 1, &pmatch, eflags)==0) { off=begin-msg->buf; if (pmatch.rm_so==-1){ @@ -355,7 +357,7 @@ static int do_replace_body_f(struct sip_msg* msg, char* key, char* str2, int nob LM_ERR("memory allocation failure\n"); return -1; } - memcpy(s, str2, len); + memcpy(s, str2, len); if (insert_new_lump_after(l, s, len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(s); @@ -407,13 +409,13 @@ static int replace_f(struct sip_msg* msg, char* key, char* str2) LM_ERR("memory allocation failure\n"); return -1; } - memcpy(s, str2, len); + memcpy(s, str2, len); if (insert_new_lump_after(l, s, len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(s); return -1; } - + return 1; } return -1; @@ -449,13 +451,13 @@ static int replace_body_f(struct sip_msg* msg, char* key, char* str2) LM_ERR("memory allocation failure\n"); return -1; } - memcpy(s, str2, len); + memcpy(s, str2, len); if (insert_new_lump_after(l, s, len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(s); return -1; } - + return 1; } return -1; @@ -473,7 +475,7 @@ static int subst_f(struct sip_msg* msg, char* subst, char* ignored) int off; int ret; int nmatches; - + se=(struct subst_expr*)subst; begin=get_header(msg); /* start after first line to avoid replacing the uri */ @@ -488,7 +490,7 @@ static int subst_f(struct sip_msg* msg, char* subst, char* ignored) rpl->rpl.len, rpl->rpl.s); if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0) goto error; - /* hack to avoid re-copying rpl, possible because both + /* hack to avoid re-copying rpl, possible because both * replace_lst & lumps use pkg_malloc */ if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0){ LM_ERR("ERROR: %s: subst_f: could not insert new lump\n", @@ -519,7 +521,7 @@ static int subst_uri_f(struct sip_msg* msg, char* subst, char* ignored) char c; struct subst_expr* se; str* result; - + se=(struct subst_expr*)subst; if (msg->new_uri.s){ len=msg->new_uri.len; @@ -548,7 +550,7 @@ static int subst_uri_f(struct sip_msg* msg, char* subst, char* ignored) } return -1; /* false, no subst. made */ } - + /* sed-perl style re: s/regular expression/replacement/flags, like @@ -613,10 +615,10 @@ static int subst_body_f(struct sip_msg* msg, char* subst, char* ignored) LM_DBG("message body has zero length\n"); return -1; } - + se=(struct subst_expr*)subst; begin=body.s; - + off=begin-msg->buf; ret=-1; if ((lst=subst_run(se, begin, msg, &nmatches))==0) @@ -628,7 +630,7 @@ static int subst_body_f(struct sip_msg* msg, char* subst, char* ignored) rpl->rpl.len, rpl->rpl.s); if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0) goto error; - /* hack to avoid re-copying rpl, possible because both + /* hack to avoid re-copying rpl, possible because both * replace_lst & lumps use pkg_malloc */ if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0){ LM_ERR("%s could not insert new lump\n", @@ -660,7 +662,7 @@ static int fixup_substre(void** param, int param_no) subst.len=strlen(*param); se=subst_parser(&subst); if (se==0){ - LM_ERR("%s: bad subst. re %s\n", exports.name, + LM_ERR("%s: bad subst. re %s\n", exports.name, (char*)*param); return E_BAD_RE; } diff --git a/modules/tlsops/README b/modules/tlsops/README index 617db8cf643..62a03e20f64 100644 --- a/modules/tlsops/README +++ b/modules/tlsops/README @@ -10,8 +10,7 @@ Klaus Darilion Copyright © 2006 enum.at Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -381,4 +380,4 @@ Chapter 2. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/tlsops/tls_select.c b/modules/tlsops/tls_select.c index 1ddee7e67e1..0b00a1a8119 100644 --- a/modules/tlsops/tls_select.c +++ b/modules/tlsops/tls_select.c @@ -20,8 +20,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -286,7 +286,7 @@ int tlsops_check_cert(struct sip_msg *msg, pv_param_t *param, LM_CRIT("unexpected parameter value \"%d\"\n", param->pvn.u.isname.name.n); return pv_get_null(msg, param, res); - } + } c = get_cur_connection(msg); if (!c) return -1; @@ -347,7 +347,7 @@ int tlsops_validity(struct sip_msg *msg, pv_param_t *param, LM_ERR("failed to print certificate date/time\n"); goto err; } - + BIO_get_mem_ptr(mem, &p); if (p->length >= 1024) { LM_ERR("Date/time too long\n"); @@ -388,17 +388,17 @@ int tlsops_sn(struct sip_msg *msg, pv_param_t *param, LM_CRIT("could not determine certificate\n"); return pv_get_null(msg, param, res); } - + if (get_cert(&cert, &c, msg, my) < 0) return pv_get_null(msg, param, res); - + serial = ASN1_INTEGER_get(X509_get_serialNumber(cert)); sn = int2str( serial, &res->rs.len); memcpy(buf, sn, res->rs.len); res->rs.s = buf; res->ri = serial; - res->flags = PV_VAL_STR | PV_VAL_INT; - + res->flags = PV_VAL_STR | PV_VAL_INT; + if (!my) X509_free(cert); tcpconn_put(c); return 0; @@ -484,7 +484,7 @@ int tlsops_comp(struct sip_msg *msg, pv_param_t *param, "certificate subject/issuer\n", elem); goto err; } - + e = X509_NAME_get_entry(name, index); asn1 = X509_NAME_ENTRY_get_data(e); text.len = ASN1_STRING_to_UTF8((unsigned char**)(void*)&text.s, asn1); @@ -496,7 +496,7 @@ int tlsops_comp(struct sip_msg *msg, pv_param_t *param, res->rs.s = buf; res->rs.len = text.len; res->flags = PV_VAL_STR; - + OPENSSL_free(text.s); } if (!my) X509_free(cert); diff --git a/modules/tlsops/tls_select.h b/modules/tlsops/tls_select.h index 1b3cb5e597a..0339dc6d8fe 100644 --- a/modules/tlsops/tls_select.h +++ b/modules/tlsops/tls_select.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/tlsops/tlsops.c b/modules/tlsops/tlsops.c index 215c9413023..a56de64bf33 100644 --- a/modules/tlsops/tlsops.c +++ b/modules/tlsops/tlsops.c @@ -15,20 +15,20 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * History: * ------- * 2006-01-26 initial version - * + * * tls module, it implements the following commands: * is_peer_verified(): returns 1 if the message is received via TLS * and the peer was verified during TLS connection handshake, * otherwise it returns -1 - * + * */ #include <stdio.h> @@ -63,7 +63,7 @@ static void mod_destroy(void); * Exported functions */ static cmd_export_t cmds[]={ - {"is_peer_verified", (cmd_function)is_peer_verified, 0, 0, 0, + {"is_peer_verified", (cmd_function)is_peer_verified, 0, 0, 0, REQUEST_ROUTE}, {0,0,0,0,0,0} }; @@ -73,7 +73,7 @@ static cmd_export_t cmds[]={ */ static param_export_t params[] = { {0,0,0} -}; +}; /* * pseudo variables @@ -105,7 +105,7 @@ static pv_export_t mod_items[] = { {{"tls_my_serial", sizeof("tls_my_serial")-1}, 850, tlsops_sn,0, 0, 0, pv_init_iname, CERT_LOCAL }, - /* certificate parameters for peer and local, for subject and issuer*/ + /* certificate parameters for peer and local, for subject and issuer*/ {{"tls_peer_subject", sizeof("tls_peer_subject")-1}, 850, tlsops_comp, 0, 0, 0, pv_init_iname, CERT_PEER | CERT_SUBJECT }, @@ -190,7 +190,7 @@ static pv_export_t mod_items[] = { {{"tls_my_issuer_unit", sizeof("tls_my_issuer_unit")-1}, 850, tlsops_comp, 0, 0, 0, pv_init_iname, CERT_LOCAL | CERT_ISSUER | COMP_OU }, - /* subject alternative name parameters for peer and local */ + /* subject alternative name parameters for peer and local */ {{"tls_peer_san_email", sizeof("tls_peer_san_email")-1}, 850, tlsops_alt, 0, 0, 0, pv_init_iname, CERT_PEER | COMP_E }, @@ -215,7 +215,7 @@ static pv_export_t mod_items[] = { {{"tls_my_san_ip", sizeof("tls_my_san_ip")-1}, 850, tlsops_alt, 0, 0, 0, pv_init_iname, CERT_LOCAL | COMP_IP }, - /* peer certificate validation parameters */ + /* peer certificate validation parameters */ {{"tls_peer_verified", sizeof("tls_peer_verified")-1}, 850, tlsops_check_cert, 0, 0, 0, pv_init_iname, CERT_VERIFIED }, @@ -237,15 +237,17 @@ static pv_export_t mod_items[] = { { {0, 0}, 0, 0, 0, 0, 0, 0, 0 } -}; +}; /* * Module interface */ struct module_exports exports = { - "tlsops", + "tlsops", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -261,7 +263,7 @@ struct module_exports exports = { static int mod_init(void) { LM_DBG("%s module - initializing...\n", exports.name); - + return 0; } @@ -286,7 +288,7 @@ static int is_peer_verified(struct sip_msg* msg, char* foo, char* foo2) } LM_DBG("trying to find TCP connection of received message...\n"); - /* what if we have multiple connections to the same remote socket? e.g. we can have + /* what if we have multiple connections to the same remote socket? e.g. we can have connection 1: localIP1:localPort1 <--> remoteIP:remotePort connection 2: localIP2:localPort2 <--> remoteIP:remotePort but I think the is very unrealistic */ @@ -306,7 +308,7 @@ static int is_peer_verified(struct sip_msg* msg, char* foo, char* foo2) return -1; } - ssl = (SSL *) c->extra_data; + ssl = (SSL *) c->extra_data; ssl_verify = SSL_get_verify_result(ssl); if ( ssl_verify != X509_V_OK ) { @@ -314,7 +316,7 @@ static int is_peer_verified(struct sip_msg* msg, char* foo, char* foo2) tcpconn_put(c); return -1; } - + /* now, we have only valid peer certificates or peers without certificates. * Thus we have to check for the existence of a peer certificate */ @@ -325,11 +327,11 @@ static int is_peer_verified(struct sip_msg* msg, char* foo, char* foo2) tcpconn_put(c); return -1; } - + X509_free(x509_cert); - + tcpconn_put(c); - + LM_DBG("tlsops:is_peer_verified: peer is successfuly verified" "...done\n"); return 1; diff --git a/modules/tlsops/tlsops.h b/modules/tlsops/tlsops.h index 30cd4a09578..288104f085a 100644 --- a/modules/tlsops/tlsops.h +++ b/modules/tlsops/tlsops.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/tm/README b/modules/tm/README index b5eddfffa9b..256e135ffb9 100644 --- a/modules/tm/README +++ b/modules/tm/README @@ -14,12 +14,15 @@ Edited by Bogdan-Andrei Iancu +Edited by + +Ovidiu Sas + Copyright © 2003 FhG FOKUS Copyright © 2005-2008 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -29,7 +32,7 @@ Bogdan-Andrei Iancu 1.1. Overview 1.1.1. Per-Branch flags - 1.1.2. Timer-Based Failover + 1.1.2. Timeout-Based Failover 1.1.3. DNS Failover 1.2. Dependencies @@ -39,8 +42,8 @@ Bogdan-Andrei Iancu 1.3. Exported Parameters - 1.3.1. fr_timer (integer) - 1.3.2. fr_inv_timer (integer) + 1.3.1. fr_timeout (integer) + 1.3.2. fr_inv_timeout (integer) 1.3.3. wt_timer (integer) 1.3.4. delete_timer (integer) 1.3.5. T1_timer (integer) @@ -49,16 +52,14 @@ Bogdan-Andrei Iancu 1.3.8. via1_matching (integer) 1.3.9. unix_tx_timeout (integer) 1.3.10. restart_fr_on_each_reply (integer) - 1.3.11. fr_timer_avp (string) - 1.3.12. fr_inv_timer_avp (string) - 1.3.13. tw_append (string) - 1.3.14. pass_provisional_replies (integer) - 1.3.15. syn_branch (integer) - 1.3.16. onreply_avp_mode (integer) - 1.3.17. disable_6xx_block (integer) - 1.3.18. enable_stats (integer) - 1.3.19. minor_branch_flag (string/integer) - 1.3.20. own_timer_proc (integer) + 1.3.11. tw_append (string) + 1.3.12. pass_provisional_replies (integer) + 1.3.13. syn_branch (integer) + 1.3.14. onreply_avp_mode (integer) + 1.3.15. disable_6xx_block (integer) + 1.3.16. enable_stats (integer) + 1.3.17. minor_branch_flag (string/integer) + 1.3.18. own_timer_proc (integer) 1.4. Exported Functions @@ -85,8 +86,10 @@ Bogdan-Andrei Iancu 1.5.1. $T_branch_idx 1.5.2. $T_reply_code - 1.5.3. $T_ruri - 1.5.4. $bavp(name) + 1.5.3. $T_fr_timeout + 1.5.4. $T_fr_inv_timeout + 1.5.5. $T_ruri + 1.5.6. $bavp(name) 1.6. Exported MI Functions @@ -119,8 +122,8 @@ Bogdan-Andrei Iancu List of Examples - 1.1. Set fr_timer parameter - 1.2. Set fr_inv_timer parameter + 1.1. Set fr_timeout parameter + 1.2. Set fr_inv_timeout parameter 1.3. Set wt_timer parameter 1.4. Set delete_timer parameter 1.5. Set T1_timer parameter @@ -129,32 +132,30 @@ Bogdan-Andrei Iancu 1.8. Set via1_matching parameter 1.9. Set unix_tx_timeout parameter 1.10. Set restart_fr_on_each_reply parameter - 1.11. Set fr_timer_avp parameter - 1.12. Set fr_inv_timer_avp parameter - 1.13. Set tw_append parameter - 1.14. Set pass_provisional_replies parameter - 1.15. Set syn_branch parameter - 1.16. Set onreply_avp_mode parameter - 1.17. Set disable_6xx_block parameter - 1.18. Set enable_stats parameter - 1.19. Set minor_branch_flag parameter - 1.20. Set own_timer_proc parameter - 1.21. t_newtran usage - 1.22. t_relay usage - 1.23. t_relay usage - 1.24. t_reply usage - 1.25. t_reply_with_body usage - 1.26. t_replicate usage - 1.27. t_check_status usage - 1.28. t_flush_flags usage - 1.29. t_local_replied usage - 1.30. t_write_req/unix usage - 1.31. t_check_trans usage - 1.32. t_was_cancelled usage - 1.33. t_cancel_branch usage - 1.34. t_on_failure usage - 1.35. t_on_reply usage - 1.36. t_on_branch usage + 1.11. Set tw_append parameter + 1.12. Set pass_provisional_replies parameter + 1.13. Set syn_branch parameter + 1.14. Set onreply_avp_mode parameter + 1.15. Set disable_6xx_block parameter + 1.16. Set enable_stats parameter + 1.17. Set minor_branch_flag parameter + 1.18. Set own_timer_proc parameter + 1.19. t_newtran usage + 1.20. t_relay usage + 1.21. t_relay usage + 1.22. t_reply usage + 1.23. t_reply_with_body usage + 1.24. t_replicate usage + 1.25. t_check_status usage + 1.26. t_flush_flags usage + 1.27. t_local_replied usage + 1.28. t_write_req/unix usage + 1.29. t_check_trans usage + 1.30. t_was_cancelled usage + 1.31. t_cancel_branch usage + 1.32. t_on_failure usage + 1.33. t_on_reply usage + 1.34. t_on_branch usage Chapter 1. Admin Guide @@ -245,29 +246,31 @@ Chapter 1. Admin Guide REGISTRAR module was the first to use this type of flags. The NAT flag is pushed in branch flags instead in message flags -1.1.2. Timer-Based Failover +1.1.2. Timeout-Based Failover - Timers can be used to trigger failover behavior. E.g. if we - send a call a gateway and the gateway does not send a + Timeouts can be used to trigger failover behavior. E.g. if we + send a call to a gateway and the gateway does not send a provisional response within 3 seconds, we want to cancel this call and send the call to another gateway. Another example is to ring a SIP client only for 30 seconds and then redirect the call to the voicemail. - There are two timers in OpenSIPS : - * fr_timer - this timer is used when no response was received - yet. If there is no response after fr_timer seconds the - timer triggers (and failure route will be executed if - t_on_failure() was called). If a provisional response was - received, the timer is set to fr_inv_timer for INVITE - transactions, and RT_T2 for all other transactions. If a - final reponse is received, the transaction has finished. - * fr_inv_timer - this timer is used when a provisional - reponse was received for an INVITE transaction. + The transaction module exports two types of timeouts: + * fr_timeout - used when no response was received yet. If + there is no response after fr_timeout seconds, the timer + triggers (and failure route will be executed if + t_on_failure() was called). For INVITE transactions, if a + provisional response was received, the timeout is reset to + fr_inv_timeout seconds and RT_T2 for all other + transactions. Once a final response is received, the + transaction has finished. + * fr_inv_timeout - this timeout starts counting down once a + provisional response was received for an INVITE + transaction. For example: You want to have failover if there is no provisional response after 3 seconds, but you want to ring for - 60 seconds. Thuse, set the fr_timer to 3 and fr_inv_timer to + 60 seconds. Thus, set the fr_timeout to 3 and fr_inv_timeout to 60. 1.1.3. DNS Failover @@ -313,31 +316,32 @@ Chapter 1. Admin Guide 1.3. Exported Parameters -1.3.1. fr_timer (integer) +1.3.1. fr_timeout (integer) - Timer which hits if no final reply for a request or ACK for a - negative INVITE reply arrives (in seconds). + Timeout which is triggered if no final reply for a request or + ACK for a negative INVITE reply arrives (in seconds). Default value is 30 seconds. - Example 1.1. Set fr_timer parameter + Example 1.1. Set fr_timeout parameter ... -modparam("tm", "fr_timer", 10) +modparam("tm", "fr_timeout", 10) ... -1.3.2. fr_inv_timer (integer) +1.3.2. fr_inv_timeout (integer) - Timer which hits if no final reply for an INVITE arrives after - a provisional message was received (in seconds). This timer is - started after the first provisional response. Thus, fast - failover (no 100 trying from gateway) can be achieved by - setting fr_timer to low values. See example below + Timeout which is triggered if no final reply for an INVITE + arrives after a provisional message was received (in seconds). + This timeout starts counting down once the first provisional + response is received. Thus, fast failover (no 100 trying from + gateway) can be achieved by setting fr_timeout to low values. + See example below. Default value is 120 seconds. - Example 1.2. Set fr_inv_timer parameter + Example 1.2. Set fr_inv_timeout parameter ... -modparam("tm", "fr_inv_timer", 200) +modparam("tm", "fr_inv_timeout", 200) ... 1.3.3. wt_timer (integer) @@ -440,8 +444,8 @@ modparam("tm", "unix_tx_timeout", 5) If true (non null value), the final response timer will be re-triggered for each received provisional reply. In this case, - final response timeout may occure after a time longe than - fr_inv_timer (if UAS keeps sending provisional replies) + final response timeout may occure after a time longer than + fr_inv_timeout (if UAS keeps sending provisional replies) Default value is 1 (true). @@ -450,39 +454,7 @@ modparam("tm", "unix_tx_timeout", 5) modparam("tm", "restart_fr_on_each_reply", 0) ... -1.3.11. fr_timer_avp (string) - - Full specification (NAME, ID, Alias) of an AVP which contains a - final response timeout value. If present, ths value will - override the static fr_timer parameter. - - If set to empty string, the whole mechanism for variable - timeout will be disabled, falling back to the static value. - - Default value is "NULL" (feature disabled). - - Example 1.11. Set fr_timer_avp parameter -... -modparam("tm", "fr_timer_avp", "$avp(i:24)") -... - -1.3.12. fr_inv_timer_avp (string) - - Full specification (NAME, ID, Alias) of an AVP which contains a - final INVITE response timeout value. If present, ths value will - overeide the static fr_inv_timer parameter. - - If set to empty string, the whole mechanism for variable - timeout will be disabled, falling back to the static value. - - Default value is "NULL" (feature disabled). - - Example 1.12. Set fr_inv_timer_avp parameter -... -modparam("tm", "fr_inv_timer_avp", "$avp(i:25)") -... - -1.3.13. tw_append (string) +1.3.11. tw_append (string) List of additional information to be appended by t_write_req and t_write_unix functions. @@ -502,37 +474,37 @@ modparam("tm", "fr_inv_timer_avp", "$avp(i:25)") accept name; the body it will be printed all the time at the end, disregarding its position in the definition string. - Example 1.13. Set tw_append parameter + Example 1.11. Set tw_append parameter ... modparam("tm", "tw_append", - "test: ua=$hdr(User-Agent) ;avp=$avp(i:10);$rb;time=$Ts") + "test: ua=$hdr(User-Agent) ;avp=$avp(avp);$rb;time=$Ts") ... -1.3.14. pass_provisional_replies (integer) +1.3.12. pass_provisional_replies (integer) Enable/disable passing of provisional replies to FIFO applications. Default value is 0. - Example 1.14. Set pass_provisional_replies parameter + Example 1.12. Set pass_provisional_replies parameter ... modparam("tm", "pass_provisional_replies", 1) ... -1.3.15. syn_branch (integer) +1.3.13. syn_branch (integer) Enable/disable the usage of stateful synonym branch IDs in the generated Via headers. They are faster but not reboot-safe. Default value is 1 (use synonym branches). - Example 1.15. Set syn_branch parameter + Example 1.13. Set syn_branch parameter ... modparam("tm", "syn_branch", 0) ... -1.3.16. onreply_avp_mode (integer) +1.3.14. onreply_avp_mode (integer) Describes how the AVPs should be handled in reply route: * 0 - the AVPs will be per message only; they will not @@ -551,12 +523,12 @@ modparam("tm", "syn_branch", 0) Default value is 0. - Example 1.16. Set onreply_avp_mode parameter + Example 1.14. Set onreply_avp_mode parameter ... modparam("tm", "onreply_avp_mode", 1) ... -1.3.17. disable_6xx_block (integer) +1.3.15. disable_6xx_block (integer) Tells how the 6xx replies should be internally handled: * 0 - the 6xx replies will block any further serial forking @@ -568,12 +540,12 @@ modparam("tm", "onreply_avp_mode", 1) Default value is 0. - Example 1.17. Set disable_6xx_block parameter + Example 1.15. Set disable_6xx_block parameter ... modparam("tm", "disable_6xx_block", 1) ... -1.3.18. enable_stats (integer) +1.3.16. enable_stats (integer) Enables statistics support in TM module - If enabled, the TM module will internally keep several statistics and export them @@ -581,12 +553,12 @@ modparam("tm", "disable_6xx_block", 1) Default value is 1 (enabled). - Example 1.18. Set enable_stats parameter + Example 1.16. Set enable_stats parameter ... modparam("tm", "enable_stats", 0) ... -1.3.19. minor_branch_flag (string/integer) +1.3.17. minor_branch_flag (string/integer) A branch flag index to be used in script to mark the minor branches ( before t_relay() ). @@ -604,26 +576,30 @@ modparam("tm", "enable_stats", 0) Default value is none (disabled). - Example 1.19. Set minor_branch_flag parameter + Example 1.17. Set minor_branch_flag parameter ... modparam("tm", "minor_branch_flag", "MINOR_BFLAG") ... -1.3.20. own_timer_proc (integer) +1.3.18. own_timer_proc (integer) - If TM module should create its own timer process (timer is used - for handling retransmissions, timeouts, etc). If disabled, TM - will used the global timer process which may be affected + If TM module should create its own timer process(es) (timer is + used for handling retransmissions, timeouts, etc). If disabled, + TM will used the global timer process which may be affected (desynchronized) by the operations performed by other modules on that timer (like usrloc flushing memory cash into DB). So, on system with high load, to keep accuracy for the TM timer, better enabled this. + The value of the parameter will set the number of timer + processes. + Default value is 0 (disabled). - Example 1.20. Set own_timer_proc parameter + Example 1.18. Set own_timer_proc parameter ... -modparam("tm", "own_timer_proc", 1) +# Enable two timer processes +modparam("tm", "own_timer_proc", 2) ... 1.4. Exported Functions @@ -641,7 +617,7 @@ Warning This function can be used from REQUEST_ROUTE. - Example 1.21. t_newtran usage + Example 1.19. t_newtran usage ... if (t_newtran()) { log("UAS logic"); @@ -700,7 +676,7 @@ if (t_newtran()) { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.22. t_relay usage + Example 1.20. t_relay usage ... if (!t_relay()) { sl_reply_error(); @@ -713,8 +689,8 @@ if (!t_relay()) { Relay a message statefully to a fixed destination. The destination is specified as “[proto:]host[:port]”. If a destination URI “$du” for this message was set before the - function is called then this value will be used as destination - instead of the function parameter. + function is called then this value will be used as the + destination instead of the function parameter. The function may take as parameter an optional set of flags for controlling the internal behaviour - for details see the above @@ -722,7 +698,7 @@ if (!t_relay()) { This functions can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.23. t_relay usage + Example 1.21. t_relay usage ... t_relay("tcp:192.168.1.10:5060"); t_relay("mydomain.com:5070","0x1"); @@ -742,7 +718,7 @@ t_relay("udp:mydomain.com"); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.24. t_reply usage + Example 1.22. t_reply usage ... t_reply("404", "Use $rU not found"); ... @@ -761,12 +737,12 @@ t_reply("404", "Use $rU not found"); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.25. t_reply_with_body usage + Example 1.23. t_reply_with_body usage ... if(is_method("INVITE")) { - append_to_reply("Contact: $var(contact)\r\nContent-Type: - application/sdp\r\n"); + append_to_reply("Contact: $var(contact)\r\n" + "Content-Type: application/sdp\r\n"); t_reply_with_body("200", "Ok", "$var(body)"); exit; } @@ -789,7 +765,7 @@ t_reply("404", "Use $rU not found"); This functions can be used from REQUEST_ROUTE. - Example 1.26. t_replicate usage + Example 1.24. t_replicate usage ... t_replicate("sip:1.2.3.4:5060"); t_replicate("sip:1.2.3.4:5060;transport=tcp"); @@ -808,7 +784,7 @@ t_replicate("sip:1.2.3.4","0x4"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE . - Example 1.27. t_check_status usage + Example 1.25. t_check_status usage ... if (t_check_status("(487)|(408)")) { log("487 or 408 negative reply\n"); @@ -824,7 +800,7 @@ if (t_check_status("(487)|(408)")) { This function can be used from REQUEST_ROUTE and BRANCH_ROUTE . - Example 1.28. t_flush_flags usage + Example 1.26. t_flush_flags usage ... t_flush_flags(); ... @@ -839,7 +815,7 @@ t_flush_flags(); This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, FAILURE_ROUTE and ONREPLY_ROUTE. - Example 1.29. t_local_replied usage + Example 1.27. t_local_replied usage ... if (t_local_replied("all")) { log ("no reply received\n"); @@ -855,10 +831,10 @@ if (t_local_replied("all")) { This functions can be used from REQUEST_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.30. t_write_req/unix usage + Example 1.28. t_write_req/unix usage ... -modparam("tm","tw_append","append1:Email=avp[i:12];UA=hdr[User-Agent]") -modparam("tm","tw_append","append2:body=msg[body]") +modparam("tm","tw_append","append1:Email=$avp(email);UA=$ua") +modparam("tm","tw_append","append2:body=$rb") ... t_write_req("voicemail/append1","/tmp/appx_fifo"); ... @@ -869,11 +845,11 @@ t_write_unix("logger/append2","/var/run/logger.sock"); Returns true if the current request is associated to a transaction. The relationship between the request and - transaction is defined as follow: + transaction is defined as follows: * non-CANCEL/non-ACK requests - if the request belongs to a transaction (it's a retransmision), the function will do a standard processing of the retransmission and will - break/stop the script. The function return false if the + break/stop the script. The function returns false if the request is not a retransmission. * CANCEL request - true if the cancelled INVITE transaction exists. @@ -889,7 +865,7 @@ t_write_unix("logger/append2","/var/run/logger.sock"); This function can be used from REQUEST_ROUTE and BRANCH_ROUTE. - Example 1.31. t_check_trans usage + Example 1.29. t_check_trans usage ... if ( is_method("CANCEL") ) { if ( t_check_trans() ) @@ -905,7 +881,7 @@ if ( is_method("CANCEL") ) { This function can be used from ONREPLY_ROUTE, FAILURE_ROUTE. - Example 1.32. t_was_cancelled usage + Example 1.30. t_was_cancelled usage ... if (t_was_cancelled()) { log("transaction was cancelled by UAC\n"); @@ -927,7 +903,7 @@ if (t_was_cancelled()) { This function can be used from ONREPLY_ROUTE. - Example 1.33. t_cancel_branch usage + Example 1.31. t_cancel_branch usage onreply_route[3] { ... if (t_check_status("183")) { @@ -964,7 +940,7 @@ onreply_route[3] { This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, ONREPLY_ROUTE and FAILURE_ROUTE. - Example 1.34. t_on_failure usage + Example 1.32. t_on_failure usage ... route { t_on_failure("1"); @@ -1013,7 +989,7 @@ failure_route[1] { This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, ONREPLY_ROUTE and FAILURE_ROUTE. - Example 1.35. t_on_reply usage + Example 1.33. t_on_reply usage ... route { seturi("sip:bob@opensips.org"); # first branch @@ -1070,7 +1046,7 @@ onreply_route[global] { This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, ONREPLY_ROUTE and FAILURE_ROUTE. - Example 1.36. t_on_branch usage + Example 1.34. t_on_branch usage ... route { t_on_branch("1"); @@ -1108,14 +1084,34 @@ branch_route[1] { failure_route will be the negative winning reply. In case of no-reply or error, '0' value is returned. -1.5.3. $T_ruri +1.5.3. $T_fr_timeout + + $T_fr_timeout (R/W) - the timeout for the final reply to the + current transaction + + With each different request received, $T_fr_timeout will + initially be equal to the fr_timeout parameter. + + "$T_fr_timeout = NULL;" will reset it to fr_timeout. + +1.5.4. $T_fr_inv_timeout + + $T_fr_inv_timeout (R/W) - the timeout for the final reply to an + INVITE request, after a 1XX reply was received + + With each different request received, $T_fr_inv_timeout will + initially be equal to the fr_inv_timeout parameter. + + "$T_fr_inv_timeout = NULL;" will reset it to fr_inv_timeout. + +1.5.5. $T_ruri $T_ruri - the ruri of the current branch; this information is taken from the transaction structure, so you can access this information for any sip message (request/reply) that has a transaction. -1.5.4. $bavp(name) +1.5.6. $bavp(name) $bavp(name) - a particular type of avp that can have different values for each branch. They can only be used in BRANCH, REPLY @@ -1248,4 +1244,4 @@ Chapter 3. Frequently Asked Questions How can I report a bug? Please follow the guidelines provided at: - http://sourceforge.net/tracker/?group_id=232389. + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/tm/callid.c b/modules/tm/callid.c index 5e0f9e92785..efd64027dbb 100644 --- a/modules/tm/callid.c +++ b/modules/tm/callid.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -65,7 +65,7 @@ int init_callid(void) int rand_bits, i; /* calculate the initial call-id */ - /* how many bits and chars do we need to display the + /* how many bits and chars do we need to display the * whole ULONG number */ callid_prefix.len = sizeof(unsigned long) * 2; callid_prefix.s = callid_buf; @@ -74,7 +74,7 @@ int init_callid(void) LM_ERR("too small callid buffer\n"); return -1; } - + for(rand_bits = 1, i = RAND_MAX; i; i >>= 1, rand_bits++); /* how long are the rand()s ? */ i = callid_prefix.len * 4 / rand_bits; /* how many rands() fit in the ULONG ? */ @@ -92,7 +92,7 @@ int init_callid(void) LM_CRIT("callid calculation failed\n"); return -2; } - + LM_DBG("Call-ID initialization: '%.*s'\n", callid_prefix.len, callid_prefix.s); return 0; } @@ -101,10 +101,10 @@ int init_callid(void) /* * Child initialization -- generates suffix */ -int child_init_callid(int rank) +int child_init_callid(int rank) { struct socket_info *si; - + /* on tcp/tls bind_address is 0 so try to get the first address we listen * on no matter the protocol */ si=bind_address?bind_address:get_first_socket(); @@ -115,7 +115,7 @@ int child_init_callid(int rank) callid_suffix.s = callid_buf + callid_prefix.len; callid_suffix.len = snprintf(callid_suffix.s, CALLID_SUFFIX_LEN, - "%c%d@%.*s", CID_SEP, my_pid(), + "%c%d@%.*s", CID_SEP, my_pid(), si->address_str.len, si->address_str.s); if ((callid_suffix.len == -1) || (callid_suffix.len > CALLID_SUFFIX_LEN)) { diff --git a/modules/tm/callid.h b/modules/tm/callid.h index 4beb38c28ad..e7bb5131c5f 100644 --- a/modules/tm/callid.h +++ b/modules/tm/callid.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/tm/config.h b/modules/tm/config.h index 26661f03d85..4a53029c5de 100644 --- a/modules/tm/config.h +++ b/modules/tm/config.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -51,7 +51,7 @@ /* DELETE timer ... tells how long should the transaction persist in memory after it was removed from the hash table and before it will be deleted */ #define DEL_TIME_OUT 2 - + /* retransmission timers */ #define RETR_T1 500 /* in milliseconds */ #define RETR_T2 4000 /* in milliseconds */ diff --git a/modules/tm/dlg.c b/modules/tm/dlg.c index c1fbd3bc05f..cc2f40572a3 100644 --- a/modules/tm/dlg.c +++ b/modules/tm/dlg.c @@ -70,7 +70,7 @@ void get_raw_uri(str* _s) { char* aq; - + if (_s->s[_s->len - 1] == '>') { aq = find_not_quoted(_s, '<'); _s->len -= aq - _s->s + 2; @@ -155,9 +155,9 @@ static int _internal_new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* return -2; } - /* Clear everything */ + /* Clear everything */ memset(res, 0, sizeof(dlg_t)); - + /* Make a copy of Call-ID */ if (shm_str_dup(&res->id.call_id, _cid) < 0) return -3; /* Make a copy of local tag (usually From tag) */ @@ -181,7 +181,7 @@ static int _internal_new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* shm_free(res); return -2; } - + return 0; } @@ -329,7 +329,7 @@ static inline int get_route_set(struct sip_msg* _m, rr_t** _rs, unsigned char _o { struct hdr_field* ptr; rr_t* last, *p, *t; - + last = 0; *_rs = 0; @@ -358,11 +358,11 @@ static inline int get_route_set(struct sip_msg* _m, rr_t** _rs, unsigned char _o p = p->next; } - + } ptr = ptr->next; } - + return 0; error: @@ -384,13 +384,13 @@ static inline int response2dlg(struct sip_msg* _m, dlg_t* _d) LM_ERR("failed to parse headers\n"); return -1; } - + if (get_contact_uri(_m, &contact) < 0) return -2; if (contact.len && shm_str_dup(&_d->rem_target, &contact) < 0) return -3; - + if (get_to_tag(_m, &rtag) < 0) goto err1; if (rtag.len && shm_str_dup(&_d->id.rem_tag, &rtag) < 0) goto err1; - + if (get_route_set(_m, &_d->route_set, REVERSE_ORDER) < 0) goto err2; return 0; @@ -416,9 +416,9 @@ static inline int dlg_new_resp_uac(dlg_t* _d, struct sip_msg* _m) int code; /* * Dialog is in DLG_NEW state, we will copy remote - * target URI, remote tag if present, and route-set - * if present. And we will transit into DLG_CONFIRMED - * if the response was 2xx and to DLG_DESTROYED if the + * target URI, remote tag if present, and route-set + * if present. And we will transit into DLG_CONFIRMED + * if the response was 2xx and to DLG_DESTROYED if the * request was a negative final response. */ @@ -442,7 +442,7 @@ static inline int dlg_new_resp_uac(dlg_t* _d, struct sip_msg* _m) return -2; } } else { - /* + /* * A negative final response, mark the dialog as destroyed * Again, I do not update the structures here because it * makes no sense to me, a dialog shouldn't be used after @@ -464,7 +464,7 @@ static inline int dlg_new_resp_uac(dlg_t* _d, struct sip_msg* _m) static inline int dlg_early_resp_uac(dlg_t* _d, struct sip_msg* _m) { int code; - code = _m->first_line.u.reply.statuscode; + code = _m->first_line.u.reply.statuscode; if (code < 200) { /* We are in early state already, do nothing @@ -522,7 +522,7 @@ static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m) /* Dialog has been already confirmed, that means we received * a response to a request sent within the dialog. We will * update remote target URI if and only if the message sent was - * a target refresher. + * a target refresher. */ /* FIXME: Currently we support only INVITEs as target refreshers, @@ -639,7 +639,7 @@ static inline int get_dlg_uri(struct hdr_field* _h, str* _s) /* From was already parsed when extracting tag * and To is parsed by default */ - + body = (struct to_body*)_h->parsed; ptr = body->param_lst; @@ -657,7 +657,7 @@ static inline int get_dlg_uri(struct hdr_field* _h, str* _s) } else { tag = body->body.s + body->body.len; } - + if (ptr->next) { tag_len = ptr->value.s + ptr->value.len - tag; } else { @@ -686,7 +686,7 @@ static inline int get_dlg_uri(struct hdr_field* _h, str* _s) /* - * Extract all information from a request + * Extract all information from a request * and update a dialog structure */ static inline int request2dlg(struct sip_msg* _m, dlg_t* _d) @@ -700,7 +700,7 @@ static inline int request2dlg(struct sip_msg* _m, dlg_t* _d) if (get_contact_uri(_m, &contact) < 0) return -2; if (contact.len && shm_str_dup(&_d->rem_target, &contact) < 0) return -3; - + if (get_from_tag(_m, &rtag) < 0) goto err1; if (rtag.len && shm_str_dup(&_d->id.rem_tag, &rtag) < 0) goto err1; @@ -713,7 +713,7 @@ static inline int request2dlg(struct sip_msg* _m, dlg_t* _d) if (get_dlg_uri(_m->from, &_d->rem_uri) < 0) goto err3; if (get_dlg_uri(_m->to, &_d->loc_uri) < 0) goto err4; - if (get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0) goto err5; + if (get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0) goto err5; return 0; err5: @@ -764,7 +764,7 @@ int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d) return -3; } /* Clear everything */ - memset(res, 0, sizeof(dlg_t)); + memset(res, 0, sizeof(dlg_t)); if (request2dlg(_req, res) < 0) { LM_ERR("converting request to dialog failed\n"); @@ -778,7 +778,7 @@ int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d) free_dlg(res); return -5; } - + *_d = res; (*_d)->state = DLG_CONFIRMED; @@ -818,8 +818,8 @@ int dlg_request_uas(dlg_t* _d, struct sip_msg* _m) /* Neither out of order nor retransmission -> update */ _d->rem_seq.value = cseq; _d->rem_seq.is_set = 1; - - /* We will als update remote target URI if the message + + /* We will als update remote target URI if the message * is target refresher */ if (_m->first_line.u.request.method_value == METHOD_INVITE) { @@ -828,7 +828,7 @@ int dlg_request_uas(dlg_t* _d, struct sip_msg* _m) LM_ERR("parsing headers failed\n"); return -4; } - + if (get_contact_uri(_m, &contact) < 0) return -5; if (contact.len) { if (_d->rem_target.s) shm_free(_d->rem_target.s); @@ -863,7 +863,7 @@ int calculate_routeset_length(dlg_t* _d) } if (_d->hooks.last_route) { - if (_d->hooks.first_route) + if (_d->hooks.first_route) len += ROUTE_SEPARATOR_LEN; len += _d->hooks.last_route->len + 2; /* < > */ } @@ -974,18 +974,18 @@ void print_dlg(FILE* out, dlg_t* _d) case DLG_DESTROYED: fprintf(out, "DLG_DESTROYED\n"); break; } print_rr(out, _d->route_set); - if (_d->hooks.request_uri) + if (_d->hooks.request_uri) fprintf(out, "hooks.request_uri: '%.*s'\n", _d->hooks.request_uri->len, _d->hooks.request_uri->s); - if (_d->hooks.next_hop) + if (_d->hooks.next_hop) fprintf(out, "hooks.next_hop : '%.*s'\n", _d->hooks.next_hop->len, _d->hooks.next_hop->s); - if (_d->hooks.first_route) + if (_d->hooks.first_route) fprintf(out, "hooks.first_route: '%.*s'\n", _d->hooks.first_route->len,_d->hooks.first_route->nameaddr.name.s); if (_d->hooks.last_route) fprintf(out, "hooks.last_route : '%.*s'\n", _d->hooks.last_route->len, _d->hooks.last_route->s); - + fprintf(out, "====dlg_t====\n"); } diff --git a/modules/tm/dlg.h b/modules/tm/dlg.h index a986dd5fd07..608393ba29e 100644 --- a/modules/tm/dlg.h +++ b/modules/tm/dlg.h @@ -105,6 +105,7 @@ typedef struct dlg { * prevent repeated analyzing of the dialog data */ struct socket_info* send_sock; + struct usr_avp *avps; } dlg_t; diff --git a/modules/tm/doc/tm.xml b/modules/tm/doc/tm.xml index 3f1a95e1881..3ed1b4fc9bc 100644 --- a/modules/tm/doc/tm.xml +++ b/modules/tm/doc/tm.xml @@ -47,6 +47,13 @@ <email>bogdan@opensips.org</email> </address> </editor> + <editor> + <firstname>Ovidiu</firstname> + <surname>Sas</surname> + <address> + <email>osas@voipembedded.com</email> + </address> + </editor> </authorgroup> <copyright> <year>2003</year> diff --git a/modules/tm/doc/tm_admin.xml b/modules/tm/doc/tm_admin.xml index d9f0ab8b690..c38515c91d7 100644 --- a/modules/tm/doc/tm_admin.xml +++ b/modules/tm/doc/tm_admin.xml @@ -115,41 +115,42 @@ </para> </section> <section id="timer-based-failover"> - <title>Timer-Based Failover + Timeout-Based Failover - Timers can be used to trigger failover behavior. E.g. if we send a call - a gateway and the gateway does not send a provisional response within 3 + Timeouts can be used to trigger failover behavior. E.g. if we send a call + to a gateway and the gateway does not send a provisional response within 3 seconds, we want to cancel this call and send the call to another gateway. Another example is to ring a SIP client only for 30 seconds and then redirect the call to the voicemail. - There are two timers in &osips; : + The transaction module exports two types of timeouts: - fr_timer - this timer is used when - no response was received yet. If there is no response after - fr_timer seconds the timer triggers + fr_timeout - used when no response was + received yet. If there is no response after + fr_timeout seconds, the timer triggers (and failure route will be executed if t_on_failure() was - called). If a provisional response was received, the timer - is set to fr_inv_timer for INVITE transactions, and RT_T2 - for all other transactions. If a final reponse is received, - the transaction has finished. + called). For INVITE transactions, if a provisional response was + received, the timeout is reset to fr_inv_timeout + seconds and RT_T2 for all other transactions. Once a final response + is received, the transaction has finished. - fr_inv_timer - this timer is used when - a provisional reponse was received for an INVITE transaction. + fr_inv_timeout - this timeout + starts counting down once a provisional response was received + for an INVITE transaction. For example: You want to have failover if there is no provisional response after 3 seconds, but you want to ring for 60 seconds. - Thuse, set the fr_timer to 3 and fr_inv_timer to 60. + Thus, set the fr_timeout to 3 and fr_inv_timeout to 60.
@@ -219,10 +220,10 @@
Exported Parameters -
- <varname>fr_timer</varname> (integer) +
+ <varname>fr_timeout</varname> (integer) - Timer which hits if no final reply for a request or ACK for a + Timeout which is triggered if no final reply for a request or ACK for a negative INVITE reply arrives (in seconds). @@ -231,24 +232,23 @@ - Set <varname>fr_timer</varname> parameter + Set <varname>fr_timeout</varname> parameter ... -modparam("tm", "fr_timer", 10) +modparam("tm", "fr_timeout", 10) ...
-
- <varname>fr_inv_timer</varname> (integer) +
+ <varname>fr_inv_timeout</varname> (integer) - Timer which hits if no final reply for an INVITE arrives after a - provisional message was received (in seconds). This timer is started - after the first provisional response. Thus, fast failover (no 100 - trying from gateway) can be achieved by setting fr_timer to low - values. See example below - + Timeout which is triggered if no final reply for an INVITE arrives after a + provisional message was received (in seconds). This timeout starts + counting down once the first provisional response is received. Thus, + fast failover (no 100 trying from gateway) can be achieved by setting + fr_timeout to low values. See example below. @@ -256,10 +256,10 @@ modparam("tm", "fr_timer", 10) - Set <varname>fr_inv_timer</varname> parameter + Set <varname>fr_inv_timeout</varname> parameter ... -modparam("tm", "fr_inv_timer", 200) +modparam("tm", "fr_inv_timeout", 200) ... @@ -428,8 +428,8 @@ modparam("tm", "unix_tx_timeout", 5) If true (non null value), the final response timer will be re-triggered for each received provisional reply. In this case, final response - timeout may occure after a time longe than fr_inv_timer (if UAS keeps - sending provisional replies) + timeout may occure after a time longer than fr_inv_timeout + (if UAS keeps sending provisional replies) @@ -446,58 +446,6 @@ modparam("tm", "restart_fr_on_each_reply", 0)
-
- <varname>fr_timer_avp</varname> (string) - - Full specification (NAME, ID, Alias) of an AVP which contains a final - response timeout value. If present, ths value will override the - static fr_timer parameter. - - - If set to empty string, the whole mechanism for variable timeout will - be disabled, falling back to the static value. - - - - Default value is "NULL" (feature disabled). - - - - Set <varname>fr_timer_avp</varname> parameter - -... -modparam("tm", "fr_timer_avp", "$avp(i:24)") -... - - -
- -
- <varname>fr_inv_timer_avp</varname> (string) - - Full specification (NAME, ID, Alias) of an AVP which contains a final - INVITE response timeout value. If present, ths value will overeide the - static fr_inv_timer parameter. - - - If set to empty string, the whole mechanism for variable timeout will - be disabled, falling back to the static value. - - - - Default value is "NULL" (feature disabled). - - - - Set <varname>fr_inv_timer_avp</varname> parameter - -... -modparam("tm", "fr_inv_timer_avp", "$avp(i:25)") -... - - -
-
<varname>tw_append</varname> (string) @@ -538,7 +486,7 @@ modparam("tm", "fr_inv_timer_avp", "$avp(i:25)") ... modparam("tm", "tw_append", - "test: ua=$hdr(User-Agent) ;avp=$avp(i:10);$rb;time=$Ts") + "test: ua=$hdr(User-Agent) ;avp=$avp(avp);$rb;time=$Ts") ... @@ -715,7 +663,7 @@ modparam("tm", "minor_branch_flag", "MINOR_BFLAG")
<varname>own_timer_proc</varname> (integer) - If TM module should create its own timer process (timer is used for + If TM module should create its own timer process(es) (timer is used for handling retransmissions, timeouts, etc). If disabled, TM will used the global timer process which may be affected (desynchronized) by the operations performed by other modules on that timer (like usrloc @@ -723,6 +671,9 @@ modparam("tm", "minor_branch_flag", "MINOR_BFLAG") accuracy for the TM timer, better enabled this. + The value of the parameter will set the number of timer processes. + + Default value is 0 (disabled). @@ -731,7 +682,8 @@ modparam("tm", "minor_branch_flag", "MINOR_BFLAG") Set <varname>own_timer_proc</varname> parameter ... -modparam("tm", "own_timer_proc", 1) +# Enable two timer processes +modparam("tm", "own_timer_proc", 2) ... @@ -887,7 +839,7 @@ if (!t_relay()) { Relay a message statefully to a fixed destination. The destination is specified as [proto:]host[:port]. If a destination URI $du for this message was set before the function - is called then this value will be used as destination instead of the + is called then this value will be used as the destination instead of the function parameter. @@ -981,7 +933,8 @@ t_reply("404", "Use $rU not found"); ... if(is_method("INVITE")) { - append_to_reply("Contact: $var(contact)\r\nContent-Type: application/sdp\r\n"); + append_to_reply("Contact: $var(contact)\r\n" + "Content-Type: application/sdp\r\n"); t_reply_with_body("200", "Ok", "$var(body)"); exit; } @@ -1133,8 +1086,8 @@ if (t_local_replied("all")) { <function>t_write_req/unix</function> usage ... -modparam("tm","tw_append","append1:Email=avp[i:12];UA=hdr[User-Agent]") -modparam("tm","tw_append","append2:body=msg[body]") +modparam("tm","tw_append","append1:Email=$avp(email);UA=$ua") +modparam("tm","tw_append","append2:body=$rb") ... t_write_req("voicemail/append1","/tmp/appx_fifo"); ... @@ -1151,14 +1104,14 @@ t_write_unix("logger/append2","/var/run/logger.sock"); Returns true if the current request is associated to a transaction. The relationship between the request and transaction is defined as - follow: + follows: non-CANCEL/non-ACK requests - if the request belongs to a transaction (it's a retransmision), the function will do a standard processing of the retransmission and - will break/stop the script. The function return false if the + will break/stop the script. The function returns false if the request is not a retransmission. @@ -1501,10 +1454,45 @@ branch_route[1] {
+ $T_fr_timeout + + $T_fr_timeout (R/W) - the timeout + for the final reply to the current transaction + + + With each different + request received, $T_fr_timeout will initially + be equal to the + parameter. + + + "$T_fr_timeout = NULL;" will reset it to + . + +
+
+ $T_fr_inv_timeout + + $T_fr_inv_timeout (R/W) - the timeout + for the final reply to an INVITE request, after a 1XX reply + was received + + + With each different request received, + $T_fr_inv_timeout will initially be equal to the + + parameter. + + + "$T_fr_inv_timeout = NULL;" will reset it to + . + +
+
$T_ruri $T_ruri - the ruri of the current branch; this - information is taken from the transaction structure, so you can + information is taken from the transaction structure, so you can access this information for any sip message (request/reply) that has a transaction. diff --git a/modules/tm/fix_lumps.h b/modules/tm/fix_lumps.h index d102ad7a67b..af3cd8313fd 100644 --- a/modules/tm/fix_lumps.h +++ b/modules/tm/fix_lumps.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/tm/h_table.c b/modules/tm/h_table.c index 875a9e70351..a0343e10bf7 100644 --- a/modules/tm/h_table.c +++ b/modules/tm/h_table.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -26,7 +26,7 @@ * from transaction state to a static var(jiri) * 2003-03-16 removed _TOTAG (jiri) * 2003-03-30 set_kr for requests only (jiri) - * 2003-04-04 bug_fix: REQ_IN callback not called for local + * 2003-04-04 bug_fix: REQ_IN callback not called for local * UAC transactions (jiri) * 2003-09-12 timer_link->tg will be set only if EXTRA_DEBUG (andrei) * 2003-12-04 global callbacks replaceed with callbacks per transaction; @@ -57,6 +57,9 @@ #include "t_fwd.h" #include "t_lookup.h" +/* indicates how much we have to shift the transaction pointer in order to + * obtain a fair distribution on the tm timers */ +int tm_timer_shift = 0; static enum kill_reason kr; /* pointer to the big table where all the transaction data @@ -82,13 +85,13 @@ enum kill_reason get_kr(void) { } -void lock_hash(int i) +void lock_hash(int i) { lock(&tm_table->entrys[i].mutex); } -void unlock_hash(int i) +void unlock_hash(int i) { unlock(&tm_table->entrys[i].mutex); } @@ -105,13 +108,23 @@ unsigned int transaction_count( void ) unsigned int i; unsigned int count; - count=0; - for (i=0; ientrys[i].cur_entries; return count; } +/* TODO: replace these macros with a more generic approach --liviu */ +#ifdef HP_MALLOC + #define __sip_msg_free sip_msg_free + #define __shm_free shm_free + #define __destroy_avp_list destroy_avp_list +#else + #define __sip_msg_free sip_msg_free_unsafe + #define __shm_free shm_free_unsafe + #define __destroy_avp_list destroy_avp_list_unsafe +#endif void free_cell( struct cell* dead_cell ) { @@ -127,45 +140,49 @@ void free_cell( struct cell* dead_cell ) empty_tmcb_list(&dead_cell->tmcb_hl); release_cell_lock( dead_cell ); + +#ifndef HP_MALLOC shm_lock(); +#endif /* UA Server */ if ( dead_cell->uas.request ) - sip_msg_free_unsafe( dead_cell->uas.request ); + __sip_msg_free( dead_cell->uas.request ); + if ( dead_cell->uas.response.buffer.s ) - shm_free_unsafe( dead_cell->uas.response.buffer.s ); + __shm_free( dead_cell->uas.response.buffer.s ); /* UA Clients */ for ( i =0 ; inr_of_outgoings; i++ ) { /* retransmission buffer */ if ( (b=dead_cell->uac[i].request.buffer.s) ) - shm_free_unsafe( b ); + __shm_free( b ); b=dead_cell->uac[i].local_cancel.buffer.s; if (b!=0 && b!=BUSY_BUFFER) - shm_free_unsafe( b ); + __shm_free( b ); rpl=dead_cell->uac[i].reply; if (rpl && rpl!=FAKED_REPLY && rpl->msg_flags&FL_SHM_CLONE) { - sip_msg_free_unsafe( rpl ); + __sip_msg_free( rpl ); } if ( (p=dead_cell->uac[i].proxy)!=NULL ) { if ( p->host.h_addr_list ) - shm_free_unsafe( p->host.h_addr_list ); + __shm_free( p->host.h_addr_list ); if ( p->dn ) { if ( p->dn->kids ) - shm_free_unsafe( p->dn->kids ); - shm_free_unsafe( p->dn ); + __shm_free( p->dn->kids ); + __shm_free( p->dn ); } - shm_free_unsafe(p); + __shm_free(p); } if (dead_cell->uac[i].path_vec.s) { - shm_free_unsafe(dead_cell->uac[i].path_vec.s); + __shm_free(dead_cell->uac[i].path_vec.s); } if (dead_cell->uac[i].duri.s) { - shm_free_unsafe(dead_cell->uac[i].duri.s); + __shm_free(dead_cell->uac[i].duri.s); } if (dead_cell->uac[i].user_avps) { - destroy_avp_list_unsafe( &dead_cell->uac[i].user_avps); + __destroy_avp_list( &dead_cell->uac[i].user_avps); } } @@ -173,23 +190,25 @@ void free_cell( struct cell* dead_cell ) tt=dead_cell->fwded_totags; while(tt) { foo=tt->next; - shm_free_unsafe(tt->tag.s); - shm_free_unsafe(tt); + __shm_free(tt->tag.s); + __shm_free(tt); tt=foo; } /* free the avp list */ if (dead_cell->user_avps) - destroy_avp_list_unsafe( &dead_cell->user_avps ); + __destroy_avp_list( &dead_cell->user_avps ); /* extra hdrs */ if ( dead_cell->extra_hdrs.s ) - shm_free_unsafe( dead_cell->extra_hdrs.s ); + __shm_free( dead_cell->extra_hdrs.s ); /* the cell's body */ - shm_free_unsafe( dead_cell ); + __shm_free( dead_cell ); +#ifndef HP_MALLOC shm_unlock(); +#endif } @@ -211,7 +230,7 @@ static inline void init_synonym_id( struct cell *t ) char_msg_val( p_msg, t->md5 ); } else { /* char value for a UAC transaction is created - randomly -- UAC is an originating stateful element + randomly -- UAC is an originating stateful element which cannot be refreshed, so the value can be anything */ @@ -225,7 +244,7 @@ static inline void init_synonym_id( struct cell *t ) } } -static inline void init_branches(struct cell *t) +static inline void init_branches(struct cell *t, unsigned int set) { unsigned int i; struct ua_client *uac; @@ -239,6 +258,10 @@ static inline void init_branches(struct cell *t) uac->request.fr_timer.tg = TG_FR; uac->request.retr_timer.tg = TG_RT; #endif + uac->request.fr_timer.set = set; + uac->request.retr_timer.set = set; + uac->local_cancel.fr_timer.set = set; + uac->local_cancel.retr_timer.set = set; uac->local_cancel=uac->request; } } @@ -250,6 +273,7 @@ struct cell* build_cell( struct sip_msg* p_msg ) int sip_msg_len; struct usr_avp **old; struct tm_callback *cbs, *cbs_tmp; + unsigned short set; /* allocs a new cell */ new_cell = (struct cell*)shm_malloc( sizeof( struct cell ) ); @@ -261,14 +285,21 @@ struct cell* build_cell( struct sip_msg* p_msg ) /* filling with 0 */ memset( new_cell, 0, sizeof( struct cell ) ); + /* get timer set id based on the transaction pointer, but + * devide by 64 to avoid issues because pointer are 64 bits + * aligned */ + set = ( ((long)new_cell)>>tm_timer_shift ) % tm_table->timer_sets; + /* UAS */ #ifdef EXTRA_DEBUG new_cell->uas.response.retr_timer.tg=TG_RT; new_cell->uas.response.fr_timer.tg=TG_FR; #endif + new_cell->uas.response.retr_timer.set = set; + new_cell->uas.response.fr_timer.set = set; new_cell->uas.response.my_T=new_cell; - /* dcm: - local generation transactions should not inherit AVPs + /* dcm: - local generation transactions should not inherit AVPs * - commpletely new message */ if(p_msg) { /* move the current avp list to transaction -bogdan */ @@ -303,7 +334,9 @@ struct cell* build_cell( struct sip_msg* p_msg ) } /* UAC */ - init_branches(new_cell); + init_branches(new_cell, set); + new_cell->fr_timeout = fr_timeout; + new_cell->fr_inv_timeout = fr_inv_timeout; new_cell->relaied_reply_branch = -1; /* new_cell->T_canceled = T_UNDEFINED; */ @@ -311,6 +344,8 @@ struct cell* build_cell( struct sip_msg* p_msg ) new_cell->wait_tl.tg=TG_WT; new_cell->dele_tl.tg=TG_DEL; #endif + new_cell->wait_tl.set = set; + new_cell->dele_tl.set = set; init_synonym_id(new_cell); init_cell_lock( new_cell ); @@ -364,7 +399,7 @@ void free_hash_table(void) /* */ -struct s_table* init_hash_table(void) +struct s_table* init_hash_table( unsigned int timer_sets ) { int i; @@ -372,14 +407,12 @@ struct s_table* init_hash_table(void) tm_table= (struct s_table*)shm_malloc( sizeof( struct s_table ) ); if ( !tm_table) { LM_ERR("no more share memory\n"); - goto error0; + goto error; } memset( tm_table, 0, sizeof (struct s_table ) ); - /* try first allocating all the structures needed for syncing */ - if (lock_initialize()==-1) - goto error1; + tm_table->timer_sets = timer_sets; /* inits the entrys */ for( i=0 ; iis_invite, t->local, t->noisy_ctimer replaced * with flags (bogdan) * 2004-08-23 avp support added - avp list linked in transaction (bogdan) - * 2007-01-25 DNS failover at transaction level added (bogdan) + * 2007-01-25 DNS failover at transaction level added (bogdan) */ #ifndef _H_TABLE_H @@ -99,7 +99,7 @@ typedef struct retr_buf 0 if request or -1 if local CANCEL */ str buffer; - + struct dest_info dst; /* a message can be linked just to retransmission and FR list */ @@ -122,7 +122,7 @@ typedef struct ua_server char *end_request; struct retr_buf response; unsigned int status; - /* keep to-tags for local 200 replies for INVITE -- + /* keep to-tags for local 200 replies for INVITE -- * we need them for dialog-wise matching of ACKs; * the pointer shows to shmem-ed reply */ str local_totag; @@ -137,7 +137,7 @@ typedef struct ua_client struct retr_buf request; struct proxy_l *proxy; /* we maintain a separate copy of cancel rather than - reuse the structure for original request; the + reuse the structure for original request; the original request is no longer needed but its delayed timer may fire and interfere with whoever tries to rewrite it */ @@ -228,7 +228,7 @@ typedef struct cell when entering WAIT state and the wait timer is the only place from which a transaction can be deleted (if ref_count==0); good for protecting from conditions in which wait_timer hits and - tries to delete a transaction whereas at the same time + tries to delete a transaction whereas at the same time a delayed message belonging to the transaction is received */ volatile unsigned int ref_count; @@ -273,6 +273,9 @@ typedef struct cell /* the branch_route to be processed separately for each branch */ unsigned int on_branch; + int fr_timeout; /* final reply timeout (sec) */ + int fr_inv_timeout; /* final reply timeout for an INVITE, after 1XX (sec) */ + /* MD5checksum (meaningful only if syn_branch=0) */ char md5[MD5_LEN]; @@ -281,8 +284,8 @@ typedef struct cell short damocles; #endif - /* to-tags of 200/INVITEs which were received from downstream and - * forwarded or passed to UAC; note that there can be arbitrarily + /* to-tags of 200/INVITEs which were received from downstream and + * forwarded or passed to UAC; note that there can be arbitrarily * many due to downstream forking; */ struct totag_elem *fwded_totags; @@ -318,6 +321,9 @@ struct s_table { /* table of hash entries; each of them is a list of synonyms */ struct entry entrys[ TM_TABLE_ENTRIES ]; + /* we keep it here just as a shortcut, we need it for assigning + * a transaction to a specific timer set */ + unsigned short timer_sets; }; @@ -353,15 +359,18 @@ struct s_table extern int syn_branch; +extern int fr_timeout; +extern int fr_inv_timeout; +extern int tm_timer_shift; void reset_kr(); void set_kr( enum kill_reason kr ); enum kill_reason get_kr(); -struct s_table* get_tm_table(); -struct s_table* init_hash_table(); -void free_hash_table( ); +struct s_table* get_tm_table( void ); +struct s_table* init_hash_table(unsigned int timer_sets); +void free_hash_table( void ); void free_cell( struct cell* dead_cell ); struct cell* build_cell( struct sip_msg* p_msg ); void remove_from_hash_table_unsafe( struct cell * p_cell); @@ -374,7 +383,7 @@ unsigned int transaction_count( void ); /* Unix socket variant */ int unixsock_hash(str* msg); - + #endif diff --git a/modules/tm/lock.c b/modules/tm/lock.c index 4b1cb4d42b4..e28acedf690 100644 --- a/modules/tm/lock.c +++ b/modules/tm/lock.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -35,16 +35,16 @@ -#ifndef GEN_LOCK_T_PREFERED +#ifndef GEN_LOCK_T_PREFERED /* semaphore probing limits */ #define SEM_MIN 16 #define SEM_MAX 4096 /* we implement mutex here using lock sets; as the number of - semaphores may be limited (e.g. sysv) and number of synchronized - elements high, we partition the synced SER elements and share - semaphores in each of the partitions; we try to use as many - semaphores as OS gives us for finest granularity. + semaphores may be limited (e.g. sysv) and number of synchronized + elements high, we partition the synced SER elements and share + semaphores in each of the partitions; we try to use as many + semaphores as OS gives us for finest granularity. we allocate the locks according to the following plans: @@ -72,12 +72,12 @@ gen_lock_set_t* reply_semaphore=0; static ser_lock_t* timer_group_lock=0; /* pointer to a TG_NR lock array, - it's safer if we alloc this in shared mem + it's safer if we alloc this in shared mem ( required for fast lock ) */ /* initialize the locks; return 0 on success, -1 otherwise */ -int lock_initialize(void) +int lock_initialize( unsigned int timer_sets ) { int i; #ifndef GEN_LOCK_T_PREFERED @@ -87,13 +87,13 @@ int lock_initialize(void) /* first try allocating semaphore sets with fixed number of semaphores */ LM_DBG("lock initialization started\n"); - timer_group_lock=shm_malloc(TG_NR*sizeof(ser_lock_t)); + timer_group_lock=shm_malloc(timer_sets*TG_NR*sizeof(ser_lock_t)); if (timer_group_lock==0){ LM_CRIT("no more share mem\n"); goto error; } #ifdef GEN_LOCK_T_PREFERED - for(i=0;itimers[timerlist_id].mutex= - &(timer_group_lock[ timer_group[timerlist_id] ]); + get_timertable()[set].timers[timerlist_id].mutex= + &(timer_group_lock[ set*TG_NR + timer_group[timerlist_id] ]); return 0; } diff --git a/modules/tm/lock.h b/modules/tm/lock.h index 305cb81074c..62226234784 100644 --- a/modules/tm/lock.h +++ b/modules/tm/lock.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -59,13 +59,13 @@ enum timer_groups { #include "h_table.h" -#include "timer.h" +#include "timer.h" /* Uni*x permissions for IPC */ #define IPC_PERMISSIONS 0666 -int lock_initialize(); +int lock_initialize( unsigned int timer_sets ); void lock_cleanup(); #ifdef DBG_LOCK @@ -89,8 +89,8 @@ int release_timerlist_lock( struct timer *timerlist ); /* lock semaphore s */ #ifdef DBG_LOCK -static inline void _lock( ser_lock_t* s , char *file, char *function, - unsigned int line ) +static inline void _lock(ser_lock_t* s , const char *file, const char *function, + unsigned int line) #else static inline void _lock( ser_lock_t* s ) #endif @@ -98,7 +98,7 @@ static inline void _lock( ser_lock_t* s ) #ifdef DBG_LOCK LM_DBG("lock : entered from %s , %s(%d)\n", function, file, line ); #endif -#ifdef GEN_LOCK_T_PREFERED +#ifdef GEN_LOCK_T_PREFERED lock_get(s); #else lock_set_get(s->semaphore_set, s->semaphore_index); @@ -108,8 +108,8 @@ static inline void _lock( ser_lock_t* s ) #ifdef DBG_LOCK -static inline void _unlock( ser_lock_t* s, char *file, char *function, - unsigned int line ) +static inline void _unlock(ser_lock_t* s, const char *file, const char *function, + unsigned int line) #else static inline void _unlock( ser_lock_t* s ) #endif @@ -124,7 +124,7 @@ static inline void _unlock( ser_lock_t* s ) #endif } -int init_timerlist_lock( enum lists timerlist_id); +int init_timerlist_lock( unsigned int set, enum lists timerlist_id); #endif diff --git a/modules/tm/mi.c b/modules/tm/mi.c index d56ff0b9610..fd7ed988344 100644 --- a/modules/tm/mi.c +++ b/modules/tm/mi.c @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -140,14 +140,14 @@ static inline char *get_hfblock( str *uri, struct hdr_field *hf, int *l, for (; hf; hf=hf->next) { if (skip_hf(hf)) continue; - begin=needle=hf->name.s; + begin=needle=hf->name.s; hf_avail=hf->len; /* substitution loop */ while(hf_avail) { d=memchr(needle, SUBST_CHAR, hf_avail); if (!d || d+1>=needle+hf_avail) { /* nothing to substitute */ - new=new_str(begin, hf_avail, &last, &total_len); + new=new_str(begin, hf_avail, &last, &total_len); if (!new) goto error; break; } else { @@ -156,7 +156,7 @@ static inline char *get_hfblock( str *uri, struct hdr_field *hf, int *l, switch(*d) { case SUBST_CHAR: /* double SUBST_CHAR: IP */ /* string before substitute */ - new=new_str(begin, frag_len, &last, &total_len); + new=new_str(begin, frag_len, &last, &total_len); if (!new) goto error; /* substitute */ if (!sock_name) { @@ -361,7 +361,7 @@ static void mi_uac_dlg_hdl( struct cell *t, int type, struct tmcb_params *ps ) pkg_free(text.s); mi_print_uris( &rpl_tree->node, 0 ); add_mi_node_child( &rpl_tree->node, 0, 0, 0, ".",1); - } else { + } else { addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%d %.*s", ps->rpl->first_line.u.reply.statuscode, ps->rpl->first_line.u.reply.reason.len, @@ -467,7 +467,7 @@ struct mi_root* mi_tm_uac_dlg(struct mi_root* cmd_tree, void* param) hdrs = &node->value; /* use SIP parser to look at what is in the FIFO request */ memset( &tmp_msg, 0, sizeof(struct sip_msg)); - tmp_msg.len = hdrs->len; + tmp_msg.len = hdrs->len; tmp_msg.buf = tmp_msg.unparsed = hdrs->s; if (parse_headers( &tmp_msg, HDR_EOH_F, 0) == -1 ) return init_mi_tree( 400, "Bad headers", 11); @@ -702,7 +702,7 @@ struct mi_root* mi_tm_reply(struct mi_root* cmd_tree, void* param) node = node->next; if (node->value.len==1 && node->value.s[0]=='.') new_hdrs = 0; - else + else new_hdrs = &node->value; /* body (param 5 - optional) */ diff --git a/modules/tm/mi.h b/modules/tm/mi.h index 0152bd54e99..9bddba45107 100644 --- a/modules/tm/mi.h +++ b/modules/tm/mi.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/tm/sip_msg.c b/modules/tm/sip_msg.c index 61aaa63a1cf..b298d622354 100644 --- a/modules/tm/sip_msg.c +++ b/modules/tm/sip_msg.c @@ -1,6 +1,6 @@ /* * $Id$ - * + * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of opensips, a free SIP server. @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -36,7 +36,7 @@ * of messages in memory); note that many operations, which * allocate pkg memory (such as parsing) cannot be used with * a cloned message -- it would result in linking pkg structures - * to shmem msg and eventually in a memory error + * to shmem msg and eventually in a memory error * * the cloned message is stored in a single memory fragment to * save too many shm_mallocs -- these are expensive as they @@ -55,7 +55,7 @@ #include "../../parser/digest/digest.h" -/* rounds to the first 4 byte multiple on 32 bit archs +/* rounds to the first 4 byte multiple on 32 bit archs * and to the first 8 byte multiple on 64 bit archs */ #define ROUND4(s) \ (((s)+(sizeof(char*)-1))&(~(sizeof(char*)-1))) @@ -130,7 +130,7 @@ inline static struct via_body* via_body_cloner( char* new_buf, new_vp->name.s=translate_pointer(new_buf,org_buf,vp->name.s); new_vp->value.s=translate_pointer(new_buf,org_buf,vp->value.s); new_vp->start=translate_pointer(new_buf,org_buf,vp->start); - + /* "translate" the shortcuts */ switch(new_vp->type){ case PARAM_BRANCH: @@ -219,7 +219,7 @@ static inline struct auth_body* auth_body_cloner(char* new_buf, char *org_buf, s new_auth = (struct auth_body*)(*p); memcpy(new_auth , auth , sizeof(struct auth_body)); (*p) += ROUND4(sizeof(struct auth_body)); - + /* authorized field must be cloned elsewhere */ new_auth->digest.username.whole.s = translate_pointer(new_buf, org_buf, auth->digest.username.whole.s); @@ -257,7 +257,7 @@ static inline int clone_authorized_hooks(struct sip_msg* new, get_authorized_cred(old->authorization, &hook1); if (!hook1) stop = 1; - + get_authorized_cred(old->proxy_auth, &hook2); if (!hook2) stop |= 2; @@ -274,7 +274,7 @@ static inline int clone_authorized_hooks(struct sip_msg* new, new_ptr; stop |= 1; } - + if (ptr == hook2) { if (!new->proxy_auth || !new->proxy_auth->parsed) { LM_CRIT("message cloner (proxy_auth) failed\n"); @@ -323,9 +323,17 @@ struct sip_msg* sip_msg_cloner( struct sip_msg *org_msg, int *sip_msg_len ) len = ROUND4(sizeof( struct sip_msg )); /*we will keep only the original msg +ZT */ len += ROUND4(org_msg->len + 1); + /*the new uri (if any)*/ if (org_msg->new_uri.s && org_msg->new_uri.len) - len+= ROUND4(org_msg->new_uri.len); + len += ROUND4(org_msg->new_uri.len); + + if (org_msg->set_global_address.s) + len += ROUND4(org_msg->set_global_address.len); + + if (org_msg->set_global_port.s) + len += ROUND4(org_msg->set_global_port.len); + /*all the headers*/ for( hdr=org_msg->headers ; hdr ; hdr=hdr->next ) { @@ -437,7 +445,7 @@ do { \ LUMP_LIST_LEN(len, org_msg->add_rm); LUMP_LIST_LEN(len, org_msg->body_lumps); - + /*length of reply lump structures*/ for(rpl_lump=org_msg->reply_lump;rpl_lump;rpl_lump=rpl_lump->next) len+=ROUND4(sizeof(struct lump_rpl))+ROUND4(rpl_lump->text.len); @@ -465,6 +473,7 @@ do { \ p += ROUND4(sizeof(struct sip_msg)); new_msg->add_rm = 0; new_msg->body_lumps = 0; + /* new_uri */ if (org_msg->new_uri.s && org_msg->new_uri.len) { @@ -472,6 +481,21 @@ do { \ memcpy( p , org_msg->new_uri.s , org_msg->new_uri.len); p += ROUND4(org_msg->new_uri.len); } + + /* advertised address and port */ + if (org_msg->set_global_address.s) + { + new_msg->set_global_address.s = p; + memcpy(p, org_msg->set_global_address.s, org_msg->set_global_address.len); + p += ROUND4(org_msg->set_global_address.len); + } + if (org_msg->set_global_port.s) + { + new_msg->set_global_port.s = p; + memcpy(p, org_msg->set_global_port.s, org_msg->set_global_port.len); + p += ROUND4(org_msg->set_global_port.len); + } + /* dst_uri to zero */ new_msg->dst_uri.s = 0; new_msg->dst_uri.len = 0; @@ -575,7 +599,7 @@ do { \ else { LINK_SIBLING_HEADER(h_via1, new_hdr); - new_hdr->parsed = + new_hdr->parsed = via_body_cloner( new_msg->buf , org_msg->buf , (struct via_body*)hdr->parsed , &p); } @@ -762,7 +786,7 @@ do { \ LINK_SIBLING_HEADER(content_type, new_hdr); } break; - + case HDR_ACCEPT_T: if (HOOK_NOT_SET(accept)) { new_msg->accept = new_hdr; diff --git a/modules/tm/sip_msg.h b/modules/tm/sip_msg.h index 8f86dc432c2..ecef406f1f7 100644 --- a/modules/tm/sip_msg.h +++ b/modules/tm/sip_msg.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/tm/t_cancel.c b/modules/tm/t_cancel.c index 66a2dcb89ef..d1bb9202a04 100644 --- a/modules/tm/t_cancel.c +++ b/modules/tm/t_cancel.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -58,7 +58,7 @@ void which_cancel( struct cell *t, branch_bm_t *cancel_bm ) int i; for( i=t->first_branch ; inr_of_outgoings ; i++ ) { - if (should_cancel_branch(t, i)) + if (should_cancel_branch(t, i)) *cancel_bm |= 1<nr_of_outgoings ; i++ ) + for( i=0 ; inr_of_outgoings ; i++ ) if (cancel_bm & (1<buffer.len=len; crb->dst=irb->dst; crb->branch=branch; - /* label it as cancel so that FR timer can better now how + /* label it as cancel so that FR timer can better now how * to deal with it */ crb->activ_type=TYPE_LOCAL_CANCEL; diff --git a/modules/tm/t_cancel.h b/modules/tm/t_cancel.h index b239b53dbd2..10b07512cf9 100644 --- a/modules/tm/t_cancel.h +++ b/modules/tm/t_cancel.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/tm/t_dlg.c b/modules/tm/t_dlg.c index 9901fc7ab8e..7e339a22be7 100644 --- a/modules/tm/t_dlg.c +++ b/modules/tm/t_dlg.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/tm/t_dlg.h b/modules/tm/t_dlg.h index 8d76a657fcf..2c78a7c4e07 100644 --- a/modules/tm/t_dlg.h +++ b/modules/tm/t_dlg.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/tm/t_fifo.c b/modules/tm/t_fifo.c index 9016986e5ae..1f35aa6274a 100644 --- a/modules/tm/t_fifo.c +++ b/modules/tm/t_fifo.c @@ -17,15 +17,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- * 2004-02-23 created by splitting it from t_funcs (bogdan) * 2004-11-15 t_write_xxx can print whatever avp/hdr - * 2005-07-14 t_write_xxx specification aligned to use pseudo-variables + * 2005-07-14 t_write_xxx specification aligned to use pseudo-variables * (bogdan) */ @@ -148,7 +148,7 @@ int parse_tw_append( modparam_t type, void* val) str foo; str bar; - + if (val==0 || ((char*)val)[0]==0) return 0; @@ -350,7 +350,7 @@ int init_twrite_sock(void) close(sock); return -1; } - + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) { LM_ERR("init_twrite_sock: fcntl: set non-blocking failed:" " %s\n", strerror(errno)); @@ -436,7 +436,7 @@ static inline char* add2buf(char *buf, char *end, str *name, str *value) -static inline char* append2buf( char *buf, int len, struct sip_msg *req, +static inline char* append2buf( char *buf, int len, struct sip_msg *req, struct append_elem *elem) { pv_value_t value; @@ -499,7 +499,7 @@ static int assemble_msg(struct sip_msg* msg, struct tw_info *twi) goto error; } - /* find index and hash; (the transaction can be safely used due + /* find index and hash; (the transaction can be safely used due * to refcounting till script completes) */ if( t_get_trans_ident(msg,&hash_index,&label) == -1 ) { LM_ERR("t_get_trans_ident failed\n"); @@ -565,7 +565,7 @@ static int assemble_msg(struct sip_msg* msg, struct tw_info *twi) /* Parse all parameters */ tmp_s.len = record_route->nameaddr.uri.len - (tmp_s.s- record_route->nameaddr.uri.s); - if (parse_params( &tmp_s, CLASS_URI, &hooks, + if (parse_params( &tmp_s, CLASS_URI, &hooks, &record_route->params) < 0) { LM_ERR("failed to parse record route uri params\n"); goto error; @@ -609,7 +609,7 @@ static int assemble_msg(struct sip_msg* msg, struct tw_info *twi) LM_DBG("calculated route: %.*s\n",route.len,route.len ? route.s : ""); LM_DBG("next r-uri: %.*s\n",str_uri.len,str_uri.len ? str_uri.s : ""); - if ( REQ_LINE(msg).method_value==METHOD_INVITE || + if ( REQ_LINE(msg).method_value==METHOD_INVITE || (twi->append && twi->append->add_body) ) { /* get body */ if( get_body(msg,&body)!=0 ){ diff --git a/modules/tm/t_fifo.h b/modules/tm/t_fifo.h index 24357e480fb..1b130aaf89a 100644 --- a/modules/tm/t_fifo.h +++ b/modules/tm/t_fifo.h @@ -15,13 +15,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- - * 2003-03-31 200 for INVITE/UAS resent even for UDP (jiri) + * 2003-03-31 200 for INVITE/UAS resent even for UDP (jiri) * 2004-11-15 t_write_xxx can print whatever avp/hdr */ diff --git a/modules/tm/t_funcs.c b/modules/tm/t_funcs.c index a7fd1cb112a..8a9e5bed4fc 100644 --- a/modules/tm/t_funcs.c +++ b/modules/tm/t_funcs.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -36,7 +36,7 @@ * 2004-02-13 t->is_invite and t->local replaced with flags (bogdan) * 2005-02-16 fr_*_timer acceps full AVP specifications; empty AVP * desable variable timer feature (bogdan) - * 2007-01-25 DNS failover at transaction level added (bogdan) + * 2007-01-25 DNS failover at transaction level added (bogdan) */ #include @@ -55,16 +55,9 @@ #include "t_lookup.h" #include "config.h" -/* fr_timer AVP specs */ -static int fr_timer_avp_type; -static int fr_timer_avp; -static int fr_inv_timer_avp_type; -static int fr_inv_timer_avp; - static str relay_reason_100 = str_init("Giving a try"); - /* ----------------------------------------------------- */ int send_pr_buffer( struct retr_buf *rb, void *buf, int len #ifdef EXTRA_DEBUG @@ -117,7 +110,7 @@ int t_release_transaction( struct cell *trans ) reset_timer( & trans->uas.response.retr_timer ); cleanup_uac_timers( trans ); - + put_on_wait( trans ); return 1; } @@ -269,101 +262,31 @@ int t_relay_to( struct sip_msg *p_msg , struct proxy_l *proxy, int flags) return ret; } - - -/* - * Initialize parameters containing the ID of - * AVPs with variable timers - */ -int init_avp_params(char *fr_timer_param, char *fr_inv_timer_param) +inline void _set_fr_retr( struct retr_buf *rb, int retr ) { - pv_spec_t avp_spec; - unsigned short avp_flags; - str s; - if (fr_timer_param && *fr_timer_param) { - s.s = fr_timer_param; s.len = strlen(s.s); - if (pv_parse_spec(&s, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP %s AVP definition\n", fr_timer_param); - return -1; - } + utime_t timer; - if(pv_get_avp_name(0, &avp_spec.pvp, &fr_timer_avp, &avp_flags)!=0) - { - LM_ERR("[%s]- invalid AVP definition\n", fr_timer_param); - return -1; - } - fr_timer_avp_type = avp_flags; - } else { - fr_timer_avp = -1; - fr_timer_avp_type = 0; + if (retr && !rb->retr_timer.deleted) { + rb->retr_list=RT_T1_TO_1; + set_timer( &rb->retr_timer, RT_T1_TO_1, NULL ); } - if (fr_inv_timer_param && *fr_inv_timer_param) { - s.s = fr_inv_timer_param; s.len = strlen(s.s); - if (pv_parse_spec(&s, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP %s AVP definition\n", - fr_inv_timer_param); - return -1; - } - - if(pv_get_avp_name(0, &avp_spec.pvp, &fr_inv_timer_avp, &avp_flags)!=0) - { - LM_ERR("[%s]- invalid AVP definition\n", fr_inv_timer_param); - return -1; - } - fr_inv_timer_avp_type = avp_flags; - } else { - fr_inv_timer_avp = -1; - fr_inv_timer_avp_type = 0; - } - return 0; -} - - -/* - * Get the FR_{INV}_TIMER from corresponding AVP - */ -static inline int avp2timer(utime_t *timer, int type, int name) -{ - struct usr_avp *avp; - int_str val_istr; - int err; - - avp = search_first_avp( type, name, &val_istr, 0); - if (!avp) - return 1; - - if (avp->flags & AVP_VAL_STR) { - *timer = str2s(val_istr.s.s, val_istr.s.len, &err); - if (err) { - LM_ERR("failed to convert string to integer\n"); - return -1; - } - } else { - *timer = val_istr.n; + if (!rb->my_T || !is_timeout_set(rb->my_T->fr_timeout)) + set_1timer(&rb->fr_timer, FR_TIMER_LIST, NULL); + else { + timer = rb->my_T->fr_timeout; + set_1timer(&rb->fr_timer, FR_TIMER_LIST, &timer); } - - return 0; } -int fr_avp2timer(utime_t* timer) +inline void start_retr(struct retr_buf *rb) { - if (fr_timer_avp>=0) - return avp2timer( timer, fr_timer_avp_type, fr_timer_avp); - else - return 1; + _set_fr_retr(rb, rb->dst.proto==PROTO_UDP); } -int fr_inv_avp2timer(utime_t* timer) +inline void force_retr(struct retr_buf *rb) { - if (fr_inv_timer_avp>=0) - return avp2timer( timer, fr_inv_timer_avp_type, fr_inv_timer_avp); - else - return 1; + _set_fr_retr(rb, 1); } - - diff --git a/modules/tm/t_funcs.h b/modules/tm/t_funcs.h index 90827ef4803..78c902f2abe 100644 --- a/modules/tm/t_funcs.h +++ b/modules/tm/t_funcs.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -26,8 +26,8 @@ * in a non-gcc specific way (andrei) * 2003-03-13 now send_pr_buffer will be called w/ function/line info * only when compiling w/ -DEXTRA_DEBUG (andrei) - * 2003-03-31 200 for INVITE/UAS resent even for UDP (jiri) - * 2007-01-25 DNS failover at transaction level added (bogdan) + * 2003-03-31 200 for INVITE/UAS resent even for UDP (jiri) + * 2007-01-25 DNS failover at transaction level added (bogdan) */ @@ -51,6 +51,13 @@ #include "../../parser/parse_uri.h" #include "../../usr_avp.h" +struct s_table; +struct timer; +struct entry; +struct cell; +struct retr_buf; + +#include "t_lookup.h" #include "config.h" #include "lock.h" #include "timer.h" @@ -58,11 +65,6 @@ #include "h_table.h" #include "ut.h" -struct s_table; -struct timer; -struct entry; -struct cell; - extern int noisy_ctimer; @@ -119,53 +121,15 @@ int send_pr_buffer( struct retr_buf *rb, void *buf, int len); #define INIT_REF_UNSAFE(_T_cell) ((_T_cell)->ref_count=1) #define IS_REFFED_UNSAFE(_T_cell) ((_T_cell)->ref_count!=0) -/* - * Parse and fixup the fr_*_timer AVP specs - */ -int init_avp_params(char *fr_timer_param, char *fr_inv_timer_param); - - -/* - * Get the FR_{INV}_TIMER from corresponding AVP - */ -int fr_avp2timer( utime_t* timer); -int fr_inv_avp2timer( utime_t* timer); - - - -inline static void _set_fr_retr( struct retr_buf *rb, int retr ) -{ - utime_t timer; - - if (retr && !rb->retr_timer.deleted) { - rb->retr_list=RT_T1_TO_1; - set_timer( &rb->retr_timer, RT_T1_TO_1, 0 ); - } - - if (!fr_avp2timer(&timer)) { - LM_DBG("FR_TIMER = %llu\n", timer); - set_timer(&rb->fr_timer, FR_TIMER_LIST, &timer); - } else { - set_timer(&rb->fr_timer, FR_TIMER_LIST, 0); - } -} - - -inline static void start_retr(struct retr_buf *rb) -{ - _set_fr_retr(rb, rb->dst.proto==PROTO_UDP); -} - - -inline static void force_retr(struct retr_buf *rb) -{ - _set_fr_retr(rb, 1); -} +#define unset_timeout(timeout) ((timeout) = 0) +#define is_timeout_set(timeout) ((timeout) != 0) +inline void set_fr_retr(struct retr_buf *rb, int retr ); +inline void start_retr(struct retr_buf *rb); +inline void force_retr(struct retr_buf *rb); void tm_shutdown(); - /* function returns: * 1 - a new transaction was created * -1 - error, including retransmission diff --git a/modules/tm/t_fwd.c b/modules/tm/t_fwd.c index 51851afbfd5..e40a6e6d348 100644 --- a/modules/tm/t_fwd.c +++ b/modules/tm/t_fwd.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -71,7 +71,7 @@ void t_on_branch( unsigned int go_to ) struct cell *t = get_t(); /* in MODE_REPLY and MODE_ONFAILURE T will be set to current transaction; - * in MODE_REQUEST T will be set only if the transaction was already + * in MODE_REQUEST T will be set only if the transaction was already * created; if not -> use the static variable */ if (route_type==BRANCH_ROUTE || !t || t==T_UNDEFINED ) goto_on_branch=go_to; @@ -86,7 +86,7 @@ unsigned int get_on_branch(void) } -static inline int pre_print_uac_request( struct cell *t, int branch, +static inline int pre_print_uac_request( struct cell *t, int branch, struct sip_msg *request) { int backup_route_type; @@ -120,7 +120,7 @@ static inline int pre_print_uac_request( struct cell *t, int branch, /********** run route & callback ************/ - /* run branch route, if any; run it before RURI's DNS lookup + /* run branch route, if any; run it before RURI's DNS lookup * to allow to be changed --bogdan */ if (t->on_branch) { /* need to pkg_malloc the dst_uri */ @@ -192,7 +192,7 @@ static inline char *print_uac_request(struct sip_msg *i_req, unsigned int *len, buf=build_req_buf_from_sip_req( i_req, len, send_sock, proto, MSG_TRANS_SHM_FLAG); if (!buf) { - LM_ERR("no more shm_mem\n"); + LM_ERR("no more shm_mem\n"); ser_error=E_OUT_OF_MEM; return NULL; } @@ -226,49 +226,6 @@ static inline void post_print_uac_request(struct sip_msg *request, } -static inline struct proxy_l* shm_clone_proxy(struct proxy_l *sp, - unsigned int move_dn) -{ - struct proxy_l *dp; - - dp = (struct proxy_l*)shm_malloc(sizeof(struct proxy_l)); - if (dp==NULL) { - LM_ERR("no more shm memory\n"); - return 0; - } - memset( dp , 0 , sizeof(struct proxy_l)); - - dp->port = sp->port; - dp->proto = sp->proto; - dp->addr_idx = sp->addr_idx; - dp->flags = PROXY_SHM_FLAG; - - /* clone the hostent */ - if (hostent_shm_cpy( &dp->host, &sp->host)!=0) - goto error0; - - /* clone the dns resolver */ - if (sp->dn) { - if (move_dn) { - dp->dn = sp->dn; - sp->dn = 0; - } else { - dp->dn = dns_res_copy(sp->dn); - if (dp->dn==NULL) - goto error1; - } - } - - return dp; -error1: - free_shm_hostent(&dp->host); -error0: - shm_free(dp); - return 0; -} - - - /* introduce a new uac, which is blind -- it only creates the data structures and starts FR timer, but that's it; it does not print messages and send anything anywhere; that is good @@ -287,7 +244,7 @@ int add_blind_uac(void) /*struct cell *t*/ return -1; } - branch=t->nr_of_outgoings; + branch=t->nr_of_outgoings; if (branch==MAX_BRANCHES) { LM_ERR("maximum number of branches exceeded\n"); return -1; @@ -350,7 +307,7 @@ static inline unsigned int count_local_rr(struct sip_msg *req) unsigned int cnt = 0; struct lump *r; - /* we look for the RR anchors only + /* we look for the RR anchors only * in the main list (no after or before) */ for( r=req->add_rm ; r ; r=r->next ) if ( r->type==HDR_RECORDROUTE_T && r->op==LUMP_NOP) { @@ -371,7 +328,7 @@ static inline unsigned int count_local_rr(struct sip_msg *req) or error (<0); it doesn't send a message yet -- a reply to it might interfere with the processes of adding multiple branches */ -static int add_uac( struct cell *t, struct sip_msg *request, str *uri, +static int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop, str* path, struct proxy_l *proxy) { unsigned short branch; @@ -459,7 +416,7 @@ static int add_uac( struct cell *t, struct sip_msg *request, str *uri, } -int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel, +int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite, int branch ) { int ret; @@ -594,7 +551,7 @@ void cancel_invite(struct sip_msg *cancel_msg, * 1 - forward successful * -1 - error during forward */ -int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , +int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , struct proxy_l * proxy) { str backup_uri; @@ -655,7 +612,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg , /* as first branch, use current uri */ current_uri = *GET_RURI(p_msg); - branch_ret = add_uac( t, p_msg, ¤t_uri, &backup_dst, + branch_ret = add_uac( t, p_msg, ¤t_uri, &backup_dst, &p_msg->path_vec, proxy); if (branch_ret>=0) added_branches |= 1<=0) + if (branch_ret>=0) added_branches |= 1<uac[i].request.buffer.s); + t->uac[i].request.buffer.s = NULL; + t->uac[i].request.buffer.len = 0; continue; + } success_branch++; @@ -791,7 +752,7 @@ int t_replicate(struct sip_msg *p_msg, str *dst, int flags) if (!t || t==T_UNDEFINED) { /* no transaction yet */ if (route_type==FAILURE_ROUTE) { - LM_CRIT(" BUG - undefined transaction in failure route\n"); + LM_CRIT("BUG - undefined transaction in failure route\n"); return -1; } return t_relay_to( p_msg, NULL, flags|TM_T_REPLY_repl_FLAG); diff --git a/modules/tm/t_fwd.h b/modules/tm/t_fwd.h index 254caeabe2a..9ffff3314f5 100644 --- a/modules/tm/t_fwd.h +++ b/modules/tm/t_fwd.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/tm/t_hooks.c b/modules/tm/t_hooks.c index 9ba7ba1a080..b603009329c 100644 --- a/modules/tm/t_hooks.c +++ b/modules/tm/t_hooks.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/tm/t_hooks.h b/modules/tm/t_hooks.h index 66af087c145..5e39e466c0e 100644 --- a/modules/tm/t_hooks.h +++ b/modules/tm/t_hooks.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -52,7 +52,7 @@ struct cell; #define TMCB_TRANS_DELETED (1<<12) #define TMCB_MAX ((1<<13)-1) -/* +/* * Caution: most of the callbacks work with shmem-ized messages * which you can no more change (e.g., lumps are fixed). Most * reply-processing callbacks are also called from a mutex, @@ -84,13 +84,13 @@ struct cell; * TMCB_RESPONSE_IN -- a brand-new reply was received which matches * an existing transaction. It may or may not be a retransmission. * - * TMCB_RESPONSE_PRE_OUT -- a final reply is about to be sent out - * (either local or proxied); you cannnot change the reply, but + * TMCB_RESPONSE_PRE_OUT -- a final reply is about to be sent out + * (either local or proxied); you cannnot change the reply, but * it is usefull to update your state before putting the reply on - * the network and to avoid any races (receiving an ACK before + * the network and to avoid any races (receiving an ACK before * updating with the status of the reply) * - * TMCB_RESPONSE_OUT -- a final reply was sent out (either local + * TMCB_RESPONSE_OUT -- a final reply was sent out (either local * or proxied) -- there is nothing more you can change from * the callback, it is good for accounting-like uses. * @@ -102,19 +102,19 @@ struct cell; * need it ... locally initiated UAC transactions set it to 0. * * (obsolete) TMCB_ON_FAILURE_RO -- called on receipt of a reply or timer; - * it means all branches completed with a failure; the callback + * it means all branches completed with a failure; the callback * function MUST not change anything in the transaction (READONLY) * that's a chance for doing ACC or stuff like this * * TMCB_ON_FAILURE -- called on receipt of a reply or timer; - * it means all branches completed with a failure; that's + * it means all branches completed with a failure; that's * a chance for example to add new transaction branches * * TMCB_RESPONSE_FWDED -- called when a reply is about to be * forwarded; it is called after a message is received but before - * a message is sent out: it is called when the decision is - * made to forward a reply; it is parametrized by pkg message - * which caused the transaction to complete (which is not + * a message is sent out: it is called when the decision is + * made to forward a reply; it is parametrized by pkg message + * which caused the transaction to complete (which is not * necessarily the same which will be forwarded). As forwarding * has not been executed and may fail, there is no guarantee * a reply will be successfully sent out at this point of time. @@ -132,9 +132,9 @@ struct cell; * feature, either set the global option "noisy_ctimer" * to 1, or set t->noisy_ctimer for selected transaction. * - * TMCB_REQUEST_FWDED -- request is being forwarded out. It is + * TMCB_REQUEST_FWDED -- request is being forwarded out. It is * called before a message is forwarded and it is your last - * chance to change its shape. + * chance to change its shape. * * TMCB_LOCAL_COMPLETED -- final reply for localy initiated * transaction arrived. Message may be FAKED_REPLY. diff --git a/modules/tm/t_lookup.c b/modules/tm/t_lookup.c index 063ff4522b0..11ae6a8391d 100644 --- a/modules/tm/t_lookup.c +++ b/modules/tm/t_lookup.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -30,7 +30,7 @@ * 2003-02-27 3261 ACK/200 consumption bug removed (jiri) * 2003-02-28 scratchpad compatibility abandoned (jiri) * 2003-03-01 kr set through a function now (jiri) - * 2003-03-06 dialog matching introduced for ACKs -- that's important for + * 2003-03-06 dialog matching introduced for ACKs -- that's important for * INVITE UAS (like INVITE) and 200/ACK proxy matching (jiri) * 2003-03-29 optimization: e2e ACK matching only if callback installed * (jiri) @@ -40,7 +40,7 @@ * 2003-04-07 new transactions inherit on_negative and on_relpy from script * variables on instantiation (jiri) * 2003-04-30 t_newtran clean up (jiri) - * 2003-08-21 request lookups fixed to skip UAC transactions, + * 2003-08-21 request lookups fixed to skip UAC transactions, * thanks Ed (jiri) * 2003-12-04 global TM callbacks switched to per transaction callbacks * (bogdan) @@ -53,15 +53,15 @@ * * This C-file takes care of matching requests and replies with * existing transactions. Note that we do not do SIP-compliant - * request matching as asked by SIP spec. We do bitwise matching of - * all header fields in requests which form a transaction key. - * It is much faster and it works pretty well -- we haven't + * request matching as asked by SIP spec. We do bitwise matching of + * all header fields in requests which form a transaction key. + * It is much faster and it works pretty well -- we haven't * had any interop issue neither in lab nor in bake-offs. The reason * is that retransmissions do look same as original requests * (it would be really silly if they would be mangled). The only * exception is we parse To as To in ACK is compared to To in * reply and both of them are constructed by different software. - * + * * As for reply matching, we match based on branch value -- that is * faster too. There are two versions .. with SYNONYMs #define * enabled, the branch includes ordinal number of a transaction @@ -118,10 +118,10 @@ #define HF_LEN(_hf) ((_hf)->len) -/* should be request-uri matching used as a part of pre-3261 +/* should be request-uri matching used as a part of pre-3261 * transaction matching, as the standard wants us to do so * (and is reasonable to do so, to be able to distinguish - * spirals)? turn only off for better interaction with + * spirals)? turn only off for better interaction with * devices that are broken and send different r-uri in * CANCEL/ACK than in original INVITE */ @@ -185,7 +185,7 @@ static inline int parse_dlg( struct sip_msg *msg ) return 1; } -/* is the ACK (p_msg) in p_msg dialog-wise equal to the INVITE (t_msg) +/* is the ACK (p_msg) in p_msg dialog-wise equal to the INVITE (t_msg) * except to-tags? */ static inline int partial_dlg_matching(struct sip_msg *t_msg, struct sip_msg *p_msg) { @@ -201,7 +201,7 @@ static inline int partial_dlg_matching(struct sip_msg *t_msg, struct sip_msg *p_ } if (inv_from->tag_value.len!=get_from(p_msg)->tag_value.len) return 0; - if (!EQ_STR(callid)) + if (!EQ_STR(callid)) return 0; if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s, get_cseq(p_msg)->number.len)!=0) @@ -223,11 +223,11 @@ static inline int dlg_matching(struct cell *p_cell, struct sip_msg *ack ) return 1; } -static inline int ack_matching(struct cell *p_cell, struct sip_msg *p_msg) +static inline int ack_matching(struct cell *p_cell, struct sip_msg *p_msg) { - /* partial dialog matching -- no to-tag, only from-tag, + /* partial dialog matching -- no to-tag, only from-tag, * callid, cseq number ; */ - if (!partial_dlg_matching(p_cell->uas.request, p_msg)) + if (!partial_dlg_matching(p_cell->uas.request, p_msg)) return 0; /* if this transaction is proxied (as opposed to UAS) we're @@ -245,7 +245,7 @@ static inline int ack_matching(struct cell *p_cell, struct sip_msg *p_msg) } /* branch-based transaction matching */ -static inline int via_matching( struct via_body *inv_via, +static inline int via_matching( struct via_body *inv_via, struct via_body *ack_via ) { if (inv_via->tid.len!=ack_via->tid.len) @@ -275,7 +275,7 @@ static inline int via_matching( struct via_body *inv_via, /* transaction matching a-la RFC-3261 using transaction ID in branch - (the function assumes there is magic cookie in branch) + (the function assumes there is magic cookie in branch) It returns: 2 if e2e ACK for a proxied transaction found 1 if found (covers ACK for local UAS) @@ -302,7 +302,7 @@ static int matching_3261( struct sip_msg *p_msg, struct cell **trans, via1->tid.len=via1->branch->value.len-MCOOKIE_LEN; for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell; - p_cell; p_cell = p_cell->next_cell ) + p_cell; p_cell = p_cell->next_cell ) { t_msg=p_cell->uas.request; if (!t_msg) continue; /* don't try matching UAC transactions */ @@ -314,7 +314,7 @@ static int matching_3261( struct sip_msg *p_msg, struct cell **trans, * to correlate the e2e ACKs with transaction context, e.g., for * purpose of accounting. We think it is a bad place here, among * other things because it is not reliable. If a transaction loops - * via SER the ACK can't be matched to proper INVITE transaction + * via OpenSIPS the ACK can't be matched to proper INVITE transaction * (it is a separate transactino with its own branch ID) and it * matches all transaction instances in the loop dialog-wise. * Eventually, regardless to which transaction in the loop the @@ -343,7 +343,7 @@ static int matching_3261( struct sip_msg *p_msg, struct cell **trans, * -- we failed to match */ continue; } - /* now real tid matching occurs for negative ACKs and any + /* now real tid matching occurs for negative ACKs and any * other requests */ if (!via_matching(t_msg->via1 /* inv via */, via1 /* ack */ )) continue; @@ -355,7 +355,7 @@ static int matching_3261( struct sip_msg *p_msg, struct cell **trans, return 1; } /* :-( ... we didn't find any */ - + /* just check if it we found an e2e ACK previously */ if (e2e_ack_trans) { *trans=e2e_ack_trans; @@ -399,7 +399,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) /* start searching into the table */ if (!p_msg->hash_index) - p_msg->hash_index=tm_hash( p_msg->callid->body , + p_msg->hash_index=tm_hash( p_msg->callid->body , get_cseq(p_msg)->number ) ; LM_DBG("start searching: hash=%d, isACK=%d\n", p_msg->hash_index,isACK); @@ -419,8 +419,8 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) && memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) { /* huhuhu! the cookie is there -- let's proceed fast */ LOCK_HASH(p_msg->hash_index); - match_status=matching_3261(p_msg,&p_cell, - /* skip transactions with different method; otherwise CANCEL + match_status=matching_3261(p_msg,&p_cell, + /* skip transactions with different method; otherwise CANCEL * would match the previous INVITE trans. */ isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD); switch(match_status) { @@ -440,14 +440,14 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) /* all the transactions from the entry are compared */ for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell; - p_cell; p_cell = p_cell->next_cell ) + p_cell; p_cell = p_cell->next_cell ) { t_msg = p_cell->uas.request; if (!t_msg) continue; /* skip UAC transactions */ - if (!isACK) { - /* compare lengths first */ + if (!isACK) { + /* compare lengths first */ if (!EQ_LEN(callid)) continue; if (!EQ_LEN(cseq)) continue; if (!EQ_LEN(from)) continue; @@ -497,7 +497,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked ) continue; } - /* it is not an e2e ACK/200 -- perhaps it is + /* it is not an e2e ACK/200 -- perhaps it is * local negative case; in which case we will want * more elements to match: r-uri and via; allow * mismatching r-uri as an config option for broken @@ -602,7 +602,7 @@ struct cell* t_lookupOriginalT( struct sip_msg* p_msg ) if (t_msg->REQ_METHOD==METHOD_CANCEL) continue; - /* check lengths now */ + /* check lengths now */ if (!EQ_LEN(callid)) continue; if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len) @@ -727,7 +727,7 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR ); loopl = n-p; scan_space-= loopl; - if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) + if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; loopi=p; p=n+1; scan_space--; @@ -736,7 +736,7 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR); synl=n-p; scan_space-=synl; - if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) + if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2; syni=p; p=n+1;scan_space--; @@ -753,7 +753,7 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) ||hash_index>=TM_TABLE_ENTRIES || (branch_id=reverse_hex2int(branchi, branchl))<0 ||branch_id>=MAX_BRANCHES - || (syn_branch ? (entry_label=reverse_hex2int(syni, synl))<0 + || (syn_branch ? (entry_label=reverse_hex2int(syni, synl))<0 : loopl!=MD5_LEN ) ) { LM_DBG("poor reply labels %d label %d branch %d\n", @@ -769,12 +769,12 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) entry first */ LOCK_HASH(hash_index); - for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; + for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; p_cell=p_cell->next_cell) { /* first look if branch matches */ if (syn_branch) { - if (p_cell->label != entry_label) + if (p_cell->label != entry_label) continue; } else { if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0) @@ -808,11 +808,11 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch ) /* if this is a 200 for INVITE, we will wish to store to-tags to be * able to distinguish retransmissions later and not to call * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are - * enabled -- except callback customers, nobody cares about + * enabled -- except callback customers, nobody cares about * retransmissions of multiple 200/INV or ACK/200s */ - if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200 - && p_msg->REPLY_STATUS<300 + if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200 + && p_msg->REPLY_STATUS<300 && ( (!is_local(p_cell) && has_tran_tmcbs(p_cell, TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT) ) @@ -870,7 +870,7 @@ int t_check( struct sip_msg* p_msg , int *param_branch ) * ACK, for which we need From-tag; We also need from-tag * in case people want to have proxied e2e ACKs accounted */ - if (p_msg->REQ_METHOD==METHOD_INVITE + if (p_msg->REQ_METHOD==METHOD_INVITE && parse_from_header(p_msg)<0) { LM_ERR("from parsing failed\n"); return -1; @@ -974,7 +974,7 @@ static inline int new_t(struct sip_msg *p_msg) if ( !new_cell ){ LM_ERR("out of mem\n"); return E_OUT_OF_MEM; - } + } insert_into_hash_table_unsafe( new_cell, p_msg->hash_index ); INIT_REF_UNSAFE(T); @@ -1012,10 +1012,10 @@ int t_newtran( struct sip_msg* p_msg ) } T = T_UNDEFINED; - /* first of all, parse everything -- we will store in shared memory - and need to have all headers ready for generating potential replies - later; parsing later on demand is not an option since the request - will be in shmem and applying parse_headers to it would intermix + /* first of all, parse everything -- we will store in shared memory + and need to have all headers ready for generating potential replies + later; parsing later on demand is not an option since the request + will be in shmem and applying parse_headers to it would intermix shmem with pkg_mem */ @@ -1027,10 +1027,10 @@ int t_newtran( struct sip_msg* p_msg ) LM_ERR("EoH not parsed\n"); return E_OUT_OF_MEM; } - /* t_lookup_requests attempts to find the transaction; + /* t_lookup_requests attempts to find the transaction; it also calls check_transaction_quadruple -> it is safe to assume we have from/callid/cseq/to - */ + */ lret = t_lookup_request( p_msg, 1 /* leave locked if not found */ ); /* on error, pass the error in the stack ... nothing is locked yet @@ -1059,11 +1059,11 @@ int t_newtran( struct sip_msg* p_msg ) return 0; } LM_DBG("building branch for end2end ACK - flags=%X\n",e2eack_T->flags); - /* to ensure unigueness acros time and space, compute the ACK - * branch in the same maner as for INVITE, but put a t->branch - * value that cannot exist for that INVITE - as it is compute as + /* to ensure unigueness acros time and space, compute the ACK + * branch in the same maner as for INVITE, but put a t->branch + * value that cannot exist for that INVITE - as it is compute as * an INVITE, it will not overlapp with other INVITEs or requests. - * But the faked value for t->branch guarantee no overalap with + * But the faked value for t->branch guarantee no overalap with * corresponding INVITE --bogdan */ if (!t_calc_branch(e2eack_T, e2eack_T->nr_of_outgoings+1, p_msg->add_to_branch_s, &p_msg->add_to_branch_len )) { @@ -1093,7 +1093,7 @@ int t_newtran( struct sip_msg* p_msg ) not possibly block during Via DNS resolution; doing it later would only burn more CPU as if there is an error, we cannot relay later whatever comes out of the - the transaction + the transaction */ if (!init_rb( &T->uas.response, p_msg)) { LM_ERR("unresolvable via1\n"); @@ -1174,7 +1174,7 @@ int t_lookup_ident(struct cell ** trans, unsigned int hash_index, /* all the transactions from the entry are compared */ for ( p_cell = get_tm_table()->entrys[hash_index].first_cell; - p_cell; p_cell = p_cell->next_cell ) + p_cell; p_cell = p_cell->next_cell ) { if(p_cell->label == label){ REF_UNSAFE(p_cell); @@ -1231,10 +1231,10 @@ int t_lookup_callid(struct cell ** trans, str callid, str cseq) { /* CANCEL is only useful after INVITE */ str invite_method; char* invite_string = INVITE; - + invite_method.s = invite_string; invite_method.len = INVITE_LEN; - + /* lookup the hash index where the transaction is stored */ hash_index=tm_hash(callid, cseq); @@ -1246,11 +1246,11 @@ int t_lookup_callid(struct cell ** trans, str callid, str cseq) { /* create header fields the same way tm does itself, then compare headers */ endpos = print_callid_mini(callid_header, callid); LM_DBG("created comparable call_id header field: >%.*s<\n", - (int)(endpos - callid_header), callid_header); + (int)(endpos - callid_header), callid_header); endpos = print_cseq_mini(cseq_header, &cseq, &invite_method); LM_DBG("created comparable cseq header field: >%.*s<\n", - (int)(endpos - cseq_header), cseq_header); + (int)(endpos - cseq_header), cseq_header); LOCK_HASH(hash_index); diff --git a/modules/tm/t_lookup.h b/modules/tm/t_lookup.h index eae48c1a0a1..fec6c4925b2 100644 --- a/modules/tm/t_lookup.h +++ b/modules/tm/t_lookup.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -50,7 +50,7 @@ int t_newtran( struct sip_msg* p_msg ); int _add_branch_label( struct cell *trans, char *str, int *len, int branch ); -int add_branch_label( struct cell *trans, +int add_branch_label( struct cell *trans, struct sip_msg *p_msg, int branch ); /* references T-context */ @@ -73,7 +73,7 @@ typedef struct cell * (*tlookuporiginalt_f)(struct sip_msg*); typedef struct cell * (*tgett_f)(void); struct cell *get_t(); -/* use carefully or better not at all -- current transaction is +/* use carefully or better not at all -- current transaction is * primarily set by lookup functions */ void set_t(struct cell *t); @@ -95,7 +95,7 @@ typedef int (*tget_ti_f)(struct sip_msg*, unsigned int*, unsigned int*); typedef int (*tlookup_ident_f)(struct cell**, unsigned int, unsigned int); int t_is_local(struct sip_msg*); -int t_get_trans_ident(struct sip_msg* p_msg, +int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label); int t_lookup_ident(struct cell** trans, unsigned int hash_index, unsigned int label); diff --git a/modules/tm/t_msgbuilder.c b/modules/tm/t_msgbuilder.c index 9afa5c13c27..5bfa51eb44a 100644 --- a/modules/tm/t_msgbuilder.c +++ b/modules/tm/t_msgbuilder.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -124,14 +124,23 @@ char *build_local(struct cell *Trans,unsigned int branch, to.len = rpl->to->len; from.s = rpl->from->name.s; from.len = rpl->from->len; + if (req && req->msg_flags&FL_USE_UAC_CSEQ) { + if ( extract_ftc_hdrs( Trans->uac[branch].request.buffer.s, + Trans->uac[branch].request.buffer.len,0 ,0 , + &cseq_n ,0)!=0 ) { + LM_ERR("build_local: failed to extract UAC hdrs\n"); + goto error; + } + } } else { to = Trans->to; from = Trans->from; - if (req && req->msg_flags&(FL_USE_UAC_FROM|FL_USE_UAC_TO)) { + if (req && req->msg_flags&(FL_USE_UAC_FROM|FL_USE_UAC_TO|FL_USE_UAC_CSEQ)) { if ( extract_ftc_hdrs( Trans->uac[branch].request.buffer.s, Trans->uac[branch].request.buffer.len, (req->msg_flags&FL_USE_UAC_FROM)?&from:0 , - (req->msg_flags&FL_USE_UAC_TO)?&to:0 , 0 ,0)!=0 ) { + (req->msg_flags&FL_USE_UAC_TO)?&to:0 , + (req->msg_flags&FL_USE_UAC_CSEQ)?&cseq_n:0 ,0)!=0 ) { LM_ERR("build_local: failed to extract UAC hdrs\n"); goto error; } @@ -255,7 +264,7 @@ struct rte { static inline void free_rte_list(struct rte* list) { struct rte* ptr; - + while(list) { ptr = list; list = list->next; @@ -270,7 +279,7 @@ static inline int process_routeset(struct sip_msg* msg, str* contact, struct rte rr_t* p; struct rte* t, *head; struct sip_uri puri; - + ptr = msg->record_route; head = 0; while(ptr) { @@ -279,7 +288,7 @@ static inline int process_routeset(struct sip_msg* msg, str* contact, struct rte LM_ERR("failed to parse Record-Route header\n"); return -1; } - + p = (rr_t*)ptr->parsed; while(p) { t = (struct rte*)pkg_malloc(sizeof(struct rte)); @@ -296,14 +305,14 @@ static inline int process_routeset(struct sip_msg* msg, str* contact, struct rte } ptr = ptr->next; } - + if (head) { if (parse_uri(head->ptr->nameaddr.uri.s, head->ptr->nameaddr.uri.len, &puri) < 0) { LM_ERR("failed to parse URI\n"); free_rte_list(head); return -1; } - + if (puri.lr.s) { /* Next hop is loose router */ *ruri = *contact; @@ -321,7 +330,7 @@ static inline int process_routeset(struct sip_msg* msg, str* contact, struct rte *ruri = *contact; *next_hop = *contact; } - + *list = head; return 0; } @@ -331,13 +340,13 @@ static inline int calc_routeset_len(struct rte* list, str* contact) { struct rte* ptr; int ret; - + if (list || contact) { ret = ROUTE_PREFIX_LEN + CRLF_LEN; } else { return 0; } - + ptr = list; while(ptr) { if (ptr != list) { @@ -346,12 +355,12 @@ static inline int calc_routeset_len(struct rte* list, str* contact) ret += ptr->ptr->len; ptr = ptr->next; } - + if (contact) { if (list) ret += ROUTE_SEPARATOR_LEN; ret += 2 + contact->len; } - + return ret; } @@ -362,30 +371,30 @@ static inline int calc_routeset_len(struct rte* list, str* contact) static inline char* print_rs(char* p, struct rte* list, str* contact) { struct rte* ptr; - + if (list || contact) { append_string(p, ROUTE_PREFIX, ROUTE_PREFIX_LEN); } else { return p; } - + ptr = list; while(ptr) { if (ptr != list) { append_string(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN); } - + append_string(p, ptr->ptr->nameaddr.name.s, ptr->ptr->len); ptr = ptr->next; } - + if (contact) { if (list) append_string(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN); *p++ = '<'; append_string(p, contact->s, contact->len); *p++ = '>'; } - + append_string(p, CRLF, CRLF_LEN); return p; } @@ -398,22 +407,22 @@ static inline char* print_rs(char* p, struct rte* list, str* contact) static inline int get_contact_uri(struct sip_msg* msg, str* uri) { contact_t* c; - + uri->len = 0; if (!msg->contact) return 1; - + if (parse_contact(msg->contact) < 0) { LM_ERR("failed to parse Contact body\n"); return -1; } - + c = ((contact_body_t*)msg->contact->parsed)->contacts; - + if (!c) { LM_ERR("body or * contact\n"); return -2; } - + *uri = c->uri; return 0; } @@ -421,7 +430,7 @@ static inline int get_contact_uri(struct sip_msg* msg, str* uri) /* - * The function creates an ACK for a local INVITE. If 200 OK, route set + * The function creates an ACK for a local INVITE. If 200 OK, route set * will be created and parsed */ char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans, @@ -481,7 +490,7 @@ char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans, set_hostport(&hp, 0); /* build via */ - via = via_builder(&via_len, send_sock, &branch_str, 0, + via = via_builder(&via_len, send_sock, &branch_str, 0, send_sock->proto, &hp); if (!via) { LM_ERR("no via header got from builder\n"); @@ -602,7 +611,7 @@ static inline int assemble_via(str* dest, struct cell* t, struct socket_info* so LM_ERR("branch calculation failed\n"); return -1; } - + branch_str.s = branch_buf; branch_str.len = len; @@ -616,7 +625,7 @@ static inline int assemble_via(str* dest, struct cell* t, struct socket_info* so LM_ERR("via building failed\n"); return -2; } - + dest->s = via; dest->len = via_len; return 0; @@ -628,13 +637,13 @@ static inline int assemble_via(str* dest, struct cell* t, struct socket_info* so */ static inline char* print_request_uri(char* w, str* method, dlg_t* dialog, struct cell* t, int branch) { - append_string(w, method->s, method->len); - append_string(w, " ", 1); + append_string(w, method->s, method->len); + *(w++) = ' '; - t->uac[branch].uri.s = w; + t->uac[branch].uri.s = w; t->uac[branch].uri.len = dialog->hooks.request_uri->len; - append_string(w, dialog->hooks.request_uri->s, dialog->hooks.request_uri->len); + append_string(w, dialog->hooks.request_uri->s, dialog->hooks.request_uri->len); append_string(w, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN); LM_DBG("%.*s\n",dialog->hooks.request_uri->len, dialog->hooks.request_uri->s ); return w; @@ -701,7 +710,7 @@ static inline char* print_from(char* w, dlg_t* dialog, struct cell* t) t->from.len +=1; *(w++) = '<'; } - + append_string(w, dialog->loc_uri.s, dialog->loc_uri.len); if(dialog->loc_dname.len || dialog->id.loc_tag.len) { @@ -726,17 +735,17 @@ static inline char* print_from(char* w, dlg_t* dialog, struct cell* t) char* print_cseq_mini(char* target, str* cseq, str* method) { append_string(target, CSEQ, CSEQ_LEN); append_string(target, cseq->s, cseq->len); - append_string(target, " ", 1); + *(target++) = ' '; append_string(target, method->s, method->len); return target; } static inline char* print_cseq(char* w, str* cseq, str* method, struct cell* t) { - t->cseq_n.s = w; + t->cseq_n.s = w; /* don't include method name and CRLF -- subsequent * local requests ACK/CANCEL will add their own */ - t->cseq_n.len = CSEQ_LEN + cseq->len; + t->cseq_n.len = CSEQ_LEN + cseq->len; w = print_cseq_mini(w, cseq, method); return w; } @@ -767,7 +776,7 @@ static inline char* print_callid(char* w, dlg_t* dialog, struct cell* t) /* * Create a request */ -char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, +char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, int branch, struct cell *t, int* len) { char* buf, *w; @@ -785,7 +794,7 @@ char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, LM_ERR("failed to print CSeq number\n"); return 0; } - *len = method->len + 1 + dialog->hooks.request_uri->len + 1 + + *len = method->len + 1 + dialog->hooks.request_uri->len + 1 + SIP_VERSION_LEN + CRLF_LEN; if (assemble_via(&via, t, dialog->send_sock, branch) < 0) { @@ -795,14 +804,14 @@ char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, *len += via.len; /* To */ - *len += TO_LEN + *len += TO_LEN + (dialog->rem_dname.len ? dialog->rem_dname.len+1 : 0) + dialog->rem_uri.len + (dialog->id.rem_tag.len ? TOTAG_LEN + dialog->id.rem_tag.len : 0) + (dialog->rem_dname.len || dialog->id.rem_tag.len ? 2 : 0) + CRLF_LEN; /* From */ - *len += FROM_LEN + *len += FROM_LEN + (dialog->loc_dname.len ? dialog->loc_dname.len+1 : 0) + dialog->loc_uri.len + (dialog->id.loc_tag.len ? FROMTAG_LEN + dialog->id.loc_tag.len : 0) @@ -832,7 +841,7 @@ char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, LM_ERR("no more share memory\n"); goto error; } - + w = buf; w = print_request_uri(w, method, dialog, t, branch); /* Request-URI */ @@ -872,6 +881,9 @@ char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, if (w-buf != *len ) abort(); #endif + /* make buffer NULL terminated */ + buf[*len] = 0; + pkg_free(via.s); return buf; @@ -881,7 +893,7 @@ char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, } -int t_calc_branch(struct cell *t, +int t_calc_branch(struct cell *t, int b, char *branch, int *branch_len) { return syn_branch ? diff --git a/modules/tm/t_msgbuilder.h b/modules/tm/t_msgbuilder.h index 64a015dad99..c649fa207c3 100644 --- a/modules/tm/t_msgbuilder.h +++ b/modules/tm/t_msgbuilder.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -29,6 +29,7 @@ #define _MSGBUILDER_H #include "../../ip_addr.h" +#include "../../receive.h" #include "dlg.h" @@ -50,7 +51,7 @@ char *build_local(struct cell *Trans, unsigned int branch, str *method, str *extra, struct sip_msg *rpl, unsigned int *len); char *build_uac_request( str msg_type, str dst, str from, - str fromtag, int cseq, str callid, str headers, + str fromtag, int cseq, str callid, str headers, str body, int branch, struct cell *t, unsigned int *len); @@ -77,4 +78,47 @@ int t_calc_branch(struct cell *t, char* print_callid_mini(char* target, str callid); char* print_cseq_mini(char* target, str* cseq, str* method); + +static inline struct sip_msg* buf_to_sip_msg(char *buf, unsigned int len, + dlg_t *dialog) +{ + static struct sip_msg req; + + memset( &req, 0, sizeof(req) ); + req.id = get_next_msg_no(); + req.buf = buf; + req.len = len; + if (parse_msg(buf, len, &req)!=0) { + LM_CRIT("BUG - buffer parsing failed!"); + return NULL; + } + /* parse all headers, to be sure they get cloned in shm */ + if (parse_headers(&req, HDR_EOH_F, 0 )<0) { + LM_ERR("parse_headers failed\n"); + free_sip_msg(&req); + return NULL; + } + /* check if we have all necessary headers */ + if (check_transaction_quadruple(&req)==0) { + LM_ERR("too few headers\n"); + free_sip_msg(&req); + /* stop processing */ + return NULL; + } + + /* populate some special fields in sip_msg */ + req.force_send_socket = dialog->send_sock; + if (set_dst_uri(&req, dialog->hooks.next_hop)) { + LM_ERR("failed to set dst_uri"); + free_sip_msg(&req); + return NULL; + } + req.rcv.proto = dialog->send_sock->proto; + req.rcv.src_ip = req.rcv.dst_ip = dialog->send_sock->address; + req.rcv.src_port = req.rcv.dst_port = dialog->send_sock->port_no; + req.rcv.bind_address = dialog->send_sock; + + return &req; +} + #endif diff --git a/modules/tm/t_reply.c b/modules/tm/t_reply.c index dbfe2feaba1..08107fb9995 100644 --- a/modules/tm/t_reply.c +++ b/modules/tm/t_reply.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -28,7 +28,7 @@ * twice with different values!) (andrei) * 2003-02-28 scratchpad compatibility abandoned (jiri) * 2003-03-01 kr set through a function now (jiri) - * 2003-03-06 saving of to-tags for ACK/200 matching introduced, + * 2003-03-06 saving of to-tags for ACK/200 matching introduced, * voicemail changes accepted, updated to new callback * names (jiri) * 2003-03-10 fixed new to tag bug/typo (if w/o {}) (andrei) @@ -56,10 +56,10 @@ * 2004-02-18 fifo_t_reply imported from vm module (bogdan) * 2004-08-23 avp list is available from failure/on_reply routes (bogdan) * 2004-10-01 added a new param.: restart_fr_on_each_reply (andrei) - * 2005-03-01 force for statefull replies the incoming interface of + * 2005-03-01 force for statefull replies the incoming interface of * the request (bogdan) * 2005-03-01 local ACK sent to same address as INVITE -> - * all [build|send]_[local]_ack functions merged into + * all [build|send]_[local]_ack functions merged into * send_ack() (bogdan) * 2007-01-25 DNS failover at transaction level added (bogdan) */ @@ -144,7 +144,7 @@ void t_on_negative( unsigned int go_to ) struct cell *t = get_t(); /* in MODE_REPLY and MODE_ONFAILURE T will be set to current transaction; - * in MODE_REQUEST T will be set only if the transaction was already + * in MODE_REQUEST T will be set only if the transaction was already * created; if not -> use the static variable */ if (!t || t==T_UNDEFINED ) goto_on_negative=go_to; @@ -158,7 +158,7 @@ void t_on_reply( unsigned int go_to ) struct cell *t = get_t(); /* in MODE_REPLY and MODE_ONFAILURE T will be set to current transaction; - * in MODE_REQUEST T will be set only if the transaction was already + * in MODE_REQUEST T will be set only if the transaction was already * created; if not -> use the static variable */ if (!t || t==T_UNDEFINED ) { goto_on_reply=go_to; @@ -183,7 +183,7 @@ unsigned int get_on_reply(void) void tm_init_tags(void) { - init_tags(tm_tags, &tm_tag_suffix, + init_tags(tm_tags, &tm_tag_suffix, "OpenSIPS-TM/tags", TM_TAG_SEPARATOR ); } @@ -195,7 +195,7 @@ int unmatched_totag(struct cell *t, struct sip_msg *ack) struct totag_elem *i; str *tag; - if (parse_headers(ack, HDR_TO_F,0)==-1 || + if (parse_headers(ack, HDR_TO_F,0)==-1 || !ack->to ) { LM_ERR("To invalid\n"); return 1; @@ -216,7 +216,7 @@ int unmatched_totag(struct cell *t, struct sip_msg *ack) return 1; } -static inline void update_local_tags(struct cell *trans, +static inline void update_local_tags(struct cell *trans, struct bookmark *bm, char *dst_buffer, char *src_buffer /* to which bm refers */) { @@ -227,7 +227,7 @@ static inline void update_local_tags(struct cell *trans, } -/* append a newly received tag from a 200/INVITE to +/* append a newly received tag from a 200/INVITE to * transaction's set; (only safe if called from within * a REPLY_LOCK); it returns 1 if such a to tag already * exists @@ -261,10 +261,15 @@ inline static int update_totag_set(struct cell *t, struct sip_msg *ok) } } /* that's a new to-tag -- record it */ +#ifndef HP_MALLOC shm_lock(); n=(struct totag_elem*) shm_malloc_unsafe(sizeof(struct totag_elem)); s=(char *)shm_malloc_unsafe(tag->len); shm_unlock(); +#else + n=(struct totag_elem*) shm_malloc(sizeof(struct totag_elem)); + s=(char *)shm_malloc(tag->len); +#endif if (!s || !n) { LM_ERR("no more share memory \n"); if (n) shm_free(n); @@ -368,7 +373,7 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, /* t_update_timers_after_sending_reply( rb ); */ trans->relaied_reply_branch=-2; if (lock) UNLOCK_REPLIES( trans ); - + /* do UAC cleanup procedures in case we generated a final answer whereas there are pending UACs */ if (code>=200) { @@ -396,8 +401,8 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, if (!is_hopbyhop_cancel(trans)) { cleanup_uac_timers( trans ); if (is_invite(trans)) cancel_uacs( trans, cancel_bitmap ); - /* for auth related replies, we do not do retransmission - (via set_final_timer()), but only wait for a final + /* for auth related replies, we do not do retransmission + (via set_final_timer()), but only wait for a final reply (put_on_wait() ) - see RFC 3261 (26.3.2.4 DoS Protection) */ if ((code != 401) && (code != 407)) set_final_timer( trans ); @@ -406,7 +411,7 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, } } - /* send it out : response.dst.send_sock is valid all the time now, + /* send it out : response.dst.send_sock is valid all the time now, * as it's taken from original request -bogdan */ if (!trans->uas.response.dst.send_sock) { LM_CRIT("send_sock is NULL\n"); @@ -451,7 +456,7 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len, /* send a UAS reply * returns 1 if everything was OK or -1 for error */ -static int _reply( struct cell *trans, struct sip_msg* p_msg, +static int _reply( struct cell *trans, struct sip_msg* p_msg, unsigned int code, str *text, int lock ) { unsigned int len; @@ -475,8 +480,8 @@ static int _reply( struct cell *trans, struct sip_msg* p_msg, if ( (p_msg->msg_flags ^ trans->uas.request->msg_flags) & FL_FORCE_RPORT ) su_setport( &trans->uas.response.dst.to, p_msg->rcv.src_port ); - if (code>=180 && p_msg->to - && (get_to(p_msg)->tag_value.s==0 + if (code>=180 && p_msg->to + && (get_to(p_msg)->tag_value.s==0 || get_to(p_msg)->tag_value.len==0)) { calc_crc_suffix( p_msg, tm_tag_suffix ); buf = build_res_buf_from_sip_req(code,text, &tm_tag, p_msg, &len, &bm); @@ -503,7 +508,7 @@ static inline void faked_env( struct cell *t,struct sip_msg *msg) if (msg) { swap_route_type( backup_route_type, FAILURE_ROUTE); /* tm actions look in beginning whether transaction is - * set -- whether we are called from a reply-processing + * set -- whether we are called from a reply-processing * or a timer process, we need to set current transaction; * otherwise the actions would attempt to look the transaction * up (unnecessary overhead, refcounting) @@ -549,23 +554,52 @@ static inline int fake_req(struct sip_msg *faked_req, struct sip_msg *shm_msg, faked_req->new_uri.s=pkg_malloc( uac->uri.len+1 ); if (!faked_req->new_uri.s) { LM_ERR("no uri/pkg mem\n"); - goto error; + return 0; } faked_req->new_uri.len = uac->uri.len; memcpy( faked_req->new_uri.s, uac->uri.s, uac->uri.len); faked_req->new_uri.s[faked_req->new_uri.len]=0; faked_req->parsed_uri_ok = 0; + /* + * duplicate the advertised address and port into private mem + * so that they can be changed at script level + */ + if (shm_msg->set_global_address.s) { + faked_req->set_global_address.s = pkg_malloc(shm_msg->set_global_address.len); + if (!faked_req->set_global_address.s) { + LM_ERR("out of pkg mem\n"); + goto out; + } + memcpy(faked_req->set_global_address.s, shm_msg->set_global_address.s, + shm_msg->set_global_address.len); + } + + if (shm_msg->set_global_port.s) { + faked_req->set_global_port.s = pkg_malloc(shm_msg->set_global_port.len); + if (!faked_req->set_global_port.s) { + LM_ERR("out of pkg mem\n"); + goto out1; + } + memcpy(faked_req->set_global_port.s, shm_msg->set_global_port.s, + shm_msg->set_global_port.len); + } + /* we could also restore dst_uri, but will be confusing from script, * so let it set to NULL */ - /* set as flags the global flags and the branch flags from the + /* set as flags the global flags and the branch flags from the * elected branch */ faked_req->flags = uas->request->flags; setb0flags( uac->br_flags); return 1; -error: + +out1: + pkg_free(faked_req->set_global_address.s); +out: + pkg_free(faked_req->new_uri.s); + return 0; } @@ -574,15 +608,23 @@ inline static void free_faked_req(struct sip_msg *faked_req, struct cell *t) { if (faked_req->new_uri.s) { pkg_free(faked_req->new_uri.s); - faked_req->new_uri.s = 0; + faked_req->new_uri.s = NULL; } if (faked_req->dst_uri.s) { pkg_free(faked_req->dst_uri.s); - faked_req->dst_uri.s = 0; + faked_req->dst_uri.s = NULL; } if (faked_req->path_vec.s) { pkg_free(faked_req->path_vec.s); - faked_req->path_vec.s = 0; + faked_req->path_vec.s = NULL; + } + if (faked_req->set_global_address.s) { + pkg_free(faked_req->set_global_address.s); + faked_req->set_global_address.s = NULL; + } + if (faked_req->set_global_port.s) { + pkg_free(faked_req->set_global_port.s); + faked_req->set_global_port.s = NULL; } /* SDP in not cloned into SHM, so if we have one, it means the SDP @@ -592,7 +634,7 @@ inline static void free_faked_req(struct sip_msg *faked_req, struct cell *t) if (faked_req->multi) { free_multi_body(faked_req->multi); - faked_req->multi = 0; + faked_req->multi = NULL; } if (faked_req->msg_cb) { @@ -628,7 +670,7 @@ static inline int run_failure_handlers(struct cell *t) /* don't start faking anything if we don't have to */ if ( !has_tran_tmcbs( t, TMCB_ON_FAILURE) && !t->on_negative ) { - LM_WARN("no negative handler (%d, %d)\n",t->on_negative, + LM_WARN("no negative handler (%d, %d)\n",t->on_negative, t->tmcb_hl.reg_types); return 1; } @@ -648,7 +690,7 @@ static inline int run_failure_handlers(struct cell *t) if (t->on_negative) { /* update flags in transaction if changed by callbacks */ shmem_msg->flags = faked_req.flags; - /* avoid recursion -- if failure_route forwards, and does not + /* avoid recursion -- if failure_route forwards, and does not * set next failure route, failure_route will not be reentered * on failure */ on_failure = t->on_negative; @@ -672,7 +714,7 @@ static inline int run_failure_handlers(struct cell *t) static inline int is_3263_failure(struct cell *t) { /* is is a DNS failover scenario? - according to RFC 3263 - * and RFC 3261, this means 503 reply with Retr-After hdr + * and RFC 3261, this means 503 reply with Retr-After hdr * or timeout with no reply */ LM_DBG("dns-failover test: branch=%d, last_recv=%d, flags=%X\n", picked_branch, t->uac[picked_branch].last_received, @@ -700,10 +742,11 @@ static inline int do_dns_failover(struct cell *t) { static struct sip_msg faked_req; struct sip_msg *shmem_msg; + struct sip_msg *req; struct ua_client *uac; - int ret; + dlg_t dialog; + int ret, sip_msg_len; - shmem_msg = t->uas.request; uac = &t->uac[picked_branch]; /* check if the DNS resolver can get at least one new IP */ @@ -712,6 +755,36 @@ static inline int do_dns_failover(struct cell *t) LM_DBG("new destination available\n"); + if (t->uas.request==NULL) { + if (!is_local(t)) { + LM_CRIT("BUG: proxy transaction without UAS request :-/\n"); + return -1; + } + /* create the cloned SIP msg -> first create a new SIP msg */ + memset( &dialog, 0, sizeof(dialog)); + dialog.send_sock = uac->request.dst.send_sock; + dialog.hooks.next_hop = &uac->uri; + req = buf_to_sip_msg(uac->request.buffer.s, uac->request.buffer.len, + &dialog); + if (req==NULL) { + LM_ERR("failed to generate SIP msg from previous buffer\n"); + return -1; + } + /* now do the actual cloning of the SIP message */ + t->uas.request = sip_msg_cloner( req, &sip_msg_len); + if (t->uas.request==NULL) { + LM_ERR("cloning failed\n"); + free_sip_msg(req); + return -1; + } + t->uas.end_request = ((char*)t->uas.request) + sip_msg_len; + /* free the actual SIP message, keep the clone only */ + free_sip_msg(req); + /* the sip_msg structure is static in buf_to_sip_msg, + so no need to free it */ + } + shmem_msg = t->uas.request; + if (!fake_req(&faked_req, shmem_msg, &t->uas, uac)) { LM_ERR("fake_req failed\n"); return -1; @@ -858,7 +931,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code, Trans->uac[branch].last_received=new_code; *should_relay=branch; return RPS_PUSHED_AFTER_COMPLETION; - } + } if ( is_hopbyhop_cancel(Trans) && new_code>=200) { *should_store=0; *should_relay=-1; @@ -868,7 +941,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code, /* except the exception above, too late messages will be discarded */ goto discard; - } + } /* if final response received at this branch, allow only INVITE 2xx */ if (Trans->uac[branch].last_received>=200 @@ -897,7 +970,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code, if (new_code >=300 ) { Trans->uac[branch].last_received=new_code; - /* also append the current reply to the transaction to + /* also append the current reply to the transaction to * make it available in failure routes - a kind of "fake" * save of the final reply per branch */ Trans->uac[branch].reply = reply; @@ -992,7 +1065,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code, *should_relay=picked_branch; picked_branch=-1; return RPS_COMPLETED; - } + } /* not >=300 ... it must be 2xx or provisional 1xx */ if (new_code>=100) { @@ -1058,13 +1131,13 @@ int t_retransmit_reply( struct cell *t ) -int t_reply( struct cell *t, struct sip_msg* p_msg, unsigned int code, +int t_reply( struct cell *t, struct sip_msg* p_msg, unsigned int code, str * text ) { return _reply( t, p_msg, code, text, 1 /* lock replies */ ); } -int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code, +int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code, str * text ) { return _reply( t, p_msg, code, text, 0 /* don't lock replies */ ); @@ -1091,7 +1164,7 @@ void set_final_timer( /* struct s_table *h_table, */ struct cell *t ) force_retr( &t->uas.response ); return; } - } + } put_on_wait(t); } @@ -1134,10 +1207,10 @@ static int store_reply( struct cell *trans, int branch, struct sip_msg *rpl) } /* this is the code which decides what and when shall be relayed - upstream; note well -- it assumes it is entered locked with + upstream; note well -- it assumes it is entered locked with REPLY_LOCK and it returns unlocked! */ -enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, +enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, unsigned int msg_status, branch_bm_t *cancel_bitmap ) { int relay; @@ -1167,7 +1240,7 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, * forwarding a first final reply or not */ /* *** store and relay message as needed *** */ - reply_status = t_should_relay_response(t, msg_status, branch, + reply_status = t_should_relay_response(t, msg_status, branch, &save_clone, &relay, cancel_bitmap, p_msg ); LM_DBG("branch=%d, save=%d, relay=%d\n", branch, save_clone, relay ); @@ -1196,8 +1269,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, text.s = error_text(relayed_code); text.len = strlen(text.s); /* FIXME - bogdan*/ - if (relayed_code>=180 && t->uas.request->to - && (get_to(t->uas.request)->tag_value.s==0 + if (relayed_code>=180 && t->uas.request->to + && (get_to(t->uas.request)->tag_value.s==0 || get_to(t->uas.request)->tag_value.len==0)) { calc_crc_suffix( t->uas.request, tm_tag_suffix ); buf = build_res_buf_from_sip_req( @@ -1220,8 +1293,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, } relayed_code=relayed_msg->REPLY_STATUS; buf = build_res_buf_from_sip_res( relayed_msg, &res_len, - uas_rb->dst.send_sock); - /* remove all lumps which are not in shm + uas_rb->dst.send_sock,0); + /* remove all lumps which are not in shm * added either by build_res_buf_from_sip_res, or by * the callbacks that have been called with shmem-ed messages - vlad */ if (branch!=relay) { @@ -1237,8 +1310,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, /* attempt to copy the message to UAS's shmem: - copy to-tag for ACK matching as well - allocate little a bit more for provisional as - larger messages are likely to follow and we will be - able to reuse the memory frag + larger messages are likely to follow and we will be + able to reuse the memory frag */ uas_rb->buffer.s = (char*)shm_resize( uas_rb->buffer.s, res_len + (msg_status<200 ? REPLY_OVERBUFFER_LEN : 0)); @@ -1270,8 +1343,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, * to avoid race conditions */ if (reply_status == RPS_COMPLETED) { - /* for auth related replies, we do not do retransmission - (via set_final_timer()), but only wait for a final + /* for auth related replies, we do not do retransmission + (via set_final_timer()), but only wait for a final reply (put_on_wait() ) - see RFC 3261 (26.3.2.4 DoS Protection) */ if ((relayed_code != 401) && (relayed_code != 407)) set_final_timer(t); @@ -1290,7 +1363,7 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, relayed_msg, relayed_code); } SEND_PR_BUFFER( uas_rb, buf, res_len ); - LM_DBG("sent buf=%p: %.9s..., shmem=%p: %.9s\n", + LM_DBG("sent buf=%p: %.9s..., shmem=%p: %.9s\n", buf, buf, uas_rb->buffer.s, uas_rb->buffer.s ); /* run the POST sending out callback */ if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) { @@ -1331,7 +1404,7 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, is received, it triggers a callback; note well -- it assumes it is entered locked with REPLY_LOCK and it returns unlocked! */ -enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch, +enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch, unsigned int msg_status, branch_bm_t *cancel_bitmap) { /* how to deal with replies for local transaction */ @@ -1342,7 +1415,7 @@ enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch, int totag_retr; /* branch_bm_t cancel_bitmap; */ - /* keep warning 'var might be used un-inited' silent */ + /* keep warning 'var might be used un-inited' silent */ winning_msg=0; winning_code=0; totag_retr=0; @@ -1358,7 +1431,7 @@ enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch, goto error; } if (local_winner>=0) { - winning_msg= branch==local_winner + winning_msg= branch==local_winner ? p_msg : t->uac[local_winner].reply; if (winning_msg==FAKED_REPLY) { winning_code = branch==local_winner @@ -1406,7 +1479,7 @@ enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch, } -/* This function is called whenever a reply for our module is received; +/* This function is called whenever a reply for our module is received; * we need to register this function on module initialization; * Returns : 0 - core router stops * 1 - core router relay statelessly @@ -1439,7 +1512,7 @@ int reply_received( struct sip_msg *p_msg ) uac=&t->uac[branch]; LM_DBG("org. status uas=%d, uac[%d]=%d local=%d is_invite=%d)\n", - t->uas.status, branch, uac->last_received, + t->uas.status, branch, uac->last_received, is_local(t), is_invite(t)); last_uac_status=uac->last_received; if_update_stat( tm_enable_stats, tm_rcv_rpls , 1); @@ -1487,7 +1560,7 @@ int reply_received( struct sip_msg *p_msg ) backup_list = 0; } /* transfer transaction flag to branch context */ - p_msg->flags = t->uas.request->flags; + p_msg->flags = t->uas.request ? t->uas.request->flags : 0; setb0flags(t->uac[branch].br_flags); /* run block - first per branch and then global one */ if ( t->uac[branch].on_reply && @@ -1511,7 +1584,8 @@ int reply_received( struct sip_msg *p_msg ) } /* transfer current message context back to t */ t->uac[branch].br_flags = getb0flags(); - t->uas.request->flags = p_msg->flags; + if (t->uas.request) + t->uas.request->flags = p_msg->flags; if (onreply_avp_mode) /* restore original avp list */ set_avp_list( backup_list ); @@ -1558,10 +1632,10 @@ int reply_received( struct sip_msg *p_msg ) /* set_final_timer(t); */ } } - + if (reply_status!=RPS_PROVISIONAL) goto done; - + /* update FR/RETR timers on provisional replies */ if (msg_status < 200 && (restart_fr_on_each_reply || ((last_uac_statususer_avps); - if (!fr_inv_avp2timer(&timer)) { - LM_DBG("FR_INV_TIMER = %lld\n", timer); - set_timer(&uac->request.fr_timer, - FR_INV_TIMER_LIST, &timer); - } else { - set_timer(& uac->request.fr_timer, FR_INV_TIMER_LIST, 0); - } + timer = is_timeout_set(t->fr_inv_timeout) ? + t->fr_inv_timeout : + timer_id2timeout[FR_INV_TIMER_LIST]; + + LM_DBG("FR_INV_TIMER = %lld\n", timer); + set_timer(&uac->request.fr_timer, FR_INV_TIMER_LIST, &timer); set_avp_list(backup_list); } else { /* non-invite: restart retransmissions (slow now) */ @@ -1586,15 +1659,15 @@ int reply_received( struct sip_msg *p_msg ) set_timer(&uac->request.retr_timer, RT_T2, 0); } } /* provisional replies */ - + done: /* we are done with the transaction, so unref it - the reference * was incremented by t_check() function -bogdan*/ t_unref(p_msg); /* don't try to relay statelessly neither on success - * (we forwarded statefully) nor on error; on troubles, - * simply do nothing; that will make the other party to - * retransmit; hopefuly, we'll then be better off + * (we forwarded statefully) nor on error; on troubles, + * simply do nothing; that will make the other party to + * retransmit; hopefuly, we'll then be better off */ _tm_branch_index = 0; return 0; @@ -1603,7 +1676,7 @@ int reply_received( struct sip_msg *p_msg ) return 1; } -int w_t_reply_with_body(struct sip_msg* msg, str* code, str *text, +int w_t_reply_body(struct sip_msg* msg, str* code, str *text, str *body) { struct cell *t; @@ -1698,7 +1771,7 @@ int t_reply_with_body( struct cell *trans, unsigned int code, str *text, to_tag_rpl = *to_tag; } else - if (code>=180 && p_msg->to && (get_to(p_msg)->tag_value.s==0 + if (code>=180 && p_msg->to && (get_to(p_msg)->tag_value.s==0 || get_to(p_msg)->tag_value.len==0)) { calc_crc_suffix( p_msg, tm_tag_suffix ); rpl.s = build_res_buf_from_sip_req(code,text, &tm_tag, p_msg, diff --git a/modules/tm/t_reply.h b/modules/tm/t_reply.h index 56b7e32135e..fba9e746419 100644 --- a/modules/tm/t_reply.h +++ b/modules/tm/t_reply.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -36,7 +36,7 @@ extern int onreply_avp_mode; /* reply processing status */ enum rps { /* something bad happened */ - RPS_ERROR=0, + RPS_ERROR=0, /* transaction completed but we still accept the reply */ RPS_PUSHED_AFTER_COMPLETION, /* reply discarded */ @@ -91,7 +91,7 @@ int t_reply_light( struct cell *trans, char* buf, unsigned int len, char *to_tag, unsigned int to_tag_len); #endif -int t_reply_with_body( struct cell *trans, unsigned int code, +int t_reply_with_body( struct cell *trans, unsigned int code, str *text, str *body, str *new_header, str *to_tag ); @@ -104,12 +104,12 @@ int t_reply( struct cell *t, struct sip_msg * , unsigned int , str * ); processing */ -int w_t_reply_with_body(struct sip_msg* msg,str* code,str *text, str *body); +int w_t_reply_body(struct sip_msg* msg,str* code,str *text, str *body); int t_reply_unsafe( struct cell *t, struct sip_msg * , unsigned int , str * ); -enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, +enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, unsigned int msg_status, branch_bm_t *cancel_bitmap ); enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch, @@ -127,7 +127,7 @@ typedef int (*tget_picked_f)(void); int t_get_picked_branch(); /* set which 'reply' structure to take if only negative - replies arrive + replies arrive */ void t_on_negative( unsigned int go_to ); unsigned int get_on_negative(); diff --git a/modules/tm/t_stats.h b/modules/tm/t_stats.h index 4d7c93c94af..05bb13c5352 100644 --- a/modules/tm/t_stats.h +++ b/modules/tm/t_stats.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -73,7 +73,7 @@ inline static void stats_trans_rpl( int code, int local ) { else update_stat( tm_rld_rpls, 1); - numerical_stat = + numerical_stat = get_stat_var_from_num_code(code, 1); /* Increment the status code. */ @@ -93,8 +93,8 @@ inline static void stats_trans_new( int local ) { } } #else - #define stats_trans_rpl( _code , _local ) - #define stats_trans_new( _local ) + #define stats_trans_rpl( _code , _local ) + #define stats_trans_new( _local ) #endif #endif diff --git a/modules/tm/timer.c b/modules/tm/timer.c index 8897a48bdf8..824f684f281 100644 --- a/modules/tm/timer.c +++ b/modules/tm/timer.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -31,12 +31,12 @@ -/* +/* timer.c is where we implement TM timers. It has been designed for high performance using some techniques of which timer users need to be aware. - One technique is "fixed-timer-length". We maintain separate + One technique is "fixed-timer-length". We maintain separate timer lists, all of them include elements of the same time to fire. That allows *appending* new events to the list as opposed to inserting them by time, which is costly due to @@ -49,7 +49,7 @@ is left. That saves time greatly as whichever process wants to add/remove a timer, it does not have to wait until the current list is processed. However, be aware the timers may hit in a delayed - manner; you have no guarantee in your process that after resetting a timer, + manner; you have no guarantee in your process that after resetting a timer, it will no more hit. It might have been removed by timer process, and is waiting to be executed. The following example shows it: @@ -58,16 +58,16 @@ 0. timer hits, it is removed from queue and about to be executed 1. process1 decides to - reset the timer + reset the timer 2. timer is executed now 3. if the process1 naively - thinks the timer could not - have been executed after + thinks the timer could not + have been executed after resetting the timer, it is WRONG -- it was (step 2.) - So be careful when writing the timer handlers. Currently defined timers - don't hurt if they hit delayed, I hope at least. Retransmission timer + So be careful when writing the timer handlers. Currently defined timers + don't hurt if they hit delayed, I hope at least. Retransmission timer may results in a useless retransmission -- not too bad. FR timer not too bad either as timer processing uses a REPLY mutex making it safe to other processing affecting transaction state. Wait timer not bad either -- processes @@ -86,13 +86,13 @@ The rule of thumb is don't touch data you put under a timer. Create data, put them under a timer, and let them live until they are safely destroyed from - wait/delete timer. The only safe place to manipulate the data is + wait/delete timer. The only safe place to manipulate the data is from timer process in which delayed timers cannot hit (all timers are processed sequentially). A "bad example" -- rewriting content of retransmission buffer - in an unprotected way is bad because a delayed retransmission timer might - hit. Thats why our reply retransmission procedure is enclosed in + in an unprotected way is bad because a delayed retransmission timer might + hit. Thats why our reply retransmission procedure is enclosed in a REPLY_LOCK. */ @@ -115,6 +115,7 @@ static struct timer_table *timertable=0; +static unsigned int timer_sets = 0; static struct timer detached_timer; /* just to have a value to compare with*/ #define DETACHED_LIST (&detached_timer) @@ -240,6 +241,7 @@ static void delete_cell( struct cell *p_cell, int unlock ) } } + static void fake_reply(struct cell *t, int branch, int code ) { branch_bm_t cancel_bitmap; @@ -250,7 +252,7 @@ static void fake_reply(struct cell *t, int branch, int code ) cancel_bitmap=do_cancel_branch ? 1<my_T); abort(); - } + } #endif /* the transaction is already removed from RETRANSMISSION_LIST by timer*/ /* retransmission */ - if ( r_buf->activ_type==TYPE_LOCAL_CANCEL + if ( r_buf->activ_type==TYPE_LOCAL_CANCEL || r_buf->activ_type==TYPE_REQUEST ) { LM_DBG("retransmission_handler : request resending" " (t=%p, %.9s ... )\n", r_buf->my_T, r_buf->buffer.s); @@ -299,7 +301,7 @@ inline static void retransmission_handler( struct timer_link *retr_tl ) id = r_buf->retr_list; r_buf->retr_list = id < RT_T2 ? id + 1 : RT_T2; - + retr_tl->timer_list= NULL; /* set to NULL so that set_timer will work */ set_timer( retr_tl, id < RT_T2 ? id + 1 : RT_T2, 0 ); @@ -326,7 +328,7 @@ inline static void final_response_handler( struct timer_link *fr_tl ) t=r_buf->my_T; # ifdef EXTRA_DEBUG - if (t->damocles) + if (t->damocles) { LM_ERR("transaction %p scheduled for deletion and" " called from FR timer\n",r_buf->my_T); @@ -394,7 +396,7 @@ inline static void wait_handler( struct timer_link *wait_tl ) LM_ERR("transaction %p scheduled for deletion and" " called from WAIT timer\n",p_cell); abort(); - } + } LM_DBG("WAIT timer hit\n"); #endif @@ -428,7 +430,7 @@ inline static void delete_handler( struct timer_link *dele_tl ) LM_ERR("transaction %p not scheduled for deletion" " and called from DELETE timer\n",p_cell); abort(); - } + } #endif /* we call delete now without any locking on hash/ref_count; @@ -457,37 +459,47 @@ void unlink_timer_lists(void) { struct timer_link *tl, *end, *tmp; enum lists i; - - if (timertable==0) return; /* nothing to do */ - /* remember the DELETE LIST */ - tl = timertable->timers[DELETE_LIST].first_tl.next_tl; - end = & timertable->timers[DELETE_LIST].last_tl; - /* unlink the timer lists */ - for( i=0; inext_tl; - free_cell( get_dele_timer_payload(tl) ); - tl=tmp; + unsigned int set; + + if (timertable==0) + return; /* nothing to do */ + + for ( set=0 ; setnext_tl; + free_cell( get_dele_timer_payload(tl) ); + tl=tmp; + } } - + } -struct timer_table *tm_init_timers(void) +struct timer_table *tm_init_timers( unsigned int sets ) { enum lists i; + unsigned int set; - timertable=(struct timer_table *) shm_malloc(sizeof(struct timer_table)); + LM_DBG("creating %d parallel timer structures\n", timer_sets); + + timertable = (struct timer_table *)shm_malloc + ( sets * sizeof(struct timer_table)); if (!timertable) { LM_ERR("no more share memory\n"); goto error0; } - memset(timertable, 0, sizeof (struct timer_table)); + memset(timertable, 0, sets * sizeof(struct timer_table)); + timer_sets = sets; /* check the timeout values */ if ( timer_id2timeout[FR_TIMER_LIST]timers[RT_T1_TO_1].id = RT_T1_TO_1; - timertable->timers[RT_T1_TO_2].id = RT_T1_TO_2; - timertable->timers[RT_T1_TO_3].id = RT_T1_TO_3; - timertable->timers[RT_T2].id = RT_T2; - timertable->timers[FR_TIMER_LIST].id = FR_TIMER_LIST; - timertable->timers[FR_INV_TIMER_LIST].id = FR_INV_TIMER_LIST; - timertable->timers[WT_TIMER_LIST].id = WT_TIMER_LIST; - timertable->timers[DELETE_LIST].id = DELETE_LIST; + /* init all timer sets */ + for( set=0 ; settimers[i] ); shm_free(timertable); } - } -void reset_timer_list( enum lists list_id) + +void reset_timer_list(unsigned int set, enum lists list_id) { - timertable->timers[list_id].first_tl.next_tl = - &(timertable->timers[list_id].last_tl ); - timertable->timers[list_id].last_tl.prev_tl = - &(timertable->timers[list_id].first_tl ); - timertable->timers[list_id].first_tl.prev_tl = - timertable->timers[list_id].last_tl.next_tl = NULL; - timertable->timers[list_id].last_tl.time_out = -1; + timertable[set].timers[list_id].first_tl.next_tl = + &(timertable[set].timers[list_id].last_tl ); + timertable[set].timers[list_id].last_tl.prev_tl = + &(timertable[set].timers[list_id].first_tl ); + timertable[set].timers[list_id].first_tl.prev_tl = + timertable[set].timers[list_id].last_tl.next_tl = NULL; + timertable[set].timers[list_id].last_tl.time_out = -1; } - - -void init_timer_list( enum lists list_id) +void init_timer_list(unsigned int set, enum lists list_id) { - reset_timer_list( list_id ); - init_timerlist_lock( list_id ); + reset_timer_list( set, list_id ); + init_timerlist_lock( set, list_id ); } -void print_timer_list( enum lists list_id) +void print_timer_list(unsigned int set, enum lists list_id) { - struct timer* timer_list=&(timertable->timers[ list_id ]); + struct timer* timer_list=&(timertable[set].timers[ list_id ]); struct timer_link *tl ; tl = timer_list->first_tl.next_tl; @@ -607,22 +620,21 @@ void print_timer_list( enum lists list_id) #ifdef TM_TIMER_DEBUG -static void check_timer_list(enum lists list_id, char *txt ) +static void check_timer_list( struct timer* timer_list, char *txt) { - struct timer* timer_list=&(timertable->timers[ list_id ]); struct timer_link *tl ; struct timer_link *tl1 ; if (list_id<0 || list_id>=NR_OF_TIMER_LISTS) { - LM_CRIT("------- list [%d] bug [%s]\n",list_id, txt); - abort(0); + LM_CRIT("TM TIMER list [%d] bug [%s]\n",timer_list->id, txt); + abort(); } tl = timer_list->last_tl.prev_tl; while (tl!=&timer_list->first_tl) { if (tl->prev_tl==0) { - LM_CRIT("------- list [%d] prev_tl==0 [%s]\n",list_id, txt); - abort(0); + LM_CRIT("TM TIMER list [%d] prev_tl==0 [%s]\n",timer_list->id, txt); + abort(); } tl = tl->prev_tl; } @@ -630,8 +642,8 @@ static void check_timer_list(enum lists list_id, char *txt ) tl = timer_list->first_tl.next_tl; while (tl!=&timer_list->last_tl) { if (tl->next_tl==0) { - LM_CRIT("------- list [%d] next_tl==0 [%s]\n",list_id, txt); - abort(0); + LM_CRIT("TM TIMER list [%d] next_tl==0 [%s]\n",timer_list->id, txt); + abort(); } tl = tl->next_tl; } @@ -639,22 +651,23 @@ static void check_timer_list(enum lists list_id, char *txt ) tl = timer_list->first_tl.next_tl; while (tl!=&timer_list->last_tl) { if (tl->ld_tl==0) { - LM_CRIT("------- list [%d] currupted - ld=0 [%s]\n",list_id, txt); - abort(0); + LM_CRIT("TM TIMER list [%d] currupted - ld=0 [%s]\n", + timer_list->id, txt); + abort(); } if (tl->ld_tl->ld_tl!=tl) { - LM_CRIT("------- list [%d] currupted - ld cycle broken [%s]\n", - list_id, txt); - abort(0); + LM_CRIT("TM TIMER list [%d] currupted - ld cycle broken [%s]\n", + timer_list->id, txt); + abort(); } if (tl->ld_tl!=tl) { tl1 = tl->next_tl; while(tl1!=tl->ld_tl) { if (tl1->ld_tl) { - LM_CRIT("------- list [%d] currupted - ld!=0 inside " - "cycle [%s]\n", list_id, txt); - abort(0); + LM_CRIT("TM TIMER list [%d] currupted - ld!=0 inside " + "cycle [%s]\n", timer_list->id, txt); + abort(); } tl1 = tl1->next_tl; } @@ -677,11 +690,11 @@ static void remove_timer_unsafe( struct timer_link* tl ) #endif if (is_in_timer_list2( tl )) { #ifdef EXTRA_DEBUG - LM_DBG("unlinking timer: tl=%p, timeout=%lld, group=%d\n", + LM_DBG("unlinking timer: tl=%p, timeout=%lld, group=%d\n", tl, tl->time_out, tl->tg); #endif #ifdef TM_TIMER_DEBUG - check_timer_list( tl->timer_list->id, "before remove" ); + check_timer_list( tl->timer_list, "before remove" ); #endif if (tl->ld_tl && tl->ld_tl!=tl) { if (tl->time_out==tl->prev_tl->time_out) { @@ -695,7 +708,7 @@ static void remove_timer_unsafe( struct timer_link* tl ) tl->prev_tl->next_tl = tl->next_tl; tl->next_tl->prev_tl = tl->prev_tl; #ifdef TM_TIMER_DEBUG - check_timer_list( tl->timer_list->id, "after remove" ); + check_timer_list( tl->timer_list, "after remove" ); #endif tl->next_tl = 0; tl->prev_tl = 0; @@ -705,7 +718,7 @@ static void remove_timer_unsafe( struct timer_link* tl ) } -/* put a new cell into a list nr. list_id */ +/* put a new linker into a timer_list */ static void insert_timer_unsafe( struct timer *timer_list, struct timer_link *tl, utime_t time_out ) { @@ -716,7 +729,7 @@ static void insert_timer_unsafe( struct timer *timer_list, tl->deleted = 0; #ifdef TM_TIMER_DEBUG - check_timer_list( timer_list->id, "before insert" ); + check_timer_list( timer_list, "before insert" ); #endif ptr = timer_list->last_tl.prev_tl; for( ; ptr != &timer_list->first_tl ; ptr = ptr->ld_tl->prev_tl) { @@ -738,7 +751,7 @@ static void insert_timer_unsafe( struct timer *timer_list, tl->ld_tl = tl; } #ifdef TM_TIMER_DEBUG - check_timer_list( timer_list->id, "after insert" ); + check_timer_list( timer_list, "after insert" ); #endif LM_DBG("[%d]: %p (%lld)\n",timer_list->id, @@ -755,7 +768,7 @@ static struct timer_link *check_and_split_time_list( struct timer *timer_list, /* quick check whether it is worth entering the lock */ - if (timer_list->first_tl.next_tl==&timer_list->last_tl + if (timer_list->first_tl.next_tl==&timer_list->last_tl || ( /* timer_list->first_tl.next_tl && */ timer_list->first_tl.next_tl->time_out > time) ) return NULL; @@ -764,7 +777,7 @@ static struct timer_link *check_and_split_time_list( struct timer *timer_list, lock(timer_list->mutex); #ifdef TM_TIMER_DEBUG - check_timer_list( timer_list->id, "before split" ); + check_timer_list( timer_list, "before split" ); #endif end = &timer_list->last_tl; tl = timer_list->first_tl.next_tl; @@ -787,7 +800,7 @@ static struct timer_link *check_and_split_time_list( struct timer *timer_list, tl->timer_list = DETACHED_LIST; } #ifdef TM_TIMER_DEBUG - check_timer_list( timer_list->id, "after split" ); + check_timer_list( timer_list, "after split" ); #endif #ifdef EXTRA_DEBUG @@ -856,7 +869,7 @@ void set_timer( struct timer_link *new_tl, enum lists list_id, } LM_DBG("relative timeout is %lld\n",timeout); - list= &(timertable->timers[ list_id ]); + list= &(timertable[new_tl->set].timers[ list_id ]); lock(list->mutex); /* check first if we are on the "detached" timer_routine list, @@ -902,7 +915,7 @@ void set_1timer( struct timer_link *new_tl, enum lists list_id, timeout = *ext_timeout; } - list= &(timertable->timers[ list_id ]); + list= &(timertable[new_tl->set].timers[ list_id ]); lock(list->mutex); if (!new_tl->time_out) { @@ -920,6 +933,7 @@ static void unlink_timers( struct cell *t ) { int i; int remove_fr, remove_retr; + unsigned short set; remove_fr=0; remove_retr=0; @@ -932,14 +946,14 @@ static void unlink_timers( struct cell *t ) be removed from timer process itself -> it is safe to use it without any protection */ - if (is_in_timer_list2(&t->uas.response.fr_timer)) remove_fr=1; + if (is_in_timer_list2(&t->uas.response.fr_timer)) remove_fr=1; else for (i=0; inr_of_outgoings; i++) if (is_in_timer_list2(&t->uac[i].request.fr_timer) || is_in_timer_list2(&t->uac[i].local_cancel.fr_timer)) { remove_fr=1; break; } - if (is_in_timer_list2(&t->uas.response.retr_timer)) remove_retr=1; + if (is_in_timer_list2(&t->uas.response.retr_timer)) remove_retr=1; else for (i=0; inr_of_outgoings; i++) if (is_in_timer_list2(&t->uac[i].request.retr_timer) || is_in_timer_list2(&t->uac[i].local_cancel.retr_timer)) { @@ -947,30 +961,32 @@ static void unlink_timers( struct cell *t ) break; } + set = t->wait_tl.set; + /* do what we have to do....*/ if (remove_retr) { /* RT_T1 lock is shared by all other RT timer lists -- we can safely lock just one */ - lock(timertable->timers[RT_T1_TO_1].mutex); + lock(timertable[set].timers[RT_T1_TO_1].mutex); remove_timer_unsafe(&t->uas.response.retr_timer); for (i=0; inr_of_outgoings; i++) { remove_timer_unsafe(&t->uac[i].request.retr_timer); remove_timer_unsafe(&t->uac[i].local_cancel.retr_timer); } - unlock(timertable->timers[RT_T1_TO_1].mutex); + unlock(timertable[set].timers[RT_T1_TO_1].mutex); } if (remove_fr) { /* FR lock is shared by all other FR timer lists -- we can safely lock just one */ - lock(timertable->timers[FR_TIMER_LIST].mutex); + lock(timertable[set].timers[FR_TIMER_LIST].mutex); remove_timer_unsafe(&t->uas.response.fr_timer); for (i=0; inr_of_outgoings; i++) { remove_timer_unsafe(&t->uac[i].request.fr_timer); remove_timer_unsafe(&t->uac[i].local_cancel.fr_timer); } - unlock(timertable->timers[FR_TIMER_LIST].mutex); + unlock(timertable[set].timers[FR_TIMER_LIST].mutex); } } @@ -993,7 +1009,7 @@ static void unlink_timers( struct cell *t ) -void timer_routine(unsigned int ticks , void * attr) +void timer_routine(unsigned int ticks , void *set) { struct timer_link *tl, *tmp_tl; int id; @@ -1002,7 +1018,7 @@ void timer_routine(unsigned int ticks , void * attr) { /* to waste as little time in lock as possible, detach list with expired items and process them after leaving the lock */ - tl=check_and_split_time_list( &timertable->timers[ id ], ticks); + tl=check_and_split_time_list( &timertable[(long)set].timers[ id ], ticks); /* process items now */ switch (id) { @@ -1022,7 +1038,7 @@ void timer_routine(unsigned int ticks , void * attr) -void utimer_routine(utime_t uticks , void * attr) +void utimer_routine(utime_t uticks , void *set) { struct timer_link *tl, *tmp_tl; int id; @@ -1031,7 +1047,7 @@ void utimer_routine(utime_t uticks , void * attr) { /* to waste as little time in lock as possible, detach list with expired items and process them after leaving the lock */ - tl=check_and_split_time_list( &timertable->timers[ id ], uticks); + tl=check_and_split_time_list( &timertable[(long)set].timers[ id ], uticks); /* process items now */ switch (id) { diff --git a/modules/tm/timer.h b/modules/tm/timer.h index ef2865c84ef..eda7ffba795 100644 --- a/modules/tm/timer.h +++ b/modules/tm/timer.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -59,7 +59,8 @@ typedef struct timer_link struct timer_link *ld_tl; volatile utime_t time_out; struct timer *timer_list; - unsigned int deleted; + unsigned short deleted; + unsigned short set; #ifdef EXTRA_DEBUG enum timer_groups tg; #endif @@ -92,11 +93,11 @@ extern unsigned int timer_id2timeout[NR_OF_TIMER_LISTS]; -struct timer_table * tm_init_timers(); +struct timer_table * tm_init_timers( unsigned int sets ); void unlink_timer_lists(); void free_timer_table(); -void init_timer_list( enum lists list_id); -void reset_timer_list( enum lists list_id); +void init_timer_list( unsigned int set, enum lists list_id); +void reset_timer_list( unsigned int set, enum lists list_id); void reset_timer( struct timer_link* tl ); diff --git a/modules/tm/tm.c b/modules/tm/tm.c index 857c696efbc..8dad7d74be5 100644 --- a/modules/tm/tm.c +++ b/modules/tm/tm.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -39,7 +39,7 @@ * 2004-02-11 FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri) * 2004-02-18 t_reply exported via FIFO - imported from VM (bogdan) * 2004-10-01 added a new param.: restart_fr_on_each_reply (andrei) - * 2005-05-30 light version of tm_load - find_export dropped -> module + * 2005-05-30 light version of tm_load - find_export dropped -> module * interface dosen't need to export internal functions (bogdan) * 2006-01-15 merged functions which diff only via proto (like t_relay, * t_replicate and t_forward_nonack) (bogdan) @@ -87,6 +87,10 @@ static int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param, static int pv_get_tm_ruri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); +/* TODO: remove in future versions (deprecated parameters) */ +int __set_fr_timer(modparam_t type, void* val); +int __set_fr_inv_timer(modparam_t type, void* val); + /* fixup functions */ static int fixup_t_send_reply(void** param, int param_no); static int fixup_local_replied(void** param, int param_no); @@ -97,6 +101,7 @@ static int fixup_cancel_branch(void** param, int param_no); static int fixup_froute(void** param, int param_no); static int fixup_rroute(void** param, int param_no); static int fixup_broute(void** param, int param_no); +static int fixup_t_new_request(void** param, int param_no); /* init functions */ @@ -121,13 +126,14 @@ inline static int t_was_cancelled(struct sip_msg* msg, char* , char* ); inline static int w_t_cancel_branch(struct sip_msg* msg, char* ); inline static int w_t_add_hdrs(struct sip_msg* msg, char* ); int t_cancel_trans(struct cell *t, str *hdrs); +inline static int w_t_new_request(struct sip_msg* msg, char*, char*, char*, char*, char*, char*); struct sip_msg* tm_pv_context_request(struct sip_msg* msg); struct sip_msg* tm_pv_context_reply(struct sip_msg* msg); -/* strings with avp definition */ -static char *fr_timer_param = NULL; -static char *fr_inv_timer_param = NULL; +/* these values are used when the transaction has not been defined yet */ +int fr_timeout; +int fr_inv_timeout; #define TM_CANCEL_BRANCH_ALL (1<<0) #define TM_CANCEL_BRANCH_OTHERS (1<<1) @@ -139,9 +145,16 @@ static char *fr_inv_timer_param = NULL; #define PV_LOCAL_BUF_SIZE 511 static char pv_local_buf[PV_LOCAL_BUF_SIZE+1]; +static str uac_ctx_avp = str_init("uac_ctx"); +static int uac_ctx_avp_id; + -int pv_get_tm_branch_avp(struct sip_msg*, pv_param_t*, pv_value_t*); -int pv_set_tm_branch_avp(struct sip_msg*, pv_param_t*, int, pv_value_t*); +int pv_get_tm_branch_avp(struct sip_msg*, pv_param_t*, pv_value_t*); +int pv_set_tm_branch_avp(struct sip_msg*, pv_param_t*, int, pv_value_t*); +int pv_get_tm_fr_timeout(struct sip_msg*, pv_param_t *, pv_value_t*); +int pv_set_tm_fr_timeout(struct sip_msg*, pv_param_t *, int, pv_value_t*); +int pv_get_tm_fr_inv_timeout(struct sip_msg*, pv_param_t *, pv_value_t*); +int pv_set_tm_fr_inv_timeout(struct sip_msg*, pv_param_t *, int, pv_value_t*); struct usr_avp** get_bavp_list(void); @@ -165,47 +178,53 @@ stat_var *tm_trans_inuse; static cmd_export_t cmds[]={ {"t_newtran", (cmd_function)w_t_newtran, 0, 0, - 0, REQUEST_ROUTE}, + 0, REQUEST_ROUTE}, {"t_reply", (cmd_function)w_pv_t_reply, 2, fixup_t_send_reply, - 0, REQUEST_ROUTE | FAILURE_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"t_replicate", (cmd_function)w_t_replicate, 1, fixup_t_replicate, - 0, REQUEST_ROUTE}, + 0, REQUEST_ROUTE}, {"t_replicate", (cmd_function)w_t_replicate, 2, fixup_t_replicate, - 0, REQUEST_ROUTE}, + 0, REQUEST_ROUTE}, {"t_relay", (cmd_function)w_t_relay, 0, 0, - 0, REQUEST_ROUTE | FAILURE_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"t_relay", (cmd_function)w_t_relay, 1, fixup_t_relay1, - 0, REQUEST_ROUTE | FAILURE_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"t_relay", (cmd_function)w_t_relay, 2, fixup_t_relay2, - 0, REQUEST_ROUTE | FAILURE_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE }, {"t_on_failure", (cmd_function)w_t_on_negative, 1, fixup_froute, - 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"t_on_reply", (cmd_function)w_t_on_reply, 1, fixup_rroute, - 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"t_on_branch", (cmd_function)w_t_on_branch, 1, fixup_broute, - 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, {"t_check_status", (cmd_function)t_check_status, 1, fixup_regexp_null, - 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, {"t_write_req", (cmd_function)t_write_req, 2, fixup_t_write, - 0, REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE }, {"t_write_unix", (cmd_function)t_write_unix, 2, fixup_t_write, - 0, REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE }, {"t_flush_flags", (cmd_function)t_flush_flags, 0, 0, - 0, REQUEST_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE | BRANCH_ROUTE }, {"t_local_replied", (cmd_function)t_local_replied, 1, fixup_local_replied, - 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE }, {"t_check_trans", (cmd_function)t_check_trans, 0, 0, - 0, REQUEST_ROUTE | BRANCH_ROUTE }, + 0, REQUEST_ROUTE | BRANCH_ROUTE }, {"t_was_cancelled", (cmd_function)t_was_cancelled, 0, 0, - 0, FAILURE_ROUTE | ONREPLY_ROUTE }, + 0, FAILURE_ROUTE | ONREPLY_ROUTE }, {"t_cancel_branch", (cmd_function)w_t_cancel_branch,0, 0, - 0, ONREPLY_ROUTE }, + 0, ONREPLY_ROUTE }, {"t_cancel_branch", (cmd_function)w_t_cancel_branch,1, fixup_cancel_branch, - 0, ONREPLY_ROUTE }, + 0, ONREPLY_ROUTE }, {"t_add_hdrs", (cmd_function)w_t_add_hdrs, 1, fixup_spve_null, - 0, REQUEST_ROUTE }, - {"t_reply_with_body",(cmd_function)w_t_reply_with_body,3, fixup_t_send_reply, - 0, REQUEST_ROUTE }, + 0, REQUEST_ROUTE }, + {"t_reply_with_body",(cmd_function)w_t_reply_body, 3,fixup_t_send_reply, + 0, REQUEST_ROUTE }, + {"t_new_request", (cmd_function)w_t_new_request, 4, fixup_t_new_request, + 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"t_new_request", (cmd_function)w_t_new_request, 5, fixup_t_new_request, + 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, + {"t_new_request", (cmd_function)w_t_new_request, 6, fixup_t_new_request, + 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"load_tm", (cmd_function)load_tm, 0, 0, 0, 0}, {0,0,0,0,0,0} @@ -217,10 +236,14 @@ static param_export_t params[]={ &ruri_matching}, {"via1_matching", INT_PARAM, &via1_matching}, - {"fr_timer", INT_PARAM, + {"fr_timeout", INT_PARAM, &(timer_id2timeout[FR_TIMER_LIST])}, - {"fr_inv_timer", INT_PARAM, + {"fr_inv_timeout", INT_PARAM, &(timer_id2timeout[FR_INV_TIMER_LIST])}, + {"fr_timer", INT_PARAM|USE_FUNC_PARAM, + __set_fr_timer}, + {"fr_inv_timer", INT_PARAM|USE_FUNC_PARAM, + __set_fr_inv_timer}, {"wt_timer", INT_PARAM, &(timer_id2timeout[WT_TIMER_LIST])}, {"delete_timer", INT_PARAM, @@ -233,10 +256,6 @@ static param_export_t params[]={ &tm_unix_tx_timeout}, {"restart_fr_on_each_reply", INT_PARAM, &restart_fr_on_each_reply}, - {"fr_timer_avp", STR_PARAM, - &fr_timer_param}, - {"fr_inv_timer_avp", STR_PARAM, - &fr_inv_timer_param}, {"tw_append", STR_PARAM|USE_FUNC_PARAM, (void*)parse_tw_append }, { "enable_stats", INT_PARAM, @@ -287,6 +306,10 @@ static pv_export_t mod_items[] = { 0, 0, 0, 0 }, { {"bavp", sizeof("bavp")-1}, 903, pv_get_tm_branch_avp, pv_set_tm_branch_avp, pv_parse_avp_name, pv_parse_index, 0, 0 }, + { {"T_fr_timeout", sizeof("T_fr_timeout")-1}, 904, pv_get_tm_fr_timeout, + pv_set_tm_fr_timeout, 0, 0, 0, 0 }, + { {"T_fr_inv_timeout", sizeof("T_fr_inv_timeout")-1}, 905, + pv_get_tm_fr_inv_timeout, pv_set_tm_fr_inv_timeout, 0, 0, 0, 0 }, { {0, 0}, 0, 0, 0, 0, 0, 0, 0 } }; @@ -306,8 +329,10 @@ struct module_exports tm_exports = { struct module_exports exports= { #endif "tm", /* module name*/ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported variables */ mod_stats, /* exported statistics */ @@ -326,7 +351,7 @@ struct module_exports exports= { static int fixup_froute(void** param, int param_no) { int rt; - + rt = get_script_route_ID_by_name( (char *)*param, failure_rlist, FAILURE_RT_NO); if (rt==-1) { @@ -342,7 +367,7 @@ static int fixup_froute(void** param, int param_no) static int fixup_rroute(void** param, int param_no) { int rt; - + rt = get_script_route_ID_by_name( (char *)*param, onreply_rlist, ONREPLY_RT_NO); if (rt==-1) { @@ -358,7 +383,7 @@ static int fixup_rroute(void** param, int param_no) static int fixup_broute(void** param, int param_no) { int rt; - + rt = get_script_route_ID_by_name( (char *)*param, branch_rlist, BRANCH_RT_NO); if (rt==-1) { @@ -399,7 +424,7 @@ static int fixup_t_replicate(void** param, int param_no) s.s = (char*)*param; s.len = strlen(s.s); model = NULL; - + if(pv_parse_format(&s ,&model) || model==NULL) { LM_ERR("wrong format [%s] for param no %d!\n", s.s, param_no); return E_CFG; @@ -426,7 +451,7 @@ static int fixup_phostport2proxy(void** param, int param_no) str host; if (param_no!=1) { - LM_CRIT("called with more than one parameter\n"); + LM_CRIT("called with more than one parameter\n"); return E_BUG; } @@ -573,10 +598,17 @@ static int fixup_cancel_branch(void** param, int param_no) pkg_free(*param); *param = (void*)(unsigned long)flags; return 0; +} + +static int fixup_t_new_request(void** param, int param_no) +{ + /* static string or pv-format for all parameters */ + return fixup_spve(param); } + /***************************** init functions *****************************/ int load_tm( struct tm_binds *tmb) { @@ -584,6 +616,7 @@ int load_tm( struct tm_binds *tmb) /* relay function */ tmb->t_relay = (cmd_function)w_t_relay; + /* reply functions */ tmb->t_reply = (treply_f)w_t_reply; tmb->t_reply_with_body = t_reply_with_body; @@ -591,6 +624,7 @@ int load_tm( struct tm_binds *tmb) /* transaction location/status functions */ tmb->t_newtran = t_newtran; tmb->t_is_local = t_is_local; + tmb->t_check_trans = (cmd_function)t_check_trans; tmb->t_get_trans_ident = t_get_trans_ident; tmb->t_lookup_ident = t_lookup_ident; tmb->t_gett = get_t; @@ -639,7 +673,7 @@ static int do_t_cleanup( struct sip_msg *foo, void *bar) reset_e2eack_t(); - return t_unref(foo); + return t_unref(foo) == 0 ? SCB_DROP_MSG : SCB_RUN_ALL; } @@ -651,19 +685,26 @@ static int script_init( struct sip_msg *foo, void *bar) set_t(T_UNDEFINED); reset_cancelled_t(); reset_e2eack_t(); - /* reset the kr status */ + fr_timeout = timer_id2timeout[FR_TIMER_LIST]; + fr_inv_timeout = timer_id2timeout[FR_INV_TIMER_LIST]; + + /* reset the kill reason status */ reset_kr(); + /* reset the static holders for T routes */ t_on_negative( 0 ); t_on_reply(0); t_on_branch(0); - return 1; + + return SCB_RUN_ALL; } static int mod_init(void) { void *timer; + unsigned int timer_sets,set; + unsigned int roundto_init; LM_INFO("TM - initializing...\n"); @@ -675,7 +716,7 @@ static int mod_init(void) return -1; } - fix_flag_name(&minor_branch_flag_str, minor_branch_flag); + fix_flag_name(minor_branch_flag_str, minor_branch_flag); minor_branch_flag = get_flag_id_by_name(FLAG_TYPE_BRANCH, minor_branch_flag_str); @@ -703,8 +744,15 @@ static int mod_init(void) return -1; } + /* how many timer sets do we need to create? */ + timer_sets = (own_timer_proc<=1)?1:own_timer_proc ; + + /* try first allocating all the structures needed for syncing */ + if (lock_initialize( timer_sets )==-1) + return -1; + /* building the hash table*/ - if (!init_hash_table()) { + if (!init_hash_table( timer_sets )) { LM_ERR("initializing hash_table failed\n"); return -1; } @@ -712,23 +760,39 @@ static int mod_init(void) /* init static hidden values */ init_t(); - if (!tm_init_timers()) { + if (!tm_init_timers( timer_sets ) ) { LM_ERR("timer init failed\n"); return -1; } + /* the ROUNDTO macro taken from the locking interface */ +#ifdef ROUNDTO + roundto_init = ROUNDTO; +#else + roundto_init = sizeof(void *); +#endif + while (roundto_init != 1) { + tm_timer_shift++; + roundto_init >>= 1; + } + + LM_DBG("timer set shift is %d\n", tm_timer_shift); + + /* register the timer functions */ if (own_timer_proc) { - timer = register_timer_process( "tm-timer", timer_routine, NULL, 1, - TIMER_PROC_INIT_FLAG); - if (timer==NULL) { - LM_ERR("failed to register timer\n"); - return -1; - } - if (append_utimer_to_process( "tm-utimer", utimer_routine, 0, - 100*1000, timer)<0) { - LM_ERR("failed to register utimer\n"); - return -1; + for ( set=0 ; set\n",uac_ctx_avp.s); return -1; } return 0; } + static int child_init(int rank) { if (child_init_callid(rank) < 0) { @@ -1050,7 +1114,7 @@ inline static int w_pv_t_reply(struct sip_msg *msg, char* code, char* text) } -inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar ) +inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar ) { /* t_newtran returns 0 on error (negative value means 'transaction exists' */ @@ -1124,22 +1188,27 @@ static inline int t_relay_inerr2scripterr(void) inline static int w_t_relay( struct sip_msg *p_msg , char *proxy, char *flags) { + struct proxy_l *p = NULL; struct cell *t; int ret; t=get_t(); + if (proxy && (p=clone_proxy((struct proxy_l*)proxy))==0) { + LM_ERR("failed to clone proxy, dropping packet\n"); + return -1; + } + if (!t || t==T_UNDEFINED) { /* no transaction yet */ if (route_type==FAILURE_ROUTE) { - LM_CRIT(" BUG - undefined transaction in failure route\n"); + LM_CRIT("BUG - undefined transaction in failure route\n"); return -1; } - ret = t_relay_to( p_msg, (struct proxy_l *)proxy, (int)(long)flags ); + ret = t_relay_to( p_msg, p, (int)(long)flags ); if (ret<0) { ret = t_relay_inerr2scripterr(); } - return ret?ret:1; } else { /* transaction already created */ @@ -1157,14 +1226,19 @@ inline static int w_t_relay( struct sip_msg *p_msg , char *proxy, char *flags) if (((int)(long)flags)&TM_T_REPLY_reason_FLAG) t->flags|=T_CANCEL_REASON_FLAG; - ret = t_forward_nonack( t, p_msg, (struct proxy_l *)proxy); + ret = t_forward_nonack( t, p_msg, p); if (ret<=0 ) { LM_ERR("t_forward_nonack failed\n"); ret = t_relay_inerr2scripterr(); } - return ret?ret:1; } + if (p) { + free_proxy(p); + pkg_free(p); + } + return ret?ret:1; + route_err: LM_CRIT("unsupported route type: %d\n", route_type); return 0; @@ -1275,6 +1349,160 @@ inline static int w_t_add_hdrs(struct sip_msg* msg, char *p_val ) } +inline static int w_t_new_request(struct sip_msg* msg, char *p_method, + char *p_ruri, char *p_from, char *p_to, char *p_body, char *p_ctx) +{ +#define CONTENT_TYPE_HDR "Content-Type: " +#define CONTENT_TYPE_HDR_LEN (sizeof(CONTENT_TYPE_HDR)-1) + static dlg_t dlg; + struct usr_avp **avp_list; + str ruri; + str method; + str body; + str headers; + str s; + int_str ctx; + char *p; + + memset( &dlg, 0, sizeof(dlg_t)); + + /* evaluate the parameters */ + + /* method */ + if ( fixup_get_svalue(msg, (gparam_p)p_method, &method)<0 ) { + LM_ERR("failed to extract METHOD param\n"); + return -1; + } + LM_DBG("setting METHOD to <%.*s>\n", method.len, method.s); + + /* ruri - next hop is the same as RURI */ + dlg.hooks.next_hop = dlg.hooks.request_uri = &ruri; + if ( fixup_get_svalue(msg, (gparam_p)p_ruri, &ruri)<0 ) { + LM_ERR("failed to extract RURI param\n"); + return -1; + } + LM_DBG("setting RURI to <%.*s>\n", + dlg.hooks.next_hop->len, dlg.hooks.next_hop->s); + + /* FROM URI + display */ + if ( fixup_get_svalue(msg, (gparam_p)p_from, &s)<0 ) { + LM_ERR("failed to extract FROM param\n"); + return -1; + } + if ( (p=q_memrchr(s.s, ' ', s.len))==NULL ) { + /* no display, only FROM URI */ + dlg.loc_uri = s; + dlg.loc_dname.s = NULL; + dlg.loc_dname.len = 0; + } else { + /* display + URI */ + dlg.loc_uri.s = p+1; + dlg.loc_uri.len = s.s+s.len - dlg.loc_uri.s; + dlg.loc_dname.s = s.s; + dlg.loc_dname.len = p - s.s; + } + LM_DBG("setting FROM to <%.*s> + <%.*s>\n", + dlg.loc_dname.len, dlg.loc_dname.s, + dlg.loc_uri.len, dlg.loc_uri.s); + + /* TO URI + display */ + if ( fixup_get_svalue(msg, (gparam_p)p_to, &s)<0 ) { + LM_ERR("failed to extract TO param\n"); + return -1; + } + if ( (p=q_memrchr(s.s, ' ', s.len))==NULL ) { + /* no display, only TO URI */ + dlg.rem_uri = s; + dlg.rem_dname.s = NULL; + dlg.rem_dname.len = 0; + } else { + /* display + URI */ + dlg.rem_uri.s = p+1; + dlg.rem_uri.len = s.s+s.len - dlg.rem_uri.s; + dlg.rem_dname.s = s.s; + dlg.rem_dname.len = p - s.s; + } + LM_DBG("setting TO to <%.*s> + <%.*s>\n", + dlg.rem_dname.len, dlg.rem_dname.s, + dlg.rem_uri.len, dlg.rem_uri.s); + + /* BODY and Content-Type */ + if (p_body!=NULL) { + if ( fixup_get_svalue(msg, (gparam_p)p_body, &body)<0 ) { + LM_ERR("failed to extract BODY param\n"); + return -1; + } + if ( (p=q_memchr(body.s, ' ', body.len))==NULL ) { + LM_ERR("Content Type not found in the beginning of body <%.*s>\n", + body.len, body.s); + return -1; + } + /* build the Content-type header */ + headers.len = CONTENT_TYPE_HDR_LEN + (p-body.s) + CRLF_LEN; + if ( (headers.s=(char*)pkg_malloc(headers.len))==NULL ) { + LM_ERR("failed to get pkg mem (needed %d)\n",headers.len); + return -1; + } + memcpy( headers.s, CONTENT_TYPE_HDR, CONTENT_TYPE_HDR_LEN); + memcpy( headers.s+CONTENT_TYPE_HDR_LEN, body.s, p-body.s); + memcpy( headers.s+CONTENT_TYPE_HDR_LEN+(p-body.s), CRLF, CRLF_LEN); + /* set the body */ + body.len = body.s + body.len - (p+1); + body.s = p + 1; + LM_DBG("setting BODY to <%.*s> <%.*s>\n", + headers.len, headers.s, + body.len, body.s ); + } else { + body.s = NULL; + body.len = 0; + headers.s = NULL; + headers.len = 0; + } + + /* context value */ + if (p_ctx!=NULL) { + if ( fixup_get_svalue(msg, (gparam_p)p_ctx, &ctx.s)<0 ) { + LM_ERR("failed to extract BODY param\n"); + if (p_body) pkg_free(headers.s); + return -1; + } + LM_DBG("setting CTX AVP to <%.*s>\n", ctx.s.len, ctx.s.s); + avp_list = set_avp_list( &dlg.avps ); + if (!add_avp( AVP_VAL_STR, uac_ctx_avp_id, ctx)) + LM_ERR("failed to add ctx AVP, ignorring...\n"); + set_avp_list( avp_list ); + } + + /* add cseq */ + dlg.loc_seq.value = DEFAULT_CSEQ; + dlg.loc_seq.is_set = 1; + + /* add callid */ + generate_callid(&dlg.id.call_id); + + /* add FROM tag */ + generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id); + /* TO tag is empty as this is a initial request */ + dlg.id.rem_tag.s = NULL; + dlg.id.rem_tag.len = 0; + + /* do the actual sending now */ + if ( t_uac( &method, headers.s?&headers:NULL, body.s?&body:NULL, + &dlg, 0, 0, 0) <= 0 ) { + LM_ERR("failed to send the request out\n"); + if (headers.s) pkg_free(headers.s); + if (dlg.avps) destroy_avp_list(&dlg.avps); + return -1; + } + + /* success -> do cleanup */ + if (headers.s) pkg_free(headers.s); + return 1; +} + + + + /* pseudo-variable functions */ static int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) @@ -1490,7 +1718,7 @@ int pv_get_tm_branch_avp(struct sip_msg *msg, pv_param_t *param, } else { val->rs.s = sint2str(avp_value.n, &val->rs.len); } - + if(p-pv_local_buf+val->rs.len+1>PV_LOCAL_BUF_SIZE) { LM_ERR("local buffer length exceeded!\n"); pv_get_null(msg, param, val); @@ -1669,3 +1897,117 @@ struct usr_avp** get_bavp_list(void) /* setting the avp head */ return &t->uac[_tm_branch_index].user_avps; } + +int pv_get_tm_fr_timeout(struct sip_msg *msg, pv_param_t *param, + pv_value_t *ret) +{ + struct cell *t; + + if (!msg || !ret) + return -1; + + t = get_t(); + + ret->flags = PV_VAL_INT; + ret->ri = (t && t != T_UNDEFINED) ? t->fr_timeout : fr_timeout; + + return 0; +} + +int pv_set_tm_fr_timeout(struct sip_msg *msg, pv_param_t *param, int op, + pv_value_t *val) +{ + struct cell *t; + int timeout; + + if (!msg) + return -1; + + /* "$T_fr_timer = NULL" will set the default timeout */ + if (!val) { + timeout = timer_id2timeout[FR_TIMER_LIST]; + goto set_timeout; + } + + if (!(val->flags & PV_VAL_INT)) { + LM_ERR("assigning non-int value as a timeout\n"); + return -1; + } + + timeout = val->ri; + +set_timeout: + t = get_t(); + if (t && t != T_UNDEFINED) + t->fr_timeout = timeout; + else + fr_timeout = timeout; + + return 0; +} + +int pv_get_tm_fr_inv_timeout(struct sip_msg *msg, + pv_param_t *param, pv_value_t *ret) +{ + struct cell *t; + + if (!msg || !ret) + return -1; + + t = get_t(); + + ret->flags = PV_VAL_INT; + ret->ri = (t && t != T_UNDEFINED) ? t->fr_inv_timeout : fr_inv_timeout; + + return 0; +} + +int pv_set_tm_fr_inv_timeout(struct sip_msg *msg, pv_param_t *param, + int op, pv_value_t *val) +{ + struct cell *t; + int timeout; + + if (!msg) + return -1; + + /* "$T_fr_inv_timer = NULL" will set the default timeout */ + if (!val) { + timeout = timer_id2timeout[FR_INV_TIMER_LIST]; + goto set_timeout; + } + + if (!(val->flags & PV_VAL_INT)) { + LM_ERR("assigning non-int value as a timeout\n"); + return -1; + } + + timeout = val->ri; + +set_timeout: + t = get_t(); + if (t && t != T_UNDEFINED) + t->fr_inv_timeout = timeout; + else + fr_inv_timeout = timeout; + + return 0; +} + +int __set_fr_timer(modparam_t type, void* val) +{ + LM_WARN("\"fr_timer\" is now deprecated! Use \"fr_timeout\" instead!\n"); + + timer_id2timeout[FR_TIMER_LIST] = (int)(long)val; + + return 1; +} + +int __set_fr_inv_timer(modparam_t type, void* val) +{ + LM_WARN("\"fr_inv_timer\" is now deprecated! Use \"fr_inv_timeout\" instead!\n"); + + timer_id2timeout[FR_INV_TIMER_LIST] = (int)(long)val; + + return 1; +} diff --git a/modules/tm/tm_load.h b/modules/tm/tm_load.h index fbd5750223d..f87652c52e2 100644 --- a/modules/tm/tm_load.h +++ b/modules/tm/tm_load.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -49,6 +49,7 @@ struct tm_binds { register_tmcb_f register_tmcb; cmd_function t_relay; + cmd_function t_check_trans; tnewtran_f t_newtran; treply_f t_reply; treply_wb_f t_reply_with_body; diff --git a/modules/tm/uac.c b/modules/tm/uac.c index df4dd9d4ad0..f334ac5fa54 100644 --- a/modules/tm/uac.c +++ b/modules/tm/uac.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -24,15 +24,15 @@ * 2003-01-23 t_uac_dlg now uses get_out_socket (jiri) * 2003-01-27 fifo:t_uac_dlg completed (jiri) * 2003-01-29 scratchpad removed (jiri) - * 2003-02-13 t_uac, t _uac_dlg, gethfblock, uri2proxy changed to use + * 2003-02-13 t_uac, t _uac_dlg, gethfblock, uri2proxy changed to use * proto & rb->dst (andrei) * 2003-02-27 FIFO/UAC now dumps reply -- good for CTD (jiri) * 2003-02-28 scratchpad compatibility abandoned (jiri) * 2003-03-01 kr set through a function now (jiri) * 2003-03-19 replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei) * 2003-04-02 port_no_str does not contain a leading ':' anymore (andrei) - * 2003-07-08 appropriate log messages in check_params(...), - * call calculate_hooks if next_hop==NULL in t_uac (dcm) + * 2003-07-08 appropriate log messages in check_params(...), + * call calculate_hooks if next_hop==NULL in t_uac (dcm) * 2003-10-24 updated to the new socket_info lists (andrei) * 2003-12-03 completion filed removed from transaction and uac callbacks * merged in transaction callbacks as LOCAL_COMPLETED (bogdan) @@ -53,7 +53,6 @@ #include "../../dprint.h" #include "../../md5.h" #include "../../socket_info.h" -#include "../../receive.h" #include "../../route.h" #include "../../action.h" #include "../../dset.h" @@ -81,7 +80,7 @@ struct cell** last_localT; /* * Initialize UAC */ -int uac_init(void) +int uac_init(void) { str src[3]; struct socket_info *si; @@ -118,7 +117,7 @@ void generate_fromtag(str* tag, str* callid) { /* calculate from tag from callid */ crcitt_string_array(&from_tag[MD5_LEN + 1], callid, 1); - tag->s = from_tag; + tag->s = from_tag; tag->len = FROM_TAG_LEN; } @@ -162,37 +161,6 @@ static inline unsigned int dlg2hash( dlg_t* dlg ) } -static inline struct sip_msg* buf_to_sip_msg(char *buf, unsigned int len, - dlg_t *dialog) -{ - static struct sip_msg req; - - memset( &req, 0, sizeof(req) ); - req.id = get_next_msg_no(); - req.buf = buf; - req.len = len; - if (parse_msg(buf, len, &req)!=0) { - LM_CRIT("BUG - buffer parsing failed!"); - return NULL; - } - /* populate some special fields in sip_msg */ - req.set_global_address=default_global_address; - req.set_global_port=default_global_port; - req.force_send_socket = dialog->send_sock; - if (set_dst_uri(&req, dialog->hooks.next_hop)) { - LM_ERR("failed to set dst_uri"); - free_sip_msg(&req); - return NULL; - } - req.rcv.proto = dialog->send_sock->proto; - req.rcv.src_ip = req.rcv.dst_ip = dialog->send_sock->address; - req.rcv.src_port = req.rcv.dst_port = dialog->send_sock->port_no; - req.rcv.bind_address = dialog->send_sock; - - return &req; -} - - /* * Send a request using data from the dialog structure */ @@ -201,6 +169,7 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, { union sockaddr_union to_su, new_to_su; struct cell *new_cell; + struct cell *backup_cell; struct retr_buf *request; static struct sip_msg *req; struct usr_avp **backup; @@ -208,17 +177,20 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, int buf_len, buf_len1; int ret, flags, sflag_bk; int backup_route_type; + int sip_msg_len; unsigned int hi; struct socket_info *send_sock, *new_send_sock; str h_to, h_from, h_cseq, h_callid; + struct proxy_l *proxy, *new_proxy; + unsigned short dst_changed; ret=-1; - - /*** added by dcm + + /*** added by dcm * - needed by external ua to send a request within a dlg */ if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0) - goto error2; + goto error3; if(dialog->obp.s) dialog->hooks.next_hop = &dialog->obp; @@ -227,28 +199,31 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, dialog->hooks.next_hop->s); /* calculate the socket corresponding to next hop */ - send_sock = uri2sock(0, dialog->hooks.next_hop, &to_su, - PROTO_NONE); - if (send_sock==0) { - ret=ser_error; - LM_ERR("no socket found\n"); + proxy = uri2proxy( dialog->hooks.next_hop, PROTO_NONE ); + if (proxy==0) { + ret=E_BAD_ADDRESS; + goto error3; + } + /* use the first address */ + hostent2su( &to_su, + &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); + /* get the send socket */ + send_sock = get_send_socket( NULL/*msg*/, &to_su, proxy->proto); + if (!send_sock) { + LM_ERR("no corresponding socket for af %d\n", to_su.s.sa_family); + ser_error = E_NO_SOCKET; goto error2; } /* if a send socket defined verify if the same protocol */ - if(dialog->send_sock) { - if(send_sock->proto != dialog->send_sock->proto) - { - dialog->send_sock = send_sock; - } - } - else - { + if (dialog->send_sock==NULL || + send_sock->proto != dialog->send_sock->proto) dialog->send_sock = send_sock; - } + LM_DBG("sending socket is %.*s \n", + dialog->send_sock->name.len,dialog->send_sock->name.s); - LM_DBG("sending socket is %.*s \n",dialog->send_sock->name.len,dialog->send_sock->name.s); + /* ***** Create TRANSACTION and all related ***** */ new_cell = build_cell(0); if (!new_cell) { ret=E_OUT_OF_MEM; @@ -288,6 +263,12 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); + /* copy AVPs into transaction */ + new_cell->user_avps = dialog->avps; + dialog->avps = NULL; + + + /* ***** Create the message buffer ***** */ buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len); if (!buf) { LM_ERR("failed to build message\n"); @@ -299,8 +280,11 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, LM_DBG("building sip_msg from buffer\n"); req = buf_to_sip_msg(buf, buf_len, dialog); if (req==NULL) { - LM_ERR("failed to build sip_msg from buffer"); + LM_ERR("failed to build sip_msg from buffer\n"); } else { + /* set this transaction as active one */ + backup_cell = get_t(); + set_t( new_cell ); /* set transaction AVP list */ backup = set_avp_list( &new_cell->user_avps ); /* backup script flags */ @@ -314,25 +298,40 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, set_route_type( backup_route_type ); /* transfer current message context back to t */ - new_cell->uac[0].br_flags = req->flags; + new_cell->uac[0].br_flags = getb0flags(); + /* restore the prevoius active transaction */ + set_t( backup_cell ); set_dset_state( 1 /*enable*/); setsflagsval(sflag_bk); set_avp_list( backup ); /* check for changes - if none, do not regenerate the buffer */ - if (req->new_uri.s || req->add_rm || req->body_lumps || - req->dst_uri.len != dialog->hooks.next_hop->len || - memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) != 0) { - new_send_sock = NULL; + dst_changed = 1; + if (req->new_uri.s || req->force_send_socket!=dialog->send_sock || + req->dst_uri.len != dialog->hooks.next_hop->len || + memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) || + (dst_changed=0)==0 || req->add_rm || req->body_lumps){ + new_send_sock = NULL; /* do we also need to change the destination? */ - if (req->dst_uri.s || req->new_uri.s) { + if (dst_changed) { /* calculate the socket corresponding to next hop */ - new_send_sock = uri2sock(req, + new_proxy = uri2proxy( req->dst_uri.s ? &(req->dst_uri) : &req->new_uri, - &new_to_su, PROTO_NONE ); + PROTO_NONE ); + if (new_proxy==0) + goto abort_update; + /* use the first address */ + hostent2su( &new_to_su, + &new_proxy->host, new_proxy->addr_idx, + new_proxy->port ? new_proxy->port:SIP_PORT); + /* get the send socket */ + new_send_sock = get_send_socket( req, &new_to_su, + new_proxy->proto); if (!new_send_sock) { + free_proxy( new_proxy ); + pkg_free( new_proxy ); LM_ERR("no socket found for the new destination\n"); goto abort_update; } @@ -340,26 +339,48 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, /* if interface change, we need to re-build the via */ if (new_send_sock && new_send_sock != dialog->send_sock) { - LM_DBG("Interface change in local route. rebuilding via\n"); - if (!del_lump(req,req->h_via1->name.s - req->buf,req->h_via1->len,0)) { + LM_DBG("Interface change in local route -> " + "rebuilding via\n"); + if (!del_lump(req,req->h_via1->name.s - req->buf, + req->h_via1->len,0)) { LM_ERR("Failed to remove initial via \n"); goto abort_update; } - memcpy(req->add_to_branch_s,req->via1->branch->value.s,req->via1->branch->value.len); + memcpy(req->add_to_branch_s,req->via1->branch->value.s, + req->via1->branch->value.len); req->add_to_branch_len = req->via1->branch->value.len; + /* update also info about new destination and send sock */ + dialog->send_sock = send_sock = new_send_sock; + free_proxy( proxy ); + pkg_free( proxy ); + proxy = new_proxy; + request->dst.send_sock = send_sock; + request->dst.proto = send_sock->proto; + request->dst.proto_reserved1 = 0; + /* build the shm buffer now */ - buf1 = build_req_buf_from_sip_req(req,(unsigned int*)&buf_len1, - new_send_sock?new_send_sock:dialog->send_sock, - new_send_sock?new_send_sock->proto:dialog->send_sock->proto, + set_init_lump_flags(LUMPFLAG_BRANCH); + buf1 = build_req_buf_from_sip_req(req, + (unsigned int*)&buf_len1, + new_send_sock, new_send_sock->proto, MSG_TRANS_SHM_FLAG); + reset_init_lump_flags(); + del_flaged_lumps( &req->add_rm, LUMPFLAG_BRANCH); + } else { + + LM_DBG("Change in local route -> rebuilding buffer\n"); /* build the shm buffer now */ - buf1 = build_req_buf_from_sip_req(req,(unsigned int*)&buf_len1, - new_send_sock?new_send_sock:dialog->send_sock, - new_send_sock?new_send_sock->proto:dialog->send_sock->proto, + buf1 = build_req_buf_from_sip_req(req, + (unsigned int*)&buf_len1, + dialog->send_sock, dialog->send_sock->proto, MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG); + /* now as it used, hide the original VIA header */ + del_lump(req,req->h_via1->name.s - req->buf, + req->h_via1->len, 0); + } if (!buf1) { @@ -387,33 +408,49 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, new_cell->callid = h_callid; new_cell->cseq_n = h_cseq; } - /* here we rely on how build_uac_req() + /* here we rely on how build_uac_req() builds the first line */ new_cell->uac[0].uri.s = buf1 + req->first_line.u.request.method.len + 1; new_cell->uac[0].uri.len = GET_RURI(req)->len; /* update also info about new destination and send sock */ - if (new_send_sock) { - if (new_send_sock != dialog->send_sock) { - dialog->send_sock = new_send_sock; - request->dst.send_sock = new_send_sock; - request->dst.proto = new_send_sock->proto; - request->dst.proto_reserved1 = 0; - } + if (new_send_sock) request->dst.to = new_to_su; - } shm_free(buf); buf = buf1; buf_len = buf_len1; /* use new buffer */ + } else { + /* no changes over the message, buffer is already generated, + just hide the original VIA for potential further branches */ + del_lump(req,req->h_via1->name.s-req->buf,req->h_via1->len,0); } abort_update: + /* save the SIP message into transaction */ + new_cell->uas.request = sip_msg_cloner( req, &sip_msg_len); + if (new_cell->uas.request==NULL) { + /* reset any T triggering */ + new_cell->on_negative = 0; + new_cell->on_reply = 0; + } else { + new_cell->uas.end_request= + ((char*)new_cell->uas.request)+sip_msg_len; + } + /* no parallel support in UAC transactions */ + new_cell->on_branch = 0; free_sip_msg(req); } } + /* for DNS based failover, copy the DNS proxy into transaction */ + if (!disable_dns_failover) { + new_cell->uac[0].proxy = shm_clone_proxy( proxy, 1/*do_free*/); + if (new_cell->uac[0].proxy==NULL) + LM_ERR("failed to store DNS info -> no DNS based failover\n"); + } + new_cell->method.s = buf; new_cell->method.len = method->len; @@ -421,14 +458,13 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, request->buffer.len = buf_len; new_cell->nr_of_outgoings++; - if(last_localT) - { + if(last_localT) { *last_localT = new_cell; REF_UNSAFE(new_cell); } if (SEND_BUFFER(request) == -1) { - LM_ERR("attempt to send to '%.*s' failed\n", + LM_ERR("attempt to send to '%.*s' failed\n", dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); } @@ -439,6 +475,8 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, start_retr(request); } + free_proxy( proxy ); + pkg_free( proxy ); return 1; @@ -448,6 +486,9 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, UNLOCK_HASH(hi); free_cell(new_cell); error2: + free_proxy( proxy ); + pkg_free( proxy ); +error3: return ret; } @@ -490,7 +531,7 @@ int req_outside(str* method, str* to, str* from, str callid, fromtag; if (check_params(method, to, from, dialog) < 0) goto err; - + generate_callid(&callid); generate_fromtag(&fromtag, &callid); @@ -530,7 +571,7 @@ int request(str* m, str* ruri, str* to, str* from, str* h, str* b, str *oburi, dialog->rem_target.len = ruri->len; dialog->hooks.request_uri = &dialog->rem_target; } - + if (oburi && oburi->s) dialog->hooks.next_hop = oburi; w_calculate_hooks(dialog); diff --git a/modules/tm/uac.h b/modules/tm/uac.h index c5d0e43df4a..c9ce90c18c7 100644 --- a/modules/tm/uac.h +++ b/modules/tm/uac.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/tm/ut.h b/modules/tm/ut.h index 64b9ffb7fe3..3b27770b90c 100644 --- a/modules/tm/ut.h +++ b/modules/tm/ut.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -115,7 +115,7 @@ inline static struct proxy_l *uri2proxy( str *uri, int forced_proto ) LM_ERR("bad host name in URI <%.*s>\n", uri->len, ZSW(uri->s)); return 0; } - + return p; } @@ -131,7 +131,7 @@ static inline int uri2su(str *uri, union sockaddr_union *to_su, int proto) return -1; } - hostent2su(to_su, &proxy->host, proxy->addr_idx, + hostent2su(to_su, &proxy->host, proxy->addr_idx, (proxy->port) ? proxy->port : SIP_PORT); proto = proxy->proto; diff --git a/modules/uac/README b/modules/uac/README index 0a81456e2e8..8f4c0bffd46 100644 --- a/modules/uac/README +++ b/modules/uac/README @@ -18,8 +18,7 @@ Ramona-Elena Modroiu Copyright © 2005-2009 Voice Sistem Revision History - Revision $Revision$ $Date: 2012-03-21 13:05:34 +0200 - (Wed, 21 Mar 2012) $ + Revision $Revision: 8806 $ $Date$ __________________________________________________________ Table of Contents @@ -38,10 +37,7 @@ Ramona-Elena Modroiu 1.3.2. restore_passwd (string) 1.3.3. rr_from_store_param (string) 1.3.4. rr_to_store_param (string) - 1.3.5. auth_realm_avp (string) - 1.3.6. auth_username_avp (string) - 1.3.7. auth_password_avp (string) - 1.3.8. force_dialog (int) + 1.3.5. force_dialog (int) 1.4. Exported Functions @@ -52,20 +48,19 @@ Ramona-Elena Modroiu 1.4.3. uac_restore_from() uac_restore_to() 1.4.4. uac_auth() + 2. Frequently Asked Questions + List of Examples 1.1. Set restore_mode parameter 1.2. Set restore_passwd parameter 1.3. Set rr_from_store_param parameter 1.4. Set rr_to_store_param parameter - 1.5. Set auth_realm_avp parameter - 1.6. Set auth_username_avp parameter - 1.7. Set auth_password_avp parameter - 1.8. Set force_dialog parameter - 1.9. uac_replace_from/uac_replace_to usage - 1.10. uac_replace_from/uac_replace_to usage - 1.11. uac_restore_from/uac_restore_to usage - 1.12. uac_auth usage + 1.5. Set force_dialog parameter + 1.6. uac_replace_from/uac_replace_to usage + 1.7. uac_replace_from/uac_replace_to usage + 1.8. uac_restore_from/uac_restore_to usage + 1.9. uac_auth usage Chapter 1. Admin Guide @@ -110,9 +105,9 @@ Chapter 1. Admin Guide There are 3 mode of restoring the original headers (FROM/TO) URI: * “none” - no information about original URI is stored; - restoretion is not possible. - * “manual” - all following replies will be restored, but not - also the sequential requests - this must be manually + restoration is not possible. + * “manual” - all following replies will be restored, except + for the sequential requests - these must be manually updated based on original URI. * “auto” - all sequential requests and replies will be automatically updated based on stored original URI. @@ -161,63 +156,14 @@ modparam("uac","rr_from_store_param","my_Fparam") modparam("uac","rr_to_store_param","my_Tparam") ... -1.3.5. auth_realm_avp (string) - - The definition of an AVP that might contain the realm to be - used to perform authentication. - - If you define it, you also need to define “auth_username_avp” - (Section 1.3.6, “auth_username_avp (string)”) and - “auth_username_avp” (Section 1.3.7, “auth_password_avp - (string)”). - - Example 1.5. Set auth_realm_avp parameter -... -modparam("uac","auth_realm_avp","$avp(10)") -... - -1.3.6. auth_username_avp (string) - - The definition of an AVP that might contain the username to be - used to perform authentication. - - If you define it, you also need to define “auth_realm_avp” - (Section 1.3.5, “auth_realm_avp (string)”) and - “auth_username_avp” (Section 1.3.7, “auth_password_avp - (string)”). - - Example 1.6. Set auth_username_avp parameter -... -modparam("uac","auth_username_avp","$avp(11)") -... - -1.3.7. auth_password_avp (string) - - The definition of an AVP that might contain the password to be - used to perform authentication. The password can be provided as - a plain text password or as a precalculated HA1 as a hexa - (lower case) string (of 32 chars) prefixed with "0x" (so a - total of 34 chars) (for example - "0xc17ba8157756f263d07e158504204629") - - If you define it, you also need to define “auth_password_avp” - (Section 1.3.7, “auth_password_avp (string)”) and - “auth_username_avp” (Section 1.3.7, “auth_password_avp - (string)”). - - Example 1.7. Set auth_password_avp parameter -... -modparam("uac","auth_password_avp","$avp(12)") -... - -1.3.8. force_dialog (int) +1.3.5. force_dialog (int) Force create dialog if it is not created from the configuration script. Default value is no. - Example 1.8. Set force_dialog parameter + Example 1.5. Set force_dialog parameter ... modparam("uac", "force_dialog", yes) ... @@ -240,7 +186,7 @@ modparam("uac", "force_dialog", yes) This function can be used from REQUEST_ROUTE, BRANCH_ROUTE and FAILURE_ROUTE. - Example 1.9. uac_replace_from/uac_replace_to usage + Example 1.6. uac_replace_from/uac_replace_to usage ... # replace both display and uri uac_replace_from("$avp(display)","$avp(uri)"); @@ -261,7 +207,7 @@ uac_replace_from("",""); This function can be used from REQUEST_ROUTE. - Example 1.10. uac_replace_from/uac_replace_to usage + Example 1.7. uac_replace_from/uac_replace_to usage ... uac_replace_from("sip:batman@gotham.org"); ... @@ -278,7 +224,7 @@ uac_replace_from("sip:batman@gotham.org"); This function can be used from REQUEST_ROUTE. - Example 1.11. uac_restore_from/uac_restore_to usage + Example 1.8. uac_restore_from/uac_restore_to usage ... uac_restore_from(); ... @@ -288,13 +234,58 @@ uac_restore_from(); This function can be called only from failure route and will build the authentication response header and insert it into the request without sending anything. Credentials for buiding the - authentication response will be taken from AVPs first (if AVPs - are defined and populated) and then from the list of - credentials provided by the uac_auth module. + authentication response will be taken from the list of + credentials provided by the uac_auth module (static or via + AVPs). This function can be used from FAILURE_ROUTE. - Example 1.12. uac_auth usage + Example 1.9. uac_auth usage ... uac_auth(); ... + +Chapter 2. Frequently Asked Questions + + 2.1. + + What happened with auth_username_avp, auth_realm_avp and + auth_password_avp parameters + + Due some restructuring of the UAC auth modules, these + parameters were moved into the "uac_auth" module. This module + is now responsible for handling all the credentials (static + defined or dynamically defined via AVPs). The UAC module will + still see the credentials defined via the AVPs. + $ + + 2.2. + + Where can I find more about OpenSIPS? + + Take a look at http://www.opensips.org/. + + 2.3. + + Where can I post a question about this module? + + First at all check if your question was already answered on one + of our mailing lists: + * User Mailing List - + http://lists.opensips.org/cgi-bin/mailman/listinfo/users + * Developer Mailing List - + http://lists.opensips.org/cgi-bin/mailman/listinfo/devel + + E-mails regarding any stable OpenSIPS release should be sent to + and e-mails regarding development + versions should be sent to . + + If you want to keep the mail private, send it to + . + + 2.4. + + How can I report a bug? + + Please follow the guidelines provided at: + https://github.com/OpenSIPS/opensips/issues. diff --git a/modules/uac/auth.c b/modules/uac/auth.c index e9d02a047a3..eae8301c1b0 100644 --- a/modules/uac/auth.c +++ b/modules/uac/auth.c @@ -40,47 +40,14 @@ #include "../../parser/parse_authenticate.h" #include "../tm/tm_load.h" #include "../uac_auth/uac_auth.h" +#include "auth.h" extern struct tm_binds uac_tmb; extern uac_auth_api_t uac_auth_api; -extern pv_spec_t auth_username_spec; -extern pv_spec_t auth_realm_spec; -extern pv_spec_t auth_password_spec; - - -static inline struct uac_credential *get_avp_credential(struct sip_msg *msg, - str *realm) -{ - static struct uac_credential crd; - pv_value_t pv_val; - - if(pv_get_spec_value( msg, &auth_realm_spec, &pv_val)!=0 - || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0) - return 0; - - crd.realm = pv_val.rs; - /* is it the domain we are looking for? */ - if (realm->len!=crd.realm.len || - strncmp( realm->s, crd.realm.s, realm->len)!=0 ) - return 0; - - /* get username and password */ - if(pv_get_spec_value( msg, &auth_username_spec, &pv_val)!=0 - || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0) - return 0; - crd.user = pv_val.rs; - - if(pv_get_spec_value( msg, &auth_password_spec, &pv_val)!=0 - || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0) - return 0; - crd.passwd = pv_val.rs; - - return &crd; -} - - +extern str rr_uac_cseq_param; +extern struct rr_binds uac_rrb; static inline int apply_urihdr_changes( struct sip_msg *req, str *uri, str *hdr) @@ -111,7 +78,7 @@ static inline int apply_urihdr_changes( struct sip_msg *req, goto error; } - anchor = anchor_lump(req, req->unparsed - req->buf, 0, 0); + anchor = anchor_lump(req, req->unparsed - req->buf, 0); if (anchor==0) { LM_ERR("failed to get anchor\n"); @@ -130,7 +97,86 @@ static inline int apply_urihdr_changes( struct sip_msg *req, return -1; } +int apply_cseq_op(struct sip_msg *msg,int val) +{ + int offset,len,olen; + struct lump *tmp; + char *buf,*obuf; + unsigned int cseq_no; + str pkg_cseq; + + if (!msg) { + LM_ERR("null pointer provided\n"); + return -1; + } + + if(parse_headers(msg, HDR_CSEQ_F, 0) <0 ) { + LM_ERR("failed to parse headers \n"); + return -1; + } + + if (str2int(&(((struct cseq_body *)msg->cseq->parsed)->number),&cseq_no) < 0) { + LM_ERR("Failed to convert cseq to integer \n"); + return -1; + } + + cseq_no=cseq_no+val; + obuf = int2str(cseq_no,&olen); + if (obuf == NULL) { + LM_ERR("Failed to convert new integer to string \n"); + return -1; + } + + pkg_cseq.s = pkg_malloc(olen); + if (!pkg_cseq.s) { + LM_ERR("No more pkg mem \n"); + return -1; + } + + memcpy(pkg_cseq.s,obuf,olen); + pkg_cseq.len = olen; + + buf = msg->buf; + len = ((struct cseq_body *)msg->cseq->parsed)->number.len; + offset = ((struct cseq_body *)msg->cseq->parsed)->number.s - buf; + + if ((tmp = del_lump(msg,offset,len,0)) == 0) + { + LM_ERR("failed to remove the existing CSEQ\n"); + pkg_free(pkg_cseq.s); + return -1; + } + + if (insert_new_lump_after(tmp,pkg_cseq.s,pkg_cseq.len,0) == 0) + { + LM_ERR("failed to insert new CSEQ\n"); + pkg_free(pkg_cseq.s); + return -1; + } + + LM_DBG("Message CSEQ translated from [%.*s] to [%.*s]\n", + ((struct cseq_body *)msg->cseq->parsed)->number.len, + ((struct cseq_body *)msg->cseq->parsed)->number.s,pkg_cseq.len, + pkg_cseq.s); + + return 0; +} + +void apply_cseq_decrement(struct cell* t, int type, struct tmcb_params *p) +{ + struct sip_msg *req; + struct sip_msg *rpl; + + if ( !t || !t->uas.request || !p->rpl ) + return; + + req = t->uas.request; + rpl = p->rpl; + if (req == FAKED_REPLY || rpl == FAKED_REPLY) + return; + apply_cseq_op(rpl,-1); +} int uac_auth( struct sip_msg *msg) { @@ -142,6 +188,8 @@ int uac_auth( struct sip_msg *msg) struct cell *t; HASHHEX response; str *new_hdr; + str param; + char *p; /* get transaction */ t = uac_tmb.t_gett(); @@ -187,13 +235,8 @@ int uac_auth( struct sip_msg *msg) } /* can we authenticate this realm? */ - crd = 0; - /* first look into AVP, if set */ - if ( auth_realm_spec.type==PVT_AVP ) - crd = get_avp_credential( msg, &auth->realm ); - /* if not found, look into predefined credentials */ - if (crd==0) - crd = uac_auth_api._lookup_realm( &auth->realm ); + /* look into existing credentials */ + crd = uac_auth_api._lookup_realm( &auth->realm ); /* found? */ if (crd==0) { @@ -216,17 +259,85 @@ int uac_auth( struct sip_msg *msg) } /* so far, so good -> add the header and set the proper RURI */ - if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 ) + if (apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0) { LM_ERR("failed to apply changes\n"); + pkg_free(new_hdr->s); + new_hdr->s = NULL; new_hdr->len = 0; goto error; } - /* increas the Cseq nr */ + if ( apply_cseq_op(msg,1) < 0) { + LM_WARN("Failure to increment the CSEQ header - continue \n"); + goto error; + } + + /* only register the TMCB once per transaction */ + if (!(msg->msg_flags & FL_USE_UAC_CSEQ || + t->uas.request->msg_flags & FL_USE_UAC_CSEQ)) { + if (uac_tmb.register_tmcb( msg, 0, TMCB_RESPONSE_FWDED, + apply_cseq_decrement,0,0)!=1) { + LM_ERR("Failed to register TMCB response fwded - continue \n"); + goto error; + } + } + + param.len=rr_uac_cseq_param.len+3; + param.s=pkg_malloc(param.len); + if (!param.s) { + LM_ERR("No more pkg mem \n"); + goto error; + } + p = param.s; + *p++=';'; + memcpy(p,rr_uac_cseq_param.s,rr_uac_cseq_param.len); + p+=rr_uac_cseq_param.len; + *p++='='; + *p++='1'; + if (uac_rrb.add_rr_param( msg, ¶m)!=0) { + LM_ERR("add_RR_param failed\n"); + pkg_free(param.s); + goto error; + } + + msg->msg_flags |= FL_USE_UAC_CSEQ; + t->uas.request->msg_flags |= FL_USE_UAC_CSEQ; + + pkg_free(param.s); + new_hdr->s = NULL; new_hdr->len = 0; return 0; error: return -1; } +void rr_uac_auth_checker(struct sip_msg *msg, str *r_param, void *cb_param) +{ + str param_val; + + LM_DBG("getting '%.*s' Route param\n", + rr_uac_cseq_param.len,rr_uac_cseq_param.s); + + /* do we have the uac auth marker ? */ + if (uac_rrb.get_route_param( msg, &rr_uac_cseq_param, ¶m_val)!=0) { + LM_DBG("route param '%.*s' not found\n", + rr_uac_cseq_param.len,rr_uac_cseq_param.s); + return; + } + + /* we don't change anything upstream */ + if (uac_rrb.is_direction( msg, RR_FLOW_UPSTREAM)==0) + return; + + if (apply_cseq_op(msg,1) < 0) { + LM_WARN("Failure to increment the CSEQ header - continue \n"); + return; + } + + if (uac_tmb.register_tmcb( msg, 0, TMCB_RESPONSE_FWDED, + apply_cseq_decrement,0,0)!=1) { + LM_ERR("Failed to register TMCB response fwded - continue \n"); + return; + } +} diff --git a/modules/uac/auth.h b/modules/uac/auth.h new file mode 100644 index 00000000000..94b39c03782 --- /dev/null +++ b/modules/uac/auth.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * history: + * --------- + * 2014-08-xx created (vlad-paiu) + */ + +#ifndef _UAC_UAC_AUTH_H_ +#define _UAC_UAC_AUTH_H_ + +#include "../../parser/msg_parser.h" +#include "../rr/api.h" + +void rr_uac_auth_checker(struct sip_msg *msg, str *r_param, void *cb_param); + +#endif diff --git a/modules/uac/doc/uac.xml b/modules/uac/doc/uac.xml index 09f62dcaa98..09c6a9a3a84 100644 --- a/modules/uac/doc/uac.xml +++ b/modules/uac/doc/uac.xml @@ -4,7 +4,7 @@ - + diff --git a/modules/uac/doc/uac_admin.xml b/modules/uac/doc/uac_admin.xml index e975ff79bd4..833151f1e72 100644 --- a/modules/uac/doc/uac_admin.xml +++ b/modules/uac/doc/uac_admin.xml @@ -94,13 +94,13 @@ none - no information about original URI is - stored; restoretion is not possible. + stored; restoration is not possible. manual - all following replies will be restored, - but not also the sequential requests - this must be manually + except for the sequential requests - these must be manually updated based on original URI. @@ -195,78 +195,6 @@ modparam("uac","rr_to_store_param","my_Tparam")
-
- <varname>auth_realm_avp</varname> (string) - - The definition of an AVP that might contain the realm to be used - to perform authentication. - - - If you define it, you also need to define - auth_username_avp - () and - auth_username_avp - (). - - - Set <varname>auth_realm_avp</varname> parameter - -... -modparam("uac","auth_realm_avp","$avp(10)") -... - - -
- -
- <varname>auth_username_avp</varname> (string) - - The definition of an AVP that might contain the username to be used - to perform authentication. - - - If you define it, you also need to define - auth_realm_avp - () and - auth_username_avp - (). - - - Set <varname>auth_username_avp</varname> parameter - -... -modparam("uac","auth_username_avp","$avp(11)") -... - - -
- -
- <varname>auth_password_avp</varname> (string) - - The definition of an AVP that might contain the password to be used - to perform authentication. The password can be provided as a plain - text password or as a precalculated HA1 as a hexa (lower case) string - (of 32 chars) prefixed with "0x" (so a total of 34 chars) (for example - "0xc17ba8157756f263d07e158504204629") - - - If you define it, you also need to define - auth_password_avp - () and - auth_username_avp - (). - - - Set <varname>auth_password_avp</varname> parameter - -... -modparam("uac","auth_password_avp","$avp(12)") -... - - -
-
<varname>force_dialog</varname> (int) @@ -394,8 +322,8 @@ uac_restore_from(); build the authentication response header and insert it into the request without sending anything. Credentials for buiding the authentication response will be taken - from AVPs first (if AVPs are defined and populated) and then from - the list of credentials provided by the uac_auth module. + from the list of credentials provided by the uac_auth module (static + or via AVPs). This function can be used from FAILURE_ROUTE. diff --git a/modules/uac/doc/uac_faq.xml b/modules/uac/doc/uac_faq.xml new file mode 100644 index 00000000000..ade4b08ff46 --- /dev/null +++ b/modules/uac/doc/uac_faq.xml @@ -0,0 +1,74 @@ + + + + + &faqguide; + + + + + What happened with auth_username_avp, auth_realm_avp and auth_password_avp parameters + + + + Due some restructuring of the UAC auth modules, these parameters were moved into the "uac_auth" module. + This module is now responsible for handling all the credentials (static defined or dynamically defined + via AVPs). The UAC module will still see the credentials defined via the AVPs. + $ + $ + $ + + + + Where can I find more about OpenSIPS? + + + + Take a look at &osipshomelink;. + + + + + + + Where can I post a question about this module? + + + + First at all check if your question was already answered on one of + our mailing lists: + + + + User Mailing List - &osipsuserslink; + + + Developer Mailing List - &osipsdevlink; + + + + E-mails regarding any stable &osips; release should be sent to + &osipsusersmail; and e-mails regarding development versions + should be sent to &osipsdevmail;. + + + If you want to keep the mail private, send it to + &osipshelpmail;. + + + + + + + How can I report a bug? + + + + Please follow the guidelines provided at: + &osipsbugslink;. + + + + + + diff --git a/modules/uac/replace.c b/modules/uac/replace.c index 07c82d6f03f..d651e1d2b07 100644 --- a/modules/uac/replace.c +++ b/modules/uac/replace.c @@ -189,7 +189,7 @@ static inline struct lump* get_display_anchor(struct sip_msg *msg, if (*p2=='<') { /* is quoted */ - l = anchor_lump( msg, p2 - msg->buf, 0, 0); + l = anchor_lump( msg, p2 - msg->buf, 0); if (l==0) { LM_ERR("unable to build lump anchor\n"); return 0; @@ -199,7 +199,7 @@ static inline struct lump* get_display_anchor(struct sip_msg *msg, } /* not quoted - more complicated....must place the closing bracket */ - l = anchor_lump( msg, (body->uri.s+body->uri.len) - msg->buf, 0, 0); + l = anchor_lump( msg, (body->uri.s+body->uri.len) - msg->buf, 0); if (l==0) { LM_ERR("unable to build lump anchor\n"); return 0; @@ -216,7 +216,7 @@ static inline struct lump* get_display_anchor(struct sip_msg *msg, return 0; } /* build anchor for display */ - l = anchor_lump( msg, body->uri.s - msg->buf, 0, 0); + l = anchor_lump( msg, body->uri.s - msg->buf, 0); if (l==0) { LM_ERR("unable to build lump anchor\n"); return 0; @@ -320,7 +320,7 @@ int replace_uri( struct sip_msg *msg, str *display, str *uri, LM_ERR("no more pkg mem\n"); goto error; } - memcpy( p, uri->s, uri->len); + memcpy( p, uri->s, uri->len); if (insert_new_lump_after( l, p, uri->len, 0)==0) { LM_ERR("insert new lump failed\n"); pkg_free(p); @@ -366,7 +366,7 @@ int replace_uri( struct sip_msg *msg, str *display, str *uri, } LM_DBG("stored <%.*s> param in dialog\n", rr_param->len, rr_param->s); } - if (dlg_api.store_dlg_value(dlg, + if (dlg_api.store_dlg_value(dlg, to ? &rr_to_param_new : &rr_from_param_new, uri) < 0) { LM_ERR("cannot store new uri value\n"); goto error; @@ -449,7 +449,7 @@ int replace_uri( struct sip_msg *msg, str *display, str *uri, } /* set TO/ FROM sepcific flags */ msg->msg_flags |= uac_flag; - if ( (Trans=uac_tmb.t_gett())!=NULL && Trans!=T_UNDEFINED && + if ( (Trans=uac_tmb.t_gett())!=NULL && Trans!=T_UNDEFINED && Trans->uas.request) Trans->uas.request->msg_flags |= uac_flag; } @@ -579,6 +579,35 @@ int restore_uri( struct sip_msg *msg, int to, int check_from) /************************** Dialog functions ******************************/ +void dlg_restore_callback(struct dlg_cell* dlg, int type, struct dlg_cb_params * params) +{ + str val; + + /* check if the UAC corresponding values are present */ + + if ( dlg_api.fetch_dlg_value( dlg, &rr_to_param_new, &val, 0)==0 ) { + /* TO variable found -> TO URI changed */ + LM_DBG("UAC TO related DLG vals found -> installing callback\n"); + if ( dlg_api.register_dlgcb(dlg, DLGCB_REQ_WITHIN|DLGCB_TERMINATED, + replace_callback, (void*)1/*to*/, 0) != 0) { + LM_ERR("cannot register callback\n"); + } + } + + if ( dlg_api.fetch_dlg_value( dlg, &rr_from_param_new, &val, 0)==0 ) { + /* FROM variable found -> FROM URI changed */ + LM_DBG("UAC FROM related DLG vals found -> installing callback\n"); + if ( dlg_api.register_dlgcb(dlg, DLGCB_REQ_WITHIN|DLGCB_TERMINATED, + replace_callback, (void*)0/*from*/, 0) != 0) { + LM_ERR("cannot register callback\n"); + } + } + + return; +} + + + static void replace_callback(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { @@ -685,7 +714,7 @@ void rr_checker(struct sip_msg *msg, str *r_param, void *cb_param) if ( (restore_uri( msg, 0, 1/*from*/) + restore_uri( msg, 1, 0/*to*/) )!= -2 ) { /* restore in req performed -> replace in reply */ - /* in callback we need TO/FROM to be parsed- it's already done + /* in callback we need TO/FROM to be parsed- it's already done * by restore_from_to() function */ if ( uac_tmb.register_tmcb( msg, 0, TMCB_RESPONSE_IN, restore_uris_reply, 0, 0)!=1 ) { @@ -758,7 +787,7 @@ int move_bavp_dlg( struct sip_msg *msg, str* rr_param, pv_spec_t *store_spec) LM_DBG("dialog not found - cannot move branch avps\n"); goto not_moved; } - + code = msg->first_line.u.reply.statuscode; if (msg->first_line.type == SIP_REPLY && code >= 200 && code < 300) { /* check to see if there are bavps stored */ @@ -775,7 +804,7 @@ int move_bavp_dlg( struct sip_msg *msg, str* rr_param, pv_spec_t *store_spec) return -1; } - LM_DBG("moved <%.*s> from branch avp list in dlg\n", + LM_DBG("moved <%.*s> from branch avp list in dlg\n", rr_param->len, rr_param->s); return 1; } @@ -800,7 +829,7 @@ void move_bavp_callback(struct cell* t, int type, struct tmcb_params *p) if (req == FAKED_REPLY || rpl == FAKED_REPLY) return; - if (req->msg_flags & FL_USE_UAC_FROM && + if (req->msg_flags & FL_USE_UAC_FROM && (move_bavp_dlg(rpl, &rr_from_param, &from_bavp_spec) < 0)) LM_ERR("failed to move bavp list\n"); diff --git a/modules/uac/replace.h b/modules/uac/replace.h index 12cc69433b8..37c2f36243e 100644 --- a/modules/uac/replace.h +++ b/modules/uac/replace.h @@ -48,5 +48,6 @@ int restore_uri( struct sip_msg *msg, int to, int check_from); /* RR callback functions */ void rr_checker(struct sip_msg *msg, str *r_param, void *cb_param); +void dlg_restore_callback(struct dlg_cell* dlg, int type, struct dlg_cb_params * params); #endif diff --git a/modules/uac/uac.c b/modules/uac/uac.c index 61dcfca27b2..b9d3613a126 100644 --- a/modules/uac/uac.c +++ b/modules/uac/uac.c @@ -50,6 +50,7 @@ #include "../dialog/dlg_load.h" #include "replace.h" +#include "auth.h" @@ -57,15 +58,13 @@ /* local variable used for init */ static char* restore_mode_str = NULL; -static char* auth_username_avp = NULL; -static char* auth_realm_avp = NULL; -static char* auth_password_avp = NULL; /* global param variables */ str rr_from_param = str_init("vsf"); str rr_from_param_new = str_init("739823"); str store_from_bavp = str_init("$bavp(739825)"); str rr_to_param = str_init("vst"); +str rr_uac_cseq_param = str_init("aci"); str rr_to_param_new = str_init("739824"); str store_to_bavp = str_init("$bavp(739826)"); pv_spec_t from_bavp_spec; @@ -76,9 +75,6 @@ int restore_mode = UAC_AUTO_RESTORE; struct tm_binds uac_tmb; struct rr_binds uac_rrb; uac_auth_api_t uac_auth_api; -pv_spec_t auth_username_spec; -pv_spec_t auth_realm_spec; -pv_spec_t auth_password_spec; int force_dialog = 0; struct dlg_binds dlg_api; @@ -115,7 +111,7 @@ static cmd_export_t cmds[]={ {"uac_restore_to", (cmd_function)w_restore_to, 0, 0, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, - {"uac_auth", (cmd_function)w_uac_auth, 0, + {"uac_auth", (cmd_function)w_uac_auth, 0, 0, 0, FAILURE_ROUTE }, {0,0,0,0,0,0} @@ -129,19 +125,42 @@ static param_export_t params[] = { {"rr_to_store_param", STR_PARAM, &rr_to_param.s }, {"restore_mode", STR_PARAM, &restore_mode_str }, {"restore_passwd", STR_PARAM, &uac_passwd.s }, - {"auth_username_avp", STR_PARAM, &auth_username_avp }, - {"auth_realm_avp", STR_PARAM, &auth_realm_avp }, - {"auth_password_avp", STR_PARAM, &auth_password_avp }, {"force_dialog", INT_PARAM, &force_dialog }, {0, 0, 0} }; +static module_dependency_t *get_deps_restore_mode(param_export_t *param) +{ + char *mode = *(char **)param->param_pointer; + + if (!mode || strlen(mode) == 0) + return NULL; + if (strcmp(mode, "none") != 0) + return alloc_module_dep(MOD_TYPE_DEFAULT, "rr", DEP_ABORT); + + return NULL; +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "dialog", DEP_SILENT }, + { MOD_TYPE_DEFAULT, "uac_auth", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "restore_mode", get_deps_restore_mode }, + { NULL, NULL }, + }, +}; struct module_exports exports= { "uac", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* param exports */ 0, /* exported statistics */ @@ -155,17 +174,6 @@ struct module_exports exports= { }; -inline static int parse_auth_avp( char *avp_spec, pv_spec_t *avp, char *txt) -{ - str s; - s.s = avp_spec; s.len = strlen(s.s); - if (pv_parse_spec(&s, avp)==NULL) { - LM_ERR("malformed or non AVP %s AVP definition\n",txt); - return -1; - } - return 0; -} - inline static int parse_store_bavp(str *s, pv_spec_t *bavp) { @@ -180,13 +188,29 @@ inline static int parse_store_bavp(str *s, pv_spec_t *bavp) return -1; } return 0; - + } static int mod_init(void) { LM_INFO("initializing...\n"); + int rr_api_loaded=0; + + if ( is_script_func_used("uac_auth", -1) ) { + /* load the UAC_AUTH API as uac_auth() is invoked from script */ + if(load_uac_auth_api(&uac_auth_api)<0){ + LM_ERR("can't load UAC_AUTH API, needed for uac_auth()\n"); + goto error; + } + } + + /* load the TM API - FIXME it should be loaded only + * if NO_RESTORE and AUTH */ + if (load_tm_api(&uac_tmb)!=0) { + LM_ERR("can't load TM API\n"); + goto error; + } if (restore_mode_str && *restore_mode_str) { if (strcasecmp(restore_mode_str,"none")==0) { @@ -202,90 +226,89 @@ static int mod_init(void) } } - rr_from_param.len = strlen(rr_from_param.s); - rr_to_param.len = strlen(rr_to_param.s); - if ( (rr_from_param.len==0 || rr_to_param.len==0) && - restore_mode!=UAC_NO_RESTORE) - { - LM_ERR("rr_store_param cannot be empty if FROM is restoreable\n"); - goto error; - } + if ( is_script_func_used("uac_replace_from", -1) || + is_script_func_used("uac_replace_to", -1) ) { - uac_passwd.len = strlen(uac_passwd.s); + /* replace TO/FROM stuff is used, get prepared */ - /* parse the auth AVP spesc, if any */ - if ( auth_username_avp || auth_password_avp || auth_realm_avp) { - if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) { - LM_ERR("partial definition of auth AVP!"); + rr_from_param.len = strlen(rr_from_param.s); + rr_to_param.len = strlen(rr_to_param.s); + if ( (rr_from_param.len==0 || rr_to_param.len==0) && + restore_mode!=UAC_NO_RESTORE) { + LM_ERR("rr_store_param cannot be empty if FROM is restoreable\n"); goto error; } - if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0 - || parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0 - || parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0 - ) { - goto error; - } - } else { - memset( &auth_realm_spec, 0, sizeof(pv_spec_t)); - memset( &auth_password_spec, 0, sizeof(pv_spec_t)); - memset( &auth_username_spec, 0, sizeof(pv_spec_t)); - } - - /* load the TM API - FIXME it should be loaded only - * if NO_RESTORE and AUTH */ - if (load_tm_api(&uac_tmb)!=0) { - LM_ERR("can't load TM API\n"); - goto error; - } - /* load the UAC_AUTH API - FIXME it should be loaded only - * if uac_auth() is invoked from script */ - if(load_uac_auth_api(&uac_auth_api)<0){ - LM_ERR("can't load UAC_AUTH API\n"); - goto error; - } + uac_passwd.len = strlen(uac_passwd.s); - if (restore_mode!=UAC_NO_RESTORE) { - /* load the RR API */ - if (load_rr_api(&uac_rrb)!=0) { - LM_ERR("can't load RR API\n"); - goto error; - } - - if (restore_mode==UAC_AUTO_RESTORE) { - /* we need the append_fromtag on in RR */ - if (!force_dialog && !uac_rrb.append_fromtag) { - LM_ERR("'append_fromtag' RR param is not enabled!" - " - required by AUTO restore mode\n"); + if (restore_mode!=UAC_NO_RESTORE) { + /* load the RR API */ + if (load_rr_api(&uac_rrb)!=0) { + LM_ERR("can't load RR API\n"); goto error; } + rr_api_loaded=1; - /* trying to load dialog module */ - memset(&dlg_api, 0, sizeof(struct dlg_binds)); - if (load_dlg_api(&dlg_api)!=0) { - if (force_dialog) { - LM_ERR("cannot force dialog. dialog module not loaded\n"); + if (restore_mode==UAC_AUTO_RESTORE) { + /* we need the append_fromtag on in RR */ + if (!force_dialog && !uac_rrb.append_fromtag) { + LM_ERR("'append_fromtag' RR param is not enabled!" + " - required by AUTO restore mode\n"); goto error; } - LM_DBG("failed to find dialog API - is dialog module loaded?\n"); - } else { - if ( (parse_store_bavp(&store_to_bavp, &to_bavp_spec) || - parse_store_bavp(&store_from_bavp, &from_bavp_spec))) { - LM_ERR("cannot set correct store parameters\n"); + + /* trying to load dialog module */ + memset(&dlg_api, 0, sizeof(struct dlg_binds)); + if (load_dlg_api(&dlg_api)!=0) { + if (force_dialog) { + LM_ERR("cannot force dialog. dialog module not loaded\n"); + goto error; + } + LM_DBG("failed to find dialog API - is dialog module loaded?\n"); + } else { + if ( (parse_store_bavp(&store_to_bavp, &to_bavp_spec) || + parse_store_bavp(&store_from_bavp, &from_bavp_spec))) { + LM_ERR("cannot set correct store parameters\n"); + goto error; + } + /* install calback to catch all loaded dialogs */ + if ( dlg_api.register_dlgcb( NULL, DLGCB_LOADED, + dlg_restore_callback, NULL, NULL) != 0 ) { + LM_ERR("failed to install dialog restore callback\n"); + goto error; + } + } + + /* get all requests doing loose route */ + if (uac_rrb.register_rrcb( rr_checker, 0, 2)!=0) { + LM_ERR("failed to install RR callback\n"); goto error; } } + } + + /* init from replacer */ + init_from_replacer(); + } - /* get all requests doing loose route */ - if (uac_rrb.register_rrcb( rr_checker, 0, 2)!=0) { - LM_ERR("failed to install RR callback\n"); + if (is_script_func_used("uac_auth", -1)) { + if (!rr_api_loaded) { + if (load_rr_api(&uac_rrb)!=0) { + LM_ERR("can't load RR API\n"); goto error; } } - } + if (!uac_rrb.append_fromtag) { + LM_ERR("'append_fromtag' RR param is not enabled!" + " - required by uac_auth() restore mode\n"); + goto error; + } - /* init from replacer */ - init_from_replacer(); + if (uac_rrb.register_rrcb( rr_uac_auth_checker, 0, 2)!=0) { + LM_ERR("failed to install RR callback\n"); + goto error; + } + } return 0; error: diff --git a/modules/uac_auth/README b/modules/uac_auth/README index 82d132245c3..9e0f5198139 100644 --- a/modules/uac_auth/README +++ b/modules/uac_auth/README @@ -1,5 +1,9 @@ UAC AUTH Module +Bogdan-Andrei Iancu + + + Ovidiu Sas @@ -10,10 +14,17 @@ Ovidiu Sas +Edited by + +Bogdan-Andrei Iancu + + + Copyright © 2011 VoIP Embedded, Inc. + + Copyright © 2013 www.opensips-solutions.com Revision History - Revision $Revision: 8101 $ $Date: 2011-06-30 18:22:35 +0300 - (Thu, 30 Jun 2011) $ + Revision $Revision: 8101 $ $Date$ __________________________________________________________ Table of Contents @@ -29,10 +40,16 @@ Ovidiu Sas 1.3. Exported Parameters 1.3.1. credential (string) + 1.3.2. auth_realm_avp (string) + 1.3.3. auth_username_avp (string) + 1.3.4. auth_password_avp (string) List of Examples 1.1. Set credential parameter + 1.2. Set auth_realm_avp parameter + 1.3. Set auth_username_avp parameter + 1.4. Set auth_password_avp parameter Chapter 1. Admin Guide @@ -79,3 +96,52 @@ modparam("uac_auth","credential","username:domain:password") modparam("uac_auth","credential","username:domain:0xc17ba8157756f263d07e 158504204629") ... + +1.3.2. auth_realm_avp (string) + + The definition of an AVP that might contain the realm to be + used to perform authentication. + + If you define it, you also need to define “auth_username_avp” + (Section 1.3.3, “auth_username_avp (string)”) and + “auth_username_avp” (Section 1.3.4, “auth_password_avp + (string)”). + + Example 1.2. Set auth_realm_avp parameter +... +modparam("uac_auth","auth_realm_avp","$avp(10)") +... + +1.3.3. auth_username_avp (string) + + The definition of an AVP that might contain the username to be + used to perform authentication. + + If you define it, you also need to define “auth_realm_avp” + (Section 1.3.2, “auth_realm_avp (string)”) and + “auth_username_avp” (Section 1.3.4, “auth_password_avp + (string)”). + + Example 1.3. Set auth_username_avp parameter +... +modparam("uac_auth","auth_username_avp","$avp(11)") +... + +1.3.4. auth_password_avp (string) + + The definition of an AVP that might contain the password to be + used to perform authentication. The password can be provided as + a plain text password or as a precalculated HA1 as a hexa + (lower case) string (of 32 chars) prefixed with "0x" (so a + total of 34 chars) (for example + "0xc17ba8157756f263d07e158504204629") + + If you define it, you also need to define “auth_password_avp” + (Section 1.3.4, “auth_password_avp (string)”) and + “auth_username_avp” (Section 1.3.4, “auth_password_avp + (string)”). + + Example 1.4. Set auth_password_avp parameter +... +modparam("uac_auth","auth_password_avp","$avp(12)") +... diff --git a/modules/uac_auth/auth.c b/modules/uac_auth/auth.c index 2c4b78f5be3..d056f692359 100644 --- a/modules/uac_auth/auth.c +++ b/modules/uac_auth/auth.c @@ -2,6 +2,7 @@ * $Id$ * * Copyright (C) 2011 VoIP Embedded Inc. + * Copyright (C) 2013 OpenSIPS Solutions * * This file is part of opensips, a free SIP server. * @@ -42,8 +43,18 @@ #include "uac_auth.h" +extern int realm_avp_name; +extern unsigned short realm_avp_type; +extern int user_avp_name; +extern unsigned short user_avp_type; +extern int pwd_avp_name; +extern unsigned short pwd_avp_type; + + + static str nc = {"00000001", 8}; static str cnonce = {"o", 1}; +static str auth_hdr = {NULL, 0}; static struct uac_credential *crd_list = NULL; @@ -61,14 +72,15 @@ static struct uac_credential *crd_list = NULL; int has_credentials(void) {return (crd_list)?1:0;} + void free_credential(struct uac_credential *crd) { if (crd) { if (crd->realm.s) pkg_free(crd->realm.s); if (crd->user.s) pkg_free(crd->user.s); - if (crd->passwd.s) pkg_free(crd->passwd.s); - pkg_free(crd); - } + if (crd->passwd.s) pkg_free(crd->passwd.s); + pkg_free(crd); + } } @@ -178,10 +190,46 @@ void destroy_credentials(void) } +static inline struct uac_credential *get_avp_credential(str *realm) +{ + static struct uac_credential crd; + struct usr_avp *avp; + int_str val; + + avp = search_first_avp( realm_avp_type, realm_avp_name, &val, 0); + if ( avp==NULL || (avp->flags&AVP_VAL_STR)==0 || val.s.len<=0 ) + return 0; + + crd.realm = val.s; + /* is it the domain we are looking for? */ + if (realm->len!=crd.realm.len || + strncmp( realm->s, crd.realm.s, realm->len)!=0 ) + return 0; + + /* get username and password */ + avp = search_first_avp( user_avp_type, user_avp_name, &val, 0); + if ( avp==NULL || (avp->flags&AVP_VAL_STR)==0 || val.s.len<=0 ) + return 0; + crd.user = val.s; + + avp = search_first_avp( pwd_avp_type, pwd_avp_name, &val, 0); + if ( avp==NULL || (avp->flags&AVP_VAL_STR)==0 || val.s.len<=0 ) + return 0; + crd.passwd = val.s; + + return &crd; +} + + struct uac_credential *lookup_realm( str *realm) { struct uac_credential *crd; + /* first look into AVP, if set */ + if ( realm_avp_name && (crd=get_avp_credential(realm))!=NULL ) + return crd; + + /* search in the static list */ for( crd=crd_list ; crd ; crd=crd->next ) if (realm->len==crd->realm.len && strncmp( realm->s, crd->realm.s, realm->len)==0 ) @@ -220,7 +268,7 @@ static inline void cvt_hex(HASH bin, HASHHEX hex) -/* +/* * calculate H(A1) */ void uac_calc_HA1( struct uac_credential *crd, @@ -255,7 +303,7 @@ void uac_calc_HA1( struct uac_credential *crd, -/* +/* * calculate H(A2) */ void uac_calc_HA2( str *method, str *uri, @@ -283,8 +331,8 @@ void uac_calc_HA2( str *method, str *uri, -/* - * calculate request-digest/response-digest as per HTTP Digest spec +/* + * calculate request-digest/response-digest as per HTTP Digest spec */ void uac_calc_response( HASHHEX ha1, HASHHEX ha2, struct authenticate_body *auth, @@ -411,11 +459,10 @@ void do_uac_auth(str *method, str *uri, struct uac_credential *crd, }while(0) -str* build_authorization_hdr(int code, str *uri, +str* build_authorization_hdr(int code, str *uri, struct uac_credential *crd, struct authenticate_body *auth, struct authenticate_nc_cnonce *auth_nc_cnonce, char *response) { - static str hdr; char *p; int len; int response_len; @@ -438,14 +485,17 @@ str* build_authorization_hdr(int code, str *uri, NC_FIELD_LEN + auth_nc_cnonce->nc->len + FIELD_SEPARATOR_UQ_LEN + CNONCE_FIELD_LEN + auth_nc_cnonce->cnonce->len + FIELD_SEPARATOR_LEN; - hdr.s = (char*)pkg_malloc( len + 1); - if (hdr.s==0) + if (auth_hdr.s || auth_hdr.len) + LM_WARN("potential memory leak at addr: %p\n", auth_hdr.s); + + auth_hdr.s = (char*)pkg_malloc( len + 1); + if (auth_hdr.s==NULL) { LM_ERR("no more pkg mem\n"); goto error; } - p = hdr.s; + p = auth_hdr.s; /* header start */ if (code==401) { @@ -462,7 +512,7 @@ str* build_authorization_hdr(int code, str *uri, FIELD_SEPARATOR_LEN+REALM_FIELD_LEN); add_string( p, crd->realm.s, crd->realm.len); /* NONCE */ - add_string( p, FIELD_SEPARATOR_S NONCE_FIELD_S, + add_string( p, FIELD_SEPARATOR_S NONCE_FIELD_S, FIELD_SEPARATOR_LEN+NONCE_FIELD_LEN); add_string( p, auth->nonce.s, auth->nonce.len); /* URI */ @@ -472,19 +522,19 @@ str* build_authorization_hdr(int code, str *uri, /* OPAQUE */ if (auth->opaque.len ) { - add_string( p, FIELD_SEPARATOR_S OPAQUE_FIELD_S, + add_string( p, FIELD_SEPARATOR_S OPAQUE_FIELD_S, FIELD_SEPARATOR_LEN+OPAQUE_FIELD_LEN); add_string( p, auth->opaque.s, auth->opaque.len); } if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT)) { - add_string( p, FIELD_SEPARATOR_S QOP_FIELD_S, + add_string( p, FIELD_SEPARATOR_S QOP_FIELD_S, FIELD_SEPARATOR_LEN+QOP_FIELD_LEN); add_string( p, "auth", 4); - add_string( p, FIELD_SEPARATOR_UQ_S NC_FIELD_S, + add_string( p, FIELD_SEPARATOR_UQ_S NC_FIELD_S, FIELD_SEPARATOR_UQ_LEN+NC_FIELD_LEN); add_string( p, auth_nc_cnonce->nc->s, auth_nc_cnonce->nc->len); - add_string( p, FIELD_SEPARATOR_UQ_S CNONCE_FIELD_S, + add_string( p, FIELD_SEPARATOR_UQ_S CNONCE_FIELD_S, FIELD_SEPARATOR_UQ_LEN+CNONCE_FIELD_LEN); add_string( p, auth_nc_cnonce->cnonce->s, auth_nc_cnonce->cnonce->len); } @@ -496,20 +546,20 @@ str* build_authorization_hdr(int code, str *uri, add_string( p, FIELD_SEPARATOR_S ALGORITHM_FIELD_S CRLF, FIELD_SEPARATOR_LEN+ALGORITHM_FIELD_LEN+CRLF_LEN); - hdr.len = p - hdr.s; + auth_hdr.len = p - auth_hdr.s; - if (hdr.len!=len) + if (auth_hdr.len!=len) { LM_CRIT("BUG: bad buffer computation " - "(%d<>%d)\n",len,hdr.len); - pkg_free( hdr.s ); + "(%d<>%d)\n",len,auth_hdr.len); + pkg_free( auth_hdr.s ); + auth_hdr.s = NULL; auth_hdr.len = 0; goto error; } - LM_DBG("hdr is <%.*s>\n", - hdr.len,hdr.s); + LM_DBG("auth_hdr is <%.*s>\n", auth_hdr.len, auth_hdr.s); - return &hdr; + return &auth_hdr; error: return 0; } diff --git a/modules/uac_auth/doc/uac_auth.xml b/modules/uac_auth/doc/uac_auth.xml index c33e72f5322..f94097e7fa5 100644 --- a/modules/uac_auth/doc/uac_auth.xml +++ b/modules/uac_auth/doc/uac_auth.xml @@ -17,6 +17,11 @@ UAC AUTH Module &osipsname; + + Bogdan-Andrei + Iancu + bogdan@opensips.org + Ovidiu Sas @@ -27,11 +32,20 @@ Sas osas@voipembedded.com + + Bogdan-Andrei + Iancu + bogdan@opensips.org + 2011 VoIP Embedded, Inc. + + 2013 + &osipssol; + $Revision: 8101 $ diff --git a/modules/uac_auth/doc/uac_auth_admin.xml b/modules/uac_auth/doc/uac_auth_admin.xml index 36619e58895..ab15fb0fdc3 100644 --- a/modules/uac_auth/doc/uac_auth_admin.xml +++ b/modules/uac_auth/doc/uac_auth_admin.xml @@ -82,6 +82,79 @@ modparam("uac_auth","credential","username:domain:0xc17ba8157756f263d07e15850420
+ +
+ <varname>auth_realm_avp</varname> (string) + + The definition of an AVP that might contain the realm to be used + to perform authentication. + + + If you define it, you also need to define + auth_username_avp + () and + auth_username_avp + (). + + + Set <varname>auth_realm_avp</varname> parameter + +... +modparam("uac_auth","auth_realm_avp","$avp(10)") +... + + +
+ +
+ <varname>auth_username_avp</varname> (string) + + The definition of an AVP that might contain the username to be used + to perform authentication. + + + If you define it, you also need to define + auth_realm_avp + () and + auth_username_avp + (). + + + Set <varname>auth_username_avp</varname> parameter + +... +modparam("uac_auth","auth_username_avp","$avp(11)") +... + + +
+ +
+ <varname>auth_password_avp</varname> (string) + + The definition of an AVP that might contain the password to be used + to perform authentication. The password can be provided as a plain + text password or as a precalculated HA1 as a hexa (lower case) string + (of 32 chars) prefixed with "0x" (so a total of 34 chars) (for example + "0xc17ba8157756f263d07e158504204629") + + + If you define it, you also need to define + auth_password_avp + () and + auth_username_avp + (). + + + Set <varname>auth_password_avp</varname> parameter + +... +modparam("uac_auth","auth_password_avp","$avp(12)") +... + + +
+
diff --git a/modules/uac_auth/uac_auth.c b/modules/uac_auth/uac_auth.c index 6fbf0774b5d..80350932501 100644 --- a/modules/uac_auth/uac_auth.c +++ b/modules/uac_auth/uac_auth.c @@ -4,6 +4,7 @@ * uac_auth module * * Copyright (C) 2011 VoIP Embedded Inc. + * Copyright (C) 2013 OpenSIPS Solutions. * * This file is part of opensips, a free SIP server. * @@ -37,11 +38,23 @@ /** Functions declarations */ static int mod_init(void); static void mod_destroy(void); -static int child_init(int rank); int uac_auth_bind(uac_auth_api_t* api); int add_credential( unsigned int type, void *val); void destroy_credentials(void); +/* local variable used for init */ +static char* auth_username_avp = NULL; +static char* auth_realm_avp = NULL; +static char* auth_password_avp = NULL; + +int realm_avp_name = 0; +unsigned short realm_avp_type=0; +int user_avp_name = 0; +unsigned short user_avp_type=0; +int pwd_avp_name = 0; +unsigned short pwd_avp_type=0; + + /** Exported functions */ static cmd_export_t cmds[]= { @@ -51,35 +64,80 @@ static cmd_export_t cmds[]= /** Exported parameters */ static param_export_t params[]= { - {"credential", STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential }, + {"credential", STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential }, + {"auth_username_avp", STR_PARAM, &auth_username_avp }, + {"auth_realm_avp", STR_PARAM, &auth_realm_avp }, + {"auth_password_avp", STR_PARAM, &auth_password_avp }, + {0,0,0} }; /** Module interface */ struct module_exports exports= { - "uac_auth", /* module name */ - MODULE_VERSION, /* module version */ - DEFAULT_DLFLAGS, /* dlopen flags */ - cmds, /* exported functions */ - params, /* exported parameters */ - NULL, /* exported statistics */ - 0, /* exported MI functions */ - NULL, /* exported pseudo-variables */ - 0, /* extra processes */ - mod_init, /* module initialization function */ - (response_function) NULL, /* response handling function */ - (destroy_function) mod_destroy, /* destroy function */ - child_init /* per-child init function */ + "uac_auth", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ + MODULE_VERSION, /* module version */ + DEFAULT_DLFLAGS, /* dlopen flags */ + NULL, /* OpenSIPS module dependencies */ + cmds, /* exported functions */ + params, /* exported parameters */ + NULL, /* exported statistics */ + 0, /* exported MI functions */ + NULL, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + (response_function) NULL, /* response handling function */ + (destroy_function) mod_destroy, /* destroy function */ + NULL /* per-child init function */ }; + + +inline static int parse_auth_avp( char *avp_spec, pv_spec_t *avp, char *txt) +{ + str s; + s.s = avp_spec; s.len = strlen(s.s); + if (pv_parse_spec(&s, avp)==NULL) { + LM_ERR("malformed or non AVP %s AVP definition\n",txt); + return -1; + } + return 0; +} + + + /** Module init function */ static int mod_init(void) { + pv_spec_t user_spec; + pv_spec_t realm_spec; + pv_spec_t pwd_spec; + LM_DBG("start\n"); + /* parse the auth AVP spesc, if any */ + if ( auth_username_avp || auth_password_avp || auth_realm_avp) { + if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) { + LM_ERR("partial definition of auth AVP!"); + return -1; + } + if ( parse_auth_avp(auth_realm_avp, &realm_spec, "realm")<0 + || parse_auth_avp(auth_username_avp, &user_spec, "username")<0 + || parse_auth_avp(auth_password_avp, &pwd_spec, "password")<0 + || pv_get_avp_name(0, &(realm_spec.pvp), &(realm_avp_name), &(realm_avp_type) )!=0 + || pv_get_avp_name(0, &(user_spec.pvp), &(user_avp_name), &(user_avp_type) )!=0 + || pv_get_avp_name(0, &(pwd_spec.pvp), &(pwd_avp_name), &(pwd_avp_type) )!=0 + ) { + LM_ERR("invalid AVP definition for AUTH avps\n"); + return -1; + } + } + return 0; } + + static void mod_destroy(void) { destroy_credentials(); @@ -87,7 +145,7 @@ static void mod_destroy(void) return; } -static int child_init(int rank){return 0;} + int uac_auth_bind(uac_auth_api_t *api) { diff --git a/modules/uac_auth/uac_auth.h b/modules/uac_auth/uac_auth.h index b47fd8e53f9..20690578179 100644 --- a/modules/uac_auth/uac_auth.h +++ b/modules/uac_auth/uac_auth.h @@ -94,7 +94,6 @@ static inline int load_uac_auth_api( uac_auth_api_t *uac_auth_api) /* import the uac_auth auto-loading function */ if ( !(load_uac_auth=(load_uac_auth_f)find_export("load_uac_auth", 1, 0))) { - LM_ERR("can't import load_uac_auth\n"); return -1; } diff --git a/modules/uac_redirect/README b/modules/uac_redirect/README index e5382df381e..fc155b969a6 100644 --- a/modules/uac_redirect/README +++ b/modules/uac_redirect/README @@ -8,8 +8,7 @@ Bogdan-Andrei Iancu Copyright © 2005 Voice Sistem Revision History - Revision $Revision$ $Date: 2012-02-22 19:29:43 +0200 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/uac_redirect/rd_funcs.c b/modules/uac_redirect/rd_funcs.c index 850a4be71bd..428e8dd61e3 100644 --- a/modules/uac_redirect/rd_funcs.c +++ b/modules/uac_redirect/rd_funcs.c @@ -182,7 +182,7 @@ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl, return 0; if ( sh_rpl->msg_flags&FL_SHM_CLONE ) { - /* duplicate the reply into private memory to be able + /* duplicate the reply into private memory to be able * to parse it and after words to free the parsed mems */ memcpy( &dup_rpl, sh_rpl, sizeof(struct sip_msg) ); LM_DBG("duplicating shm reply\n"); @@ -275,7 +275,7 @@ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl, backup_uri = req->new_uri; req->new_uri = scontacts[i]; //FIXME - rd_acc_fct( req, (char*)reason, acc_db_table, + rd_acc_fct( req, (char*)reason, acc_db_table, NULL, NULL, NULL, NULL); req->new_uri = backup_uri; } @@ -289,7 +289,7 @@ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl, free_contact( (contact_body_t**)(void*)(&hdr->parsed) ); /* are any new headers found? */ if (dup_rpl.last_header!=sh_rpl->last_header) { - /* identify in the new headere list (from dup_rpl) + /* identify in the new headere list (from dup_rpl) * the sh_rpl->last_header and start remove everything after */ hdr = sh_rpl->last_header; free_hdr_field_lst(hdr->next); diff --git a/modules/uac_redirect/redirect.c b/modules/uac_redirect/redirect.c index a235c2b5db8..6c2361c22ac 100644 --- a/modules/uac_redirect/redirect.c +++ b/modules/uac_redirect/redirect.c @@ -88,11 +88,23 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "acc", DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; struct module_exports exports = { "uac_redirect", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -127,7 +139,7 @@ int get_nr_max(char *s, unsigned char *max) *max = (unsigned char)nr; return 0; }else{ - LM_ERR("bad number <%s>\n",s); + LM_ERR("bad number <%s>\n",s); return -1; } } diff --git a/modules/uac_registrant/README b/modules/uac_registrant/README index feb700c77c7..0e9f86bac5f 100644 --- a/modules/uac_registrant/README +++ b/modules/uac_registrant/README @@ -10,10 +10,9 @@ Ovidiu Sas - Copyright © 2011 VoIP Embedded, Inc. + Copyright © 2011-2014 VoIP Embedded, Inc. Revision History - Revision $Revision$ $Date: 2011-06-30 17:23:37 +0300 (Thu, 30 - Jun 2011) $ + Revision $Revision$ $Date$ __________________________________________________________ Table of Contents @@ -47,6 +46,7 @@ Ovidiu Sas 1.5. Exported MI Functions 1.5.1. reg_list + 1.5.2. reg_reload List of Examples @@ -70,17 +70,24 @@ Chapter 1. Admin Guide 1.1. Overview The module enable OpenSIPS to register itself on a remote SIP - registrar. Several registrant accounts can be defined, each - account is specified by the "uac" parameter. + registrar. At startup, the registrant records are loaded into a hash table in memory and a timer is started. The hash index is computed - over the AOR field. For better hash distribution, the size of - the hash table is configurable. When the timer fires for the - first time, the first hash table will be checked and REGISTERs - will be sent out for each record that is found. On the next - timeout fire, the second hash table will be checked and so on. - The timer interval is configurable. + over the AOR field. + + The timer interval for checking records in a hash bucket is + computed by dividing the timer_interval module param by the + number of hash buckets. When the timer fires for the first + time, the first hash bucket will be checked and REGISTERs will + be sent out for each record that is found. On the next timeout + fire, the second hash bucket will be checked and so on. If the + configured timer_interval module param is lower then the number + of buckets, the module will fail to start. + + Example: setting the timer_interval module to 8 with a + hash_size of 2, will result in having 4 hash buckets (2^2=4) + and buckets will be checked one by one every 2s (8/4=2). Each registrant has it's own state. Registranr's status can be inspected via "reg_list" MI comand. @@ -176,7 +183,7 @@ modparam("uac_registrant", "table_name", "my_registrant") Example 1.5. Set “registrar_column” parameter ... -modparam("uac_registrant", "registrar_column", "registranr_uri") +modparam("uac_registrant", "registrar_column", "registrant_uri") ... 1.3.6. proxy_column (string) @@ -320,3 +327,15 @@ modparam("uac_registrant", "forced_socket_column", "fs") MI FIFO Command Format: :reg_list:_reply_fifo_file_ _empty_line_ + +1.5.2. reg_reload + + Reloads the registrant records from the database. + + Name: reg_reload + + Parameters: none + + MI FIFO Command Format: +:reg_reload:_reply_fifo_file_ +_empty_line_ diff --git a/modules/uac_registrant/doc/uac_registrant.xml b/modules/uac_registrant/doc/uac_registrant.xml index 4c51f37d736..b9041f5f0fb 100644 --- a/modules/uac_registrant/doc/uac_registrant.xml +++ b/modules/uac_registrant/doc/uac_registrant.xml @@ -29,7 +29,7 @@ - 2011 + 2011-2014 VoIP Embedded, Inc. diff --git a/modules/uac_registrant/doc/uac_registrant_admin.xml b/modules/uac_registrant/doc/uac_registrant_admin.xml index 2bb0bb13b71..3e06a0073fb 100644 --- a/modules/uac_registrant/doc/uac_registrant_admin.xml +++ b/modules/uac_registrant/doc/uac_registrant_admin.xml @@ -9,22 +9,28 @@ Overview The module enable &osips; to register itself on a remote SIP registrar. - Several registrant accounts can be defined, each account is - specified by the "uac" parameter. At startup, the registrant records are loaded into a hash table in memory and a timer is started. The hash index is computed over the AOR field. - For better hash distribution, the size of the hash table is configurable. - When the timer fires for the first time, the first hash table will be checked and + + + The timer interval for checking records in a hash bucket is computed + by dividing the timer_interval module param by the number of hash buckets. + When the timer fires for the first time, the first hash bucket will be checked and REGISTERs will be sent out for each record that is found. - On the next timeout fire, the second hash table will be checked and so on. - The timer interval is configurable. + On the next timeout fire, the second hash bucket will be checked and so on. + If the configured timer_interval module param is lower then the number of buckets, + the module will fail to start. + + + Example: setting the timer_interval module to 8 with a hash_size of 2, will result + in having 4 hash buckets (2^2=4) and buckets will be checked one by one every 2s (8/4=2). - Each registrant has it's own state. - Registranr's status can be inspected via "reg_list" MI comand. + Each registrant has it's own state. + Registranr's status can be inspected via "reg_list" MI comand. UAC registrant states: @@ -193,7 +199,7 @@ modparam("uac_registrant", "table_name", "my_registrant") Set <quote>registrar_column</quote> parameter ... -modparam("uac_registrant", "registrar_column", "registranr_uri") +modparam("uac_registrant", "registrar_column", "registrant_uri") ... @@ -413,6 +419,17 @@ modparam("uac_registrant", "forced_socket_column", "fs") MI FIFO Command Format: :reg_list:_reply_fifo_file_ +_empty_line_ + +
+
+ <function moreinfo="none">reg_reload</function> + Reloads the registrant records from the database. + Name: reg_reload + Parameters: none + MI FIFO Command Format: + +:reg_reload:_reply_fifo_file_ _empty_line_
diff --git a/modules/uac_registrant/reg_db_handler.c b/modules/uac_registrant/reg_db_handler.c index 55be7399d8c..3b2d399714f 100644 --- a/modules/uac_registrant/reg_db_handler.c +++ b/modules/uac_registrant/reg_db_handler.c @@ -72,12 +72,12 @@ static int use_reg_table(void) } -static int load_reg_info_from_db(void) +int load_reg_info_from_db(unsigned int plist) { db_res_t * res = NULL; db_val_t * values; db_row_t * rows; - int i, nr_rows; + int i, nr_rows, ret; unsigned int n_result_cols = 0; unsigned int registrar_col; unsigned int proxy_col; @@ -289,6 +289,13 @@ static int load_reg_info_from_db(void) /* Get the expiration param */ uac_param.expires = values[expiry_col].val.int_val; + if (uac_param.expires <= timer_interval) { + LM_ERR("Please decrease timer_interval=[%u]" + " - requested expires=[%u] to small for AOR=[%.*s]\n", + timer_interval, uac_param.expires, + uac_param.to_uri.len, uac_param.to_uri.s); + continue; + } /* Get the socket */ if (values[forced_socket_col].val.string_val && @@ -323,7 +330,10 @@ static int load_reg_info_from_db(void) uac_param.proxy_uri.len, uac_param.proxy_uri.s, uac_param.contact_uri.len, uac_param.contact_uri.s, uac_param.from_uri.len, uac_param.from_uri.s); - if(add_record(&uac_param, &now)<0) { + lock_get(®_htable[uac_param.hash_code].lock); + ret = add_record(&uac_param, &now, plist); + lock_release(®_htable[uac_param.hash_code].lock); + if(ret<0) { LM_ERR("can't load registrant\n"); continue; } @@ -367,7 +377,8 @@ int init_reg_db(const str *db_url) LM_ERR("error during table version check.\n"); return -1; } - if(load_reg_info_from_db() !=0){ + /* Load registrants into the primary list */ + if(load_reg_info_from_db(0) !=0){ LM_ERR("unable to load the registrant data\n"); return -1; } diff --git a/modules/uac_registrant/reg_db_handler.h b/modules/uac_registrant/reg_db_handler.h index eebdd95c373..a69fabd15f5 100644 --- a/modules/uac_registrant/reg_db_handler.h +++ b/modules/uac_registrant/reg_db_handler.h @@ -67,8 +67,11 @@ extern str forced_socket_column; extern str reg_table_name; +extern unsigned int timer_interval; + int init_reg_db(const str *db_url); int connect_reg_db(const str *db_url); +int load_reg_info_from_db(unsigned int plist); void destroy_reg_db(void); #endif diff --git a/modules/uac_registrant/reg_records.c b/modules/uac_registrant/reg_records.c index ecda1ca4906..385a2bbcce7 100644 --- a/modules/uac_registrant/reg_records.c +++ b/modules/uac_registrant/reg_records.c @@ -32,15 +32,17 @@ #include "reg_records.h" extern unsigned int default_expires; +extern const str uac_reg_state[]; static char call_id_ftag_buf[MD5_LEN]; void reg_print_record(reg_record_t *rec) { - LM_DBG("checking uac=[%p] state=[%d] expires=[%d]" + LM_DBG("checking uac=[%p] state=[%d][%.*s] expires=[%d]" " last_register_sent=[%d] registration_timeout=[%d]" " auth_user[%p][%d]->[%.*s] auth_password=[%p][%d]->[%.*s] sock=[%p]\n", - rec, rec->state, rec->expires, + rec, rec->state, + uac_reg_state[rec->state].len, uac_reg_state[rec->state].s, rec->expires, (unsigned int)rec->last_register_sent, (unsigned int)rec->registration_timeout, rec->auth_user.s, rec->auth_user.len, rec->auth_user.len, rec->auth_user.s, rec->auth_password.s, rec->auth_password.len, @@ -104,20 +106,25 @@ void new_call_id_ftag_4_record(reg_record_t *rec, str *now) } -int add_record(uac_reg_map_t *uac, str *now) +int add_record(uac_reg_map_t *uac, str *now, unsigned int plist) { - reg_record_t *rec, *prev_rec, *record; + reg_record_t *record; unsigned int size; dlg_t *td; str call_id_ftag; char *p; + slinkedl_list_t *list; /* Reserve space for record */ size = sizeof(reg_record_t) + MD5_LEN + uac->to_uri.len + uac->from_uri.len + uac->registrar_uri.len + uac->auth_user.len + uac->auth_password.len + uac->contact_uri.len + uac->contact_params.len + uac->proxy_uri.len; - record = (reg_record_t *)shm_malloc(size); + + if(plist==0) list = reg_htable[uac->hash_code].p_list; + else list = reg_htable[uac->hash_code].s_list; + + record = (reg_record_t*)slinkedl_append(list, size); if(!record) { LM_ERR("oom\n"); return -1; @@ -222,22 +229,11 @@ int add_record(uac_reg_map_t *uac, str *now) reg_print_record(record); - rec = reg_htable[uac->hash_code].first; - if (rec) { - while(rec) { - prev_rec = rec; - rec = rec->next; - } - prev_rec->next = record; - record->prev = prev_rec; - } else { - reg_htable[uac->hash_code].first = record; - record->prev = record->next = NULL; - } - return 0; } +void *reg_alloc(size_t size) { return shm_malloc(size); } +void reg_free(void *ptr) { shm_free(ptr); return; } int init_reg_htable(void) { int i; @@ -250,7 +246,13 @@ int init_reg_htable(void) { for(i= 0; inext; - } + slinkedl_list_destroy(reg_htable[i].p_list); + reg_htable[i].p_list = NULL; } shm_free(reg_htable); reg_htable = NULL; diff --git a/modules/uac_registrant/reg_records.h b/modules/uac_registrant/reg_records.h index 7bd0556e87a..d2699306b7b 100644 --- a/modules/uac_registrant/reg_records.h +++ b/modules/uac_registrant/reg_records.h @@ -37,6 +37,7 @@ #include "../../mem/shm_mem.h" #include "../tm/dlg.h" #include "../tm/tm_load.h" +#include "../../sliblist.h" #define NOT_REGISTERED_STATE 0 @@ -82,7 +83,8 @@ typedef struct reg_record { } reg_record_t; typedef struct reg_entry { - reg_record_t *first; + slinkedl_list_t *p_list; + slinkedl_list_t *s_list; gen_lock_t lock; } reg_entry_t; @@ -91,11 +93,13 @@ typedef reg_entry_t *reg_table_t; extern reg_table_t reg_htable; extern unsigned int reg_hsize; +void *reg_alloc(size_t size); +void reg_free(void *ptr); int init_reg_htable(void); void destroy_reg_htable(void); void new_call_id_ftag_4_record(reg_record_t *rec, str *now); -int add_record(uac_reg_map_t *uac, str *now); +int add_record(uac_reg_map_t *uac, str *now, unsigned int plist); void reg_print_record(reg_record_t *rec); #endif diff --git a/modules/uac_registrant/registrant.c b/modules/uac_registrant/registrant.c index ada06daaf8c..d663eeb7a64 100644 --- a/modules/uac_registrant/registrant.c +++ b/modules/uac_registrant/registrant.c @@ -42,18 +42,37 @@ #include "reg_db_handler.h" -#define UAC_REGISTRAR_URI_PARAM 1 -#define UAC_PROXY_URI_PARAM 2 -#define UAC_AOR_URI_PARAM 3 -#define UAC_THIRD_PARTY_REGISTRANT_URI_PARAM 4 -#define UAC_AUTH_USER_PARAM 5 -#define UAC_AUTH_PASSWORD_PARAM 6 -#define UAC_CONTACT_URI_PARAM 7 -#define UAC_CONTACT_PARAMS_PARAM 8 -#define UAC_EXPIRES_PARAM 9 -#define UAC_FORCED_SOCKET_PARAM 10 -#define UAC_MAX_PARAMS_NO 11 - +#define UAC_REGISTRAR_URI_PARAM 1 +#define UAC_PROXY_URI_PARAM 2 +#define UAC_AOR_URI_PARAM 3 +#define UAC_THIRD_PARTY_REGISTRANT_URI_PARAM 4 +#define UAC_AUTH_USER_PARAM 5 +#define UAC_AUTH_PASSWORD_PARAM 6 +#define UAC_CONTACT_URI_PARAM 7 +#define UAC_CONTACT_PARAMS_PARAM 8 +#define UAC_EXPIRES_PARAM 9 +#define UAC_FORCED_SOCKET_PARAM 10 +#define UAC_MAX_PARAMS_NO 11 + +#define UAC_REG_NOT_REGISTERED_STATE "NOT_REGISTERED_STATE" +#define UAC_REG_REGISTERING_STATE "REGISTERING_STATE" +#define UAC_REG_AUTHENTICATING_STATE "AUTHENTICATING_STATE" +#define UAC_REG_REGISTERED_STATE "REGISTERED_STATE" +#define UAC_REG_REGISTER_TIMEOUT_STATE "REGISTER_TIMEOUT_STATE" +#define UAC_REG_INTERNAL_ERROR_STATE "INTERNAL_ERROR_STATE" +#define UAC_REG_WRONG_CREDENTIALS_STATE "WRONG_CREDENTIALS_STATE" +#define UAC_REG_REGISTRAR_ERROR_STATE "REGISTRAR_ERROR_STATE" + +const str uac_reg_state[]={ + str_init(UAC_REG_NOT_REGISTERED_STATE), + str_init(UAC_REG_REGISTERING_STATE), + str_init(UAC_REG_AUTHENTICATING_STATE), + str_init(UAC_REG_REGISTERED_STATE), + str_init(UAC_REG_REGISTER_TIMEOUT_STATE), + str_init(UAC_REG_INTERNAL_ERROR_STATE), + str_init(UAC_REG_WRONG_CREDENTIALS_STATE), + str_init(UAC_REG_REGISTRAR_ERROR_STATE), +}; /** Functions declarations */ static int mod_init(void); @@ -63,6 +82,7 @@ static int child_init(int rank); void timer_check(unsigned int ticks, void* param); static struct mi_root* mi_reg_list(struct mi_root* cmd, void* param); +static struct mi_root* mi_reg_reload(struct mi_root* cmd, void* param); int send_register(unsigned int hash_index, reg_record_t *rec, str *auth_hdr); @@ -127,16 +147,29 @@ static param_export_t params[]= { /** MI commands */ static mi_export_t mi_cmds[] = { - {"reg_list", 0, mi_reg_list, 0, 0, 0}, - {0, 0, 0, 0, 0, 0} + {"reg_list", 0, mi_reg_list, 0, 0, 0}, + {"reg_reload", 0, mi_reg_reload, 0, 0, 0}, + {0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "uac_auth", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; /** Module interface */ struct module_exports exports= { "uac_registrant", /* module name */ + MOD_TYPE_DEFAULT, /* class of this module */ MODULE_VERSION, /* module version */ DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ NULL, /* exported statistics */ @@ -153,6 +186,8 @@ struct module_exports exports= { /** Module init function */ static int mod_init(void) { + unsigned int _timer; + if(load_uac_auth_api(&uac_auth_api)<0){ LM_ERR("Failed to load uac_auth api\n"); return -1; @@ -200,7 +235,13 @@ static int mod_init(void) return -1; } - register_timer("registrat-check",timer_check, 0, timer_interval/reg_hsize); + _timer = timer_interval/reg_hsize; + if (_timer) { + register_timer("uac_reg_check", timer_check, 0, _timer); + } else { + LM_ERR("timer_interval=[%d] MUST be bigger then reg_hsize=[%d]\n", timer_interval, reg_hsize); + return -1; + } return 0; } @@ -226,13 +267,19 @@ static int child_init(int rank) void shm_free_param(void* param) {shm_free(param);} -void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) +struct reg_tm_cback_data { + struct cell *t; + struct tmcb_params *ps; + time_t now; + reg_tm_cb_t *cb_param; +}; + +int run_reg_tm_cback(void *e_data, void *data, void *r_data) { struct sip_msg *msg; - reg_tm_cb_t *cb_param; int statuscode = 0; unsigned int exp = 0; - reg_record_t *rec; + reg_record_t *rec = (reg_record_t*)e_data; struct hdr_field *c_ptr, *head_contact; struct uac_credential crd; contact_t *contact; @@ -240,43 +287,22 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) static struct authenticate_nc_cnonce auth_nc_cnonce; HASHHEX response; str *new_hdr; + struct reg_tm_cback_data *tm_cback_data = (struct reg_tm_cback_data*)data; + struct cell *t; + struct tmcb_params *ps; time_t now; + reg_tm_cb_t *cb_param; - if(ps==NULL || ps->rpl==NULL) { - LM_ERR("wrong ps parameter\n"); - return; - } - if(ps->param==NULL || *ps->param==NULL) { - LM_ERR("null callback parameter\n"); - return; - } - cb_param = (reg_tm_cb_t *)*ps->param; - if(cb_param->uac == NULL) { - LM_ERR("null record\n"); - return; + cb_param = tm_cback_data->cb_param; + if (rec!=cb_param->uac) { + /* no action on current list elemnt */ + return 0; /* continue list traversal */ } - statuscode = ps->code; - now = time(0); - LM_DBG("tm [%p] notification cb for %s [%d] reply at [%d]\n", - t, (ps->rpl==FAKED_REPLY)?"FAKED_REPLY":"", - statuscode, (unsigned int)now); - if(statuscode<200) return; + t = tm_cback_data->t; + ps = tm_cback_data->ps; + now = tm_cback_data->now; - lock_get(®_htable[cb_param->hash_index].lock); - rec = reg_htable[cb_param->hash_index].first; - while(rec) { - if (rec==cb_param->uac) { - break; - } - rec = rec->next; - } - if(!rec) { - LM_ERR("record [%p] not found on hash index [%d]\n", - cb_param->uac, cb_param->hash_index); - lock_release(®_htable[cb_param->hash_index].lock); - return; - } reg_print_record(rec); if (ps->rpl==FAKED_REPLY) @@ -284,6 +310,7 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) else if (rec->td.forced_to_su.s.sa_family == AF_UNSPEC) rec->td.forced_to_su = t->uac[0].request.dst.to; + statuscode = ps->code; switch(statuscode) { case 200: msg = ps->rpl; @@ -323,13 +350,11 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) contact->expires->body.len, contact->expires->body.s, contact->uri.len, contact->uri.s); - } else { - rec->expires = exp; } } break; } - + /* get the next contact */ if (contact->next == NULL) { contact = NULL; @@ -347,6 +372,13 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) } } rec->state = REGISTERED_STATE; + if (exp) rec->expires = exp; + if (rec->expires <= timer_interval) { + LM_ERR("Please decrease timer_interval=[%u]" + " - imposed server expires [%u] to small for AOR=[%.*s]\n", + timer_interval, rec->expires, + rec->td.rem_uri.len, rec->td.rem_uri.s); + } rec->registration_timeout = now + rec->expires - timer_interval; break; @@ -363,8 +395,8 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) LM_ERR("Credentials not provisioned\n"); rec->state = WRONG_CREDENTIALS_STATE; rec->registration_timeout = 0; - lock_release(®_htable[cb_param->hash_index].lock); - return; + /* action successfuly completed on current list element */ + return 1; /* exit list traversal */ } if (statuscode==WWW_AUTH_CODE) { @@ -396,8 +428,8 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) rec->td.rem_uri.len, rec->td.rem_uri.s); rec->state = WRONG_CREDENTIALS_STATE; rec->registration_timeout = 0; - lock_release(®_htable[cb_param->hash_index].lock); - return; + /* action successfuly completed on current list element */ + return 1; /* exit list traversal */ default: LM_ERR("Unexpected [%d] notification cb in state [%d]\n", statuscode, rec->state); @@ -428,6 +460,8 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) } else { rec->state = INTERNAL_ERROR_STATE; } + pkg_free(new_hdr->s); + new_hdr->s = NULL; new_hdr->len = 0; break; case 423: /* Interval Too Brief */ @@ -448,6 +482,11 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) } break; + case 408: /* Interval Too Brief */ + rec->state = REGISTER_TIMEOUT_STATE; + rec->registration_timeout = now + rec->expires - timer_interval; + break; + default: if(statuscode<400 && statuscode>=300) { LM_ERR("Redirection not implemented yet\n"); @@ -456,17 +495,65 @@ void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) /* we got an error from the server */ rec->state = REGISTRAR_ERROR_STATE; rec->registration_timeout = now + rec->expires - timer_interval; - + } } - lock_release(®_htable[cb_param->hash_index].lock); - - return; + /* action successfuly completed on current list element */ + return 1; /* exit list traversal */ done: rec->state = INTERNAL_ERROR_STATE; rec->registration_timeout = now + rec->expires; + return -1; /* exit list traversal */ +} + + + +void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) +{ + reg_tm_cb_t *cb_param; + int statuscode = 0; + int ret; + time_t now; + struct reg_tm_cback_data tm_cback_data; + + if(ps==NULL || ps->rpl==NULL) { + LM_ERR("wrong ps parameter\n"); + return; + } + if(ps->param==NULL || *ps->param==NULL) { + LM_ERR("null callback parameter\n"); + return; + } + cb_param = (reg_tm_cb_t *)*ps->param; + if(cb_param->uac == NULL) { + LM_ERR("null record\n"); + return; + } + statuscode = ps->code; + now = time(0); + LM_DBG("tm [%p] notification cb for %s [%d] reply at [%d]\n", + t, (ps->rpl==FAKED_REPLY)?"FAKED_REPLY":"", + statuscode, (unsigned int)now); + + if(statuscode<200) return; + + /* Initialize slinkedl run traversal data */ + tm_cback_data.t = t; + tm_cback_data.ps = ps; + tm_cback_data.cb_param = cb_param; + tm_cback_data.now = now; + + lock_get(®_htable[cb_param->hash_index].lock); + ret = slinkedl_traverse(reg_htable[cb_param->hash_index].p_list, + &run_reg_tm_cback, (void*)&tm_cback_data, NULL); lock_release(®_htable[cb_param->hash_index].lock); + + if (ret==0) { + LM_ERR("record [%p] not found on hash index [%d]\n", + cb_param->uac, cb_param->hash_index); + } + return; } @@ -534,14 +621,67 @@ int send_register(unsigned int hash_index, reg_record_t *rec, str *auth_hdr) } +struct timer_check_data { + time_t now; + str *s_now; +}; + +int run_timer_check(void *e_data, void *data, void *r_data) +{ + unsigned int i=hash_index; + reg_record_t *rec = (reg_record_t*)e_data; + struct timer_check_data *t_check_data = (struct timer_check_data*)data; + time_t now = t_check_data->now; + str *s_now = t_check_data->s_now; + + switch(rec->state){ + case REGISTERING_STATE: + case AUTHENTICATING_STATE: + break; + case WRONG_CREDENTIALS_STATE: + case REGISTER_TIMEOUT_STATE: + case INTERNAL_ERROR_STATE: + case REGISTRAR_ERROR_STATE: + reg_print_record(rec); + new_call_id_ftag_4_record(rec, s_now); + if(send_register(i, rec, NULL)==1) { + rec->last_register_sent = now; + rec->state = REGISTERING_STATE; + } else { + rec->registration_timeout = now + rec->expires - timer_interval; + rec->state = INTERNAL_ERROR_STATE; + } + break; + case REGISTERED_STATE: + /* check if we need to re-register */ + if (now < rec->registration_timeout) { + break; + } + case NOT_REGISTERED_STATE: + if(send_register(i, rec, NULL)==1) { + rec->last_register_sent = now; + rec->state = REGISTERING_STATE; + } else { + rec->registration_timeout = now + rec->expires - timer_interval; + rec->state = INTERNAL_ERROR_STATE; + } + break; + default: + LM_ERR("Unexpected state [%d] for rec [%p]\n", rec->state, rec); + } + + return 0; /* continue list traversal */ +} + + void timer_check(unsigned int ticks, void* param) { unsigned int i=hash_index; - reg_record_t *rec; char *p; - int len; + int len, ret; time_t now; str str_now = {NULL, 0}; + struct timer_check_data t_check_data; now = time(0); @@ -557,47 +697,15 @@ void timer_check(unsigned int ticks, void* param) } } + /* Initialize slinkedl run traversal data */ + t_check_data.now = now; + t_check_data.s_now = &str_now; + + LM_DBG("checking ... [%d] on htable[%d]\n", (unsigned int)now, i); lock_get(®_htable[i].lock); - //LM_DBG("checking ... [%d] on htable[%d]\n", (unsigned int)now, i); - rec = reg_htable[i].first; - while (rec) { - switch(rec->state){ - case REGISTERING_STATE: - case AUTHENTICATING_STATE: - break; - case WRONG_CREDENTIALS_STATE: - case REGISTER_TIMEOUT_STATE: - case INTERNAL_ERROR_STATE: - case REGISTRAR_ERROR_STATE: - reg_print_record(rec); - new_call_id_ftag_4_record(rec, &str_now); - if(send_register(i, rec, NULL)==1) { - rec->last_register_sent = now; - rec->state = REGISTERING_STATE; - } else { - rec->registration_timeout = now + rec->expires - timer_interval; - rec->state = INTERNAL_ERROR_STATE; - } - break; - case REGISTERED_STATE: - /* check if we need to re-register */ - if (now < rec->registration_timeout) { - break; - } - case NOT_REGISTERED_STATE: - if(send_register(i, rec, NULL)==1) { - rec->last_register_sent = now; - rec->state = REGISTERING_STATE; - } else { - rec->registration_timeout = now + rec->expires - timer_interval; - rec->state = INTERNAL_ERROR_STATE; - } - break; - default: - LM_ERR("Unexpected state [%d] for rec [%p]\n", rec->state, rec); - } - rec = rec->next; - } + ret = slinkedl_traverse(reg_htable[i].p_list, &run_timer_check, + (void*)&t_check_data, NULL); + if (ret<0) LM_CRIT("Unexpected return code %d\n", ret); lock_release(®_htable[i].lock); if (str_now.s) {pkg_free(str_now.s);} @@ -608,98 +716,161 @@ void timer_check(unsigned int ticks, void* param) } -static struct mi_root* mi_reg_list(struct mi_root* cmd, void* param) +/*** MI **/ + +int run_mi_reg_list(void *e_data, void *data, void *r_data) { - struct mi_root *rpl_tree; - struct mi_node *rpl=NULL, *node, *node1; + struct mi_root* rpl_tree = (struct mi_root*)data; + struct mi_node *node, *node1; struct mi_attr* attr; - reg_record_t *rec; - int i, len; + reg_record_t *rec = (reg_record_t*)e_data; + int len; char* p; struct ip_addr addr; + node = add_mi_node_child(&rpl_tree->node, MI_DUP_VALUE, "AOR", 3, + rec->td.rem_uri.s, rec->td.rem_uri.len); + if(node == NULL) goto error; + p = int2str(rec->expires, &len); + attr = add_mi_attr(node, MI_DUP_VALUE, "expires", 7, p, len); + if(attr == NULL) goto error; + + node1 = add_mi_node_child(node, MI_DUP_VALUE, "state", 5, + uac_reg_state[rec->state].s, uac_reg_state[rec->state].len); + if(node1 == NULL) goto error; + + p = ctime(&rec->last_register_sent); + len = strlen(p)-1; + node1 = add_mi_node_child(node, MI_DUP_VALUE, "last_register_sent", 18, p, len); + if(node1 == NULL) goto error; + + p = ctime(&rec->registration_timeout); + len = strlen(p)-1; + node1 = add_mi_node_child(node, MI_DUP_VALUE, "registration_t_out", 18, p, len); + if(node1 == NULL) goto error; + + node1 = add_mi_node_child(node, MI_DUP_VALUE, "registrar", 9, + rec->td.rem_target.s, rec->td.rem_target.len); + if(node1 == NULL) goto error; + + node1 = add_mi_node_child(node, MI_DUP_VALUE, "binding", 7, + rec->contact_uri.s, rec->contact_uri.len); + if(node1 == NULL) goto error; + + if(rec->td.loc_uri.s != rec->td.rem_uri.s) { + node1 = add_mi_node_child(node, MI_DUP_VALUE, + "third_party_registrant", 12, + rec->td.loc_uri.s, rec->td.loc_uri.len); + if(node1 == NULL) goto error; + } + + if (rec->td.obp.s && rec->td.obp.len) { + node1 = add_mi_node_child(node, MI_DUP_VALUE, + "proxy", 5, rec->td.obp.s, rec->td.obp.len); + if(node1 == NULL) goto error; + } + + switch(rec->td.forced_to_su.s.sa_family) { + case AF_UNSPEC: + break; + case AF_INET: + case AF_INET6: + node1 = add_mi_node_child(node, MI_DUP_VALUE, "dst_IP", 6, + (rec->td.forced_to_su.s.sa_family==AF_INET)?"IPv4":"IPv6", 4); + sockaddr2ip_addr(&addr, &rec->td.forced_to_su.s); + p = ip_addr2a(&addr); + if (p == NULL) goto error; + len = strlen(p); + attr = add_mi_attr(node1, MI_DUP_VALUE, "ip", 2, p, len); + if(attr == NULL) goto error; + break; + default: + LM_ERR("unexpected sa_family [%d]\n", rec->td.forced_to_su.s.sa_family); + node1 = add_mi_node_child(node, MI_DUP_VALUE, "dst_IP", 6, "Error", 5); + p = int2str(rec->td.forced_to_su.s.sa_family, &len); + attr = add_mi_attr(node, MI_DUP_VALUE, "sa_family", 9, p, len); + if(attr == NULL) goto error; + } + + /* action successfuly completed on current list element */ + return 0; /* continue list traversal */ +error: + LM_ERR("Unable to create reply\n"); + return -1; /* exit list traversal */ +} + + +static struct mi_root* mi_reg_list(struct mi_root* cmd, void* param) +{ + struct mi_root *rpl_tree; + int i, ret; + rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return NULL; - rpl = &rpl_tree->node; + rpl_tree->node.flags |= MI_IS_ARRAY; - for(i = 0; i< reg_hsize; i++) { + for(i=0; itd.rem_uri.s, rec->td.rem_uri.len); - if(node == NULL) goto error; - p = int2str(rec->state, &len); - attr = add_mi_attr(node, MI_DUP_VALUE, "state", 5, p, len); - if(attr == NULL) goto error; - p = int2str(rec->expires, &len); - attr = add_mi_attr(node, MI_DUP_VALUE, "expires", 7, p, len); - if(attr == NULL) goto error; - p = int2str((unsigned int)rec->last_register_sent, &len); - attr = add_mi_attr(node, MI_DUP_VALUE, "last_register_sent", 18, p, len); - if(attr == NULL) goto error; - p = int2str((unsigned int)rec->registration_timeout, &len); - attr = add_mi_attr(node, MI_DUP_VALUE, "registration_timeout", 20, p, len); - if(attr == NULL) goto error; - - node1 = add_mi_node_child(node, MI_DUP_VALUE, "registrar", 9, - rec->td.rem_target.s, rec->td.rem_target.len); - if(node1 == NULL) goto error; - - node1 = add_mi_node_child(node, MI_DUP_VALUE, "binding", 7, - rec->contact_uri.s, rec->contact_uri.len); - if(node1 == NULL) goto error; - - if(rec->td.loc_uri.s != rec->td.rem_uri.s) { - node1 = add_mi_node_child(node, MI_DUP_VALUE, - "third_party_registrant", 12, - rec->td.loc_uri.s, rec->td.loc_uri.len); - if(node1 == NULL) goto error; - } + ret = slinkedl_traverse(reg_htable[i].p_list, + &run_mi_reg_list, (void*)rpl_tree, NULL); + lock_release(®_htable[i].lock); + if (ret<0) { + LM_ERR("Unable to create reply\n"); + free_mi_tree(rpl_tree); + return NULL; + } + } + return rpl_tree; +} - if (rec->td.obp.s && rec->td.obp.len) { - node1 = add_mi_node_child(node, MI_DUP_VALUE, - "proxy", 5, rec->td.obp.s, rec->td.obp.len); - if(node1 == NULL) goto error; - } +static struct mi_root* mi_reg_reload(struct mi_root* cmd, void* param) +{ + struct mi_root *rpl_tree; + int i; + int err = 0; - switch(rec->td.forced_to_su.s.sa_family) { - case AF_UNSPEC: - break; - case AF_INET: - case AF_INET6: - node1 = add_mi_node_child(node, MI_DUP_VALUE, - "dst_IP", 6, - (rec->td.forced_to_su.s.sa_family==AF_INET)? - "IPv4":"IPv6", 4); - sockaddr2ip_addr(&addr, &rec->td.forced_to_su.s); - p = ip_addr2a(&addr); - if (p == NULL) goto error; - len = strlen(p); - attr = add_mi_attr(node1, MI_DUP_VALUE, "ip", 2, - p, len); - if(attr == NULL) goto error; - break; - default: - LM_ERR("unexpected sa_family [%d]\n", - rec->td.forced_to_su.s.sa_family); - node1 = add_mi_node_child(node, MI_DUP_VALUE, - "dst_IP", 6, "Error", 5); - p = int2str(rec->td.forced_to_su.s.sa_family, &len); - attr = add_mi_attr(node, MI_DUP_VALUE, "sa_family", 9, - p, len); - if(attr == NULL) goto error; - } + rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); + if (rpl_tree==NULL) return NULL; - rec = rec->next; + for(i=0; inext; } } - + nok: free_params(params); return -1; @@ -349,7 +349,7 @@ static inline int e164_check(str* _user) { int i; char c; - + if ((_user->len > 2) && (_user->len < 17) && ((_user->s)[0] == '+')) { for (i = 1; i <= _user->len; i++) { c = (_user->s)[i]; diff --git a/modules/uri/checks.h b/modules/uri/checks.h index db988fae091..1993db7901e 100644 --- a/modules/uri/checks.h +++ b/modules/uri/checks.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/uri/doc/uri_admin.xml b/modules/uri/doc/uri_admin.xml index fa0e65c7474..7a3e50b3cb8 100644 --- a/modules/uri/doc/uri_admin.xml +++ b/modules/uri/doc/uri_admin.xml @@ -317,8 +317,9 @@ if (db_check_from()) { Check if username in the request &uri; belongs to an existing user. - As the checking is done against &uri; table (if use_uri_table is set) - or subscriber table. + Matching is done against the &uri; table (if + use_uri_table is set) + or the subscriber table. This function can be used from REQUEST_ROUTE. @@ -602,8 +603,8 @@ tel2sip(); if (is_uri_user_e164("$fu")) { # Check From header URI user part ... } -if (is_uri_user_e164("$avp(i:705)") { - # Check user part of URI stored in avp i:705 +if (is_uri_user_e164("$avp(uri)") { + # Check user part of URI stored in avp uri ... }; ... diff --git a/modules/uri/uri_mod.c b/modules/uri/uri_mod.c index 7a96716c2c0..f2784983e1a 100644 --- a/modules/uri/uri_mod.c +++ b/modules/uri/uri_mod.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Various URI related functions * @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -122,10 +122,10 @@ static cmd_export_t cmds[] = { {"does_uri_user_exist", (cmd_function)NULL, 1, obsolete_fixup_2, 0, REQUEST_ROUTE|LOCAL_ROUTE}, {"aaa_does_uri_exist", (cmd_function)aaa_does_uri_exist_0, 0, - aaa_fixup_0, 0, + aaa_fixup_0, 0, REQUEST_ROUTE|LOCAL_ROUTE}, {"aaa_does_uri_exist", (cmd_function)aaa_does_uri_exist_1, 1, - aaa_fixup_1, fixup_free_pvar_null, + aaa_fixup_1, fixup_free_pvar_null, REQUEST_ROUTE|LOCAL_ROUTE}, {"aaa_does_uri_user_exist", (cmd_function)aaa_does_uri_user_exist_0, 0, aaa_fixup_0, 0, @@ -194,14 +194,36 @@ static stat_export_t uridb_stats[] = { {0,0,0} }; +static module_dependency_t *get_deps_aaa_url(param_export_t *param) +{ + char *url = *(char **)param->param_pointer; + + if (url || strlen(url) == 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_AAA, NULL, DEP_SILENT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "aaa_url", get_deps_aaa_url }, + { "db_url", get_deps_sqldb_url }, + { NULL, NULL }, + }, +}; /* * Module interface */ struct module_exports exports = { - "uri", + "uri", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ uridb_stats, /* exported statistics */ diff --git a/modules/uri/uri_mod.h b/modules/uri/uri_mod.h index 9cffe013e91..2d900bb7028 100644 --- a/modules/uri/uri_mod.h +++ b/modules/uri/uri_mod.h @@ -1,7 +1,7 @@ /* * $Id: $ * - * URI checks + * URI checks * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2009 Irina Stanescu @@ -19,8 +19,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/userblacklist/README b/modules/userblacklist/README index 43ca474b6ed..05ea48199bb 100644 --- a/modules/userblacklist/README +++ b/modules/userblacklist/README @@ -13,8 +13,7 @@ Henning Westerholt Copyright © 2008 1&1 Internet AG Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents @@ -152,9 +151,7 @@ number, string table) Example 1.4. check_user_blacklist usage ... -$avp(i:80) = $rU; -# rewrite the R-URI -if (!check_user_blacklist("$avp(i:80)", "$avp(i:82)")) +if (!check_user_blacklist("user", "domain.com")) sl_send_reply("403", "Forbidden"); exit; } diff --git a/modules/userblacklist/db.c b/modules/userblacklist/db.c index cbd1f73901c..72427d4d377 100644 --- a/modules/userblacklist/db.c +++ b/modules/userblacklist/db.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -94,7 +94,7 @@ int db_build_userbl_tree(const str *username, const str *domain, const str *tabl db_res_t *res; int i; int n = 0; - + if (dbf.use_table(dbc, table) < 0) { LM_ERR("cannot use table '%.*s'.\n", table->len, table->s); return -1; @@ -141,7 +141,7 @@ int db_reload_source(const str *table, struct dt_node_t *root) db_res_t *res; int i; int n = 0; - + if (dbf.use_table(dbc, table) < 0) { LM_ERR("cannot use table '%.*s'.\n", table->len, table->s); return -1; diff --git a/modules/userblacklist/db.h b/modules/userblacklist/db.h index c36711f8e47..c70d3ab758b 100644 --- a/modules/userblacklist/db.h +++ b/modules/userblacklist/db.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/userblacklist/doc/userblacklist_admin.xml b/modules/userblacklist/doc/userblacklist_admin.xml index a92d79438c8..f0453d5991a 100644 --- a/modules/userblacklist/doc/userblacklist_admin.xml +++ b/modules/userblacklist/doc/userblacklist_admin.xml @@ -138,9 +138,7 @@ modparam("userblacklist", "use_domain", 0) <function>check_user_blacklist</function> usage ... -$avp(i:80) = $rU; -# rewrite the R-URI -if (!check_user_blacklist("$avp(i:80)", "$avp(i:82)")) +if (!check_user_blacklist("user", "domain.com")) sl_send_reply("403", "Forbidden"); exit; } diff --git a/modules/userblacklist/dt.c b/modules/userblacklist/dt.c index 6b6553cd0f9..8b928179f60 100644 --- a/modules/userblacklist/dt.c +++ b/modules/userblacklist/dt.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/userblacklist/dt.h b/modules/userblacklist/dt.h index 2bcf461e51b..46aef54982b 100644 --- a/modules/userblacklist/dt.h +++ b/modules/userblacklist/dt.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/modules/userblacklist/userblacklist.c b/modules/userblacklist/userblacklist.c index 4ef7ffbeaaf..32c7dc73dca 100644 --- a/modules/userblacklist/userblacklist.c +++ b/modules/userblacklist/userblacklist.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -102,11 +102,22 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; struct module_exports exports= { "userblacklist", + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, + &deps, /* OpenSIPS module dependencies */ cmds, params, 0, @@ -353,7 +364,7 @@ static int check_blacklist_fixup(void **arg, int arg_no) if (add_source(table) != 0) { LM_ERR("could not add table"); return -1; - } + } /* get the node that belongs to the table */ node = table2dt(table); @@ -521,7 +532,7 @@ struct mi_root * mi_reload_blacklist(struct mi_root* cmd, void* param) struct mi_root * tmp = NULL; if(reload_sources() == 0) { - tmp = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); + tmp = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); } else { tmp = init_mi_tree( 500, "cannot reload blacklist", 21); } diff --git a/modules/usrloc/README b/modules/usrloc/README index 29a02b09078..d55426f1525 100644 --- a/modules/usrloc/README +++ b/modules/usrloc/README @@ -16,8 +16,7 @@ Bogdan-Andrei Iancu Copyright © 2005-2008 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-02-22 21:29:43 +0400 - (Wed, 22 Feb 2012) $ + Revision $Revision: 8740 $ $Date$ __________________________________________________________ Table of Contents @@ -27,6 +26,7 @@ Bogdan-Andrei Iancu 1.1. Overview 1.1.1. Contact matching + 1.1.2. Contact replication 1.2. Dependencies @@ -50,14 +50,19 @@ Bogdan-Andrei Iancu 1.3.13. received_column (string) 1.3.14. socket_column (string) 1.3.15. path_column (string) - 1.3.16. use_domain (integer) - 1.3.17. desc_time_order (integer) - 1.3.18. timer_interval (integer) - 1.3.19. db_url (string) - 1.3.20. db_mode (integer) - 1.3.21. matching_mode (integer) - 1.3.22. cseq_delay (integer) - 1.3.23. hash_size (integer) + 1.3.16. sip_instance_column (string) + 1.3.17. attr_column (string) + 1.3.18. use_domain (integer) + 1.3.19. desc_time_order (integer) + 1.3.20. timer_interval (integer) + 1.3.21. db_url (string) + 1.3.22. db_mode (integer) + 1.3.23. matching_mode (integer) + 1.3.24. cseq_delay (integer) + 1.3.25. accept_replicated_contacts (integer) + 1.3.26. replicate_contacts_to (string) + 1.3.27. skip_replicated_db_ops (int) + 1.3.28. hash_size (integer) 1.4. Exported Functions 1.5. Exported MI Functions @@ -77,25 +82,38 @@ Bogdan-Andrei Iancu 1.6.3. expires 1.6.4. registered_users + 1.7. Exported Events + + 1.7.1. E_UL_AOR_INSERT + 1.7.2. E_UL_AOR_DELETE + 1.7.3. E_UL_CONTACT_INSERT + 1.7.4. E_UL_CONTACT_DELETE + 1.7.5. E_UL_CONTACT_UPDATE + 2. Developer Guide 2.1. Available Functions 2.1.1. ul_register_domain(name) - 2.1.2. ul_insert_urecord(domain, aor, rec) - 2.1.3. ul_delete_urecord(domain, aor) + 2.1.2. ul_insert_urecord(domain, aor, rec, + is_replicated) + + 2.1.3. ul_delete_urecord(domain, aor, is_replicated) + 2.1.4. ul_get_urecord(domain, aor) 2.1.5. ul_lock_udomain(domain) 2.1.6. ul_unlock_udomain(domain) - 2.1.7. ul_release_urecord(record) - 2.1.8. ul_insert_ucontact(record, contact, expires, - q, callid, cseq, flags, cont, ua, sock) + 2.1.7. ul_release_urecord(record, is_replicated) + 2.1.8. ul_insert_ucontact(record, contact, + contact_info, contact, is_replicated) + + 2.1.9. ul_delete_ucontact (record, contact, + is_replicated) - 2.1.9. ul_delete_ucontact (record, contact) 2.1.10. ul_get_ucontact(record, contact) 2.1.11. ul_get_all_ucontacts (buf, len, flags) - 2.1.12. ul_update_ucontact(contact, expires, q, - callid, cseq, set, res, ua, sock) + 2.1.12. ul_update_ucontact(record, contact, + contact_info, is_replicated) 2.1.13. ul_bind_ursloc( api ) 2.1.14. ul_register_ulcb(type ,callback, param) @@ -118,14 +136,19 @@ Bogdan-Andrei Iancu 1.13. Set received_column parameter 1.14. Set socket_column parameter 1.15. Set path_column parameter - 1.16. Set use_domain parameter - 1.17. Set desc_time_order parameter - 1.18. Set timer_interval parameter - 1.19. Set db_url parameter - 1.20. Set db_mode parameter - 1.21. Set matching_mode parameter - 1.22. Set cseq_delay parameter - 1.23. Set hash_size parameter + 1.16. Set sip_instance_column parameter + 1.17. Set attr_column parameter + 1.18. Set use_domain parameter + 1.19. Set desc_time_order parameter + 1.20. Set timer_interval parameter + 1.21. Set db_url parameter + 1.22. Set db_mode parameter + 1.23. Set matching_mode parameter + 1.24. Set cseq_delay parameter + 1.25. Setting the accept_replicated_contacts parameter + 1.26. Setting the replicate_contacts_to parameter + 1.27. Setting the skip_replicated_db_ops parameter + 1.28. Set hash_size parameter Chapter 1. Admin Guide @@ -137,7 +160,7 @@ Chapter 1. Admin Guide 1.1.1. Contact matching - How the contacts are matched (dor same AOR - Address of Record) + How the contacts are matched (for same AOR - Address of Record) is an important aspect of the usrloc modules, especialy in the context of NAT traversal - this raise mre problems since contacts from different phones of same users may overlap (if @@ -151,18 +174,49 @@ Chapter 1. Admin Guide otherwise invalid). But as argumented above, this is not enough in NAT traversal context, so the OpenSIPS implementation of contact machting offers more algorithms: - * contact based only - it strict RFC 3261 compiancy - the + * contact based only - strict RFC 3261 compliancy - the contact is matched as string and extra checked via callid - and cseg (if callid is the same, it must have a higher cseq + and cseq (if callid is the same, it must have a higher cseq number, otherwise invalid). - * contact nad callid based - it an extension of the first - case - the contact and callid must matched as string; the - cseg must be higher than the previous one - so be careful - how you deal with REGISTER retransmissions in this case. - - How to control/select the contact maching algorithm, please see - the module parameter matching_mode at Section 1.3.21, - “matching_mode (integer)”. + * contact and callid based - an extension of the first case - + the contact and callid must match as strings; the cseq must + be higher than the previous one - so be careful how you + deal with REGISTER retransmissions in this case. + + For more details on how to control/select the contact matching + algorithm, please see the module parameter matching_mode at + Section 1.3.23, “matching_mode (integer)”. + +1.1.2. Contact replication + + Starting from OpenSIPS 1.11, the usrloc module offers the + possibility of performing real-time mirroring of the entire + in-memory user location information of one OpenSIPS instance to + one or more other instances. This module-to-module + communication is UDP-based, and it is done through the Binary + Interface. + + Advantages of replicating user-location data using this feature + instead of sending duplicated SIP REGISTER requests: + * no message parsing required + * reduced bandwith usage + * no additional script logic needed + + In order to control the DB operations performed by the + receiving instance(s), the skip_replicated_db_ops parameter can + be set. To summarise, the replication logic works together with + the DB modes as follows: + * 0 (No DB) - only in-memory data is replicated (no DB + operations are performed at all) + * 1 (Write through) and 2 (Write back) - default behaviour on + all instances, skip_replicated_db_ops can be set on the + receiving ones + * 3 (DB only) - data replication is OFF + + Configuring both receival and sending of usrloc replication + packets is trivial and can be done by using the + accept_replicated_contacts and replicate_contacts_to parameters + of the module. 1.2. Dependencies @@ -187,9 +241,7 @@ Chapter 1. Admin Guide module. WARNING: Setting INT flags is deprecated! Use quoted strings - instead! - - Default value is “NULL” (not set). + instead! Default value is “NULL” (not set). Example 1.1. Set nat_bflag parameter ... @@ -352,7 +404,30 @@ modparam("usrloc", "socket_column", "socket") modparam("usrloc", "path_column", "path") ... -1.3.16. use_domain (integer) +1.3.16. sip_instance_column (string) + + Name of column containing the SIP instance. + + Default value is “NULL”. + + Example 1.16. Set sip_instance_column parameter +... +modparam("usrloc", "sip_instance_column", "sip_instance") +... + +1.3.17. attr_column (string) + + Name of column containing additional registration-related + information. + + Default value is “NULL”. + + Example 1.17. Set attr_column parameter +... +modparam("usrloc", "attr_column", "attr") +... + +1.3.18. use_domain (integer) If the domain part of the user should be also saved and used for identifing the user (along with the username part). Useful @@ -360,12 +435,12 @@ modparam("usrloc", "path_column", "path") Default value is “0 (false)”. - Example 1.16. Set use_domain parameter + Example 1.18. Set use_domain parameter ... modparam("usrloc", "use_domain", 1) ... -1.3.17. desc_time_order (integer) +1.3.19. desc_time_order (integer) If the user's contacts should be kept timestamp ordered; otherwise the contact will be ordered based on q value. Non 0 @@ -373,12 +448,12 @@ modparam("usrloc", "use_domain", 1) Default value is “0 (false)”. - Example 1.17. Set desc_time_order parameter + Example 1.19. Set desc_time_order parameter ... modparam("usrloc", "desc_time_order", 1) ... -1.3.18. timer_interval (integer) +1.3.20. timer_interval (integer) Number of seconds between two timer runs. The module uses timer to delete expired contacts, synchronize with database and other @@ -386,25 +461,25 @@ modparam("usrloc", "desc_time_order", 1) Default value is 60. - Example 1.18. Set timer_interval parameter + Example 1.20. Set timer_interval parameter ... modparam("usrloc", "timer_interval", 120) ... -1.3.19. db_url (string) +1.3.21. db_url (string) URL of the database that should be used. Default value is “mysql://opensips:opensipsrw@localhost/opensips”. - Example 1.19. Set db_url parameter + Example 1.21. Set db_url parameter ... modparam("usrloc", "db_url", "dbdriver://username:password@dbhost/dbname ") ... -1.3.20. db_mode (integer) +1.3.22. db_mode (integer) The usrloc module can utilize database for persistent contact storage. If you use database, your contacts will survive @@ -448,12 +523,12 @@ Warning Default value is 0. - Example 1.20. Set db_mode parameter + Example 1.22. Set db_mode parameter ... modparam("usrloc", "db_mode", 2) ... -1.3.21. matching_mode (integer) +1.3.23. matching_mode (integer) What contact matching algorithm to be used. Refer to section Section 1.1.1, “Contact matching” for the description of the @@ -465,12 +540,12 @@ modparam("usrloc", "db_mode", 2) Default value is 0 (CONTACT_ONLY). - Example 1.21. Set matching_mode parameter + Example 1.23. Set matching_mode parameter ... modparam("usrloc", "matching_mode", 1) ... -1.3.22. cseq_delay (integer) +1.3.24. cseq_delay (integer) Delay (in seconds) for accepting as retransmissions register requests with same Call-ID and Cseq. The delay is calculated @@ -485,12 +560,66 @@ modparam("usrloc", "matching_mode", 1) Default value is “20 seconds”. - Example 1.22. Set cseq_delay parameter + Example 1.24. Set cseq_delay parameter ... modparam("usrloc", "cseq_delay", 5) ... -1.3.23. hash_size (integer) +1.3.25. accept_replicated_contacts (integer) + + Set this to 1 in order to accept and process user-location + related information received from other OpenSIPS instances + through the Binary Interface. + + Default value is “0” - Binary Interface listeners (if any) will + simply ignore any usrloc-related packets + + More details on the user location replication mechanism are + available in Section 1.1.2, “Contact replication” + + Example 1.25. Setting the accept_replicated_contacts parameter +... +modparam("usrloc", "accept_replicated_contacts", 1) +... + +1.3.26. replicate_contacts_to (string) + + Define a new OpenSIPS instance which will receive all the + user-location related information from this machine + (addresses-of-record, contacts), organized into specific events + (inserts, deletes or updates) + + This parameter may be set multiple times. It does not ignore + duplicate entries. + + Default value is "none" (no replication destinations) + + More details on the user location replication mechanism are + available in Section 1.1.2, “Contact replication” + + Example 1.26. Setting the replicate_contacts_to parameter +... +modparam("usrloc", "replicate_contacts_to", "192.168.2.182:5062") +... + +1.3.27. skip_replicated_db_ops (int) + + Prevent OpenSIPS from performing any DB-related contact + operations when events are received over the Binary Interface. + This is commonly used to prevent unneeded duplicate operations. + + Default value is "0" (upon receival of usrloc-related Binary + Interface events, DB queries may be freely performed) + + More details on the user location replication mechanism are + available in Section 1.1.2, “Contact replication” + + Example 1.27. Setting the skip_replicated_db_ops parameter +... +modparam("usrloc", "skip_replicated_db_ops", 1) +... + +1.3.28. hash_size (integer) The number of entries of the hash table used by usrloc to store the location records is 2^hash_size. For hash_size=4, the @@ -498,7 +627,7 @@ modparam("usrloc", "cseq_delay", 5) Default value is “9”. - Example 1.23. Set hash_size parameter + Example 1.28. Set hash_size parameter ... modparam("usrloc", "hash_size", 10) ... @@ -610,6 +739,70 @@ modparam("usrloc", "hash_size", 10) Total number of AOR existing in the USRLOC memory cache for all domains - can not be resetted. +1.7. Exported Events + +1.7.1. E_UL_AOR_INSERT + + This event is raised when a new AOR is inserted in the USRLOC + memory cache. + + Parameters: + * aor - The AOR of the inserted record. + +1.7.2. E_UL_AOR_DELETE + + This event is raised when a new AOR is deleted from the USRLOC + memory cache. + + Parameters: + * aor - The AOR of the deleted record. + +1.7.3. E_UL_CONTACT_INSERT + + This event is raised when a new contact is inserted in any of + the existing AOR's contact list. For each new contact, if its + AOR does not exist in the memory, then both the E_UL_AOR_CREATE + and E_UL_CONTACT_INSERT events will be raised. + + Parameters: + * address - The address of the inserted contact. + * callid - The Call-ID header of the registration message. + * received - IP, port and protocol the registration message + was received from. If these have the same value as the + contact's address (see the address parameter) then the + received parameter will be an empty string. + * cseq - The cseq number as an int value. + +1.7.4. E_UL_CONTACT_DELETE + + This event is raised when a contact is deleted from an existing + AOR's contact list. If the contact is the only one in the list + then both the E_UL_AOR_DELETE and E_UL_CONTACT_DELETE events + will be raised. + + Parameters: + * address - The address of the inserted contact. + * callid - The Call-ID header of the registration message. + * received - IP, port and protocol the registration message + was received from. If these have the same value as the + contact's address (see the address parameter) then the + received parameter will be an empty string. + * cseq - The cseq number as an int value. + +1.7.5. E_UL_CONTACT_UPDATE + + This event is raised when a contact's info is updated by + receiving another registration message. + + Parameters: + * address - The address of the inserted contact. + * callid - The Call-ID header of the registration message. + * received - IP, port and protocol the registration message + was received from. If these have the same value as the + contact's address (see the address parameter) then the + received parameter will be an empty string. + * cseq - The cseq number as an int value. + Chapter 2. Developer Guide 2.1. Available Functions @@ -630,7 +823,7 @@ Chapter 2. Developer Guide * const char* name - Name of the domain (also called table) to be registered. -2.1.2. ul_insert_urecord(domain, aor, rec) +2.1.2. ul_insert_urecord(domain, aor, rec, is_replicated) The function creates a new record structure and inserts it in the specified domain. The record is structure that contains all @@ -639,14 +832,15 @@ Chapter 2. Developer Guide Meaning of the parameters is as follows: * udomain_t* domain - Pointer to domain returned by ul_register_udomain. - * str* aor - Address of Record (aka username) of the new record (at this time the record will contain no contacts yet). - * urecord_t** rec - The newly created record structure. + * char is_replicated - Specifies whether this function will + be called from the context of a Binary Interface callback. + If uncertain, simply use 0. -2.1.3. ul_delete_urecord(domain, aor) +2.1.3. ul_delete_urecord(domain, aor, is_replicated) The function deletes all the contacts bound with the given Address Of Record. @@ -654,9 +848,11 @@ Chapter 2. Developer Guide Meaning of the parameters is as follows: * udomain_t* domain - Pointer to domain returned by ul_register_udomain. - * str* aor - Address of record (aka username) of the record, that should be deleted. + * char is_replicated - Specifies whether this function will + be called from the context of a Binary Interface callback. + If uncertain, simply use 0. 2.1.4. ul_get_urecord(domain, aor) @@ -688,16 +884,19 @@ Chapter 2. Developer Guide Meaning of the parameters is as follows: * udomain_t* domain - Domain to be unlocked. -2.1.7. ul_release_urecord(record) +2.1.7. ul_release_urecord(record, is_replicated) Do some sanity checks - if all contacts have been removed, delete the entire record structure. Meaning of the parameters is as follows: * urecord_t* record - Record to be released. + * char is_replicated - Specifies whether this function will + be called from the context of a Binary Interface callback. + If uncertain, simply use 0. -2.1.8. ul_insert_ucontact(record, contact, expires, q, callid, cseq, -flags, cont, ua, sock) +2.1.8. ul_insert_ucontact(record, contact, contact_info, contact, +is_replicated) The function inserts a new contact in the given record with specified parameters. @@ -706,20 +905,13 @@ flags, cont, ua, sock) * urecord_t* record - Record in which the contact should be inserted. * str* contact - Contact URI. - * time_t expires - Expires of the contact in absolute value. - * float q - q value of the contact. - * str* callid - Call-ID of the REGISTER message that - contained the contact. - * int cseq - CSeq of the REGISTER message that contained the - contact. - * unsigned int flags - Flags to be set. - * ucontact_t* cont - Pointer to newly created structure. - * str* ua - User-Agent of the REGISTER message that contained - the contact. - * struct socket_info *sock - socket on which the REGISTER - message was received on. - -2.1.9. ul_delete_ucontact (record, contact) + * ucontact_info_t* contact_info - Single structure containing + the new contact information + * char is_replicated - Specifies whether this function will + be called from the context of a Binary Interface callback. + If uncertain, simply use 0. + +2.1.9. ul_delete_ucontact (record, contact, is_replicated) The function deletes given contact from record. @@ -728,6 +920,9 @@ flags, cont, ua, sock) removed. * ucontact_t* contact - Contact to be deleted. + * char is_replicated - Specifies whether this function will + be called from the context of a Binary Interface callback. + If uncertain, simply use 0. 2.1.10. ul_get_ucontact(record, contact) @@ -761,25 +956,20 @@ flags, cont, ua, sock) * unsigned int flags - Flags that must be set. -2.1.12. ul_update_ucontact(contact, expires, q, callid, cseq, set, -res, ua, sock) +2.1.12. ul_update_ucontact(record, contact, contact_info, +is_replicated) The function updates contact with new values. Meaning of the parameters is as follows: + * urecord_t* record - Record in which the contact should be + inserted. * ucontact_t* contact - Contact URI. - * time_t expires - Expires of the contact in absolute value. - * float q - q value of the contact. - * str* callid - Call-ID of the REGISTER message that - contained the contact. - * int cseq - CSeq of the REGISTER message that contained the - contact. - * unsigned int set - OR value of flags to be set. - * unsigned int res - OR value of flags to be reset. - * str* ua - User-Agent of the REGISTER message that contained - the contact. - * struct socket_info *sock - socket on which the REGISTER - message was received on. + * ucontact_info_t* contact_info - Single structure containing + the new contact information + * char is_replicated - Specifies whether this function will + be called from the context of a Binary Interface callback. + If uncertain, simply use 0. 2.1.13. ul_bind_ursloc( api ) diff --git a/modules/usrloc/dlist.c b/modules/usrloc/dlist.c index 77a8a267509..344ed111fae 100644 --- a/modules/usrloc/dlist.c +++ b/modules/usrloc/dlist.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -45,6 +45,8 @@ #include "../../dprint.h" #include "../../ip_addr.h" #include "../../socket_info.h" +#include "../../parser/parse_rr.h" +#include "../../parser/parse_uri.h" #include "udomain.h" /* new_udomain, free_udomain */ #include "utime.h" #include "ul_mod.h" @@ -89,56 +91,66 @@ static inline int find_dlist(str* _n, dlist_t** _d) *_d = ptr; return 0; } - + ptr = ptr->next; } - + return 1; } - - -static inline int get_all_db_ucontacts(void *buf, int len, unsigned int flags, - unsigned int part_idx, unsigned int part_max) +static int get_all_db_ucontacts(void *buf, int len, unsigned int flags, + unsigned int part_idx, unsigned int part_max) { static char query_buf[512]; static str query_str; + static struct sip_uri puri; struct socket_info *sock; - unsigned int dbflags; - db_res_t* res = NULL; + struct proxy_l next_hop; + db_res_t *res = NULL; db_row_t *row; + db_val_t *val; dlist_t *dom; - char *p, *p1; - char now_s[25]; + str uri, host, flag_list; + int i, no_rows = 10; int now_len; + char now_s[25]; + char *p, *p1; int port, proto, p_len, p1_len; - str host; - int i; - void *cp; - int shortage, needed; + unsigned int dbflags; + int needed; + int shortage = 0; - cp = buf; shortage = 0; /* Reserve space for terminating 0000 */ - len -= sizeof(p_len); + len -= sizeof p_len; /* get the current time in DB format */ now_len = 25; - if (db_time2str( time(0), now_s, &now_len)!=0) { + if (db_time2str(time(NULL), now_s, &now_len) != 0) { LM_ERR("failed to print now time\n"); return -1; } - for (dom = root; dom!=NULL ; dom=dom->next) { - /* build query */ - i = snprintf( query_buf, sizeof(query_buf), "select %.*s, %.*s, %.*s," + LM_DBG("buf: %p. flags: %d\n", buf, flags); + + /* for each table */ + for (dom = root; dom; dom = dom->next) { + if (db_check_table_version(&ul_dbf, ul_dbh, dom->d->name, UL_TABLE_VERSION)) + goto error; + + /* read the destinations */ + if (ul_dbf.use_table(ul_dbh, dom->d->name) < 0) { + LM_ERR("cannot select table \"%.*s\"\n", dom->d->name->len, + dom->d->name->s); + goto error; + } + + i = snprintf(query_buf, sizeof query_buf, "select %.*s, %.*s, %.*s," #ifdef ORACLE_USRLOC - " %.*s, %.*s from %s where %.*s > %.*s and " - "bitand(%.*s, %d) = %d and mod(id, %u) = %u", + " %.*s, %.*s from %s where %.*s > %.*s and mod(id, %u) = %u", #else - " %.*s, %.*s from %s where %.*s > %.*s and %.*s & %d = %d and " - "id %% %u = %u", + " %.*s, %.*s from %s where %.*s > %.*s and id %% %u = %u", #endif received_col.len, received_col.s, contact_col.len, contact_col.s, @@ -148,112 +160,188 @@ static inline int get_all_db_ucontacts(void *buf, int len, unsigned int flags, dom->d->name->s, expires_col.len, expires_col.s, now_len, now_s, - cflags_col.len, cflags_col.s, - flags, flags, part_max, part_idx); - if ( i>=sizeof(query_buf) ) { + part_max, part_idx); + + LM_DBG("query: %.*s\n", (int)(sizeof query_buf), query_buf); + if (i >= sizeof query_buf) { LM_ERR("DB query too long\n"); - return -1; + goto error; } + query_str.s = query_buf; query_str.len = i; - if ( ul_dbf.raw_query( ul_dbh, &query_str, &res)<0 ) { + + if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) { + if (ul_dbf.raw_query(ul_dbh, &query_str, 0) < 0) { + LM_ERR("raw_query failed\n"); + goto error; + } + + no_rows = estimate_available_rows(20+128+20+128+64, 5); + if (no_rows == 0) + no_rows = 10; + + LM_DBG("fetching %d rows\n", no_rows); + + if (ul_dbf.fetch_result(ul_dbh, &res, no_rows) < 0) { + LM_ERR("Error fetching rows\n"); + goto error; + } + } else if (ul_dbf.raw_query(ul_dbh, &query_str, &res) < 0) { LM_ERR("raw_query failed\n"); - return -1; - } - if( RES_ROW_N(res)==0 ) { - ul_dbf.free_result(ul_dbh, res); - continue; + goto error; } - for(i = 0; i < RES_ROW_N(res); i++) { - row = RES_ROWS(res) + i; + do { + for (i = 0; i < RES_ROW_N(res); i++) { + row = RES_ROWS(res) + i; + val = ROW_VALUES(row) + 3; /* cflags */ + flag_list.s = (char *)VAL_STRING(val); + flag_list.len = strlen(flag_list.s); + + LM_DBG("contact cflags: '%.*s'\n", flag_list.len, flag_list.s); - /* received */ - p = (char*)VAL_STRING(ROW_VALUES(row)); - if ( VAL_NULL(ROW_VALUES(row)) || p==0 || p[0]==0 ) { - /* contact */ - p = (char*)VAL_STRING(ROW_VALUES(row)+1); - if (VAL_NULL(ROW_VALUES(row)+1) || p==0 || p[0]==0) { - LM_ERR("empty contact -> skipping\n"); + /* contact is not flagged at all */ + if (flags && (val->nul || !flag_list.s)) continue; + + dbflags = flag_list_to_bitmask(&flag_list, + FLAG_TYPE_BRANCH, FLAG_DELIM); + + LM_DBG("masks: param: %d --- %d :db\n", flags, dbflags); + + /* check if contact flags match the given bitmask */ + if ((dbflags & flags) != flags) + continue; + + /* received */ + p = (char*)VAL_STRING(ROW_VALUES(row)); + if (VAL_NULL(ROW_VALUES(row)) || !p || !p[0]) { + /* contact */ + p = (char*)VAL_STRING(ROW_VALUES(row) + 1); + if (VAL_NULL(ROW_VALUES(row) + 1) || !p || *p == '\0') { + LM_ERR("empty contact -> skipping\n"); + continue; + } } - } - p_len = strlen(p); - - /* path */ - p1 = (char*)VAL_STRING(ROW_VALUES(row)+4); - if (VAL_NULL(ROW_VALUES(row)+4) || p1==0 || p1[0]==0){ - p1 = NULL; - p1_len = 0; - } else { - p1_len = strlen(p1); - } + p_len = strlen(p); - needed = (int)(sizeof(p_len)+p_len+sizeof(sock)+sizeof(dbflags)+ - sizeof(p1_len)+p1_len); - if (len < needed) { - shortage += needed ; - continue; - } + /* path */ + p1 = (char*)VAL_STRING(ROW_VALUES(row) + 4); + if (VAL_NULL(ROW_VALUES(row) + 4) || !p1 || *p1 == '\0') { + p1 = NULL; + p1_len = 0; + } else + p1_len = strlen(p1); + + needed = (int)(p_len + sizeof p_len + p1_len + sizeof p1_len + + sizeof sock + sizeof dbflags + sizeof next_hop); - /* write received/contact */ - memcpy(cp, &p_len, sizeof(p_len)); - cp = (char*)cp + sizeof(p_len); - memcpy(cp, p, p_len); - cp = (char*)cp + p_len; - - /* sock */ - p = (char*)VAL_STRING(ROW_VALUES(row) + 2); - if (VAL_NULL(ROW_VALUES(row)+2) || p==0 || p[0]==0){ - sock = 0; - } else { - if (parse_phostport( p, strlen(p), &host.s, &host.len, - &port, &proto)!=0) { - LM_ERR("bad socket <%s>...ignoring\n", p); - sock = 0; + LM_DBG("len: %d, needed: %d\n", len, needed); + + if (len < needed) { + shortage += needed; + continue; + } + + /* determine and parse the URI of this contact's next hop */ + if (p1_len > 0) { + /* send to first URI in path */ + host.s = p1; + host.len = p1_len; + if (get_path_dst_uri(&host, &uri) < 0) { + LM_ERR("failed to get dst_uri for Path\n"); + continue; + } + if (parse_uri(uri.s, uri.len, &puri) < 0) { + LM_ERR("failed to parse path URI of next hop: '%*.s'\n", + p1_len, p1); + return -1; + } } else { - sock = grep_sock_info( &host, (unsigned short)port, proto); - if (sock==0) { - LM_DBG("non-local socket <%s>...ignoring\n", p); + if (parse_uri(p, p_len, &puri) < 0) { + LM_ERR("failed to parse contact of next hop: '%*.s'\n", + p_len, p); + return -1; } } - } - /* flags */ - dbflags = VAL_BITMAP(ROW_VALUES(row) + 3); + /* write received/contact */ + memcpy(buf, &p_len, sizeof p_len); + buf += sizeof p_len; + memcpy(buf, p, p_len); + buf += p_len; + + /* write path */ + memcpy(buf, &p1_len, sizeof p1_len); + buf += sizeof p1_len; + memcpy(buf, p1, p1_len); + buf += p1_len; + + /* sock */ + p = (char*)VAL_STRING(ROW_VALUES(row) + 2); + if (VAL_NULL(ROW_VALUES(row)+2) || !p || *p == '\0') { + sock = NULL; + } else { + if (parse_phostport(p, strlen(p), &host.s, &host.len, + &port, &proto) != 0) { + LM_ERR("bad socket <%s>...ignoring\n", p); + sock = NULL; + } else { + sock = grep_sock_info(&host, (unsigned short)port, proto); + if (!sock) + LM_DBG("non-local socket <%s>...ignoring\n", p); + } + } + + /* write sock and flags */ + memcpy(buf, &sock, sizeof sock); + buf += sizeof sock; + memcpy(buf, &dbflags, sizeof dbflags); + buf += sizeof dbflags; + + memset(&next_hop, 0, sizeof next_hop); + next_hop.port = puri.port_no; + next_hop.proto = puri.proto; + next_hop.name = puri.host; - /* write sock and flags */ - memcpy(cp, &sock, sizeof(sock)); - cp = (char*)cp + sizeof(sock); - memcpy(cp, &dbflags, sizeof(dbflags)); - cp = (char*)cp + sizeof(dbflags); + /* write the next hop */ + memcpy(buf, &next_hop, sizeof next_hop); + buf += sizeof next_hop; - /* write path */ - memcpy(cp, &p1_len, sizeof(p1_len)); - cp = (char*)cp + sizeof(p1_len); - memcpy(cp, p1, p1_len); - cp = (char*)cp + p1_len; + len -= needed; + } + + if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) { + if (ul_dbf.fetch_result(ul_dbh, &res, no_rows) < 0) { + LM_ERR("fetching rows (1)\n"); + goto error; + } + } else + break; - len -= needed; - } /* row cycle */ + } while (RES_ROW_N(res) > 0); ul_dbf.free_result(ul_dbh, res); - } /* domain cycle */ + } - /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */ + /* len < 0 is possible, if size of the buffer < sizeof c->c.len */ if (len >= 0) - memset(cp, 0, sizeof(p_len)); + memset(buf, 0, sizeof p_len); /* Shouldn't happen */ - if (shortage > 0 && len > shortage) { + if (shortage > 0 && len > shortage) abort(); - } shortage -= len; return shortage > 0 ? shortage : 0; -} +error: + if (res) + ul_dbf.free_result(ul_dbh, res); + return -1; +} static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags, @@ -294,10 +382,12 @@ static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags, iterator_is_valid(&it); iterator_next(&it) ) { - + dest = iterator_val(&it); - if( dest == NULL ) + if( dest == NULL ) { + unlock_ulslot(p->d, i); return -1; + } r =( urecord_t * ) *dest; @@ -311,45 +401,55 @@ static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags, */ if ((c->cflags & flags) != flags) continue; + if (c->received.s) { - needed = (int)(sizeof(c->received.len) - + c->received.len + sizeof(c->sock) - + sizeof(c->cflags) + sizeof(c->path.len) - + c->path.len); + needed = (int) + (sizeof(c->received.len) + c->received.len + + sizeof(c->path.len) + c->path.len + + sizeof(c->sock) + sizeof(c->cflags) + + sizeof(c->next_hop)); + if (len >= needed) { memcpy(cp,&c->received.len,sizeof(c->received.len)); cp = (char*)cp + sizeof(c->received.len); memcpy(cp, c->received.s, c->received.len); cp = (char*)cp + c->received.len; - memcpy(cp, &c->sock, sizeof(c->sock)); - cp = (char*)cp + sizeof(c->sock); - memcpy(cp, &c->cflags, sizeof(c->cflags)); - cp = (char*)cp + sizeof(c->cflags); memcpy(cp, &c->path.len, sizeof(c->path.len)); cp = (char*)cp + sizeof(c->path.len); memcpy(cp, c->path.s, c->path.len); cp = (char*)cp + c->path.len; + memcpy(cp, &c->sock, sizeof(c->sock)); + cp = (char*)cp + sizeof(c->sock); + memcpy(cp, &c->cflags, sizeof(c->cflags)); + cp = (char*)cp + sizeof(c->cflags); + memcpy(cp, &c->next_hop, sizeof(c->next_hop)); + cp = (char*)cp + sizeof(c->next_hop); len -= needed; } else { shortage += needed; } } else { - needed = (int)(sizeof(c->c.len) + c->c.len + - sizeof(c->sock) + sizeof(c->cflags) + - sizeof(c->path.len) + c->path.len); + needed = (int) + (sizeof(c->c.len) + c->c.len + + sizeof(c->path.len) + c->path.len + + sizeof(c->sock) + sizeof(c->cflags) + + sizeof(c->next_hop)); + if (len >= needed) { memcpy(cp, &c->c.len, sizeof(c->c.len)); cp = (char*)cp + sizeof(c->c.len); memcpy(cp, c->c.s, c->c.len); cp = (char*)cp + c->c.len; - memcpy(cp, &c->sock, sizeof(c->sock)); - cp = (char*)cp + sizeof(c->sock); - memcpy(cp, &c->cflags, sizeof(c->cflags)); - cp = (char*)cp + sizeof(c->cflags); memcpy(cp, &c->path.len, sizeof(c->path.len)); cp = (char*)cp + sizeof(c->path.len); memcpy(cp, c->path.s, c->path.len); cp = (char*)cp + c->path.len; + memcpy(cp, &c->sock, sizeof(c->sock)); + cp = (char*)cp + sizeof(c->sock); + memcpy(cp, &c->cflags, sizeof(c->cflags)); + cp = (char*)cp + sizeof(c->cflags); + memcpy(cp, &c->next_hop, sizeof(c->next_hop)); + cp = (char*)cp + sizeof(c->next_hop); len -= needed; } else { shortage += needed; @@ -475,7 +575,7 @@ int register_udomain(const char* _n, udomain_t** _d) *_d = d->d; return 0; } - + if (new_dlist(&s, &d) < 0) { LM_ERR("failed to create new domain\n"); return -1; @@ -506,7 +606,7 @@ int register_udomain(const char* _n, udomain_t** _d) d->next = root; root = d; - + *_d = d->d; return 0; @@ -543,7 +643,7 @@ void free_all_udomains(void) void print_all_udomains(FILE* _f) { dlist_t* ptr; - + ptr = root; fprintf(_f, "===Domain list===\n"); @@ -556,19 +656,19 @@ void print_all_udomains(FILE* _f) /*! \brief - * Loops through all domains summing up the number of users. + * Loops through all domains summing up the number of users. */ unsigned long get_number_of_users(void* foo) { int numberOfUsers = 0; dlist_t* current_dlist; - + current_dlist = root; while (current_dlist) { - numberOfUsers += get_stat_val(current_dlist->d->users); + numberOfUsers += get_stat_val(current_dlist->d->users); current_dlist = current_dlist->next; } diff --git a/modules/usrloc/dlist.h b/modules/usrloc/dlist.h index 9c58096e83f..1ca7f50d621 100644 --- a/modules/usrloc/dlist.h +++ b/modules/usrloc/dlist.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/usrloc/doc/usrloc_admin.xml b/modules/usrloc/doc/usrloc_admin.xml index 9d6d6a6ba53..8c7ca585cb6 100644 --- a/modules/usrloc/doc/usrloc_admin.xml +++ b/modules/usrloc/doc/usrloc_admin.xml @@ -1,55 +1,123 @@ - + &adminguide; - +
Overview - User location module. The module keeps a user location table and - provides access to the table to other modules. The module exports no + User location module. The module keeps a user location table and + provides access to the table to other modules. The module exports no functions that could be used directly from scripts.
Contact matching - How the contacts are matched (dor same AOR - Address of Record) is an + How the contacts are matched (for same AOR - Address of Record) is an important aspect of the usrloc modules, especialy in the context of NAT - traversal - this raise mre problems since contacts from different + traversal - this raise mre problems since contacts from different phones of same users may overlap (if behind NATs with same configuration) or the re-register contact of same phone may be seen as a new one (due different binding via NAT). - The SIP RFC 3261 publishes a matching algorithm based only on the + The SIP RFC 3261 publishes a matching algorithm based only on the contact string with callid and cseq number extra checking (if callid is the same, it must have a higher cseq number, otherwise invalid). - But as argumented above, this is not enough in NAT traversal context, + But as argumented above, this is not enough in NAT traversal context, so the &osips; implementation of contact machting offers more algorithms: - contact based only - it strict RFC 3261 - compiancy - the contact is matched as string and extra checked - via callid and cseg (if callid is the same, it must have a + contact based only - strict RFC 3261 + compliancy - the contact is matched as string and extra checked + via callid and cseq (if callid is the same, it must have a higher cseq number, otherwise invalid). - contact nad callid based - it an extension - of the first case - the contact and callid must matched as - string; the cseg must be higher than the previous one - so be - careful how you deal with REGISTER retransmissions in this + contact and callid based - an extension + of the first case - the contact and callid must match as + strings; the cseq must be higher than the previous one - so be + careful how you deal with REGISTER retransmissions in this case. - How to control/select the contact maching algorithm, please see the - module parameter matching_mode at . + For more details on how to control/select the contact matching algorithm, + please see the module parameter matching_mode at + . + +
+ +
+ Contact replication + + Starting from &osips; 1.11, the usrloc module + offers the possibility of performing real-time mirroring of the entire + in-memory user location information of one &osips; instance to one or more + other instances. This module-to-module communication is UDP-based, and + it is done through the Binary Interface. + + + Advantages of replicating user-location data using this feature + instead of sending duplicated SIP REGISTER requests: + + + + no message parsing required + + + + + reduced bandwith usage + + + + + no additional script logic needed + + + + + + In order to control the DB operations performed by the receiving instance(s), + the + parameter can be set. To summarise, the replication logic works together + with the DB modes as follows: + + + + 0 (No DB) - only in-memory + data is replicated (no DB operations are performed at all) + + + + + 1 (Write through) and 2 (Write back) + - default behaviour on all instances, can be set + on the receiving ones + + + + + 3 (DB only) - + data replication is OFF + + + + + + Configuring both receival and sending of usrloc replication packets is + trivial and can be done by using the + and + parameters of the + module.
@@ -72,7 +140,7 @@
External Libraries or Applications - The following libraries or applications must be installed before + The following libraries or applications must be installed before running &osips; with this module loaded: @@ -89,15 +157,13 @@
<varname>nat_bflag</varname> (string/integer) - The name of the branch flag to be used as NAT marker (if the contact - is or not natted). This is a branch flag and it will be imported and + The name of the branch flag to be used as NAT marker (if the contact + is or not natted). This is a branch flag and it will be imported and used by all other modules depending of usrloc module. - WARNING: Setting INT flags is deprecated! Use quoted strings instead! - Default value is NULL (not set). @@ -394,11 +460,51 @@ modparam("usrloc", "path_column", "path")
+
+ <varname>sip_instance_column</varname> (string) + + Name of column containing the SIP instance. + + + + Default value is NULL. + + + + Set <varname>sip_instance_column</varname> parameter + +... +modparam("usrloc", "sip_instance_column", "sip_instance") +... + + +
+ +
+ <varname>attr_column</varname> (string) + + Name of column containing additional registration-related information. + + + + Default value is NULL. + + + + Set <varname>attr_column</varname> parameter + +... +modparam("usrloc", "attr_column", "attr") +... + + +
+
<varname>use_domain</varname> (integer) If the domain part of the user should be also saved and used for - identifing the user (along with the username part). Useful in + identifing the user (along with the username part). Useful in multi domain scenarios. Non 0 value means true. @@ -441,8 +547,8 @@ modparam("usrloc", "desc_time_order", 1)
<varname>timer_interval</varname> (integer) - Number of seconds between two timer runs. The module uses timer to - delete expired contacts, synchronize with database and other tasks, + Number of seconds between two timer runs. The module uses timer to + delete expired contacts, synchronize with database and other tasks, that need to be run periodically. @@ -484,60 +590,60 @@ modparam("usrloc", "db_url", "&exampledb;") <varname>db_mode</varname> (integer) The usrloc module can utilize database for persistent contact storage. - If you use database, your contacts will survive machine restarts or - SW crashes. The disadvantage is that accessing database can be very - time consuming. Therefore, usrloc module implements four database + If you use database, your contacts will survive machine restarts or + SW crashes. The disadvantage is that accessing database can be very + time consuming. Therefore, usrloc module implements four database accessing modes: - 0 - This disables database completely. Only memory will be used. - Contacts will not survive restart. Use this value if you need a - really fast usrloc and contact persistence is not necessary or + 0 - This disables database completely. Only memory will be used. + Contacts will not survive restart. Use this value if you need a + really fast usrloc and contact persistence is not necessary or is provided by other means. - 1 - Write-Through scheme. All changes to usrloc are immediately - reflected in database too. This is very slow, but very reliable. - Use this scheme if speed is not your priority but need to make - sure that no registered contacts will be lost during crash or + 1 - Write-Through scheme. All changes to usrloc are immediately + reflected in database too. This is very slow, but very reliable. + Use this scheme if speed is not your priority but need to make + sure that no registered contacts will be lost during crash or reboot. - 2 - Write-Back scheme. This is a combination of previous two - schemes. All changes are made to memory and database - synchronization is done in the timer. The timer deletes all - expired contacts and flushes all modified or new contacts to - database. Use this scheme if you encounter high-load peaks - and want them to process as fast as possible. The mode will - not help at all if the load is high all the time. Also, latency - of this mode is much lower than latency of mode 1, but slightly + 2 - Write-Back scheme. This is a combination of previous two + schemes. All changes are made to memory and database + synchronization is done in the timer. The timer deletes all + expired contacts and flushes all modified or new contacts to + database. Use this scheme if you encounter high-load peaks + and want them to process as fast as possible. The mode will + not help at all if the load is high all the time. Also, latency + of this mode is much lower than latency of mode 1, but slightly higher than latency of mode 0. 3 - DB-Only scheme. No memory cache is kept, all operations being - directly performed with the database. The timer deletes all + directly performed with the database. The timer deletes all expired contacts from database - cleans after clients that didn't un-register or re-register. The mode is useful if you configure more servers sharing the same DB without any replication at SIP level. The mode may be slower due the high number of DB operation. For example NAT pinging is a killer since during each ping cycle - all nated contact are loaded from the DB; The lack of memory + all nated contact are loaded from the DB; The lack of memory caching also disable the statistics exports. - In case of crash or restart contacts that are in memory only and - haven't been flushed yet will get lost. If you want minimize the + In case of crash or restart contacts that are in memory only and + haven't been flushed yet will get lost. If you want minimize the risk, use shorter timer interval. @@ -559,8 +665,8 @@ modparam("usrloc", "db_mode", 2)
<varname>matching_mode</varname> (integer) - What contact matching algorithm to be used. Refer to section - for the description of the + What contact matching algorithm to be used. Refer to section + for the description of the algorithms. @@ -573,7 +679,7 @@ modparam("usrloc", "db_mode", 2) - 1 - CONTACT and CALLID based + 1 - CONTACT and CALLID based matching algorithm. @@ -597,7 +703,7 @@ modparam("usrloc", "matching_mode", 1) <varname>cseq_delay</varname> (integer) Delay (in seconds) for accepting as retransmissions register requests - with same Call-ID and Cseq. The delay is calculated starting from the + with same Call-ID and Cseq. The delay is calculated starting from the receiving time of the first register with that Call-ID and Cseq. @@ -623,6 +729,89 @@ modparam("usrloc", "cseq_delay", 5)
+
+ <varname>accept_replicated_contacts</varname> (integer) + + Set this to 1 in order to accept and process user-location related + information received from other &osips; instances through the + Binary Interface. + + + Default value is 0 - Binary Interface listeners (if any) + will simply ignore any usrloc-related packets + + + More details on the user location replication mechanism are available in + + + Setting the <varname>accept_replicated_contacts</varname> + parameter + +... +modparam("usrloc", "accept_replicated_contacts", 1) +... + + +
+ +
+ <varname>replicate_contacts_to</varname> (string) + + Define a new &osips; instance which will receive all the user-location + related information from this machine + (addresses-of-record, contacts), + organized into specific events (inserts, deletes or updates) + + + This parameter may be set multiple times. It does + not ignore duplicate entries. + + + Default value is "none" (no replication destinations) + + + More details on the user location replication mechanism are available in + + + Setting the <varname>replicate_contacts_to</varname> + parameter + +... +modparam("usrloc", "replicate_contacts_to", "192.168.2.182:5062") +... + + +
+ +
+ <varname>skip_replicated_db_ops</varname> (int) + + Prevent &osips; from performing any DB-related contact operations + when events are received over the Binary Interface. + This is commonly used to prevent unneeded duplicate operations. + + + Default value is "0" (upon receival of usrloc-related Binary Interface + events, DB queries may be freely performed) + + + More details on the user location replication mechanism are available + in + + + Setting the <varname>skip_replicated_db_ops</varname> + parameter + +... +modparam("usrloc", "skip_replicated_db_ops", 1) +... + + +
+
<varname>hash_size</varname> (integer) @@ -761,11 +950,11 @@ modparam("usrloc", "hash_size", 10) backword compatibility) - flags - internal USRLOC flags of the + flags - internal USRLOC flags of the contact - cflags - per branch flags of the + cflags - per branch flags of the contact @@ -836,15 +1025,15 @@ modparam("usrloc", "hash_size", 10) users Number of AOR existing in the USRLOC memory cache for that domain - - can not be resetted; this statistic will be register for each + - can not be resetted; this statistic will be register for each used domain (Ex: location).
contacts - Number of contacts existing in the USRLOC memory cache for that - domain - can not be resetted; this statistic will be register for + Number of contacts existing in the USRLOC memory cache for that + domain - can not be resetted; this statistic will be register for each used domain (Ex: location).
@@ -852,7 +1041,7 @@ modparam("usrloc", "hash_size", 10) expires Total number of expired contacts for that domain - can be resetted; - this statistic will be register for each used domain + this statistic will be register for each used domain (Ex: location).
@@ -866,5 +1055,122 @@ modparam("usrloc", "hash_size", 10)
+
+ Exported Events +
+ + <function moreinfo="none">E_UL_AOR_INSERT</function> + + + This event is raised when a new AOR is inserted in the USRLOC + memory cache. + + Parameters: + + + aor - The AOR of the inserted record. + + +
+
+ + <function moreinfo="none">E_UL_AOR_DELETE</function> + + + This event is raised when a new AOR is deleted from the USRLOC + memory cache. + + Parameters: + + + aor - The AOR of the deleted record. + + +
+
+ + <function moreinfo="none">E_UL_CONTACT_INSERT</function> + + + This event is raised when a new contact is inserted in any of the + existing AOR's contact list. For each new contact, if its AOR does + not exist in the memory, then both the E_UL_AOR_CREATE and + E_UL_CONTACT_INSERT events will be raised. + + Parameters: + + + address - The address of the inserted contact. + + + callid - The Call-ID header of the registration message. + + + received - IP, port and protocol the registration + message was received from. If these have the same value as the + contact's address (see the address parameter) then the received + parameter will be an empty string. + + + cseq - The cseq number as an int value. + + +
+
+ + <function moreinfo="none">E_UL_CONTACT_DELETE</function> + + + This event is raised when a contact is deleted from an + existing AOR's contact list. If the contact is the only one in + the list then both the E_UL_AOR_DELETE and + E_UL_CONTACT_DELETE events will be raised. + + Parameters: + + + address - The address of the inserted contact. + + + callid - The Call-ID header of the registration message. + + + received - IP, port and protocol the registration + message was received from. If these have the same value as the + contact's address (see the address parameter) then the received + parameter will be an empty string. + + + cseq - The cseq number as an int value. + + +
+
+ + <function moreinfo="none">E_UL_CONTACT_UPDATE</function> + + + This event is raised when a contact's info is updated by receiving + another registration message. + + Parameters: + + + address - The address of the inserted contact. + + + callid - The Call-ID header of the registration message. + + + received - IP, port and protocol the registration + message was received from. If these have the same value as the + contact's address (see the address parameter) then the received + parameter will be an empty string. + + + cseq - The cseq number as an int value. + + +
+
- diff --git a/modules/usrloc/doc/usrloc_devel.xml b/modules/usrloc/doc/usrloc_devel.xml index b316ec825a9..26cf7dbcb1d 100644 --- a/modules/usrloc/doc/usrloc_devel.xml +++ b/modules/usrloc/doc/usrloc_devel.xml @@ -31,7 +31,8 @@
- <function moreinfo="none">ul_insert_urecord(domain, aor, rec)</function> + <function moreinfo="none"> + ul_insert_urecord(domain, aor, rec, is_replicated)</function> The function creates a new record structure and inserts it in the @@ -45,28 +46,31 @@ returned by ul_register_udomain. - - str* aor - Address of Record (aka username) of the new record (at this time the record will contain no contacts yet). - - urecord_t** rec - The newly created record structure. + + char is_replicated - Specifies whether + this function will be called from the context of a Binary Interface + callback. If uncertain, simply use 0. + +
- <function moreinfo="none">ul_delete_urecord(domain, aor)</function> + <function moreinfo="none"> + ul_delete_urecord(domain, aor, is_replicated)</function> The function deletes all the contacts bound with the given Address @@ -79,13 +83,17 @@ returned by ul_register_udomain. - - str* aor - Address of record (aka username) of the record, that should be deleted. + + char is_replicated - Specifies whether + this function will be called from the context of a Binary Interface + callback. If uncertain, simply use 0. + +
@@ -152,7 +160,8 @@
- <function moreinfo="none">ul_release_urecord(record)</function> + <function moreinfo="none"> + ul_release_urecord(record, is_replicated)</function> Do some sanity checks - if all contacts have been removed, delete @@ -165,13 +174,19 @@ released. + + char is_replicated - Specifies whether + this function will be called from the context of a Binary Interface + callback. If uncertain, simply use 0. + +
<function moreinfo="none">ul_insert_ucontact(record, contact, - expires, q, callid, cseq, flags, cont, ua, sock)</function> + contact_info, contact, is_replicated)</function> The function inserts a new contact in the given record with @@ -189,41 +204,14 @@ - time_t expires - Expires of the - contact in absolute value. - - - - float q - q value of the contact. - - - - str* callid - Call-ID of the REGISTER - message that contained the contact. + ucontact_info_t* contact_info - + Single structure containing the new contact information - int cseq - CSeq of the REGISTER - message that contained the contact. - - - - unsigned int flags - Flags to be set. - - - - ucontact_t* cont - Pointer to newly - created structure. - - - - str* ua - User-Agent of the REGISTER - message that contained the contact. - - - - struct socket_info *sock - socket on - which the REGISTER message was received on. + char is_replicated - Specifies whether + this function will be called from the context of a Binary Interface + callback. If uncertain, simply use 0. @@ -232,7 +220,7 @@
<function moreinfo="none">ul_delete_ucontact - (record, contact)</function> + (record, contact, is_replicated)</function> The function deletes given contact from record. @@ -251,6 +239,12 @@ deleted. + + char is_replicated - Specifies whether + this function will be called from the context of a Binary Interface + callback. If uncertain, simply use 0. + +
@@ -324,8 +318,8 @@
- <function moreinfo="none">ul_update_ucontact(contact, expires, q, - callid, cseq, set, res, ua, sock)</function> + <function moreinfo="none">ul_update_ucontact(record, contact, + contact_info, is_replicated)</function> The function updates contact with new values. @@ -333,48 +327,23 @@ Meaning of the parameters is as follows: - ucontact_t* contact - Contact &uri;. - - - - time_t expires - Expires of the - contact in absolute value. - - - - float q - q value of the contact. - - - - str* callid - Call-ID of the REGISTER - message that contained the contact. - - - - int cseq - CSeq of the REGISTER message - that contained the contact. - - - - - unsigned int set - OR value of flags to - be set. + urecord_t* record - Record in which + the contact should be inserted. - - unsigned int res - OR value of flags to be - reset. + ucontact_t* contact - Contact &uri;. - str* ua - User-Agent of the REGISTER - message that contained the contact. + ucontact_info_t* contact_info - + Single structure containing the new contact information - struct socket_info *sock - socket on - which the REGISTER message was received on. + char is_replicated - Specifies whether + this function will be called from the context of a Binary Interface + callback. If uncertain, simply use 0. diff --git a/modules/usrloc/hslot.c b/modules/usrloc/hslot.c index b110b977cc4..86501ff7f9b 100644 --- a/modules/usrloc/hslot.c +++ b/modules/usrloc/hslot.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Hash table collision slot related functions * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -153,8 +153,8 @@ int slot_add(hslot_t* _s, struct urecord* _r) LM_ERR("inserting into map\n"); return -1; } - - + + *dest = _r; _r->slot = _s; @@ -170,5 +170,5 @@ void slot_rem(hslot_t* _s, struct urecord* _r) { map_remove( _s->records, _r->aor ); - _r->slot = 0; + _r->slot = 0; } diff --git a/modules/usrloc/hslot.h b/modules/usrloc/hslot.h index 3d1b3cab5ca..c9b0d81227b 100644 --- a/modules/usrloc/hslot.h +++ b/modules/usrloc/hslot.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Usrloc hash table collision slot * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -45,7 +45,7 @@ struct urecord; typedef struct hslot { map_t records; - + struct udomain* d; /*!< Domain we belong to */ #ifdef GEN_LOCK_T_PREFERED gen_lock_t *lock; /*!< Lock for hash entry - fastlock */ diff --git a/modules/usrloc/ucontact.c b/modules/usrloc/ucontact.c index ea400d2c983..aa489e7bc69 100644 --- a/modules/usrloc/ucontact.c +++ b/modules/usrloc/ucontact.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Usrloc contact structure * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -35,6 +35,8 @@ #include "ucontact.h" #include /* memcpy */ +#include "../../parser/parse_uri.h" +#include "../../parser/parse_rr.h" #include "../../mem/shm_mem.h" #include "../../ut.h" #include "../../ip_addr.h" @@ -46,6 +48,47 @@ #include "ul_callback.h" #include "urecord.h" #include "ucontact.h" +#include "ureplication.h" +#include "udomain.h" + +extern event_id_t ei_c_update_id; + +/* + * Determines the IP address of the next hop on the way to given contact based + * on following URIs: path URI -> received URI -> contact URI + * + * @contact: input/output param; results are written in contact->next_hop + */ +static int compute_next_hop(ucontact_t *contact) +{ + str uri; + struct sip_uri puri; + + if (contact->path.s && contact->path.len > 0) { + if (get_path_dst_uri(&contact->path, &uri) < 0) { + LM_ERR("failed to get dst_uri for Path '%*.s'\n", + contact->path.len, contact->path.s); + return -1; + } + + } else if (contact->received.s && contact->received.len > 0) + uri = contact->received; + else if (contact->c.s && contact->c.len > 0) + uri = contact->c; + + if (parse_uri(uri.s, uri.len, &puri) < 0) { + LM_ERR("failed to parse URI of next hop: '%*.s'\n", uri.len, uri.s); + return -1; + } + + memset(&contact->next_hop, 0, sizeof contact->next_hop); + + contact->next_hop.port = puri.port_no; + contact->next_hop.proto = puri.proto; + contact->next_hop.name = puri.host; + + return 0; +} /*! \brief @@ -58,24 +101,28 @@ ucontact_t* new_ucontact(str* _dom, str* _aor, str* _contact, ucontact_info_t* _ c = (ucontact_t*)shm_malloc(sizeof(ucontact_t)); if (!c) { LM_ERR("no more shm memory\n"); - return 0; + return NULL; } memset(c, 0, sizeof(ucontact_t)); - if (shm_str_dup( &c->c, _contact) < 0) goto error; - if (shm_str_dup( &c->callid, _ci->callid) < 0) goto error; - if (shm_str_dup( &c->user_agent, _ci->user_agent) < 0) goto error; + if (shm_str_dup( &c->c, _contact) < 0) goto mem_error; + if (shm_str_dup( &c->callid, _ci->callid) < 0) goto mem_error; + if (shm_str_dup( &c->user_agent, _ci->user_agent) < 0) goto mem_error; if (_ci->received.s && _ci->received.len) { - if (shm_str_dup( &c->received, &_ci->received) < 0) goto error; + if (shm_str_dup( &c->received, &_ci->received) < 0) goto mem_error; } if (_ci->instance.s && _ci->instance.len) { - if (shm_str_dup( &c->instance, &_ci->instance) < 0) goto error; + if (shm_str_dup( &c->instance, &_ci->instance) < 0) goto mem_error; } if (_ci->path && _ci->path->len) { - if (shm_str_dup( &c->path, _ci->path) < 0) goto error; + if (shm_str_dup( &c->path, _ci->path) < 0) goto mem_error; + } + + if (_ci->attr && _ci->attr->len) { + if (shm_str_dup( &c->attr, _ci->attr) < 0) goto mem_error; } c->domain = _dom; @@ -90,17 +137,26 @@ ucontact_t* new_ucontact(str* _dom, str* _aor, str* _contact, ucontact_info_t* _ c->methods = _ci->methods; c->last_modified = _ci->last_modified; + if (compute_next_hop(c) != 0) { + LM_ERR("failed to resolve next hop\n"); + goto out_free; + } + return c; -error: + +mem_error: LM_ERR("no more shm memory\n"); + +out_free: if (c->path.s) shm_free(c->path.s); if (c->received.s) shm_free(c->received.s); if (c->user_agent.s) shm_free(c->user_agent.s); if (c->callid.s) shm_free(c->callid.s); if (c->c.s) shm_free(c->c.s); if (c->instance.s) shm_free(c->instance.s); + if (c->attr.s) shm_free(c->attr.s); shm_free(c); - return 0; + return NULL; } @@ -117,6 +173,7 @@ void free_ucontact(ucontact_t* _c) if (_c->user_agent.s) shm_free(_c->user_agent.s); if (_c->callid.s) shm_free(_c->callid.s); if (_c->c.s) shm_free(_c->c.s); + if (_c->attr.s) shm_free(_c->attr.s); shm_free( _c ); } @@ -161,6 +218,7 @@ void print_ucontact(FILE* _f, ucontact_t* _c) _c->path.len, ZSW(_c->path.s)); fprintf(_f, "State : %s\n", st); fprintf(_f, "Flags : %u\n", _c->flags); + fprintf(_f, "Attrs : '%.*s'\n", _c->attr.len, _c->attr.s); if (_c->sock) { fprintf(_f, "Sock : %.*s (as %.*s )(%p)\n", _c->sock->sock_str.len,_c->sock->sock_str.s, @@ -200,7 +258,7 @@ int mem_update_ucontact(ucontact_t* _c, ucontact_info_t* _ci) char* ptr; - /* No need to update Callid as it is constant + /* No need to update Callid as it is constant * per ucontact (set at insert time) -bogdan */ update_str( &_c->user_agent, _ci->user_agent); @@ -212,7 +270,7 @@ int mem_update_ucontact(ucontact_t* _c, ucontact_info_t* _ci) _c->received.s = 0; _c->received.len = 0; } - + if (_ci->path) { update_str( &_c->path, _ci->path); } else { @@ -221,6 +279,14 @@ int mem_update_ucontact(ucontact_t* _c, ucontact_info_t* _ci) _c->path.len = 0; } + if (_ci->attr && _ci->attr->s && _ci->attr->len) { + update_str( &_c->attr, _ci->attr); + } else { + if (_c->attr.s) shm_free(_c->attr.s); + _c->attr.s = 0; + _c->attr.len = 0; + } + _c->sock = _ci->sock; _c->expires = _ci->expires; _c->q = _ci->q; @@ -230,6 +296,13 @@ int mem_update_ucontact(ucontact_t* _c, ucontact_info_t* _ci) _c->flags = _ci->flags; _c->cflags = _ci->cflags; + if (compute_next_hop(_c) != 0) + LM_ERR("failed to resolve next hop. keeping old one - '%.*s'\n", + _c->next_hop.name.len, _c->next_hop.name.s); + + ul_raise_contact_event(ei_c_update_id, &_c->c, &_c->callid, + &_c->received, _c->cseq); + return 0; } @@ -251,9 +324,9 @@ void st_update_ucontact(ucontact_t* _c) break; case CS_SYNC: - /* For db mode 1 & 2 a modified contact needs to be - * updated also in the database, so transit into - * CS_DIRTY and let the timer to do the update + /* For db mode 1 & 2 a modified contact needs to be + * updated also in the database, so transit into + * CS_DIRTY and let the timer to do the update * again. For db mode 1 we try to update right * now and if fails, let the timer to do the job */ @@ -289,10 +362,10 @@ int st_delete_ucontact(ucontact_t* _c) case CS_SYNC: case CS_DIRTY: /* Contact is in the database, - * we cannot remove it from the memory + * we cannot remove it from the memory * directly, but we can set expires to zero - * and the timer will take care of deleting - * the contact from the memory as well as + * and the timer will take care of deleting + * the contact from the memory as well as * from the database */ if (db_mode == WRITE_BACK) { @@ -314,7 +387,7 @@ int st_delete_ucontact(ucontact_t* _c) /*! \brief * Called when the timer is about to delete - * an expired contact. + * an expired contact. * \return 1 if the contact should be removed from * the database and 0 otherwise */ @@ -387,8 +460,8 @@ int db_insert_ucontact(ucontact_t* _c,query_list_t **ins_list, int update) static db_ps_t myI_ps = NULL; static db_ps_t myR_ps = NULL; char* dom; - db_key_t keys[16]; - db_val_t vals[16]; + db_key_t keys[17]; + db_val_t vals[17]; if (_c->flags & FL_MEM) { return 0; @@ -409,7 +482,8 @@ int db_insert_ucontact(ucontact_t* _c,query_list_t **ins_list, int update) keys[12] = &methods_col; keys[13] = &last_mod_col; keys[14] = &sip_instance_col; - keys[15] = &domain_col; + keys[15] = &attr_col; + keys[16] = &domain_col; vals[0].type = DB_STR; vals[0].nul = 0; @@ -418,7 +492,7 @@ int db_insert_ucontact(ucontact_t* _c,query_list_t **ins_list, int update) vals[1].type = DB_STR; vals[1].nul = 0; - vals[1].val.str_val.s = _c->c.s; + vals[1].val.str_val.s = _c->c.s; vals[1].val.str_val.len = _c->c.len; vals[2].type = DB_DATETIME; @@ -442,9 +516,9 @@ int db_insert_ucontact(ucontact_t* _c,query_list_t **ins_list, int update) vals[6].nul = 0; vals[6].val.bitmap_val = _c->flags; - vals[7].type = DB_INT; + vals[7].type = DB_STR; vals[7].nul = 0; - vals[7].val.bitmap_val = _c->cflags; + vals[7].val.str_val = bitmask_to_flag_list(FLAG_TYPE_BRANCH, _c->cflags); vals[8].type = DB_STR; vals[8].nul = 0; @@ -459,7 +533,7 @@ int db_insert_ucontact(ucontact_t* _c,query_list_t **ins_list, int update) vals[9].val.str_val.s = _c->received.s; vals[9].val.str_val.len = _c->received.len; } - + vals[10].type = DB_STR; if (_c->path.s == 0) { vals[10].nul = 1; @@ -499,46 +573,52 @@ int db_insert_ucontact(ucontact_t* _c,query_list_t **ins_list, int update) vals[14].val.str_val.len = _c->instance.len; } + vals[15].type = DB_STR; + if (_c->attr.s == 0) { + vals[15].nul = 1; + } else { + vals[15].nul = 0; + vals[15].val.str_val.s = _c->attr.s; + vals[15].val.str_val.len = _c->attr.len; + } if (use_domain) { - vals[15].type = DB_STR; - vals[15].nul = 0; + vals[16].type = DB_STR; + vals[16].nul = 0; dom = q_memchr(_c->aor->s, '@', _c->aor->len); if (dom==0) { vals[0].val.str_val.len = 0; - vals[15].val.str_val = *_c->aor; + vals[16].val.str_val = *_c->aor; } else { vals[0].val.str_val.len = dom - _c->aor->s; - vals[15].val.str_val.s = dom + 1; - vals[15].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1; + vals[16].val.str_val.s = dom + 1; + vals[16].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1; } } - if (ul_dbf.use_table(ul_dbh, _c->domain) < 0) { LM_ERR("sql use_table failed\n"); return -1; } - if ( !update ) { /* do simple insert */ CON_PS_REFERENCE(ul_dbh) = &myI_ps; if (ins_list) { if (con_set_inslist(&ul_dbf,ul_dbh,ins_list,keys, - (use_domain) ? (16) : (15)) < 0 ) + (use_domain) ? (17) : (16)) < 0 ) CON_RESET_INSLIST(ul_dbh); } - if (ul_dbf.insert(ul_dbh, keys, vals, (use_domain) ? (16) : (15)) < 0) { + if (ul_dbf.insert(ul_dbh, keys, vals, (use_domain) ? (17) : (16)) < 0) { LM_ERR("inserting contact in db failed\n"); return -1; } } else { /* do insert-update / replace */ CON_PS_REFERENCE(ul_dbh) = &myR_ps; - if (ul_dbf.insert_update(ul_dbh, keys, vals, (use_domain) ? (16) : (15)) < 0) { + if (ul_dbf.insert_update(ul_dbh, keys, vals, (use_domain) ? (17) : (16)) < 0) { LM_ERR("inserting contact in db failed\n"); return -1; } @@ -558,8 +638,8 @@ int db_update_ucontact(ucontact_t* _c) db_key_t keys1[4]; db_val_t vals1[4]; - db_key_t keys2[11]; - db_val_t vals2[11]; + db_key_t keys2[12]; + db_val_t vals2[12]; if (_c->flags & FL_MEM) { return 0; @@ -580,6 +660,7 @@ int db_update_ucontact(ucontact_t* _c) keys2[8] = &sock_col; keys2[9] = &methods_col; keys2[10] = &last_mod_col; + keys2[11] = &attr_col; vals1[0].type = DB_STR; vals1[0].nul = 0; @@ -609,9 +690,9 @@ int db_update_ucontact(ucontact_t* _c) vals2[3].nul = 0; vals2[3].val.bitmap_val = _c->flags; - vals2[4].type = DB_BITMAP; + vals2[4].type = DB_STR; vals2[4].nul = 0; - vals2[4].val.bitmap_val = _c->cflags; + vals2[4].val.str_val = bitmask_to_flag_list(FLAG_TYPE_BRANCH, _c->cflags); vals2[5].type = DB_STR; vals2[5].nul = 0; @@ -624,7 +705,7 @@ int db_update_ucontact(ucontact_t* _c) vals2[6].nul = 0; vals2[6].val.str_val = _c->received; } - + vals2[7].type = DB_STR; if (_c->path.s == 0) { vals2[7].nul = 1; @@ -654,6 +735,14 @@ int db_update_ucontact(ucontact_t* _c) vals2[10].nul = 0; vals2[10].val.time_val = _c->last_modified; + vals2[11].type = DB_STR; + if (_c->attr.s == 0) { + vals2[11].nul = 1; + } else { + vals2[11].nul = 0; + vals2[11].val.str_val = _c->attr; + } + if (use_domain) { vals1[3].type = DB_STR; vals1[3].nul = 0; @@ -675,8 +764,8 @@ int db_update_ucontact(ucontact_t* _c) CON_PS_REFERENCE(ul_dbh) = &my_ps; - if (ul_dbf.update(ul_dbh, keys1, 0, vals1, keys2, vals2, - (use_domain) ? (4) : (3), 11) < 0) { + if (ul_dbf.update(ul_dbh, keys1, 0, vals1, keys2, vals2, + (use_domain) ? (4) : (3), 12) < 0) { LM_ERR("updating database failed\n"); return -1; } @@ -811,7 +900,8 @@ static inline void update_contact_pos(struct urecord* _r, ucontact_t* _c) /*! \brief * Update ucontact with new values */ -int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci) +int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci, + char is_replicated) { int ret; @@ -822,6 +912,9 @@ int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci) return -1; } + if (!is_replicated && replication_dests && db_mode != DB_ONLY) + replicate_ucontact_update(_r, &_c->c, _ci); + /* run callbacks for UPDATE event */ if (exists_ulcb_type(UL_CONTACT_UPDATE)) { diff --git a/modules/usrloc/ucontact.h b/modules/usrloc/ucontact.h index e1fc7517839..16a2d801ad8 100644 --- a/modules/usrloc/ucontact.h +++ b/modules/usrloc/ucontact.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Usrloc contact structure * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -42,6 +42,7 @@ #include #include "../../qvalue.h" #include "../../str.h" +#include "../../proxy.h" #include "../../db/db_insertq.h" @@ -65,7 +66,7 @@ typedef enum flags { /*! \brief - * Main structure for handling of registered Contact: data + * Main structure for handling of registered Contact: data */ typedef struct ucontact { str* domain; /*!< Pointer to domain name (NULL terminated) */ @@ -85,6 +86,9 @@ typedef struct ucontact { struct socket_info *sock; /*!< received socket */ time_t last_modified; /*!< When the record was last modified */ unsigned int methods; /*!< Supported methods */ + str attr; /*!< Additional registration info */ + struct proxy_l next_hop;/*!< SIP-wise determined next hop */ + struct ucontact* next; /*!< Next contact in the linked list */ struct ucontact* prev; /*!< Previous contact in the linked list */ } ucontact_t; @@ -103,6 +107,7 @@ typedef struct ucontact_info { struct socket_info *sock; unsigned int methods; time_t last_modified; + str *attr; } ucontact_info_t; /*! \brief @@ -207,8 +212,9 @@ struct urecord; * Update ucontact with new values */ typedef int (*update_ucontact_t)(struct urecord* _r, ucontact_t* _c, - ucontact_info_t* _ci); + ucontact_info_t* _ci, char is_replicated); -int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci); +int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci, + char is_replicated); #endif /* UCONTACT_H */ diff --git a/modules/usrloc/udomain.c b/modules/usrloc/udomain.c index 7438d752e0f..7a555b3bcc3 100644 --- a/modules/usrloc/udomain.c +++ b/modules/usrloc/udomain.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -26,11 +26,11 @@ * 2004-06-07 updated to the new DB api (andrei) * 2004-08-23 hash function changed to process characters as unsigned * -> no negative results occur (jku) - * + * */ /*! \file - * \brief USRLOC - + * \brief USRLOC - * \ingroup usrloc */ @@ -45,6 +45,7 @@ #include "../../hash_func.h" #include "ul_mod.h" /* usrloc module parameters */ #include "utime.h" +#include "ureplication.h" @@ -62,7 +63,7 @@ int new_udomain(str* _n, int _s, udomain_t** _d) #ifdef STATISTICS char *name; #endif - + /* Must be always in shared memory, since * the cache is accessed from timer which * lives in a separate process @@ -73,7 +74,7 @@ int new_udomain(str* _n, int _s, udomain_t** _d) goto error0; } memset(*_d, 0, sizeof(udomain_t)); - + (*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s); if (!(*_d)->table) { LM_ERR("no memory left 2\n"); @@ -81,7 +82,7 @@ int new_udomain(str* _n, int _s, udomain_t** _d) } (*_d)->name = _n; - + for(i = 0; i < _s; i++) { if (init_slot(*_d, &((*_d)->table[i]), i) < 0) { LM_ERR("initializing hash table failed\n"); @@ -120,6 +121,158 @@ int new_udomain(str* _n, int _s, udomain_t** _d) } +static event_id_t ei_ins_id = EVI_ERROR; +static event_id_t ei_del_id = EVI_ERROR; +event_id_t ei_c_ins_id = EVI_ERROR; +event_id_t ei_c_del_id = EVI_ERROR; +event_id_t ei_c_update_id = EVI_ERROR; +static str ei_ins_name = str_init("E_UL_AOR_INSERT"); +static str ei_del_name = str_init("E_UL_AOR_DELETE"); +static str ei_contact_ins_name = str_init("E_UL_CONTACT_INSERT"); +static str ei_contact_del_name = str_init("E_UL_CONTACT_DELETE"); +static str ei_contact_update_name = str_init("E_UL_CONTACT_UPDATE"); +static str ei_aor_name = str_init("aor"); +static str ei_c_addr_name = str_init("address"); +static str ei_c_recv_name = str_init("received"); +static str ei_callid_name = str_init("callid"); +static str ei_cseq_name = str_init("cseq"); +static evi_params_p ul_event_params; +static evi_param_p ul_aor_param; +static evi_params_p ul_contact_event_params; +static evi_param_p ul_c_addr_param, ul_c_callid_param; +static evi_param_p ul_c_recv_param; +static evi_param_p ul_c_cseq_param; + +/*! \brief + * Initialize event structures + */ +int ul_event_init(void) +{ + ei_ins_id = evi_publish_event(ei_ins_name); + if (ei_ins_id == EVI_ERROR) { + LM_ERR("cannot register aor insert event\n"); + return -1; + } + + ei_del_id = evi_publish_event(ei_del_name); + if (ei_del_id == EVI_ERROR) { + LM_ERR("cannot register aor delete event\n"); + return -1; + } + + ei_c_ins_id = evi_publish_event(ei_contact_ins_name); + if (ei_c_ins_id == EVI_ERROR) { + LM_ERR("cannot register contact insert event\n"); + return -1; + } + + ei_c_del_id = evi_publish_event(ei_contact_del_name); + if (ei_c_del_id == EVI_ERROR) { + LM_ERR("cannot register contact delete event\n"); + return -1; + } + + ei_c_update_id = evi_publish_event(ei_contact_update_name); + if (ei_c_update_id == EVI_ERROR) { + LM_ERR("cannot register contact delete event\n"); + return -1; + } + + ul_event_params = pkg_malloc(sizeof(evi_params_t)); + if (!ul_event_params) { + LM_ERR("no more pkg memory\n"); + return -1; + } + memset(ul_event_params, 0, sizeof(evi_params_t)); + ul_aor_param = evi_param_create(ul_event_params, &ei_aor_name); + if (!ul_aor_param) { + LM_ERR("cannot create AOR parameter\n"); + return -1; + } + + ul_contact_event_params = pkg_malloc(sizeof(evi_params_t)); + if (!ul_contact_event_params) { + LM_ERR("no more pkg memory\n"); + return -1; + } + memset(ul_contact_event_params, 0, sizeof(evi_params_t)); + + ul_c_addr_param = evi_param_create(ul_contact_event_params, &ei_c_addr_name); + if (!ul_c_addr_param) { + LM_ERR("cannot create contact address parameter\n"); + return -1; + } + + ul_c_callid_param = evi_param_create(ul_contact_event_params, &ei_callid_name); + if (!ul_c_callid_param) { + LM_ERR("cannot create callid parameter\n"); + return -1; + } + + ul_c_recv_param = evi_param_create(ul_contact_event_params, &ei_c_recv_name); + if (!ul_c_recv_param) { + LM_ERR("cannot create received parameter\n"); + return -1; + } + + ul_c_cseq_param = evi_param_create(ul_contact_event_params, &ei_cseq_name); + if (!ul_c_cseq_param) { + LM_ERR("cannot create cseq parameter\n"); + return -1; + } + + return 0; +} + +/*! \brief + * Raise an event when an AOR is inserted/deleted + */ +static void ul_raise_event(event_id_t _e, struct urecord* _r) +{ + if (_e == EVI_ERROR) { + LM_ERR("event not yet registered %d\n", _e); + return; + } + if (evi_param_set_str(ul_aor_param, &_r->aor) < 0) { + LM_ERR("cannot set AOR parameter\n"); + return; + } + if (evi_raise_event(_e, ul_event_params) < 0) + LM_ERR("cannot raise event\n"); +} + +void ul_raise_contact_event(event_id_t _e, str *addr, str *callid, str *recv, + int cseq) +{ + if (_e == EVI_ERROR) { + LM_ERR("event not yet registered %d\n", _e); + return; + } + if (evi_param_set_str(ul_c_addr_param, addr) < 0) { + LM_ERR("cannot set contact address parameter\n"); + return; + } + + if (evi_param_set_str(ul_c_callid_param, callid) < 0) { + LM_ERR("cannot set callid parameter\n"); + return; + } + + if (evi_param_set_str(ul_c_recv_param, recv) < 0) { + LM_ERR("cannot set received parameter\n"); + return; + } + + if (evi_param_set_int(ul_c_cseq_param, &cseq) < 0) { + LM_ERR("cannot set cseq parameter\n"); + return; + } + + if (evi_raise_event(_e, ul_contact_event_params) < 0) + LM_ERR("cannot raise event\n"); +} + + /*! \brief * Free all memory allocated for * the domain @@ -127,7 +280,7 @@ int new_udomain(str* _n, int _s, udomain_t** _d) void free_udomain(udomain_t* _d) { int i; - + if (_d->table) { for(i = 0; i < _d->size; i++) { lock_ulslot(_d, i); @@ -183,9 +336,9 @@ void print_udomain(FILE* _f, udomain_t* _d) iterator_is_valid(&it); iterator_next(&it) ) print_urecord(_f, (struct urecord *)*iterator_val(&it)); - + } - + fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n); fprintf(_f, "\n---/Domain---\n"); } @@ -198,7 +351,7 @@ void print_udomain(FILE* _f, udomain_t* _d) static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact) { static ucontact_info_t ci; - static str callid, ua, received, host, path,instance; + static str callid, ua, received, host, path, instance, attr, flags; int port, proto; char *p; @@ -243,11 +396,15 @@ static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact) } ci.flags = VAL_BITMAP(vals+5); - if (VAL_NULL(vals+6)) { - LM_CRIT("empty cflag\n"); - return 0; + if (!VAL_NULL(vals+6)) { + flags.s = (char *)VAL_STRING(vals+6); + flags.len = strlen(flags.s); + LM_DBG("flag str: '%.*s'\n", flags.len, flags.s); + + ci.cflags = flag_list_to_bitmask(&flags, FLAG_TYPE_BRANCH, FLAG_DELIM); + + LM_DBG("set flags: %d\n", ci.cflags); } - ci.cflags = VAL_BITMAP(vals+6); ua.s = (char*)VAL_STRING(vals+7); if (VAL_NULL(vals+7) || !ua.s || !ua.s[0]) { @@ -266,7 +423,7 @@ static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact) received.len = strlen(received.s); } ci.received = received; - + path.s = (char*)VAL_STRING(vals+9); if (VAL_NULL(vals+9) || !path.s || !path.s[0]) { path.len = 0; @@ -281,7 +438,7 @@ static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact) if (VAL_NULL(vals+10) || p==0 || p[0]==0){ ci.sock = 0; } else { - if (parse_phostport( p, strlen(p), &host.s, &host.len, + if (parse_phostport( p, strlen(p), &host.s, &host.len, &port, &proto)!=0) { LM_ERR("bad socket <%s>\n", p); return 0; @@ -313,6 +470,15 @@ static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact) } ci.instance = instance; + attr.s = (char*)VAL_STRING(vals+14); + if (VAL_NULL(vals+14) || !attr.s) { + attr.s = NULL; + attr.len = 0; + } else + attr.len = strlen(attr.s); + + ci.attr = &attr; + return &ci; } @@ -324,7 +490,7 @@ int preload_udomain(db_con_t* _c, udomain_t* _d) char uri[MAX_URI_SIZE]; ucontact_info_t *ci; db_row_t *row; - db_key_t columns[16]; + db_key_t columns[17]; db_res_t* res = NULL; str user, contact; char* domain; @@ -350,7 +516,8 @@ int preload_udomain(db_con_t* _c, udomain_t* _d) columns[12] = &methods_col; columns[13] = &last_mod_col; columns[14] = &sip_instance_col; - columns[15] = &domain_col; + columns[15] = &attr_col; + columns[16] = &domain_col; if (ul_dbf.use_table(_c, _d->name) < 0) { LM_ERR("sql use_table failed\n"); @@ -362,20 +529,20 @@ int preload_udomain(db_con_t* _c, udomain_t* _d) #endif if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) { - if (ul_dbf.query(_c, 0, 0, 0, columns, 0, (use_domain)?(16):(15), 0, + if (ul_dbf.query(_c, 0, 0, 0, columns, 0, (use_domain)?(17):(16), 0, 0) < 0) { LM_ERR("db_query (1) failed\n"); return -1; } no_rows = estimate_available_rows( 32+64+4+8+128+8+4+4+64 - +32+128+16+8+8+255+32, 16); + +32+128+16+8+8+255+32+255, 17); if (no_rows==0) no_rows = 10; if(ul_dbf.fetch_result(_c, &res, no_rows)<0) { LM_ERR("fetching rows failed\n"); return -1; } } else { - if (ul_dbf.query(_c, 0, 0, 0, columns, 0, (use_domain)?(16):(15), 0, + if (ul_dbf.query(_c, 0, 0, 0, columns, 0, (use_domain)?(17):(16), 0, &res) < 0) { LM_ERR("db_query failed\n"); return -1; @@ -411,8 +578,8 @@ int preload_udomain(db_con_t* _c, udomain_t* _d) } if (use_domain) { - domain = (char*)VAL_STRING(ROW_VALUES(row) + 15); - if (VAL_NULL(ROW_VALUES(row)+15) || domain==0 || domain[0]==0){ + domain = (char*)VAL_STRING(ROW_VALUES(row) + 16); + if (VAL_NULL(ROW_VALUES(row)+16) || domain==0 || domain[0]==0){ LM_CRIT("empty domain record for user %.*s...skipping\n", user.len, user.s); continue; @@ -428,7 +595,7 @@ int preload_udomain(db_con_t* _c, udomain_t* _d) } } - + lock_udomain(_d, &user); if (get_urecord(_d, &user, &r) > 0) { if (mem_insert_urecord(_d, &user, &r) < 0) { @@ -483,7 +650,7 @@ urecord_t* db_load_urecord(db_con_t* _c, udomain_t* _d, str *_aor) { /*static db_ps_t my_ps = NULL;*/ ucontact_info_t *ci; - db_key_t columns[14]; + db_key_t columns[15]; db_key_t keys[2]; db_val_t vals[2]; db_key_t order = &q_col; @@ -512,6 +679,7 @@ urecord_t* db_load_urecord(db_con_t* _c, udomain_t* _d, str *_aor) columns[11] = &methods_col; columns[12] = &last_mod_col; columns[13] = &sip_instance_col; + columns[14] = &attr_col; if (desc_time_order) order = &last_mod_col; @@ -542,7 +710,7 @@ urecord_t* db_load_urecord(db_con_t* _c, udomain_t* _d, str *_aor) /* CON_PS_REFERENCE(_c) = &my_ps; - this is still dangerous with STMT */ - if (ul_dbf.query(_c, keys, 0, vals, columns, (use_domain)?2:1, 14, order, + if (ul_dbf.query(_c, keys, 0, vals, columns, (use_domain)?2:1, 15, order, &res) < 0) { LM_ERR("db_query failed\n"); return 0; @@ -563,7 +731,7 @@ urecord_t* db_load_urecord(db_con_t* _c, udomain_t* _d, str *_aor) _aor->len, _aor->s, _d->name->s); continue; } - + if ( r==0 ) get_static_urecord( _d, _aor, &r); @@ -636,7 +804,7 @@ int testdb_udomain(db_con_t* con, udomain_t* d) VAL_TYPE(val) = DB_STRING; VAL_NULL(val) = 0; VAL_STRING(val) = "dummy_user"; - + if (ul_dbf.query( con, key, 0, val, col, 1, 1, 0, &res) < 0) { LM_ERR("failure in db_query\n"); return -1; @@ -653,7 +821,7 @@ int testdb_udomain(db_con_t* con, udomain_t* d) int mem_insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r) { int sl; - + if (new_urecord(_d->name, _aor, _r) < 0) { LM_ERR("creating urecord failed\n"); return -1; @@ -669,6 +837,7 @@ int mem_insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r) return -1; } + ul_raise_event(ei_ins_id, *_r); update_stat( _d->users, 1); return 0; } @@ -679,6 +848,7 @@ int mem_insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r) */ void mem_delete_urecord(udomain_t* _d, struct urecord* _r) { + ul_raise_event(ei_del_id, _r); slot_rem(_r->slot, _r); free_urecord(_r); update_stat( _d->users, -1); @@ -702,8 +872,10 @@ int mem_timer_udomain(udomain_t* _d) { dest = iterator_val(&it); - if( dest == NULL ) + if( dest == NULL ) { + unlock_ulslot(_d, i); return -1; + } ptr = (struct urecord *)*dest; @@ -715,7 +887,7 @@ int mem_timer_udomain(udomain_t* _d) unlock_ulslot(_d, i); return -1; } - + if (ret) flush=1; @@ -726,7 +898,7 @@ int mem_timer_udomain(udomain_t* _d) mem_delete_urecord(_d,ptr); } } - + unlock_ulslot(_d, i); } @@ -811,16 +983,21 @@ void unlock_ulslot(udomain_t* _d, int i) /*! \brief * Create and insert a new record */ -int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r) +int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r, + char is_replicated) { if (db_mode!=DB_ONLY) { if (mem_insert_urecord(_d, _aor, _r) < 0) { LM_ERR("inserting record failed\n"); return -1; } + + if (!is_replicated && replication_dests) + replicate_urecord_insert(*_r); } else { get_static_urecord( _d, _aor, _r); } + return 0; } @@ -839,7 +1016,7 @@ int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r) /* search in cache */ aorhash = core_hash(_aor, 0, 0); sl = aorhash&(_d->size-1); - + dest = map_find(_d->table[sl].records, *_aor); @@ -850,7 +1027,7 @@ int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r) return 0; - + } else { /* search in DB */ r = db_load_urecord( ul_dbh, _d, _aor); @@ -867,7 +1044,8 @@ int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r) /*! \brief * Delete a urecord from domain */ -int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r) +int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r, + char is_replicated) { struct ucontact* c, *t; @@ -888,16 +1066,19 @@ int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r) } } + if (!is_replicated && replication_dests) + replicate_urecord_delete(_r); + c = _r->contacts; while(c) { t = c; c = c->next; - if (delete_ucontact(_r, t) < 0) { + if (delete_ucontact(_r, t, is_replicated) < 0) { LM_ERR("deleting contact failed\n"); return -1; } } - release_urecord(_r); + release_urecord(_r, is_replicated); return 0; } diff --git a/modules/usrloc/udomain.h b/modules/usrloc/udomain.h index f87c64811a9..6623c901e56 100644 --- a/modules/usrloc/udomain.h +++ b/modules/usrloc/udomain.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Usrloc domain structure * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* @@ -46,7 +46,6 @@ #include "urecord.h" #include "hslot.h" - struct hslot; /*!< Hash table slot */ struct urecord; /*!< Usrloc record */ @@ -159,8 +158,10 @@ void unlock_ulslot(udomain_t* _d, int slot); /*! \brief * Create and insert a new record */ -typedef int (*insert_urecord_t)(udomain_t* _d, str* _aor, struct urecord** _r); -int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r); +typedef int (*insert_urecord_t)(udomain_t* _d, str* _aor, struct urecord** _r, + char is_replicated); +int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r, + char is_replicated); /*! \brief @@ -173,10 +174,14 @@ int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r); /*! \brief * Delete a urecord from domain */ -typedef int (*delete_urecord_t)(udomain_t* _d, str* _a, struct urecord* _r); -int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r); +typedef int (*delete_urecord_t)(udomain_t* _d, str* _a, struct urecord* _r, + char is_replicated); +int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r, + char is_replicated); +void ul_raise_contact_event(event_id_t _e, str *addr, str *callid, str *recv, + int cseq); #endif /* UDOMAIN_H */ diff --git a/modules/usrloc/ul_callback.c b/modules/usrloc/ul_callback.c index 605aa802111..8673bc30a47 100644 --- a/modules/usrloc/ul_callback.c +++ b/modules/usrloc/ul_callback.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -75,7 +75,7 @@ void destroy_ulcb_list(void) -/*! \brief +/*! \brief register a callback function 'f' for 'types' mask of events; */ int register_ulcb( int types, ul_cb f, void *param ) diff --git a/modules/usrloc/ul_callback.h b/modules/usrloc/ul_callback.h index 97ac1ddc523..1f50b441fb9 100644 --- a/modules/usrloc/ul_callback.h +++ b/modules/usrloc/ul_callback.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/usrloc/ul_mi.c b/modules/usrloc/ul_mi.c index d6d456a6346..511c70657f4 100644 --- a/modules/usrloc/ul_mi.c +++ b/modules/usrloc/ul_mi.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -95,10 +95,11 @@ static inline int mi_add_aor_node(struct mi_node *parent, urecord_t* r, time_t t struct mi_node *node; struct mi_attr *attr; ucontact_t* c; + str st; char *p; int len; - anode = add_mi_node_child( parent, MI_DUP_VALUE, "AOR", 3, + anode = add_mi_node_child( parent, MI_IS_ARRAY|MI_DUP_VALUE, "AOR", 3, r->aor.s, r->aor.len); if (anode==0) return -1; @@ -189,8 +190,8 @@ static inline int mi_add_aor_node(struct mi_node *parent, urecord_t* r, time_t t return -1; /* cflags */ - p = int2str((unsigned long)c->cflags, &len); - node = add_mi_node_child( cnode, MI_DUP_VALUE, "Cflags", 5, p, len); + st = bitmask_to_flag_list(FLAG_TYPE_BRANCH, c->cflags); + node = add_mi_node_child( cnode, MI_DUP_VALUE, "Cflags", 6, st.s, st.len); if (node==0) return -1; @@ -213,6 +214,22 @@ static inline int mi_add_aor_node(struct mi_node *parent, urecord_t* r, time_t t if (node==0) return -1; + /* additional information */ + if (c->attr.len) { + node = add_mi_node_child( cnode, MI_DUP_VALUE, "Attr", 4, + c->attr.s, c->attr.len); + if (node==0) + return -1; + } + + /* sip_instance */ + if (c->instance.len && c->instance.s) { + node = add_mi_node_child( cnode, MI_DUP_VALUE, "SIP_instance", 12, + c->instance.s, c->instance.len); + if (node==0) + return -1; + } + } /* for */ return 0; @@ -247,7 +264,7 @@ struct mi_root* mi_usrloc_rm_aor(struct mi_root *cmd, void *param) return init_mi_tree( 400, "Domain missing in AOR", 21); lock_udomain( dom, aor); - if (delete_urecord( dom, aor, 0) < 0) { + if (delete_urecord( dom, aor, NULL, 0) < 0) { unlock_udomain( dom, aor); return init_mi_tree( 500, "Failed to delete AOR", 20); } @@ -304,12 +321,12 @@ struct mi_root* mi_usrloc_rm_contact(struct mi_root *cmd, void *param) return init_mi_tree( 404, "Contact not found", 17); } - if (delete_ucontact(rec, con) < 0) { + if (delete_ucontact(rec, con, 0) < 0) { unlock_udomain( dom, aor); return 0; } - release_urecord(rec); + release_urecord(rec, 0); unlock_udomain( dom, aor); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); } @@ -332,7 +349,7 @@ struct mi_root* mi_usrloc_dump(struct mi_root *cmd, void *param) int short_dump; map_iterator_t it; void ** dest; - + node = cmd->node.kids; if (node && node->next) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); @@ -348,12 +365,14 @@ struct mi_root* mi_usrloc_dump(struct mi_root *cmd, void *param) if (rpl_tree==NULL) return 0; rpl = &rpl_tree->node; + /* all domains go under this node as array */ + rpl->flags |= MI_IS_ARRAY; t = time(0); for( dl=root ; dl ; dl=dl->next ) { /* add a domain node */ - node = add_mi_node_child( rpl, MI_NOT_COMPLETED, "Domain", 6, - dl->name.s, dl->name.len); + node = add_mi_node_child( rpl, MI_IS_ARRAY|MI_NOT_COMPLETED, + "Domain", 6, dl->name.s, dl->name.len); if (node==0) goto error; @@ -375,15 +394,13 @@ struct mi_root* mi_usrloc_dump(struct mi_root *cmd, void *param) dest = iterator_val(&it); if( dest == NULL ) - goto error; + goto error_unlock; r =( urecord_t * ) *dest; /* add entry */ - if (mi_add_aor_node( node, r, t, short_dump)!=0) { - unlock_ulslot( dom, i); - goto error; - } + if (mi_add_aor_node( node, r, t, short_dump)!=0) + goto error_unlock; n++; /* at each 50 AORs, flush the tree */ if ( (n % 50) == 0 ) @@ -402,6 +419,9 @@ struct mi_root* mi_usrloc_dump(struct mi_root *cmd, void *param) } return rpl_tree; + +error_unlock: + unlock_ulslot( dom, i); error: free_mi_tree(rpl_tree); return 0; @@ -422,7 +442,7 @@ struct mi_root* mi_usrloc_flush(struct mi_root *cmd, void *param) /*! \brief - * Expects 7 nodes: + * Expects 7 nodes: * table name, * AOR * contact @@ -501,7 +521,7 @@ struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param) n = get_urecord( dom, aor, &r); if ( n==1) { - if (insert_urecord( dom, aor, &r) < 0) + if (insert_urecord( dom, aor, &r, 0) < 0) goto lock_error; c = 0; } else { @@ -519,17 +539,17 @@ struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param) if (c) { /* update contact record */ ci.cseq = c->cseq; - if (update_ucontact( r, c, &ci) < 0) + if (update_ucontact( r, c, &ci, 0) < 0) goto release_error; } else { /* new contact record */ ci.callid = &mi_ul_cid; ci.cseq = MI_UL_CSEQ; - if ( insert_ucontact( r, contact, &ci, &c) < 0 ) + if ( insert_ucontact( r, contact, &ci, &c, 0) < 0 ) goto release_error; } - release_urecord(r); + release_urecord(r, 0); unlock_udomain( dom, aor); @@ -537,7 +557,7 @@ struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param) bad_syntax: return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); release_error: - release_urecord(r); + release_urecord(r, 0); lock_error: unlock_udomain( dom, aor); return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN); @@ -603,10 +623,12 @@ struct mi_root* mi_usrloc_show_contact(struct mi_root *cmd, void *param) if (rpl_tree==0) goto error; rpl = &rpl_tree->node; + rpl->flags |= MI_IS_ARRAY; } node = addf_mi_node_child( rpl, 0, "Contact", 7, "<%.*s>;q=%s;expires=%d;flags=0x%X;cflags=0x%X;socket=<%.*s>;" + "callid=<%.*s>;" "methods=0x%X" "%s%.*s%s" /*received*/ "%s%.*s%s" /*user-agent*/ @@ -615,6 +637,7 @@ struct mi_root* mi_usrloc_show_contact(struct mi_root *cmd, void *param) q2str(con->q, 0), (int)(con->expires - act_time), con->flags, con->cflags, use_sock_str.len,use_sock_str.s, + con->callid.len, ZSW(con->callid.s), con->methods, con->received.len?";received=<":"",con->received.len, ZSW(con->received.s), con->received.len?">":"", diff --git a/modules/usrloc/ul_mi.h b/modules/usrloc/ul_mi.h index e931cd94194..4f05f8347aa 100644 --- a/modules/usrloc/ul_mi.h +++ b/modules/usrloc/ul_mi.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/usrloc/ul_mod.c b/modules/usrloc/ul_mod.c index 9a4704e36fe..8e75d8d8d0d 100644 --- a/modules/usrloc/ul_mod.c +++ b/modules/usrloc/ul_mod.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -56,6 +56,7 @@ #include "udomain.h" /* {insert,delete,get,release}_urecord */ #include "urecord.h" /* {insert,delete,get}_ucontact */ #include "ucontact.h" /* update_ucontact */ +#include "ureplication.h" #include "ul_mi.h" #include "ul_callback.h" #include "usrloc.h" @@ -76,6 +77,7 @@ #define PATH_COL "path" #define SOCK_COL "socket" #define METHODS_COL "methods" +#define ATTR_COL "attr" #define LAST_MOD_COL "last_modified" #define SIP_INSTANCE_COL "sip_instance" @@ -85,9 +87,13 @@ static void timer(unsigned int ticks, void* param); /*!< Timer handler */ static int child_init(int rank); /*!< Per-child init function */ static int mi_child_init(void); +static int add_replication_dest(modparam_t type, void *val); + extern int bind_usrloc(usrloc_api_t* api); extern int ul_locks_no; extern rw_lock_t *sync_lock; +extern int skip_replicated_db_ops; + /* * Module parameters and their default values */ @@ -106,7 +112,8 @@ str received_col = str_init(RECEIVED_COL); /*!< Name of column containing tr str path_col = str_init(PATH_COL); /*!< Name of column containing the Path header */ str sock_col = str_init(SOCK_COL); /*!< Name of column containing the received socket */ str methods_col = str_init(METHODS_COL); /*!< Name of column containing the supported methods */ -str last_mod_col = str_init(LAST_MOD_COL); /*!< Name of column containing the last modified date */ +str last_mod_col = str_init(LAST_MOD_COL); /*!< Name of column containing the last modified date */ +str attr_col = str_init(ATTR_COL); /*!< Name of column containing additional info */ str sip_instance_col = str_init(SIP_INSTANCE_COL); str db_url = {NULL, 0}; /*!< Database URL */ int timer_interval = 60; /*!< Timer interval in seconds */ @@ -121,11 +128,14 @@ unsigned int nat_bflag = (unsigned int)-1; static char *nat_bflag_str = 0; unsigned int init_flag = 0; +/* usrloc data replication using the bin interface */ +int accept_replicated_udata; +struct replication_dest *replication_dests; + db_con_t* ul_dbh = 0; /* Database connection handle */ db_func_t ul_dbf; - /*! \brief * Exported functions */ @@ -136,33 +146,40 @@ static cmd_export_t cmds[] = { /*! \brief - * Exported parameters + * Exported parameters */ static param_export_t params[] = { - {"user_column", STR_PARAM, &user_col.s }, - {"domain_column", STR_PARAM, &domain_col.s }, - {"contact_column", STR_PARAM, &contact_col.s }, - {"expires_column", STR_PARAM, &expires_col.s }, - {"q_column", STR_PARAM, &q_col.s }, - {"callid_column", STR_PARAM, &callid_col.s }, - {"cseq_column", STR_PARAM, &cseq_col.s }, - {"flags_column", STR_PARAM, &flags_col.s }, - {"cflags_column", STR_PARAM, &cflags_col.s }, - {"db_url", STR_PARAM, &db_url.s }, - {"timer_interval", INT_PARAM, &timer_interval }, - {"db_mode", INT_PARAM, &db_mode }, - {"use_domain", INT_PARAM, &use_domain }, - {"desc_time_order", INT_PARAM, &desc_time_order }, - {"user_agent_column", STR_PARAM, &user_agent_col.s}, - {"received_column", STR_PARAM, &received_col.s }, - {"path_column", STR_PARAM, &path_col.s }, - {"socket_column", STR_PARAM, &sock_col.s }, - {"methods_column", STR_PARAM, &methods_col.s }, - {"matching_mode", INT_PARAM, &matching_mode }, - {"cseq_delay", INT_PARAM, &cseq_delay }, - {"hash_size", INT_PARAM, &ul_hash_size }, - {"nat_bflag", STR_PARAM, &nat_bflag_str }, - {"nat_bflag", INT_PARAM, &nat_bflag }, + {"user_column", STR_PARAM, &user_col.s }, + {"domain_column", STR_PARAM, &domain_col.s }, + {"contact_column", STR_PARAM, &contact_col.s }, + {"expires_column", STR_PARAM, &expires_col.s }, + {"q_column", STR_PARAM, &q_col.s }, + {"callid_column", STR_PARAM, &callid_col.s }, + {"cseq_column", STR_PARAM, &cseq_col.s }, + {"flags_column", STR_PARAM, &flags_col.s }, + {"cflags_column", STR_PARAM, &cflags_col.s }, + {"db_url", STR_PARAM, &db_url.s }, + {"timer_interval", INT_PARAM, &timer_interval }, + {"db_mode", INT_PARAM, &db_mode }, + {"use_domain", INT_PARAM, &use_domain }, + {"desc_time_order", INT_PARAM, &desc_time_order }, + {"user_agent_column", STR_PARAM, &user_agent_col.s }, + {"received_column", STR_PARAM, &received_col.s }, + {"path_column", STR_PARAM, &path_col.s }, + {"socket_column", STR_PARAM, &sock_col.s }, + {"methods_column", STR_PARAM, &methods_col.s }, + {"sip_instance_column",STR_PARAM, &sip_instance_col.s}, + {"attr_column", STR_PARAM, &attr_col.s }, + {"matching_mode", INT_PARAM, &matching_mode }, + {"cseq_delay", INT_PARAM, &cseq_delay }, + {"hash_size", INT_PARAM, &ul_hash_size }, + {"nat_bflag", STR_PARAM, &nat_bflag_str }, + {"nat_bflag", INT_PARAM, &nat_bflag }, + /* data replication through UDP binary packets */ + { "accept_replicated_contacts",INT_PARAM, &accept_replicated_udata }, + { "replicate_contacts_to", STR_PARAM|USE_FUNC_PARAM, + (void *)add_replication_dest }, + { "skip_replicated_db_ops", INT_PARAM, &skip_replicated_db_ops }, {0, 0, 0} }; @@ -191,11 +208,30 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static module_dependency_t *get_deps_db_mode(param_export_t *param) +{ + if (*(int *)param->param_pointer == NO_DB) + return NULL; + + return alloc_module_dep(MOD_TYPE_SQLDB, NULL, DEP_ABORT); +} + +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { "db_mode", get_deps_db_mode }, + { NULL, NULL }, + }, +}; struct module_exports exports = { "usrloc", + MOD_TYPE_DEFAULT,/*!< class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /*!< dlopen flags */ + &deps, /*!< OpenSIPS module dependencies */ cmds, /*!< Exported functions */ params, /*!< Export parameters */ mod_stats, /*!< exported statistics */ @@ -232,6 +268,8 @@ static int mod_init(void) path_col.len = strlen(path_col.s); sock_col.len = strlen(sock_col.s); methods_col.len = strlen(methods_col.s); + sip_instance_col.len = strlen(sip_instance_col.s); + attr_col.len = strlen(attr_col.s); last_mod_col.len = strlen(last_mod_col.s); if(ul_hash_size<=1) @@ -285,8 +323,8 @@ static int mod_init(void) } } - fix_flag_name(&nat_bflag_str, nat_bflag); - + fix_flag_name(nat_bflag_str, nat_bflag); + nat_bflag = get_flag_id_by_name(FLAG_TYPE_BRANCH, nat_bflag_str); if (nat_bflag==(unsigned int)-1) { @@ -298,6 +336,18 @@ static int mod_init(void) nat_bflag = 1<to, he, 0, port); + + rd->next = replication_dests; + replication_dests = rd; + + return 1; +} + diff --git a/modules/usrloc/ul_mod.h b/modules/usrloc/ul_mod.h index d4a4cf291dc..e1acefc47df 100644 --- a/modules/usrloc/ul_mod.h +++ b/modules/usrloc/ul_mod.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -48,7 +48,7 @@ #define WRITE_BACK 2 #define DB_ONLY 3 -#define UL_TABLE_VERSION 1007 +#define UL_TABLE_VERSION 1009 extern str user_col; extern str domain_col; @@ -64,6 +64,7 @@ extern str received_col; extern str path_col; extern str sock_col; extern str methods_col; +extern str attr_col; extern str last_mod_col; extern str sip_instance_col; @@ -78,7 +79,6 @@ extern int ul_hash_size; extern db_con_t* ul_dbh; /* Database connection handle */ extern db_func_t ul_dbf; - /* * Matching algorithms */ @@ -88,4 +88,9 @@ extern db_func_t ul_dbf; extern int matching_mode; +/*! \brief + * Initialize event structures + */ +int ul_event_init(void); + #endif /* UL_MOD_H */ diff --git a/modules/usrloc/urecord.c b/modules/usrloc/urecord.c index e5ec80ec8f5..9e863b52590 100644 --- a/modules/usrloc/urecord.c +++ b/modules/usrloc/urecord.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Usrloc record structure * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -44,12 +44,17 @@ #include "ul_mod.h" #include "utime.h" #include "ul_callback.h" +#include "ureplication.h" +#include "udomain.h" int matching_mode = CONTACT_ONLY; int cseq_delay = 20; +extern event_id_t ei_c_ins_id; +extern event_id_t ei_c_del_id; + /*! \brief * Create and initialize new record structure */ @@ -91,7 +96,7 @@ void free_urecord(urecord_t* _r) _r->contacts = _r->contacts->next; free_ucontact(ptr); } - + /* if mem cache is not used, the urecord struct is static*/ if (db_mode!=DB_ONLY) { if (_r->aor.s) shm_free(_r->aor.s); @@ -114,7 +119,7 @@ void print_urecord(FILE* _f, urecord_t* _r) fprintf(_f, "aor : '%.*s'\n", _r->aor.len, ZSW(_r->aor.s)); fprintf(_f, "aorhash: '%u'\n", (unsigned)_r->aorhash); fprintf(_f, "slot: '%d'\n", _r->aorhash&(_r->slot->d->size-1)); - + if (_r->contacts) { ptr = _r->contacts; while(ptr) { @@ -129,7 +134,7 @@ void print_urecord(FILE* _f, urecord_t* _r) /*! \brief * Add a new contact - * Contacts are ordered by: 1) q + * Contacts are ordered by: 1) q * 2) descending modification time */ ucontact_t* mem_insert_ucontact(urecord_t* _r, str* _c, ucontact_info_t* _ci) @@ -171,6 +176,8 @@ ucontact_t* mem_insert_ucontact(urecord_t* _r, str* _c, ucontact_info_t* _ci) _r->contacts = c; } + ul_raise_contact_event(ei_c_ins_id, &c->c, &c->callid, &c->received, + c->cseq); return c; } @@ -191,7 +198,9 @@ void mem_remove_ucontact(urecord_t* _r, ucontact_t* _c) _c->next->prev = 0; } } -} + ul_raise_contact_event(ei_c_del_id, &_c->c, &_c->callid, &_c->received, + _c->cseq); +} @@ -274,7 +283,7 @@ static inline int wt_timer(urecord_t* _r) ptr = ptr->next; } } - + return 0; } @@ -413,11 +422,15 @@ int db_delete_urecord(urecord_t* _r) * Release urecord previously obtained * through get_urecord */ -void release_urecord(urecord_t* _r) +void release_urecord(urecord_t* _r, char is_replicated) { if (db_mode==DB_ONLY) { free_urecord(_r); } else if (_r->contacts == 0) { + + if (!is_replicated && replication_dests) + replicate_urecord_delete(_r); + mem_delete_urecord(_r->slot->d, _r); } } @@ -428,13 +441,16 @@ void release_urecord(urecord_t* _r) * into urecord */ int insert_ucontact(urecord_t* _r, str* _contact, ucontact_info_t* _ci, - ucontact_t** _c) + ucontact_t** _c, char is_replicated) { if ( ((*_c)=mem_insert_ucontact(_r, _contact, _ci)) == 0) { LM_ERR("failed to insert contact\n"); return -1; } + if (!is_replicated && replication_dests && db_mode != DB_ONLY) + replicate_ucontact_insert(_r, _contact, _ci); + if (exists_ulcb_type(UL_CONTACT_INSERT)) { run_ul_callbacks( UL_CONTACT_INSERT, *_c); } @@ -454,8 +470,11 @@ int insert_ucontact(urecord_t* _r, str* _contact, ucontact_info_t* _ci, /*! \brief * Delete ucontact from urecord */ -int delete_ucontact(urecord_t* _r, struct ucontact* _c) +int delete_ucontact(urecord_t* _r, struct ucontact* _c, char is_replicated) { + if (!is_replicated && replication_dests && db_mode != DB_ONLY) + replicate_ucontact_delete(_r, _c); + if (exists_ulcb_type(UL_CONTACT_DELETE)) { run_ul_callbacks( UL_CONTACT_DELETE, _c); } @@ -480,7 +499,7 @@ static inline struct ucontact* contact_match( ucontact_t* ptr, str* _c) if ((_c->len == ptr->c.len) && !memcmp(_c->s, ptr->c.s, _c->len)) { return ptr; } - + ptr = ptr->next; } return 0; @@ -497,7 +516,7 @@ static inline struct ucontact* contact_callid_match( ucontact_t* ptr, ) { return ptr; } - + ptr = ptr->next; } return 0; diff --git a/modules/usrloc/urecord.h b/modules/usrloc/urecord.h index 64fa522ec0d..fff022f5198 100644 --- a/modules/usrloc/urecord.h +++ b/modules/usrloc/urecord.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Usrloc record structure * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -50,7 +50,7 @@ struct hslot; * Basic hash table element */ typedef struct urecord { - str* domain; /*!< Pointer to domain we belong to + str* domain; /*!< Pointer to domain we belong to * ( null terminated string) */ str aor; /*!< Address of record */ unsigned int aorhash; /*!< Hash over address of record */ @@ -88,7 +88,7 @@ void mem_remove_ucontact(urecord_t* _r, ucontact_t* _c); /* - * Remove contact from the list and delete + * Remove contact from the list and delete */ void mem_delete_ucontact(urecord_t* _r, ucontact_t* _c); @@ -112,24 +112,25 @@ int db_delete_urecord(urecord_t* _r); * Release urecord previously obtained * through get_urecord */ -typedef void (*release_urecord_t)(urecord_t* _r); -void release_urecord(urecord_t* _r); +typedef void (*release_urecord_t)(urecord_t* _r, char is_replicated); +void release_urecord(urecord_t* _r, char is_replicated); /* * Insert new contact */ typedef int (*insert_ucontact_t)(urecord_t* _r, str* _contact, - ucontact_info_t* _ci, ucontact_t** _c); + ucontact_info_t* _ci, ucontact_t** _c, char is_replicated); int insert_ucontact(urecord_t* _r, str* _contact, - ucontact_info_t* _ci, ucontact_t** _c); + ucontact_info_t* _ci, ucontact_t** _c, char is_replicated); /* * Delete ucontact from urecord */ -typedef int (*delete_ucontact_t)(urecord_t* _r, struct ucontact* _c); -int delete_ucontact(urecord_t* _r, struct ucontact* _c); +typedef int (*delete_ucontact_t)(urecord_t* _r, struct ucontact* _c, + char is_replicated); +int delete_ucontact(urecord_t* _r, struct ucontact* _c, char is_replicated); /* diff --git a/modules/usrloc/ureplication.c b/modules/usrloc/ureplication.c new file mode 100644 index 00000000000..819f138661e --- /dev/null +++ b/modules/usrloc/ureplication.c @@ -0,0 +1,560 @@ +/* + * Usrloc record and contact replication + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2013-10-09 initial version (Liviu) + */ + +#include "ureplication.h" +#include "dlist.h" + +str repl_module_name = str_init("ul"); + +/* Skip all DB operations when receiving replicated data */ +int skip_replicated_db_ops; + +/* packet sending */ + +void replicate_urecord_insert(urecord_t *r) +{ + struct replication_dest *d; + + if (bin_init(&repl_module_name, REPL_URECORD_INSERT) != 0) { + LM_ERR("failed to replicate this event\n"); + return; + } + + bin_push_str(r->domain); + bin_push_str(&r->aor); + + for (d = replication_dests; d; d = d->next) + bin_send(&d->to); +} + +void replicate_urecord_delete(urecord_t *r) +{ + struct replication_dest *d; + + if (bin_init(&repl_module_name, REPL_URECORD_DELETE) != 0) { + LM_ERR("failed to replicate this event\n"); + return; + } + + bin_push_str(r->domain); + bin_push_str(&r->aor); + + for (d = replication_dests; d; d = d->next) + bin_send(&d->to); +} + +void replicate_ucontact_insert(urecord_t *r, str *contact, ucontact_info_t *ci) +{ + struct replication_dest *d; + str st; + + if (bin_init(&repl_module_name, REPL_UCONTACT_INSERT) != 0) { + LM_ERR("failed to replicate this event\n"); + return; + } + + bin_push_str(r->domain); + bin_push_str(&r->aor); + bin_push_str(contact); + bin_push_str(ci->callid); + bin_push_str(ci->user_agent); + bin_push_str(ci->path); + bin_push_str(ci->attr); + bin_push_str(&ci->received); + bin_push_str(&ci->instance); + + st.s = (char *)&ci->expires; + st.len = sizeof ci->expires; + bin_push_str(&st); + + st.s = (char *)&ci->q; + st.len = sizeof ci->q; + bin_push_str(&st); + + bin_push_str(&ci->sock->sock_str); + bin_push_int(ci->cseq); + bin_push_int(ci->flags); + bin_push_int(ci->cflags); + bin_push_int(ci->methods); + + st.s = (char *)&ci->last_modified; + st.len = sizeof ci->last_modified; + bin_push_str(&st); + + for (d = replication_dests; d; d = d->next) + bin_send(&d->to); +} + +void replicate_ucontact_update(urecord_t *r, str *contact, ucontact_info_t *ci) +{ + struct replication_dest *d; + str st; + + if (bin_init(&repl_module_name, REPL_UCONTACT_UPDATE) != 0) { + LM_ERR("failed to replicate this event\n"); + return; + } + + bin_push_str(r->domain); + bin_push_str(&r->aor); + bin_push_str(contact); + bin_push_str(ci->callid); + bin_push_str(ci->user_agent); + bin_push_str(ci->path); + bin_push_str(ci->attr); + bin_push_str(&ci->received); + bin_push_str(&ci->instance); + + st.s = (char *)&ci->expires; + st.len = sizeof ci->expires; + bin_push_str(&st); + + st.s = (char *)&ci->q; + st.len = sizeof ci->q; + bin_push_str(&st); + + bin_push_str(&ci->sock->sock_str); + bin_push_int(ci->cseq); + bin_push_int(ci->flags); + bin_push_int(ci->cflags); + bin_push_int(ci->methods); + + st.s = (char *)&ci->last_modified; + st.len = sizeof ci->last_modified; + bin_push_str(&st); + + for (d = replication_dests; d; d = d->next) + bin_send(&d->to); +} + +void replicate_ucontact_delete(urecord_t *r, ucontact_t *c) +{ + struct replication_dest *d; + + if (bin_init(&repl_module_name, REPL_UCONTACT_DELETE) != 0) { + LM_ERR("failed to replicate this event\n"); + return; + } + + bin_push_str(r->domain); + bin_push_str(&r->aor); + bin_push_str(&c->c); + bin_push_str(&c->callid); + bin_push_int(c->cseq); + + for (d = replication_dests; d; d = d->next) + bin_send(&d->to); +} + +/* packet receiving */ + +/** + * Note: prevents the creation of any duplicate AoR + */ +static int receive_urecord_insert(void) +{ + str d, aor; + urecord_t *r; + udomain_t *domain; + + bin_pop_str(&d); + bin_pop_str(&aor); + + if (find_domain(&d, &domain) != 0) { + LM_ERR("domain '%.*s' is not local\n", d.len, d.s); + goto out_err; + } + + lock_udomain(domain, &aor); + + if (get_urecord(domain, &aor, &r) == 0) + goto out; + + if (insert_urecord(domain, &aor, &r, 1) != 0) { + unlock_udomain(domain, &aor); + goto out_err; + } + +out: + unlock_udomain(domain, &aor); + + return 0; + +out_err: + LM_ERR("failed to replicate event locally. dom: '%.*s', aor: '%.*s'\n", + d.len, d.s, aor.len, aor.s); + return -1; +} + +static int receive_urecord_delete(void) +{ + str d, aor; + udomain_t *domain; + + bin_pop_str(&d); + bin_pop_str(&aor); + + if (find_domain(&d, &domain) != 0) { + LM_ERR("domain '%.*s' is not local\n", d.len, d.s); + goto out_err; + } + + lock_udomain(domain, &aor); + + if (delete_urecord(domain, &aor, NULL, 1) != 0) { + unlock_udomain(domain, &aor); + goto out_err; + } + + unlock_udomain(domain, &aor); + + return 0; + +out_err: + LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n", + d.len, d.s, aor.len, aor.s); + return -1; +} + +static int receive_ucontact_insert(void) +{ + static ucontact_info_t ci; + static str d, aor, host, contact_str, callid, + user_agent, path, attr, st, sock; + udomain_t *domain; + urecord_t *record; + ucontact_t *contact; + int port, proto; + + bin_pop_str(&d); + bin_pop_str(&aor); + + if (find_domain(&d, &domain) != 0) { + LM_ERR("domain '%.*s' is not local\n", d.len, d.s); + goto error; + } + + bin_pop_str(&contact_str); + + bin_pop_str(&callid); + ci.callid = &callid; + + bin_pop_str(&user_agent); + ci.user_agent = &user_agent; + + bin_pop_str(&path); + ci.path = &path; + + bin_pop_str(&attr); + ci.attr = &attr; + + bin_pop_str(&ci.received); + bin_pop_str(&ci.instance); + + bin_pop_str(&st); + memcpy(&ci.expires, st.s, sizeof ci.expires); + + bin_pop_str(&st); + memcpy(&ci.q, st.s, sizeof ci.q); + + bin_pop_str(&sock); + + if (!sock.s || sock.s[0] == 0) { + LM_ERR("bad received socket: '%.*s'\n", sock.len, sock.s); + goto error; + } + + if (parse_phostport(sock.s, sock.len, &host.s, &host.len, + &port, &proto) != 0) { + LM_ERR("bad socket <%.*s>\n", sock.len, sock.s); + goto error; + } + + ci.sock = grep_sock_info(&host, (unsigned short)port, (unsigned short)proto); + if (!ci.sock) { + LM_ERR("non-local socket <%.*s>\n", sock.len, sock.s); + goto error; + } + + bin_pop_int(&ci.cseq); + bin_pop_int(&ci.flags); + bin_pop_int(&ci.cflags); + bin_pop_int(&ci.methods); + + bin_pop_str(&st); + memcpy(&ci.last_modified, st.s, sizeof ci.last_modified); + + if (skip_replicated_db_ops) + ci.flags |= FL_MEM; + + lock_udomain(domain, &aor); + + if (get_urecord(domain, &aor, &record) != 0) { + LM_INFO("failed to fetch local urecord - creating new one " + "(ci: '%.*s') \n", callid.len, callid.s); + + if (insert_urecord(domain, &aor, &record, 1) != 0) { + LM_ERR("failed to insert new record\n"); + unlock_udomain(domain, &aor); + goto error; + } + } + + if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) { + LM_ERR("failed to insert ucontact (ci: '%.*s')\n", callid.len, callid.s); + unlock_udomain(domain, &aor); + goto error; + } + + unlock_udomain(domain, &aor); + + return 0; + +error: + LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n", + d.len, d.s, aor.len, aor.s); + return -1; +} + +static int receive_ucontact_update(void) +{ + static ucontact_info_t ci; + static str d, aor, host, contact_str, callid, + user_agent, path, attr, st, sock; + udomain_t *domain; + urecord_t *record; + ucontact_t *contact; + int port, proto; + int rc; + + bin_pop_str(&d); + bin_pop_str(&aor); + + if (find_domain(&d, &domain) != 0) { + LM_ERR("domain '%.*s' is not local\n", d.len, d.s); + goto error; + } + + bin_pop_str(&contact_str); + + bin_pop_str(&callid); + ci.callid = &callid; + + bin_pop_str(&user_agent); + ci.user_agent = &user_agent; + + bin_pop_str(&path); + ci.path = &path; + + bin_pop_str(&attr); + ci.attr = &attr; + + bin_pop_str(&ci.received); + bin_pop_str(&ci.instance); + + bin_pop_str(&st); + memcpy(&ci.expires, st.s, sizeof ci.expires); + + bin_pop_str(&st); + memcpy(&ci.q, st.s, sizeof ci.q); + + bin_pop_str(&sock); + + if (!sock.s || sock.s[0] == 0) { + LM_ERR("bad received socket: '%.*s'\n", sock.len, sock.s); + goto error; + } + + if (parse_phostport(sock.s, sock.len, &host.s, &host.len, + &port, &proto) != 0) { + LM_ERR("bad socket <%.*s>\n", sock.len, sock.s); + goto error; + } + + ci.sock = grep_sock_info(&host, (unsigned short)port, (unsigned short)proto); + if (!ci.sock) { + LM_ERR("non-local socket <%.*s>\n", sock.len, sock.s); + goto error; + } + + bin_pop_int(&ci.cseq); + bin_pop_int(&ci.flags); + bin_pop_int(&ci.cflags); + bin_pop_int(&ci.methods); + + bin_pop_str(&st); + memcpy(&ci.last_modified, st.s, sizeof ci.last_modified); + + if (skip_replicated_db_ops) + ci.flags |= FL_MEM; + + lock_udomain(domain, &aor); + + /* failure in retrieving a urecord may be ok, because packet order in UDP + * is not guaranteed, so update commands may arrive before inserts */ + if (get_urecord(domain, &aor, &record) != 0) { + LM_INFO("failed to fetch local urecord - create new record and contact" + " (ci: '%.*s')\n", callid.len, callid.s); + + if (insert_urecord(domain, &aor, &record, 1) != 0) { + LM_ERR("failed to insert urecord\n"); + unlock_udomain(domain, &aor); + goto error; + } + + if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) { + LM_ERR("failed (ci: '%.*s')\n", callid.len, callid.s); + unlock_udomain(domain, &aor); + goto error; + } + } else { + rc = get_ucontact(record, &contact_str, &callid, ci.cseq + 1, &contact); + if (rc != 0 && rc != -2) { + LM_INFO("contact '%.*s' not found, inserting new (ci: '%.*s')\n", + contact_str.len, contact_str.s, callid.len, callid.s); + + if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) { + LM_ERR("failed to insert ucontact (ci: '%.*s')\n", + callid.len, callid.s); + unlock_udomain(domain, &aor); + goto error; + } + } else { + if (update_ucontact(record, contact, &ci, 1) != 0) { + LM_ERR("failed to update ucontact '%.*s' (ci: '%.*s')\n", + contact_str.len, contact_str.s, callid.len, callid.s); + unlock_udomain(domain, &aor); + goto error; + } + } + } + + unlock_udomain(domain, &aor); + + return 0; + +error: + LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n", + d.len, d.s, aor.len, aor.s); + return -1; +} + +static int receive_ucontact_delete(void) +{ + udomain_t *domain; + urecord_t *record; + ucontact_t *contact; + str d, aor, contact_str, callid; + int cseq, rc; + + bin_pop_str(&d); + bin_pop_str(&aor); + bin_pop_str(&contact_str); + bin_pop_str(&callid); + bin_pop_int(&cseq); + + if (find_domain(&d, &domain) != 0) { + LM_ERR("domain '%.*s' is not local\n", d.len, d.s); + goto error; + } + + lock_udomain(domain, &aor); + + /* failure in retrieving a urecord may be ok, because packet order in UDP + * is not guaranteed, so urecord_delete commands may arrive before + * ucontact_delete's */ + if (get_urecord(domain, &aor, &record) != 0) { + LM_INFO("failed to fetch local urecord - ignoring request " + "(ci: '%.*s')\n", callid.len, callid.s); + unlock_udomain(domain, &aor); + return 0; + } + + /* simply specify a higher cseq and completely avoid any complications */ + rc = get_ucontact(record, &contact_str, &callid, cseq + 1, &contact); + if (rc != 0 && rc != 2) { + LM_ERR("contact '%.*s' not found: (ci: '%.*s')\n", contact_str.len, + contact_str.s, callid.len, callid.s); + unlock_udomain(domain, &aor); + goto error; + } + + if (skip_replicated_db_ops) + contact->flags |= FL_MEM; + + if (delete_ucontact(record, contact, 1) != 0) { + LM_ERR("failed to delete ucontact '%.*s' (ci: '%.*s')\n", + contact_str.len, contact_str.s, callid.len, callid.s); + unlock_udomain(domain, &aor); + goto error; + } + + unlock_udomain(domain, &aor); + + return 0; + +error: + LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n", + d.len, d.s, aor.len, aor.s); + return -1; +} + +void receive_binary_packet(int packet_type) +{ + int rc; + + LM_DBG("received a binary packet [%d]!\n", packet_type); + + switch (packet_type) { + case REPL_URECORD_INSERT: + rc = receive_urecord_insert(); + break; + + case REPL_URECORD_DELETE: + rc = receive_urecord_delete(); + break; + + case REPL_UCONTACT_INSERT: + rc = receive_ucontact_insert(); + break; + + case REPL_UCONTACT_UPDATE: + rc = receive_ucontact_update(); + break; + + case REPL_UCONTACT_DELETE: + rc = receive_ucontact_delete(); + break; + + default: + rc = -1; + LM_ERR("invalid usrloc binary packet type: %d\n", packet_type); + } + + if (rc != 0) + LM_ERR("failed to process a binary packet!\n"); +} + diff --git a/modules/usrloc/ureplication.h b/modules/usrloc/ureplication.h new file mode 100644 index 00000000000..388a9c0699b --- /dev/null +++ b/modules/usrloc/ureplication.h @@ -0,0 +1,63 @@ +/* + * Usrloc record and contact replication + * + * Copyright (C) 2013 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * -------- + * 2013-10-09 initial version (Liviu) + */ + +#ifndef _USRLOC_REPLICATION_H_ +#define _USRLOC_REPLICATION_H_ + +#include "../../ut.h" +#include "../../bin_interface.h" +#include "../../socket_info.h" +#include "../../resolve.h" +#include "../../timer.h" + +#include "urecord.h" + +#define REPL_URECORD_INSERT 1 +#define REPL_URECORD_DELETE 2 +#define REPL_UCONTACT_INSERT 3 +#define REPL_UCONTACT_UPDATE 4 +#define REPL_UCONTACT_DELETE 5 + +extern int accept_replicated_udata; +extern struct replication_dest *replication_dests; +extern str repl_module_name; + +struct replication_dest { + union sockaddr_union to; + struct replication_dest *next; +}; + +/* duplicate local events to other OpenSIPS instances */ +void replicate_urecord_insert(urecord_t *r); +void replicate_urecord_delete(urecord_t *r); +void replicate_ucontact_insert(urecord_t *r, str *contact, ucontact_info_t *ci); +void replicate_ucontact_update(urecord_t *r, str *contact, ucontact_info_t *ci); +void replicate_ucontact_delete(urecord_t *r, ucontact_t *c); + +void receive_binary_packet(int packet_type); + +#endif /* _USRLOC_REPLICATION_H_ */ + diff --git a/modules/usrloc/usrloc.c b/modules/usrloc/usrloc.c index a44afa6e6e6..38edcf1afc2 100644 --- a/modules/usrloc/usrloc.c +++ b/modules/usrloc/usrloc.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/usrloc/usrloc.h b/modules/usrloc/usrloc.h index f56ef9c4e40..17f1448f8de 100644 --- a/modules/usrloc/usrloc.h +++ b/modules/usrloc/usrloc.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/usrloc/utime.c b/modules/usrloc/utime.c index f0964d05adb..e0a491bed5a 100644 --- a/modules/usrloc/utime.c +++ b/modules/usrloc/utime.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/usrloc/utime.h b/modules/usrloc/utime.h index 354c041fea6..4661c4c2ab1 100644 --- a/modules/usrloc/utime.h +++ b/modules/usrloc/utime.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/modules/xcap/README b/modules/xcap/README index 7a47a201833..cd40e3c57aa 100644 --- a/modules/xcap/README +++ b/modules/xcap/README @@ -34,10 +34,12 @@ Saul Ibarra Corretge 2. Developer Guide 2.1. bind_xcap_api(xcap_api_t* api) - 2.2. parse_xcap_uri - 2.3. db_url - 2.4. xcap_table - 2.5. integrated_server + 2.2. normalize_xcap_uri + 2.3. parse_xcap_uri + 2.4. get_xcap_doc + 2.5. db_url + 2.6. xcap_table + 2.7. integrated_server List of Examples @@ -129,15 +131,27 @@ typedef struct xcap_api { int integrated_server; str db_url; str xcap_table; + normalize_sip_uri_t normalize_sip_uri; parse_xcap_uri_t parse_xcap_uri; + get_xcap_doc_t get_xcap_doc; } xcap_api_t; ... -2.2. parse_xcap_uri +2.2. normalize_xcap_uri + + This function normalizes a SIP URI found in a XCAP document. It + un-escapes it and adds the SIP scheme in case it was missing. + Returns a statically allocated string buffer containing the + normalized form. + + Parameters: + * uri- the URI that needs to be normalized + +2.3. parse_xcap_uri This function parses the given XCAP URI. - The parameters signification: + Parameters: * uri- the URI that needs to be parsed in string format * xcap_uri- xcap_uri_t structure that will be filled with the parsed information @@ -155,16 +169,36 @@ typedef struct { } xcap_uri_t; ... -2.3. db_url +2.4. get_xcap_doc + + This function queries the local DB for the required XCAP + document. It will return the document and its corresponding + etag. + + Parameters: + * user- user part od the URI of the document owner + * domain- domain part od the URI of the document owner + * type- type of the requested document, represents the AUID, + can be one of PRES_RULES, RESOURCE_LISTS, RLS_SERVICES, + PIDF_MANIPULATION, OMA_PRES_RULES + * filename- if specified it will be used to match the + document filename, it defaults to 'index' + * match_etag- if specified the document is only returned its + etag matches this one + * doc- reference to the storage for the returned document + * etag- reference to the storage for the returned document's + etag + +2.5. db_url URL of the database to which the XCAP mdoules witll connect. -2.4. xcap_table +2.6. xcap_table Name of the table used to store XCAP documents. Defaults to 'xcap'. -2.5. integrated_server +2.7. integrated_server Boolean flag indicating if the XCAP server has access to the local database or xcap_client will be used to fetch documents. diff --git a/modules/xcap/xcap_mod.c b/modules/xcap/xcap_mod.c index aa0e6d941ad..948d734d718 100644 --- a/modules/xcap/xcap_mod.c +++ b/modules/xcap/xcap_mod.c @@ -66,11 +66,23 @@ static param_export_t params[]={ { 0, 0, 0 } }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_SQLDB, NULL, DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports = { "xcap", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ diff --git a/modules/xcap_client/README b/modules/xcap_client/README index cc4a86b948d..937c554db77 100644 --- a/modules/xcap_client/README +++ b/modules/xcap_client/README @@ -2,8 +2,6 @@ XCAP_Client Module Anca-Maria Vamanu - Voice Sistem SRL - Edited by Anca-Maria Vamanu @@ -14,8 +12,7 @@ Saul Ibarra Corretge Copyright © 2007 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2012-11-14 17:46:37 +0100 - (Wed, 14 Nov 2012) $ + Revision $Revision: 9442 $ $Date$ __________________________________________________________ Table of Contents @@ -259,7 +256,8 @@ typedef int (*register_xcapcb_t)(int types, xcap_cb f); ... - 'types' parameter can have a combined value of PRES_RULES, - RESOURCE_LIST, RLS_SERVICES and PIDF_MANIPULATION. + RESOURCE_LISTS, RLS_SERVICES, OMA_PRES_RULES and + PIDF_MANIPULATION. -the callback function has type : ... diff --git a/modules/xcap_client/xcap_callbacks.c b/modules/xcap_client/xcap_callbacks.c index 0bbbf8817a4..51beaacec1d 100644 --- a/modules/xcap_client/xcap_callbacks.c +++ b/modules/xcap_client/xcap_callbacks.c @@ -17,10 +17,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * *History: *-------- * 2007-08-30 initial version (anca) @@ -40,8 +40,8 @@ void run_xcap_update_cb(int type, str xid, char* stream) for (cb= xcapcb_list; cb; cb=cb->next) { - if(cb->types & type) - { + if(cb->types & type) + { LM_DBG("found callback\n"); cb->callback(type, xid, stream); } @@ -72,12 +72,12 @@ int register_xcapcb( int types, xcap_cb f) void destroy_xcapcb_list(void) { xcap_callback_t* xcb, *prev_xcb; - + xcb= xcapcb_list; while(xcb) { - prev_xcb= xcb; - xcb= xcb->next; - shm_free(xcb); + prev_xcb=xcb; + xcb=xcb->next; + shm_free(prev_xcb); } } diff --git a/modules/xcap_client/xcap_callbacks.h b/modules/xcap_client/xcap_callbacks.h index 4a7937e138d..8eb1fb5ad6a 100644 --- a/modules/xcap_client/xcap_callbacks.h +++ b/modules/xcap_client/xcap_callbacks.h @@ -17,10 +17,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * *History: *-------- * 2007-08-30 initial version (Anca Vamanu) diff --git a/modules/xcap_client/xcap_client.c b/modules/xcap_client/xcap_client.c index 776db3489ae..a8da5135a82 100644 --- a/modules/xcap_client/xcap_client.c +++ b/modules/xcap_client/xcap_client.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -101,11 +101,24 @@ static mi_export_t mi_cmds[] = { { 0, 0, 0, 0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "xcap", DEP_ABORT }, + { MOD_TYPE_SQLDB, NULL, DEP_SILENT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /** module exports */ struct module_exports exports= { "xcap_client", /* module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ @@ -148,7 +161,7 @@ static int mod_init(void) LM_ERR("Database module not found\n"); return -1; } - + if (!DB_CAPABILITY(xcap_dbf, DB_CAP_ALL)) { LM_ERR("Database module does not implement all functions" " needed by the module\n"); @@ -168,7 +181,7 @@ static int mod_init(void) { register_timer("xcapc-update", query_xcap_update, 0, query_period); } - + if(xcap_db) xcap_dbf.close(xcap_db); xcap_db = NULL; @@ -208,8 +221,8 @@ void query_xcap_update(unsigned int ticks, void* param) db_key_t result_cols[7]; int n_result_cols = 0, n_query_cols= 0, n_update_cols= 0; db_res_t* result= NULL; - int user_col, domain_col, doc_type_col, etag_col, doc_uri_col, port_col; - db_row_t *row ; + int user_col, domain_col, doc_type_col, etag_col, doc_uri_col, port_col; + db_row_t *row ; db_val_t *row_vals ; unsigned int port; char* etag, *path, *new_etag= NULL; @@ -245,8 +258,8 @@ void query_xcap_update(unsigned int ticks, void* param) result_cols[etag_col=n_result_cols++] = &str_etag_col; result_cols[doc_uri_col= n_result_cols++] = &str_doc_uri_col; result_cols[port_col= n_result_cols++] = &str_port_col; - - if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0) + + if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0) { LM_ERR("in use_table-[table]= %.*s\n", xcap_db_table.len, xcap_db_table.s); goto error; @@ -269,13 +282,13 @@ void query_xcap_update(unsigned int ticks, void* param) return; } n_query_cols++; - + /* ask if updated */ for(i= 0; i< result->n; i++) { row = &result->rows[i]; row_vals = ROW_VALUES(row); - + path= (char*)row_vals[doc_uri_col].val.string_val; port= row_vals[port_col].val.int_val; etag= (char*)row_vals[etag_col].val.string_val; @@ -332,17 +345,17 @@ void query_xcap_update(unsigned int ticks, void* param) int parse_doc_url(str doc_url, char** serv_addr, xcap_doc_sel_t* doc_sel) { - char* sl, *str_type; - + char* sl, *str_type; + sl= strchr(doc_url.s, '/'); *sl= '\0'; *serv_addr= doc_url.s; - + sl++; doc_sel->auid.s= sl; sl= strchr(sl, '/'); doc_sel->auid.len= sl- doc_sel->auid.s; - + sl++; str_type= sl; sl= strchr(sl, '/'); @@ -361,7 +374,7 @@ int parse_doc_url(str doc_url, char** serv_addr, xcap_doc_sel_t* doc_sel) } /* * mi cmd: refreshXcapDoc - * + * * * */ @@ -410,7 +423,7 @@ struct mi_root* refreshXcapDoc(struct mi_root* cmd, void* param) LM_ERR("in http get\n"); return 0; } - + /* call registered functions with document argument */ if(parse_doc_url(doc_url, &serv_addr, &doc_sel)< 0) { diff --git a/modules/xcap_client/xcap_client.h b/modules/xcap_client/xcap_client.h index 2a7069ff8d0..240dfeb95e1 100644 --- a/modules/xcap_client/xcap_client.h +++ b/modules/xcap_client/xcap_client.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/modules/xcap_client/xcap_functions.c b/modules/xcap_client/xcap_functions.c index 6b4a689e802..cb61e9be22e 100644 --- a/modules/xcap_client/xcap_functions.c +++ b/modules/xcap_client/xcap_functions.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -50,7 +50,7 @@ char* get_xcap_path(xcap_get_req_t req); int bind_xcap_client(xcap_client_api_t* api) { - if (!api) + if (!api) { LM_ERR("Invalid parameter value\n"); return -1; @@ -62,7 +62,7 @@ int bind_xcap_client(xcap_client_api_t* api) api->free_node_sel= xcapFreeNodeSel; api->register_xcb= register_xcapcb; api->getNewDoc= xcapGetNewDoc; - + return 0; } @@ -83,10 +83,10 @@ void xcapFreeNodeSel(xcap_node_sel_t* node) n= node->ns_list; while(n) { - m= n; - n= n->next; - pkg_free(n->value.s); - pkg_free(n); + m=n; + n=n->next; + pkg_free(m->value.s); + pkg_free(m); } pkg_free(node); @@ -156,7 +156,7 @@ xcap_node_sel_t* xcapNodeSelAddStep(xcap_node_sel_t* curr_sel, str* name, size+= 2+ attr_test->name.len+ attr_test->value.len; if(extra_sel) size+= 2+ extra_sel->len; - + new_step.s= (char*)pkg_malloc(size* sizeof(char)); if(new_step.s== NULL) { @@ -174,7 +174,7 @@ xcap_node_sel_t* xcapNodeSelAddStep(xcap_node_sel_t* curr_sel, str* name, LM_ERR("Insuficient name cards for namespaces\n"); goto error; } - new_step.len= sprintf(new_step.s, "%c:", ns_card); + new_step.len= sprintf(new_step.s, "%c:", ns_card); } memcpy(new_step.s+new_step.len, name->s, name->len); new_step.len+= name->len; @@ -233,7 +233,7 @@ xcap_node_sel_t* xcapNodeSelAddStep(xcap_node_sel_t* curr_sel, str* name, { curr_sel->size+= namespace->len+ 3; } - + return curr_sel; error: @@ -251,7 +251,7 @@ xcap_node_sel_t* xcapNodeSelAddStep(xcap_node_sel_t* curr_sel, str* name, return NULL; } -xcap_node_sel_t* xcapNodeSelAddTerminal(xcap_node_sel_t* curr_sel, +xcap_node_sel_t* xcapNodeSelAddTerminal(xcap_node_sel_t* curr_sel, char* attr_sel, char* namespace_sel, char* extra_sel ) { @@ -287,14 +287,14 @@ char* get_node_selector(xcap_node_sel_t* node_sel) if(ns_elem) buf[len++]= '?'; - + while(ns_elem) { len+= sprintf(buf+ len, "xmlns(%c=%.*s)", ns_elem->name, ns_elem->value.len, ns_elem->value.s); ns_elem= ns_elem->next; } - + buf[len]= '\0'; return buf; @@ -303,7 +303,7 @@ char* get_node_selector(xcap_node_sel_t* node_sel) return NULL; } -int xcapGetNewDoc(xcap_get_req_t req, str user, +int xcapGetNewDoc(xcap_get_req_t req, str user, str domain, str* xcap_doc) { char* etag= NULL; @@ -340,13 +340,13 @@ int xcapGetNewDoc(xcap_get_req_t req, str user, query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = user; n_query_cols++; - + query_cols[n_query_cols] = &str_domain_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val = domain; n_query_cols++; - + query_cols[n_query_cols] = &str_doc_type_col; query_vals[n_query_cols].type = DB_INT; query_vals[n_query_cols].nul = 0; @@ -376,19 +376,19 @@ int xcapGetNewDoc(xcap_get_req_t req, str user, query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.string_val= path; n_query_cols++; - + query_cols[n_query_cols] = &str_port_col; query_vals[n_query_cols].type = DB_INT; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.int_val= req.port; n_query_cols++; - if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0) + if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0) { LM_ERR("in use_table-[table]= %.*s\n", xcap_db_table.len, xcap_db_table.s); goto error; } - + if(xcap_dbf.insert(xcap_db, query_cols, query_vals, n_query_cols)< 0) { LM_ERR("in sql insert\n"); @@ -401,7 +401,7 @@ int xcapGetNewDoc(xcap_get_req_t req, str user, error: pkg_free(path); if(doc.s) - pkg_free(doc.s); + pkg_free(doc.s); return -1; } @@ -413,7 +413,7 @@ char* get_xcap_path(xcap_get_req_t req) len= (strlen(req.xcap_root)+ 1+ req.doc_sel.auid.len+ 5+ req.doc_sel.xid.len+ req.doc_sel.filename.len+ 50)* sizeof(char); - + if(req.node_sel) len+= req.node_sel->size; @@ -432,7 +432,7 @@ char* get_xcap_path(xcap_get_req_t req) goto error; } } - + size= sprintf(path, "%s/%.*s/", req.xcap_root, req.doc_sel.auid.len, req.doc_sel.auid.s); @@ -443,7 +443,7 @@ char* get_xcap_path(xcap_get_req_t req) size+= sprintf(path+ size, "%s/", "global"); size+= sprintf(path+ size, "%.*s", req.doc_sel.filename.len, req.doc_sel.filename.s); - + if(node_selector) { size+= sprintf(path+ size, "/~~%s", node_selector); @@ -454,12 +454,12 @@ char* get_xcap_path(xcap_get_req_t req) LM_ERR("buffer size overflow\n"); goto error; } - + if(node_selector) pkg_free(node_selector); return path; - + error: if(path) pkg_free(path); @@ -474,7 +474,7 @@ char* xcapGetElem(xcap_get_req_t req, char** etag) { char* path= NULL; str stream= {0, 0}; - + path= get_xcap_path(req); if(path== NULL) { @@ -487,7 +487,7 @@ char* xcapGetElem(xcap_get_req_t req, char** etag) { LM_DBG("the serched element was not found\n"); } - + if(etag== NULL) { LM_ERR("no etag found\n"); @@ -497,7 +497,7 @@ char* xcapGetElem(xcap_get_req_t req, char** etag) if(path) pkg_free(path); - + return stream.s; } @@ -542,14 +542,14 @@ char* send_http_get(char* path, unsigned int xcap_port, char* match_etag, if(match_etag) { char* hdr_name= NULL; - + memset(buf, 0, 128); match_header= buf; - - hdr_name= (match_type==IF_MATCH)?"If-Match":"If-None-Match"; - + + hdr_name= (match_type==IF_MATCH)?"If-Match":"If-None-Match"; + len=sprintf(match_header, "%s: %s", hdr_name, match_etag); - + match_header[len]= '\0'; LM_DBG("match_header = %s\n", match_header); } @@ -557,21 +557,21 @@ char* send_http_get(char* path, unsigned int xcap_port, char* match_etag, LM_DBG("path = [%s]\n", path); curl_handle = curl_easy_init(); - + curl_easy_setopt(curl_handle, CURLOPT_URL, path); - + curl_easy_setopt(curl_handle, CURLOPT_PORT, xcap_port); curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl_handle, CURLOPT_STDERR, stdout); - + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_function); - + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &buff); curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, get_xcap_etag); - + curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, etag); curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, err_buff); @@ -586,7 +586,7 @@ char* send_http_get(char* path, unsigned int xcap_port, char* match_etag, curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); ret_code= curl_easy_perform(curl_handle ); - + if( ret_code!=0) { LM_ERR("Error [%i] while performing curl operation\n", ret_code); LM_ERR("[%s]\n", err_buff); @@ -618,16 +618,16 @@ size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream) int len = (int)(size*nmemb); str* buff = (str*) stream; - if (len == -1) + if (len == -1) len=strlen(s); - if (len == 0) + if (len == 0) return buff->len; if(buff->len + len == 0) return 0; newData= (char*)pkg_realloc(buff->s, buff->len + len + 1); - if(newData== NULL) + if(newData== NULL) { LM_ERR("No more memory\n"); ERR_MEM(PKG_MEM_STR); diff --git a/modules/xcap_client/xcap_functions.h b/modules/xcap_client/xcap_functions.h index eddcd5a9d7d..26092bda50e 100644 --- a/modules/xcap_client/xcap_functions.h +++ b/modules/xcap_client/xcap_functions.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -48,7 +48,7 @@ typedef struct xcap_doc_sel { str auid; int doc_type; - int type; + int type; str xid; str filename; }xcap_doc_sel_t; @@ -102,10 +102,10 @@ xcap_node_sel_t* xcapNodeSelAddStep(xcap_node_sel_t* curr_sel, str* name, typedef xcap_node_sel_t* (*xcap_nodeSel_add_step_t)(xcap_node_sel_t* curr_sel, str* name,str* namespace,int pos,attr_test_t* attr_test,str* extra_sel); -xcap_node_sel_t* xcapNodeSelAddTerminal(xcap_node_sel_t* curr_sel, +xcap_node_sel_t* xcapNodeSelAddTerminal(xcap_node_sel_t* curr_sel, char* attr_sel, char* namespace_sel, char* extra_sel ); -typedef xcap_node_sel_t* (*xcap_nodeSel_add_terminal_t)(xcap_node_sel_t* curr_sel, +typedef xcap_node_sel_t* (*xcap_nodeSel_add_terminal_t)(xcap_node_sel_t* curr_sel, char* attr_sel, char* namespace_sel, char* extra_sel ); /* generical function to get an element from an xcap server */ @@ -117,7 +117,7 @@ void xcapFreeNodeSel(xcap_node_sel_t* node); typedef void (*xcap_nodeSel_free_t)(xcap_node_sel_t* node); -/* specifical function to get a new document, not present in xcap table +/* specifical function to get a new document, not present in xcap table * to be updated and handled by the xcap_client module*/ typedef int (*xcapGetNewDoc_t)(xcap_get_req_t req, str user, str domain, str* xcap_doc); @@ -139,6 +139,6 @@ typedef int (*bind_xcap_client_t)(xcap_client_api_t* api); char* send_http_get(char* path, unsigned int xcap_port, char* match_etag, int match_type, char** etag, int* doc_len); -int xcapGetNewDoc(xcap_get_req_t req, str user, +int xcapGetNewDoc(xcap_get_req_t req, str user, str domain, str* xcap_doc); #endif diff --git a/modules/xmpp/README b/modules/xmpp/README index 1bbe7529d7c..b49658d1afa 100644 --- a/modules/xmpp/README +++ b/modules/xmpp/README @@ -10,10 +10,9 @@ Andreea Spirea - Copyright © 2006-2008 voice-system.ro + Copyright © 2006-2008 Voice Sistem SRL Revision History - Revision $Revision$ $Date: 2009-07-21 10:45:05 +0300 - (Tue, 21 Jul 2009) $ + Revision $Revision: 5901 $ $Date$ __________________________________________________________ Table of Contents diff --git a/modules/xmpp/network.c b/modules/xmpp/network.c index 9aea9a36bdb..123b21b917d 100644 --- a/modules/xmpp/network.c +++ b/modules/xmpp/network.c @@ -44,16 +44,16 @@ int net_listen(char *server, int port) int fd; struct sockaddr_in sin; int on = 1; - + memset(&sin, 0, sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons(port); - + if (!inet_aton(server, &sin.sin_addr)) { struct hostent *host; - + LM_DBG("resolving %s...\n", server); - + if (!(host = resolvehost(server,0))) { LM_ERR("resolving %s failed (%s).\n", server, hstrerror(h_errno)); @@ -61,14 +61,14 @@ int net_listen(char *server, int port) } memcpy(&sin.sin_addr, host->h_addr_list[0], host->h_length); } - + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { LM_ERR("socket() failed: %s\n", strerror(errno)); return -1; } - + LM_DBG("listening on %s:%d\n", inet_ntoa(sin.sin_addr), port); - + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { LM_WARN("setsockopt(SO_REUSEADDR) failed: %s\n",strerror(errno)); } @@ -92,16 +92,16 @@ int net_connect(char *server, int port) { int fd; struct sockaddr_in sin; - + memset(&sin, 0, sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons(port); - + if (!inet_aton(server, &sin.sin_addr)) { struct hostent *host; - + LM_DBG("resolving %s...\n", server); - + if (!(host = resolvehost(server,0))) { LM_ERR("resolving %s failed (%s).\n", server, hstrerror(h_errno)); @@ -109,14 +109,14 @@ int net_connect(char *server, int port) } memcpy(&sin.sin_addr, host->h_addr_list[0], host->h_length); } - + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { LM_ERR("socket() failed: %s\n", strerror(errno)); return -1; } - + LM_DBG("connecting to %s:%d...\n", inet_ntoa(sin.sin_addr), port); - + if (connect(fd, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) { LM_ERR("connect() failed: %s\n", strerror(errno)); close(fd); @@ -147,13 +147,13 @@ int net_printf(int fd, char *format, ...) { va_list args; char buf[4096]; - + va_start(args, format); vsnprintf(buf, sizeof(buf) - 1, format, args); va_end(args); LM_DBG("net_printf: [%s]\n", buf); - + return net_send(fd, buf, strlen(buf)); } diff --git a/modules/xmpp/sha.c b/modules/xmpp/sha.c index 23494c2a90c..9202e9e327d 100644 --- a/modules/xmpp/sha.c +++ b/modules/xmpp/sha.c @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * + * * Gabber * Copyright (C) 1999-2000 Dave Smith & Julian Missig * @@ -22,7 +22,7 @@ -/* +/* Implements the Secure Hash Algorithm (SHA1) Copyright (C) 1999 Scott G. Miller @@ -30,12 +30,12 @@ Released under the terms of the GNU General Public License v2 see file COPYING for details - Credits: - Robert Klep -- Expansion function fix + Credits: + Robert Klep -- Expansion function fix Thomas "temas" Muldowney : -- shahash() for string fun -- Will add the int32 stuff in a few - + --- FIXME: This source takes int to be a 32 bit integer. This may vary from system to system. I'd use autoconf if I was familiar @@ -67,7 +67,7 @@ (x>>24 & 0x000000ff) /* Initial hash values */ -#define Ai 0x67452301 +#define Ai 0x67452301 #define Bi 0xefcdab89 #define Ci 0x98badcfe #define Di 0x10325476 @@ -76,7 +76,7 @@ /* SHA1 round constants */ #define K1 0x5a827999 #define K2 0x6ed9eba1 -#define K3 0x8f1bbcdc +#define K3 0x8f1bbcdc #define K4 0xca62c1d6 /* Round functions. Note that f2() is used in both rounds 2 and 4 */ @@ -94,34 +94,34 @@ 32 bit ints), into the ongoing 160 bit hash value (five 32 bit ints) 'hash' */ -int -sha_hash(int *data, int *hash) +int +sha_hash(int *data, int *hash) { int W[80]; unsigned int A=hash[0], B=hash[1], C=hash[2], D=hash[3], E=hash[4]; unsigned int t, x, TEMP; - for (t=0; t<16; t++) + for (t=0; t<16; t++) { #ifndef WORDS_BIGENDIAN W[t]=switch_endianness(data[t]); -#else +#else W[t]=data[t]; #endif } /* SHA1 Data expansion */ - for (t=16; t<80; t++) + for (t=16; t<80; t++) { x=W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]; W[t]=rol1(x); } - /* SHA1 main loop (t=0 to 79) + /* SHA1 main loop (t=0 to 79) This is broken down into four subloops in order to use the correct round function and constant */ - for (t=0; t<20; t++) + for (t=0; t<20; t++) { TEMP=rol5(A) + f1(B,C,D) + E + W[t] + K1; E=D; @@ -130,7 +130,7 @@ sha_hash(int *data, int *hash) B=A; A=TEMP; } - for (; t<40; t++) + for (; t<40; t++) { TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K2; E=D; @@ -139,7 +139,7 @@ sha_hash(int *data, int *hash) B=A; A=TEMP; } - for (; t<60; t++) + for (; t<60; t++) { TEMP=rol5(A) + f3(B,C,D) + E + W[t] + K3; E=D; @@ -148,7 +148,7 @@ sha_hash(int *data, int *hash) B=A; A=TEMP; } - for (; t<80; t++) + for (; t<80; t++) { TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K4; E=D; @@ -157,7 +157,7 @@ sha_hash(int *data, int *hash) B=A; A=TEMP; } - hash[0]+=A; + hash[0]+=A; hash[1]+=B; hash[2]+=C; hash[3]+=D; @@ -170,8 +170,8 @@ sha_hash(int *data, int *hash) initializes it to the start constants of the SHA1 algorithm. This must be called before using hash in the call to sha_hash */ -int -sha_init(int *hash) +int +sha_init(int *hash) { hash[0]=Ai; hash[1]=Bi; @@ -181,11 +181,11 @@ sha_init(int *hash) return 0; } -int strprintsha(char *dest, int *hashval) +int strprintsha(char *dest, int *hashval) { int x; char *hashstr = dest; - for (x=0; x<5; x++) + for (x=0; x<5; x++) { snprintf(hashstr, 9, "%08x", hashval[x]); hashstr+=8; @@ -198,12 +198,12 @@ int strprintsha(char *dest, int *hashval) return 0; } -char *shahash(const char *str) +char *shahash(const char *str) { char read_buffer[65]; //int read_buffer[64]; int c=1, i; - + INT64 length=0; int strsz; @@ -216,43 +216,43 @@ char *shahash(const char *str) strsz = strlen(str); - if(strsz == 0) + if(strsz == 0) { memset(read_buffer, 0, 65); read_buffer[0] = 0x80; sha_hash((int *)read_buffer, hashval); } - while (strsz>0) + while (strsz>0) { memset(read_buffer, 0, 65); strncpy((char*)read_buffer, str, 64); c = strlen((char *)read_buffer); length+=c; strsz-=c; - if (strsz<=0) + if (strsz<=0) { - length<<=3; + length<<=3; read_buffer[c]=(char)0x80; - for (i=c+1; i<64; i++) + for (i=c+1; i<64; i++) read_buffer[i]=0; - if (c>55) + if (c>55) { /* we need to do an entire new block */ sha_hash((int *)read_buffer, hashval); - for (i=0; i<14; i++) + for (i=0; i<14; i++) ((int*)read_buffer)[i]=0; - } + } #ifndef WORDS_BIGENDIAN - for (i=0; i<8; i++) + for (i=0; i<8; i++) { read_buffer[56+i]=(char)(length>>(56-(i*8))) & 0xff; } -#else +#else memcpy(read_buffer+56, &length, 8); #endif } - + sha_hash((int *)read_buffer, hashval); str+=64; } diff --git a/modules/xmpp/util.c b/modules/xmpp/util.c index 6e107296833..630ed703c4e 100644 --- a/modules/xmpp/util.c +++ b/modules/xmpp/util.c @@ -92,7 +92,7 @@ char* uri_xmpp2sip(char* uri, int* len) } else user.len = strlen(uri); - + if(5 + user.len > 256) { LM_ERR("Buffer overflow\n"); @@ -133,7 +133,7 @@ char* uri_xmpp2sip(char* uri, int* len) char *extract_domain(char *jid) { char *p; - + if ((p = strchr(jid, '/'))) *p = 0; if ((p = strchr(jid, '@'))) { @@ -161,7 +161,7 @@ char *db_key(char *secret, char *domain, char *id) { char buf[1024]; char *hash; - + snprintf(buf, sizeof(buf), "%s", secret); hash = shahash(buf); diff --git a/modules/xmpp/xmpp.c b/modules/xmpp/xmpp.c index 51f7100c0fb..d39cf67f39b 100644 --- a/modules/xmpp/xmpp.c +++ b/modules/xmpp/xmpp.c @@ -151,13 +151,25 @@ static param_export_t params[] = { {0, 0, 0} }; +static dep_export_t deps = { + { /* OpenSIPS module dependencies */ + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_NULL, NULL, 0 }, + }, + { /* modparam dependencies */ + { NULL, NULL }, + }, +}; + /* * Module description */ struct module_exports exports = { "xmpp", /* Module name */ + MOD_TYPE_DEFAULT,/* class of this module */ MODULE_VERSION, DEFAULT_DLFLAGS, /* dlopen flags */ + &deps, /* OpenSIPS module dependencies */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ @@ -181,7 +193,7 @@ static int mod_init(void) { LM_ERR("failed to load tm API\n"); return -1; } - + if (strcmp(backend, "component") && strcmp(backend, "server")) { LM_ERR("invalid backend '%s'\n", backend); return -1; @@ -208,7 +220,7 @@ static int mod_init(void) { LM_ERR("pipe() failed\n"); return -1; } - + xmpp_pid = (int*)shm_malloc(sizeof(int)); if(xmpp_pid == NULL) { LM_ERR("No more shared memory\n"); @@ -266,7 +278,7 @@ int xmpp_send_sip_msg(char *from, char *to, char *msg) char buf_from[256]; ENC_SIP_URI(fromstr, buf_from, from); - + hdr.s = buf; hdr.len = snprintf(buf, sizeof(buf), "Content-type: text/plain" CRLF "Contact: %s" CRLF, from); @@ -323,11 +335,11 @@ void xmpp_free_pipe_cmd(struct xmpp_pipe_cmd *cmd) shm_free(cmd); } -static int xmpp_send_pipe_cmd(enum xmpp_pipe_cmd_type type, str *from, str *to, +static int xmpp_send_pipe_cmd(enum xmpp_pipe_cmd_type type, str *from, str *to, str *body, str *id) { struct xmpp_pipe_cmd *cmd; - + /* todo: make shm allocation for one big chunk to include all fields */ cmd = (struct xmpp_pipe_cmd *) shm_malloc(sizeof(struct xmpp_pipe_cmd)); memset(cmd, 0, sizeof(struct xmpp_pipe_cmd)); @@ -368,7 +380,7 @@ static int cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar) int mime; LM_DBG("cmd_send_message\n"); - + /* extract body */ if (get_body(msg,&body)!=0 || body.len==0) { LM_ERR("failed to extract body\n"); @@ -378,7 +390,7 @@ static int cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar) LM_ERR("failed parse content-type\n"); return -1; } - if (mime != (TYPE_TEXT << 16) + SUBTYPE_PLAIN + if (mime != (TYPE_TEXT << 16) + SUBTYPE_PLAIN && mime != (TYPE_MESSAGE << 16) + SUBTYPE_CPIM) { LM_ERR("invalid content-type 0x%x\n", mime); return -1; @@ -394,7 +406,7 @@ static int cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar) LM_ERR("failed to parse From header\n"); return -1; } - + from_uri.s = uri_sip2xmpp(&((struct to_body *) msg->from->parsed)->uri); from_uri.len = strlen(from_uri.s); @@ -406,7 +418,7 @@ static int cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar) if (msg->new_uri.len > 0) { LM_DBG("using new URI as destination\n"); dst = msg->new_uri; - } else if (msg->first_line.u.request.uri.s + } else if (msg->first_line.u.request.uri.s && msg->first_line.u.request.uri.len > 0) { LM_DBG("using R-URI as destination\n"); dst = msg->first_line.u.request.uri; @@ -419,7 +431,7 @@ static int cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar) } dst.s = dst.s + 4; dst.len = dst.len - 4; - + if (!xmpp_send_pipe_cmd(XMPP_PIPE_SEND_MESSAGE, &from_uri, &dst, &body, &tagid)) return 1; diff --git a/modules/xmpp/xmpp.h b/modules/xmpp/xmpp.h index e5011a416ca..4f54b254a38 100644 --- a/modules/xmpp/xmpp.h +++ b/modules/xmpp/xmpp.h @@ -61,7 +61,7 @@ char *random_secret(void); char *db_key(char *secret, char *domain, char *id); char* uri_sip2xmpp(str* uri); char* uri_xmpp2sip(char* uri, int* len); - + /* xmpp_server.c */ int xmpp_server_child_process(int data_pipe); diff --git a/modules/xmpp/xmpp_api.c b/modules/xmpp/xmpp_api.c index 336e01f2fca..e2ba77a585a 100644 --- a/modules/xmpp/xmpp_api.c +++ b/modules/xmpp/xmpp_api.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * + * */ diff --git a/modules/xmpp/xmpp_api.h b/modules/xmpp/xmpp_api.h index 14e007e6746..501093402c5 100644 --- a/modules/xmpp/xmpp_api.h +++ b/modules/xmpp/xmpp_api.h @@ -20,7 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * + * */ #ifndef _XMPP_API_H_ diff --git a/modules/xmpp/xmpp_component.c b/modules/xmpp/xmpp_component.c index 36f9be94280..84cc3e664e8 100644 --- a/modules/xmpp/xmpp_component.c +++ b/modules/xmpp/xmpp_component.c @@ -42,7 +42,7 @@ static int xode_send(int fd, xode x) { char *str = xode_to_str(x); int len = strlen(str); - + LM_DBG("xode_send [%s]\n", str); if (net_send(fd, str, len) != len) { @@ -53,7 +53,7 @@ static int xode_send(int fd, xode x) return len; } -static void stream_node_callback(int type, xode node, void *arg) +static void stream_node_callback(int type, xode node, void *arg) { struct xmpp_private_data *priv = (struct xmpp_private_data *) arg; char *id, *hash, *tag; @@ -66,7 +66,7 @@ static void stream_node_callback(int type, xode node, void *arg) id = xode_get_attrib(node, "id"); snprintf(buf, sizeof(buf), "%s%s", id, xmpp_password); hash = shahash(buf); - + x = xode_new_tag("handshake"); xode_insert_cdata(x, hash, -1); xode_send(priv->fd, x); @@ -83,14 +83,14 @@ static void stream_node_callback(int type, xode node, void *arg) char *type = xode_get_attrib(node, "type"); xode body = xode_get_tag(node, "body"); char *msg; - + if (!type) type = "chat"; - if (!strcmp(type, "error")) { + if (!strcmp(type, "error")) { LM_DBG("received message error stanza\n"); goto out; } - + if (!from || !to || !body) { LM_DBG("invalid attributes\n"); goto out; @@ -137,7 +137,7 @@ static int do_send_message_component(struct xmpp_private_data *priv, xode_put_attrib(x, "to", cmd->to); xode_put_attrib(x, "type", "chat"); xode_insert_cdata(xode_insert_tag(x, "body"), cmd->body, -1); - + xode_send(priv->fd, x); xode_free(x); @@ -185,7 +185,7 @@ int xmpp_component_child_process(int data_pipe) xode_stream stream; struct xmpp_private_data priv; struct xmpp_pipe_cmd *cmd; - + while (1) { fd = net_connect(xmpp_host, xmpp_port); if (fd < 0) { @@ -196,16 +196,16 @@ int xmpp_component_child_process(int data_pipe) priv.fd = fd; priv.running = 1; - + pool = xode_pool_new(); stream = xode_stream_new(pool, stream_node_callback, &priv); - + net_printf(fd, "" "", xmpp_domain); - + while (priv.running) { FD_ZERO(&fdset); FD_SET(data_pipe, &fdset); @@ -238,9 +238,9 @@ int xmpp_component_child_process(int data_pipe) } } } - + xode_pool_free(pool); - + close(fd); } return 0; diff --git a/modules/xmpp/xmpp_server.c b/modules/xmpp/xmpp_server.c index a03ab574ee5..819afd910e7 100644 --- a/modules/xmpp/xmpp_server.c +++ b/modules/xmpp/xmpp_server.c @@ -109,15 +109,15 @@ static struct xmpp_connection *conn_list = NULL; static struct xmpp_connection *conn_new(int type, int fd, char *domain) { struct xmpp_connection *conn = NULL; - + conn = malloc(sizeof(struct xmpp_connection)); - if(conn==NULL) + if(conn==NULL) { LM_ERR("out of memory\n"); return NULL; } - + memset(conn, 0, sizeof(struct xmpp_connection)); conn->domain = domain ? strdup(domain) : NULL; conn->type = type; @@ -128,7 +128,7 @@ static struct xmpp_connection *conn_new(int type, int fd, char *domain) conn->stream = xode_stream_new(conn->pool, (type==CONN_INBOUND)?in_stream_node_callback:out_stream_node_callback, conn); - + conn->next = conn_list; conn_list = conn; return conn; @@ -137,7 +137,7 @@ static struct xmpp_connection *conn_new(int type, int fd, char *domain) static void conn_free(struct xmpp_connection *conn) { struct xmpp_connection **last_p, *link; - + last_p = &conn_list; for (link = conn_list; link; link = link->next) { if (link == conn) { @@ -162,9 +162,9 @@ static void conn_free(struct xmpp_connection *conn) static struct xmpp_connection *conn_find_domain(char *domain, int type) { struct xmpp_connection *conn; - + for (conn = conn_list; conn; conn = conn->next) - if (conn->domain && !strcasecmp(conn->domain, domain) + if (conn->domain && !strcasecmp(conn->domain, domain) && conn->type == type) return conn; return NULL; @@ -174,7 +174,7 @@ static struct xmpp_connection *conn_find_domain(char *domain, int type) static struct xmpp_connection *conn_find_fd(int fd) { struct xmpp_connection *conn; - + for (conn = conn_list; conn; conn = conn->next) if (conn->fd == fd) return conn; @@ -188,7 +188,7 @@ static int xode_send(int fd, xode x) { char *str = xode_to_str(x); int len = strlen(str); - + LM_DBG("xode_send->%d [%s]\n", fd, str); if (net_send(fd, str, len) != len) { @@ -220,7 +220,7 @@ static void out_stream_node_callback(int type, xode node, void *arg) char *tag; xode x; - LM_DBG("outstream callback: %d: %s\n", type, + LM_DBG("outstream callback: %d: %s\n", type, node?xode_get_name(node):"n/a"); if (conn->domain) @@ -248,7 +248,7 @@ static void out_stream_node_callback(int type, xode node, void *arg) char *id = xode_get_attrib(node, "id"); char *type = xode_get_attrib(node, "type"); /* char *cdata = xode_get_data(node); */ - + if (!strcmp(type, "valid") || !strcmp(type, "invalid")) { /* got a reply, report it */ x = xode_new_tag("db:result"); @@ -266,7 +266,7 @@ static void out_stream_node_callback(int type, xode node, void *arg) } } else if (!strcmp(tag, "db:result")) { char *type = xode_get_attrib(node, "type"); - + if (type && !strcmp(type, "valid")) { /* the remote server has successfully authenticated us, * we can now send data */ @@ -290,7 +290,7 @@ static void out_stream_node_callback(int type, xode node, void *arg) xode_free(node); } -static void in_stream_node_callback(int type, xode node, void *arg) +static void in_stream_node_callback(int type, xode node, void *arg) { struct xmpp_connection *conn = (struct xmpp_connection *) arg; char *tag; @@ -316,7 +316,7 @@ static void in_stream_node_callback(int type, xode node, void *arg) /* char *id = xode_get_attrib(node, "id"); */ char *type = xode_get_attrib(node, "type"); char *cdata = xode_get_data(node); - + if (!type) { if (conn->domain) { LM_DBG("connection %d has old domain '%s'\n",conn->fd, @@ -336,14 +336,14 @@ static void in_stream_node_callback(int type, xode node, void *arg) xode_put_attrib(x, "id", conn->stream_id); xode_insert_cdata(x, cdata, -1); xode_send_domain(from, x); - } + } } else if (!strcmp(tag, "db:verify")) { char *from = xode_get_attrib(node, "from"); char *to = xode_get_attrib(node, "to"); char *id = xode_get_attrib(node, "id"); char *type = xode_get_attrib(node, "type"); char *cdata = xode_get_data(node); - + if (!type) { /* it's a request */ x = xode_new_tag("db:verify"); @@ -359,21 +359,21 @@ static void in_stream_node_callback(int type, xode node, void *arg) } xode_send(conn->fd, x); xode_free(x); - } + } } else if (!strcmp(tag, "message")) { char *from = xode_get_attrib(node, "from"); char *to = xode_get_attrib(node, "to"); char *type = xode_get_attrib(node, "type"); xode body = xode_get_tag(node, "body"); char *msg; - + if (!type) type = "chat"; - if (!strcmp(type, "error")) { + if (!strcmp(type, "error")) { LM_DBG("received message error stanza\n"); goto out; } - + if (!from || !to || !body) { LM_DBG("invalid attributes\n"); goto out; @@ -439,7 +439,7 @@ int xmpp_server_child_process(int data_pipe) int listen_fd; fd_set fdset; struct xmpp_connection *conn; - + snprintf(local_secret, sizeof(local_secret), "%s", random_secret()); while ((listen_fd = net_listen(xmpp_domain, xmpp_port)) < 0) { @@ -451,7 +451,7 @@ int xmpp_server_child_process(int data_pipe) FD_ZERO(&fdset); FD_SET(data_pipe, &fdset); FD_SET(listen_fd, &fdset); - + /* check for dead connections */ for (conn = conn_list; conn; ) { struct xmpp_connection *next = conn->next; @@ -476,7 +476,7 @@ int xmpp_server_child_process(int data_pipe) } else { conn->type = CONN_DEAD; } - } + } if (conn->fd != -1) FD_SET(conn->fd, &fdset); diff --git a/modules/xmpp/xode.c b/modules/xmpp/xode.c index 025d129a21e..d7a37054539 100644 --- a/modules/xmpp/xode.c +++ b/modules/xmpp/xode.c @@ -561,14 +561,14 @@ char* xode_get_data(xode node) int xode_get_datasz(xode node) { - + if( node == NULL ) { - return (int)(long)NULL; - } + return (int)(long)NULL; + } else if(xode_get_type(node) == XODE_TYPE_TAG) /* loop till we find a CDATA */ { - xode cur; + xode cur; for(cur = xode_get_firstchild(node); cur != NULL; cur = xode_get_nextsibling(cur)) if(xode_get_type(cur) == XODE_TYPE_CDATA) return cur->data_sz; @@ -814,8 +814,8 @@ _xode_to_prettystr( xode_spool s, xode x, int deep ) xode y; if(xode_get_type(x) != XODE_TYPE_TAG) return; - - for(i=0; i"); xode_spool_add(s,"\n"); - + if( xode_get_data(x)) { - for(i=0; i<=deep; i++) xode_spool_add(s, "\t"); - xode_spool_add( s , xode_get_data(x)); + for(i=0; i<=deep; i++) xode_spool_add(s, "\t"); + xode_spool_add( s , xode_get_data(x)); } - + y = xode_get_firstchild(x); while( y ) { @@ -842,20 +842,20 @@ _xode_to_prettystr( xode_spool s, xode x, int deep ) y = xode_get_nextsibling(y); xode_spool_add(s,"\n"); } - - for(i=0; i" , s ); return; } -char * +char * xode_to_prettystr( xode x ) { xode_spool s; if( !x) return NULL; - + s = xode_spool_newfrompool( xode_get_pool(x)); _xode_to_prettystr( s , x, 0 ); diff --git a/modules/xmpp/xode.h b/modules/xmpp/xode.h index 22bef98a90d..ad141a01e35 100644 --- a/modules/xmpp/xode.h +++ b/modules/xmpp/xode.h @@ -85,7 +85,7 @@ extern int ap_vsnprintf(char *, size_t, const char *, va_list ap); /* xode_pool_cleaner - callback type which is associated - with a pool entry; invoked when the pool entry is + with a pool entry; invoked when the pool entry is free'd */ typedef void (*xode_pool_cleaner)(void *arg); @@ -112,20 +112,20 @@ xode_pool xode_pool_new(void); /* pool wrappers for malloc */ void *xode_pool_malloc (xode_pool p, int size); -void *xode_pool_mallocx (xode_pool p, int size, char c); -void *xode_pool_malloco (xode_pool p, int size); +void *xode_pool_mallocx (xode_pool p, int size, char c); +void *xode_pool_malloco (xode_pool p, int size); /* wrapper around strdup, gains mem from pool */ -char *xode_pool_strdup (xode_pool p, const char *src); +char *xode_pool_strdup (xode_pool p, const char *src); /* calls f(arg) before the pool is freed during cleanup */ -void xode_pool_cleanup (xode_pool p, xode_pool_cleaner f, void *arg); +void xode_pool_cleanup (xode_pool p, xode_pool_cleaner f, void *arg); /* pool wrapper for free, called on a pool */ -void xode_pool_free (xode_pool p); +void xode_pool_free (xode_pool p); /* returns total bytes allocated in this pool */ -int xode_pool_size (xode_pool p); +int xode_pool_size (xode_pool p); /* --------------------------------------------------------- */ /* */ @@ -178,8 +178,8 @@ void xode_spool_free ( xode_spool s ); /* Free's t #define XODE_TYPE_LAST 2 #define XODE_TYPE_UNDEF -1 -/* -------------------------------------------------------------------------- - Node structure. Do not use directly! Always use accessors macros +/* -------------------------------------------------------------------------- + Node structure. Do not use directly! Always use accessors macros and methods! -------------------------------------------------------------------------- */ typedef struct xode_struct @@ -191,9 +191,9 @@ typedef struct xode_struct int complete; xode_pool p; struct xode_struct* parent; - struct xode_struct* firstchild; + struct xode_struct* firstchild; struct xode_struct* lastchild; - struct xode_struct* prev; + struct xode_struct* prev; struct xode_struct* next; struct xode_struct* firstattrib; struct xode_struct* lastattrib; @@ -204,7 +204,7 @@ xode xode_wrap(xode x,const char* wrapper); xode xode_new(const char* name); xode xode_new_tag(const char* name); xode xode_new_frompool(xode_pool p, const char* name); -xode xode_insert_tag(xode parent, const char* name); +xode xode_insert_tag(xode parent, const char* name); xode xode_insert_cdata(xode parent, const char* CDATA, unsigned int size); xode xode_insert_tagnode(xode parent, xode node); void xode_insert_node(xode parent, xode node); diff --git a/modules/xmpp/xode_from.c b/modules/xmpp/xode_from.c index 019148d8727..ff24070df93 100644 --- a/modules/xmpp/xode_from.c +++ b/modules/xmpp/xode_from.c @@ -130,11 +130,11 @@ xode xode_from_strx(char *str, int len, int *err, int *pos) if(err != NULL) *err = XML_GetErrorCode(p); if(pos != NULL) - *pos = XML_GetCurrentByteIndex(p); + *pos = XML_GetCurrentByteIndex(p); node = *x; free(x); XML_ParserFree(p); - + return node; /* return the xmlnode x points to */ } diff --git a/modules/xmpp/xode_str.c b/modules/xmpp/xode_str.c index 0db1bd26b12..22d99463dc9 100644 --- a/modules/xmpp/xode_str.c +++ b/modules/xmpp/xode_str.c @@ -34,7 +34,7 @@ int xode_spool_getlen(const xode_spool s) if(s == NULL) return 0; - return s->len; + return s->len; } void xode_spool_free(xode_spool s) diff --git a/modules/xmpp/xpool.c b/modules/xmpp/xpool.c index 884e8ec58e9..246d35b99d5 100644 --- a/modules/xmpp/xpool.c +++ b/modules/xmpp/xpool.c @@ -17,26 +17,26 @@ * * Jabber * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/ - * + * * 2/27/00:3am, random plans by jer - * + * * ok based on gprof, we really need some innovation here... my thoughs are this: - * + * * most things are strings, so have a string-based true-blue garbage collector * one big global hash containing all the strings created by any pstrdup, returning const char * * a refcount on each string block * when a pool is freed, it moves down the refcount * garbage collector collects pools on the free stack, and runs through the hash for unused strings * j_strcmp can check for == (if they are both from a pstrdup) - * + * * let's see... this would change: * pstrdup: do a hash lookup, success=return, fail=pmalloc & hash put - * pool_free: - * - * - * - * - * + * pool_free: + * + * + * + * + * */ #include "xode.h" @@ -175,7 +175,7 @@ void *xode_pool_mallocx(xode_pool p, int size, char c) if (result != NULL) memset(result, c, size); return result; -} +} /* easy safety utility (for creating blank mem for structs, etc) */ void *xode_pool_malloco(xode_pool p, int size) @@ -183,7 +183,7 @@ void *xode_pool_malloco(xode_pool p, int size) void *block = xode_pool_malloc(p, size); memset(block, 0, size); return block; -} +} /* XXX efficient: move this to const char * and then loop through the existing heaps to see if src is within a block in this pool */ char *xode_pool_strdup(xode_pool p, const char *src) diff --git a/modules/xmpp/xsnprintf.c b/modules/xmpp/xsnprintf.c index 0db801797cd..a47c31cdacd 100644 --- a/modules/xmpp/xsnprintf.c +++ b/modules/xmpp/xsnprintf.c @@ -8,7 +8,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -366,7 +366,7 @@ conv_10(register wide_int num, register bool_int is_unsigned, *is_negative = (num < 0); /* - * On a 2's complement machine, negating the most negative integer + * On a 2's complement machine, negating the most negative integer * results in a number that cannot be represented as a signed integer. * Here is what we do to obtain the number's magnitude: * a. add 1 to the number @@ -383,7 +383,7 @@ conv_10(register wide_int num, register bool_int is_unsigned, } /* - * We use a do-while loop so that we write at least 1 digit + * We use a do-while loop so that we write at least 1 digit */ do { register u_wide_int new_magnitude = magnitude / 10; @@ -806,11 +806,11 @@ static int format_converter(register buffy * odp, const char *fmt, break; /* - * Always extract the argument as a "char *" pointer. We - * should be using "void *" but there are still machines + * Always extract the argument as a "char *" pointer. We + * should be using "void *" but there are still machines * that don't understand it. * If the pointer size is equal to the size of an unsigned - * integer we convert the pointer to a hex number, otherwise + * integer we convert the pointer to a hex number, otherwise * we print "%p" to indicate that we don't handle "%p". */ case 'p': @@ -868,7 +868,7 @@ static int format_converter(register buffy * odp, const char *fmt, PAD(min_width, s_len, pad_char); } /* - * Print the string s. + * Print the string s. */ for (i = s_len; i != 0; i--) { INS_CHAR(*s, sp, bep, cc); diff --git a/modules/xmpp/xstream.c b/modules/xmpp/xstream.c index 0f98cc92bda..ec59e1dab17 100644 --- a/modules/xmpp/xstream.c +++ b/modules/xmpp/xstream.c @@ -138,7 +138,7 @@ xode_stream xode_stream_new(xode_pool p, xode_stream_onNode f, void *arg) XML_SetElementHandler(newx->parser, (void (*)(void*, const char*, const char**))_xode_stream_startElement, (void (*)(void*, const char*))_xode_stream_endElement); - XML_SetCharacterDataHandler(newx->parser, + XML_SetCharacterDataHandler(newx->parser, (void (*)(void*, const char*, int))_xode_stream_charData); xode_pool_cleanup(p, _xode_stream_cleanup, (void *)newx); diff --git a/msg_callbacks.h b/msg_callbacks.h index 2a787ae46ae..8ae58e94cd6 100644 --- a/msg_callbacks.h +++ b/msg_callbacks.h @@ -24,7 +24,7 @@ /* * This is a mechanism to register per-message callback handlers * to be called at certain points of the message lifecycle. - * + * * Apart from the sip_msg structure, each handler is passed a * pointer to a handler type-specific structure from the core * and pointer to an opaque structure allocated by the module. diff --git a/msg_translator.c b/msg_translator.c index 2208a844f1d..2b12e9d3e98 100644 --- a/msg_translator.c +++ b/msg_translator.c @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2003-01-20 bug_fix: use of return value of snprintf aligned to C99 (jiri) - * 2003-01-23 added rport patches, contributed by + * 2003-01-23 added rport patches, contributed by * Maxim Sobolev and heavily modified by me * (andrei) * 2003-01-24 added i param to via of outgoing requests (used by tcp), @@ -39,7 +39,7 @@ * 2003-03-18 killed the build_warning snprintf (andrei) * 2003-03-31 added subst lump support (andrei) * 2003-04-01 added opt (conditional) lump support (andrei) - * 2003-04-02 added more subst lumps: SUBST_{SND,RCV}_ALL + * 2003-04-02 added more subst lumps: SUBST_{SND,RCV}_ALL * => ip:port;transport=proto (andrei) * 2003-04-12 added FL_FORCE_RPORT support (andrei) * 2003-04-13 updated warning builder -- fixed (andrei) @@ -77,18 +77,18 @@ * if no received was present and received is added too) * \section localreplies Local replies: * (see also sl_send_reply) - * - rport and received are added in mostly the same way as for requests, but - * in the reverse order (first rport and then received). See also + * - rport and received are added in mostly the same way as for requests, but + * in the reverse order (first rport and then received). See also * limitations. - * - the local reply is sent to the message source ip address. The - * destination port is set to the source port if rport is present or + * - the local reply is sent to the message source ip address. The + * destination port is set to the source port if rport is present or * FL_FORCE_RPORT flag is set, to the via port or to * the default sip port (5060) if neither rport or via port are present. * \section normalreplies "Normal" replies: * - if received is present the message is sent to the received address else - * if no port is present (neither a normal via port or rport) a dns srv - * lookup is performed on the host part and the reply is sent to the - * resulting ip. If a port is present or the host part is an ip address + * if no port is present (neither a normal via port or rport) a dns srv + * lookup is performed on the host part and the reply is sent to the + * resulting ip. If a port is present or the host part is an ip address * the dns lookup will be a "normal" one (A or AAAA). * - if rport is present, it's value will be used as the destination port * (and this will also disable srv lookups) @@ -146,19 +146,19 @@ extern int version_len; int received_test( struct sip_msg *msg ) { int rcvd; - + if(msg->via1->received !=NULL) return 1; if(msg->via1->maddr){ - rcvd = check_ip_address(&msg->rcv.src_ip, &msg->via1->maddr->value, + rcvd = check_ip_address(&msg->rcv.src_ip, &msg->via1->maddr->value, msg->via1->port, msg->via1->proto, received_dns); } else { rcvd = check_ip_address(&msg->rcv.src_ip, &msg->via1->host, msg->via1->port, msg->via1->proto, received_dns); } - return rcvd; + return rcvd; } @@ -177,29 +177,29 @@ static char * warning_builder( struct sip_msg *msg, unsigned int *returned_len) memcpy(buf+clen, (string), l); \ clen+=l; \ }while(0) - + #define str_lenpair_print(string, string_len, string2, string2_len) \ do{ \ str_print(string, string_len); \ str_print(string2, string2_len);\ }while(0) - + #define str_pair_print( string, string2, string2_len) \ str_lenpair_print((string), strlen((string)), (string2), (string2_len)) - + #define str_int_print(string, intval)\ do{\ t=int2str((intval), &print_len); \ str_pair_print(string, t, print_len);\ } while(0) - + #define str_ipaddr_print(string, ipaddr_val)\ do{\ t=ip_addr2a((ipaddr_val)); \ print_len=strlen(t); \ str_pair_print(string, t, print_len);\ } while(0) - + clen=0; str_lenpair_print(WARNING, WARNING_LEN, msg->rcv.bind_address->name.s, @@ -207,7 +207,7 @@ static char * warning_builder( struct sip_msg *msg, unsigned int *returned_len) str_lenpair_print(":", 1, msg->rcv.bind_address->port_no_str.s, msg->rcv.bind_address->port_no_str.len); str_print(WARNING_PHRASE, WARNING_PHRASE_LEN); - + /*adding out_uri*/ if (msg->new_uri.s) foo=&(msg->new_uri); @@ -226,8 +226,8 @@ static char * warning_builder( struct sip_msg *msg, unsigned int *returned_len) str_int_print("=", via_cnt); if (clenrcv.src_port, &tmp_len); len=RPORT_LEN+tmp_len; @@ -285,7 +285,7 @@ char* rport_builder(struct sip_msg *msg, unsigned int *rport_len) memcpy(buf, RPORT, RPORT_LEN); memcpy(buf+RPORT_LEN, tmp, tmp_len); buf[len]=0; /*null terminate it*/ - + *rport_len=len; return buf; } @@ -297,7 +297,7 @@ char* id_builder(struct sip_msg* msg, unsigned int *id_len) char* buf, *p; int len, value_len, size; char revhex[sizeof(int)*2]; - + size=sizeof(int)*2; p=&revhex[0]; if (int2reverse_hex(&p, &size, msg->rcv.proto_reserved1)==-1){ @@ -305,7 +305,7 @@ char* id_builder(struct sip_msg* msg, unsigned int *id_len) return 0; } value_len=p-&revhex[0]; - len=ID_PARAM_LEN+value_len; + len=ID_PARAM_LEN+value_len; buf=pkg_malloc(sizeof(char)*(len+1));/* place for ending \0 */ if (buf==0){ ser_error=E_OUT_OF_MEM; @@ -326,7 +326,7 @@ char* clen_builder(struct sip_msg* msg, int *clen_len, int diff) char *buf, * value_s; int len, value, value_len; str body; - + if ( (get_body(msg,&body)!=0) || body.len==0 ) { ser_error=E_BAD_REQ; LM_ERR("no message body found (missing crlf?)"); @@ -335,7 +335,7 @@ char* clen_builder(struct sip_msg* msg, int *clen_len, int diff) value = body.len + diff; value_s=int2str(value, &value_len); LM_DBG("content-length: %d (%s)\n", value, value_s); - + len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN; buf=pkg_malloc(sizeof(char)*(len+1)); if (buf==0){ @@ -353,7 +353,7 @@ char* clen_builder(struct sip_msg* msg, int *clen_len, int diff) -/*! \brief* checks if a lump opt condition +/*! \brief* checks if a lump opt condition * returns 1 if cond is true, 0 if false */ static inline int lump_check_opt( struct lump *l, struct sip_msg* msg, @@ -378,7 +378,7 @@ static inline int lump_check_opt( struct lump *l, port=msg->rcv.dst_port; \ proto=msg->rcv.proto; \ } \ - + switch(l->u.cond){ case COND_FALSE: return 0; @@ -389,28 +389,42 @@ static inline int lump_check_opt( struct lump *l, get_ip_port_proto; /* faster tests first */ if ((port==snd_s->port_no)&&(proto==snd_s->proto)&& - (ip_addr_cmp(ip, &snd_s->address))) + (ip_addr_cmp(ip, &snd_s->address))) { + l->flags &= ~LUMPFLAG_COND_TRUE; return 0; + } l->flags |= LUMPFLAG_COND_TRUE; return 1; case COND_IF_DIFF_AF: get_ip_port_proto; - if (ip->af==snd_s->address.af) return 0; + if (ip->af==snd_s->address.af) { + l->flags &= ~LUMPFLAG_COND_TRUE; + return 0; + } l->flags |= LUMPFLAG_COND_TRUE; return 1; case COND_IF_DIFF_PROTO: get_ip_port_proto; - if (proto==snd_s->proto) return 0; + if (proto==snd_s->proto) { + l->flags &= ~LUMPFLAG_COND_TRUE; + return 0; + } l->flags |= LUMPFLAG_COND_TRUE; return 1; case COND_IF_DIFF_PORT: get_ip_port_proto; - if (port==snd_s->port_no) return 0; + if (port==snd_s->port_no) { + l->flags &= ~LUMPFLAG_COND_TRUE; + return 0; + } l->flags |= LUMPFLAG_COND_TRUE; return 1; case COND_IF_DIFF_IP: get_ip_port_proto; - if (ip_addr_cmp(ip, &snd_s->address)) return 0; + if (ip_addr_cmp(ip, &snd_s->address)) { + l->flags &= ~LUMPFLAG_COND_TRUE; + return 0; + } l->flags |= LUMPFLAG_COND_TRUE; return 1; default: @@ -427,6 +441,7 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, struct socket_info* send_sock) { unsigned int s_offset, new_len; + unsigned int last_del; struct lump *t, *r; str *send_address_str, *send_port_str; str *rcv_address_str=NULL; @@ -437,18 +452,14 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, case SUBST_RCV_IP: \ if (msg->rcv.bind_address){ \ new_len+=rcv_address_str->len; \ - }else{ \ - /* FIXME */ \ - LM_CRIT("fixme:null bind_address\n"); \ - }; \ + } else \ + report_programming_bug("null bind adress 1"); \ break; \ case SUBST_RCV_PORT: \ if (msg->rcv.bind_address){ \ new_len+=rcv_port_str->len; \ - }else{ \ - /* FIXME */ \ - LM_CRIT("fixme: null bind_address\n"); \ - }; \ + } else \ + report_programming_bug("null bind adress 2"); \ break; \ case SUBST_RCV_PROTO: \ if (msg->rcv.bind_address){ \ @@ -466,10 +477,8 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, LM_CRIT("unknown proto %d\n", \ msg->rcv.bind_address->proto); \ }\ - }else{ \ - /* FIXME */ \ - LM_CRIT("fixme: null bind_address\n"); \ - }; \ + } else \ + report_programming_bug("null bind adress 3"); \ break; \ case SUBST_RCV_ALL: \ if (msg->rcv.bind_address){ \ @@ -494,26 +503,20 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, LM_CRIT("unknown proto %d\n", \ msg->rcv.bind_address->proto); \ }\ - }else{ \ - /* FIXME */ \ - LM_CRIT("fixme: null bind_address\n"); \ - }; \ + } else \ + report_programming_bug("null bind adress 4"); \ break; \ case SUBST_SND_IP: \ if (send_sock){ \ new_len+=send_address_str->len; \ - }else{ \ - LM_CRIT("fixme: lumps_len called with" \ - " null send_sock\n"); \ - }; \ + } else \ + report_programming_bug("null send_socket 1"); \ break; \ case SUBST_SND_PORT: \ if (send_sock){ \ new_len+=send_port_str->len; \ - }else{ \ - LM_CRIT("lumps_len called with" \ - " null send_sock\n"); \ - }; \ + } else \ + report_programming_bug("null send_socket 2"); \ break; \ case SUBST_SND_PROTO: \ if (send_sock){ \ @@ -531,10 +534,8 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, LM_CRIT("unknown proto %d\n", \ send_sock->proto); \ }\ - }else{ \ - LM_CRIT("lumps_len called with" \ - " null send_sock\n"); \ - }; \ + } else \ + report_programming_bug("null send_socket 3"); \ break; \ case SUBST_SND_ALL: \ if (send_sock){ \ @@ -560,11 +561,8 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, LM_CRIT("unknown proto %d\n", \ send_sock->proto); \ }\ - }else{ \ - /* FIXME */ \ - LM_CRIT("lumps_len called with" \ - " null send_sock\n"); \ - }; \ + } else \ + report_programming_bug("null send_socket 4"); \ break; \ case SUBST_NOP: /* do nothing */ \ break; \ @@ -572,20 +570,28 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, LM_CRIT("unknown subst type %d\n", \ (subst_l)->u.subst); \ } - + + s_offset=0; new_len=0; + last_del=0; + /* init send_address_str & send_port_str */ if(send_sock && send_sock->adv_name_str.len) send_address_str=&(send_sock->adv_name_str); - else if (msg->set_global_address.len) + else if (msg->set_global_address.s) send_address_str=&(msg->set_global_address); + else if (default_global_address.s) + send_address_str=&default_global_address; else send_address_str=&(send_sock->address_str); + if(send_sock && send_sock->adv_port_str.len) send_port_str=&(send_sock->adv_port_str); - else if (msg->set_global_port.len) + else if (msg->set_global_port.s) send_port_str=&(msg->set_global_port); + else if (default_global_port.s) + send_port_str=&default_global_port; else send_port_str=&(send_sock->port_no_str); @@ -600,35 +606,35 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, else rcv_port_str=&(msg->rcv.bind_address->port_no_str); } - - - for(t=lumps;t;t=t->next){ - /* if a SKIP lump, go to the last in the list*/ - if (t->op==LUMP_SKIP) { - if (!t->next) break; - for(;t->next;t=t->next); - } - /* skip if this is an OPT lump and the condition is not satisfied */ - if ((t->op==LUMP_ADD_OPT) && !lump_check_opt(t, msg, send_sock)) + + for (t = lumps; t; t = t->next) { + /* is this lump still valid? (it must not be anchored in a deleted area */ + if (t->u.offset < s_offset && t->u.offset != last_del) { + LM_DBG("skip a %d, buffer offset=%d, lump offset=%d, last_del=%d\n", + t->op,s_offset, t->u.offset,last_del); continue; - for(r=t->before;r;r=r->before){ - switch(r->op){ + } + + for (r = t->before; r; r = r->before) { + switch (r->op) { case LUMP_ADD: - new_len+=r->len; + new_len += r->len; break; case LUMP_ADD_SUBST: SUBST_LUMP_LEN(r); break; case LUMP_ADD_OPT: - /* skip if this is an OPT lump and the condition is + /* skip if this is an OPT lump and the condition is * not satisfied */ if (!lump_check_opt(r, msg, send_sock)) goto skip_before; break; case LUMP_SKIP: /* if a SKIP lump, go to the last in the list*/ - if (!r->before || !r->before->before) continue; - for(;r->before->before;r=r->before); + if (!r->before || !r->before->before) + continue; + for (; r->before->before; r = r->before) + ; break; default: /* only ADD allowed for before/after */ @@ -636,42 +642,48 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, } } skip_before: - switch(t->op){ - case LUMP_ADD: - new_len+=t->len; + switch (t->op) { + case LUMP_DEL: + last_del=t->u.offset; + + if (t->u.offset < s_offset) { + if (t->u.offset + t->len > s_offset) { + new_len -= t->len - (s_offset - t->u.offset); + s_offset = t->u.offset + t->len; + } + } else { + new_len -= t->len; + s_offset = t->u.offset + t->len; + } + break; - case LUMP_ADD_SUBST: - SUBST_LUMP_LEN(t); + case LUMP_NOP: + /* do nothing */ + break; + case LUMP_ADD: + /* FIXME: inconsistent with process_lumps() */ + new_len += t->len; break; case LUMP_ADD_OPT: + report_programming_bug("LUMP_ADD_OPT"); /* we don't do anything here, it's only a condition for * before & after */ break; - case LUMP_DEL: - /* fix overlapping deleted zones */ - if (t->u.offset < s_offset){ - /* change len */ - if (t->len>s_offset-t->u.offset) - t->len-=s_offset-t->u.offset; - else t->len=0; - t->u.offset=s_offset; - } - s_offset=t->u.offset+t->len; - new_len-=t->len; + case LUMP_SKIP: + report_programming_bug("LUMP_SKIP"); + /* we don't do anything here, it's only a condition for + * before & after */ break; - case LUMP_NOP: - /* fix offset if overlapping on a deleted zone */ - if (t->u.offset < s_offset){ - t->u.offset=s_offset; - }else - s_offset=t->u.offset; - /* do nothing */ + case LUMP_ADD_SUBST: + report_programming_bug("LUMP_ADD_SUBST"); + SUBST_LUMP_LEN(t); break; default: - LM_CRIT("op for data lump (%x)\n", r->op); + report_programming_bug("op for data lump (%x)", r->op); } - for (r=t->after;r;r=r->after){ - switch(r->op){ + + for (r = t->after; r; r = r->after) { + switch (r->op) { case LUMP_ADD: new_len+=r->len; break; @@ -679,15 +691,17 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, SUBST_LUMP_LEN(r); break; case LUMP_ADD_OPT: - /* skip if this is an OPT lump and the condition is + /* skip if this is an OPT lump and the condition is * not satisfied */ if (!lump_check_opt(r, msg, send_sock)) goto skip_after; break; case LUMP_SKIP: /* if a SKIP lump, go to the last in the list*/ - if (!r->after || !r->after->after) continue; - for(;r->after->after;r=r->after); + if (!r->after || !r->after->after) + continue; + for (; r->after->after; r = r->after) + ; break; default: /* only ADD allowed for before/after */ @@ -703,18 +717,19 @@ int lumps_len(struct sip_msg* msg, struct lump* lumps, /*! \brief another helper functions, adds/Removes the lump, - code moved form build_req_from_req */ + code moved from build_req_from_req */ void process_lumps( struct sip_msg* msg, struct lump* lumps, - char* new_buf, - unsigned int* new_buf_offs, + char* new_buf, + unsigned int* new_buf_offs, unsigned int* orig_offs, struct socket_info* send_sock) { struct lump *t, *r; char* orig; unsigned int size, offset, s_offset; + unsigned int last_del; str *send_address_str, *send_port_str; str *rcv_address_str=NULL; str *rcv_port_str=NULL; @@ -920,18 +935,22 @@ void process_lumps( struct sip_msg* msg, (subst_l)->u.subst); \ } \ \ - + /* init send_address_str & send_port_str */ if(send_sock && send_sock->adv_name_str.len) send_address_str=&(send_sock->adv_name_str); else if (msg->set_global_address.len) send_address_str=&(msg->set_global_address); + else if (default_global_address.s) + send_address_str=&default_global_address; else send_address_str=&(send_sock->address_str); if(send_sock && send_sock->adv_port_str.len) send_port_str=&(send_sock->adv_port_str); else if (msg->set_global_port.len) send_port_str=&(msg->set_global_port); + else if (default_global_port.s) + send_port_str=&default_global_port; else send_port_str=&(send_sock->port_no_str); @@ -947,34 +966,40 @@ void process_lumps( struct sip_msg* msg, rcv_port_str=&(msg->rcv.bind_address->port_no_str); } - orig=msg->buf; offset=*new_buf_offs; s_offset=*orig_offs; - - for (t=lumps;t;t=t->next){ - switch(t->op){ - case LUMP_SKIP: - /* if a SKIP lump, go to the last in the list*/ - if (!t->next || !t->next->next) continue; - for(;t->next->next;t=t->next); - break; - case LUMP_ADD: - case LUMP_ADD_SUBST: - case LUMP_ADD_OPT: - /* skip if this is an OPT lump and the condition is - * not satisfied */ - if ((t->op==LUMP_ADD_OPT) && - (!lump_check_opt(t, msg, send_sock))) - continue; - /* just add it here! */ + last_del=0; + + for (t = lumps; t; t = t->next) { + /* skip this lump if the "offset" is still in a "deleted" area */ + if (t->u.offset < s_offset && t->u.offset != last_del) { + LM_DBG("skip a %d, buffer offset=%d, lump offset=%d, last_del=%d\n", + t->op,s_offset, t->u.offset,last_del); + continue; + } + + switch (t->op) { + case LUMP_NOP: + case LUMP_DEL: + /* copy till offset (if any) */ + if (s_offset < t->u.offset) { + size = t->u.offset-s_offset; + memcpy(new_buf+offset, orig+s_offset, size); + offset += size; + s_offset += size; + } + + if (t->op == LUMP_DEL) + last_del = t->u.offset; + /* process before */ - for(r=t->before;r;r=r->before){ - switch (r->op){ + for (r = t->before; r; r = r->before) { + switch (r->op) { case LUMP_ADD: /*just add it here*/ memcpy(new_buf+offset, r->u.value, r->len); - offset+=r->len; + offset += r->len; break; case LUMP_ADD_SUBST: SUBST_LUMP(r); @@ -983,42 +1008,37 @@ void process_lumps( struct sip_msg* msg, /* skip if this is an OPT lump and the condition is * not satisfied */ if (!lump_check_opt(r, msg, send_sock)) - goto skip_before; + goto skip_nop_before; break; case LUMP_SKIP: /* if a SKIP lump, go to the last in the list*/ - if (!r->before || !r->before->before) continue; - for(;r->before->before;r=r->before); + if (!r->before || !r->before->before) + continue; + for (; r->before->before; r = r->before) + ; break; default: /* only ADD allowed for before/after */ - LM_CRIT("invalid op for data lump (%x)\n", r->op); + report_programming_bug("invalid op 1 (%x)",r->op); } } -skip_before: - /* copy "main" part */ - switch(t->op){ - case LUMP_ADD: - memcpy(new_buf+offset, t->u.value, t->len); - offset+=t->len; - break; - case LUMP_ADD_SUBST: - SUBST_LUMP(t); - break; - case LUMP_ADD_OPT: - /* do nothing, it's only a condition */ - break; - default: - /* should not ever get here */ - LM_CRIT("unhandled data lump op %d\n", t->op); +skip_nop_before: + if (t->op == LUMP_DEL) { + /* + * skip at most len bytes from orig msg + * and properly handle DEL lumps at the same offset --liviu + */ + if (t->u.offset + t->len > s_offset) + s_offset += t->len - (s_offset - t->u.offset); } + /* process after */ - for(r=t->after;r;r=r->after){ - switch (r->op){ + for (r = t->after; r; r = r->after) { + switch (r->op) { case LUMP_ADD: /*just add it here*/ memcpy(new_buf+offset, r->u.value, r->len); - offset+=r->len; + offset += r->len; break; case LUMP_ADD_SUBST: SUBST_LUMP(r); @@ -1027,36 +1047,32 @@ void process_lumps( struct sip_msg* msg, /* skip if this is an OPT lump and the condition is * not satisfied */ if (!lump_check_opt(r, msg, send_sock)) - goto skip_after; + goto skip_nop_after; break; case LUMP_SKIP: /* if a SKIP lump, go to the last in the list*/ - if (!r->after || !r->after->after) continue; - for(;r->after->after;r=r->after); + if (!r->after || !r->after->after) + continue; + for (; r->after->after; r = r->after) + ; break; default: /* only ADD allowed for before/after */ - LM_CRIT("invalid op for data lump (%x)\n", r->op); + report_programming_bug("invalid op 2 (%x)", r->op); } } -skip_after: +skip_nop_after: break; - case LUMP_NOP: - case LUMP_DEL: - /* copy till offset */ - if (s_offset>t->u.offset){ - LM_WARN("(%d) overlapped lumps offsets," - " ignoring(%x, %x)\n", t->op, s_offset,t->u.offset); - /* this should've been fixed above (when computing len) */ - /* just ignore it*/ - break; - } - size=t->u.offset-s_offset; - if (size){ - memcpy(new_buf+offset, orig+s_offset,size); - offset+=size; - s_offset+=size; - } + case LUMP_ADD: + case LUMP_ADD_SUBST: + case LUMP_ADD_OPT: + report_programming_bug("ADD|SUBST|OPT"); + /* skip if this is an OPT lump and the condition is + * not satisfied */ + if ((t->op==LUMP_ADD_OPT) && + (!lump_check_opt(t, msg, send_sock))) + continue; + /* just add it here! */ /* process before */ for(r=t->before;r;r=r->before){ switch (r->op){ @@ -1072,7 +1088,7 @@ void process_lumps( struct sip_msg* msg, /* skip if this is an OPT lump and the condition is * not satisfied */ if (!lump_check_opt(r, msg, send_sock)) - goto skip_nop_before; + goto skip_before; break; case LUMP_SKIP: /* if a SKIP lump, go to the last in the list*/ @@ -1081,14 +1097,25 @@ void process_lumps( struct sip_msg* msg, break; default: /* only ADD allowed for before/after */ - LM_CRIT("invalid op for data lump (%x)\n",r->op); + report_programming_bug("invalid op 3 (%x)", r->op); } } -skip_nop_before: - /* process main (del only) */ - if (t->op==LUMP_DEL){ - /* skip len bytes from orig msg */ - s_offset+=t->len; +skip_before: + /* copy "main" part */ + switch(t->op){ + case LUMP_ADD: + memcpy(new_buf+offset, t->u.value, t->len); + offset+=t->len; + break; + case LUMP_ADD_SUBST: + SUBST_LUMP(t); + break; + case LUMP_ADD_OPT: + /* do nothing, it's only a condition */ + break; + default: + /* should not ever get here */ + report_programming_bug("invalid op 4 %d", t->op); } /* process after */ for(r=t->after;r;r=r->after){ @@ -1104,8 +1131,8 @@ void process_lumps( struct sip_msg* msg, case LUMP_ADD_OPT: /* skip if this is an OPT lump and the condition is * not satisfied */ - if (!lump_check_opt(r, msg, send_sock)) - goto skip_nop_after; + if (!lump_check_opt(r, msg, send_sock)) + goto skip_after; break; case LUMP_SKIP: /* if a SKIP lump, go to the last in the list*/ @@ -1114,17 +1141,26 @@ void process_lumps( struct sip_msg* msg, break; default: /* only ADD allowed for before/after */ - LM_CRIT("invalid op for data lump (%x)\n", r->op); + report_programming_bug("invalid op 5 (%x)", r->op); } } -skip_nop_after: +skip_after: + break; + case LUMP_SKIP: + report_programming_bug("LUMP_SKIP"); + /* if a SKIP lump, go to the last in the list*/ + if (!t->next || !t->next->next) + continue; + for (; t->next->next; t = t->next) + ; break; default: - LM_CRIT("unknown op (%x)\n", t->op); + report_programming_bug("invalid op 6 (%x)", t->op); } } - *new_buf_offs=offset; - *orig_offs=s_offset; + + *new_buf_offs = offset; + *orig_offs = s_offset; } @@ -1144,7 +1180,7 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto) clen_buf = 0; anchor=0; - + /* check to see if we need to add clen */ #ifdef USE_TCP if (proto == PROTO_TCP @@ -1161,7 +1197,7 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto) /* msg->unparsed should point just before the final crlf * - whole message was parsed by the above parse_headers * which did not find content-length */ - anchor=anchor_lump(msg, msg->unparsed-msg->buf, 0, + anchor=anchor_lump(msg, msg->unparsed-msg->buf, HDR_CONTENTLENGTH_T); if (anchor==0){ LM_ERR("cannot set clen anchor\n"); @@ -1170,14 +1206,14 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto) } } #endif - - + + if ((anchor==0) && body_delta){ if (parse_headers(msg, HDR_CONTENTLENGTH_F, 0) == -1) { LM_ERR("parsing Content-Length\n"); goto error; } - + /* The body has been changed, try to find * existing Content-Length */ @@ -1189,7 +1225,7 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto) * - whole message was parsed by the above parse_headers * which did not find content-length */ if (proto!=PROTO_UDP){ - anchor=anchor_lump(msg, msg->unparsed-msg->buf, 0, + anchor=anchor_lump(msg, msg->unparsed-msg->buf, HDR_CONTENTLENGTH_T); if (anchor==0){ LM_ERR("cannot set clen anchor\n"); @@ -1208,7 +1244,7 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto) } } } - + if (anchor){ clen_buf = clen_builder(msg, &clen_len, body_delta); if (!clen_buf) goto error; @@ -1226,9 +1262,9 @@ static inline int adjust_clen(struct sip_msg* msg, int body_delta, int proto) /*! \brief * Save given Path body as Route header in message. - * - * If another Route HF is found, it's placed right before that. - * Otherwise, it's placed after the last Via HF. If also no + * + * If another Route HF is found, it's placed right before that. + * Otherwise, it's placed after the last Via HF. If also no * Via HF is found, it's placed as first HF. */ #define ROUTE_STR "Route: " @@ -1248,18 +1284,18 @@ static inline int insert_path_as_route(struct sip_msg* msg, str* path) } if (hf) { /* Route HF found, insert before it */ - anchor = anchor_lump(msg, hf->name.s - msg->buf, 0, 0); + anchor = anchor_lump(msg, hf->name.s - msg->buf, 0); } else if(last_via) { if (last_via->next) { /* Via HF in between, insert after it */ - anchor = anchor_lump(msg, last_via->next->name.s - msg->buf, 0, 0); + anchor = anchor_lump(msg, last_via->next->name.s - msg->buf, 0); } else { /* Via HF is last, so append */ - anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0); + anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0); } } else { /* None of the above, insert as first */ - anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0, 0); + anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0); } if (anchor == 0) { @@ -1318,7 +1354,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, struct lump *anchor, *via_insert_param; str branch, extra_params; struct hostport hp; - + id_buf=0; id_len=0; via_insert_param=0; @@ -1377,7 +1413,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, if(msg->msg_flags&FL_FORCE_LOCAL_RPORT) { id_buf=extra_params.s; id_len=extra_params.len; - extra_params.len += RPORT_LEN-1; /* last char in RPORT define is '=' + extra_params.len += RPORT_LEN-1; /* last char in RPORT define is '=' which is not added, but the new buffer will be null terminated */ extra_params.s = (char*)pkg_malloc(extra_params.len+1); @@ -1386,7 +1422,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, if (id_buf) pkg_free(id_buf); goto error; } - + if(id_buf!=0) { memcpy(extra_params.s, id_buf, id_len); pkg_free(id_buf); @@ -1408,9 +1444,9 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, via1_deleted = is_del_via1_lump(msg); /* check if received needs to be added: - * - if the VIA address and the received address are different + * - if the VIA address and the received address are different * - if the rport was forced (rport requires received) - * - if the rport was received in the VIA hdr + * - if the rport was received in the VIA hdr * - and there is no lump that delets VIA1 hdr */ if ( (msg->via1->rport || (msg->msg_flags&FL_FORCE_RPORT) || received_test(msg) ) && !via1_deleted) { @@ -1419,7 +1455,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, goto error01; /* free also line_buf */ } } - + /* check if rport needs to be updated: * - if FL_FORCE_RPORT is set add it (and del. any previous version) * - if via already contains an rport add it and overwrite the previous @@ -1436,7 +1472,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, /* add via header to the list */ /* try to add it before msg. 1st via */ /* add first via, as an anchor for second via*/ - anchor=anchor_lump(msg, msg->via1->hdr.s-buf, 0, HDR_VIA_T); + anchor=anchor_lump(msg, msg->via1->hdr.s-buf, HDR_VIA_T); if (anchor==0) goto error01; if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA_T)==0) goto error01; @@ -1452,7 +1488,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, size += msg->via1->port_str.len + 1; /* +1 for ':'*/ } } - /* if received needs to be added, add anchor after host and add it, or + /* if received needs to be added, add anchor after host and add it, or * overwrite the previous one if already present */ if (received_len){ if (msg->via1->received){ /* received already present => overwrite it*/ @@ -1461,7 +1497,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, msg->via1->received->size+1, /*;*/ HDR_VIA_T); }else if (via_insert_param==0){ /* receive not present, ok */ via_insert_param=anchor_lump(msg, - msg->via1->hdr.s-buf+size,0, HDR_VIA_T); + msg->via1->hdr.s-buf+size, HDR_VIA_T); } if (via_insert_param==0) goto error02; /* free received_buf */ if (insert_new_lump_after(via_insert_param, received_buf, received_len, @@ -1476,7 +1512,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, }else if (via_insert_param==0){ /*force rport, no rport present */ /* no rport, add it */ via_insert_param=anchor_lump(msg, - msg->via1->hdr.s-buf+size,0, HDR_VIA_T); + msg->via1->hdr.s-buf+size, HDR_VIA_T); } if (via_insert_param==0) goto error03; /* free rport_buf */ if (insert_new_lump_after(via_insert_param, rport_buf, rport_len, @@ -1497,7 +1533,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, } if (flags&MSG_TRANS_SHM_FLAG) new_buf=(char*)shm_malloc(new_len+1); - else + else new_buf=(char*)pkg_malloc(new_len+1); if (new_buf==0){ ser_error=E_OUT_OF_MEM; @@ -1546,23 +1582,15 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg, char * build_res_buf_from_sip_res( struct sip_msg* msg, - unsigned int *returned_len, struct socket_info *sock) + unsigned int *returned_len, struct socket_info *sock,int flags) { - unsigned int new_len, via_len, body_delta, len; + unsigned int new_len, body_delta, len; char *new_buf, *buf; - unsigned offset, s_offset, via_offset; + unsigned int offset, s_offset; buf=msg->buf; len=msg->len; new_buf=0; - /* we must remove the first via */ - if (msg->via1->next) { - via_len=msg->via1->bsize; - via_offset=msg->h_via1->body.s-buf; - } else { - via_len=msg->h_via1->len; - via_offset=msg->h_via1->name.s-buf; - } /* Calculate message body difference and adjust * Content-Length @@ -1574,16 +1602,28 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg, goto error; } - /* remove the first via*/ - if (del_lump( msg, via_offset, via_len, HDR_VIA_T)==0){ - LM_ERR("failed to remove first via\n"); - goto error; + /* remove the first via */ + if (!(flags & MSG_TRANS_NOVIA_FLAG)) { + unsigned int via_len, via_offset; + + if (msg->via1->next) { + via_len = msg->via1->bsize; + via_offset = msg->h_via1->body.s-buf; + } else { + via_len = msg->h_via1->len; + via_offset = msg->h_via1->name.s-buf; + } + + if (del_lump(msg, via_offset, via_len, HDR_VIA_T) == 0) { + LM_ERR("failed to remove first via\n"); + goto error; + } } new_len=len+body_delta+lumps_len(msg, msg->add_rm, sock); - + LM_DBG(" old size: %d, new size: %d\n", len, new_len); - new_buf=(char*)pkg_malloc(new_len+1); /* +1 is for debugging + new_buf=(char*)pkg_malloc(new_len+1); /* +1 is for debugging (\0 to print it )*/ if (new_buf==0){ LM_ERR("out of pkg mem\n"); @@ -1596,11 +1636,11 @@ char * build_res_buf_from_sip_res( struct sip_msg* msg, process_lumps(msg, msg->body_lumps, new_buf, &offset, &s_offset, sock); /* copy the rest of the message */ memcpy(new_buf+offset, - buf+s_offset, + buf+s_offset, len-s_offset); /* as it is a relaied reply, if 503, make it 500 (just reply code) */ if ( !disable_503_translation && msg->first_line.u.reply.statuscode==503 ) - new_buf[(int)(msg->first_line.u.reply.status.s-msg->buf)+2] = '0'; + new_buf[(int)(msg->first_line.u.reply.status.s-msg->buf)+2] = '0'; /* send it! */ LM_DBG("copied size: orig:%d, new: %d, rest: %d" " msg=\n%s\n", s_offset, offset, len-s_offset, new_buf); @@ -1649,7 +1689,7 @@ char * build_res_buf_from_sip_req( unsigned int code, str *text ,str *new_tag, LM_ERR("rport_builder failed\n"); goto error00; } - if (msg->via1->rport) + if (msg->via1->rport) len -= msg->via1->rport->size+1; /* include ';' */ } @@ -1726,7 +1766,7 @@ char * build_res_buf_from_sip_req( unsigned int code, str *text ,str *new_tag, buf = (char*) pkg_malloc( len+1 ); if (!buf) { - LM_ERR("out of pkg memory ; needs %d\n",len); + LM_ERR("out of pkg memory; needs %d\n",len); goto error01; } @@ -1770,18 +1810,18 @@ char * build_res_buf_from_sip_req( unsigned int code, str *text ,str *new_tag, append_str(p, rport_buf, rport_len); /* copy the rest of the via */ append_str_trans(p, msg->via1->rport->start+ - msg->via1->rport->size, + msg->via1->rport->size, hdr->body.s+hdr->body.len- msg->via1->rport->start- msg->via1->rport->size, msg); }else{ /* just copy rport and rest of hdr */ append_str(p, rport_buf, rport_len); - append_str_trans( p, hdr->name.s+i , + append_str_trans( p, hdr->name.s+i , (hdr->body.s+hdr->body.len)-hdr->name.s-i,msg); } }else{ /* normal whole via copy */ - append_str_trans( p, hdr->name.s+i , + append_str_trans( p, hdr->name.s+i , (hdr->body.s+hdr->body.len)-hdr->name.s-i, msg); } }else{ @@ -1815,7 +1855,7 @@ char * build_res_buf_from_sip_req( unsigned int code, str *text ,str *new_tag, bmark->to_tag_val.s=p; bmark->to_tag_val.len=new_tag->len; append_str( p, new_tag->s,new_tag->len); - append_str( p, after_body, + append_str( p, after_body, hdr->name.s+hdr->len-after_body); } break; @@ -1942,11 +1982,11 @@ int branch_builder( unsigned int hash_index, *len=MAX_BRANCH_PARAM_LEN-size; return size; - + } -char* via_builder( unsigned int *len, +char* via_builder( unsigned int *len, struct socket_info* send_sock, str* branch, str* extra_params, int proto, struct hostport* hp) { @@ -1955,13 +1995,13 @@ char* via_builder( unsigned int *len, int max_len, local_via_len=MY_VIA_LEN; str* address_str; /* address displayed in via */ str* port_str; /* port no displayed in via */ - + /* use pre-set address in via or the outbound socket one */ if (hp && hp->host && hp->host->len) address_str=hp->host; else if(send_sock->adv_name_str.len) address_str=&(send_sock->adv_name_str); - else if (default_global_address.len) + else if (default_global_address.s) address_str=&default_global_address; else address_str=&(send_sock->address_str); @@ -1970,7 +2010,7 @@ char* via_builder( unsigned int *len, port_str=hp->port; else if(send_sock->adv_port_str.len) port_str=&(send_sock->adv_port_str); - else if (default_global_port.len) + else if (default_global_port.s) port_str=&default_global_port; else port_str=&(send_sock->port_no_str); @@ -1990,7 +2030,7 @@ char* via_builder( unsigned int *len, extra_len=0; - memcpy(line_buf, MY_VIA, local_via_len); + memcpy(line_buf, MY_VIA, local_via_len); if (proto==PROTO_UDP){ /* do nothing */ }else if (proto==PROTO_TCP){ @@ -2004,9 +2044,9 @@ char* via_builder( unsigned int *len, LM_CRIT("unknown proto %d\n", proto); return 0; } - + via_len=local_via_len+address_str->len; /*space included in MY_VIA*/ - + memcpy(line_buf+local_via_len+extra_len, address_str->s, address_str->len); line_buf[via_len]=':'; via_len++; memcpy(line_buf+via_len, port_str->s, port_str->len); @@ -2024,7 +2064,7 @@ char* via_builder( unsigned int *len, memcpy(line_buf+via_len, extra_params->s, extra_params->len); via_len+=extra_params->len; } - + memcpy(line_buf+via_len, CRLF, CRLF_LEN); via_len+=CRLF_LEN; line_buf[via_len]=0; /* null terminate the string*/ @@ -2056,11 +2096,11 @@ char *construct_uri(str *protocol,str *username,str *domain,str *port, LM_ERR("no domain specified\n"); return 0; } - + memcpy(uri_buff,protocol->s,protocol->len); pos += protocol->len; uri_buff[pos++] = ':'; - + if (username->s && username->len != 0) { memcpy(uri_buff+pos,username->s,username->len); diff --git a/msg_translator.h b/msg_translator.h index bbe2aa64014..7055f62eefb 100644 --- a/msg_translator.h +++ b/msg_translator.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -67,23 +67,31 @@ struct hostport { #define set_hostport(hp, msg) \ - do{ \ - if ((msg) && ((struct sip_msg*)(msg))->set_global_address.len) \ - (hp)->host=&(((struct sip_msg*)(msg))->set_global_address); \ - else \ - (hp)->host=NULL; \ - if ((msg) && ((struct sip_msg*)(msg))->set_global_port.len) \ - (hp)->port=&(((struct sip_msg*)(msg))->set_global_port); \ - else \ - (hp)->port=NULL; \ - }while(0) + do { \ + if (!(msg)) \ + (hp)->host = NULL; \ + else { \ + if (((struct sip_msg *)(msg))->set_global_address.s) \ + (hp)->host = &(((struct sip_msg *)(msg))->set_global_address); \ + else \ + (hp)->host = &default_global_address; \ + } \ + if (!(msg)) \ + (hp)->port = NULL; \ + else { \ + if (((struct sip_msg *)(msg))->set_global_port.s) \ + (hp)->port = &(((struct sip_msg *)(msg))->set_global_port); \ + else \ + (hp)->port = &default_global_port; \ + } \ + } while (0) char * build_req_buf_from_sip_req ( struct sip_msg* msg, unsigned int *returned_len, struct socket_info* send_sock, int proto, unsigned int flags); char * build_res_buf_from_sip_res( struct sip_msg* msg, - unsigned int *returned_len, struct socket_info *sock); + unsigned int *returned_len, struct socket_info *sock,int flags); char * build_res_buf_from_sip_req( unsigned int code, @@ -98,7 +106,7 @@ char* via_builder( unsigned int *len, str *branch, str* extra_params, int proto, struct hostport *hp ); -int branch_builder( unsigned int hash_index, +int branch_builder( unsigned int hash_index, /* only either parameter useful */ unsigned int label, char * char_v, int branch, diff --git a/name_alias.c b/name_alias.c index 8d49bc49965..d46db83d68c 100644 --- a/name_alias.c +++ b/name_alias.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -45,7 +45,7 @@ struct alias_function* alias_fcts = NULL; int add_alias(char* name, int len, unsigned short port, unsigned short proto) { struct host_alias* a; - + if ((port) && (proto)){ /* don't add if there is already an alias matching it */ if (grep_aliases(name,len, port, proto)) return 0; diff --git a/name_alias.h b/name_alias.h index 6c110fcee14..12fdc8125ea 100644 --- a/name_alias.h +++ b/name_alias.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -64,7 +64,7 @@ static inline int grep_aliases(char* name, int len, unsigned short port, { struct host_alias* a; struct alias_function *af; - + #ifdef USE_IPV6 if ((len>2)&&((*name)=='[')&&(name[len-1]==']')){ /* ipv6 reference, skip [] */ @@ -73,11 +73,11 @@ static inline int grep_aliases(char* name, int len, unsigned short port, } #endif for(a=aliases;a;a=a->next) - if ((a->alias.len==len) && ((a->port==0) || (port==0) || - (a->port==port)) && ((a->proto==0) || (proto==0) || + if ((a->alias.len==len) && ((a->port==0) || (port==0) || + (a->port==port)) && ((a->proto==0) || (proto==0) || (a->proto==proto)) && (strncasecmp(a->alias.s, name, len)==0)) return 1; - + for( af=alias_fcts ; af ; af=af->next ) { if ( af->alias_f(name,len,port,proto)>0 ) return 1; diff --git a/opensips.8 b/opensips.8 index 2c999cfb428..a3053f0fcd5 100644 --- a/opensips.8 +++ b/opensips.8 @@ -186,9 +186,9 @@ see Full documentation on opensips is available at .I http://www.opensips.org/. .PP -Project tracker and SVN +Project tracker and GIT .I -http://sourceforge.net/projects/opensips/. +https://github.com/OpenSIPS/opensips. .PP Mailing lists: .nf diff --git a/packaging/debian-lenny/changelog b/packaging/debian-lenny/changelog deleted file mode 100644 index e311a377c20..00000000000 --- a/packaging/debian-lenny/changelog +++ /dev/null @@ -1,75 +0,0 @@ -opensips (1.9.0-1) stable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Tue, 29 Jan 2013 15:39:34 +0200 - - -opensips (1.8.0-1) stable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Thu, 22 Mar 2012 09:00:00 +0200 - - -opensips (1.7.0-1) stable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Thu, 12 Jul 2011 09:00:00 +0200 - - -opensips (1.6.0-1) unstable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Thu, 15 Oct 2009 09:00:00 +0200 - - -opensips (1.5.0-1) unstable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Mon, 21 Mar 2009 09:00:00 +0200 - - -opensips (1.4.0-1) unstable; urgency=low - - * First Public Release. - - -- Bogdan-Andrei Iancu Mon, 21 Jul 2008 09:00:00 +0200 - -opensips (1.8.0-1) stable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Thu, 22 Mar 2012 09:00:00 +0200 - - -opensips (1.7.0-1) stable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Thu, 12 Jul 2011 09:00:00 +0200 - - -opensips (1.6.0-1) unstable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Thu, 15 Oct 2009 09:00:00 +0200 - - -opensips (1.5.0-1) unstable; urgency=low - - * Major Public Release. - - -- Bogdan-Andrei Iancu Mon, 21 Mar 2009 09:00:00 +0200 - - -opensips (1.4.0-1) unstable; urgency=low - - * First Public Release. - - -- Bogdan-Andrei Iancu Mon, 21 Jul 2008 09:00:00 +0200 - diff --git a/packaging/debian-lenny/compat b/packaging/debian-lenny/compat deleted file mode 100644 index 7ed6ff82de6..00000000000 --- a/packaging/debian-lenny/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/packaging/debian-lenny/control b/packaging/debian-lenny/control deleted file mode 100644 index 807db1da2c4..00000000000 --- a/packaging/debian-lenny/control +++ /dev/null @@ -1,274 +0,0 @@ -Source: opensips -Section: net -Priority: optional -Maintainer: Bogdan Iancu -Uploaders: Bogdan Iancu -Build-Depends: debhelper (>= 5), dpatch, libmysqlclient15-dev, libexpat1-dev, libxml2-dev, libpq-dev, libradiusclient-ng-dev, flex, bison, zlib1g-dev, unixodbc-dev, libxmlrpc-c3-dev, libperl-dev, libsnmp-dev, dpkg-dev (>= 1.13.19), libdb-dev (>= 4.6.19), xsltproc, libconfuse-dev, libldap2-dev, libcurl4-gnutls-dev, libgeoip-dev (>= 1.4.4), libpcre3-dev -Standards-Version: 3.8.0 -Homepage: http://www.opensips.org/ - -Package: opensips -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, adduser -Suggests: opensips-mysql-module, opensips-postgres-module, opensips-unixodbc-module, opensips-jabber-module, opensips-cpl-module, opensips-radius-modules, opensips-presence-modules, opensips-xmlrpc-module, opensips-perl-modules, opensips-snmpstats-module, opensips-xmpp-module, opensips-carrierroute-module, opensips-berkeley-module, opensips-ldap-modules, opensips-geoip-module, opensips-regex-module, opensips-identity-module, opensips-b2bua-module, opensips-dbhttp-module, opensips-dialplan-module, opensips-memcached-module, opensips-json-module, opensips-console -Description: very fast and configurable SIP server - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - C Shell-like scripting language provides full control over the server's - behaviour. Its modular architecture allows only required functionality to be - loaded. - . - Among others, the following modules are available: Digest Authentication, CPL - scripts, Instant Messaging, MySQL support, Presence Agent, Radius - Authentication, Record Routing, SMS Gateway, Jabber/XMPP Gateway, Transaction - Module, Registrar and User Location, Load Balaning/Dispatching/LCR, - XMLRPC Interface. - . - This package contains the main OpenSIPS binary along with the principal modules - and support binaries. - -Package: opensips-dbg -Priority: extra -Architecture: any -Depends: opensips (= ${binary:Version}) -Conflicts: opensips (<< ${binary:Version}) -Description: very fast and configurable SIP server [debug symbols] - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package contains the debugging symbols for the OpenSIPS binaries and - modules. You only need to install it if you need to debug OpenSIPS. - -Package: opensips-mysql-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}), mysql-client -Description: MySQL database connectivity module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the MySQL database driver for OpenSIPS. - -Package: opensips-postgres-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}), postgresql-client -Description: PostgreSQL database connectivity module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the PostgreSQL database driver for OpenSIPS. - -Package: opensips-jabber-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: Jabber gateway module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the SIP to Jabber translator module for OpenSIPS. - -Package: opensips-cpl-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: CPL module (CPL interpreter engine) for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides a CPL (Call Processing Language) interpreter for - OpenSIPS, turning OpenSIPS into a CPL server (storage and interpreter). - -Package: opensips-radius-modules -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: Radius modules for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the RADIUS driver for the AAA API from OpenSIPS. - -Package: opensips-unixodbc-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: unixODBC database connectivity module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the unixODBC database driver for OpenSIPS. - -Package: opensips-presence-modules -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: SIMPLE presence modules for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides several OpenSIPS modules for implementing presence - server and presence user agent for RICH presence, registrar-based presence, - external triggered presence and XCAP support. - -Package: opensips-xmlrpc-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: XMLRPC support for OpenSIPS's Management Interface - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the XMLRPC transport implementation for OpenSIPS's - Management Interface. - -Package: opensips-perl-modules -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: Perl extensions and database driver for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides an interface for OpenSIPS to write Perl extensions and - the db_perlvdb database driver for OpenSIPS. - -Package: opensips-snmpstats-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}), snmpd -Description: SNMP AgentX subagent module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the snmpstats module for OpenSIPS. This module acts - as an AgentX subagent which connects to a master agent. - -Package: opensips-xmpp-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: XMPP gateway module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the SIP to XMPP IM translator module for OpenSIPS. - -Package: opensips-carrierroute-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: Carrierroute module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the carrierroute module for OpenSIPS, an integrated - solution for routing, balancing and blacklisting. - -Package: opensips-berkeley-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}), db4.6-util -Description: Berkeley Database module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the berkeley database module for OpenSIPS, a - high-performance embedded DB kernel. All database tables are stored - in files, no additional server is necessary. - -Package: opensips-ldap-modules -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: LDAP modules for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the ldap and h350 modules for OpenSIPS, enabling LDAP - queries from the OpenSIPS config and storage of SIP account data in an LDAP - directory. - -Package: opensips-geoip-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: IP address-to-location looku (MaxMind GeoIP API) for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This module is a lightweight wrapper for the MaxMind GeoIP API. - It adds IP address-to-location lookup capability to OpenSIPS - scripts. Lookups are executed against the freely-available GeoLite City - database; and the non-free GeoIP City database is drop-in - compatible Lookups are executed against the freely-available GeoLite City - database; and the non-free GeoIP City database is drop-in compatible - -Package: opensips-regex-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: PCRE regexp modules for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides a module for matching operations against regular - expressions using the powerful PCRE library. By default, OpenSIPS support - sed-like regular expresions; PCRE library brings perl-like regular expresions. - -Package: opensips-identity-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: SIP Identity module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides support for SIP Identity (see RFC 4474). - -Package: opensips-b2bua-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: B2B User Agent modules for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides modules for B2BUA support in OpenSIPS. Both the - implementation and control (XML based scenario description) are included. - -Package: opensips-dbhttp-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: HTTP database connectivity module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides the HTTP-based database driver for OpenSIPS - -Package: opensips-dialplan-module -Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}) -Description: Generic string translation module for OpenSIPS - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides dialplan module that implements generic string translations based on matching and replacement rules. It can be used to manipulate R-URI or a PV and to translated to a new format/value. - -Package: opensips-console -Architecture: any -Depends: opensips (= ${binary:Version}), python-mysqldb, libfrontier-rpc-perl, libnet-ip-perl, libberkeleydb-perl, libterm-readline-perl-perl -Suggests: opensips-mysql-module, opensips-postgres-module, opensips-unixodbc-module, opensips-xmlrpc-module, opensips-berkeley-module -Description: Generic tool for OpenSIPS provisioning - OpenSIPS is a very fast and flexible SIP (RFC3261) - server. Written entirely in C, OpenSIPS can handle thousands calls - per second even on low-budget hardware. - . - This package provides an OpenSIPS Console written in Perl for OpenSIPS - provisioning. diff --git a/packaging/debian-lenny/copyright b/packaging/debian-lenny/copyright deleted file mode 100644 index 6cdc735f6d1..00000000000 --- a/packaging/debian-lenny/copyright +++ /dev/null @@ -1,29 +0,0 @@ -This package was debianized by Andrei Pelinescu-Onciul - on Tue, 16 Jul 2002 15:41:31 +0200. -This package was debianized by Julien BLACHE -on Thu, 29 Jun 2006 09:55:24 +0200, based on Andrei's work. -This package was debianized by Bogdan IANCU -on Thu, 15 Oct 2009 21:14:24 +0200 - -It was downloaded from: http://opensips.org - -Upstream Authors: - Andrei Pelinescu-Onciul - Bogdan-Andrei Iancu - Daniel-Constantin Mierla - Jan Janak - Jiri Kuthan - Juha Heinanen - Ramona-Elena Modroiu - Maxim Sobolev - Miklos Tirpak - Nils Ohlmeier - and others ; see the AUTHORS file in the source code tree for details - -This software is copyright (c) 2002-2003 by FhG Fokus - -You are free to distribute this software under the terms of -the GNU General Public License. - -On Debian systems, the complete text of the GNU General Public -License can be found in the file `/usr/share/common-licenses/GPL. diff --git a/packaging/debian-lenny/opensips.README.Debian b/packaging/debian-lenny/opensips.README.Debian deleted file mode 100644 index 647439adc70..00000000000 --- a/packaging/debian-lenny/opensips.README.Debian +++ /dev/null @@ -1,38 +0,0 @@ -OpenSIPS for Debian ------------------- - -* init script check for fork=no -------------------------------- - -The OpenSIPS init script will not start OpenSIPS on boot if fork=no is -specified in the config file. The check in the initscript will match -any occurrence of fork=no in the file, even inside C-style comments. - -You can disable this check in the init script if you wish; just comment -out the calls to the check_fork function in the script. Your changes to -the init script will be preserved upon upgrade, as the file is tagged -as a conffile. - - -* OpenSIPS setup ---------------- - -To setup OpenSIPS, you need to: - - configure OpenSIPS properly to suit your needs - - edit /etc/default/opensips, adjust the MEMORY parameter and set - RUN_OPENSIPS to "yes" - -If you are building an HA cluster using heartbeat or similar, you'll want -to disable the init script by running: - - update-rc.d opensips remove - -so that OpenSIPS will not be launched at system startup. You still need -to set RUN_OPENSIPS to "yes" if you want to use the /etc/init.d/opensips init -script. - -Set the DUMP_CORE parameter in /etc/default/opensips to "yes" if you want to -get a core dump in case OpenSIPS crashes. The debug symbols for OpenSIPS are -provided by the opensips-dbg package. - --- Julien BLACHE , Fri, 08 Sep 2006 14:43:21 +0200 diff --git a/packaging/debian-lenny/opensips.default b/packaging/debian-lenny/opensips.default deleted file mode 100644 index 84cb99c961d..00000000000 --- a/packaging/debian-lenny/opensips.default +++ /dev/null @@ -1,24 +0,0 @@ -# -# OpenSIPS startup options -# - -# Set to yes to enable opensips, once configured properly. -RUN_OPENSIPS=no - -# User to run as -USER=opensips - -# Group to run as -GROUP=opensips - -# Amount of memory to allocate for the running OpenSIPS server (in Mb) -MEMORY=64 - -# Enable the server to leave a core file when it crashes. -# Set this to 'yes' to enable OpenSIPS to leave a core file when it crashes -# or 'no' to disable this feature. This option is case sensitive and only -# accepts 'yes' and 'no' and only in lowercase letters. -# On some systems (e.g. Ubuntu 6.10, Debian 4.0) it is necessary to specify -# a directory for the core files to get a dump. Look into the opensips -# init file for an example configuration. -DUMP_CORE=no diff --git a/packaging/debian-lenny/opensips.dirs b/packaging/debian-lenny/opensips.dirs deleted file mode 100644 index 40d7ac63e4d..00000000000 --- a/packaging/debian-lenny/opensips.dirs +++ /dev/null @@ -1,2 +0,0 @@ -var/run/opensips - diff --git a/packaging/debian-lenny/opensips.examples b/packaging/debian-lenny/opensips.examples deleted file mode 100644 index c48447a3e9c..00000000000 --- a/packaging/debian-lenny/opensips.examples +++ /dev/null @@ -1,2 +0,0 @@ -examples/* - diff --git a/packaging/debian-lenny/opensips.init b/packaging/debian-lenny/opensips.init deleted file mode 100644 index 173e2b9d57a..00000000000 --- a/packaging/debian-lenny/opensips.init +++ /dev/null @@ -1,159 +0,0 @@ -#! /bin/sh -# -### BEGIN INIT INFO -# Provides: opensips -# Required-Start: $syslog $network $local_fs $time -# Required-Stop: $syslog $network $local_fs -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start the OpenSIPS SIP server -# Description: Start the OpenSIPS SIP server -### END INIT INFO -# -# TODO: -# The following fields should be added (and completed): -# Should-Start: postgresql mysql radius -# Should-Stop: postgresql mysql radius - -PATH=/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/opensips -NAME=opensips -DESC=opensips -HOMEDIR=/var/run/opensips -PIDFILE=$HOMEDIR/$NAME.pid -DEFAULTS=/etc/default/opensips -RUN_OPENSIPS=no - -# Do not start opensips if fork=no is set in the config file -# otherwise the boot process will just stop -check_fork () -{ - if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" /etc/opensips/opensips.cfg; then - echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/opensips debug instead" - exit 1 - fi -} - -check_opensips_config () -{ - # Check if opensips configuration is valid before starting the server - set +e - out=$($DAEMON -c 2>&1 > /dev/null) - retcode=$? - set -e - if [ "$retcode" != '0' ]; then - echo "Not starting $DESC: invalid configuration file!" - echo -e "\n$out\n" - exit 1 - fi -} - -create_radius_seqfile () -{ - # Create a radius sequence file to be used by the radius client if - # radius accounting is enabled. This is needed to avoid any issue - # with the file not being writable if opensips first starts as user - # root because DUMP_CORE is enabled and creates this file as user - # root and then later it switches back to user opensips and cannot - # write to the file. If the file exists before opensips starts, it - # won't change it's ownership and will be writable for both root - # and opensips, no matter what options are chosen at install time - RADIUS_SEQ_FILE=/var/run/opensips/opensips_radius.seq - if [ -d /var/run/opensips ]; then - chown ${USER}:${GROUP} /var/run/opensips - - if [ ! -f $RADIUS_SEQ_FILE ]; then - touch $RADIUS_SEQ_FILE - fi - - chown ${USER}:${GROUP} $RADIUS_SEQ_FILE - chmod 660 $RADIUS_SEQ_FILE - fi -} - -test -f $DAEMON || exit 0 - -# Load startup options if available -if [ -f $DEFAULTS ]; then - . $DEFAULTS || true -fi - -if [ "$RUN_OPENSIPS" != "yes" ]; then - echo "OpenSIPS not yet configured. Edit /etc/default/opensips first." - exit 0 -fi - -set -e - -MEMORY=$((`echo $MEMORY | sed -e 's/[^0-9]//g'`)) -[ -z "$USER" ] && USER=opensips -[ -z "$GROUP" ] && GROUP=opensips -[ $MEMORY -le 0 ] && MEMORY=32 - -if test "$DUMP_CORE" = "yes" ; then - # set proper ulimit - ulimit -c unlimited - - # directory for the core dump files - # COREDIR=/home/corefiles - # [ -d $COREDIR ] || mkdir $COREDIR - # chmod 777 $COREDIR - # echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern -fi - -OPTIONS="-P $PIDFILE -m $MEMORY -u $USER -g $GROUP" - -case "$1" in - start|debug) - check_opensips_config - create_radius_seqfile - - if [ "$1" != "debug" ]; then - check_fork - fi - - echo -n "Starting $DESC: $NAME" - start-stop-daemon --start --quiet --pidfile $PIDFILE \ - --exec $DAEMON -- $OPTIONS || echo -n " already running" - echo "." - ;; - stop) - echo -n "Stopping $DESC: $NAME" - start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \ - --exec $DAEMON - echo "." - ;; - restart|force-reload) - check_opensips_config - create_radius_seqfile - - echo -n "Restarting $DESC: $NAME" - start-stop-daemon --oknodo --stop --quiet --pidfile \ - $PIDFILE --exec $DAEMON - sleep 1 - start-stop-daemon --start --quiet --pidfile \ - $PIDFILE --exec $DAEMON -- $OPTIONS - echo "." - ;; - status) - echo -n "Status of $DESC: " - if [ ! -r "$PIDFILE" ]; then - echo "$NAME is not running." - exit 3 - fi - if read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then - echo "$NAME is running." - exit 0 - else - echo "$NAME is not running but $PIDFILE exists." - exit 1 - fi - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload|debug|status}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/packaging/debian-lenny/opensips.postinst b/packaging/debian-lenny/opensips.postinst deleted file mode 100644 index 1b6c233defd..00000000000 --- a/packaging/debian-lenny/opensips.postinst +++ /dev/null @@ -1,48 +0,0 @@ -#! /bin/sh -# -# $Id: opensips.postinst 5891 2009-07-20 12:53:09Z bogdan_iancu $ - -PKG=opensips -DEFAULTS=/etc/default/opensips -HOMEDIR=/var/run/opensips - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package -# -# quoting from the policy: -# Any necessary prompting should almost always be confined to the -# post-installation script, and should be protected with a conditional -# so that unnecessary prompting doesn't happen if a package's -# installation fails and the `postinst' is called with `abort-upgrade', -# `abort-remove' or `abort-deconfigure'. - -case "$1" in - configure) - adduser --quiet --system --group --disabled-password \ - --shell /bin/false --gecos "OpenSIPS" \ - --home $HOMEDIR opensips || true - - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - diff --git a/packaging/debian-lenny/patches/00list b/packaging/debian-lenny/patches/00list deleted file mode 100644 index 8b137891791..00000000000 --- a/packaging/debian-lenny/patches/00list +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packaging/debian-lenny/rules b/packaging/debian-lenny/rules deleted file mode 100755 index 58ffdfa7de6..00000000000 --- a/packaging/debian-lenny/rules +++ /dev/null @@ -1,292 +0,0 @@ -#!/usr/bin/make -f -# Sample debian/rules that uses debhelper. -# GNU copyright 1997 to 1999 by Joey Hess. -# 2010/08/24: Allow building of individual modules (kennard) - -# To control which packages get built, set BUILD_MODPKG_LIST to list -# of packages to build (see ALL_MODPKG_LIST for candiate names). Set to -# 'NONE' to not build any module packages (the primary package is always -# built). By default all delcared packages (debian/control) will be built. - - -# Supported DEB_BUILD_OPTIONS: -# noopt,nostrip,debug -- standard -# upstreamcflags -- don't set cflags, let upstream package Makefile do it - -DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) - -DEBVERSION:=$(shell head -n 1 debian/changelog \ - | sed -e 's/^[^(]*(\([^)]*\)).*/\1/') -UPVERSION:=$(shell echo $(DEBVERSION) | sed -e 's/^.*://' -e 's/-[0-9.]*$$//' -e 's/.dfsg$$//') - -FILENAME := opensips_$(UPVERSION).orig.tar.gz -UPFILENAME := opensips-$(UPVERSION)-tls_src.tar.gz -URL := http://opensips.org/pub/opensips/$(UPVERSION)/src/opensips-$(UPVERSION)-tls_src.tar.gz - -# Uncomment this to turn on verbose mode. -# export DH_VERBOSE=1 - -# Include dpatch rules -include /usr/share/dpatch/dpatch.make - - -# Do we want the TLS version ? -# Disabled by default due to license issues, set to non-void to enable -TLS= - - -# List of all debian module packages we will build -# Used to index the make variable below, which has details about each package -ALL_MODPKG_LIST := \ - MYSQL POSTGRES UNIXODBC JABBER CPL RADIUS \ - PRESENCE XMLRPC PERL SNMPSTATS XMPP CROUTE BERKELEY LDAP \ - GEOIP REGEX IDENTITY B2BUA DBHTTP DIALPLAN - -ifeq ($(BUILD_MODPKG_LIST),NONE) -override BUILD_MODPKG_LIST := -else -ifeq ($(BUILD_MODPKG_LIST),) -override BUILD_MODPKG_LIST := $(ALL_MODPKG_LIST) -endif -endif - -# FOO_MODULES is the directory name within modules/ that belongs to the package -# FOO_MOD_PATH is same as FOO_MODULES, but with 'modules/' prepended - -MYSQL_PKGNAME = opensips-mysql-module -MYSQL_MODULES = db_mysql -MYSQL_MOD_PATH=$(addprefix modules/, $(MYSQL_MODULES)) -POSTGRES_PKGNAME = opensips-postgres-module -POSTGRES_MODULES = db_postgres -POSTGRES_MOD_PATH=$(addprefix modules/, $(POSTGRES_MODULES)) -UNIXODBC_PKGNAME = opensips-unixodbc-module -UNIXODBC_MODULES=db_unixodbc -UNIXODBC_MOD_PATH=$(addprefix modules/, $(UNIXODBC_MODULES)) -JABBER_PKGNAME = opensips-jabber-module -JABBER_MODULES = jabber -JABBER_MOD_PATH=$(addprefix modules/, $(JABBER_MODULES)) -CPL_PKGNAME = opensips-cpl-module -CPL_MODULES = cpl-c -CPL_MOD_PATH=$(addprefix modules/, $(CPL_MODULES)) -RADIUS_PKGNAME = opensips-radius-modules -RADIUS_MODULES = aaa_radius peering -RADIUS_MOD_PATH=$(addprefix modules/, $(RADIUS_MODULES)) -PRESENCE_PKGNAME = opensips-presence-modules -PRESENCE_MODULES = presence presence_dialoginfo presence_xml presence_mwi presence_xcapdiff pua pua_bla pua_dialoginfo pua_mi pua_usrloc pua_xmpp rls xcap xcap_client -PRESENCE_MOD_PATH=$(addprefix modules/, $(PRESENCE_MODULES)) -XMLRPC_PKGNAME = opensips-xmlrpc-module -XMLRPC_MODULES = mi_xmlrpc -XMLRPC_MOD_PATH=$(addprefix modules/, $(XMLRPC_MODULES)) -PERL_PKGNAME = opensips-perl-modules -PERL_MODULES = perl db_perlvdb -PERL_MOD_PATH=$(addprefix modules/, $(PERL_MODULES)) -SNMPSTATS_PKGNAME = opensips-snmpstats-module -SNMPSTATS_MODULES = snmpstats -SNMPSTATS_MOD_PATH=$(addprefix modules/, $(SNMPSTATS_MODULES)) -XMPP_PKGNAME = opensips-xmpp-module -XMPP_MODULES = xmpp -XMPP_MOD_PATH=$(addprefix modules/, $(XMPP_MODULES)) -CROUTE_PKGNAME = opensips-carrierroute-module -CROUTE_MODULES = carrierroute -CROUTE_MOD_PATH=$(addprefix modules/, $(CROUTE_MODULES)) -BERKELEY_PKGNAME = opensips-berkeley-module -BERKELEY_MODULES = db_berkeley -BERKELEY_MOD_PATH=$(addprefix modules/, $(BERKELEY_MODULES)) -LDAP_PKGNAME = opensips-ldap-modules -LDAP_MODULES = ldap h350 -LDAP_MOD_PATH=$(addprefix modules/, $(LDAP_MODULES)) -GEOIP_PKGNAME = opensips-geoip-module -GEOIP_MODULES = mmgeoip -GEOIP_MOD_PATH=$(addprefix modules/, $(GEOIP_MODULES)) -REGEX_PKGNAME = opensips-regex-module -REGEX_MODULES = regex -REGEX_MOD_PATH=$(addprefix modules/, $(REGEX_MODULES)) -IDENTITY_PKGNAME = opensips-identity-module -IDENTITY_MODULES = identity -IDENTITY_MOD_PATH=$(addprefix modules/, $(IDENTITY_MODULES)) -B2BUA_PKGNAME = opensips-b2bua-module -B2BUA_MODULES = b2b_entities b2b_logic -B2BUA_MOD_PATH=$(addprefix modules/, $(B2BUA_MODULES)) -DBHTTP_PKGNAME = opensips-dbhttp-module -DBHTTP_MODULES = db_http -DBHTTP_MOD_PATH=$(addprefix modules/, $(DBHTTP_MODULES)) -DIALPLAN_PKGNAME = opensips-dialplan-module -DIALPLAN_MODULES = dialplan -DIALPLAN_MOD_PATH=$(addprefix modules/, $(DIALPLAN_MODULES)) - - -# Need this per-package variables available in environment so accessible -# to shell. Since have underscore in them, need to explicitly export -export $(foreach pkg,$(ALL_MODPKG_LIST),$(pkg)_PKGNAME $(pkg)_MODULES $(pkg)_MOD_PATH) - -# not needed anymore -#ALL_PACKAGES = opensips $(foreach pkg,$(ALL_MODPKG_LIST),$($(pkg)_PKGNAME)) \ -# opensips-console -ALL_MODULES = $(foreach pkg,$(ALL_MODPKG_LIST),$($(pkg)_MODULES)) -BUILD_MODULE_PATHS = $(foreach pkg,$(BUILD_MODPKG_LIST),$($(pkg)_MOD_PATH)) - -## modules not in the "main" package or unstable modules that we never want to build -## Everything we don't specifically exclude here will get built into the primary package -NONCORE_MODULES = $(ALL_MODULES) osp - - -ifeq (cc, $(CC)) - CC = gcc -endif - -ifneq (,$(findstring upstreamcflags,$(DEB_BUILD_OPTIONS))) -CFLAGS= -else -CFLAGS = -Wall -g - -ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) - CFLAGS += -O0 -else - CFLAGS += -O2 -endif -endif - -# force lib (versus lib64) and SMP support all the time -VARS = LIBDIR=lib ISSMP=yes TLS=$(TLS) - -ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) - INSTALL_PROGRAM += -s -endif - -configure: configure-stamp -configure-stamp: - dh_testdir - # Add here commands to configure the package. - - touch configure-stamp - - -build: build-stamp -build-stamp: patch-stamp configure-stamp - dh_testdir - - # Add here commands to compile the package. - CC="$(CC)" CFLAGS="$(CFLAGS)" $(VARS) $(MAKE) app \ - modules skip_modules="$(NONCORE_MODULES)" cfg-target=/etc/opensips/ - CC="$(CC)" CFLAGS="$(CFLAGS)" $(VARS) $(MAKE) \ - modules modules="$(BUILD_MODULE_PATHS)" cfg-target=/etc/opensips/ - # generate the utils db_berkeley - CC="$(CC)" CFLAGS="$(CFLAGS)" $(VARS) $(MAKE) utils include_modules="db_berkeley" - - touch build-stamp - -clean: real-clean unpatch -real-clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - - # Add here commands to clean up after the build process. - $(MAKE) $(VARS) include_modules="$(ALL_MODULES)" proper - rm -f cfg.tab.h - rm -f utils/opensipsunix/opensipsunix.o utils/opensipsunix/opensipsunix - rm -f utils/db_berkeley/bdb_recover.o utils/db_berkeley/bdb_recover - - dh_clean - -show-env: - env - -show-mod-info: - set -e;\ - for mod in $(ALL_MODPKG_LIST) ; do\ - eval mod_pkgname=\$$$${mod}_PKGNAME;\ - eval mod_modules=\$$$${mod}_MODULES;\ - eval mod_paths=\$$$${mod}_MOD_PATH;\ - echo "MODULE $${mod} AS $${mod_pkgname} FROM $${mod_modules} PATHS $${mod_paths}";\ - done - @echo "ALL_MOD_PATHS: $(ALL_MODULE_PATHS)" - -install: build - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - - # Add here commands to install the package into debian/opensips - # opensips base package - CC="$(CC)" CFLAGS="$(CFLAGS)" $(VARS) $(MAKE) install-app \ - install-modules-all skip_modules="$(NONCORE_MODULES)" \ - basedir=$(CURDIR)/debian/opensips \ - prefix=/usr \ - cfg-prefix=$(CURDIR)/debian/opensips \ - cfg-target=/etc/opensips/ \ - doc-dir=share/doc/opensips - - find $(CURDIR)/debian/opensips/etc/opensips -type f -exec chmod -x {} \; - sed -i -e "s/^PATH.*//" $(CURDIR)/debian/opensips/usr/sbin/opensipsctl - # not needed anymore with makefile restructring - #rm -f $(CURDIR)/debian/opensips/usr/sbin/osipsconsole - - set -e;\ - for pkg in $(BUILD_MODPKG_LIST) ; do\ - eval pkg_pkgname=\$$$${pkg}_PKGNAME;\ - eval pkg_modules=\$$$${pkg}_MODULES;\ - eval pkg_paths=\$$$${pkg}_MOD_PATH;\ - echo "rules: Installing $${pkg} as $${pkg_pkgname} from $${pkg_modules} ...";\ - CC="$(CC)" CFLAGS="$(CFLAGS)" $(VARS) $(MAKE) install-modules-all \ - modules="$${pkg_paths}" \ - basedir=$(CURDIR)/debian/$${pkg_pkgname} \ - prefix=/usr \ - cfg-prefix=$(CURDIR)/debian/$${pkg_pkgname} \ - cfg-target=/etc/opensips/ \ - doc-dir=share/doc/$${pkg_pkgname} \ - ;\ - done - - # install only the opensips console tool - $(MAKE) install-console \ - basedir=$(CURDIR)/debian/opensips-console \ - prefix=/usr - - # the modules packages all ship an empty /usr/sbin directory. clean it up - # not needed anymore with makefile restructuring - #-rmdir $(patsubst %,$(CURDIR)/debian/%/usr/sbin,$(ALL_PACKAGES)) - -# This single target is used to build all the packages, all at once, or -# one at a time. So keep in mind: any options passed to commands here will -# affect _all_ packages. Anything you want to only affect one package -# should be put in another target, such as the install target. -binary-arch: build install - dh_testdir - dh_testroot - dh_installdocs - dh_installexamples --exclude=".svn" -# dh_installlogrotate - dh_installinit -popensips -- defaults 23 - dh_installcron - dh_installman - dh_installinfo - dh_installchangelogs - dh_link - dh_strip --dbg-package=opensips-dbg - dh_compress - dh_fixperms - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -# Build architecture-independent packages using the common target -binary-indep: build install -# We have nothing to do by default. - -binary: binary-indep binary-arch - -print-version: - @@echo "Debian version: $(DEBVERSION)" - @@echo "Upstream version: $(UPVERSION)" - -get-orig-source: - @@dh_testdir - @@[ -d ../tarballs/. ]||mkdir -p ../tarballs - @@echo Downloading $(FILENAME) from $(URL) ... - @@wget -N -nv -T10 -t3 -O ../tarballs/$(FILENAME) $(URL) - -.PHONY: build clean binary-indep binary-arch binary install configure patch unpatch real-clean diff --git a/packaging/debian/changelog b/packaging/debian/changelog index af0c75a99e1..93669e576ed 100644 --- a/packaging/debian/changelog +++ b/packaging/debian/changelog @@ -1,3 +1,17 @@ +opensips (1.11.0-1) stable; urgency=low + + * Major Public Release. + + -- Bogdan-Andrei Iancu Thu, 20 Mar 2014 21:32:16 +0200 + + +opensips (1.10.0-1) stable; urgency=low + + * Major Public Release. + + -- Bogdan-Andrei Iancu Mon, 05 Aug 2013 16:31:46 +0200 + + opensips (1.9.0-1) stable; urgency=low * Major Public Release. diff --git a/packaging/debian/control b/packaging/debian/control index 2fbdfe5b886..b05964c25d3 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -330,7 +330,7 @@ Description: LUA extensions for OpenSIPS Package: opensips-http-modules Architecture: any -Depends: ${shlibs:Depends}, opensips (= ${binary:Version}), libmicrohttpd5 +Depends: ${shlibs:Depends}, opensips (= ${binary:Version}), libmicrohttpd5|libmicrohttpd10 Description: HTTP transport layer and Management Interface for OpenSIPS. OpenSIPS is a very fast and flexible SIP (RFC3261) server. Written entirely in C, OpenSIPS can handle thousands calls diff --git a/packaging/debian/opensips.init b/packaging/debian/opensips.init index 6a5d3cc8a18..d9c35718d63 100644 --- a/packaging/debian/opensips.init +++ b/packaging/debian/opensips.init @@ -19,6 +19,9 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/opensips NAME=opensips DESC=opensips +CFGFILE=/etc/opensips/opensips.cfg +M4CFGFILE=/etc/opensips/opensips.m4 +M4ARCHIVEDIR=/etc/opensips/archive HOMEDIR=/var/run/opensips PIDFILE=$HOMEDIR/$NAME.pid DEFAULTS=/etc/default/opensips @@ -28,7 +31,7 @@ RUN_OPENSIPS=no # otherwise the boot process will just stop check_fork () { - if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" /etc/opensips/opensips.cfg; then + if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/opensips debug instead" exit 1 fi @@ -119,6 +122,28 @@ case "$1" in chmod 775 "$HOMEDIR" chown "$USER:$GROUP" "$HOMEDIR" >/dev/null 2>&1 || true + # Generate config from M4 + if [ -f $M4CFGFILE ]; then + m4 -Q $M4CFGFILE >$CFGFILE.tmp + if [ $? != 0 ]; then + echo "Cannot process m4 macro" + rm "$CFGFILE.tmp" + exit 1 + fi + + [ -e $CFGFILE ] || touch $CFGFILE + + # compare configs + if [ `md5sum $CFGFILE|awk '{print $1}'` != `md5sum $CFGFILE.tmp|awk '{print $1}'` ]; then + mkdir -p "$M4ARCHIVEDIR" + mv "$CFGFILE" "$M4ARCHIVEDIR/$NAME.cfg-`date +%Y%m%d_%H%M%S`" + fi + + mv "$CFGFILE.tmp" "$CFGFILE" + chown $USER:$GROUP $CFGFILE + chmod 640 $CFGFILE + fi + echo -n "Starting $DESC: $NAME" start-stop-daemon --start --quiet --pidfile $PIDFILE \ --exec $DAEMON -- $OPTIONS || echo -n " already running" diff --git a/packaging/debian/rules b/packaging/debian/rules index ad2b20a915d..479c3894d15 100755 --- a/packaging/debian/rules +++ b/packaging/debian/rules @@ -130,7 +130,7 @@ LUA_PKGNAME = opensips-lua-module LUA_MODULES = lua LUA_MOD_PATH=$(addprefix modules/, $(LUA_MODULES)) HTTP_PKGNAME = opensips-http-modules -HTTP_MODULES = httpd mi_http pi_http +HTTP_MODULES = httpd mi_http pi_http mi_json HTTP_MOD_PATH=$(addprefix modules/, $(HTTP_MODULES)) JSON_PKGNAME = opensips-json-module JSON_MODULES = json diff --git a/packaging/fedora/opensips.init b/packaging/fedora/opensips.init index 7e8ac40fcd7..af680353895 100644 --- a/packaging/fedora/opensips.init +++ b/packaging/fedora/opensips.init @@ -21,10 +21,13 @@ . /etc/rc.d/init.d/functions prog=opensips -oser=/usr/sbin/$prog +opensips=/usr/sbin/$prog +cfgdir="/etc/$prog" pidfile="/var/run/$prog.pid" lockfile="/var/lock/subsys/$prog" -configfile="/etc/$prog/$prog.cfg" +configfile="$cfgdir/$prog.cfg" +m4configfile="$cfgdir/$prog.m4" +m4archivedir="$cfgdir/archive" OPTIONS="" RETVAL=0 @@ -39,9 +42,32 @@ start() { return 0 fi + # Generate config from M4 + if [ -f $m4configfile ]; then + cd "$cfgdir" + m4 -Q $m4configfile >$configfile.tmp + if [ $? != 0 ]; then + echo -n "cannot process m4 macro" && failure && echo + rm "$configfile.tmp" + return 1 + fi + + [ -e $configfile ] || touch $configfile + + # compare configs + if [ `md5sum $configfile|awk '{print $1}'` != `md5sum $configfile.tmp|awk '{print $1}'` ]; then + mkdir -p "$m4archivedir" + mv "$configfile" "$m4archivedir/$prog.cfg-`date +%Y%m%d_%H%M%S`" + fi + + mv "$configfile.tmp" "$configfile" + chown $prog:$prog $configfile + chmod 640 $configfile + fi + # there is something at end of this output which is needed to # report proper [ OK ] status in Fedora scripts - daemon $oser -P $pidfile -f $configfile $OPTIONS 2>/dev/null | tail -1 + daemon $opensips -u $prog -g $prog -P $pidfile -f $configfile $OPTIONS 2>/dev/null | tail -1 RETVAL=$? echo [ $RETVAL = 0 ] && touch $lockfile diff --git a/packaging/fedora/opensips.m4cfg b/packaging/fedora/opensips.m4cfg new file mode 100644 index 00000000000..e871e352056 --- /dev/null +++ b/packaging/fedora/opensips.m4cfg @@ -0,0 +1,32 @@ +#!/bin/bash + +prog=opensips +cfgdir="/etc/$prog" +configfile="$cfgdir/$prog.cfg" +m4configfile="$cfgdir/$prog.m4" +m4archivedir="$cfgdir/archive" + +# Generate config from M4 +if [ -f $m4configfile ]; then + cd "$cfgdir" + m4 -Q $m4configfile >$configfile.tmp + if [ $? != 0 ]; then + echo "cannot process m4 macro" + rm "$configfile.tmp" + exit 1 + fi + + [ -e $configfile ] || touch $configfile + + # compare configs + if [ `md5sum ${configfile}|awk '{print $1}'` != `md5sum ${configfile}.tmp|awk '{print $1}'` ]; then + mkdir -p "${m4archivedir}" + mv "${configfile}" "${m4archivedir}/${prog}.cfg-`date +%Y%m%d_%H%M%S`" + fi + + mv "${configfile}.tmp" "${configfile}" + chown ${prog}:${prog} ${configfile} + chmod 640 ${configfile} +fi + +exit 0 diff --git a/packaging/fedora/opensips.service b/packaging/fedora/opensips.service index c69f1643792..7b0ea3a4b9b 100644 --- a/packaging/fedora/opensips.service +++ b/packaging/fedora/opensips.service @@ -9,6 +9,7 @@ Group=opensips EnvironmentFile=-/etc/sysconfig/opensips PIDFile=/var/run/opensips/opensips.pid ExecStart=/usr/sbin/opensips -P /var/run/opensips/opensips.pid -f /etc/opensips/opensips.cfg $OPTIONS +ExecStartPre=/usr/sbin/opensips-m4cfg [Install] WantedBy=multi-user.target diff --git a/packaging/fedora/opensips.spec b/packaging/fedora/opensips.spec index 8c3a260aba9..e58c8ee0897 100644 --- a/packaging/fedora/opensips.spec +++ b/packaging/fedora/opensips.spec @@ -1,29 +1,27 @@ %if 0%{?rhel} # copied from lm_sensors exclusive arch %ifnarch alpha i386 i486 i586 i686 pentium3 pentium4 athlon x86_64 -%define disable_snmpstats snmpstats +%global disable_snmpstats snmpstats %endif %endif -%define EXCLUDE_MODULES mi_xmlrpc osp json %{?disable_snmpstats} %{!?_with_oracle:db_oracle} +%global EXCLUDE_MODULES sngtc osp cachedb_cassandra cachedb_couchbase cachedb_mongodb %{?disable_snmpstats} %{?el5:db_perlvdb} %{?el5:cachedb_redis} %{!?_with_oracle:db_oracle} lua Summary: Open Source SIP Server Name: opensips -Version: 1.9.0 -Release: 4%{?dist} +Version: 1.11.0 +Release: 1%{?dist} License: GPLv2+ Group: System Environment/Daemons Source0: http://opensips.org/pub/%{name}/%{version}/src/%{name}-%{version}-tls_src.tar.gz -Source1: %{name}.sysconfig -Patch1: opensips--init.patch -Patch2: opensips--openssl10.patch URL: http://opensips.org BuildRequires: expat-devel BuildRequires: libxml2-devel BuildRequires: bison BuildRequires: flex -#BuildRequires: subversion +BuildRequires: subversion +BuildRequires: which # needed by snmpstats BuildRequires: radiusclient-ng-devel BuildRequires: mysql-devel @@ -37,20 +35,38 @@ BuildRequires: net-snmp-devel BuildRequires: unixODBC-devel BuildRequires: openssl-devel BuildRequires: expat-devel -#BuildRequires: xmlrpc-c-devel +BuildRequires: xmlrpc-c-devel BuildRequires: libconfuse-devel +%if 0%{?rhel} BuildRequires: db4-devel +%else +BuildRequires: libdb-devel +%endif BuildRequires: openldap-devel BuildRequires: curl-devel -BuildRequires: libmemcached-devel BuildRequires: GeoIP-devel BuildRequires: pcre-devel - - +BuildRequires: python-devel +%if 0%{?fedora} > 16 +BuildRequires: systemd-units +%endif +BuildRequires: libxslt +BuildRequires: lynx +BuildRequires: ncurses-devel +BuildRequireS: json-c-devel + +#Initscripts +%if 0%{?fedora} > 16 +# Users and groups +Requires(pre): shadow-utils +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd +%else Requires(post): chkconfig Requires(preun):chkconfig -# for /sbin/service Requires(preun):initscripts +%endif BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %description @@ -108,6 +124,7 @@ server, namely DIameter Server Client (DISC). Summary: Back-2-Back User Agent Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} +Requires: %{name}-pua %description b2bua B2BUA is an implementation of the behavior of a B2BUA as defined in RFC 3261 @@ -118,7 +135,7 @@ Summary: Routing extension suitable for carriers Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} -%description carrierroute +%description carrierroute A module which provides routing, balancing and blacklisting capabilities. %package cpl-c @@ -132,7 +149,7 @@ Support for uploading/downloading/removing scripts via SIP REGISTER method is present. %package db_berkeley -Summary: Berkley DB backend support +Summary: Berkeley DB backend support Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} @@ -149,6 +166,64 @@ Requires: %{name} = %{version}-%{release} This module provides access to a database that is implemented as a HTTP server. +%if %{undefined el5} +%package db_perlvdb +Summary: Perl virtual database engine +Group: System Environment/Daemons +# require perl-devel for >F7 and perl for <=F6 +BuildRequires: perl(ExtUtils::MakeMaker) +Requires: %{name} = %{version}-%{release} +Requires: %{name}-perl +Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) + +%description db_perlvdb +The Perl Virtual Database (VDB) provides a virtualization framework for +OpenSIPS's database access. It does not handle a particular database engine +itself but lets the user relay database requests to arbitrary Perl functions. +%endif + +%package event_datagram +Summary: Event datagram module +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} + +%description event_datagram +This is a module which provides a UNIX/UDP SOCKET transport layer +implementation for the Event Interface. + +%package event_rabbitmq +Summary: Event RabbitMQ module +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} +BuildRequires: librabbitmq-devel + +%description event_rabbitmq +This module provides the implementation of a RabbitMQ client for the Event Interface. +It is used to send AMQP messages to a RabbitMQ server each time the Event Interface +triggers an event subscribed for. + +%package event_route +Summary: Route triggering based on events +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} + +%description event_route +This module provides a simple way for handling different events, triggered through +the OpenSIPS Event Interface, directly from the OpenSIPS script. For a specific event, +a special route (event_route) has to be declared in the script, and should contain +the code that handles the event. The route is executed by the module when the +corresponding event is raised by the OpenSIPS Event Interface. + +%package event_xmlrpc +Summary: Event XMLRPC client module +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} + +%description event_xmlrpc +This module is an implementation of an XMLRPC client used to notify XMLRPC servers +whenever certain notifications are raised by OpenSIPS. It acts as a transport layer +for the Event Notification Interface. + %package h350 Summary: H350 implementation Group: System Environment/Daemons @@ -159,6 +234,15 @@ The OpenSIPS H350 module enables an OpenSIPS SIP proxy server to access SIP account data stored in an LDAP [RFC4510] directory containing H.350 [H.350] commObjects. +%package httpd +Summary: HTTP transport layer implementation +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} +BuildRequires: libmicrohttpd-devel + +%description httpd +This module provides an HTTP transport layer for OpenSIPS. + %package jabber Summary: Gateway between OpenSIPS and a jabber server Group: System Environment/Daemons @@ -167,6 +251,15 @@ Requires: %{name} = %{version}-%{release} %description jabber Jabber module that integrates XODE XML parser for parsing Jabber messages. +%package json +Summary: A JSON variables within the script +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} + +%description json +This module introduces a new type of variable that provides both serialization and +de-serialization from JSON format. + %package ldap Summary: LDAP connector Group: System Environment/Daemons @@ -179,6 +272,7 @@ The LDAP module implements an LDAP search interface for OpenSIPS. Summary: Memcached connector Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} +BuildRequires: libmemcached-devel %description memcached Memcached module is an implementation of a cache system designed to @@ -193,26 +287,37 @@ Requires: %{name} = %{version}-%{release} Mmgeoip is a lightweight wrapper for the MaxMind GeoIP API. It adds IP address-to-location lookup capability to OpenSIPS scripts. -%if %{defined db_oracle} +%package mysql +Summary: MySQL Storage Support for the OpenSIPS +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} +Requires: mysql-libs + +%description mysql +The %{name}-mysql package contains the MySQL plugin for %{name}, which allows +a MySQL-Database to be used for persistent storage. + +%if 0%{?_with_oracle} %package oracle Summary: Oracle Storage Support for the OpenSIPS Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} +BuildRequires: oracle-instantclient-devel -%description oracle +%description oracle The %{name}-oracle package contains the Oracle plugin for %{name}, which allows a Oracle-Database to be used for persistent storage. %endif -%package mysql -Summary: MySQL Storage Support for the OpenSIPS +%package peering +Summary: Radius peering Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} - -%description mysql -The %{name}-mysql package contains the MySQL plugin for %{name}, which allows -a MySQL-Database to be used for persistent storage. +%description peering +Peering module allows SIP providers (operators or organizations) +to verify from a broker if source or destination of a SIP request +is a trusted peer. %package perl Summary: Helps implement your own OpenSIPS extensions in Perl @@ -222,7 +327,11 @@ BuildRequires: perl(ExtUtils::MakeMaker) %if 0%{?rhel} BuildRequires: perl(ExtUtils::Embed) %else +%if 0%{?redhat} == 5 BuildRequires: perl(ExtUtils::Embed), perl-devel +%else +BuildRequires: perl(ExtUtils::Embed) +%endif %endif Requires: %{name} = %{version}-%{release} Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) @@ -236,34 +345,21 @@ simple access to the full world of CPAN modules. SIP URI rewriting could be implemented based on regular expressions; accessing arbitrary data backends, e.g. LDAP or Berkeley DB files, is now extremely simple. -%package perlvdb -Summary: Perl virtual database engine +%package pi_http +Summary: Provisioning Interface module Group: System Environment/Daemons -# require perl-devel for >F7 and perl for <=F6 -BuildRequires: perl(ExtUtils::MakeMaker) Requires: %{name} = %{version}-%{release} -Requires: %{name}-perl -Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) - -%description perlvdb -The Perl Virtual Database (VDB) provides a virtualization framework for -OpenSIPS's database access. It does not handle a particular database engine -itself but lets the user relay database requests to arbitrary Perl functions. -%package peering -Summary: Radius peering -Group: System Environment/Daemons -Requires: %{name} = %{version}-%{release} - -%description peering -Peering module allows SIP providers (operators or organizations) -to verify from a broker if source or destination of a SIP request -is a trusted peer. +%description pi_http +This module provides an HTTP provisioning interface for OpenSIPS. It is using the +OpenSIPS's internal database API to provide a simple way of manipulating records +inside OpenSIPS's tables. %package postgresql Summary: PostgreSQL Storage Support for the OpenSIPS Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} +Requires: postgresql-libs %description postgresql The %{name}-postgresql package contains the PostgreSQL plugin for %{name}, @@ -281,6 +377,19 @@ of published presence information for the same presentity using more devices. It can also filter the information provided to watchers according to privacy rules. +%package presence_callinfo +Summary: SIMPLE Presence extension +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} +Requires: %{name}-presence + +%description presence_callinfo +The module enables the handling of "call-info" and "line-seize" events inside +the presence module. It is used with the general event handling module: +presence and it constructs and adds "Call-Info" headers to notification events. +To send "call-info" notification to watchers, a third-party application must +publish "call-info" events to the presence server. + %package presence_dialoginfo Summary: Extension to Presence server for Dialog-Info Group: System Environment/Daemons @@ -320,7 +429,6 @@ Summary: SIMPLE Presence extension Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} Requires: %{name}-presence -Requires: %{name}-xcap Requires: %{name}-xcap_client %description presence_xml @@ -336,6 +444,17 @@ Requires: %{name} = %{version}-%{release} This module offer the functionality of a presence user agent client, sending Subscribe and Publish messages. +%package pua_bla +Summary: BLA extension for PUA +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} +Requires: %{name}-pua +Requires: %{name}-presence + +%description pua_bla +The pua_bla module enables Bridged Line Appearances support according to the +specifications in draft-anil-sipping-bla-03.txt. + %package pua_dialoginfo Summary: Dialog-Info extension for PUA Group: System Environment/Daemons @@ -349,17 +468,6 @@ pua module. Thus, in combination with the presence_xml module this can be used to derive dialog-info from the dialog module and NOTIFY the subscribed watchers about dialog-info changes. -%package pua_bla -Summary: BLA extension for PUA -Group: System Environment/Daemons -Requires: %{name} = %{version}-%{release} -Requires: %{name}-pua -Requires: %{name}-presence - -%description pua_bla -The pua_bla module enables Bridged Line Appearances support according to the -specifications in draft-anil-sipping-bla-03.txt. - %package pua_mi Summary: Connector between usrloc and MI interface Group: System Environment/Daemons @@ -399,6 +507,26 @@ This module is a gateway for presence between SIP and XMPP. It translates one format into another and uses xmpp, pua and presence modules to manage the transmition of presence state information. +%package python +Summary: Python scripting support +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} + +%description python +Helps implement your own OpenSIPS extensions in Python + +%if %{undefined el5} +%package redis +Summary: Redis connector +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} +BuildRequires: hiredis-devel + +%description redis +This module is an implementation of a cache system designed to work +with a Redis server. +%endif + %package regex Summary: RegExp via PCRE library Group: System Environment/Daemons @@ -408,12 +536,22 @@ Requires: %{name} = %{version}-%{release} This module offers matching operations against regular expressions using the powerful PCRE library. +%package rest_client +Summary: Implementation of an HTTP client +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} + +%description rest_client +The rest_client module provides a means of interacting with an HTTP server +by doing RESTful queries, such as GET and POST. + %package rls Summary: Resource List Server Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} -Requires: %{name}-pua -Requires: %{name}-presence +Requires: %{name}-pua +Requires: %{name}-presence +Requires: %{name}-xcap %description rls The modules is a Resource List Server implementation following the @@ -481,17 +619,18 @@ The %{name}-unixodbc package contains the unixODBC plugin for %{name}, which allows a unixODBC to be used for persistent storage %package xcap -Summary: XCAP utilities +Summary: XCAP API provider Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} %description xcap -The modules contains XCAP related utilities for OpenSIPS +The module contains several parameters and functions common to all modules using XCAP capabilities. %package xcap_client Summary: XCAP client Group: System Environment/Daemons Requires: %{name} = %{version}-%{release} +Requires: %{name}-xcap %description xcap_client The modules is an XCAP client for OpenSIPS that can be used by other modules. @@ -499,6 +638,15 @@ It fetches XCAP elements, either documents or part of them, by sending HTTP GET requests. It also offers support for conditional queries. It uses libcurl library as a client-side HTTP transfer library. +%package xmlrpc +Summary: A xmlrpc server +Group: System Environment/Daemons +Requires: %{name} = %{version}-%{release} + +%description xmlrpc +This module implements a xmlrpc server that handles xmlrpc requests and generates +xmlrpc responses. When a xmlrpc message is received a default method is executed. + %package xmpp Summary: Gateway between OpenSIPS and a jabber server Group: System Environment/Daemons @@ -511,14 +659,12 @@ clients. %prep %setup -q -n %{name}-%{version}-tls -%patch1 -p1 -%patch2 -p1 %build -LOCALBASE=/usr CFLAGS="%{optflags}" %{__make} all %{?_smp_mflags} TLS=1 \ +LOCALBASE=/usr NICER=0 CFLAGS="%{optflags}" %{?_with_oracle:ORAHOME="$ORACLE_HOME"} %{__make} all %{?_smp_mflags} TLS=1 \ exclude_modules="%EXCLUDE_MODULES" \ cfg-target=%{_sysconfdir}/opensips/ \ - modules-prefix=%{buildroot}/%{_prefix} \ + modules-prefix=%{buildroot}%{_prefix} \ modules-dir=%{_lib}/%{name}/modules %install @@ -532,6 +678,9 @@ rm -rf $RPM_BUILD_ROOT DBTEXTON=yes # fixed dbtext documentation installation # clean some things +%if 0%{?el5} +rm -rf $RPM_BUILD_ROOT/%{_libdir}/opensips/perl/OpenSIPS/VDB* +%endif mkdir -p $RPM_BUILD_ROOT/%{perl_vendorlib} if [ -d "$RPM_BUILD_ROOT/%{_prefix}/perl" ]; then # for fedora>=11 @@ -554,54 +703,104 @@ for i in docdir/*; do rm -f $i.old done -mkdir -p $RPM_BUILD_ROOT%{_initrddir} -%{__install} -p -D -m 755 packaging/fedora/opensips.init \ - $RPM_BUILD_ROOT%{_initrddir}/opensips +%if 0%{?fedora} > 16 +# install systemd files +install -D -m 0644 -p packaging/fedora/%{name}.service $RPM_BUILD_ROOT%{_unitdir}/%{name}.service +install -D -m 0644 -p packaging/fedora/%{name}.tmpfiles.conf $RPM_BUILD_ROOT%{_sysconfdir}/tmpfiles.d/%{name}.conf +install -D -m 0755 -p packaging/fedora/%{name}.m4cfg $RPM_BUILD_ROOT%{_sbindir}/%{name}-m4cfg +mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/run/%{name} +%else +install -p -D -m 755 packaging/fedora/opensips.init $RPM_BUILD_ROOT%{_initrddir}/opensips +%endif echo -e "\nETCDIR=\"%{_sysconfdir}/opensips\"\n" \ >> $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/opensipsctlrc #install sysconfig file -install -D -p -m 644 %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/%{name} +install -D -p -m 644 packaging/fedora/%{name}.sysconfig $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/%{name} %clean rm -rf $RPM_BUILD_ROOT + +%pre +getent group %{name} >/dev/null || groupadd -r %{name} +getent passwd %{name} >/dev/null || \ +useradd -r -g %{name} -d %{_localstatedir}/run/%{name} -s /sbin/nologin \ +-c "OpenSIPS SIP Server" %{name} 2>/dev/null || : + %post -/sbin/chkconfig --add opensips +%if 0%{?fedora} > 16 +if [ $1 -eq 1 ] ; then + # Initial installation + /bin/systemctl daemon-reload >/dev/null 2>&1 || : +fi +%else +/sbin/chkconfig --add %{name} +%endif %preun +%if 0%{?fedora} > 16 +if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable %{name}.service > /dev/null 2>&1 || : + /bin/systemctl stop %{name}.service > /dev/null 2>&1 || : +fi +%else if [ $1 = 0 ]; then - /sbin/service opensips stop > /dev/null 2>&1 - /sbin/chkconfig --del opensips + /sbin/service %{name} stop > /dev/null 2>&1 + /sbin/chkconfig --del %{name} fi +%endif + +%if 0%{?fedora} > 16 +%triggerun -- %{name} < 1.7.2-1 +# Save the current service runlevel info +# User must manually run systemd-sysv-convert --apply opensips +# to migrate them to systemd targets +/usr/bin/systemd-sysv-convert --save %{name} >/dev/null 2>&1 ||: + +# Run these because the SysV package being removed won't do them +/sbin/chkconfig --del %{name} >/dev/null 2>&1 || : +/bin/systemctl try-restart %{name}.service >/dev/null 2>&1 || : + +%triggerun -- opensips < 1.7.2-4 +chown -R %{name}:%{name} %{_sysconfdir}/%{name} +%endif %files -%defattr(-,root,root,-) %{_sbindir}/opensips %{_sbindir}/opensipsctl %{_sbindir}/opensipsdbctl %{_sbindir}/opensipsunix +%{_sbindir}/osipsconfig %{_sbindir}/osipsconsole -%attr(750,root,root) %dir %{_sysconfdir}/opensips -%attr(750,root,root) %dir %{_sysconfdir}/opensips/tls -%attr(750,root,root) %dir %{_sysconfdir}/opensips/tls/rootCA -%attr(750,root,root) %dir %{_sysconfdir}/opensips/tls/rootCA/certs -%attr(750,root,root) %dir %{_sysconfdir}/opensips/tls/rootCA/private -%attr(750,root,root) %dir %{_sysconfdir}/opensips/tls/user +%attr(750,%{name},%{name}) %dir %{_sysconfdir}/opensips +%attr(750,%{name},%{name}) %dir %{_sysconfdir}/opensips/tls +%attr(750,%{name},%{name}) %dir %{_sysconfdir}/opensips/tls/rootCA +%attr(750,%{name},%{name}) %dir %{_sysconfdir}/opensips/tls/rootCA/certs +%attr(750,%{name},%{name}) %dir %{_sysconfdir}/opensips/tls/rootCA/private +%attr(750,%{name},%{name}) %dir %{_sysconfdir}/opensips/tls/user %dir %{_libdir}/opensips/ %dir %{_libdir}/opensips/modules/ %dir %{_libdir}/opensips/opensipsctl/ -%dir %{_libdir}/opensips/opensipsctl/dbtextdb +%dir %{_libdir}/opensips/opensipsctl/dbtextdb/ +%if 0%{?fedora} > 16 +%{_unitdir}/%{name}.service +%{_sysconfdir}/tmpfiles.d/%{name}.conf +%{_sbindir}/%{name}-m4cfg +%dir %attr(0755, %{name}, %{name}) %{_localstatedir}/run/%{name} +%else %attr(755,root,root) %{_initrddir}/opensips +%endif %config(noreplace) %{_sysconfdir}/opensips/dictionary.opensips %config(noreplace) %{_sysconfdir}/sysconfig/%{name} -%attr(640,root,root) %config(noreplace) %{_sysconfdir}/opensips/opensips.cfg -%attr(640,root,root) %config(noreplace) %{_sysconfdir}/opensips/opensipsctlrc -%attr(640,root,root) %config(noreplace) %{_sysconfdir}/opensips/osipsconsolerc -# these files are just an example so no need to restrict access to them +%attr(640,%{name},%{name}) %config(noreplace) %{_sysconfdir}/opensips/opensips.cfg +%attr(640,%{name},%{name}) %config(noreplace) %{_sysconfdir}/opensips/opensipsctlrc +%attr(640,%{name},%{name}) %config(noreplace) %{_sysconfdir}/opensips/osipsconsolerc +# these files are just an examples so no need to restrict access to them %config(noreplace) %{_sysconfdir}/opensips/tls/ca.conf %config(noreplace) %{_sysconfdir}/opensips/tls/request.conf %config(noreplace) %{_sysconfdir}/opensips/tls/rootCA/cacert.pem @@ -615,15 +814,24 @@ fi %config(noreplace) %{_sysconfdir}/opensips/tls/user/user-cert_req.pem %config(noreplace) %{_sysconfdir}/opensips/tls/user/user-privkey.pem -%{_libdir}/opensips/opensipsctl/opensipsctl.* +%{_libdir}/opensips/opensipsctl/opensipsctl.base +%{_libdir}/opensips/opensipsctl/opensipsctl.ctlbase +%{_libdir}/opensips/opensipsctl/opensipsctl.dbtext +%{_libdir}/opensips/opensipsctl/opensipsctl.fifo +%{_libdir}/opensips/opensipsctl/opensipsctl.sqlbase +%{_libdir}/opensips/opensipsctl/opensipsctl.unixsock + %{_libdir}/opensips/opensipsctl/opensipsdbctl.base %{_libdir}/opensips/opensipsctl/opensipsdbctl.dbtext %{_libdir}/opensips/opensipsctl/dbtextdb/dbtextdb.py* -%dir %{_datadir}/opensips -%dir %{_datadir}/opensips/dbtext -%dir %{_datadir}/opensips/dbtext/opensips +%dir %{_datadir}/opensips/ +%dir %{_datadir}/opensips/dbtext/ +%dir %{_datadir}/opensips/dbtext/opensips/ +%dir %{_datadir}/opensips/menuconfig_templates/ + %{_datadir}/opensips/dbtext/opensips/* +%{_datadir}/opensips/menuconfig_templates/*.m4 %{_mandir}/man5/opensips.cfg.5* %{_mandir}/man8/opensips.8* @@ -634,7 +842,6 @@ fi %doc docdir/NEWS %doc docdir/README %doc docdir/README-MODULES -%doc docdir/README.tls %doc COPYING %{_libdir}/opensips/modules/acc.so @@ -643,12 +850,16 @@ fi %{_libdir}/opensips/modules/auth_db.so %{_libdir}/opensips/modules/avpops.so %{_libdir}/opensips/modules/benchmark.so +%{_libdir}/opensips/modules/cachedb_local.so +%{_libdir}/opensips/modules/cachedb_sql.so %{_libdir}/opensips/modules/call_control.so %{_libdir}/opensips/modules/closeddial.so %{_libdir}/opensips/modules/cfgutils.so +%{_libdir}/opensips/modules/db_cachedb.so %{_libdir}/opensips/modules/db_flatstore.so %{_libdir}/opensips/modules/db_virtual.so %{_libdir}/opensips/modules/db_text.so +%{_libdir}/opensips/modules/dns_cache.so %{_libdir}/opensips/modules/dialog.so %{_libdir}/opensips/modules/dialplan.so %{_libdir}/opensips/modules/dispatcher.so @@ -663,15 +874,18 @@ fi %{_libdir}/opensips/modules/identity.so %{_libdir}/opensips/modules/imc.so %{_libdir}/opensips/modules/load_balancer.so -%{_libdir}/opensips/modules/localcache.so %{_libdir}/opensips/modules/mangler.so +%{_libdir}/opensips/modules/mathops.so %{_libdir}/opensips/modules/maxfwd.so %{_libdir}/opensips/modules/mediaproxy.so %{_libdir}/opensips/modules/mi_fifo.so %{_libdir}/opensips/modules/mi_datagram.so +%{_libdir}/opensips/modules/mi_http.so +%{_libdir}/opensips/modules/mi_json.so %{_libdir}/opensips/modules/msilo.so %{_libdir}/opensips/modules/nathelper.so %{_libdir}/opensips/modules/nat_traversal.so +%{_libdir}/opensips/modules/rtpproxy.so %{_libdir}/opensips/modules/options.so %{_libdir}/opensips/modules/path.so %{_libdir}/opensips/modules/pdt.so @@ -681,7 +895,10 @@ fi %{_libdir}/opensips/modules/ratelimit.so %{_libdir}/opensips/modules/registrar.so %{_libdir}/opensips/modules/rr.so +%{_libdir}/opensips/modules/script_helper.so %{_libdir}/opensips/modules/signaling.so +%{_libdir}/opensips/modules/sipcapture.so +%{_libdir}/opensips/modules/sipmsgops.so %{_libdir}/opensips/modules/siptrace.so %{_libdir}/opensips/modules/sl.so %{_libdir}/opensips/modules/speeddial.so @@ -695,7 +912,8 @@ fi %{_libdir}/opensips/modules/userblacklist.so %{_libdir}/opensips/modules/uri.so %{_libdir}/opensips/modules/usrloc.so -%{_libdir}/opensips/modules/xlog.so +%{_libdir}/opensips/modules/uac_auth.so +%{_libdir}/opensips/modules/uac_registrant.so %doc docdir/README.acc %doc docdir/README.alias_db @@ -703,89 +921,110 @@ fi %doc docdir/README.auth_db %doc docdir/README.avpops %doc docdir/README.benchmark +%doc docdir/README.cachedb_local +%doc docdir/README.cachedb_sql +%doc docdir/README.call_control %doc docdir/README.cfgutils +%doc docdir/README.closeddial +%doc docdir/README.db_cachedb +%doc docdir/README.db_flatstore %doc docdir/README.db_text +%doc docdir/README.db_virtual %doc docdir/README.dialog %doc docdir/README.dialplan %doc docdir/README.dispatcher %doc docdir/README.diversion +%doc docdir/README.dns_cache %doc docdir/README.domain %doc docdir/README.domainpolicy %doc docdir/README.drouting %doc docdir/README.enum %doc docdir/README.exec -#%doc docdir/README.flatstore %doc docdir/README.gflags %doc docdir/README.group +%doc docdir/README.identity %doc docdir/README.imc +%doc docdir/README.load_balancer %doc docdir/README.mangler +%doc docdir/README.mathops %doc docdir/README.maxfwd %doc docdir/README.mediaproxy -%doc docdir/README.mi_fifo %doc docdir/README.mi_datagram +%doc docdir/README.mi_fifo +%doc docdir/README.mi_http +%doc docdir/README.mi_json %doc docdir/README.msilo +%doc docdir/README.nat_traversal %doc docdir/README.nathelper %doc docdir/README.options %doc docdir/README.path %doc docdir/README.pdt %doc docdir/README.permissions %doc docdir/README.pike +%doc docdir/README.qos +%doc docdir/README.ratelimit %doc docdir/README.registrar %doc docdir/README.rr +%doc docdir/README.rtpproxy +%doc docdir/README.script_helper +%doc docdir/README.signaling +%doc docdir/README.sipcapture +%doc docdir/README.sipmsgops %doc docdir/README.siptrace %doc docdir/README.sl %doc docdir/README.speeddial %doc docdir/README.sst %doc docdir/README.statistics -#%doc docdir/README.textops +%doc docdir/README.stun +%doc docdir/README.textops +%doc docdir/README.tls %doc docdir/README.tm %doc docdir/README.uac +%doc docdir/README.uac_auth %doc docdir/README.uac_redirect +%doc docdir/README.uac_registrant %doc docdir/README.uri +%doc docdir/README.userblacklist %doc docdir/README.usrloc -%doc docdir/README.xlog %files aaa_radius -%defattr(-,root,root,-) %{_libdir}/opensips/modules/aaa_radius.so %doc docdir/README.aaa_radius %files acc -%defattr(-,root,root,-) %{_libdir}/opensips/modules/acc.so %doc docdir/README.acc %files auth_aaa -%defattr(-,root,root,-) %{_libdir}/opensips/modules/auth_aaa.so %doc docdir/README.auth_aaa %files auth_diameter -%defattr(-,root,root,-) %{_libdir}/opensips/modules/auth_diameter.so %doc docdir/README.auth_diameter %files b2bua -%defattr(-,root,root,-) %{_libdir}/opensips/modules/b2b_entities.so %{_libdir}/opensips/modules/b2b_logic.so +%{_libdir}/opensips/modules/b2b_sca.so +%{_libdir}/opensips/modules/call_center.so %doc docdir/README.b2b_entities %doc docdir/README.b2b_logic +%doc docdir/README.b2b_sca +%doc docdir/README.call_center %files carrierroute -%defattr(-,root,root,-) %{_libdir}/opensips/modules/carrierroute.so %doc docdir/README.carrierroute %files cpl-c -%defattr(-,root,root,-) %{_libdir}/opensips/modules/cpl-c.so %doc docdir/README.cpl-c %files db_berkeley -%defattr(-,root,root,-) %{_sbindir}/bdb_recover %{_libdir}/opensips/modules/db_berkeley.so +%{_libdir}/opensips/opensipsctl/opensipsctl.db_berkeley %{_libdir}/opensips/opensipsctl/opensipsdbctl.db_berkeley %dir %{_datadir}/opensips/db_berkeley %dir %{_datadir}/opensips/db_berkeley/opensips @@ -793,55 +1032,99 @@ fi %doc docdir/README.db_berkeley %files db_http -%defattr(-,root,root,-) %{_libdir}/opensips/modules/db_http.so %doc docdir/README.db_http +%if %{undefined el5} +%files db_perlvdb +%dir %{perl_vendorlib}/OpenSIPS/VDB +%dir %{perl_vendorlib}/OpenSIPS/VDB/Adapter +%{_libdir}/opensips/modules/db_perlvdb.so +%{perl_vendorlib}/OpenSIPS/VDB.pm +%{perl_vendorlib}/OpenSIPS/VDB/Adapter/AccountingSIPtrace.pm +%{perl_vendorlib}/OpenSIPS/VDB/Adapter/Alias.pm +%{perl_vendorlib}/OpenSIPS/VDB/Adapter/Auth.pm +%{perl_vendorlib}/OpenSIPS/VDB/Adapter/Describe.pm +%{perl_vendorlib}/OpenSIPS/VDB/Adapter/Speeddial.pm +%{perl_vendorlib}/OpenSIPS/VDB/Adapter/TableVersions.pm +%{perl_vendorlib}/OpenSIPS/VDB/Column.pm +%{perl_vendorlib}/OpenSIPS/VDB/Pair.pm +%{perl_vendorlib}/OpenSIPS/VDB/ReqCond.pm +%{perl_vendorlib}/OpenSIPS/VDB/Result.pm +%{perl_vendorlib}/OpenSIPS/VDB/VTab.pm +%{perl_vendorlib}/OpenSIPS/VDB/Value.pm +%doc docdir/README.db_perlvdb +%endif + +%files event_datagram +%{_libdir}/opensips/modules/event_datagram.so +%doc docdir/README.event_datagram + +%files event_rabbitmq +%{_libdir}/opensips/modules/event_rabbitmq.so +%doc docdir/README.event_rabbitmq + +%files event_route +%{_libdir}/opensips/modules/event_route.so +%doc docdir/README.event_route + +%files event_xmlrpc +%{_libdir}/opensips/modules/event_xmlrpc.so +%doc docdir/README.event_xmlrpc + %files h350 -%defattr(-,root,root,-) %{_libdir}/opensips/modules/h350.so %doc docdir/README.h350 +%files httpd +%{_libdir}/opensips/modules/httpd.so +%doc docdir/README.httpd + %files jabber -%defattr(-,root,root,-) %{_libdir}/opensips/modules/jabber.so %doc docdir/README.jabber +%files json +%{_libdir}/opensips/modules/json.so +%doc docdir/README.json + %files ldap -%defattr(-,root,root,-) %{_libdir}/opensips/modules/ldap.so %doc docdir/README.ldap %files memcached -%defattr(-,root,root,-) -%{_libdir}/opensips/modules/memcached.so -%doc docdir/README.memcached +%{_libdir}/opensips/modules/cachedb_memcached.so +%doc docdir/README.cachedb_memcached %files mmgeoip -%defattr(-,root,root,-) %{_libdir}/opensips/modules/mmgeoip.so %doc docdir/README.mmgeoip %files mysql -%defattr(-,root,root,-) %{_libdir}/opensips/modules/db_mysql.so +%{_libdir}/opensips/opensipsctl/opensipsctl.mysql %{_libdir}/opensips/opensipsctl/opensipsdbctl.mysql %dir %{_datadir}/opensips/mysql %{_datadir}/opensips/mysql/*.sql %doc docdir/README.db_mysql -%if %{defined db_oracle} +%if 0%{?_with_oracle} %files oracle -%defattr(-,root,root,-) -%{_libdir}/opensips/modules/db_oracle.db +%{_sbindir}/opensips_orasel +%{_libdir}/opensips/modules/db_oracle.so +%{_libdir}/opensips/opensipsctl/opensipsctl.oracle %{_libdir}/opensips/opensipsctl/opensipsdbctl.oracle +%{_libdir}/opensips/opensipsctl/opensipsdbfunc.oracle %dir %{_datadir}/opensips/oracle %{_datadir}/opensips/oracle/* %doc docdir/README.db_oracle %endif +%files peering +%{_libdir}/opensips/modules/peering.so +%doc docdir/README.peering + %files perl -%defattr(-,root,root,-) %dir %{perl_vendorlib}/OpenSIPS %dir %{perl_vendorlib}/OpenSIPS/LDAPUtils %dir %{perl_vendorlib}/OpenSIPS/Utils @@ -855,116 +1138,98 @@ fi %{perl_vendorlib}/OpenSIPS/Utils/Debug.pm %doc docdir/README.perl -%files perlvdb -%defattr(-,root,root,-) -%dir %{perl_vendorlib}/OpenSIPS/VDB -%dir %{perl_vendorlib}/OpenSIPS/VDB/Adapter -%{_libdir}/opensips/modules/db_perlvdb.so -%{perl_vendorlib}/OpenSIPS/VDB.pm -%{perl_vendorlib}/OpenSIPS/VDB/Adapter/AccountingSIPtrace.pm -%{perl_vendorlib}/OpenSIPS/VDB/Adapter/Alias.pm -%{perl_vendorlib}/OpenSIPS/VDB/Adapter/Auth.pm -%{perl_vendorlib}/OpenSIPS/VDB/Adapter/Describe.pm -%{perl_vendorlib}/OpenSIPS/VDB/Adapter/Speeddial.pm -%{perl_vendorlib}/OpenSIPS/VDB/Adapter/TableVersions.pm -%{perl_vendorlib}/OpenSIPS/VDB/Column.pm -%{perl_vendorlib}/OpenSIPS/VDB/Pair.pm -%{perl_vendorlib}/OpenSIPS/VDB/ReqCond.pm -%{perl_vendorlib}/OpenSIPS/VDB/Result.pm -%{perl_vendorlib}/OpenSIPS/VDB/VTab.pm -%{perl_vendorlib}/OpenSIPS/VDB/Value.pm -%doc docdir/README.perlvdb - -%files peering -%defattr(-,root,root,-) -%{_libdir}/opensips/modules/peering.so -%doc docdir/README.peering +%files pi_http +%{_libdir}/opensips/modules/pi_http.so +%{_datadir}/opensips/pi_http/* +%doc docdir/README.pi_http %files postgresql -%defattr(-,root,root,-) %{_libdir}/opensips/modules/db_postgres.so +%{_libdir}/opensips/opensipsctl/opensipsctl.pgsql %{_libdir}/opensips/opensipsctl/opensipsdbctl.pgsql %dir %{_datadir}/opensips/postgres %{_datadir}/opensips/postgres/*.sql %doc docdir/README.db_postgres %files presence -%defattr(-,root,root,-) %{_libdir}/opensips/modules/presence.so %doc docdir/README.presence +%files presence_callinfo +%{_libdir}/opensips/modules/presence_callinfo.so +%doc docdir/README.presence_callinfo + %files presence_dialoginfo -%defattr(-,root,root,-) %{_libdir}/opensips/modules/presence_dialoginfo.so %doc docdir/README.presence_dialoginfo %files presence_mwi -%defattr(-,root,root,-) %{_libdir}/opensips/modules/presence_mwi.so %doc docdir/README.presence_mwi %files presence_xcapdiff -%defattr(-,root,root,-) %{_libdir}/opensips/modules/presence_xcapdiff.so +%doc docdir/README.presence_xcapdiff %files presence_xml -%defattr(-,root,root,-) %{_libdir}/opensips/modules/presence_xml.so %doc docdir/README.presence_xml %files pua -%defattr(-,root,root,-) %{_libdir}/opensips/modules/pua.so %doc docdir/README.pua -%files pua_dialoginfo -%defattr(-,root,root,-) -%{_libdir}/opensips/modules/pua_dialoginfo.so -%doc docdir/README.pua_dialoginfo - %files pua_bla -%defattr(-,root,root,-) %{_libdir}/opensips/modules/pua_bla.so %doc docdir/README.pua_bla +%files pua_dialoginfo +%{_libdir}/opensips/modules/pua_dialoginfo.so +%doc docdir/README.pua_dialoginfo + %files pua_mi -%defattr(-,root,root,-) %{_libdir}/opensips/modules/pua_mi.so %doc docdir/README.pua_mi %files pua_usrloc -%defattr(-,root,root,-) %{_libdir}/opensips/modules/pua_usrloc.so %doc docdir/README.pua_usrloc %files pua_xmpp -%defattr(-,root,root,-) %{_libdir}/opensips/modules/pua_xmpp.so %doc docdir/README.pua_xmpp +%files python +%{_libdir}/opensips/modules/python.so + +%if %{undefined el5} +%files redis +%{_libdir}/opensips/modules/cachedb_redis.so +%doc docdir/README.cachedb_redis +%endif + %files regex -%defattr(-,root,root,-) %{_libdir}/opensips/modules/regex.so %doc docdir/README.regex +%files rest_client +%{_libdir}/opensips/modules/rest_client.so +%doc docdir/README.rest_client + %files rls -%defattr(-,root,root,-) %{_libdir}/opensips/modules/rls.so %doc docdir/README.rls %files seas -%defattr(-,root,root,-) %{_libdir}/opensips/modules/seas.so %doc docdir/README.seas %files sms -%defattr(-,root,root,-) %{_libdir}/opensips/modules/sms.so %doc docdir/README.sms %if %{undefined disable_snmpstats} %files snmpstats -%defattr(-,root,root,-) %{_libdir}/opensips/modules/snmpstats.so %doc docdir/README.snmpstats %dir %{_datadir}/snmp @@ -977,35 +1242,192 @@ fi %endif %files tlsops -%defattr(-,root,root,-) %{_libdir}/opensips/modules/tlsops.so %doc docdir/README.tlsops %files unixodbc -%defattr(-,root,root,-) %{_libdir}/opensips/modules/db_unixodbc.so %doc docdir/README.db_unixodbc %files xcap -%defattr(-,root,root,-) %{_libdir}/opensips/modules/xcap.so %doc docdir/README.xcap %files xcap_client -%defattr(-,root,root,-) %{_libdir}/opensips/modules/xcap_client.so %doc docdir/README.xcap_client +%files xmlrpc +%{_libdir}/opensips/modules/mi_xmlrpc.so +%{_libdir}/opensips/modules/mi_xmlrpc_ng.so +%doc docdir/README.mi_xmlrpc +%doc docdir/README.mi_xmlrpc_ng + %files xmpp -%defattr(-,root,root,-) %{_libdir}/opensips/modules/xmpp.so %doc docdir/README.xmpp %changelog -* Wed Nov 04 2009 John Khvatov - 1.6.0-4: +* Fri Mar 21 2014 Nick Altmann - 1.11.0-1 +- Update to 1.11.0 + +* Tue Jul 30 2013 Nick Altmann - 1.10.0-1 +- Update to 1.10.0 + +* Wed May 22 2013 Nick Altmann - 1.9.1-1 +- Rebuild specification, add new modules and dependencies + +* Tue Jan 22 2013 Peter Lemenkov - 1.8.2-3 +- Revert systemd macros + +* Thu Jan 10 2013 Peter Lemenkov - 1.8.2-2 +- Allow rtpproxy module to accept avps +- Few bugfixes + +* Tue Nov 06 2012 Peter Lemenkov - 1.8.2-1 +- Ver. 1.8.2 (Bugfix release) + +* Sat Sep 22 2012 Remi Collet - 1.8.1-3 +- rebuild against libmemcached.so.11 without SASL + +* Fri Aug 17 2012 Peter Lemenkov - 1.8.1-2 +- Enabled json module +- Enabled xmlrpc module +- Enabled cachedb_memcached module on EL5, EL6 +- Enabled cachedb_redis module on EL6 + +* Wed Aug 15 2012 Peter Lemenkov - 1.8.1-1 +- Ver. 1.8.1 +- Dropped all upstreamed patches + +* Fri Jul 20 2012 Fedora Release Engineering - 1.8.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jul 09 2012 Petr Pisar - 1.8.0-2 +- Perl 5.16 rebuild + +* Tue Jul 03 2012 Peter Lemenkov - 1.8.0-1 +- update to 1.8.0 + +* Fri Jun 08 2012 Petr Pisar - 1.7.2-8 +- Perl 5.16 rebuild + +* Sat May 12 2012 Peter Lemenkov - 1.7.2-7 +- Change %%define to %%global + +* Sat May 12 2012 Peter Lemenkov - 1.7.2-6 +- Added missing docs + +* Fri May 11 2012 Peter Lemenkov - 1.7.2-5 +- Fixed conditional building with Oracle DB + +* Sat Apr 28 2012 Peter Lemenkov - 1.7.2-4 +- Fixes for systemd unit + +* Sun Apr 22 2012 Remi Collet - 1.7.2-3 +- rebuild against libmemcached.so.10 + +* Thu Apr 19 2012 Peter Lemenkov - 1.7.2-2 +- Fix building on EPEL + +* Thu Apr 19 2012 Peter Lemenkov - 1.7.2-1 +- update to 1.7.2 (bugfix release). +- enable systemd support where possible + +* Fri Apr 13 2012 Jindrich Novy - 1.7.1-6 +- rebuild against new librpm and libdb + +* Sat Mar 03 2012 Remi Collet - 1.7.1-5 +- rebuild against libmemcached.so.9 + +* Fri Feb 10 2012 Petr Pisar - 1.7.1-4 +- Rebuild against PCRE 8.30 + +* Fri Jan 13 2012 Fedora Release Engineering - 1.7.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Thu Dec 01 2011 John Khvatov - 1.7.1-2 +- upstream tarball rebuild + +* Thu Nov 24 2011 John Khvatov - 1.7.1-1 +- update to 1.7.1 (bugfix release). + +* Mon Nov 07 2011 John Khvatov - 1.7.0-1 +- update to 1.7.0 +- dropped upstreamed patches +- added new modules: event_datagram and python +- removed lcr module + +* Sat Sep 17 2011 Remi Collet - 1.6.4-13 +- rebuild against libmemcached.so.8 + +* Mon Aug 22 2011 John Khvatov - 1.6.4-12 +- rebuild against new libnetsnmp + +* Thu Jul 21 2011 Petr Sabata - 1.6.4-11 +- Perl mass rebuild + +* Wed Jul 20 2011 Petr Sabata - 1.6.4-10 +- Perl mass rebuild + +* Mon Jul 11 2011 Peter Lemenkov - 1.6.4-9 +- Updated init-script + +* Mon Jul 11 2011 Peter Lemenkov - 1.6.4-8 +- Upstream re-released traball with several new patches (API compatible) + +* Fri Jun 17 2011 Marcela Mašláňová - 1.6.4-7 +- Perl mass rebuild + +* Wed Mar 23 2011 Dan Horák - 1.6.4-6 +- rebuilt for mysql 5.5.10 (soname bump in libmysqlclient) + +* Tue Feb 08 2011 Fedora Release Engineering - 1.6.4-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Wed Dec 22 2010 John Khvatov - 1.6.4-1 +- dropped upstreamed patch (opensips-build.patch) +- update to 1.6.4 +- added new module: presence_callinfo + +* Sat Oct 30 2010 John Khvatov - 1.6.3-4 +- rebuild against new libnetsnmp + +* Wed Oct 06 2010 Remi Collet - 1.6.3-3 +- rebuilt against new libmemcached + +* Wed Sep 08 2010 Dan Horák - 1.6.3-2 +- fix a build issue + +* Thu Aug 12 2010 John Khvatov - 1.6.3-1 +- update to 1.6.3 + +* Wed Aug 11 2010 David Malcolm - 1.6.2-5 +- recompiling .py files against Python 2.7 (rhbz#623343) + +* Tue Jun 01 2010 Marcela Maslanova - 1.6.2-4 +- Mass rebuild with perl-5.12.0 + +* Wed May 05 2010 Remi Collet - 1.6.2-3 +- rebuilt against new libmemcached + +* Thu Apr 15 2010 John Khvatov - 1.6.2-2 +- Disabled build of the memcached subpackage for EPEL + +* Thu Apr 15 2010 John Khvatov - 1.6.2-1 +- Updated to 1.6.2 + +* Sun Feb 07 2010 Remi Collet - 1.6.1-2 +- rebuilt against new libmemcached + +* Tue Dec 22 2009 John Khvatov - 1.6.1-1 +- Updated to 1.6.1 +- Dropped upstreamed patches + +* Wed Nov 04 2009 John Khvatov - 1.6.0-4 - Fixed typo: pia_mi to pua_mi in presence_xcapdiff dependencies -* Thu Nov 03 2009 John Khvatov - 1.6.0-3 +* Tue Nov 03 2009 John Khvatov - 1.6.0-3 - Added patch for compatibility with new openssl * Thu Oct 29 2009 John Khvatov - 1.6.0-2 @@ -1141,7 +1563,7 @@ fi * Thu Sep 6 2007 Peter Lemenkov 1.2.2-8 - Added another one missing BR - which (needs by snmpstats module) - Cosmetic: dropped commented out 'Requires' - + * Thu Sep 06 2007 Jan ONDREJ (SAL) 1.2.2-7 - added attr macro for init script - added -p to install arguments to preserve timestamp @@ -1173,3 +1595,4 @@ fi * Tue Jul 24 2007 Peter Lemenkov 1.2.1-1 - Initial spec. + diff --git a/packaging/freebsd/Makefile b/packaging/freebsd/Makefile index bb58c61ee89..d7a45cd3f51 100644 --- a/packaging/freebsd/Makefile +++ b/packaging/freebsd/Makefile @@ -6,7 +6,7 @@ # PORTNAME= opensips -PORTVERSION= 1.9.0 +PORTVERSION= 1.11.0 CATEGORIES= net MASTER_SITES= http://opensips.org/pub/opensips/${PORTVERSION}/src/ DISTNAME= ${PORTNAME}-${PORTVERSION}-tls_src diff --git a/packaging/gentoo/opensips-1.9.0.ebuild b/packaging/gentoo/opensips-1.11.0.ebuild similarity index 100% rename from packaging/gentoo/opensips-1.9.0.ebuild rename to packaging/gentoo/opensips-1.11.0.ebuild diff --git a/packaging/netbsd/Makefile b/packaging/netbsd/Makefile index 5fcb512ed56..a3dbaaf9cc7 100644 --- a/packaging/netbsd/Makefile +++ b/packaging/netbsd/Makefile @@ -8,9 +8,9 @@ COMMENT= "OpenSIPS" PORTNAME= opensips -PORTVERSION= 1.9.0-notls +PORTVERSION= 1.11.0-notls CATEGORIES= net -MASTER_SITES= http://opensips.org/pub/opensips/1.9.0/src/ +MASTER_SITES= http://opensips.org/pub/opensips/1.11.0/src/ MAINTAINER= bogdan@opensips.org diff --git a/packaging/openbsd/Makefile b/packaging/openbsd/Makefile index 6a6c6744eab..58e1eb47058 100644 --- a/packaging/openbsd/Makefile +++ b/packaging/openbsd/Makefile @@ -8,7 +8,7 @@ COMMENT= "OpenSIPS" PORTNAME= opensips -PORTVERSION= 1.9.0-notls +PORTVERSION= 1.11.0-notls CATEGORIES= net MASTER_SITES= http://opensips.org/pub/opensips/1.6.0/src/ diff --git a/packaging/rpm/opensips.spec.CentOS b/packaging/rpm/opensips.spec.CentOS index 50e04d59c9f..bbcdc7bb027 100644 --- a/packaging/rpm/opensips.spec.CentOS +++ b/packaging/rpm/opensips.spec.CentOS @@ -1,19 +1,8 @@ %define name opensips -%define ver 1.9.0 +%define ver 1.11.0 %define rel 0 %define _sharedir %{_prefix}/share -%define EXCLUDED_MODULES aaa_radius b2b_entities b2b_logic db_http json memcached jabber cpl-c xmpp rls mi_xmlrpc xcap_client db_mysql db_postgres db_unixodbc db_oracle db_berkeley osp perl snmpstats db_perlvdb peering carrierroute mmgeoip presence presence_xml presence_mwi presence_dialoginfo pua pua_bla pua_mi pua_usrloc pua_xmpp pua_dialoginfo xcap xcap_client ldap h350 identity regex -%define MYSQL_MODULES modules/db_mysql -%define UNIXODBC_MODULES modules/db_unixodbc -%define POSTGRES_MODULES modules/db_postgres -%define XMPP_MODULES modules/jabber modules/xmpp -%define CPL_MODULES modules/cpl-c -%define SNMPSTATS_MODULES modules/snmpstats -%define PRESENCE_MODULES modules/presence modules/presence_dialoginfo modules/presence_xml modules/presence_mwi modules/presence_xcapdiff modules/pua modules/pua_bla modules/pua_dialoginfo modules/pua_mi modules/pua_usrloc modules/pua_xmpp modules/rls modules/xcap modules/xcap_client -%define RADIUS_MODULES modules/aaa_radius modules/peering -%define B2BUA_MODULES modules/b2b_entities modules/b2b_logic - Summary: OpenSIPS, very fast and flexible SIP Server Name: %name Version: %ver @@ -21,14 +10,14 @@ Release: %rel Packager: Bogdan-Andrei Iancu License: GPL Group: System Environment/Daemons -Source0: http://opensips.org/pub/opensips/%{ver}/src/%{name}-%{ver}-tls_src.tar.gz +Source0: http://opensips.org/pub/opensips/%{ver}/src/%{name}-%{ver}_src.tar.gz Source1: opensips.init Source2: opensips.default URL: http://opensips.org/ Vendor: opensips.org BuildRoot: %{_tmppath}/%{name}-%{ver}-buildroot Conflicts: opensips-mysql < %ver, opensips-xmpp < %ver, opensips-radius < %ver, opensips-cpl < %ver, opensips-unixodbc < %ver, opensips-presence < %ver, opensips-postgres < %ver, opensips-snmpstats < %ver -BuildPrereq: make flex bison pcre-devel +BuildRequires: make flex bison pcre-devel lua-devel libmemcache-devel OSPToolkit-devel mongo-c-driver-devel %description @@ -48,7 +37,7 @@ interface. Summary: MySQL connectivity for the OpenSIPS. Group: System Environment/Daemons Requires: opensips = %ver -BuildPrereq: mysql-devel, zlib-devel +BuildRequires: mysql-devel, zlib-devel %description mysql The opensips-mysql package contains MySQL database connectivity that you @@ -59,7 +48,7 @@ entries. Summary: MPOSTGRES connectivity for the OpenSIPS. Group: System Environment/Daemons Requires: opensips = %ver -BuildPrereq: postgresql-devel +BuildRequires: postgresql-devel %description postgres The opensips-postgres package contains Postgres database connectivity that you @@ -70,7 +59,7 @@ entries. Summary: UNIXODBC connectivity for OpenSIPS. Group: System Environment/Daemons Requires: opensips = %ver -BuildPrereq: unixODBC-devel +BuildRequires: unixODBC-devel %description unixodbc The opensips-unixodbc package contains UNIXODBC database connectivity support @@ -80,7 +69,7 @@ that is required by other modules with database dependencies. Summary: sip 2 xmpp/jabber message translation support for the OpenSIPS. Group: System Environment/Daemons Requires: opensips = %ver -BuildPrereq: expat-devel +BuildRequires: expat-devel %description xmpp The opensips-xmpp package contains a sip to xmpp/jabber message translator. @@ -89,7 +78,7 @@ The opensips-xmpp package contains a sip to xmpp/jabber message translator. Summary: CPL interpreter engine for the OpenSIPS. Group: System Environment/Daemons Requires: opensips = %ver -BuildPrereq: libxml2-devel +BuildRequires: libxml2-devel %description cpl The opensips-cpl package contains a SIP CPL interpreter engine. @@ -98,7 +87,7 @@ The opensips-cpl package contains a SIP CPL interpreter engine. Summary: sip presence user agent support for the OpenSIPS. Group: System Environment/Daemons Requires: opensips = %ver -BuildPrereq: libxml2-devel, curl-devel +BuildRequires: libxml2-devel, curl-devel %description presence The opensips-pua package contains a sip Presence Agent. @@ -107,7 +96,7 @@ The opensips-pua package contains a sip Presence Agent. Summary: opensips radius support for AAA API. Group: System Environment/Daemons Requires: opensips = %ver -BuildPrereq: radiusclient-ng-devel +BuildRequires: radiusclient-ng-devel %description radius The opensips-radius package contains modules for radius authentication, group @@ -117,7 +106,7 @@ The opensips-radius package contains modules for radius authentication, group Summary: opensips b2bua implementation. Group: System Environment/Daemons Requires: opensips = %ver -BuildPrereq: libxml2-devel +BuildRequires: libxml2-devel %description b2bua The opensips-b2bua package contains modules implement b2bua scenarios. @@ -126,7 +115,7 @@ The opensips-b2bua package contains modules implement b2bua scenarios. Summary: SNMP AgentX subagent module for OpenSIPS Group: System Environment/Daemons Requires: opensips = %ver, net-snmp-utils -BuildPrereq: lm_sensors-devel net-snmp-devel +BuildRequires: lm_sensors-devel net-snmp-devel %description snmpstats OpenSIPS is a very fast and flexible SIP (RFC3261) @@ -135,117 +124,271 @@ per second even on low-budget hardware. This package provides the snmpstats module for OpenSIPS. This module acts as an AgentX subagent which connects to a master agent. +%package ldap +Summary: opensips ldap implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: openldap-devel + +%description ldap +The LDAP module implements an LDAP search interface for OpenSIPS. +It exports script functions to perform an LDAP search operation and to store the search results as OpenSIPS AVPs. +This allows for using LDAP directory data in the OpenSIPS SIP message routing script. + + +%package identity +Summary: opensips identity implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: openssl-devel + +%description identity +This module adds support for SIP Identity (see RFC 4474). + + +%package regex +Summary: opensips identity implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: pcre-devel + +%description regex +This module offers matching operations against regular expressions using the powerful PCRE library. + + +%package mmgeoip +Summary: opensips mmgeoip implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: GeoIP-devel + +%description mmgeoip +This module is a lightweight wrapper for the MaxMind GeoIP API. +It adds IP address-to-location lookup capability to OpenSIPS scripts. + + +%package json +Summary: opensips json implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: json-c-devel + +%description json +This module introduces a new type of variable that provides both serialization and de-serialization from JSON format. + + +%package carrierroute +Summary: opensips carrierroute implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: libconfuse-devel + +%description carrierroute +A module which provides routing, balancing and blacklisting capabilities. + + +%package cachedb_memcached +Summary: opensips cachedb_memcached implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: libconfuse-devel libmemcached-devel + +%description cachedb_memcached +This module is an implementation of a cache system designed to work with a memcached server. +It uses libmemcached client library to connect to several memcached servers that store data. +It registers the three functions for storing, fetching and removing a value to the core memcache management interface. + + +%package cachedb_couchbase +Summary: opensips cachedb_couchbase implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: libcouchbase-devel + +%description cachedb_couchbase +This module is an implementation of a cache system designed to work with a Couchbase server. +It uses the libcouchbase client library to connect to the server instance, +It uses the Key-Value interface exported from the core. + + +%package event_rabbitmq +Summary: opensips event_rabbitmq implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: librabbitmq-devel + +%description event_rabbitmq +This module provides the implementation of a RabbitMQ client for the Event Interface. +It is used to send AMQP messages to a RabbitMQ server each time the Event Interface triggers an event subscribed for. + + +%package cachedb_redis +Summary: opensips cachedb_redis implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: hiredis-devel + +%description cachedb_redis +This module is an implementation of a cache system designed to work with a Redis server. +It uses hiredis client library to connect to either a single Redis server instance, +or to a Redis Server inside a Redis Cluster. +It uses the Key-Value interface exported from the core. + + +%package db_berkeley +Summary: opensips db_berkeley implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: db4-devel + +%description db_berkeley +This is a module which integrates the Berkeley DB into OpenSIPS. It implements the DB API defined in OpenSIPS. + + +%package db_oracle +Summary: opensips db_oracle implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: oracle-instantclient11.2-devel +AutoReqProv: no + +%description db_oracle +This is a module which provides Oracle connectivity for OpenSIPS. +It implements the DB API defined in OpenSIPS. +If you want to use the nathelper module, +or any other modules that calls the get_all_ucontacts API export from usrloc, +then you need to set the DORACLE_USRLOC define in the Makefile.defs file before compilation. + + +%package mi_xmlrpc +Summary: opensips mi_xmlrpc implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: xmlrpc-c-devel + +%description mi_xmlrpc +This module implements a xmlrpc server that handles xmlrpc requests and generates xmlrpc responses. +When a xmlrpc message is received a default method is executed. + + +%package mi_xmlrpc_ng +Summary: opensips mi_xmlrpc_ng implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: xmlrpc-c-devel + +%description mi_xmlrpc_ng +This module implements a xmlrpc_ng server that handles xmlrpc_ng requests and generates xmlrpc_ng responses. +When a xmlrpc_ng message is received a default method is executed. + + +%package db_http +Summary: opensips db_http implementation. +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: libcurl-devel libmicrohttpd-devel + +%description db_http +This module provides access to a database that is implemented as a HTTP server. +It may be used in special cases where traversing firewalls is a problem, +or where data encryption is required. + +%package cachedb_cassandra +Summary: Cassandra connector +Group: System Environment/Daemons +Requires: opensips = %ver +BuildRequires: thrift-cpp-devel + +%description cachedb_cassandra +Cassandra module is an implementation of a cache system designed to +work with a cassandra server. + +%package cachedb_mongodb +Summary: Mongodb connector +Group: System Environment/Daemons +Requires: opensips = %ver + +%description cachedb_mongodb +Mongodb module is an implementation of a cache system designed to +work with a mongodb server. + +%package osp +Summary: OSP Support for the OpenSIPS +Group: System Environment/Daemons +Requires: opensips = %ver + +%description osp +The OSP module enables OpenSIPS to support secure, multi-lateral peering using +the OSP standard defined by ETSI (TS 101 321 V4.1.1). + +%package perl +Summary: Helps implement your own OpenSIPS extensions in Perl +Group: System Environment/Daemons +BuildRequires: perl(ExtUtils::MakeMaker),perl(ExtUtils::Embed), perl-devel +Requires: opensips = %ver +Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) + +%description perl +The time needed when writing a new OpenSIPS module unfortunately is quite +high, while the options provided by the configuration file are limited to +the features implemented in the modules. With this Perl module, you can +easily implement your own OpenSIPS extensions in Perl. This allows for +simple access to the full world of CPAN modules. SIP URI rewriting could be +implemented based on regular expressions; accessing arbitrary data backends, +e.g. LDAP or Berkeley DB files, is now extremely simple. + +%package perlvdb +Summary: Perl virtual database engine +Group: System Environment/Daemons +BuildRequires: perl(ExtUtils::MakeMaker) +Requires: opensips = %ver +Requires: opensips-perl +Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) + +%description perlvdb +The Perl Virtual Database (VDB) provides a virtualization framework for +OpenSIPS's database access. It does not handle a particular database engine +itself but lets the user relay database requests to arbitrary Perl functions. + +%package sngtc +Summary: Sangoma media transcoding interface for the OpenSIPS +Group: System Environment/Daemons +Requires: opensips = %ver + +%description sngtc +The sngtc package implements interface to Sangoma media transcoding. + + +%package tlsops +Summary: TLS-relating functions for the OpenSIPS +Group: System Environment/Daemons +Requires: opensips = %ver + +%description tlsops +The opensips-tlsops package implements TLS related functions to use in the +routing script, and exports pseudo variables with certificate and TLS +parameters. + + %prep %setup -n %{name}-%{ver}-tls %build -make all skip_modules="%EXCLUDED_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%MYSQL_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%POSTGRES_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%UNIXODBC_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%XMPP_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%CPL_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%PRESENCE_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%RADIUS_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%B2BUA_MODULES" cfg-target=/%{_sysconfdir}/opensips/ -make modules modules="%SNMPSTATS_MODULES" cfg-target=/%{_sysconfdir}/opensips/ +ARCH=$(uname -m) +if [ "$ARCH" == "x86_64" ]; then + ORACLIENT=64 +else + ORACLIENT= +fi + +make all exclude_modules="" ORAVERSION=11.2/client$ORACLIENT cfg-target=%{_sysconfdir}/opensips/ %install [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT" -make install skip_modules="%EXCLUDED_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%MYSQL_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%MYSQL_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%POSTGRES_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%POSTGRES_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%UNIXODBC_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%UNIXODBC_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%XMPP_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%XMPP_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%CPL_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%CPL_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%PRESENCE_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%PRESENCE_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%RADIUS_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%RADIUS_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%B2BUA_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%B2BUA_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-modules modules="%SNMPSTATS_MODULES" \ - basedir=$RPM_BUILD_ROOT \ - prefix=/usr \ - cfg-prefix=$RPM_BUILD_ROOT \ - cfg-target=/%{_sysconfdir}/opensips/ -make install-doc modules="%SNMPSTATS_MODULES" \ +make install exclude_modules="" \ basedir=$RPM_BUILD_ROOT \ prefix=/usr \ cfg-prefix=$RPM_BUILD_ROOT \ @@ -289,31 +432,39 @@ fi %doc %{_docdir}/opensips/README.auth_diameter %doc %{_docdir}/opensips/README.avpops %doc %{_docdir}/opensips/README.benchmark +%doc %{_docdir}/opensips/README.cachedb_local +%doc %{_docdir}/opensips/README.cachedb_sql %doc %{_docdir}/opensips/README.call_control %doc %{_docdir}/opensips/README.cfgutils %doc %{_docdir}/opensips/README.closeddial %doc %{_docdir}/opensips/README.db_flatstore +%doc %{_docdir}/opensips/README.db_cachedb %doc %{_docdir}/opensips/README.db_text %doc %{_docdir}/opensips/README.db_virtual %doc %{_docdir}/opensips/README.dialog %doc %{_docdir}/opensips/README.dispatcher %doc %{_docdir}/opensips/README.diversion +%doc %{_docdir}/opensips/README.dns_cache %doc %{_docdir}/opensips/README.domain %doc %{_docdir}/opensips/README.domainpolicy %doc %{_docdir}/opensips/README.drouting %doc %{_docdir}/opensips/README.enum %doc %{_docdir}/opensips/README.event_datagram +%doc %{_docdir}/opensips/README.event_route +%doc %{_docdir}/opensips/README.event_xmlrpc %doc %{_docdir}/opensips/README.exec %doc %{_docdir}/opensips/README.gflags %doc %{_docdir}/opensips/README.group %doc %{_docdir}/opensips/README.imc %doc %{_docdir}/opensips/README.load_balancer -%doc %{_docdir}/opensips/README.localcache +%doc %{_docdir}/opensips/README.lua %doc %{_docdir}/opensips/README.mangler +%doc %{_docdir}/opensips/README.mathops %doc %{_docdir}/opensips/README.maxfwd %doc %{_docdir}/opensips/README.mediaproxy %doc %{_docdir}/opensips/README.mi_datagram %doc %{_docdir}/opensips/README.mi_fifo +%doc %{_docdir}/opensips/README.mi_http %doc %{_docdir}/opensips/README.msilo %doc %{_docdir}/opensips/README.nat_traversal %doc %{_docdir}/opensips/README.nathelper @@ -325,10 +476,14 @@ fi %doc %{_docdir}/opensips/README.qos %doc %{_docdir}/opensips/README.ratelimit %doc %{_docdir}/opensips/README.registrar +%doc %{_docdir}/opensips/README.rest_client %doc %{_docdir}/opensips/README.rr %doc %{_docdir}/opensips/README.rtpproxy %doc %{_docdir}/opensips/README.seas +%doc %{_docdir}/opensips/README.script_helper %doc %{_docdir}/opensips/README.signaling +%doc %{_docdir}/opensips/README.sipcapture +%doc %{_docdir}/opensips/README.sipmsgops %doc %{_docdir}/opensips/README.siptrace %doc %{_docdir}/opensips/README.sl %doc %{_docdir}/opensips/README.sms @@ -362,31 +517,39 @@ fi %{_libdir}/opensips/modules/auth_diameter.so %{_libdir}/opensips/modules/avpops.so %{_libdir}/opensips/modules/benchmark.so +%{_libdir}/opensips/modules/cachedb_local.so +%{_libdir}/opensips/modules/cachedb_sql.so %{_libdir}/opensips/modules/call_control.so %{_libdir}/opensips/modules/cfgutils.so %{_libdir}/opensips/modules/closeddial.so +%{_libdir}/opensips/modules/db_cachedb.so %{_libdir}/opensips/modules/db_flatstore.so %{_libdir}/opensips/modules/db_text.so %{_libdir}/opensips/modules/db_virtual.so %{_libdir}/opensips/modules/dialog.so %{_libdir}/opensips/modules/dispatcher.so %{_libdir}/opensips/modules/diversion.so +%{_libdir}/opensips/modules/dns_cache.so %{_libdir}/opensips/modules/domain.so %{_libdir}/opensips/modules/domainpolicy.so %{_libdir}/opensips/modules/drouting.so %{_libdir}/opensips/modules/enum.so %{_libdir}/opensips/modules/event_datagram.so +%{_libdir}/opensips/modules/event_route.so +%{_libdir}/opensips/modules/event_xmlrpc.so %{_libdir}/opensips/modules/exec.so %{_libdir}/opensips/modules/gflags.so %{_libdir}/opensips/modules/group.so %{_libdir}/opensips/modules/imc.so %{_libdir}/opensips/modules/load_balancer.so -%{_libdir}/opensips/modules/localcache.so +%{_libdir}/opensips/modules/lua.so %{_libdir}/opensips/modules/mangler.so +%{_libdir}/opensips/modules/mathops.so %{_libdir}/opensips/modules/maxfwd.so %{_libdir}/opensips/modules/mediaproxy.so %{_libdir}/opensips/modules/mi_datagram.so %{_libdir}/opensips/modules/mi_fifo.so +%{_libdir}/opensips/modules/mi_http.so %{_libdir}/opensips/modules/msilo.so %{_libdir}/opensips/modules/nat_traversal.so %{_libdir}/opensips/modules/nathelper.so @@ -395,13 +558,18 @@ fi %{_libdir}/opensips/modules/pdt.so %{_libdir}/opensips/modules/permissions.so %{_libdir}/opensips/modules/pike.so +%{_libdir}/opensips/modules/python.so %{_libdir}/opensips/modules/qos.so %{_libdir}/opensips/modules/ratelimit.so %{_libdir}/opensips/modules/registrar.so +%{_libdir}/opensips/modules/rest_client.so %{_libdir}/opensips/modules/rr.so %{_libdir}/opensips/modules/rtpproxy.so %{_libdir}/opensips/modules/seas.so +%{_libdir}/opensips/modules/script_helper.so %{_libdir}/opensips/modules/signaling.so +%{_libdir}/opensips/modules/sipcapture.so +%{_libdir}/opensips/modules/sipmsgops.so %{_libdir}/opensips/modules/siptrace.so %{_libdir}/opensips/modules/sl.so %{_libdir}/opensips/modules/sms.so @@ -421,10 +589,13 @@ fi %{_sbindir}/opensips %{_sbindir}/osipsconsole +%{_sbindir}/osipsconfig %{_sbindir}/opensipsctl %{_sbindir}/opensipsdbctl %{_sbindir}/opensipsunix %{_libdir}/opensips/opensipsctl/dbtextdb/dbtextdb.py +%{_libdir}/opensips/opensipsctl/dbtextdb/dbtextdb.pyc +%{_libdir}/opensips/opensipsctl/dbtextdb/dbtextdb.pyo %{_libdir}/opensips/opensipsctl/opensipsctl.base %{_libdir}/opensips/opensipsctl/opensipsctl.ctlbase %{_libdir}/opensips/opensipsctl/opensipsctl.dbtext @@ -438,6 +609,7 @@ fi %{_mandir}/man8/* %{_sharedir}/opensips/dbtext/opensips/* +%{_sharedir}/opensips/menuconfig_templates/ %files mysql %defattr(-,root,root) @@ -494,6 +666,7 @@ fi %doc %{_docdir}/opensips/README.pua_usrloc %doc %{_docdir}/opensips/README.pua_xmpp %doc %{_docdir}/opensips/README.rls +%doc %{_docdir}/opensips/README.xcap %doc %{_docdir}/opensips/README.xcap_client %{_libdir}/opensips/modules/presence.so @@ -509,6 +682,7 @@ fi %{_libdir}/opensips/modules/pua_usrloc.so %{_libdir}/opensips/modules/pua_xmpp.so %{_libdir}/opensips/modules/rls.so +%{_libdir}/opensips/modules/xcap.so %{_libdir}/opensips/modules/xcap_client.so @@ -537,12 +711,235 @@ fi %defattr(-,root,root) %doc %{_docdir}/opensips/README.b2b_entities %doc %{_docdir}/opensips/README.b2b_logic +%doc %{_docdir}/opensips/README.b2b_sca +%doc %{_docdir}/opensips/README.call_center %{_libdir}/opensips/modules/b2b_entities.so %{_libdir}/opensips/modules/b2b_logic.so +%{_libdir}/opensips/modules/b2b_sca.so +%{_libdir}/opensips/modules/call_center.so + + +%files ldap +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.ldap +%doc %{_docdir}/opensips/README.h350 + +%{_libdir}/opensips/modules/ldap.so +%{_libdir}/opensips/modules/h350.so + + +%files identity +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.identity + +%{_libdir}/opensips/modules/identity.so + + +%files regex +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.regex +%doc %{_docdir}/opensips/README.dialplan + +%{_libdir}/opensips/modules/regex.so +%{_libdir}/opensips/modules/dialplan.so + + +%files mmgeoip +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.mmgeoip + +%{_libdir}/opensips/modules/mmgeoip.so + + +%files json +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.json +%doc %{_docdir}/opensips/README.mi_json + +%{_libdir}/opensips/modules/json.so +%{_libdir}/opensips/modules/mi_json.so + + +%files carrierroute +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.carrierroute + +%{_libdir}/opensips/modules/carrierroute.so + + +%files cachedb_memcached +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.cachedb_memcached + +%{_libdir}/opensips/modules/cachedb_memcached.so + + +%files event_rabbitmq +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.event_rabbitmq + +%{_libdir}/opensips/modules/event_rabbitmq.so + + +%files cachedb_couchbase +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.cachedb_couchbase + +%{_libdir}/opensips/modules/cachedb_couchbase.so + + +%files cachedb_redis +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.cachedb_redis + +%{_libdir}/opensips/modules/cachedb_redis.so + + +%files db_berkeley +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.db_berkeley + +%{_sbindir}/bdb_recover +%{_libdir}/opensips/modules/db_berkeley.so +%{_libdir}/opensips/opensipsctl/opensipsctl.db_berkeley +%{_libdir}/opensips/opensipsctl/opensipsdbctl.db_berkeley +%{_sharedir}/opensips/db_berkeley/* + + +%files db_oracle +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.db_oracle + +%{_sbindir}/opensips_orasel +%{_libdir}/opensips/modules/db_oracle.so +%{_libdir}/opensips/opensipsctl/opensipsctl.oracle +%{_libdir}/opensips/opensipsctl/opensipsdbctl.oracle +%{_libdir}/opensips/opensipsctl/opensipsdbfunc.oracle +%{_sharedir}/opensips/oracle/* + +%files mi_xmlrpc +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.mi_xmlrpc + +%{_libdir}/opensips/modules/mi_xmlrpc.so + + +%files mi_xmlrpc_ng +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.mi_xmlrpc_ng + +%{_libdir}/opensips/modules/mi_xmlrpc_ng.so + + +%files db_http +%defattr(-,root,root) +%doc %{_docdir}/opensips/README.db_http +%doc %{_docdir}/opensips/README.httpd +%doc %{_docdir}/opensips/README.pi_http + +%{_libdir}/opensips/modules/db_http.so +%{_libdir}/opensips/modules/httpd.so +%{_libdir}/opensips/modules/pi_http.so +%{_sharedir}/opensips/pi_http/* + +%files cachedb_cassandra +%defattr(-,root,root,-) +%doc %{_docdir}/opensips/README.cachedb_cassandra + +%{_libdir}/opensips/modules/cachedb_cassandra.so + +%files cachedb_mongodb +%defattr(-,root,root,-) +%doc %{_docdir}/opensips/README.cachedb_mongodb + +%{_libdir}/opensips/modules/cachedb_mongodb.so + +%files osp +%defattr(-,root,root,-) +%doc %{_docdir}/opensips/README.osp + +%{_libdir}/opensips/modules/osp.so + +%files perl +%defattr(-,root,root,-) +%dir %{_libdir}/opensips/perl/OpenSIPS +%dir %{_libdir}/opensips/perl/OpenSIPS/LDAPUtils +%dir %{_libdir}/opensips/perl/OpenSIPS/Utils +%doc %{_docdir}/opensips/README.perl + +%{_libdir}/opensips/modules/perl.so +%{_libdir}/opensips/perl/OpenSIPS.pm +%{_libdir}/opensips/perl/OpenSIPS/Constants.pm +%{_libdir}/opensips/perl/OpenSIPS/LDAPUtils/LDAPConf.pm +%{_libdir}/opensips/perl/OpenSIPS/LDAPUtils/LDAPConnection.pm +%{_libdir}/opensips/perl/OpenSIPS/Message.pm +%{_libdir}/opensips/perl/OpenSIPS/Utils/PhoneNumbers.pm +%{_libdir}/opensips/perl/OpenSIPS/Utils/Debug.pm + +%files perlvdb +%defattr(-,root,root,-) +%dir %{_libdir}/opensips/perl/OpenSIPS/VDB +%dir %{_libdir}/opensips/perl/OpenSIPS/VDB/Adapter +%doc %{_docdir}/opensips/README.db_perlvdb + +%{_libdir}/opensips/modules/db_perlvdb.so +%{_libdir}/opensips/perl/OpenSIPS/VDB.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Adapter/AccountingSIPtrace.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Adapter/Alias.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Adapter/Auth.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Adapter/Describe.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Adapter/Speeddial.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Adapter/TableVersions.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Column.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Pair.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/ReqCond.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Result.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/VTab.pm +%{_libdir}/opensips/perl/OpenSIPS/VDB/Value.pm + +%files sngtc +%defattr(-,root,root,-) +%doc %{_docdir}/opensips/README.sngtc + +%{_libdir}/opensips/modules/sngtc.so + + +%files tlsops +%defattr(-,root,root,-) +%doc %{_docdir}/opensips/README.tlsops + +%{_libdir}/opensips/modules/tlsops.so %changelog +* Sun Apr 13 2014 Fabrizio Picconi +- Fix x64_86 compilation problems + +* Tue Mar 22 2014 Fabrizio Picconi +- Some new rpm optional modules are added: + b2b_sca,call_center,mi_json,script_helper + +* Tue Aug 06 2013 Fabrizio Picconi +- Some new rpm optional modules are added: + mi_xmlrpc_ng,sngtc,db_cachedb,mathops,rest_client + +* Sun Jul 21 2013 Fabrizio Picconi +- Some new rpm optional modules are added: + cachedb_cassandra,cachedb_mongodb,osp,perl,perlvdb,tlsops + +* Sun Jun 02 2013 Fabrizio Picconi +- CentOS 6 support + Remove rpmbuild warning on BuildPrereq now deprecated for BuildRequires +- opensips 1.9.1 support + Updated list of excluded modules + Updated list of file in rpm of core and modules +- Some new rpm optional modules are added: + db_http pi_http json cachedb_couchbase cachedb_memcached + cachedb_redis event_rabbitmq db_berkeley perl db_perlvdb + carrierroute mmgeoip ldap h350 identity regex dialplan + Xlog mi_xmlrpc db_oracle + * Mon Oct 18 2010 Marc Leurent - Add missing dependencies pcre-devel for compilation - Xlog Module has been merged into core. diff --git a/packaging/rpm/opensips.spec.SuSE b/packaging/rpm/opensips.spec.SuSE index a696ed80949..3e8f8a100de 100644 --- a/packaging/rpm/opensips.spec.SuSE +++ b/packaging/rpm/opensips.spec.SuSE @@ -1,5 +1,5 @@ %define name opensips -%define ver 1.9.0 +%define ver 1.11.0 %define rel 0 %define EXCLUDED_MODULES aaa_radius b2b_entities b2b_logic db_http json memcached jabber cpl-c xmpp rls mi_xmlrpc xcap_client db_mysql db_postgres db_unixodbc db_oracle db_berkeley osp perl snmpstats db_perlvdb peering carrierroute mmgeoip presence presence_xml presence_mwi presence_dialoginfo pua pua_bla pua_mi pua_usrloc pua_xmpp pua_dialoginfo xcap xcap_client ldap h350 identity regex diff --git a/packaging/solaris/base-pkginfo b/packaging/solaris/base-pkginfo index 118ad79fe4f..c656e024343 100644 --- a/packaging/solaris/base-pkginfo +++ b/packaging/solaris/base-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-base-dbg" NAME="Programmable SIP Server Base Install - Debugging Symbols" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="bogdan@opensips.org" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/berkeley-pkginfo b/packaging/solaris/berkeley-pkginfo index b9d2ca0de0b..f606518e3bd 100644 --- a/packaging/solaris/berkeley-pkginfo +++ b/packaging/solaris/berkeley-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-berkeley-dbg" NAME="Programmable SIP Server Berkeley Database Support - Debugging Symbols" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/carrierroute-pkginfo b/packaging/solaris/carrierroute-pkginfo index 238715d89fc..d683342ed2a 100644 --- a/packaging/solaris/carrierroute-pkginfo +++ b/packaging/solaris/carrierroute-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-carrierroute" NAME="Programmable SIP Server carrierroute Support" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/identity-pkginfo b/packaging/solaris/identity-pkginfo index 29d5c537627..334afd0224d 100644 --- a/packaging/solaris/identity-pkginfo +++ b/packaging/solaris/identity-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-identity" NAME="Programmable SIP Server Identity Module" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/ldap-pkginfo b/packaging/solaris/ldap-pkginfo index 4bf5300966d..b7eb4034d10 100644 --- a/packaging/solaris/ldap-pkginfo +++ b/packaging/solaris/ldap-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-ldap" NAME="Programmable SIP Server LDAP Support" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/mmgeoip-pkginfo b/packaging/solaris/mmgeoip-pkginfo index 89d68acabe6..aa9cc59c6de 100644 --- a/packaging/solaris/mmgeoip-pkginfo +++ b/packaging/solaris/mmgeoip-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-geoip" NAME="Programmable SIP Server Address Location Support" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/mysql-pkginfo b/packaging/solaris/mysql-pkginfo index b7b2fd47527..bdfd266f0e5 100644 --- a/packaging/solaris/mysql-pkginfo +++ b/packaging/solaris/mysql-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-mysql" NAME="Programmable SIP Server MySQL Support" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/perl-pkginfo b/packaging/solaris/perl-pkginfo index 1bc03424a75..3b4cdd6873e 100644 --- a/packaging/solaris/perl-pkginfo +++ b/packaging/solaris/perl-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-perl" NAME="Programmable SIP Server PERL Support" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/pgsql-pkginfo b/packaging/solaris/pgsql-pkginfo index 644b1b68b04..7c337f97f10 100644 --- a/packaging/solaris/pgsql-pkginfo +++ b/packaging/solaris/pgsql-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-pgsql" NAME="Programmable SIP Server PostgreSQL Support" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/regex-pkginfo b/packaging/solaris/regex-pkginfo index 91466faca7e..2ccd6cd2cf7 100644 --- a/packaging/solaris/regex-pkginfo +++ b/packaging/solaris/regex-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-regex" NAME="Programmable SIP Server Regex Module" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/snmp-pkginfo b/packaging/solaris/snmp-pkginfo index 4de0cd09acb..1b8f308c326 100644 --- a/packaging/solaris/snmp-pkginfo +++ b/packaging/solaris/snmp-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-snmp" NAME="Programmable SIP Server SNMP Support" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/tls-pkginfo b/packaging/solaris/tls-pkginfo index 33efd9f0598..7cccaee85b3 100644 --- a/packaging/solaris/tls-pkginfo +++ b/packaging/solaris/tls-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-base-TLS" NAME="Programmable SIP Server Base Install with TLS" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/packaging/solaris/xmlrpc-pkginfo b/packaging/solaris/xmlrpc-pkginfo index f58c52b2e3f..3aff6859249 100644 --- a/packaging/solaris/xmlrpc-pkginfo +++ b/packaging/solaris/xmlrpc-pkginfo @@ -1,11 +1,11 @@ PKG="OpenSIPS-xmlrpc" NAME="Programmable SIP Server MI XMLRPC Support" -VERSION="1.9.0-notls" +VERSION="1.11.0-notls" ARCH="sparc" CLASSES="none" CATEGORY="utility" VENDOR="OpenSIPS Solutions" -PSTAMP="29thJan13" +PSTAMP="20thMar14" EMAIL="saguti@gmail.com" ISTATES="S s 1 2 3" RSTATES="S s 1 2 3" diff --git a/parser/case_acce.h b/parser/case_acce.h index b1ba8305779..62b4e2a3ffa 100644 --- a/parser/case_acce.h +++ b/parser/case_acce.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Accept and Accept-Language Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_allo.h b/parser/case_allo.h index 8af10fac9ae..7b618c2ff44 100644 --- a/parser/case_allo.h +++ b/parser/case_allo.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Allow Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_auth.h b/parser/case_auth.h index 3de7bb152ad..f74ed807b88 100644 --- a/parser/case_auth.h +++ b/parser/case_auth.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Authorization Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_call.h b/parser/case_call.h index b797c2e51c8..7c2d3e15dfa 100644 --- a/parser/case_call.h +++ b/parser/case_call.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Call-ID Header Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_cont.h b/parser/case_cont.h index 7356dac77b4..4c3698e8de0 100644 --- a/parser/case_cont.h +++ b/parser/case_cont.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Contact, Content-Type, Content-Length, Content-Disposition * Header Field Name Parsing Macros @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_cseq.h b/parser/case_cseq.h index c9e2645ed39..56bb6c94eb2 100644 --- a/parser/case_cseq.h +++ b/parser/case_cseq.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * CSeq Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_dive.h b/parser/case_dive.h index aa335040458..b3cc2ffd0a6 100644 --- a/parser/case_dive.h +++ b/parser/case_dive.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Diversion Header Field Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_even.h b/parser/case_even.h index e65e35b8949..88d938d44b1 100644 --- a/parser/case_even.h +++ b/parser/case_even.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Event Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_expi.h b/parser/case_expi.h index 5e54709bee9..196ce9907c9 100644 --- a/parser/case_expi.h +++ b/parser/case_expi.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Expires Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_from.h b/parser/case_from.h index 6a6d2aa1e07..ec003216010 100644 --- a/parser/case_from.h +++ b/parser/case_from.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * From Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_max.h b/parser/case_max.h index 1ae992deaf4..b07c0e41d36 100644 --- a/parser/case_max.h +++ b/parser/case_max.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Max-Forwards Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_min_.h b/parser/case_min_.h index e01f317c813..dca4d8b94fc 100644 --- a/parser/case_min_.h +++ b/parser/case_min_.h @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Session-Expires Header Field Name Parsing Macros * * Copyright (c) 2006 SOMA Networks, Inc. @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -46,7 +46,7 @@ #define SE_EXPI_CASE \ if ( LOWER_BYTE(*p) == 's' ) { \ p++; \ - switch ( LOWER_BYTE(*(p+1)) ) { \ + switch ( LOWER_BYTE(*p) ) { \ case 'e': \ hdr->type = HDR_MIN_SE_T; \ hdr->name.len = 6; \ diff --git a/parser/case_orga.h b/parser/case_orga.h index 34843c942e1..96d800dada0 100644 --- a/parser/case_orga.h +++ b/parser/case_orga.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Organization Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_p_as.h b/parser/case_p_as.h index f941be599a5..56815b3e640 100644 --- a/parser/case_p_as.h +++ b/parser/case_p_as.h @@ -1,4 +1,4 @@ -/* +/* * * P-Asserted-Identity Header Field Name Parsing Macros * @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_p_pr.h b/parser/case_p_pr.h index 57b9e60dee3..e95314c1eeb 100644 --- a/parser/case_p_pr.h +++ b/parser/case_p_pr.h @@ -1,4 +1,4 @@ -/* +/* * * P-Preferred-Identity Header Field Name Parsing Macros * @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_prio.h b/parser/case_prio.h index 0867937f6b5..92ddf801eef 100644 --- a/parser/case_prio.h +++ b/parser/case_prio.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Priority Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_priv.h b/parser/case_priv.h index 8bd4dc766ff..61f2fadbff4 100644 --- a/parser/case_priv.h +++ b/parser/case_priv.h @@ -1,4 +1,4 @@ -/* +/* * * Privacy Header Field Name Parsing Macros * @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_prox.h b/parser/case_prox.h index 9329ec80ebc..ae4589711ad 100644 --- a/parser/case_prox.h +++ b/parser/case_prox.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Proxy-Require, Proxy-Authorization Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_reco.h b/parser/case_reco.h index 8649917b88a..e0d04ff7c75 100644 --- a/parser/case_reco.h +++ b/parser/case_reco.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Record-Route Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_refe.h b/parser/case_refe.h index 8cfed49b5cd..27b235fd298 100644 --- a/parser/case_refe.h +++ b/parser/case_refe.h @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Refer-To Header Field Name Parsing Macros * * Copyright (C) 2005 Juha Heinanen @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/parser/case_remo.h b/parser/case_remo.h index 8b2c922cf6f..ebcf3797bbf 100644 --- a/parser/case_remo.h +++ b/parser/case_remo.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Remote-Party-ID Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_requ.h b/parser/case_requ.h index 2d33ebfa452..88eb0c03a3f 100644 --- a/parser/case_requ.h +++ b/parser/case_requ.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Require Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_retr.h b/parser/case_retr.h index 4a6d3d1f198..d38ec3de7cb 100644 --- a/parser/case_retr.h +++ b/parser/case_retr.h @@ -1,4 +1,4 @@ -/* +/* * * P-Asserted-Identity Header Field Name Parsing Macros * @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_rout.h b/parser/case_rout.h index 94778ca931b..191193fc7a2 100644 --- a/parser/case_rout.h +++ b/parser/case_rout.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Route Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_sess.h b/parser/case_sess.h index d796194205a..afb489872d9 100644 --- a/parser/case_sess.h +++ b/parser/case_sess.h @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Session-Expires Header Field Name Parsing Macros * * Copyright (c) 2006 SOMA Networks, Inc. @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_sip.h b/parser/case_sip.h index 966fb2ca560..23daf87c28f 100644 --- a/parser/case_sip.h +++ b/parser/case_sip.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Route Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -45,7 +45,7 @@ atch_CASE; \ goto other; \ } - + #define sip_CASE \ LM_DBG("beginning of SIP-If-Match: yet=0x%04x\n",LOWER_DWORD(val)); \ p += 4; \ diff --git a/parser/case_subj.h b/parser/case_subj.h index 55f155dc85e..524f995a696 100644 --- a/parser/case_subj.h +++ b/parser/case_subj.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Subject Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_supp.h b/parser/case_supp.h index 465b783e062..22d2bc05cba 100644 --- a/parser/case_supp.h +++ b/parser/case_supp.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Supported Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_to.h b/parser/case_to.h index e931acfbe04..3c9bf2e073c 100644 --- a/parser/case_to.h +++ b/parser/case_to.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * To Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_unsu.h b/parser/case_unsu.h index 8b9bfafe46d..537144581a9 100644 --- a/parser/case_unsu.h +++ b/parser/case_unsu.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Unsupported Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_user.h b/parser/case_user.h index ce071059864..faf46efd04b 100644 --- a/parser/case_user.h +++ b/parser/case_user.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * User-Agent Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/case_via.h b/parser/case_via.h index 6ee2bf24071..f4c2bdcad34 100644 --- a/parser/case_via.h +++ b/parser/case_via.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Via Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/case_www.h b/parser/case_www.h index 8c22d097f22..152b072a7c0 100644 --- a/parser/case_www.h +++ b/parser/case_www.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * WWW-Authenticate Header Field Name Parsing Macros * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -44,7 +44,7 @@ val = READ(p); \ CATE_CASE; \ goto other; \ -} +} #define WWW_AUTH_CASE \ diff --git a/parser/contact/contact.c b/parser/contact/contact.c index a0d7d8a0949..7019eade3f4 100644 --- a/parser/contact/contact.c +++ b/parser/contact/contact.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -70,17 +70,17 @@ static inline int skip_uri(str* _s) case '<': switch(st) { case ST1: st = ST3; break; - case ST3: + case ST3: LM_ERR("second < found\n"); return -1; case ST5: st = ST2; break; case ST6: st = ST4; break; } break; - + case '>': switch(st) { - case ST1: + case ST1: LM_ERR("> is first\n"); return -2; @@ -126,7 +126,7 @@ static inline int skip_name(str* _s) { char* last_wsp, *p; int i, quoted = 0; - + if (!_s) { LM_ERR("invalid parameter value\n"); @@ -147,7 +147,7 @@ static inline int skip_name(str* _s) _s->len -= i; return 0; } - + if (*p == ':') { if (last_wsp) { _s->s = last_wsp; @@ -195,7 +195,7 @@ int parse_contacts(str* _s, contact_t** _c) goto error; } memset(c, 0, sizeof(contact_t)); - + c->name.s = _s->s; if (skip_name(_s) < 0) { @@ -206,13 +206,13 @@ int parse_contacts(str* _s, contact_t** _c) c->uri.s = _s->s; c->name.len = _s->s - c->name.s; trim_trailing(&c->name); - + /* Find the end of the URI */ if (skip_uri(_s) < 0) { LM_ERR("failed to skip URI\n"); goto error; } - + c->uri.len = _s->s - c->uri.s; /* Calculate URI length */ trim_trailing(&(c->uri)); /* Remove any trailing spaces from URI */ @@ -224,14 +224,14 @@ int parse_contacts(str* _s, contact_t** _c) } trim(&c->uri); - + if (_s->len == 0) goto ok; - + if (_s->s[0] == ';') { /* Contact parameter found */ _s->s++; _s->len--; trim_leading(_s); - + if (_s->len == 0) { LM_ERR("failed to parse params\n"); goto error; diff --git a/parser/contact/contact.h b/parser/contact/contact.h index 8929e491611..7d6cff121d4 100644 --- a/parser/contact/contact.h +++ b/parser/contact/contact.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/contact/parse_contact.c b/parser/contact/parse_contact.c index b4cbd94f825..a80b938f4ea 100644 --- a/parser/contact/parse_contact.c +++ b/parser/contact/parse_contact.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -27,7 +27,7 @@ */ #include /* memset */ -#include "../hf.h" +#include "../hf.h" #include "../../mem/mem.h" /* pkg_malloc, pkg_free */ #include "../../dprint.h" #include "../../trim.h" /* trim_leading */ @@ -108,7 +108,7 @@ void free_contact(contact_body_t** _c) if ((*_c)->contacts) { free_contacts(&((*_c)->contacts)); } - + pkg_free(*_c); *_c = 0; } @@ -199,10 +199,10 @@ int contact_iterator(contact_t** c, struct sip_msg* msg, contact_t* prev) LM_ERR("failed to parse message header\n"); return -1; } - + /* Check if last found header field is Contact * and if it is not the same header field as the - * previous Contact HF (that indicates that the previous + * previous Contact HF (that indicates that the previous * one was the last header field in the header) */ if ((msg->last_header->type == HDR_CONTACT_T) && @@ -213,12 +213,12 @@ int contact_iterator(contact_t** c, struct sip_msg* msg, contact_t* prev) return 1; } } - + if (parse_contact(hdr) < 0) { LM_ERR("failed to parse Contact HF body\n"); return -1; } - + /* And return first contact within that * header field */ diff --git a/parser/contact/parse_contact.h b/parser/contact/parse_contact.h index dfcb1009809..23bd4756bb9 100644 --- a/parser/contact/parse_contact.h +++ b/parser/contact/parse_contact.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/digest/digest.c b/parser/digest/digest.c index 4483e5b7619..702aab9035d 100644 --- a/parser/digest/digest.c +++ b/parser/digest/digest.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -42,7 +42,7 @@ static inline int new_credentials(struct hdr_field* _h) LM_ERR("no pkg memory left\n"); return -1; } - + init_dig_cred(&(b->digest)); b->stale = 0; b->authorized = 0; @@ -78,7 +78,7 @@ int parse_credentials(struct hdr_field* _h) * credentials are broken */ res = parse_digest_cred(&(_h->body), &(((auth_body_t*)(_h->parsed))->digest)); - + if (res != 0) { free_credentials((auth_body_t**)(void*)&(_h->parsed)); } @@ -99,11 +99,11 @@ void free_credentials(auth_body_t** _b) /* * Check semantics of a digest credentials structure - * Make sure that all attributes needed to verify response + * Make sure that all attributes needed to verify response * string are set or at least have a default value * * The returned value is logical OR of all errors encountered - * during the check, see dig_err_t type for more details + * during the check, see dig_err_t type for more details */ dig_err_t check_dig_cred(dig_cred_t* _c) { @@ -115,13 +115,6 @@ dig_err_t check_dig_cred(dig_cred_t* _c) /* Realm must be present */ if (_c->realm.s == 0) res |= E_DIG_REALM; - /* If Username has domain, it must equal to Realm */ - if (_c->username.domain.s && - ((_c->username.domain.len != _c->realm.len) || - (strncmp(_c->username.domain.s, _c->realm.s, - _c->realm.len) != 0))) - res |= E_DIG_DOMAIN; - /* Nonce that was used must be specified */ if (_c->nonce.s == 0) res |= E_DIG_NONCE; @@ -140,8 +133,8 @@ dig_err_t check_dig_cred(dig_cred_t* _c) /* and also nonce count must be specified */ if (_c->nc.s == 0) res |= E_DIG_NC; } - - return res; + + return res; } @@ -197,7 +190,7 @@ void print_cred(dig_cred_t* _c) int mark_authorized_cred(struct sip_msg* _m, struct hdr_field* _h) { struct hdr_field* f; - + switch(_h->type) { case HDR_AUTHORIZATION_T: f = _m->authorization; break; case HDR_PROXYAUTH_T: f = _m->proxy_auth; break; @@ -230,6 +223,6 @@ int get_authorized_cred(struct hdr_field* _f, struct hdr_field** _h) } else { *_h = 0; } - + return 0; } diff --git a/parser/digest/digest.h b/parser/digest/digest.h index 3390e939c40..416e0b7ca42 100644 --- a/parser/digest/digest.h +++ b/parser/digest/digest.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -40,7 +40,7 @@ typedef struct auth_body { * This is necessary for functions called after * {www,proxy}_authorize, these functions need to know * which credentials are authorized and they will simply - * look into + * look into * sip_msg->{authorization,proxy_auth}->parsed->authorized */ struct hdr_field* authorized; diff --git a/parser/digest/digest_keys.h b/parser/digest/digest_keys.h index d1ca05bc1f6..cb6c058510e 100644 --- a/parser/digest/digest_keys.h +++ b/parser/digest/digest_keys.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/digest/digest_parser.c b/parser/digest/digest_parser.c index 193e4343302..26e1bf12bdc 100644 --- a/parser/digest/digest_parser.c +++ b/parser/digest/digest_parser.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -207,7 +207,7 @@ static inline int parse_digest_param(str* _s, dig_cred_t* _c) return -4; } } - + return 0; } @@ -256,7 +256,7 @@ static inline void parse_algorithm(struct algorithm* _a) _a->alg_parsed = ALG_MD5SESS; } else { _a->alg_parsed = ALG_OTHER; - } + } } @@ -292,11 +292,11 @@ static inline int parse_digest_params(str* _s, dig_cred_t* _c) if (parse_digest_param(_s, _c) < 0) { return -1; } - + /* Try to find the next parameter */ comma = q_memchr(_s->s, ',', _s->len); if (comma) { - /* Yes, there is another, + /* Yes, there is another, * remove any leading white-spaces * and let _s point to the next * parameter name @@ -338,7 +338,7 @@ int parse_digest_cred(str* _s, dig_cred_t* _c) str tmp; /* Make a temporary copy, we are - * going to modify it + * going to modify it */ tmp.s = _s->s; tmp.len = _s->len; @@ -354,14 +354,14 @@ int parse_digest_cred(str* _s, dig_cred_t* _c) */ if (!strncasecmp(tmp.s, DIGEST_SCHEME, DIG_LEN) && ((tmp.s[DIG_LEN] == ' ') || /* Test for one of LWS chars */ - (tmp.s[DIG_LEN] == '\r') || - (tmp.s[DIG_LEN] == 'n') || + (tmp.s[DIG_LEN] == '\r') || + (tmp.s[DIG_LEN] == 'n') || (tmp.s[DIG_LEN] == '\t') || (tmp.s[DIG_LEN] == ','))) { /* Scheme is Digest */ tmp.s += DIG_LEN + 1; tmp.len -= DIG_LEN + 1; - + /* Again, skip all white-spaces */ trim_leading(&tmp); diff --git a/parser/digest/digest_parser.h b/parser/digest/digest_parser.h index 95e6235416a..2f418affe6a 100644 --- a/parser/digest/digest_parser.h +++ b/parser/digest/digest_parser.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -44,7 +44,7 @@ typedef enum alg { /* Quality Of Protection used */ -typedef enum qop_type { +typedef enum qop_type { QOP_UNSPEC_D = 0, /* QOP parameter not present in response */ QOP_AUTH_D = 1, /* Authentication only */ QOP_AUTHINT_D = 2, /* Authentication with integrity checks */ diff --git a/parser/digest/param_parser.c b/parser/digest/param_parser.c index 4e255042fde..54ffae3f35a 100644 --- a/parser/digest/param_parser.c +++ b/parser/digest/param_parser.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -188,16 +188,16 @@ int parse_param_name(str* _s, dig_par_t* _type) register char* p; register int val; char* end; - + end = _s->s + _s->len; - + p = _s->s; val = READ(p); - + if (_s->len < 4) { goto other; } - + switch(LOWER_DWORD(val)) { FIRST_QUATERNIONS; default: @@ -213,7 +213,7 @@ int parse_param_name(str* _s, dig_par_t* _type) if (_s->s[0] == '=') { return 0; } - + other: p = q_memchr(p, '=', end - p); if (!p) { diff --git a/parser/digest/param_parser.h b/parser/digest/param_parser.h index d9ef4ff5fe8..fd71ac1f6b8 100644 --- a/parser/digest/param_parser.h +++ b/parser/digest/param_parser.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/hf.c b/parser/hf.c index 86651ae29bd..6bb82f260c3 100644 --- a/parser/hf.c +++ b/parser/hf.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -148,10 +148,10 @@ void clean_hdr_field(struct hdr_field* hf) case HDR_ACCEPTLANGUAGE_T: break; - + case HDR_ORGANIZATION_T: break; - + case HDR_PRIORITY_T: break; @@ -229,13 +229,13 @@ void clean_hdr_field(struct hdr_field* hf) } -/* +/* * Frees a hdr_field list, * WARNING: frees only ->parsed and ->next*/ void free_hdr_field_lst(struct hdr_field* hf) { struct hdr_field* foo; - + while(hf) { foo=hf; hf=hf->next; diff --git a/parser/hf.h b/parser/hf.h index f2b9f1434a4..9a6bf6ae82e 100644 --- a/parser/hf.h +++ b/parser/hf.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -110,7 +110,7 @@ typedef unsigned long long hdr_flags_t; /** * Flags definitions - * (enums won't work with all the compilers (e.g. icc) due to the 64bit size) + * (enums won't work with all the compilers (e.g. icc) due to the 64bit size) */ #define HDR_EOH_F HDR_F_DEF(EOH) #define HDR_VIA_F HDR_F_DEF(VIA) diff --git a/parser/keys.h b/parser/keys.h index 16b127cc6d3..5c6674fe101 100644 --- a/parser/keys.h +++ b/parser/keys.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Fast 32-bit Header Field Name Parser -- keys * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/msg_parser.c b/parser/msg_parser.c index 6789862fb4b..e77f94584ec 100644 --- a/parser/msg_parser.c +++ b/parser/msg_parser.c @@ -1,7 +1,7 @@ /* * $Id$ * - * sip msg. header proxy parser + * sip msg. header proxy parser * * Copyright (C) 2001-2003 FhG Fokus * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -94,7 +94,7 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) } /* eliminate leading whitespace */ - tmp=eat_lws_end(tmp, end); + tmp=eat_lws_end(tmp, end); if (tmp>=end) { LM_ERR("hf empty\n"); goto error_bad_hdr; @@ -150,8 +150,8 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) hdr->parsed=cseq_b; hdr->body.len=tmp-hdr->body.s; LM_DBG("cseq <%.*s>: <%.*s> <%.*s>\n", - hdr->name.len, ZSW(hdr->name.s), - cseq_b->number.len, ZSW(cseq_b->number.s), + hdr->name.len, ZSW(hdr->name.s), + cseq_b->number.len, ZSW(cseq_b->number.s), cseq_b->method.len, cseq_b->method.s); break; case HDR_TO_T: @@ -174,7 +174,7 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) hdr->parsed=to_b; hdr->body.len=tmp-hdr->body.s; LM_DBG("<%.*s> [%d]; uri=[%.*s] \n", - hdr->name.len, ZSW(hdr->name.s), + hdr->name.len, ZSW(hdr->name.s), hdr->body.len, to_b->uri.len,ZSW(to_b->uri.s)); LM_DBG("to body [%.*s]\n",to_b->body.len, ZSW(to_b->body.s)); break; @@ -303,13 +303,13 @@ int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next) end=msg->buf+msg->len; tmp=msg->unparsed; - + if (next) { orig_flag = msg->parsed_flag; msg->parsed_flag &= ~flags; }else - orig_flag=0; - + orig_flag=0; + LM_DBG("flags=%llx\n", (unsigned long long)flags); while( tmpparsed_flag) != flags){ hf=pkg_malloc(sizeof(struct hdr_field)); @@ -523,8 +523,8 @@ int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next) } #ifdef EXTRA_DEBUG LM_DBG("header field type %d, name=<%.*s>, body=<%.*s>\n", - hf->type, - hf->name.len, ZSW(hf->name.s), + hf->type, + hf->name.len, ZSW(hf->name.s), hf->body.len, ZSW(hf->body.s)); #endif tmp=rest; @@ -563,7 +563,7 @@ int parse_msg(char* buf, unsigned int len, struct sip_msg* msg) switch(fl->type){ case SIP_INVALID: LM_DBG("invalid message\n"); - /* if failed to parse the first line, we simply consider that the whole + /* if failed to parse the first line, we simply consider that the whole buffer was parsed, so that nothing is left to be parsed :) - this will do the trick and make "msg" struct acceptable for following parsing attempts */ @@ -602,52 +602,52 @@ int parse_msg(char* buf, unsigned int len, struct sip_msg* msg) /* dump parsed data */ if (msg->via1){ LM_DBG(" first via: <%.*s/%.*s/%.*s> <%.*s:%.*s(%d)>", - msg->via1->name.len, - ZSW(msg->via1->name.s), + msg->via1->name.len, + ZSW(msg->via1->name.s), msg->via1->version.len, ZSW(msg->via1->version.s), msg->via1->transport.len, - ZSW(msg->via1->transport.s), + ZSW(msg->via1->transport.s), msg->via1->host.len, ZSW(msg->via1->host.s), - msg->via1->port_str.len, - ZSW(msg->via1->port_str.s), + msg->via1->port_str.len, + ZSW(msg->via1->port_str.s), msg->via1->port); - if (msg->via1->params.s) LM_DBG(";<%.*s>", + if (msg->via1->params.s) LM_DBG(";<%.*s>", msg->via1->params.len, ZSW(msg->via1->params.s)); - if (msg->via1->comment.s) - LM_DBG(" <%.*s>", + if (msg->via1->comment.s) + LM_DBG(" <%.*s>", msg->via1->comment.len, ZSW(msg->via1->comment.s)); LM_DBG ("\n"); } if (msg->via2){ LM_DBG(" first via: <%.*s/%.*s/%.*s> <%.*s:%.*s(%d)>", - msg->via2->name.len, - ZSW(msg->via2->name.s), + msg->via2->name.len, + ZSW(msg->via2->name.s), msg->via2->version.len, ZSW(msg->via2->version.s), - msg->via2->transport.len, - ZSW(msg->via2->transport.s), + msg->via2->transport.len, + ZSW(msg->via2->transport.s), msg->via2->host.len, ZSW(msg->via2->host.s), - msg->via2->port_str.len, - ZSW(msg->via2->port_str.s), + msg->via2->port_str.len, + ZSW(msg->via2->port_str.s), msg->via2->port); - if (msg->via2->params.s) LM_DBG(";<%.*s>", + if (msg->via2->params.s) LM_DBG(";<%.*s>", msg->via2->params.len, ZSW(msg->via2->params.s)); - if (msg->via2->comment.s) LM_DBG(" <%.*s>", + if (msg->via2->comment.s) LM_DBG(" <%.*s>", msg->via2->comment.len, ZSW(msg->via2->comment.s)); LM_DBG ("\n"); } #endif - + #ifdef EXTRA_DEBUG LM_DBG("exiting\n"); #endif return 0; - + error: /* more debugging, msg->orig is/should be null terminated*/ LM_ERR("message=<%.*s>\n", (int)len, ZSW(buf)); @@ -673,6 +673,14 @@ void free_sip_msg(struct sip_msg* msg) { if (msg->msg_cb) { msg_callback_process(msg, MSG_DESTROY, NULL); } if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; } + if (msg->set_global_address.s) { + pkg_free(msg->set_global_address.s); + msg->set_global_address.s = NULL; + } + if (msg->set_global_port.s) { + pkg_free(msg->set_global_port.s); + msg->set_global_port.s = NULL; + } if (msg->dst_uri.s) { pkg_free(msg->dst_uri.s); msg->dst_uri.len=0; } if (msg->path_vec.s) { pkg_free(msg->path_vec.s); msg->path_vec.len=0; } if (msg->headers) free_hdr_field_lst(msg->headers); @@ -683,7 +691,7 @@ void free_sip_msg(struct sip_msg* msg) if (msg->multi ) { free_multi_body(msg->multi);msg->multi = 0;} /* don't free anymore -- now a pointer to a static buffer */ # ifdef DYN_BUF - pkg_free(msg->buf); + pkg_free(msg->buf); # endif } @@ -831,7 +839,7 @@ int extract_ftc_hdrs( char *buf, int len, str *from, str *to, str *cseq,str *cal end = buf+len; state = 1; b = 0; - flags = ((from!=0)?0x1:0) | ((to!=0)?0x2:0) | ((cseq!=0)?0x4:0) + flags = ((from!=0)?0x1:0) | ((to!=0)?0x2:0) | ((cseq!=0)?0x4:0) | ((callid!=0)?0x8:0); flag = 0; fill = 0; @@ -897,13 +905,13 @@ int extract_ftc_hdrs( char *buf, int len, str *from, str *to, str *cseq,str *cal if (state!=2) {state = 1;break;} /* hdr starting with 'c' */ if (cseq==0 && callid == 0) break; - if (p+3new_uri.s && (m)->new_uri.len) ? (&(m)->new_uri) : (&(m)->first_line.u.request.uri)) -enum _uri_type{ERROR_URI_T=0, SIP_URI_T, SIPS_URI_T, TEL_URI_T, TELS_URI_T}; +enum _uri_type{ERROR_URI_T=0, SIP_URI_T, SIPS_URI_T, TEL_URI_T, TELS_URI_T, URN_SERVICE_URI_T}; typedef enum _uri_type uri_type; struct sip_uri { @@ -152,7 +152,7 @@ struct sip_uri { str host; /* Host name */ str port; /* Port number */ str params; /* Parameters */ - str headers; + str headers; unsigned short port_no; unsigned short proto; /* from transport */ uri_type type; /* uri scheme */ @@ -248,7 +248,7 @@ struct sip_msg { char* eoh; /* pointer to the end of header (if found) or null */ char* unparsed; /* here we stopped parsing*/ - + struct receive_info rcv; /* source & dest ip, ports, proto a.s.o*/ char* buf; /* scratch pad, holds a unmodified message, @@ -261,7 +261,7 @@ struct sip_msg { * don't forget to set parsed_uri_ok to 0 */ str dst_uri; /* Destination URI, must be forwarded to this URI if len!=0 */ - + /* current uri */ int parsed_uri_ok; /* 1 if parsed_uri is valid, 0 if not, set it to 0 if you modify the uri (e.g change new_uri)*/ @@ -278,16 +278,16 @@ struct sip_msg { /* whatever whoever want to append to branch comes here */ char add_to_branch_s[MAX_BRANCH_PARAM_LEN]; int add_to_branch_len; - - /* index to TM hash table; stored in core to avoid + + /* index to TM hash table; stored in core to avoid * unnecessary calculations */ unsigned int hash_index; /* flags used from script */ flag_t flags; - /* flags used by core - allows to set various flags on the message; may - * be used for simple inter-module communication or remembering + /* flags used by core - allows to set various flags on the message; may + * be used for simple inter-module communication or remembering * processing state reached */ unsigned int msg_flags; @@ -345,7 +345,7 @@ inline static int char_msg_val( struct sip_msg *msg, char *cv ) src[2]= msg->callid->body; src[3]= msg->first_line.u.request.uri; src[4]= get_cseq( msg )->number; - + /* topmost Via is part of transaction key as well ! */ src[5]= msg->via1->host; src[6]= msg->via1->port_str; @@ -406,9 +406,9 @@ inline static int get_body(struct sip_msg *msg, str *body) } -/* +/* * Search through already parsed headers (no parsing done) a non-standard - * header - all known headers are skipped! + * header - all known headers are skipped! */ #define get_header_by_static_name(_msg, _name) \ get_header_by_name(_msg, _name, sizeof(_name)-1) diff --git a/parser/parse_allow.c b/parser/parse_allow.c index 8aeb95cead0..fbfe6b8e680 100644 --- a/parser/parse_allow.c +++ b/parser/parse_allow.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -71,7 +71,7 @@ int parse_allow(struct sip_msg *msg) } if (parse_methods(&(hdr->body), &(ab->allow))!=0) { - LM_ERR("bad allow body header\n"); + LM_ERR("bad allow body header\n"); set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, "error parsing ALLOW header"); set_err_reply(400, "bad headers"); diff --git a/parser/parse_allow.h b/parser/parse_allow.h index 89fba8ab880..9c6f3a601a8 100644 --- a/parser/parse_allow.h +++ b/parser/parse_allow.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -30,9 +30,9 @@ #include "../mem/mem.h" #include "msg_parser.h" - -/* - * casting macro for accessing Allow body + +/* + * casting macro for accessing Allow body */ #define get_allow_methods(p_msg) \ (((struct allow_body*)(p_msg)->allow->parsed)->allow_all) diff --git a/parser/parse_authenticate.c b/parser/parse_authenticate.c index 31dc05efbcd..bebbb60087c 100644 --- a/parser/parse_authenticate.c +++ b/parser/parse_authenticate.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -25,7 +25,7 @@ * 2005-01-31 first version (ramona) * 2011-03-07 Initial revision (Ovidiu Sas) */ - + #include #include #include "../dprint.h" @@ -242,7 +242,7 @@ int parse_authenticate_body( str *body, struct authenticate_body *auth) if (val.len==4 && LOWER4B(GET4B(val.s))==0x74727565) /*true*/ { auth->flags |= AUTHENTICATE_STALE; - } else if ( !(val.len==5 && LOWER1B(val.s[4])=='e' && + } else if ( !(val.len==5 && LOWER1B(val.s[4])=='e' && LOWER4B(GET4B(val.s))==0x66616c73) ) { LM_ERR("unsupported stale value \"%.*s\"\n",val.len,val.s); diff --git a/parser/parse_authenticate.h b/parser/parse_authenticate.h index ead39ca79f0..faf0ead1af5 100644 --- a/parser/parse_authenticate.h +++ b/parser/parse_authenticate.h @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Copyright (c) 2011 VoIP Embedded Inc. * * This file is part of opensips, a free SIP server. @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/parse_call_info.c b/parser/parse_call_info.c index 5aac96ed387..45cd7c238b6 100644 --- a/parser/parse_call_info.c +++ b/parser/parse_call_info.c @@ -14,15 +14,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2010-11-09 Initial revision (Ovidiu Sas) */ - + #include "parse_from.h" #include "parse_to.h" #include "parse_call_info.h" @@ -34,7 +34,7 @@ #include "../errinfo.h" #include "../mem/mem.h" - + /* * This method is used to parse Call-Info header. * @@ -50,14 +50,14 @@ int parse_call_info_header( struct sip_msg *msg ) void **parsed; char *tmp, *end, *start; unsigned int len; - + if ( !msg->call_info && (parse_headers(msg, HDR_CALL_INFO_F,0)==-1 || !msg->call_info)) { return -1; } call_info=msg->call_info; - + /* maybe the header is already parsed! */ if (call_info->parsed) return 0; diff --git a/parser/parse_call_info.h b/parser/parse_call_info.h index 5e6b58261d7..c293727c339 100644 --- a/parser/parse_call_info.h +++ b/parser/parse_call_info.h @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Copyright (c) 2010 VoIP Embedded Inc. * * This file is part of opensips, a free SIP server. @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/parse_content.c b/parser/parse_content.c index 06dac4dea8a..09767118f00 100644 --- a/parser/parse_content.c +++ b/parser/parse_content.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -41,7 +41,7 @@ #define is_mime_char(_c_) \ - (isalpha((int)_c_) || (_c_)=='-' || (_c_)=='+' || (_c_)=='.') + (isalnum((int)_c_) || (_c_)=='-' || (_c_)=='+' || (_c_)=='.') #define is_char_equal(_c_,_cs_) \ ( (isalpha((int)_c_)?(((_c_)|0x20)==(_cs_)):((_c_)==(_cs_)))==1 ) @@ -195,7 +195,7 @@ static type_node_t subtype_tree[] = { {'c',SUBTYPE_UNKNOWN,1,-1}, {'.',SUBTYPE_UNKNOWN,1,-1}, {'p',SUBTYPE_UNKNOWN,1,-1}, - {'i',SUBTYPE_UNKNOWN,1,-1}, + {'i',SUBTYPE_UNKNOWN,1,-1}, {'d',SUBTYPE_UNKNOWN,1,-1}, {'f',SUBTYPE_XML_MSRTC_PIDF,0,-1}, {'e',SUBTYPE_UNKNOWN,1,118}, /* 105 */ @@ -243,6 +243,11 @@ char* parse_content_length( char* buffer, char* end, int* length) number = 0; while (p='0' && *p<='9') { number = number*10 + (*p)-'0'; + if (number<0) { + LM_ERR("number overflow at pos %d in len number [%.*s]\n", + (int)(p-buffer),(int)(end-buffer), buffer); + return 0; + } size ++; p++; } @@ -355,11 +360,11 @@ char* decode_mime_type(char *start, char *end, unsigned int *mime_type, content_ if( con == NULL) for(p++; pparams; while(cur) { if( cur->name.len == 8 && !strncasecmp(cur->name.s,"boundary",cur->name.len ) ) con->boundary = cur->body; - + if( cur->name.len == 5 && !strncasecmp(cur->name.s,"start",cur->name.len ) ) con->start = cur->body; @@ -453,7 +458,7 @@ int parse_content_type_hdr( struct sip_msg *msg ) goto parse_error; } - + rez->type = mime; msg->content_type->parsed = rez; return mime; @@ -557,4 +562,4 @@ void free_contenttype(content_t ** con) } *con = 0; } - + diff --git a/parser/parse_content.h b/parser/parse_content.h index 3805b6d59ad..cc527ba5e75 100644 --- a/parser/parse_content.h +++ b/parser/parse_content.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -69,7 +69,7 @@ struct mime_type { /* - * Maximum number of mimes allowed in Accept header + * Maximum number of mimes allowed in Accept header */ #define MAX_MIMES_NR 128 diff --git a/parser/parse_cseq.c b/parser/parse_cseq.c index 4373d712dc0..6a8fe11298b 100644 --- a/parser/parse_cseq.c +++ b/parser/parse_cseq.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * @@ -15,10 +15,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2003-02-28 scratchpad compatibility abandoned (jiri) @@ -40,10 +40,10 @@ char* parse_cseq(char *buf, char* end, struct cseq_body* cb) { char *t, *m, *m_end; - + cb->error=PARSE_ERROR; t=buf; - + cb->number.s=t; t=eat_token_end(t, end); if (t>=end) goto error; @@ -64,15 +64,15 @@ char* parse_cseq(char *buf, char* end, struct cseq_body* cb) cb->method.s=m; t=m_end; cb->method.len=t-cb->method.s; - + /* cache the method id */ if(parse_method(cb->method.s, t, (unsigned int*)&cb->method_id)==0) { LM_ERR("cannot parse the method\n"); goto error; } - - /* there may be trailing LWS + + /* there may be trailing LWS * (it was not my idea to put it in SIP; -jiri ) */ t=eat_lws_end(t, end); diff --git a/parser/parse_cseq.h b/parser/parse_cseq.h index a612765d14a..0631cefa35c 100644 --- a/parser/parse_cseq.h +++ b/parser/parse_cseq.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_def.h b/parser/parse_def.h index ddef175a8ac..47740693711 100644 --- a/parser/parse_def.h +++ b/parser/parse_def.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_disposition.c b/parser/parse_disposition.c index 1bc54a88c51..046bda93e6f 100644 --- a/parser/parse_disposition.c +++ b/parser/parse_disposition.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/parse_disposition.h b/parser/parse_disposition.h index c5a620b84ab..bfcb4d8a1ef 100644 --- a/parser/parse_disposition.h +++ b/parser/parse_disposition.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/parse_diversion.c b/parser/parse_diversion.c index 03ef87c4c0c..25be4a48bb9 100644 --- a/parser/parse_diversion.c +++ b/parser/parse_diversion.c @@ -15,13 +15,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #include -#include +#include #include "../dprint.h" #include "../ut.h" #include "../mem/mem.h" @@ -39,7 +39,7 @@ int parse_diversion_header(struct sip_msg *msg) { struct to_body* diversion_b; - + if (!msg->diversion && (parse_headers(msg, HDR_DIVERSION_F, 0) == -1 || !msg->diversion)) { goto error; @@ -58,7 +58,7 @@ int parse_diversion_header(struct sip_msg *msg) } /* now parse it!! */ - parse_to(msg->diversion->body.s, + parse_to(msg->diversion->body.s, msg->diversion->body.s + msg->diversion->body.len + 1, diversion_b); if (diversion_b->error == PARSE_ERROR) { LM_ERR("bad diversion header\n"); @@ -66,7 +66,7 @@ int parse_diversion_header(struct sip_msg *msg) goto error; } msg->diversion->parsed = diversion_b; - + return 0; error: return -1; diff --git a/parser/parse_diversion.h b/parser/parse_diversion.h index 1b3be5d45c7..78ae42f6073 100644 --- a/parser/parse_diversion.h +++ b/parser/parse_diversion.h @@ -15,21 +15,21 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #ifndef PARSE_DIVERSION_H #define PARSE_DIVERSION_H - + #include "msg_parser.h" - + /* casting macro for accessing Diversion body */ #define get_diversion(p_msg) ((struct to_body*)(p_msg)->diversion->parsed) - - + + /* * Diversion header field parser */ @@ -40,5 +40,5 @@ int parse_diversion_header(struct sip_msg *msg); * Get value of given diversion parameter */ str *diversion_param(struct sip_msg *msg, str name); - + #endif /* PARSE_DIVERSION_H */ diff --git a/parser/parse_event.c b/parser/parse_event.c index 56f5d29a949..c08094aa34b 100644 --- a/parser/parse_event.c +++ b/parser/parse_event.c @@ -21,8 +21,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -110,22 +110,22 @@ int event_parser(char* _s, int _l, event_t* _e) _e->text.len = end - tmp.s; - if ((_e->text.len == PRES_STR_LEN) && + if ((_e->text.len == PRES_STR_LEN) && !strncasecmp(PRES_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_PRESENCE; - } else if ((_e->text.len == PRES_XCAP_DIFF_STR_LEN) && + } else if ((_e->text.len == PRES_XCAP_DIFF_STR_LEN) && !strncasecmp(PRES_XCAP_DIFF_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_XCAP_DIFF; - } else if ((_e->text.len == PRES_WINFO_STR_LEN) && + } else if ((_e->text.len == PRES_WINFO_STR_LEN) && !strncasecmp(PRES_WINFO_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_PRESENCE_WINFO; - } else if ((_e->text.len == PRES_SIP_PROFILE_STR_LEN) && + } else if ((_e->text.len == PRES_SIP_PROFILE_STR_LEN) && !strncasecmp(PRES_SIP_PROFILE_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_SIP_PROFILE; - } else if ((_e->text.len == DIALOG_STR_LEN) && + } else if ((_e->text.len == DIALOG_STR_LEN) && !strncasecmp(DIALOG_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_DIALOG; - } else if ((_e->text.len == MWI_STR_LEN) && + } else if ((_e->text.len == MWI_STR_LEN) && !strncasecmp(MWI_STR, tmp.s, _e->text.len)) { _e->parsed = EVENT_MWI; } else if ((_e->text.len == CALL_INFO_STR_LEN) && @@ -203,11 +203,11 @@ int parse_event(struct hdr_field* _h) void free_event(event_t** _e) { if (*_e) - { + { if((*_e)->params) free_params((*_e)->params); pkg_free(*_e); - } + } *_e = 0; } @@ -219,7 +219,7 @@ void print_event(event_t* _e) { printf("===Event===\n"); printf("text : \'%.*s\'\n", _e->text.len, ZSW(_e->text.s)); - printf("parsed: %s\n", + printf("parsed: %s\n", (_e->parsed == EVENT_PRESENCE) ? ("EVENT_PRESENCE") : ("EVENT_OTHER")); printf("===/Event===\n"); } diff --git a/parser/parse_event.h b/parser/parse_event.h index 2f323ce6900..f08623c94be 100644 --- a/parser/parse_event.h +++ b/parser/parse_event.h @@ -21,8 +21,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_expires.c b/parser/parse_expires.c index a99a7c941e4..a75ce30c9e2 100644 --- a/parser/parse_expires.c +++ b/parser/parse_expires.c @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -82,7 +82,7 @@ int parse_expires(struct hdr_field* _h) LM_ERR("no pkg memory left\n"); return -1; } - + memset(e, 0, sizeof(exp_body_t)); if (expires_parser(_h->body.s, _h->body.len, e) < 0) { @@ -93,7 +93,7 @@ int parse_expires(struct hdr_field* _h) pkg_free(e); return -2; } - + _h->parsed = (void*)e; return 0; } diff --git a/parser/parse_expires.h b/parser/parse_expires.h index 1e6e2627ba4..bbdbc12b923 100644 --- a/parser/parse_expires.h +++ b/parser/parse_expires.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_fline.c b/parser/parse_fline.c index 35599ef02df..25751721a1f 100644 --- a/parser/parse_fline.c +++ b/parser/parse_fline.c @@ -1,8 +1,8 @@ /* * $Id$ - * + * * sip first line parsing automaton - * + * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of opensips, a free SIP server. @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -51,7 +51,7 @@ enum { START, BYE1, BYE2, SIP1, SIP2, SIP3, SIP4, SIP5, SIP6, FIN_INVITE = 100, FIN_ACK, FIN_CANCEL, FIN_BYE, FIN_SIP, - P_METHOD = 200, L_URI, P_URI, L_VER, + P_METHOD = 200, L_URI, P_URI, L_VER, VER1, VER2, VER3, VER4, VER5, VER6, FIN_VER, L_STATUS, P_STATUS, L_REASON, P_REASON, L_LF, F_CR, F_LF @@ -193,7 +193,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) state=P_METHOD; } break; - + case 'i': case 'I': switch(state){ @@ -244,7 +244,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) state=P_METHOD; } break; - + case 'p': case 'P': switch(state){ @@ -293,7 +293,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) } break; - + case '/': switch(state){ case START: @@ -340,7 +340,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) state=P_METHOD; } break; - + case '2': switch(state){ case START: @@ -389,7 +389,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) state=P_METHOD; } break; - + case '.': switch(state){ case START: @@ -436,7 +436,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) state=P_METHOD; } break; - + case '0': switch(state){ case START: @@ -486,7 +486,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) state=P_METHOD; } break; - + case 'n': case 'N': switch(state){ @@ -1055,7 +1055,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) default: state=P_METHOD; } - + default: switch(state){ case START: @@ -1104,7 +1104,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) /* fl->u.reply.statusclass=stat/100; */ } return tmp; - + error: LM_ERR("while parsing first line (state=%d)\n", state); fl->type=SIP_INVALID; @@ -1117,7 +1117,7 @@ char* parse_fline(char* buffer, char* end, struct msg_start* fl) also modifies buffer (to avoid extra copy ops) */ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) { - + char *tmp; char* second; char* third; @@ -1134,7 +1134,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) response = version SP status SP reason CRLF (version = "SIP/2.0") */ - + end=buffer+len; /* see if it's a reply (status) */ @@ -1143,7 +1143,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) /* drop messages which are so short they are for sure useless; utilize knowledge of minimum size in parsing the first - token + token */ if (len <=16 ) { LM_INFO("message too short: %d\n", len); @@ -1152,7 +1152,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) tmp=buffer; /* is it perhaps a reply, ie does it start with "SIP...." ? */ - if ( (*tmp=='S' || *tmp=='s') && + if ( (*tmp=='S' || *tmp=='s') && strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 && (*(tmp+SIP_VERSION_LEN)==' ')) { fl->type=SIP_REPLY; @@ -1161,7 +1161,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) } else IFISMETHOD( INVITE, 'I' ) else IFISMETHOD( CANCEL, 'C') else IFISMETHOD( ACK, 'A' ) - else IFISMETHOD( BYE, 'B' ) + else IFISMETHOD( BYE, 'B' ) else IFISMETHOD( INFO, 'I' ) /* if you want to add another method XXX, include METHOD_XXX in H-file (this is the value which you will take later in @@ -1170,7 +1170,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) latter; everything must be capitals */ else { - /* neither reply, nor any of known method requests, + /* neither reply, nor any of known method requests, let's believe it is an unknown method request */ tmp=eat_token_end(buffer,buffer+len); @@ -1193,9 +1193,9 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) } fl->u.request.method.len=tmp-buffer; } - - /* identifying type of message over now; + + /* identifying type of message over now; tmp points at space after; go ahead */ fl->u.request.method.s=buffer; /* store ptr to first token */ @@ -1203,7 +1203,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) offset=second-buffer; /* EoJku */ - + /* next element */ tmp=eat_token_end(second, second+len-offset); if (tmp>=end){ @@ -1226,7 +1226,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) goto error; } s1=*second; s2=*(second+1);s3=*(second+2); - if (s1>='0' && s1<='9' && + if (s1>='0' && s1<='9' && s2>='0' && s2<='9' && s3>='0' && s3<='9' ) { fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0'); @@ -1251,7 +1251,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) goto error; } }else{ - tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line + tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line ('\n' or '\r') */ if (tmp>=end){ /* no crlf in packet => invalid */ goto error; diff --git a/parser/parse_fline.h b/parser/parse_fline.h index bf6d71ab327..c3eb5fc6edc 100644 --- a/parser/parse_fline.h +++ b/parser/parse_fline.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_from.c b/parser/parse_from.c index 5a8fc1d8ce6..b080be66d66 100644 --- a/parser/parse_from.c +++ b/parser/parse_from.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -38,7 +38,7 @@ /* * This method is used to parse the from header. It was decided not to parse - * anything in core that is not *needed* so this method gets called by + * anything in core that is not *needed* so this method gets called by * rad_acc module and any other modules that needs the FROM header. * * params: msg : sip msg @@ -97,7 +97,7 @@ int parse_from_header( struct sip_msg *msg) struct sip_uri *parse_from_uri(struct sip_msg *msg) { struct to_body *tb = NULL; - + if(msg==NULL) return NULL; @@ -106,7 +106,7 @@ struct sip_uri *parse_from_uri(struct sip_msg *msg) LM_ERR("cannot parse FROM header\n"); return NULL; } - + if(msg->from==NULL || get_from(msg)==NULL) return NULL; diff --git a/parser/parse_from.h b/parser/parse_from.h index 1b0f991a0cf..1a50c1d6acd 100644 --- a/parser/parse_from.h +++ b/parser/parse_from.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_hname2.c b/parser/parse_hname2.c index d4f7efcdb23..eb0e7c55263 100644 --- a/parser/parse_hname2.c +++ b/parser/parse_hname2.c @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Fast 32-bit Header Field Name Parser * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -48,7 +48,7 @@ static inline char* skip_ws(char* p, char *end) } return p; } - + /* * Parser macros */ @@ -168,13 +168,13 @@ char* parse_hname2(char* begin, char* end, struct hdr_field* hdr) switch(LOWER_BYTE(*(p + 1))) { case 'o': p += 2; - hdr->type = HDR_TO_T; + hdr->type = HDR_TO_T; hdr->name.len = 2; goto dc_cont; case ' ': case '\t': p += 2; - hdr->type = HDR_TO_T; + hdr->type = HDR_TO_T; hdr->name.len = 1; goto dc_end; case ':': diff --git a/parser/parse_hname2.h b/parser/parse_hname2.h index 32c7442dc03..ce42f6dc360 100644 --- a/parser/parse_hname2.h +++ b/parser/parse_hname2.h @@ -1,5 +1,5 @@ -/* - * $Id$ +/* + * $Id$ * * Fast 32-bit Header Field Name Parser * @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_methods.c b/parser/parse_methods.c index 247d14cf297..25527a0b361 100644 --- a/parser/parse_methods.c +++ b/parser/parse_methods.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -46,8 +46,8 @@ static inline int method_char(char _c) || (_c == '-') || (_c == '.') || (_c == '%') || (_c == '*') || (_c == '_') || (_c == '+') || (_c == '~') || (_c == '+'); } - - + + /* * Parse a method pointed by start, end is the last character to check (if NULL * assume that start is a zero terminated string) @@ -59,7 +59,7 @@ char* parse_method(char* start, char* end, unsigned int* method) { int len=0; int max=0; - + if (!start || !method) { LM_ERR("invalid parameter value\n"); return NULL; @@ -88,7 +88,7 @@ char* parse_method(char* start, char* end, unsigned int* method) case 'b': if(end && max<3) goto unknown; - + if ((start[1]=='y' || start[1]=='Y') && (start[2]=='e' || start[2]=='E')) { @@ -120,7 +120,7 @@ char* parse_method(char* start, char* end, unsigned int* method) goto unknown; if(start[1]=='n' && start[1]=='N') goto unknown; - + if ((start[2]=='f' || start[2]=='F') && (start[3]=='o' || start[3]=='O')) { @@ -128,7 +128,7 @@ char* parse_method(char* start, char* end, unsigned int* method) len = 4; goto done; } - + if(end && max<6) goto unknown; if ((start[2]=='v' || start[2]=='V') @@ -204,10 +204,10 @@ char* parse_method(char* start, char* end, unsigned int* method) len = 5; goto done; } - + if(end && max<7) goto unknown; - + if ((start[1]=='u' || start[1]=='U') && (start[2]=='b' || start[2]=='B') && (start[3]=='l' || start[3]=='L') @@ -227,7 +227,7 @@ char* parse_method(char* start, char* end, unsigned int* method) goto unknown; if(start[1]!='e' && start[1]!='E') goto unknown; - + if((start[2]=='f' || start[2]=='F') && (start[3]=='e' || start[3]=='E') && (start[4]=='R' || start[4]=='R')) @@ -239,7 +239,7 @@ char* parse_method(char* start, char* end, unsigned int* method) if(end && max<8) goto unknown; - + if ((start[2]=='g' || start[2]=='G') && (start[3]=='i' || start[3]=='I') && (start[4]=='s' || start[4]=='S') @@ -290,7 +290,7 @@ char* parse_method(char* start, char* end, unsigned int* method) default: goto unknown; } - + done: if(!end || (end && len < max)) { @@ -298,7 +298,7 @@ char* parse_method(char* start, char* end, unsigned int* method) && start[len]!='\t' && start[len]!='\r' && start[len]!='\n') goto unknown; } - + return (start+len); unknown: @@ -312,18 +312,18 @@ char* parse_method(char* start, char* end, unsigned int* method) || start[len]=='\t' || start[len]=='\r' || start[len]=='\n')) return (start+len); - + if(!method_char(start[len])) { LM_ERR("invalid character %c\n", start[len]); return NULL; } - + len++; } return end; } - + while(start[len]!='\0' && start[len]!=',' && start[len]!=' ' && start[len]!='\t' && start[len]!='\r' && start[len]!='\n') { @@ -337,9 +337,9 @@ char* parse_method(char* start, char* end, unsigned int* method) return (start+len); } - - -/* + + +/* * Parse comma separated list of methods pointed by _body and assign their * enum bits to _methods. Returns 0 on success and -1 on failure. */ @@ -367,7 +367,7 @@ int parse_methods(str* _body, unsigned int* _methods) method = 0; p = next.s; - + while (p=next.s+next.len || *p == '\0') goto done; - - + + if (*p == ',') { p++; diff --git a/parser/parse_methods.h b/parser/parse_methods.h index ec633ba0644..e6f3abe6f00 100644 --- a/parser/parse_methods.h +++ b/parser/parse_methods.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -27,7 +27,7 @@ #define ALL_METHODS (0xFFFFFFFF) -/* +/* * Parse comma separated list of methods pointed by _body and assign their * enum bits to _methods. Returns 1 on success and 0 on failure. */ diff --git a/parser/parse_min_expires.c b/parser/parse_min_expires.c index daaaadbd419..98e7dfc3af7 100644 --- a/parser/parse_min_expires.c +++ b/parser/parse_min_expires.c @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Copyright (c) 2011 VoIP Embedded, Inc. * * This file is part of opensips, a free SIP server. @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/parse_min_expires.h b/parser/parse_min_expires.h index ab5a3e7aa79..07453a7089f 100644 --- a/parser/parse_min_expires.h +++ b/parser/parse_min_expires.h @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Copyright (c) 2011 VoIP Embedded, Inc. * * This file is part of opensips, a free SIP server. @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/parse_multipart.c b/parser/parse_multipart.c index 02c9420ed6a..20488ce9c9b 100644 --- a/parser/parse_multipart.c +++ b/parser/parse_multipart.c @@ -2,7 +2,7 @@ * $Id$ * * Copyright (C) 2009 Voice Sistem SRL - * + * * This file is part of opensips, a free SIP server. * * opensips is free software; you can redistribute it and/or modify @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -267,7 +267,7 @@ void free_multi_body(struct multi_body * multi) struct part * p, *tmp; p = multi->first; - + while(p) { diff --git a/parser/parse_multipart.h b/parser/parse_multipart.h index 7b8e5c9b2ea..c03b1ccf99f 100644 --- a/parser/parse_multipart.h +++ b/parser/parse_multipart.h @@ -2,7 +2,7 @@ * $Id$ * * Copyright (C) 2009 Voice Sistem SRL - * + * * This file is part of opensips, a free SIP server. * * opensips is free software; you can redistribute it and/or modify @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/parser/parse_nameaddr.c b/parser/parse_nameaddr.c index 6121ce5bab8..942bff18756 100644 --- a/parser/parse_nameaddr.c +++ b/parser/parse_nameaddr.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -47,7 +47,7 @@ int parse_nameaddr(str* _s, name_addr_t* _a) _a->name.s = _s->s; - _a->uri.s = find_not_quoted(_s, '<'); + _a->uri.s = find_not_quoted(_s, '<'); if (_a->uri.s) { _a->name.len = _a->uri.s - _a->name.s; _a->uri.s++; /* We will skip < character */ @@ -55,10 +55,10 @@ int parse_nameaddr(str* _s, name_addr_t* _a) LM_ERR("no < found\n"); return -3; } - + _a->uri.len = _s->len - _a->name.len - 1; uri_end = find_not_quoted(&_a->uri, '>'); - + if (!uri_end) { LM_ERR("no > found\n"); return -4; @@ -66,7 +66,7 @@ int parse_nameaddr(str* _s, name_addr_t* _a) /* Total length of the field including <> */ _a->len = uri_end - _a->name.s + 1; - + _a->uri.len = uri_end - _a->uri.s; return 0; } diff --git a/parser/parse_nameaddr.h b/parser/parse_nameaddr.h index af55e4cfa9b..3d169b0887c 100644 --- a/parser/parse_nameaddr.h +++ b/parser/parse_nameaddr.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History diff --git a/parser/parse_pai.c b/parser/parse_pai.c index f9530ca221a..f84f009038a 100644 --- a/parser/parse_pai.c +++ b/parser/parse_pai.c @@ -14,11 +14,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #include "parse_from.h" #include "parse_to.h" #include @@ -29,7 +29,7 @@ #include "../errinfo.h" #include "../mem/mem.h" - + /* * This method is used to parse P-Asserted-Identity header (RFC 3325). * @@ -43,16 +43,16 @@ int parse_pai_header( struct sip_msg *msg ) { struct to_body* pai_b; - + if ( !msg->pai && (parse_headers(msg, HDR_PAI_F,0)==-1 || !msg->pai)) { goto error; } - + /* maybe the header is already parsed! */ if (msg->pai->parsed) return 0; - + /* bad luck! :-( - we have to parse it */ /* first, get some memory */ pai_b = pkg_malloc(sizeof(struct to_body)); @@ -60,7 +60,7 @@ int parse_pai_header( struct sip_msg *msg ) LM_ERR("out of pkg_memory\n"); goto error; } - + /* now parse it!! */ parse_to(msg->pai->body.s, msg->pai->body.s + msg->pai->body.len+1, @@ -74,7 +74,7 @@ int parse_pai_header( struct sip_msg *msg ) goto error; } msg->pai->parsed = pai_b; - + return 0; error: return -1; diff --git a/parser/parse_pai.h b/parser/parse_pai.h index 3d4ec40ffdb..4e64044da18 100644 --- a/parser/parse_pai.h +++ b/parser/parse_pai.h @@ -14,19 +14,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - - + + #ifndef PARSE_PAI_H #define PARSE_PAI_H - + #include "msg_parser.h" - - + + /* casting macro for accessing P-Asserted-Identity body */ #define get_pai(p_msg) ((struct to_body*)(p_msg)->pai->parsed) @@ -35,5 +35,5 @@ * P-Asserted-Identity header field parser */ int parse_pai_header( struct sip_msg *msg); - + #endif /* PARSE_PAI_H */ diff --git a/parser/parse_param.c b/parser/parse_param.c index bb13b460889..77dcb320740 100644 --- a/parser/parse_param.c +++ b/parser/parse_param.c @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Generic Parameter Parser @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -57,7 +57,7 @@ static inline void parse_contact_class(param_hooks_t* _h, param_t* _p) _h->contact.q = _p; } break; - + case 'e': case 'E': if ((_p->name.len == 7) && @@ -66,7 +66,7 @@ static inline void parse_contact_class(param_hooks_t* _h, param_t* _p) _h->contact.expires = _p; } break; - + case 'm': case 'M': if ((_p->name.len == 7) && @@ -75,7 +75,7 @@ static inline void parse_contact_class(param_hooks_t* _h, param_t* _p) _h->contact.methods = _p; } break; - + case 'r': case 'R': if ((_p->name.len == 8) && @@ -146,7 +146,7 @@ static inline void parse_uri_class(param_hooks_t* _h, param_t* _p) _h->uri.maddr = _p; } break; - + case 'd': case 'D': if ((_p->name.len == 5) && @@ -303,7 +303,7 @@ static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, par out: _p->name.len = _s->s - _p->name.s; - + switch(_c) { case CLASS_CONTACT: parse_contact_class(_h, _p); break; case CLASS_URI: parse_uri_class(_h, _p); break; @@ -378,12 +378,12 @@ int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p) parse_param_name(_s, _c, _h, t); trim_leading(_s); - + if (_s->len == 0) { /* The last parameter without body */ t->len = t->name.len; goto ok; } - + if (_s->s[0] == '=') { _s->s++; _s->len--; @@ -420,7 +420,7 @@ int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p) _s->s++; _s->len--; trim_leading(_s); - + if (_s->len == 0) { LM_ERR("param name missing after ;\n"); goto error; @@ -449,13 +449,13 @@ int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p) static inline void do_free_params(param_t* _p, int _shm) { param_t* ptr; - + while(_p) { ptr = _p; _p = _p->next; if (_shm) shm_free(ptr); else pkg_free(ptr); - } + } } @@ -485,7 +485,7 @@ static inline void print_param(FILE* _o, param_t* _p) char* type; fprintf(_o, "---param(%p)---\n", _p); - + switch(_p->type) { case P_OTHER: type = "P_OTHER"; break; case P_Q: type = "P_Q"; break; @@ -501,7 +501,7 @@ static inline void print_param(FILE* _o, param_t* _p) case P_DSTPORT: type = "P_DSTPORT"; break; default: type = "UNKNOWN"; break; } - + fprintf(_o, "type: %s\n", type); fprintf(_o, "name: \'%.*s\'\n", _p->name.len, _p->name.s); fprintf(_o, "body: \'%.*s\'\n", _p->body.len, _p->body.s); @@ -516,7 +516,7 @@ static inline void print_param(FILE* _o, param_t* _p) void print_params(FILE* _o, param_t* _p) { param_t* ptr; - + ptr = _p; while(ptr) { print_param(_o, ptr); @@ -536,7 +536,7 @@ static inline int do_duplicate_params(param_t** _n, param_t* _p, int _shm) LM_ERR("invalid parameter value\n"); return -1; } - + last = 0; *_n = 0; ptr = _p; diff --git a/parser/parse_param.h b/parser/parse_param.h index 465ee56913e..7dc4a54bbfd 100644 --- a/parser/parse_param.h +++ b/parser/parse_param.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Generic Parameter Parser @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/parse_ppi.c b/parser/parse_ppi.c index c00449316e8..095e30bc0dd 100644 --- a/parser/parse_ppi.c +++ b/parser/parse_ppi.c @@ -14,11 +14,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #include "parse_ppi.h" #include "parse_to.h" #include "parse_uri.h" @@ -30,7 +30,7 @@ #include "../errinfo.h" #include "../mem/mem.h" - + /* * This method is used to parse P-Preferred-Identity header (RFC 3325). * @@ -44,16 +44,16 @@ int parse_ppi_header( struct sip_msg *msg ) { struct to_body* ppi_b; - + if ( !msg->ppi && (parse_headers(msg, HDR_PPI_F,0)==-1 || !msg->ppi)) { goto error; } - + /* maybe the header is already parsed! */ if (msg->ppi->parsed) return 0; - + /* bad luck! :-( - we have to parse it */ /* first, get some memory */ ppi_b = pkg_malloc(sizeof(struct to_body)); @@ -61,7 +61,7 @@ int parse_ppi_header( struct sip_msg *msg ) LM_ERR("out of pkg_memory\n"); goto error; } - + /* now parse it!! */ parse_to(msg->ppi->body.s, msg->ppi->body.s + msg->ppi->body.len+1, @@ -75,7 +75,7 @@ int parse_ppi_header( struct sip_msg *msg ) goto error; } msg->ppi->parsed = ppi_b; - + return 0; error: return -1; @@ -88,7 +88,7 @@ int parse_ppi_header( struct sip_msg *msg ) struct sip_uri *parse_ppi_uri(struct sip_msg *msg) { struct to_body *tb = NULL; - + if(msg==NULL) return NULL; @@ -97,7 +97,7 @@ struct sip_uri *parse_ppi_uri(struct sip_msg *msg) LM_ERR("cannot parse P-P-I header\n"); return NULL; } - + if(msg->ppi==NULL || get_ppi(msg)==NULL) return NULL; diff --git a/parser/parse_ppi.h b/parser/parse_ppi.h index 5dc32533dee..8b3cb1d8e5d 100644 --- a/parser/parse_ppi.h +++ b/parser/parse_ppi.h @@ -14,19 +14,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - - + + #ifndef PARSE_PPI_H #define PARSE_PPI_H - + #include "msg_parser.h" - - + + /* casting macro for accessing P-Preferred-Identity body */ #define get_ppi(p_msg) ((struct to_body*)(p_msg)->ppi->parsed) @@ -37,5 +37,5 @@ int parse_ppi_header( struct sip_msg *msg); struct sip_uri *parse_ppi_uri(struct sip_msg *msg); - + #endif /* PARSE_PPI_H */ diff --git a/parser/parse_privacy.c b/parser/parse_privacy.c index 7bfa4245d1e..c02a6b52e29 100644 --- a/parser/parse_privacy.c +++ b/parser/parse_privacy.c @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -32,7 +32,7 @@ #include "parse_privacy.h" #include "msg_parser.h" - + /* * Parse a privacy value pointed by start that can be at most max_len long. * Returns length of matched privacy value or NULL otherwise. @@ -137,7 +137,7 @@ unsigned int parse_priv_value(char* start, unsigned int max_len, && start[len] != '\t' && start[len] != '\r' && start[len] != '\n') return 0; } - + return len; } @@ -146,7 +146,7 @@ unsigned int parse_priv_value(char* start, unsigned int max_len, * This method is used to parse Privacy HF body, which consist of * comma separated list of priv-values. After parsing, msg->privacy->parsed * contains enum bits of privacy values defined in parse_privacy.h. - * Returns 0 on success and -1 on failure. + * Returns 0 on success and -1 on failure. */ int parse_privacy(struct sip_msg *msg) { diff --git a/parser/parse_privacy.h b/parser/parse_privacy.h index 01997e3cb24..82518b9bcbb 100644 --- a/parser/parse_privacy.h +++ b/parser/parse_privacy.h @@ -14,8 +14,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -40,8 +40,8 @@ enum privacy_value { PRIVACY_HISTORY=64 }; - -/* + +/* * casting macro for accessing enumeration of priv-values */ #define get_privacy_values(p_msg) \ diff --git a/parser/parse_refer_to.c b/parser/parse_refer_to.c index 780787643c4..2b52be6825b 100644 --- a/parser/parse_refer_to.c +++ b/parser/parse_refer_to.c @@ -14,11 +14,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #include #include #include "../dprint.h" @@ -29,7 +29,7 @@ #include "parse_from.h" #include "parse_to.h" - + /* * This method is used to parse Refer-To header. * @@ -40,7 +40,7 @@ int parse_refer_to_header( struct sip_msg *msg ) { struct to_body* refer_to_b; - + if ( !msg->refer_to && (parse_headers(msg, HDR_REFER_TO_F,0)==-1 || !msg->refer_to)) { goto error; diff --git a/parser/parse_refer_to.h b/parser/parse_refer_to.h index 299c0fc7954..b25c7e11091 100644 --- a/parser/parse_refer_to.h +++ b/parser/parse_refer_to.h @@ -15,19 +15,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - - + + #ifndef PARSE_REFER_TO_H #define PARSE_REFER_TO_H - + #include "msg_parser.h" - - + + /* casting macro for accessing Refer-To body */ #define get_refer_to(p_msg) ((struct to_body*)(p_msg)->refer_to->parsed) @@ -36,5 +36,5 @@ * Refer-To header field parser */ int parse_refer_to_header( struct sip_msg *msg); - + #endif /* PARSE_REFER_TO_H */ diff --git a/parser/parse_replaces.c b/parser/parse_replaces.c index 8f81909ac94..7f9fc52b519 100644 --- a/parser/parse_replaces.c +++ b/parser/parse_replaces.c @@ -15,15 +15,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2011-06-28 initial implementation (Ovidiu Sas) */ - + #include #include #include "../dprint.h" @@ -31,7 +31,7 @@ #include "../errinfo.h" #include "../mem/mem.h" #include "parse_replaces.h" - + /* * This method is used to parse Replaces header body. * @@ -243,7 +243,7 @@ int parse_replaces_body(char* buf, int buf_len, struct replaces_body* replaces_b state = VAL_P; } break; - + /* from-tag param */ param_switch(FT_F, 'r', 'R', FT_R); param_switch(FT_R, 'o', 'O', FT_O); diff --git a/parser/parse_replaces.h b/parser/parse_replaces.h index 25e69e7cc47..2767f3f13b7 100644 --- a/parser/parse_replaces.h +++ b/parser/parse_replaces.h @@ -15,19 +15,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2011-06-28 initial implementation (Ovidiu Sas) */ - - + + #ifndef PARSE_REPLACES_H #define PARSE_REPLACES_H - + #include "msg_parser.h" /* rfc3891: The SIP "Replaces" Header */ @@ -42,13 +42,13 @@ struct replaces_body{ }; - + int parse_replaces_body(char* buf, int buf_len, struct replaces_body* replaces_b); - + ///* casting macro for accessing Replace body */ //#define get_replaces(p_msg) ((struct to_body*)(p_msg)->refer_to->parsed) // ///* Replace header field parser */ //int parse_replaces_header( struct sip_msg *msg); - + #endif /* PARSE_REPLACES_H */ diff --git a/parser/parse_rpid.c b/parser/parse_rpid.c index ece276ab689..b9a7e21e43b 100644 --- a/parser/parse_rpid.c +++ b/parser/parse_rpid.c @@ -1,7 +1,7 @@ /* $Id$ * * Copyright (C) 2001-2003 Juha Heinanen - * + * * This file is part of opensips, a free SIP server. * * opensips is free software; you can redistribute it and/or modify @@ -14,12 +14,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - + #include "parse_from.h" #include "parse_to.h" #include @@ -30,7 +30,7 @@ #include "../errinfo.h" #include "../mem/mem.h" - + /* * This method is used to parse RPID header. * @@ -41,7 +41,7 @@ int parse_rpid_header( struct sip_msg *msg ) { struct to_body* rpid_b; - + if ( !msg->rpid && (parse_headers(msg, HDR_RPID_F, 0)==-1 || !msg->rpid)) { goto error; } diff --git a/parser/parse_rpid.h b/parser/parse_rpid.h index d297e024e5e..853f18cf078 100644 --- a/parser/parse_rpid.h +++ b/parser/parse_rpid.h @@ -1,6 +1,6 @@ /* * $Id$ - * + * * Copyright (C) 2001-2003 Juha Heinanen * * This file is part of opensips, a free SIP server. @@ -15,19 +15,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - - + + #ifndef PARSE_RPID_H #define PARSE_RPID_H - + #include "msg_parser.h" - - + + /* casting macro for accessing RPID body */ #define get_rpid(p_msg) ((struct to_body*)(p_msg)->rpid->parsed) @@ -36,5 +36,5 @@ * RPID header field parser */ int parse_rpid_header( struct sip_msg *msg); - + #endif /* PARSE_RPID_H */ diff --git a/parser/parse_rr.c b/parser/parse_rr.c index 57be89fba71..192479a2f10 100644 --- a/parser/parse_rr.c +++ b/parser/parse_rr.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -68,7 +68,7 @@ static inline int do_parse_rr_body(char *buf, int len, rr_t **head) goto error; } memset(r, 0, sizeof(rr_t)); - + /* Parse name-addr part of the header */ if (parse_nameaddr(&s, &r->nameaddr) < 0) { LM_ERR("failed to parse name-addr\n"); @@ -83,12 +83,12 @@ static inline int do_parse_rr_body(char *buf, int len, rr_t **head) trim_leading(&s); /* Skip any white-chars */ if (s.len == 0) goto ok; /* Nothing left, finish */ - + if (s.s[0] == ';') { /* Route parameter found */ s.s++; s.len--; trim_leading(&s); - + if (s.len == 0) { LM_ERR("failed to parse params\n"); goto parse_error; @@ -113,7 +113,7 @@ static inline int do_parse_rr_body(char *buf, int len, rr_t **head) LM_ERR("invalid character '%c', comma expected\n", s.s[0]); goto parse_error; } - + /* Next character is comma or end of header*/ s.s++; s.len--; @@ -252,12 +252,12 @@ static inline void xlate_pointers(rr_t* _orig, rr_t* _r) { param_t* ptr; _r->nameaddr.uri.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, _r->nameaddr.uri.s); - + ptr = _r->params; while(ptr) { /* if (ptr->type == P_R2) _r->r2 = ptr; */ ptr->name.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->name.s); - ptr->body.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->body.s); + ptr->body.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->body.s); ptr = ptr->next; } } @@ -375,9 +375,9 @@ int print_rr_body(struct hdr_field *iroute, str *oroute, int order, route_len= 0; memset(route, 0, MAX_RR_HDRS*sizeof(str)); - while (iroute!=NULL) + while (iroute!=NULL) { - if (parse_rr(iroute) < 0) + if (parse_rr(iroute) < 0) { LM_ERR("failed to parse RR\n"); goto error; @@ -402,18 +402,18 @@ int print_rr_body(struct hdr_field *iroute, str *oroute, int order, } for(i=0;i=*nb_recs)) || (order && (i<=(n-*nb_recs)) )) ) ) { route_len+= route[i].len; nr++; } - + } if(nb_recs) LM_DBG("skipping %i route records\n", *nb_recs); - + route_len += --nr; /* for commas */ oroute->s=(char*)pkg_malloc(route_len); @@ -437,9 +437,9 @@ int print_rr_body(struct hdr_field *iroute, str *oroute, int order, *(cp++) = ','; } } else { - + i = (nb_recs == NULL) ? n-1 : (n-*nb_recs-1); - + while (i>=0) { memcpy(cp, route[i].s, route[i].len); @@ -453,7 +453,7 @@ int print_rr_body(struct hdr_field *iroute, str *oroute, int order, LM_DBG("out rr [%.*s]\n", oroute->len, oroute->s); LM_DBG("we have %i records\n", n); if(nb_recs != NULL) - *nb_recs = (unsigned int)n; + *nb_recs = (unsigned int)n; return 0; @@ -464,7 +464,7 @@ int print_rr_body(struct hdr_field *iroute, str *oroute, int order, /* - * Path must be available. Function returns the first uri + * Path must be available. Function returns the first uri * from Path without any duplication. */ int get_path_dst_uri(str *_p, str *_dst) diff --git a/parser/parse_rr.h b/parser/parse_rr.h index 1103ea714db..3b1eb6bacb9 100644 --- a/parser/parse_rr.h +++ b/parser/parse_rr.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -97,7 +97,7 @@ int print_rr_body(struct hdr_field *iroute, str *oroute, int order, unsigned int * nb_recs); /* - * Function returns the first uri + * Function returns the first uri * from Path without any duplication. */ int get_path_dst_uri(str *_p, str *_dst); diff --git a/parser/parse_sipifmatch.c b/parser/parse_sipifmatch.c index 87d08566bfe..d9b44da7497 100644 --- a/parser/parse_sipifmatch.c +++ b/parser/parse_sipifmatch.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_sipifmatch.h b/parser/parse_sipifmatch.h index 1639bb21c1d..0b5d6d32eb6 100644 --- a/parser/parse_sipifmatch.h +++ b/parser/parse_sipifmatch.h @@ -1,8 +1,8 @@ /* * $Id$ - * + * * Copyright (C) 2001-2003 FhG FOKUS - * + * * This file is part of opensips, a free SIP server. * * opensips is free software; you can redistribute it and/or modify @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/parser/parse_sst.c b/parser/parse_sst.c index 8e1f912abb6..f5b11d7cd2b 100644 --- a/parser/parse_sst.c +++ b/parser/parse_sst.c @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Copyright (c) 2006 SOMA Networks, Inc. * * This file is part of opensips, a free SIP server. @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -130,7 +130,7 @@ parse_session_expires_body( struct hdr_field *hf ) } } else /* not "esher=" */ { - /* there are no other se-params + /* there are no other se-params that start with "refr" */ for ( ; pos < len && *p != ';'; ++pos, ++p ) /*skip to ';'*/; diff --git a/parser/parse_sst.h b/parser/parse_sst.h index 8faf4b67871..5a04a6bd94d 100644 --- a/parser/parse_sst.h +++ b/parser/parse_sst.h @@ -1,6 +1,6 @@ -/* +/* * $Id$ - * + * * Copyright (c) 2006 SOMA Networks, Inc. * * This file is part of opensips, a free SIP server. @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/parser/parse_supported.c b/parser/parse_supported.c index 8a6e39613c1..8a6f1da3404 100644 --- a/parser/parse_supported.c +++ b/parser/parse_supported.c @@ -97,7 +97,7 @@ static inline int parse_supported_body(str *body, unsigned int *sup) } else goto default_label; break; - + /* "eventlist" */ case _even_: if ( pos+9 <= len && LOWER_DWORD(READ(p+4))==_tlis_ && LOWER_BYTE(*(p+8))=='t' @@ -117,7 +117,7 @@ static inline int parse_supported_body(str *body, unsigned int *sup) break; } } - + return 0; } @@ -159,7 +159,7 @@ int parse_supported( struct sip_msg *msg) supported |= sb->supported; } - ((struct supported_body*)msg->supported->parsed)->supported_all = + ((struct supported_body*)msg->supported->parsed)->supported_all = supported; return 0; } diff --git a/parser/parse_supported.h b/parser/parse_supported.h index 98f3fb2a4cf..27f27f09f80 100644 --- a/parser/parse_supported.h +++ b/parser/parse_supported.h @@ -24,7 +24,7 @@ * * History: * ------- - * 2006-03-02 parse_supported() parses and cumulates all SUPPORTED + * 2006-03-02 parse_supported() parses and cumulates all SUPPORTED * headers (bogdan) */ @@ -64,7 +64,7 @@ struct supported_body { unsigned int supported; /* supported mask for the current hdr */ unsigned int supported_all; /* suppoted mask for the all "supported" hdr - * - it's set only for the first hdr in + * - it's set only for the first hdr in * sibling list*/ }; diff --git a/parser/parse_to.c b/parser/parse_to.c index 8c6ee949e0e..a02e49424ba 100644 --- a/parser/parse_to.c +++ b/parser/parse_to.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -773,3 +773,43 @@ struct sip_uri *parse_to_uri(struct sip_msg *msg) return &tb->parsed_uri; } + +int parse_to_header( struct sip_msg *msg) +{ + struct to_body* to_b; + + if ( !msg->to && ( parse_headers(msg,HDR_TO_F,0)==-1 || !msg->to)) { + LM_ERR("bad msg or missing To header\n"); + goto error; + } + + /* maybe the header is already parsed! */ + if (msg->to->parsed) + return 0; + + /* bad luck! :-( - we have to parse it */ + /* first, get some memory */ + to_b = pkg_malloc(sizeof(struct to_body)); + if (to_b == 0) { + LM_ERR("out of pkg_memory\n"); + goto error; + } + + /* now parse it!! */ + memset(to_b, 0, sizeof(struct to_body)); + parse_to(msg->to->body.s,msg->to->body.s+msg->to->body.len+1,to_b); + if (to_b->error == PARSE_ERROR) { + LM_ERR("bad to header\n"); + pkg_free(to_b); + set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, + "error parsing too header"); + set_err_reply(400, "bad header"); + goto error; + } + + msg->to->parsed = to_b; + + return 0; +error: + return -1; +} diff --git a/parser/parse_to.h b/parser/parse_to.h index 1b9262f7882..c43177d0527 100644 --- a/parser/parse_to.h +++ b/parser/parse_to.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -60,6 +60,8 @@ struct to_body{ */ char* parse_to(char* buffer, char *end, struct to_body *to_b); +int parse_to_header( struct sip_msg *msg); + struct sip_uri *parse_to_uri(struct sip_msg *msg); void free_to(struct to_body* tb); diff --git a/parser/parse_uri.c b/parser/parse_uri.c index 5d63e7ee9f4..4374ec3ae1c 100644 --- a/parser/parse_uri.c +++ b/parser/parse_uri.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -153,13 +153,13 @@ int parse_uri_headers(str headers, str h_name[], str h_val[], int h_size) /* buf= pointer to begining of uri (sip:x@foo.bar:5060;a=b?h=i) * len= len of uri - * returns: fills uri & returns <0 on error or 0 if ok + * returns: fills uri & returns <0 on error or 0 if ok */ int parse_uri(char* buf, int len, struct sip_uri* uri) { enum states { URI_INIT, URI_USER, URI_PASSWORD, URI_PASSWORD_ALPHA, URI_HOST, URI_HOST_P, - URI_HOST6_P, URI_HOST6_END, URI_PORT, + URI_HOST6_P, URI_HOST6_END, URI_PORT, URI_PARAM, URI_PARAM_P, URI_PARAM_VAL_P, URI_VAL_P, URI_HEADERS, /* param states */ /* transport */ @@ -179,7 +179,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) PG_G, PG_G_FIN, PG_eq, /* r2 */ PR2_R, PR2_2_FIN, PR2_eq, - + /* transport values */ /* udp */ VU_U, VU_D, VU_P_FIN, @@ -209,16 +209,19 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) #ifdef EXTRA_DEBUG int i; #endif - -#define SIP_SCH 0x3a706973 -#define SIPS_SCH 0x73706973 -#define TEL_SCH 0x3a6c6574 - + +#define SIP_SCH 0x3a706973 +#define SIPS_SCH 0x73706973 +#define TEL_SCH 0x3a6c6574 +#define URN_SERVICE_SCH 0x3a6e7275 +#define URN_SERVICE_STR ":service:" +#define URN_SERVICE_STR_LEN (sizeof(URN_SERVICE_STR) - 1) + #define case_port( ch, var) \ case ch: \ (var)=(var)*10+ch-'0'; \ break - + #define still_at_user \ if (found_user==0){ \ user.s=uri->host.s; \ @@ -241,7 +244,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) found_user=1;\ error_headers=0; \ state=URI_HOST; \ - }else goto error_bad_char + }else goto error_bad_char #define check_host_end \ case ':': \ @@ -265,14 +268,14 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) break; \ case '&': \ case '@': \ - goto error_bad_char + goto error_bad_char #define param_set(t_start, v_start) \ param->s=(t_start);\ param->len=(p-(t_start));\ param_val->s=(v_start); \ - param_val->len=(p-(v_start)) + param_val->len=(p-(v_start)) #define u_param_set(t_start, v_start) \ if (uri->u_params_no < URI_MAX_U_PARAMS){ \ @@ -298,7 +301,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) found_user=1;/* no user, pass cannot contain ';'*/ \ pass=0; \ } \ - state=URI_PARAM /* new param */ + state=URI_PARAM /* new param */ #define question_case \ case '?': \ @@ -453,8 +456,8 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) break; \ } \ break - - + + /* init */ end=buf+len; @@ -480,8 +483,13 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) else goto error_bad_uri; }else if (scheme==TEL_SCH){ uri->type=TEL_URI_T; + }else if (scheme==URN_SERVICE_SCH){ + if (memcmp(buf+3,URN_SERVICE_STR,URN_SERVICE_STR_LEN) == 0) { + p+= URN_SERVICE_STR_LEN-1; + uri->type=URN_SERVICE_URI_T; + } else goto error_bad_uri; }else goto error_bad_uri; - + s=p; for(;pinvalid */ case '&': @@ -806,7 +814,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) value_switch(VS_C, 't', 'T', VS_T); value_switch(VS_T, 'p', 'P', VS_P_FIN); transport_fin(VS_P_FIN, PROTO_SCTP); - + /* ttl */ param_switch(PTTL_T2, 'l', 'L', PTTL_L); param_switch1(PTTL_L, '=', PTTL_eq); @@ -820,7 +828,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) state=URI_VAL_P; } break; - + /* user param */ param_switch(PU_U, 's', 'S', PU_S); param_switch(PU_S, 'e', 'E', PU_E); @@ -836,7 +844,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) state=URI_VAL_P; } break; - + /* method*/ param_switch_big(PM_M, 'e', 'E', 'a', 'A', PM_E, PMA_A); param_switch(PM_E, 't', 'T', PM_T); @@ -870,22 +878,22 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) state=URI_VAL_P; } break; - + /* lr */ param_switch(PLR_L, 'r', 'R', PLR_R_FIN); case PLR_R_FIN: switch(*p){ case '@': - still_at_user; + still_at_user; break; case '=': state=PLR_eq; break; - semicolon_case; + semicolon_case; uri->lr.s=b; uri->lr.len=(p-b); break; - question_case; + question_case; uri->lr.s=b; uri->lr.len=(p-b); break; @@ -912,16 +920,16 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) case PR2_2_FIN: switch(*p){ case '@': - still_at_user; + still_at_user; break; case '=': state=PR2_eq; break; - semicolon_case; + semicolon_case; uri->r2.s=b; uri->r2.len=(p-b); break; - question_case; + question_case; uri->r2.s=b; uri->r2.len=(p-b); break; @@ -942,23 +950,23 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) state=URI_VAL_P; } break; - + /* gr */ param_switch(PG_G, 'r', 'R', PG_G_FIN); case PG_G_FIN: switch(*p){ case '@': - still_at_user; + still_at_user; break; case '=': state=PG_eq; break; - semicolon_case; + semicolon_case; uri->gr.s=b; uri->gr.len=(p-b); break; - question_case; + question_case; uri->gr.s=b; uri->gr.len=(p-b); break; @@ -980,9 +988,9 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) } break; - + case URI_HEADERS: - /* for now nobody needs them so we completely ignore the + /* for now nobody needs them so we completely ignore the * headers (they are not allowed in request uri) --andrei */ switch(*p){ case '@': @@ -1198,8 +1206,11 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) uri->host.s=""; uri->host.len=0; break; + case URN_SERVICE_URI_T: + /* leave the actual service name in the URI domain part */ + break; case ERROR_URI_T: - LM_ERR("unexpected error (BUG?)\n"); + LM_ERR("unexpected error (BUG?)\n"); goto error_bad_uri; break; /* do nothing, avoids a compilation warning */ } @@ -1220,21 +1231,21 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) uri->transport.len, ZSW(uri->transport.s), uri->transport_val.len, ZSW(uri->transport_val.s), uri->proto); LM_DBG(" user-param=<%.*s>, val=<%.*s>\n", - uri->user_param.len, ZSW(uri->user_param.s), + uri->user_param.len, ZSW(uri->user_param.s), uri->user_param_val.len, ZSW(uri->user_param_val.s)); LM_DBG(" method=<%.*s>, val=<%.*s>\n", - uri->method.len, ZSW(uri->method.s), + uri->method.len, ZSW(uri->method.s), uri->method_val.len, ZSW(uri->method_val.s)); LM_DBG(" ttl=<%.*s>, val=<%.*s>\n", - uri->ttl.len, ZSW(uri->ttl.s), + uri->ttl.len, ZSW(uri->ttl.s), uri->ttl_val.len, ZSW(uri->ttl_val.s)); LM_DBG(" maddr=<%.*s>, val=<%.*s>\n", - uri->maddr.len, ZSW(uri->maddr.s), + uri->maddr.len, ZSW(uri->maddr.s), uri->maddr_val.len, ZSW(uri->maddr_val.s)); LM_DBG(" lr=<%.*s>, val=<%.*s>\n", uri->lr.len, ZSW(uri->lr.s), - uri->lr_val.len, ZSW(uri->lr_val.s)); + uri->lr_val.len, ZSW(uri->lr_val.s)); LM_DBG(" r2=<%.*s>, val=<%.*s>\n", uri->r2.len, ZSW(uri->r2.s), - uri->r2_val.len, ZSW(uri->r2_val.s)); + uri->r2_val.len, ZSW(uri->r2_val.s)); for(i=0; iu_name[i].s; i++) LM_DBG("uname=[%p]-><%.*s> uval=[%p]-><%.*s>\n", uri->u_name[i].s, uri->u_name[i].len, uri->u_name[i].s, @@ -1243,7 +1254,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) LM_ERR("inconsisten # of u_name:[%d]!=[%d]\n", i, uri->u_params_no); #endif return 0; - + error_too_short: LM_ERR("uri too short: <%.*s> (%d)\n", len, ZSW(buf), len); @@ -1267,7 +1278,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) len, ZSW(buf), len); goto error_exit; error_bad_uri: - LM_ERR("bad uri, state %d parsed: <%.*s> (%d) / <%.*s> (%d)\n", + LM_ERR("bad uri, state %d parsed: <%.*s> (%d) / <%.*s> (%d)\n", state, (int)(p-buf), ZSW(buf), (int)(p-buf), len, ZSW(buf), len); goto error_exit; @@ -1277,7 +1288,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri) len, ZSW(buf), len); goto error_exit; error_bug: - LM_CRIT("bad state %d parsed: <%.*s> (%d) / <%.*s> (%d)\n", + LM_CRIT("bad state %d parsed: <%.*s> (%d) / <%.*s> (%d)\n", state, (int)(p-buf), ZSW(buf), (int)(p-buf), len, ZSW(buf), len); error_exit: ser_error=E_BAD_URI; @@ -1353,7 +1364,7 @@ int parse_orig_ruri(struct sip_msg* msg) } while (0) /* Compare 2 SIP URIs according to RFC 3261 - * + * * Return value : 0 if URIs match * 1 if URIs don't match * -1 if errors have occured @@ -1374,7 +1385,7 @@ int compare_uris(str *raw_uri_a,struct sip_uri* parsed_uri_a, if (raw_uri_a && raw_uri_b) { - + /* maybe we're lucky and straight-forward comparison succeeds */ if (raw_uri_a->len == raw_uri_b->len) if (strncasecmp(raw_uri_a->s,raw_uri_b->s,raw_uri_a->len) == 0) @@ -1485,3 +1496,48 @@ int compare_uris(str *raw_uri_a,struct sip_uri* parsed_uri_a, compare_uri_val(headers,strncasecmp); return 0; } + +static const str uri_type_names[6] = { + {NULL, 0}, /*This is the error type*/ + str_init("sip"), + str_init("sips"), + str_init("tel"), + str_init("tels"), + str_init("urn:service") +}; + +char* uri_type2str(const uri_type type, char *result) +{ + if (type == ERROR_URI_T) + return NULL; + + memcpy(result, uri_type_names[type].s, uri_type_names[type].len); + return result + uri_type_names[type].len; +} + +int uri_typestrlen(const uri_type type) +{ + return uri_type_names[type].len; +} + +uri_type str2uri_type(char * buf) +{ + int scheme = 0; + uri_type type = ERROR_URI_T; + scheme=buf[0]+(buf[1]<<8)+(buf[2]<<16)+(buf[3]<<24); + scheme|=0x20202020; + if (scheme==SIP_SCH){ + type=SIP_URI_T; + }else if(scheme==SIPS_SCH){ + if(buf[4]==':') + type=SIPS_URI_T; + else type = ERROR_URI_T; + }else if (scheme==TEL_SCH){ + type=TEL_URI_T; + }else if (scheme==URN_SERVICE_SCH){ + if (memcmp(buf+3,URN_SERVICE_STR,URN_SERVICE_STR_LEN) == 0) { + type=URN_SERVICE_URI_T; + } + } + return type; +} diff --git a/parser/parse_uri.h b/parser/parse_uri.h index 3fda7d4e1a9..937543e5fa4 100644 --- a/parser/parse_uri.h +++ b/parser/parse_uri.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -35,7 +35,7 @@ /* buf= pointer to begining of uri (sip:x@foo.bar:5060;a=b?h=i) * len= len of uri - * returns: fills uri & returns <0 on error or 0 if ok + * returns: fills uri & returns <0 on error or 0 if ok */ int parse_uri(char *buf, int len, struct sip_uri* uri); /* headers : the list of headers to parse (taken from uri structure) @@ -47,5 +47,8 @@ int parse_sip_msg_uri(struct sip_msg* msg); int parse_orig_ruri(struct sip_msg* msg); int compare_uris(str *raw_uri_a,struct sip_uri* parsed_uri_a, str *raw_uri_b,struct sip_uri *parsed_uri_b); +char * uri_type2str(const uri_type type, char *result); +int uri_typestrlen(const uri_type type); +uri_type str2uri_type(char * buf); #endif /* PARSE_URI_H */ diff --git a/parser/parse_via.c b/parser/parse_via.c index 5e92b24369c..197695753f1 100644 --- a/parser/parse_via.c +++ b/parser/parse_via.c @@ -1,8 +1,8 @@ /* - * $Id$ + * $Id$ * * via parsing automaton - * + * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of opensips, a free SIP server. @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/* * 2003-01-21 added rport parsing code, contributed by * Maxim Sobolev * 2003-01-23 added extra via param parsing code (i=...), used @@ -59,13 +59,13 @@ /* main via states (uri:port ...) */ -enum { +enum { F_HOST, P_HOST, L_PORT, F_PORT, P_PORT, L_PARAM, F_PARAM, P_PARAM, L_VIA, F_VIA, F_COMMENT, P_COMMENT, - F_IP6HOST, P_IP6HOST, + F_IP6HOST, P_IP6HOST, F_CRLF, F_LF, F_CR, @@ -91,7 +91,7 @@ enum { /* param related states * WARNING: keep in sync with parse_via.h, PARAM_HIDDEN, ... */ -enum { +enum { L_VALUE = 200, F_VALUE, P_VALUE, P_STRING, HIDDEN1, HIDDEN2, HIDDEN3, HIDDEN4, HIDDEN5, TTL1, TTL2, @@ -112,12 +112,12 @@ enum { /* entry state must be F_PARAM, or saved_state=F_PARAM and * state=F_{LF,CR,CRLF}! * output state = L_PARAM or F_PARAM or END_OF_HEADER - * (and saved_state= last state); everything else => error - * WARNING: param->start must be filled before, it's used in param->size + * (and saved_state= last state); everything else => error + * WARNING: param->start must be filled before, it's used in param->size * computation. */ static /*inline*/ char* parse_via_param(char* p, char* end, - unsigned char* pstate, + unsigned char* pstate, unsigned char* psaved_state, struct via_param* param) { @@ -173,7 +173,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, case FIN_ALIAS: param->type=state; param->name.len=tmp-param->name.s; - param->size=tmp-param->start; + param->size=tmp-param->start; saved_state=L_PARAM; state=F_LF; goto endofparam; @@ -185,7 +185,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, case FIN_RPORT: param->type=state; param->name.len=tmp-param->name.s; - param->size=tmp-param->start; + param->size=tmp-param->start; saved_state=L_VALUE; state=F_LF; goto find_value; @@ -205,7 +205,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, param->type=GEN_PARAM; saved_state=L_VALUE; param->name.len=tmp-param->name.s; - param->size=tmp-param->start; + param->size=tmp-param->start; state=F_LF; goto find_value; } @@ -216,7 +216,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, case FIN_ALIAS: param->type=state; param->name.len=tmp-param->name.s; - param->size=tmp-param->start; + param->size=tmp-param->start; saved_state=L_PARAM; state=F_CR; goto endofparam; @@ -228,7 +228,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, case FIN_RPORT: param->type=state; param->name.len=tmp-param->name.s; - param->size=tmp-param->start; + param->size=tmp-param->start; saved_state=L_VALUE; state=F_CR; goto find_value; @@ -244,7 +244,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, default: param->type=GEN_PARAM; param->name.len=tmp-param->name.s; - param->size=tmp-param->start; + param->size=tmp-param->start; saved_state=L_VALUE; state=F_CR; goto find_value; @@ -339,7 +339,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, state=F_VIA; goto endofvalue; } - break; + break; /* param names */ case 'h': @@ -740,7 +740,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, saved_state=state; state=END_OF_HEADER; goto parse_error; - + find_value: tmp++; for(;*tmp;tmp++){ @@ -750,7 +750,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, switch(state){ case L_VALUE: case F_VALUE: /*eat space*/ - break; + break; case P_VALUE: state=L_PARAM; param->value.len=tmp-param->value.s; @@ -935,7 +935,7 @@ static /*inline*/ char* parse_via_param(char* p, char* end, saved_state=state; state=END_OF_HEADER; goto parse_error; - + endofparam: endofvalue: param->size=tmp-param->start; @@ -943,15 +943,15 @@ static /*inline*/ char* parse_via_param(char* p, char* end, *pstate=state; *psaved_state=saved_state; LM_DBG("found param type %d, <%.*s> = <%.*s>; state=%d\n", param->type, - param->name.len, ZSW(param->name.s), + param->name.len, ZSW(param->name.s), (param->value.len?param->value.len:3), (param->value.len?param->value.s:"n/a"), state); return tmp; - + end_via: /* if we are here we found an "unexpected" end of via * (cr/lf). This is valid only if the param type is GEN_PARAM or - * RPORT (the only ones which can miss the value; HIDDEN is a + * RPORT (the only ones which can miss the value; HIDDEN is a * special case )*/ if ((param->type==GEN_PARAM)||(param->type==PARAM_RPORT)){ saved_state=L_PARAM; /* change the saved_state, we have an unknown @@ -1167,7 +1167,7 @@ char* parse_via(char* buffer, char* end, struct via_body *vbody) goto parse_error; } break; - + case '/': switch(state){ case FIN_SIP: @@ -1503,7 +1503,7 @@ char* parse_via(char* buffer, char* end, struct via_body *vbody) goto parse_error; } break; - + default: switch(state){ case F_PROTO: @@ -1679,7 +1679,7 @@ char* parse_via(char* buffer, char* end, struct via_body *vbody) goto parse_error; } break; - + case ':': switch(state){ case F_HOST: @@ -1774,7 +1774,7 @@ char* parse_via(char* buffer, char* end, struct via_body *vbody) break; case P_COMMENT: /*everything is allowed in a comment*/ break; - + default: LM_CRIT("on <%c> state %d\n", *tmp, state); goto parse_error; @@ -1811,7 +1811,7 @@ char* parse_via(char* buffer, char* end, struct via_body *vbody) goto parse_error; case F_VIA: /* do nothing, eat ","*/ - break; + break; case F_CRLF: case F_LF: case F_CR: @@ -1962,7 +1962,7 @@ char* parse_via(char* buffer, char* end, struct via_body *vbody) goto parse_error; } break; - + default: switch(state){ case F_HOST: @@ -2047,7 +2047,7 @@ char* parse_via(char* buffer, char* end, struct via_body *vbody) vb->maddr=param; break; } - + if (state==END_OF_HEADER){ state=saved_state; goto endofheader; @@ -2094,7 +2094,7 @@ char* parse_via(char* buffer, char* end, struct via_body *vbody) LM_DBG("end of packet reached, state=%d\n", state); goto endofpacket; /*end of packet, probably should be goto error*/ - + endofheader: state=saved_state; LM_DBG("end of header reached, state=%d\n", state); diff --git a/parser/parse_via.h b/parser/parse_via.h index 81cb9c98158..a139ce24b77 100644 --- a/parser/parse_via.h +++ b/parser/parse_via.h @@ -15,13 +15,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -/* +/* * 2003-01-21 added rport parsing code, contributed by * Maxim Sobolev * 2003-01-21 added extra via param parsing code (i=...), used @@ -38,11 +38,11 @@ #include "../str.h" /* via param types - * WARNING: keep in sync with parse_via.c FIN_HIDDEN... + * WARNING: keep in sync with parse_via.c FIN_HIDDEN... * and with tm/sip_msg.c via_body_cloner */ enum { - PARAM_HIDDEN=230, PARAM_TTL, PARAM_BRANCH, + PARAM_HIDDEN=230, PARAM_TTL, PARAM_BRANCH, PARAM_MADDR, PARAM_RECEIVED, PARAM_RPORT, PARAM_I, PARAM_ALIAS, GEN_PARAM, PARAM_ERROR @@ -64,7 +64,7 @@ struct via_param { /* Format: name/version/transport host:port;params comment */ /* WARNING: keep in sync with tm/sip_msg.c via_body_cloner */ -struct via_body { +struct via_body { int error; str hdr; /* Contains "Via" or "v" */ str name; diff --git a/parser/parser_f.c b/parser/parser_f.c index 2d8d70e9d45..176b93a7b52 100644 --- a/parser/parser_f.c +++ b/parser/parser_f.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -35,7 +35,7 @@ char* eat_line(char* buffer, unsigned int len) as I do not care about CR */ nl=(char *)q_memchr( buffer, '\n', len ); - if ( nl ) { + if ( nl ) { if ( nl + 1 < buffer+len) nl++; if (( nl+1len; i++) { if (!quoted) { if (_s->s[i] == '\"') quoted = 1; diff --git a/parser/sdp/sdp.c b/parser/sdp/sdp.c index a2287d1a851..0b60de0e43b 100644 --- a/parser/sdp/sdp.c +++ b/parser/sdp/sdp.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -57,7 +57,7 @@ static inline int new_sdp(struct sip_msg* _m) return -1; } memset( sdp, 0, sizeof(sdp_info_t)); - + _m->sdp = sdp; return 0; @@ -299,7 +299,7 @@ sdp_stream_cell_t* get_sdp_stream(struct sip_msg* _m, int session_num, int strea { if (_m->sdp == NULL) return NULL; return get_sdp_stream_sdp(_m->sdp, session_num, stream_num); - + } @@ -350,7 +350,7 @@ sdp_payload_attr_t* get_sdp_payload4index(sdp_stream_cell_t *stream, int index) /** * SDP parser method. */ -static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_info_t* _sdp) +int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_info_t* _sdp) { str body = *sdp_body; str sdp_ip = {NULL,0}; @@ -436,7 +436,7 @@ static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_ m2p = m1p; stream_num = 0; for (;;) { - m1p = m2p; + m1p = m2p; if (m1p == NULL || m1p >= bodylimit) break; m2p = find_next_sdp_line(m1p, bodylimit, 'm', bodylimit); @@ -749,14 +749,20 @@ int parse_sdp(struct sip_msg* _m) /** * Free all memory. */ -void free_sdp(sdp_info_t** _sdp) +void free_sdp(sdp_info_t** sdp) +{ + __free_sdp(*sdp); + pkg_free(*sdp); + *sdp = NULL; +} + +void __free_sdp(sdp_info_t* sdp) { - sdp_info_t *sdp = *_sdp; sdp_session_cell_t *session, *l_session; sdp_stream_cell_t *stream, *l_stream; sdp_payload_attr_t *payload, *l_payload; - LM_DBG("_sdp = %p\n", _sdp); + LM_DBG("sdp = %p\n", sdp); if (sdp == NULL) return; LM_DBG("sdp = %p\n", sdp); session = sdp->sessions; @@ -781,11 +787,8 @@ void free_sdp(sdp_info_t** _sdp) } pkg_free(l_session); } - pkg_free(sdp); - *_sdp = NULL; } - void print_sdp_stream(sdp_stream_cell_t *stream, int log_level) { sdp_payload_attr_t *payload; diff --git a/parser/sdp/sdp.h b/parser/sdp/sdp.h index 0e646cd55e5..9ef4ce89056 100644 --- a/parser/sdp/sdp.h +++ b/parser/sdp/sdp.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -135,6 +135,8 @@ typedef struct sdp_info { * Parse SDP. */ int parse_sdp(struct sip_msg* _m); +int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, + sdp_info_t* _sdp); /** * Get number of sessions in existing SDP. @@ -177,7 +179,8 @@ sdp_payload_attr_t* get_sdp_payload4index(sdp_stream_cell_t *stream, int index); * * Note: this will free up the parsed sdp structure (form PKG_MEM). */ -void free_sdp(sdp_info_t** _sdp); +void free_sdp(sdp_info_t** sdp); +void __free_sdp(sdp_info_t* sdp); /** diff --git a/parser/sdp/sdp_cloner.h b/parser/sdp/sdp_cloner.h index 6129dc9b27c..e52f3351c6d 100644 --- a/parser/sdp/sdp_cloner.h +++ b/parser/sdp/sdp_cloner.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * diff --git a/parser/sdp/sdp_helpr_funcs.c b/parser/sdp/sdp_helpr_funcs.c index e0991355ee4..cb9ad625697 100644 --- a/parser/sdp/sdp_helpr_funcs.c +++ b/parser/sdp/sdp_helpr_funcs.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -137,7 +137,7 @@ int get_mixed_part_delimiter(str* body, str *mp_delimiter) x = READ(p-4); if (!one_of_16(x,dary)) goto other; - + /* skip spaces and tabs if any */ while (*p==' ' || *p=='\t') advance(p,1,str_type,error); @@ -152,9 +152,9 @@ int get_mixed_part_delimiter(str* body, str *mp_delimiter) mp_delimiter->s = p; return 1; -error: +error: return -1; -other: +other: LM_DBG("'boundary' parsing error\n"); return -1; } @@ -385,7 +385,7 @@ int extract_bwidth(str *body, str *bwtype, str *bwwitdth) /* skip ':' */ bwwitdth->s = cp1 + 1; bwwitdth->len = len - 1; - + return 0; } @@ -433,7 +433,7 @@ int extract_mediaip(str *body, str *mediaip, int *pf, char *line) break; } } - /* consume all spaces starting from the second char after the token + /* consume all spaces starting from the second char after the token First char after the token is the char that stoped the token parsing, so it is space or \r / \n, so we simply skip it */ cp = eat_space_end(cp + len + 1, mediaip->s + mediaip->len); @@ -577,7 +577,7 @@ char *find_sdp_line_complex(char* p, char* plimit, char * name) { char *cp, *cp1; int len = strlen(name); - + /* Iterate through body */ cp = p; for (;;) { @@ -636,7 +636,7 @@ char* get_sdp_hdr_field(char* buf, char* end, struct hdr_field* hdr) } /* eliminate leading whitespace */ - tmp=eat_lws_end(tmp, end); + tmp=eat_lws_end(tmp, end); if (tmp>=end) { LM_ERR("hf empty\n"); goto error; diff --git a/parser/sdp/sdp_helpr_funcs.h b/parser/sdp/sdp_helpr_funcs.h index 9185a08da2d..d8272dcf428 100644 --- a/parser/sdp/sdp_helpr_funcs.h +++ b/parser/sdp/sdp_helpr_funcs.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -70,5 +70,5 @@ char *find_sdp_line_complex(char* p, char* plimit, char * name); char* get_sdp_hdr_field(char* , char* , struct hdr_field* ); char *find_sdp_line_delimiter(char *p, char *plimit, str delimiter); -char *find_next_sdp_line_delimiter(char *p, char *plimit, str delimiter, char *defptr); +char *find_next_sdp_line_delimiter(char *p, char *plimit, str delimiter, char *defptr); #endif diff --git a/pass_fd.c b/pass_fd.c index 3b500431748..d30f8709919 100644 --- a/pass_fd.c +++ b/pass_fd.c @@ -43,24 +43,24 @@ /* receive all the data or returns error (handles EINTR etc.) * params: socket * data - buffer for the results - * data_len - + * data_len - * flags - recv flags for the first recv (see recv(2)), only * 0, MSG_WAITALL and MSG_DONTWAIT make sense * if flags is set to MSG_DONWAIT (or to 0 and the socket fd is non-blocking), - * and if no data is queued on the fd, recv_all will not wait (it will + * and if no data is queued on the fd, recv_all will not wait (it will * return error and set errno to EAGAIN/EWOULDBLOCK). However if even 1 byte * is queued, the call will block until the whole data_len was read or an * error or eof occured ("semi-nonblocking" behaviour, some tcp code * counts on it). * if flags is set to MSG_WAITALL it will block even if no byte is available. - * + * * returns: bytes read or error (<0) * can return < data_len if EOF */ int recv_all(int socket, void* data, int data_len, int flags) { int b_read; int n; - + b_read=0; again: n=recv(socket, (char*)data, data_len, flags); @@ -94,7 +94,7 @@ int recv_all(int socket, void* data, int data_len, int flags) int send_all(int socket, void* data, int data_len) { int n; - + again: n=send(socket, data, data_len, 0); if (n<0){ @@ -105,6 +105,19 @@ int send_all(int socket, void* data, int data_len) return n; } +/* gcc does the right thing */ +static inline int get_unaligned_int(const void *p) +{ + const struct { int d; } __attribute__((packed)) *pp = p; + return pp->d; +} + +/* gcc does the right thing */ +static inline void put_unaligned_int(void *p, int value) +{ + struct { int d; } __attribute__((packed, may_alias)) *pp = p; + pp->d = value; +} /* at least 1 byte must be sent! */ int send_fd(int unix_socket, void* data, int data_len, int fd) @@ -119,31 +132,31 @@ int send_fd(int unix_socket, void* data, int data_len, int fd) struct cmsghdr cm; char control[CMSG_SPACE(sizeof(fd))]; }control_un; - + msg.msg_control=control_un.control; /* openbsd doesn't like "more space", msg_controllen must not * include the end padding */ msg.msg_controllen=CMSG_LEN(sizeof(fd)); - + cmsg=CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); - *(int*)CMSG_DATA(cmsg)=fd; + put_unaligned_int(CMSG_DATA(cmsg), fd); msg.msg_flags=0; #else msg.msg_accrights=(caddr_t) &fd; msg.msg_accrightslen=sizeof(fd); #endif - + msg.msg_name=0; msg.msg_namelen=0; - + iov[0].iov_base=data; iov[0].iov_len=data_len; msg.msg_iov=iov; msg.msg_iovlen=1; - + again: ret=sendmsg(unix_socket, &msg, 0); if (ret<0){ @@ -156,14 +169,14 @@ int send_fd(int unix_socket, void* data, int data_len, int fd) unix_socket, strerror(errno)); } } - + return ret; } /* receives a fd and data_len data - * params: unix_socket + * params: unix_socket * data * data_len * fd - will be set to the passed fd value or -1 if no fd @@ -183,22 +196,22 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags) struct cmsghdr cm; char control[CMSG_SPACE(sizeof(new_fd))]; }control_un; - + msg.msg_control=control_un.control; msg.msg_controllen=sizeof(control_un.control); #else msg.msg_accrights=(caddr_t) &new_fd; msg.msg_accrightslen=sizeof(int); #endif - + msg.msg_name=0; msg.msg_namelen=0; - + iov[0].iov_base=data; iov[0].iov_len=data_len; msg.msg_iov=iov; msg.msg_iovlen=1; - + again: ret=recvmsg(unix_socket, &msg, flags); if (ret<0){ @@ -213,7 +226,7 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags) goto error; } if (retcmsg_len==CMSG_LEN(sizeof(new_fd)))){ @@ -237,10 +250,10 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags) ret=-1; goto error; } - *fd=*((int*) CMSG_DATA(cmsg)); + *fd = get_unaligned_int(CMSG_DATA(cmsg)); }else{ /* - LM_ERR("no descriptor passed, cmsg=%p,len=%d\n", + LM_ERR("no descriptor passed, cmsg=%p,len=%d\n", cmsg, (unsigned)cmsg->cmsg_len); */ *fd=-1; /* it's not really an error */ @@ -249,12 +262,12 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags) if (msg.msg_accrightslen==sizeof(int)){ *fd=new_fd; }else{ - /*LM_ERR("no descriptor passed, accrightslen=%d\n", + /*LM_ERR("no descriptor passed, accrightslen=%d\n", msg.msg_accrightslen); */ *fd=-1; } #endif - + error: return ret; } diff --git a/poll_types.h b/poll_types.h index 3971dd63306..8e57b235283 100644 --- a/poll_types.h +++ b/poll_types.h @@ -37,7 +37,7 @@ enum poll_types { POLL_NONE, POLL_POLL, POLL_EPOLL_LT, POLL_EPOLL_ET, /* all the function and vars are defined in io_wait.c */ extern char* poll_method_str[POLL_END]; -extern char* poll_support; +extern char* poll_support; enum poll_types choose_poll_method(); diff --git a/prime_hash.c b/prime_hash.c index cca78a0ee49..ee3578917ea 100644 --- a/prime_hash.c +++ b/prime_hash.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/prime_hash.h b/prime_hash.h index db41dde9a66..2192a9b4480 100644 --- a/prime_hash.h +++ b/prime_hash.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -39,7 +39,7 @@ * \brief * Determines from which part of a message the hash shall be calculated. * Possible values are: - * + * * - \b shs_call_id the content of the Call-ID header field * - \b shs_from_uri the entire URI in the From header field * - \b shs_from_user the username part of the URI in the From header field diff --git a/proxy.c b/proxy.c index d22a6131b1a..b7a767c42e4 100644 --- a/proxy.c +++ b/proxy.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -56,21 +56,6 @@ struct proxy_l* proxies=0; int disable_dns_failover=0; -/* searches for the proxy named 'name', on port 'port' with - proto 'proto'; if proto==0 => proto wildcard (will match any proto) - returns: pointer to proxy_l on success or 0 if not found */ -static struct proxy_l* find_proxy(str *name, unsigned short port, int proto) -{ - struct proxy_l* t; - for(t=proxies; t; t=t->next) - if (((t->name.len == name->len) && - ((proto==PROTO_NONE)||(t->proto==proto))&& - (strncasecmp(t->name.s, name->s, name->len)==0)) && - (t->port==port)) - break; - return t; -} - int hostent_shm_cpy(struct hostent *dst, struct hostent* src) { @@ -137,7 +122,7 @@ int hostent_cpy(struct hostent *dst, struct hostent* src) for (i=0;ih_aliases[i])+1; dst->h_aliases[i]=(char*)pkg_malloc(sizeof(char)*len2); - if (dst->h_aliases==0){ + if (dst->h_aliases[i]==0){ ser_error=ret=E_OUT_OF_MEM; pkg_free(dst->h_name); for(r=0; rh_aliases[r]); @@ -177,7 +162,7 @@ int hostent_cpy(struct hostent *dst, struct hostent* src) dst->h_addrtype=src->h_addrtype; dst->h_length=src->h_length; /*finished hostent copy */ - + return 0; error: @@ -198,7 +183,7 @@ void free_hostent(struct hostent *dst) pkg_free(dst->h_aliases); } if (dst->h_addr_list){ - for (r=0; dst->h_addr_list[r];r++) { + for (r=0; dst->h_addr_list[r];r++) { pkg_free(dst->h_addr_list[r]); } pkg_free(dst->h_addr_list); @@ -207,26 +192,7 @@ void free_hostent(struct hostent *dst) -struct proxy_l* add_proxy( str* name, unsigned short port, - unsigned short proto) -{ - struct proxy_l* p; - - if ((p=find_proxy(name, port, proto))!=0) return p; - if ((p=mk_proxy(name, port, proto, 0))==0) goto error; - /* add p to the proxy list */ - p->next=proxies; - proxies=p; - return p; - -error: - return 0; -} - - - - -/* same as add_proxy, but it doesn't add the proxy to the list +/* Creates a proxy structure out of the host, port and proto * uses also SRV if possible & port==0 (quick hack) */ struct proxy_l* mk_proxy(str* name, unsigned short port, unsigned short proto, @@ -267,7 +233,8 @@ struct proxy_l* mk_proxy(str* name, unsigned short port, unsigned short proto, -/* same as mk_proxy, but get the host as an ip*/ +/* same as mk_proxy, but in shared memory + * uses also SRV if possible & port==0 (quick hack) */ struct proxy_l* mk_proxy_from_ip(struct ip_addr* ip, unsigned short port, unsigned short proto) { @@ -322,7 +289,7 @@ void free_shm_proxy(struct proxy_l* p) } /* same as add_proxy, but it doesn't add the proxy to the list - * uses also SRV if possible & port==0 (quick hack) + * uses also SRV if possible & port==0 (quick hack) works in shared memory */ struct proxy_l* mk_shm_proxy(str* name, unsigned short port, unsigned short proto, int is_sips) @@ -359,3 +326,40 @@ struct proxy_l* mk_shm_proxy(str* name, unsigned short port, unsigned short prot error: return 0; } + +/* clones a proxy into pkg memory */ +struct proxy_l* clone_proxy(struct proxy_l *sp) +{ + struct proxy_l *dp; + + dp = (struct proxy_l*)pkg_malloc(sizeof(struct proxy_l)); + if (dp==NULL) { + LM_ERR("no more pkg memory\n"); + return 0; + } + memset( dp , 0 , sizeof(struct proxy_l)); + + dp->port = sp->port; + dp->proto = sp->proto; + dp->addr_idx = sp->addr_idx; + + /* clone the hostent */ + if (hostent_cpy( &dp->host, &sp->host)!=0) + goto error0; + + /* clone the dns resolver */ + if (sp->dn) { + dp->dn = dns_res_copy(sp->dn); + if (dp->dn==NULL) + goto error1; + } + + return dp; +error1: + free_hostent(&dp->host); +error0: + pkg_free(dp); + return 0; +} + + diff --git a/proxy.h b/proxy.h index e852d5ec9c1..8507a3edd94 100644 --- a/proxy.h +++ b/proxy.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -39,7 +39,6 @@ struct dns_node; #define PROXY_SHM_FLAG (1<<0) struct proxy_l{ - struct proxy_l* next; str name; /* original name */ unsigned short flags; unsigned short port; @@ -48,14 +47,13 @@ struct proxy_l{ unsigned short addr_idx; /* crt. addr. idx. */ struct hostent host; /* addresses */ + /* tree with the DNS resolving status + * NOTE: this is all the time in SHM */ struct dns_node *dn; }; extern struct proxy_l* proxies; -struct proxy_l* add_proxy( str* name, unsigned short port, - unsigned short proto); - struct proxy_l* mk_proxy( str* name, unsigned short port, unsigned short proto, int is_sips); struct proxy_l* mk_shm_proxy(str* name, unsigned short port, unsigned short proto, @@ -74,6 +72,8 @@ int hostent_shm_cpy(struct hostent *dst, struct hostent* src); void free_shm_hostent(struct hostent *dst); +struct proxy_l* clone_proxy(struct proxy_l *sp); + #include "resolve.h" #endif diff --git a/pt.c b/pt.c index 362261b70d0..6a751effc14 100644 --- a/pt.c +++ b/pt.c @@ -2,7 +2,7 @@ * $Id$ * * Copyright (C) 2007 Voice Sistem SRL - * + * * This file is part of opensips, a free SIP server. * * opensips is free software; you can redistribute it and/or modify @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -37,6 +37,7 @@ #include "dprint.h" #include "timer.h" #include "pt.h" +#include "bin_interface.h" /* array with children pids, 0= main proc, @@ -76,6 +77,10 @@ int init_multi_proc_support(void) /* attendent */ proc_no++; } + + /* info packet UDP receivers */ + proc_no += bin ? bin_children : 0; + /* timer processes */ proc_no += count_timer_procs(); @@ -165,6 +170,8 @@ pid_t internal_fork(char *proc_desc) process_counter = CHILD_COUNTER_STOP; /* each children need a unique seed */ seed_child(seed); + init_debug(); + /* set attributes */ set_proc_attrs(proc_desc); /* set TCP communication */ @@ -203,7 +210,7 @@ int count_init_children(int flags) struct sr_module *m; struct socket_info* si; - if (dont_fork) + if (dont_fork) goto skip_listeners; /* UDP listening children */ @@ -231,7 +238,7 @@ int count_init_children(int flags) for (i=0;m->exports->procs[i].name;i++) { if (!m->exports->procs[i].no || !m->exports->procs[i].function) continue; - + if (!flags || (m->exports->procs[i].flags & flags)) ret+=m->exports->procs[i].no; } @@ -240,3 +247,14 @@ int count_init_children(int flags) LM_DBG("%d children are going to be inited\n",ret); return ret; } + +int id_of_pid(pid_t pid) +{ + int i; + + for (i = 0; i < counted_processes; i++) + if (pt[i].pid == pid) + return i; + + return -1; +} diff --git a/pt.h b/pt.h index 729afcfa6ff..33676351a1a 100644 --- a/pt.h +++ b/pt.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -44,9 +44,13 @@ struct process_table { int pid; #ifdef USE_TCP int unix_sock; /* unix socket on which tcp main listens */ - int idx; /* tcp child index, -1 for other processes */ + int idx; /* tcp child index, -1 for other processes */ #endif char desc[MAX_PT_DESC]; + + int default_debug; /* used when resetting the log level */ + int debug; /* logging level of this process */ + stat_var *load; }; @@ -61,6 +65,9 @@ void set_proc_attrs( char *fmt, ...); pid_t internal_fork(char *proc_desc); int count_init_children(int flags); +/* @return: -1 or the index of the given process */ +int id_of_pid(pid_t pid); + /* return processes pid */ inline static int my_pid(void) { diff --git a/pvar.c b/pvar.c index 60f77d8f3a3..fb34b56a353 100644 --- a/pvar.c +++ b/pvar.c @@ -3,7 +3,7 @@ * * Copyright (C) 2001-2003 FhG Fokus * Copyright (C) 2005-2009 Voice Sistem SRL - * + * * This file is part of opensips, a free SIP server. * * opensips is free software; you can redistribute it and/or modify @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -40,8 +40,8 @@ #include "dprint.h" #include "mem/mem.h" #include "mem/shm_mem.h" -#include "ut.h" -#include "trim.h" +#include "ut.h" +#include "trim.h" #include "dset.h" #include "action.h" #include "socket_info.h" @@ -102,6 +102,33 @@ static str str_tls = { _str_tls_hlp, 3 }; static char _str_sctp_hlp[5] = {'s','c','t','p',0}; static str str_sctp = { _str_sctp_hlp, 4 }; +static char _str_request_route_hlp[] = {'r','e','q','u','e','s','t','_','r','o','u','t','e',0}; +static str str_request_route = { _str_request_route_hlp, 13 }; + +static char _str_failure_route_hlp[] = {'f','a','i','l','u','r','e','_','r','o','u','t','e',0}; +static str str_failure_route = { _str_failure_route_hlp, 13 }; + +static char _str_onreply_route_hlp[] = {'o','n','r','e','p','l','y','_','r','o','u','t','e',0}; +static str str_onreply_route = { _str_onreply_route_hlp, 13 }; + +static char _str_branch_route_hlp[] = {'b','r','a','n','c','h','_','r','o','u','t','e',0}; +static str str_branch_route = { _str_branch_route_hlp, 12 }; + +static char _str_error_route_hlp[] = {'e','r','r','o','r','_','r','o','u','t','e',0}; +static str str_error_route = { _str_error_route_hlp, 11 }; + +static char _str_local_route_hlp[] = {'l','o','c','a','l','_','r','o','u','t','e',0}; +static str str_local_route = { _str_local_route_hlp, 11 }; + +static char _str_startup_route_hlp[] = {'s','t','a','r','t','u','p','_','r','o','u','t','e',0}; +static str str_startup_route = { _str_startup_route_hlp, 13 }; + +static char _str_timer_route_hlp[] = {'t','i','m','e','r','_','r','o','u','t','e',0}; +static str str_timer_route = { _str_timer_route_hlp, 11 }; + +static char _str_event_route_hlp[] = {'e','v','e','n','t','_','r','o','u','t','e',0}; +static str str_event_route = { _str_event_route_hlp, 11 }; + int _pv_pid = 0; #define PV_FIELD_DELIM ", " @@ -223,7 +250,7 @@ int pv_get_null(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { if(res==NULL) return -1; - + res->rs = str_empty; res->ri = 0; res->flags = PV_VAL_NULL; @@ -328,7 +355,7 @@ static int pv_get_timef(struct sip_msg *msg, pv_param_t *param, { time_t t; str s; - + if(msg==NULL) return -1; @@ -358,14 +385,14 @@ static int pv_get_method(struct sip_msg *msg, pv_param_t *param, &msg->first_line.u.request.method, (int)msg->first_line.u.request.method_value); } - - if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) || + + if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) || (msg->cseq==NULL))) { LM_ERR("no CSEQ header\n"); return pv_get_null(msg, param, res); } - + return pv_get_strintval(msg, param, res, &get_cseq(msg)->method, get_cseq(msg)->method_id); @@ -393,7 +420,7 @@ static int pv_get_reason(struct sip_msg *msg, pv_param_t *param, if(msg->first_line.type != SIP_REPLY) return pv_get_null(msg, param, res); - + return pv_get_strval(msg, param, res, &msg->first_line.u.reply.reason); } @@ -411,7 +438,7 @@ static int pv_get_ruri(struct sip_msg *msg, pv_param_t *param, LM_ERR("failed to parse the R-URI\n"); return pv_get_null(msg, param, res); } - + if (msg->new_uri.s!=NULL) return pv_get_strval(msg, param, res, &msg->new_uri); return pv_get_strval(msg, param, res, &msg->first_line.u.request.uri); @@ -489,7 +516,7 @@ static int pv_get_ruri_attr(struct sip_msg *msg, pv_param_t *param, return pv_get_null(msg, param, res); } return pv_get_xuri_attr(msg, &(msg->parsed_uri), param, res); -} +} static int pv_get_ouri_attr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) @@ -670,12 +697,12 @@ static int pv_get_contact_body(struct sip_msg *msg, pv_param_t *param, return -1; /* get all CONTACT headers */ - if(msg->contact==NULL && parse_headers(msg, HDR_EOH_F, 0)==-1) + if(msg->contact==NULL && parse_headers(msg, HDR_EOH_F, 0)==-1) { LM_DBG("no contact header\n"); return pv_get_null(msg, param, res); } - + if(!msg->contact || !msg->contact->body.s || msg->contact->body.len<=0) { LM_DBG("no contact header!\n"); @@ -736,7 +763,7 @@ static int pv_get_contact_body(struct sip_msg *msg, pv_param_t *param, ct = ct_b->contacts; } } - } while (ct_b); + } while (ct_h); res->rs.s = pv_local_buf; res->rs.len = p - pv_local_buf; @@ -833,7 +860,7 @@ static int pv_get_xto_attr(struct sip_msg *msg, pv_param_t *param, if(param->pvn.u.isname.name.n==1) /* uri */ return pv_get_strval(msg, param, res, &xto->uri); - + if(param->pvn.u.isname.name.n==4) /* tag */ { if (xto->tag_value.s==NULL || xto->tag_value.len<=0) @@ -919,7 +946,7 @@ static int pv_get_from_attr(struct sip_msg *msg, pv_param_t *param, LM_ERR("cannot parse From header\n"); return pv_get_null(msg, param, res); } - + if(msg->from==NULL || get_from(msg)==NULL) { LM_DBG("no From header\n"); return pv_get_null(msg, param, res); @@ -932,7 +959,7 @@ static int pv_get_cseq(struct sip_msg *msg, pv_param_t *param, { if(msg==NULL) return -1; - + if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) || (msg->cseq==NULL)) ) { @@ -948,7 +975,7 @@ static int pv_get_msg_buf(struct sip_msg *msg, pv_param_t *param, str s; if(msg==NULL) return -1; - + s.s = msg->buf; s.len = msg->len; return pv_get_strval(msg, param, res, &s); @@ -959,17 +986,21 @@ static int pv_get_msg_len(struct sip_msg *msg, pv_param_t *param, { if(msg==NULL) return -1; - + return pv_get_uintval(msg, param, res, msg->len); } static int pv_get_flags(struct sip_msg *msg, pv_param_t *param, - pv_value_t *res) + pv_value_t *res) { - if(msg==NULL) + str buf; + + if (!msg) return -1; - return pv_get_uintval(msg, param, res, msg->flags); + buf = bitmask_to_flag_list(FLAG_TYPE_MSG, msg->flags); + + return pv_get_strval(msg, param, res, &buf); } static inline char* int_to_8hex(int val) @@ -977,7 +1008,7 @@ static inline char* int_to_8hex(int val) unsigned short digit; int i; static char outbuf[9]; - + outbuf[8] = '\0'; for(i=0; i<8; i++) { @@ -993,52 +1024,30 @@ static inline char* int_to_8hex(int val) return outbuf; } -static int pv_get_hexflags(struct sip_msg *msg, pv_param_t *param, - pv_value_t *res) -{ - str s; - if(msg==NULL || res==NULL) - return -1; - - s.s = int_to_8hex(msg->flags); - s.len = 8; - return pv_get_strintval(msg, param, res, &s, (int)msg->flags); -} - static int pv_get_bflags(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { - return pv_get_uintval(msg, param, res, getb0flags()); -} + str buf; -static int pv_get_hexbflags(struct sip_msg *msg, pv_param_t *param, - pv_value_t *res) -{ - str s; - if(res==NULL) + if (!msg) return -1; - s.s = int_to_8hex((int)getb0flags()); - s.len = 8; - return pv_get_strintval(msg, param, res, &s, (int)getb0flags()); + buf = bitmask_to_flag_list(FLAG_TYPE_BRANCH, getb0flags()); + + return pv_get_strval(msg, param, res, &buf); } static int pv_get_sflags(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { - return pv_get_uintval(msg, param, res, getsflags()); -} + str buf; -static int pv_get_hexsflags(struct sip_msg *msg, pv_param_t *param, - pv_value_t *res) -{ - str s; - if(res==NULL) + if (!msg) return -1; - s.s = int_to_8hex((int)getsflags()); - s.len = 8; - return pv_get_strintval(msg, param, res, &s, (int)getsflags()); + buf = bitmask_to_flag_list(FLAG_TYPE_SCRIPT, getsflags()); + + return pv_get_strval(msg, param, res, &buf); } static int pv_get_callid(struct sip_msg *msg, pv_param_t *param, @@ -1046,7 +1055,7 @@ static int pv_get_callid(struct sip_msg *msg, pv_param_t *param, { if(msg==NULL) return -1; - + if(msg->callid==NULL && ((parse_headers(msg, HDR_CALLID_F, 0)==-1) || (msg->callid==NULL)) ) { @@ -1082,11 +1091,11 @@ static int pv_get_rcvip(struct sip_msg *msg, pv_param_t *param, { if(msg==NULL) return -1; - - if(msg->rcv.bind_address==NULL + + if(msg->rcv.bind_address==NULL || msg->rcv.bind_address->address_str.s==NULL) return pv_get_null(msg, param, res); - + return pv_get_strval(msg, param, res, &msg->rcv.bind_address->address_str); } @@ -1095,11 +1104,11 @@ static int pv_get_rcvport(struct sip_msg *msg, pv_param_t *param, { if(msg==NULL) return -1; - - if(msg->rcv.bind_address==NULL + + if(msg->rcv.bind_address==NULL || msg->rcv.bind_address->port_no_str.s==NULL) return pv_get_null(msg, param, res); - + return pv_get_intstrval(msg, param, res, (int)msg->rcv.bind_address->port_no, &msg->rcv.bind_address->port_no_str); @@ -1110,7 +1119,7 @@ static int pv_get_force_sock(struct sip_msg *msg, pv_param_t *param, { if(msg==NULL) return -1; - + if (msg->force_send_socket==0) return pv_get_null(msg, param, res); @@ -1120,7 +1129,7 @@ static int pv_get_force_sock(struct sip_msg *msg, pv_param_t *param, static int pv_get_useragent(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { - if(msg==NULL) + if(msg==NULL) return -1; if(msg->user_agent==NULL && ((parse_headers(msg, HDR_USERAGENT_F, 0)==-1) || (msg->user_agent==NULL))) @@ -1128,7 +1137,7 @@ static int pv_get_useragent(struct sip_msg *msg, pv_param_t *param, LM_DBG("no User-Agent header\n"); return pv_get_null(msg, param, res); } - + return pv_get_strval(msg, param, res, &msg->user_agent->body); } @@ -1143,13 +1152,53 @@ static int pv_get_refer_to(struct sip_msg *msg, pv_param_t *param, LM_DBG("no Refer-To header\n"); return pv_get_null(msg, param, res); } - + if(msg->refer_to==NULL || get_refer_to(msg)==NULL) return pv_get_null(msg, param, res); return pv_get_strval(msg, param, res, &(get_refer_to(msg)->uri)); } +static int pv_get_route_type(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res) +{ + str s; + + switch(route_type) + { + case REQUEST_ROUTE: + s = str_request_route; + break; + case FAILURE_ROUTE: + s = str_failure_route; + break; + case ONREPLY_ROUTE: + s = str_onreply_route; + break; + case BRANCH_ROUTE: + s = str_branch_route; + break; + case ERROR_ROUTE: + s = str_error_route; + break; + case LOCAL_ROUTE: + s = str_local_route; + break; + case STARTUP_ROUTE: + s = str_startup_route; + break; + case TIMER_ROUTE: + s = str_timer_route; + break; + case EVENT_ROUTE: + s = str_event_route; + default: + s = str_null; + } + + return pv_get_strval(msg, param, res, &s); +} + static int pv_get_diversion(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { @@ -1164,7 +1213,7 @@ static int pv_get_diversion(struct sip_msg *msg, pv_param_t *param, LM_DBG("no Diversion header\n"); return pv_get_null(msg, param, res); } - + if(msg->diversion == NULL || get_diversion(msg) == NULL) { LM_DBG("no Diversion header\n"); @@ -1212,7 +1261,7 @@ static int pv_get_rpid(struct sip_msg *msg, pv_param_t *param, LM_DBG("no RPID header\n"); return pv_get_null(msg, param, res); } - + if(msg->rpid==NULL || get_rpid(msg)==NULL) return pv_get_null(msg, param, res); @@ -1223,7 +1272,7 @@ static int pv_get_ppi_attr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { struct sip_uri *uri; - + if(msg==NULL) return -1; @@ -1231,16 +1280,16 @@ static int pv_get_ppi_attr(struct sip_msg *msg, pv_param_t *param, LM_DBG("no P-Preferred-Identity header\n"); return pv_get_null(msg, param, res); } - + if(msg->ppi == NULL || get_ppi(msg) == NULL) { LM_DBG("no P-Preferred-Identity header\n"); return pv_get_null(msg, param, res); } - + if(param->pvn.u.isname.name.n == 1) { /* uri */ return pv_get_strval(msg, param, res, &(get_ppi(msg)->uri)); } - + if(param->pvn.u.isname.name.n==4) { /* display name */ if(get_ppi(msg)->display.s == NULL || get_ppi(msg)->display.len <= 0) { @@ -1278,18 +1327,18 @@ static int pv_get_pai(struct sip_msg *msg, pv_param_t *param, { if(msg==NULL) return -1; - + if(parse_pai_header(msg)==-1) { LM_DBG("no P-Asserted-Identity header\n"); return pv_get_null(msg, param, res); } - + if(msg->pai==NULL || get_pai(msg)==NULL) { LM_DBG("no P-Asserted-Identity header\n"); return pv_get_null(msg, param, res); } - + return pv_get_strval(msg, param, res, &(get_pai(msg)->uri)); } @@ -1372,7 +1421,7 @@ static int pv_get_dsturi_attr(struct sip_msg *msg, pv_param_t *param, LM_ERR("failed to parse dst uri\n"); return pv_get_null(msg, param, res); } - + if(param->pvn.u.isname.name.n==1) /* domain */ { if(uri.host.s==NULL || uri.host.len<=0) @@ -1396,7 +1445,7 @@ static int pv_get_dsturi_attr(struct sip_msg *msg, pv_param_t *param, static int pv_get_content_type(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { - if(msg==NULL) + if(msg==NULL) return -1; if(msg->content_type==NULL @@ -1406,14 +1455,14 @@ static int pv_get_content_type(struct sip_msg *msg, pv_param_t *param, LM_DBG("no Content-Type header\n"); return pv_get_null(msg, param, res); } - + return pv_get_strval(msg, param, res, &msg->content_type->body); } static int pv_get_content_length(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { - if(msg==NULL) + if(msg==NULL) return -1; if(msg->content_length==NULL && ((parse_headers(msg, HDR_CONTENTLENGTH_F, 0)==-1) @@ -1422,7 +1471,7 @@ static int pv_get_content_length(struct sip_msg *msg, pv_param_t *param, LM_DBG("no Content-Length header\n"); return pv_get_null(msg, param, res); } - + return pv_get_intstrval(msg, param, res, (int)(long)msg->content_length->parsed, &msg->content_length->body); @@ -1436,7 +1485,7 @@ static int pv_get_msg_body(struct sip_msg *msg, pv_param_t *param, if(msg==NULL) return -1; - if (get_body( msg, &s)!=0 || s.len==0 ) + if (get_body( msg, &s)!=0 || s.len==0 ) { LM_DBG("no message body\n"); return pv_get_null(msg, param, res); @@ -1526,7 +1575,7 @@ static inline str *cred_user(struct sip_msg *rq) if (!h) get_authorized_cred(rq->authorization, &h); if (!h) return 0; cred=(auth_body_t*)(h->parsed); - if (!cred || !cred->digest.username.user.len) + if (!cred || !cred->digest.username.user.len) return 0; return &cred->digest.username.user; } @@ -1578,7 +1627,7 @@ static int pv_get_acc_username(struct sip_msg *msg, pv_param_t *param, } return pv_get_strval(msg, param, res, user); } - + /* from from uri */ if(parse_from_header(msg)<0) { @@ -1840,24 +1889,38 @@ static int pv_get_avp(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) } return 0; } + + /* print the entire AVP array */ if(idxf==PV_IDX_ALL) { p = pv_local_buf; - do { + + /* separately handle the first AVP */ + if(avp->flags & AVP_VAL_STR) + { + res->rs = avp_value.s; + } else { + res->rs.s = sint2str(avp_value.n, &res->rs.len); + } + + if(p-pv_local_buf+res->rs.len+1>PV_LOCAL_BUF_SIZE) + { + LM_ERR("local buffer length exceeded!\n"); + return pv_get_null(msg, param, res); + } + memcpy(p, res->rs.s, res->rs.len); + p += res->rs.len; + + /* print subsequent AVPs as [DELIM AVP]* */ + while ((avp = search_first_avp(name_type, avp_name, &avp_value, avp))) + { if(avp->flags & AVP_VAL_STR) { res->rs = avp_value.s; } else { res->rs.s = sint2str(avp_value.n, &res->rs.len); } - - if(p-pv_local_buf+res->rs.len+1>PV_LOCAL_BUF_SIZE) - { - LM_ERR("local buffer length exceeded!\n"); - return pv_get_null(msg, param, res); - } - memcpy(p, res->rs.s, res->rs.len); - p += res->rs.len; + if(p-pv_local_buf+PV_FIELD_DELIM_LEN+1>PV_LOCAL_BUF_SIZE) { LM_ERR("local buffer length exceeded\n"); @@ -1865,13 +1928,20 @@ static int pv_get_avp(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) } memcpy(p, PV_FIELD_DELIM, PV_FIELD_DELIM_LEN); p += PV_FIELD_DELIM_LEN; - } while ((avp=search_first_avp(name_type, avp_name, - &avp_value, avp))!=0); + + if(p-pv_local_buf+res->rs.len+1>PV_LOCAL_BUF_SIZE) + { + LM_ERR("local buffer length exceeded!\n"); + return pv_get_null(msg, param, res); + } + memcpy(p, res->rs.s, res->rs.len); + p += res->rs.len; + } + *p = 0; res->rs.s = pv_local_buf; res->rs.len = p - pv_local_buf; return 0; - } /* we have a numeric index */ @@ -1902,7 +1972,7 @@ static int pv_get_avp(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) } } n=0; - while(n use type to find it */ for (hf=msg->headers; hf; hf=hf->next) { - if (tv.ri==hf->type) + if (tv.ri==hf->type) ++n; } } else { @@ -2001,7 +2071,7 @@ static int pv_get_hdr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) if (tv.flags==0) { /* it is a known header -> use type to find it */ for (hf=msg->headers; hf; hf=hf->next) { - if (tv.ri==hf->type) + if (tv.ri==hf->type) break; } } else { @@ -2043,7 +2113,7 @@ static int pv_get_hdr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) memcpy(p, PV_FIELD_DELIM, PV_FIELD_DELIM_LEN); p += PV_FIELD_DELIM_LEN; } - + if(p-pv_local_buf+hf->body.len+1>PV_LOCAL_BUF_SIZE) { LM_ERR("local buffer length exceeded!\n"); @@ -2082,7 +2152,7 @@ static int pv_get_hdr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) if (tv.flags==0 ) { /* it is a known header -> use type to find it */ for (hf0=hf->next; hf0; hf0=hf0->next) { - if (tv.ri==hf0->type) + if (tv.ri==hf0->type) n++; } } else { @@ -2149,7 +2219,7 @@ static int pv_get_scriptvar(struct sip_msg *msg, pv_param_t *param, int ival = 0; char *sval = NULL; script_var_t *sv=NULL; - + if(msg==NULL || res==NULL) return -1; @@ -2309,7 +2379,7 @@ int pv_set_dsturi(struct sip_msg* msg, pv_param_t *param, LM_ERR("bad parameters\n"); return -1; } - + if(val == NULL) { memset(&act, 0, sizeof(act)); @@ -2326,7 +2396,7 @@ int pv_set_dsturi(struct sip_msg* msg, pv_param_t *param, LM_ERR("error - str value requred to set dst uri\n"); goto error; } - + if(set_dst_uri(msg, &val->rs)!=0) goto error; @@ -2394,7 +2464,7 @@ int pv_set_ruri_user(struct sip_msg* msg, pv_param_t *param, LM_ERR("bad parameters\n"); return -1; } - + if(val == NULL) { memset(&act, 0, sizeof(act)); @@ -2414,7 +2484,7 @@ int pv_set_ruri_user(struct sip_msg* msg, pv_param_t *param, LM_ERR("str value required to set R-URI user\n"); goto error; } - + memset(&act, 0, sizeof(act)); act.elem[0].type = STR_ST; act.elem[0].u.s = val->rs; @@ -2446,7 +2516,7 @@ int pv_set_ruri_host(struct sip_msg* msg, pv_param_t *param, LM_ERR("str value required to set R-URI hostname\n"); goto error; } - + memset(&act, 0, sizeof(act)); act.elem[0].type = STR_ST; act.elem[0].u.s = val->rs; @@ -2478,7 +2548,7 @@ int pv_set_dsturi_host(struct sip_msg* msg, pv_param_t *param, LM_ERR("str value required to set DST-URI hostname\n"); goto error; } - + memset(&act, 0, sizeof(act)); act.elem[0].type = STR_ST; act.elem[0].u.s = val->rs; @@ -2505,7 +2575,7 @@ int pv_set_dsturi_port(struct sip_msg* msg, pv_param_t *param, LM_ERR("bad parameters\n"); return -1; } - + if(val == NULL) { memset(&act, 0, sizeof(act)); @@ -2526,7 +2596,7 @@ int pv_set_dsturi_port(struct sip_msg* msg, pv_param_t *param, val->rs.s = int2str(val->ri, &val->rs.len); val->flags |= PV_VAL_STR; } - + memset(&act, 0, sizeof(act)); act.elem[0].type = STR_ST; act.elem[0].u.s = val->rs; @@ -2555,7 +2625,7 @@ int pv_set_ruri_port(struct sip_msg* msg, pv_param_t *param, LM_ERR("bad parameters\n"); return -1; } - + if(val == NULL) { memset(&act, 0, sizeof(act)); @@ -2576,7 +2646,7 @@ int pv_set_ruri_port(struct sip_msg* msg, pv_param_t *param, val->rs.s = int2str(val->ri, &val->rs.len); val->flags |= PV_VAL_STR; } - + memset(&act, 0, sizeof(act)); act.elem[0].type = STR_ST; act.elem[0].u.s = val->rs; @@ -2674,7 +2744,7 @@ int pv_set_branch_fields(struct sip_msg* msg, pv_param_t *param, return -1; } q = (!val||val->flags&PV_VAL_NULL)? Q_UNSPECIFIED : val->ri; - return update_branch( idx, NULL, NULL, + return update_branch( idx, NULL, NULL, NULL, &q, NULL, NULL); case BR_DURI_ID: /* set DURI */ if ( val && !(val->flags&PV_VAL_STR) ) { @@ -2698,7 +2768,7 @@ int pv_set_branch_fields(struct sip_msg* msg, pv_param_t *param, return -1; } flags = (!val||val->flags&PV_VAL_NULL)? 0 : val->ri; - return update_branch( idx, NULL, NULL, + return update_branch( idx, NULL, NULL, NULL, NULL, &flags, NULL); case BR_SOCKET_ID: /* set SOCKET */ if ( val && !(val->flags&PV_VAL_STR) ) { @@ -2735,7 +2805,7 @@ int pv_set_force_sock(struct sip_msg* msg, pv_param_t *param, struct socket_info *si; int port, proto; str host; - + if(msg==NULL || param==NULL) { LM_ERR("bad parameters\n"); @@ -2753,7 +2823,7 @@ int pv_set_force_sock(struct sip_msg* msg, pv_param_t *param, LM_ERR("str value required to set the force send sock\n"); goto error; } - + if (parse_phostport(val->rs.s, val->rs.len, &host.s, &host.len, &port, &proto) < 0) { LM_ERR("invalid socket specification\n"); @@ -2774,91 +2844,13 @@ int pv_set_force_sock(struct sip_msg* msg, pv_param_t *param, return -1; } -int pv_set_mflags(struct sip_msg* msg, pv_param_t *param, - int op, pv_value_t *val) -{ - if(msg==NULL || param==NULL) - { - LM_ERR("bad parameters\n"); - return -1; - } - - if(val == NULL) - { - msg->flags = 0; - return 0; - } - - if(!(val->flags&PV_VAL_INT)) - { - LM_ERR("assigning non-int value to msg flags\n"); - return -1; - } - - msg->flags = val->ri; - - return 0; -} - -int pv_set_sflags(struct sip_msg* msg, pv_param_t *param, - int op, pv_value_t *val) -{ - if(msg==NULL || param==NULL) - { - LM_ERR("bad parameters\n"); - return -1; - } - - if(val == NULL) - { - setsflagsval(0); - return 0; - } - - if(!(val->flags&PV_VAL_INT)) - { - LM_ERR("assigning non-int value to script flags\n"); - return -1; - } - - setsflagsval((unsigned int)val->ri); - - return 0; -} - -int pv_set_bflags(struct sip_msg* msg, pv_param_t *param, - int op, pv_value_t *val) -{ - if(msg==NULL || param==NULL) - { - LM_ERR("bad parameters\n"); - return -1; - } - - if(val == NULL) - { - setb0flags(0); - return 0; - } - - if(!(val->flags&PV_VAL_INT)) - { - LM_ERR("assigning non-int value to branch 0 flags\n"); - return -1; - } - - setb0flags((unsigned int)val->ri); - - return 0; -} - /********* end PV set functions *********/ int pv_parse_scriptvar_name(pv_spec_p sp, str *in) { if(in==NULL || in->s==NULL || sp==NULL) return -1; - + sp->pvp.pvn.type = PV_NAME_PVAR; sp->pvp.pvn.u.dname = (void*)add_var(in); if(sp->pvp.pvn.u.dname==NULL) @@ -2878,7 +2870,7 @@ int pv_parse_hdr_name(pv_spec_p sp, str *in) if(in==NULL || in->s==NULL || sp==NULL) return -1; - + p = in->s; if(*p==PV_MARKER) { @@ -3052,8 +3044,7 @@ static pv_export_t _pv_names_table[] = { pv_parse_avp_name, pv_parse_index, 0, 0}, {{"hdr", (sizeof("hdr")-1)}, PVT_HDR, pv_get_hdr, 0, pv_parse_hdr_name, pv_parse_index, 0, 0}, - {{"hdrcnt", (sizeof("hdrcnt")-1)}, PVT_HDRCNT, pv_get_hdrcnt, 0, pv_parse_hdr_name, - pv_parse_index, 0, 0}, + {{"hdrcnt", (sizeof("hdrcnt")-1)}, PVT_HDRCNT, pv_get_hdrcnt, 0, pv_parse_hdr_name, 0, 0, 0}, {{"var", (sizeof("var")-1)}, PVT_SCRIPTVAR, pv_get_scriptvar, pv_set_scriptvar, pv_parse_scriptvar_name, 0, 0, 0}, {{"ai", (sizeof("ai")-1)}, /* */ @@ -3074,10 +3065,13 @@ static pv_export_t _pv_names_table[] = { {{"an", (sizeof("an")-1)}, /* */ PVT_AUTH_NONCE, pv_get_authattr, 0, 0, 0, pv_init_iname, 5}, + {{"auth.nonce", (sizeof("auth.nonce")-1)}, /* */ + PVT_AUTH_NONCE, pv_get_authattr, 0, + 0, 0, pv_init_iname, 5}, {{"auth.resp", (sizeof("auth.resp")-1)}, /* */ PVT_AUTH_RESPONSE, pv_get_authattr, 0, 0, 0, pv_init_iname, 6}, - {{"auth.nonce", (sizeof("auth.nonce")-1)}, /* */ + {{"auth.cnonce", (sizeof("auth.cnonce")-1)}, /* */ PVT_AUTH_CNONCE, pv_get_authattr, 0, 0, 0, pv_init_iname, 7}, {{"auth.opaque", (sizeof("auth.opaque")-1)}, /* */ @@ -3099,10 +3093,7 @@ static pv_export_t _pv_names_table[] = { PVT_ACC_USERNAME, pv_get_acc_username, 0, 0, 0, pv_init_iname, 1}, {{"bf", (sizeof("bf")-1)}, /* */ - PVT_BFLAGS, pv_get_bflags, pv_set_bflags, - 0, 0, 0, 0}, - {{"bF", (sizeof("bF")-1)}, /* */ - PVT_HEXBFLAGS, pv_get_hexbflags, pv_set_bflags, + PVT_BFLAGS, pv_get_bflags, 0, 0, 0, 0, 0}, {{"branch", (sizeof("branch")-1)}, /* */ PVT_BRANCH, pv_get_branch_fields, pv_set_branch, @@ -3201,10 +3192,7 @@ static pv_export_t _pv_names_table[] = { PVT_MSG_BUF, pv_get_msg_buf, 0, 0, 0, 0, 0}, {{"mf", (sizeof("mf")-1)}, /* */ - PVT_FLAGS, pv_get_flags, pv_set_mflags, - 0, 0, 0, 0}, - {{"mF", (sizeof("mF")-1)}, /* */ - PVT_HEXFLAGS, pv_get_hexflags, pv_set_mflags, + PVT_FLAGS, pv_get_flags, 0, 0, 0, 0, 0}, {{"mi", (sizeof("mi")-1)}, /* */ PVT_MSGID, pv_get_msgid, 0, @@ -3290,6 +3278,9 @@ static pv_export_t _pv_names_table[] = { {{"rt", (sizeof("rt")-1)}, /* */ PVT_REFER_TO, pv_get_refer_to, 0, 0, 0, 0, 0}, + {{"rT", (sizeof("rt")-1)}, /* */ + PVT_ROUTE_TYPE, pv_get_route_type, 0, + 0, 0, 0, 0}, {{"ru", (sizeof("ru")-1)}, /* */ PVT_RURI, pv_get_ruri, pv_set_ruri, 0, 0, 0, 0}, @@ -3312,10 +3303,7 @@ static pv_export_t _pv_names_table[] = { PVT_RCVPORT, pv_get_rcvport, 0, 0, 0, 0, 0}, {{"sf", (sizeof("sf")-1)}, /* */ - PVT_SFLAGS, pv_get_sflags, pv_set_sflags, - 0, 0, 0, 0}, - {{"sF", (sizeof("sF")-1)}, /* */ - PVT_HEXSFLAGS, pv_get_hexsflags, pv_set_sflags, + PVT_SFLAGS, pv_get_sflags, 0, 0, 0, 0, 0}, {{"src_ip", (sizeof("src_ip")-1)}, /* */ PVT_SRCIP, pv_get_srcip, 0, @@ -3488,7 +3476,7 @@ char* pv_parse_spec(str *in, pv_spec_p e) goto done_all; } - if (*p==PV_LCBRACKET) + if (*p==PV_LCBRACKET) { /* context definition*/ p++; pvcontext.s = p; @@ -3548,7 +3536,7 @@ char* pv_parse_spec(str *in, pv_spec_p e) pvstate); goto error; } - } else { + } else { if(!is_in_str(p, in)) { p--; goto done_inm; @@ -3768,12 +3756,14 @@ int pv_parse_format(str *in, pv_elem_p *el) return -1; /*LM_DBG("parsing [%.*s]\n", in->len, in->s);*/ - + if(in->len == 0) { *el = pkg_malloc(sizeof(pv_elem_t)); - if(*el == NULL) + if(*el == NULL) { + LM_ERR("not enough pkg memory for PV element (1)\n"); goto error; + } memset(*el, 0, sizeof(pv_elem_t)); (*el)->text = *in; return 0; @@ -3787,28 +3777,32 @@ int pv_parse_format(str *in, pv_elem_p *el) { e0 = e; e = pkg_malloc(sizeof(pv_elem_t)); - if(!e) + if(!e) { + LM_ERR("not enough pkg memory for PV element (2)\n"); goto error; + } memset(e, 0, sizeof(pv_elem_t)); n++; if(*el == NULL) *el = e; if(e0) e0->next = e; - + e->text.s = p; while(is_in_str(p,in) && *p!=PV_MARKER) p++; e->text.len = p - e->text.s; - + if(!is_in_str(p,in)) break; s.s = p; s.len = in->s+in->len-p; p0 = pv_parse_spec(&s, &e->spec); - - if(p0==NULL) + + if(p0==NULL) { + LM_ERR("parsing PV spec failed\n"); goto error; + } if(!is_in_str(p0,in)) break; p = p0; @@ -3885,7 +3879,7 @@ int pv_get_avp_name(struct sip_msg* msg, pv_param_p ip, int *avp_name, LM_ERR("null or empty name\n"); return -1; } - + if(!(tv.flags&PV_VAL_STR)) tv.rs.s = int2str(tv.ri, &tv.rs.len); @@ -3914,7 +3908,7 @@ int pv_get_spec_index(struct sip_msg* msg, pv_param_p ip, int *idx, int *flags) if(ip->pvi.type == PV_IDX_ALL) { return 0; } - + if(ip->pvi.type == PV_IDX_INT) { *idx = ip->pvi.u.ival; @@ -4005,9 +3999,9 @@ int pv_print_spec(struct sip_msg* msg, pv_spec_p sp, char *buf, int *len) if(*len <= 0) return -1; - + memset(&tok, 0, sizeof(pv_value_t)); - + /* put the value of the specifier */ if(pv_get_spec_value(msg, sp, &tok)==0) { @@ -4018,11 +4012,11 @@ int pv_print_spec(struct sip_msg* msg, pv_spec_p sp, char *buf, int *len) else goto overflow; } - + *len = tok.rs.len; buf[tok.rs.len] = '\0'; return 0; - + overflow: LM_ERR("buffer overflow -- increase the buffer size...\n"); return -1; @@ -4035,7 +4029,9 @@ int pv_printf(struct sip_msg* msg, pv_elem_p list, char *buf, int *len) pv_value_t tok; pv_elem_p it; char *cur; - + char *p; + int l; + if(msg==NULL || list==NULL || buf==NULL || len==NULL) return -1; @@ -4067,24 +4063,41 @@ int pv_printf(struct sip_msg* msg, pv_elem_p list, char *buf, int *len) { if(tok.flags&PV_VAL_NULL) tok.rs = str_null; - if(n+tok.rs.len < *len) - { - if(tok.rs.len>0) + if (tok.flags&PV_VAL_STR || tok.flags&PV_VAL_NULL) { + if(n+tok.rs.len < *len) + { + if(tok.rs.len>0) + { + memcpy(cur, tok.rs.s, tok.rs.len); + n += tok.rs.len; + cur += tok.rs.len; + } + } else { + LM_ERR("no more space for spec value [%d][%d]\n", + n, tok.rs.len); + goto overflow; + } + } else if (tok.flags&(PV_VAL_INT|PV_TYPE_INT)){ + p = int2str(tok.ri, &l); + if (n+l < *len) { - memcpy(cur, tok.rs.s, tok.rs.len); - n += tok.rs.len; - cur += tok.rs.len; + memcpy(cur, p, l); + n += l; + cur += l; + } else { + LM_ERR("no more space for spec value [%d][%d]\n", + n, tok.rs.len); + goto overflow; } } else { - LM_ERR("no more space for spec value [%d][%d]\n", - n, tok.rs.len); - goto overflow; + LM_ERR("unkown type %x\n", tok.flags); + return -1; } } } goto done; - + overflow: LM_ERR("buffer overflow -- increase the buffer size from [%d]...\n",*len); return -1; @@ -4186,7 +4199,7 @@ void pv_value_destroy(pv_value_t *val) } #define PV_PRINT_BUF_SIZE 1024 -#define PV_PRINT_BUF_NO 5 +#define PV_PRINT_BUF_NO 7 /*IMPORTANT NOTE - even if the function prints and returns a static buffer, it * has built-in support for 3 levels of nesting (or concurrent usage). * If you think it's not enough for you, either use pv_printf() directly, @@ -4298,7 +4311,7 @@ int pv_add_extra(pv_export_t *e) LM_ERR("invalid parameters\n"); return -1; } - + if(_pv_extra_list==0) { LM_DBG("extra items list is not initialized\n"); @@ -4309,7 +4322,7 @@ int pv_add_extra(pv_export_t *e) } } in = &(e->name); - p = in->s; + p = in->s; while(is_in_str(p,in) && is_pv_valid_char(*p)) p++; if(is_in_str(p,in)) @@ -4397,7 +4410,7 @@ int pv_free_extra_list(void) pkg_free(_pv_extra_list); _pv_extra_list = 0; } - + return 0; } @@ -4534,7 +4547,7 @@ pv_context_t* pv_get_context(str* name) int pv_contextlist_check(void) { pv_context_t* pvc = pv_context_lst; - + while(pvc) { if(pvc->contextf == NULL) @@ -4552,7 +4565,7 @@ argv_p argv_vars = NULL; argv_p search_argv(str *name) { argv_p it; - + for (it = argv_vars; it; it = it->next) { if (it->name.len == name->len && !strncmp(it->name.s, name->s, name->len)) @@ -4566,7 +4579,7 @@ int add_arg_var(char *opt) char *eq; str name; argv_p new = NULL; - + if (!opt) { LM_ERR("cannot receive null option\n"); return -1; @@ -4731,7 +4744,7 @@ static int pv_get_param(struct sip_msg *msg, pv_param_t *ip, pv_value_t *res) return -1; } } - + if (index < 1 || index > route_params_number) { LM_DBG("no such parameter index %d\n", index); diff --git a/pvar.h b/pvar.h index 4ffebe6a57f..da99671380b 100644 --- a/pvar.h +++ b/pvar.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -76,8 +76,8 @@ && (pv)->pvp.pvn.u.isname.type&AVP_NAME_STR) #define pv_is_w(pv) ((pv)->setf!=NULL) -enum _pv_type { - PVT_NONE=0, PVT_EMPTY, PVT_NULL, +enum _pv_type { + PVT_NONE=0, PVT_EMPTY, PVT_NULL, PVT_MARKER, PVT_AVP, PVT_HDR, PVT_PID, PVT_RETURN_CODE, PVT_TIMES, PVT_TIMEF, PVT_MSGID, PVT_METHOD, @@ -109,7 +109,8 @@ enum _pv_type { PVT_TIME, PVT_PATH, PVT_ARGV, PVT_HDRCNT, PVT_AUTH_NONCE_COUNT, PVT_AUTH_QOP, PVT_AUTH_ALGORITHM, PVT_AUTH_OPAQUE, PVT_AUTH_CNONCE, - PVT_RU_Q, PVT_ROUTE_PARAM, PVT_EXTRA /* keep it last */ + PVT_RU_Q, PVT_ROUTE_PARAM, PVT_ROUTE_TYPE, + PVT_EXTRA /* keep it last */ }; typedef enum _pv_type pv_type_t; diff --git a/qvalue.c b/qvalue.c index e276abafc39..5cd2cd93ab7 100644 --- a/qvalue.c +++ b/qvalue.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -170,11 +170,11 @@ int str2q(qvalue_t* q, char* s, int len) switch(state) { case ST_START: return E_Q_EMPTY; - + case ST_0_PT: case ST_1_PT: return E_Q_DEC_MISSING; - + default: return 0; } diff --git a/qvalue.h b/qvalue.h index 72f116bfd12..96aa81f9691 100644 --- a/qvalue.h +++ b/qvalue.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -33,7 +33,7 @@ #include /*! \page QvalueHandling Q Value Handling - * + * * The q value expresses the priority of a URI within a set of URIs * (Contact header field in the same SIP message or dset array in * ser. The higher is the q value of a URI the higher is the priority @@ -145,7 +145,7 @@ static inline char* q2str(qvalue_t q, unsigned int* len) } else { memcpy(p, Q_PREFIX, Q_PREFIX_LEN); p += Q_PREFIX_LEN; - + *p++ = q / 100 + '0'; q %= 100; if (!q) goto end; diff --git a/radius.h b/radius.h index d49c50a76b8..b896aa9da9f 100644 --- a/radius.h +++ b/radius.h @@ -13,8 +13,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * WARNING: Don't forget to update the dictionary if you update this file !!! diff --git a/re.c b/re.c index b6e06c8cb93..9d7f807b8f0 100644 --- a/re.c +++ b/re.c @@ -1,8 +1,8 @@ -/* +/* * $Id$ * * regexp and regexp substitutions implementations - * + * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of opensips, a free SIP server. @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @@ -57,7 +57,7 @@ void subst_expr_free(struct subst_expr* se) void replace_lst_free(struct replace_lst* l) { struct replace_lst* t; - + while (l){ t=l; l=l->next; @@ -67,7 +67,7 @@ void replace_lst_free(struct replace_lst* l) } #define MAX_REPLACE_WITH 100 -int parse_repl(struct replace_with * rw, char ** begin, +int parse_repl(struct replace_with * rw, char ** begin, char * end, int *max_token_nb, int with_sep) { @@ -145,7 +145,7 @@ int parse_repl(struct replace_with * rw, char ** begin, rw[token_nb].type=REPLACE_NMATCH; rw[token_nb].u.nmatch=(*p)-'0'; /* 0 is the whole matched str*/ - if (max_pmatchlen, subst->s); goto error; } - + p=subst->s; end=subst->s+subst->len; c=*p; if (c=='\\'){ - LM_ERR("invalid separator char <%c> in %.*s\n", c, + LM_ERR("invalid separator char <%c> in %.*s\n", c, subst->len, subst->s); goto error; } p++; - + /* find re */ re=p; for (;plen, subst->s); goto error; } @@ -323,7 +323,7 @@ struct subst_expr* subst_parser(str* subst) for (r=0; rreplace[r]=rw[r]; LM_DBG("ok, se is %p\n", se); return se; - + error: if (se) { subst_expr_free(se); regex=0; } if (regex) { regfree (regex); pkg_free(regex); } @@ -338,7 +338,7 @@ static int replace_len(const char* match, int nmatch, regmatch_t* pmatch, int r; int len; str* uri; - + len=se->replacement.len; for (r=0; rn_escapes; r++){ switch(se->replace[r].type){ @@ -389,7 +389,7 @@ static int replace_build(const char* match, int nmatch, regmatch_t* pmatch, int size; #define REPLACE_BUFFER_SIZE 1024 static char rbuf[REPLACE_BUFFER_SIZE]; - + #if 0 /* use static bufer now since we cannot easily get the length */ rpl->len=replace_len(match, nmatch, pmatch, se, msg); @@ -403,7 +403,7 @@ static int replace_build(const char* match, int nmatch, regmatch_t* pmatch, goto error; } #endif - + p=se->replacement.s; end=p+se->replacement.len; dest=rbuf; @@ -428,7 +428,7 @@ static int replace_build(const char* match, int nmatch, regmatch_t* pmatch, LM_ERR("overflow\n"); goto error; } - memcpy(dest, + memcpy(dest, match+pmatch[se->replace[r].u.nmatch].rm_so, size); dest+=size; @@ -475,7 +475,7 @@ static int replace_build(const char* match, int nmatch, regmatch_t* pmatch, } } memcpy(dest, p, end-p); - + rpl->len = (dest-rbuf)+(end-p); rpl->s=pkg_malloc(rpl->len); if (rpl->s==0){ @@ -483,7 +483,7 @@ static int replace_build(const char* match, int nmatch, regmatch_t* pmatch, goto error; } memcpy(rpl->s, rbuf, rpl->len); - + return 0; error: return -1; @@ -508,8 +508,8 @@ struct replace_lst* subst_run(struct subst_expr* se, const char* input, int nmatch; int eflags; int cnt; - - + + /* init */ head=0; cnt=0; @@ -546,7 +546,7 @@ struct replace_lst* subst_run(struct subst_expr* se, const char* input, (*crt)->offset=pmatch[0].rm_so+(int)(p-input); (*crt)->size=pmatch[0].rm_eo-pmatch[0].rm_so; LM_DBG("matched (%d, %d): [%.*s]\n", - (*crt)->offset, (*crt)->size, + (*crt)->offset, (*crt)->size, (*crt)->size, input+(*crt)->offset); /* create subst. string */ /* construct the string from replace[] */ @@ -578,8 +578,8 @@ struct replace_lst* subst_run(struct subst_expr* se, const char* input, /*! \return the substitution result in a str, input must be 0 term * 0 on no match or malloc error * if count is non zero it will be set to the number of matches, or -1 - * if error - */ + * if error + */ str* subst_str(const char *input, struct sip_msg* msg, struct subst_expr* se, int* count) { @@ -591,8 +591,8 @@ str* subst_str(const char *input, struct sip_msg* msg, struct subst_expr* se, const char* p; char* dest; const char* end; - - + + /* compute the len */ len=strlen(input); end=input+len; @@ -615,7 +615,7 @@ str* subst_str(const char *input, struct sip_msg* msg, struct subst_expr* se, } res->s[len]=0; res->len=len; - + /* replace */ dest=res->s; p=input; diff --git a/re.h b/re.h index 60ffc1b4583..a9b6106f6ca 100644 --- a/re.h +++ b/re.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -59,7 +59,7 @@ struct replace_with{ struct subst_expr{ regex_t* re; str replacement; - int replace_all; + int replace_all; int n_escapes; /* escapes number (replace[] size) */ int max_pmatch ; /* highest () referenced */ struct replace_with replace[1]; /* 0 does not work on all compilers */ @@ -76,10 +76,10 @@ struct replace_lst{ void subst_expr_free(struct subst_expr* se); void replace_lst_free(struct replace_lst* l); -int parse_repl(struct replace_with * rw, char ** begin, +int parse_repl(struct replace_with * rw, char ** begin, char * end, int *max_token_nb, int flag); struct subst_expr* subst_parser(str* subst); -struct replace_lst* subst_run( struct subst_expr* se, const char* input, +struct replace_lst* subst_run( struct subst_expr* se, const char* input, struct sip_msg* msg, int *count); str* subst_str(const char* input, struct sip_msg* msg, struct subst_expr* se, int* count); diff --git a/receive.c b/receive.c index e78713c4a6f..75a4e5f271f 100644 --- a/receive.c +++ b/receive.c @@ -1,4 +1,4 @@ -/* +/* *$Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -36,8 +36,8 @@ * 2006-12-22 functions for script flags added (bogdan) */ -/*! - * \file +/*! + * \file * \brief Receive message and process routing for it */ @@ -81,13 +81,26 @@ unsigned int get_next_msg_no(void) return ++msg_no; } -/*! \note WARNING: buf must be 0 terminated (buf[len]=0) or some things might +/*! \note WARNING: buf must be 0 terminated (buf[len]=0) or some things might * break (e.g.: modules/textops) */ -int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) +int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) { struct sip_msg* msg; struct timeval start; + int rc; + char *tmp; + str in_buff; + + in_buff.len = len; + in_buff.s = buf; + + /* the raw processing callbacks can change the buffer, + further use in_buff.s and at the end try to free in_buff.s + if changed by callbacks */ + run_raw_processing_cb(PRE_RAW_PROCESSING,&in_buff); + /* update the length for further processing */ + len = in_buff.len; msg=pkg_malloc(sizeof(struct sip_msg)); if (msg==0) { @@ -100,15 +113,14 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */ /* fill in msg */ - msg->buf=buf; + msg->buf=in_buff.s; msg->len=len; msg->rcv=*rcv_info; msg->id=msg_no; - msg->set_global_address=default_global_address; - msg->set_global_port=default_global_port; - - if (parse_msg(buf,len, msg)!=0){ - LM_ERR("parse_msg failed\n"); + + if (parse_msg(in_buff.s,len, msg)!=0){ + tmp=ip_addr2a(&(rcv_info->src_ip)); + LM_ERR("Unable to parse msg received from [%s:%d]\n", tmp, rcv_info->src_port); /* if a REQUEST msg was detected (first line was succesfully parsed) we should trigger the error route */ if ( msg->first_line.type==SIP_REQUEST && error_rlist.a!=NULL ) @@ -134,7 +146,7 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) /* check if necessary to add receive?->moved to forward_req */ /* check for the alias stuff */ #ifdef USE_TCP - if (msg->via1->alias && tcp_accept_aliases && + if (msg->via1->alias && tcp_accept_aliases && (((rcv_info->proto==PROTO_TCP) && !tcp_disable) #ifdef USE_TLS || ((rcv_info->proto==PROTO_TLS) && !tls_disable) @@ -160,16 +172,20 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) * (like presence of at least one via), so you can count * on via1 being parsed in a pre-script callback --andrei */ - if (exec_pre_req_cb(msg)==0 ) { + rc = exec_pre_req_cb(msg); + if (rc == SCB_DROP_MSG) { update_stat( drp_reqs, 1); goto end; /* drop the message */ } /* exec the routing script */ - run_top_route(rlist[DEFAULT_RT].a, msg); + if (rc & SCB_RUN_TOP_ROUTE) + run_top_route(rlist[DEFAULT_RT].a, msg); /* execute post request-script callbacks */ - exec_post_req_cb(msg); + if (rc & SCB_RUN_POST_CBS) + exec_post_req_cb(msg); + } else if (msg->first_line.type==SIP_REPLY) { update_stat( rcv_rpls, 1); /* sanity checks */ @@ -190,15 +206,17 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) * (like presence of at least one via), so you can count * on via1 being parsed in a pre-script callback --andrei */ - if (exec_pre_rpl_cb(msg)==0 ) { + rc = exec_pre_rpl_cb(msg); + if (rc == SCB_DROP_MSG) { update_stat( drp_rpls, 1); goto end; /* drop the reply */ } /* exec the onreply routing script */ - if ( onreply_rlist[DEFAULT_RT].a!=0 && - (run_top_route(onreply_rlist[DEFAULT_RT].a,msg)&ACT_FL_DROP) - && msg->REPLY_STATUS<200 ) { + if (rc & SCB_RUN_TOP_ROUTE && onreply_rlist[DEFAULT_RT].a && + (run_top_route(onreply_rlist[DEFAULT_RT].a,msg) & ACT_FL_DROP) + && msg->REPLY_STATUS < 200) { + LM_DBG("dropping provisional reply %d\n", msg->REPLY_STATUS); update_stat( drp_rpls, 1); goto end; /* drop the message */ @@ -209,7 +227,8 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) } /* execute post reply-script callbacks */ - exec_post_rpl_cb(msg); + if (rc & SCB_RUN_POST_CBS) + exec_post_rpl_cb(msg); } end: @@ -222,12 +241,16 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) LM_DBG("cleaning up\n"); free_sip_msg(msg); pkg_free(msg); + if (in_buff.s != buf) + pkg_free(in_buff.s); return 0; parse_error: exec_parse_err_cb(msg); free_sip_msg(msg); pkg_free(msg); error: + if (in_buff.s != buf) + pkg_free(in_buff.s); return -1; } diff --git a/receive.h b/receive.h index 488ccfafe1f..c294930cff1 100644 --- a/receive.h +++ b/receive.h @@ -15,13 +15,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*! - * \file + * \file * \brief Receive message handling */ diff --git a/regexp.c b/regexp.c index 69c44e7f435..a75c03c73eb 100644 --- a/regexp.c +++ b/regexp.c @@ -17,14 +17,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*! - * \file + * \file * \brief Regular Expression functions */ diff --git a/regexp.h b/regexp.h index d24edf9215f..200d8c6d7c0 100644 --- a/regexp.h +++ b/regexp.h @@ -17,15 +17,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*! - * \file - * \brief Regular expression definitions + * \file + * \brief Regular expression definitions */ diff --git a/resolve.c b/resolve.c index d4fd2d7c4dd..231d28eecdf 100644 --- a/resolve.c +++ b/resolve.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -25,11 +25,11 @@ * 2003-07-03 default port value set according to proto (andrei) * 2007-01-25 support for DNS failover added (bogdan) * 2008-07-25 support for SRV load-balancing added (bogdan) - */ + */ /*! - * \file + * \file * \brief DNS resolver for OpenSIPS */ @@ -67,6 +67,7 @@ struct dns_val { #define local_free pkg_free int dns_try_ipv6=0; /*!< default off */ +int dns_try_naptr=1; /*!< default on */ /* declared in globals.h */ int dns_retr_time=-1; int dns_retr_no=-1; @@ -244,7 +245,7 @@ int get_dns_answer(union dns_query *answer,int anslen,char *qname,int qtype,int had_error++; continue; } - + strcpy(bp, tbuf); global_he.h_name = bp; bp += n; @@ -408,7 +409,7 @@ struct hostent* own_gethostbyname2(char *name,int af) default: LM_ERR("Only A and AAAA queries\n"); return NULL; - } + } cached_he = (struct hostent *)dnscache_fetch_func(name,af==AF_INET?T_A:T_AAAA,0); if (cached_he == NULL) { @@ -430,7 +431,7 @@ struct hostent* own_gethostbyname2(char *name,int af) if (size < 0) { LM_DBG("Domain name not found\n"); if (dnscache_put_func(name,af==AF_INET?T_A:T_AAAA,NULL,0,1,0) < 0) - LM_ERR("Failed to store %s - %d in cache\n",name,af); + LM_ERR("Failed to store %s - %d in cache\n",name,af); return NULL; } @@ -438,16 +439,16 @@ struct hostent* own_gethostbyname2(char *name,int af) LM_ERR("Failed to get dns answer\n"); return NULL; } - + if (dnscache_put_func(name,af==AF_INET?T_A:T_AAAA,&global_he,-1,0,min_ttl) < 0) - LM_ERR("Failed to store %s - %d in cache\n",name,af); + LM_ERR("Failed to store %s - %d in cache\n",name,af); return &global_he; } inline struct hostent* resolvehost(char* name, int no_ip_test) { static struct hostent* he=0; -#ifdef HAVE_GETIPNODEBYNAME +#ifdef HAVE_GETIPNODEBYNAME int err; static struct hostent* he2=0; #endif @@ -485,7 +486,7 @@ inline struct hostent* resolvehost(char* name, int no_ip_test) else { he=gethostbyname2(name, AF_INET6); } - + #elif defined HAVE_GETIPNODEBYNAME /* on solaris 8 getipnodebyname has a memory leak, * after some time calls to it will fail with err=3 @@ -579,17 +580,17 @@ struct hostent * own_gethostbyaddr(void *addr, socklen_t len, int af) if (size < 0) { LM_DBG("ptr not found\n"); if (dnscache_put_func(addr,T_PTR,NULL,len,1,0) < 0) - LM_ERR("Failed to store PTR in cache\n"); + LM_ERR("Failed to store PTR in cache\n"); return NULL; } if (get_dns_answer(&ptr_buff,size,qbuf,T_PTR,&min_ttl) < 0) { LM_ERR("Failed to get dns answer\n"); return NULL; - } - + } + if (dnscache_put_func(addr,T_PTR,&global_he,len,0,min_ttl) < 0) - LM_ERR("Failed to store PTR in cache\n"); + LM_ERR("Failed to store PTR in cache\n"); return &global_he; } @@ -600,13 +601,13 @@ inline struct hostent* rev_resolvehost(struct ip_addr *ip) return own_gethostbyaddr((char*)(ip)->u.addr, (ip)->len, (ip)->af); } else return gethostbyaddr((char*)(ip)->u.addr, (ip)->len, (ip)->af); -} +} /*! \brief checks if ip is in host(name) and ?host(ip)=name? * ip must be in network byte order! * resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made * \return 0 if equal */ -int check_ip_address(struct ip_addr* ip, str *name, +int check_ip_address(struct ip_addr* ip, str *name, unsigned short port, unsigned short proto, int resolver) { struct hostent* he; @@ -633,7 +634,7 @@ int check_ip_address(struct ip_addr* ip, str *name, else #endif - if (strncmp(name->s, s, name->len)==0) + if (strncmp(name->s, s, name->len)==0) return 0; }else{ LM_CRIT("could not convert ip address\n"); @@ -751,7 +752,7 @@ unsigned char* dns_skipname(unsigned char* p, unsigned char* end) * \param msg - pointer to the dns message * \param end - pointer to the end of the message * \param rdata - pointer to the rdata part of the srv answer - * \return 0 on error, or a dyn. alloc'ed srv_rdata structure + * \return 0 on error, or a dyn. alloc'ed srv_rdata structure * * SRV rdata format: * 111111 @@ -773,7 +774,7 @@ struct srv_rdata* dns_srv_parser( unsigned char* msg, unsigned char* end, { struct srv_rdata* srv; int len; - + srv=0; if ((rdata+6)>=end) goto error; srv=(struct srv_rdata*)local_malloc(sizeof(struct srv_rdata)); @@ -781,7 +782,7 @@ struct srv_rdata* dns_srv_parser( unsigned char* msg, unsigned char* end, LM_ERR("out of pkg memory\n"); goto error; } - + memcpy((void*)&srv->priority, rdata, 2); memcpy((void*)&srv->weight, rdata+2, 2); memcpy((void*)&srv->port, rdata+4, 2); @@ -804,7 +805,7 @@ struct srv_rdata* dns_srv_parser( unsigned char* msg, unsigned char* end, * \param msg - pointer to the dns message * \param end - pointer to the end of the message * \param rdata - pointer to the rdata part of the naptr answer - * \return 0 on error, or a dyn. alloc'ed naptr_rdata structure + * \return 0 on error, or a dyn. alloc'ed naptr_rdata structure * * NAPTR rdata format: * 111111 @@ -831,7 +832,7 @@ struct naptr_rdata* dns_naptr_parser( unsigned char* msg, unsigned char* end, unsigned char* rdata) { struct naptr_rdata* naptr; - + naptr = 0; if ((rdata + 7) >= end) goto error; @@ -840,7 +841,7 @@ struct naptr_rdata* dns_naptr_parser( unsigned char* msg, unsigned char* end, LM_ERR("out of pkg memory\n"); goto error; } - + memcpy((void*)&naptr->order, rdata, 2); naptr->order=ntohs(naptr->order); memcpy((void*)&naptr->pref, rdata + 2, 2); @@ -877,7 +878,7 @@ struct cname_rdata* dns_cname_parser( unsigned char* msg, unsigned char* end, { struct cname_rdata* cname; int len; - + cname=0; cname=(struct cname_rdata*)local_malloc(sizeof(struct cname_rdata)); if(cname==0){ @@ -900,7 +901,7 @@ struct cname_rdata* dns_cname_parser( unsigned char* msg, unsigned char* end, struct a_rdata* dns_a_parser(unsigned char* rdata, unsigned char* end) { struct a_rdata* a; - + if (rdata+4>=end) goto error; a=(struct a_rdata*)local_malloc(sizeof(struct a_rdata)); if (a==0){ @@ -916,12 +917,12 @@ struct a_rdata* dns_a_parser(unsigned char* rdata, unsigned char* end) /*! \brief Parses an AAAA (ipv6) record rdata into an aaaa_rdata structure - * \return 0 on error or a dyn. alloc'ed aaaa_rdata struct + * \return 0 on error or a dyn. alloc'ed aaaa_rdata struct */ struct aaaa_rdata* dns_aaaa_parser(unsigned char* rdata, unsigned char* end) { struct aaaa_rdata* aaaa; - + if (rdata+16>=end) goto error; aaaa=(struct aaaa_rdata*)local_malloc(sizeof(struct aaaa_rdata)); if (aaaa==0){ @@ -946,7 +947,7 @@ struct txt_rdata* dns_txt_parser( unsigned char* msg, unsigned char* end, { struct txt_rdata* txt; unsigned int len; - + txt=0; txt=(struct txt_rdata*)local_malloc(sizeof(struct txt_rdata)); if(txt==0){ @@ -970,7 +971,7 @@ struct txt_rdata* dns_txt_parser( unsigned char* msg, unsigned char* end, } -/*! \brief parses a EBL record into a ebl_rdata structure +/*! \brief parses a EBL record into a ebl_rdata structure * * EBL Record * @@ -988,7 +989,7 @@ struct ebl_rdata* dns_ebl_parser( unsigned char* msg, unsigned char* end, { struct ebl_rdata* ebl; int len; - + ebl=0; ebl=(struct ebl_rdata*)local_malloc(sizeof(struct ebl_rdata)); if(ebl==0){ @@ -1081,16 +1082,16 @@ struct rdata* get_record(char* name, int type) head = (struct rdata *)dnscache_fetch_func(name,type,0); if (head == NULL) { LM_DBG("not found in cache or other internal error\n"); - goto query; + goto query; } else if (head == (void *)-1) { LM_DBG("previously failed query\n"); - goto not_found; + goto not_found; } else { LM_DBG("cache hit for %s - %d\n",name,type); return head; } } - + query: start_expire_timer(start,execdnsthreshold); size=res_search(name, C_IN, type, buff.buff, sizeof(buff)); @@ -1099,14 +1100,14 @@ struct rdata* get_record(char* name, int type) LM_DBG("lookup(%s, %d) failed\n", name, type); if (dnscache_put_func != NULL) { if (dnscache_put_func(name,type,NULL,0,1,0) < 0) - LM_ERR("Failed to store %s - %d in cache\n",name,type); + LM_ERR("Failed to store %s - %d in cache\n",name,type); } goto not_found; } else if ((unsigned int)size > sizeof(buff)) size=sizeof(buff); head=rd=0; last=crt=&head; - + p=buff.buff+DNS_HDR_SIZE; end=buff.buff+size; if (p>=end) goto error_boundary; @@ -1154,7 +1155,7 @@ struct rdata* get_record(char* name, int type) /* get ttl*/ memcpy((void*) &ttl, (void*)p, 4); ttl=ntohl(ttl); - if (ttl < min_ttl) + if (ttl < min_ttl) min_ttl = ttl; p+=4; /* get size */ @@ -1170,7 +1171,7 @@ struct rdata* get_record(char* name, int type) } */ /* expand the "type" record (rdata)*/ - + rd=(struct rdata*) local_malloc(sizeof(struct rdata)); if (rd==0){ LM_ERR("out of pkg memory\n"); @@ -1187,15 +1188,15 @@ struct rdata* get_record(char* name, int type) srv_rd= dns_srv_parser(buff.buff, end, p); if (srv_rd==0) goto error_parse; if (dnscache_put_func) - rdata_buf_len+=4*sizeof(unsigned short) + + rdata_buf_len+=4*sizeof(unsigned short) + sizeof(unsigned int ) + srv_rd->name_len+1; rd->rdata=(void*)srv_rd; - + /* insert sorted into the list */ for (crt=&head; *crt; crt= &((*crt)->next)){ crt_srv=(struct srv_rdata*)(*crt)->rdata; if ((srv_rd->priority < crt_srv->priority) || - ( (srv_rd->priority == crt_srv->priority) && + ( (srv_rd->priority == crt_srv->priority) && ((srv_rd->weight==0) || (crt_srv->weight!=0)) ) ){ /* insert here */ goto skip; @@ -1206,7 +1207,7 @@ struct rdata* get_record(char* name, int type) /* insert here */ rd->next=*crt; *crt=rd; - + break; case T_A: rd->rdata=(void*) dns_a_parser(p,end); @@ -1239,7 +1240,7 @@ struct rdata* get_record(char* name, int type) rd->rdata=(void*) naptr_rd; if(rd->rdata==0) goto error_parse; if (dnscache_put_func) - rdata_buf_len+=2*sizeof(unsigned short) + + rdata_buf_len+=2*sizeof(unsigned short) + 4*sizeof(unsigned int) + naptr_rd->flags_len+1 + + naptr_rd->services_len+1+naptr_rd->regexp_len + + 1 + naptr_rd->repl_len + 1; @@ -1248,7 +1249,7 @@ struct rdata* get_record(char* name, int type) break; case T_TXT: txt_rd = dns_txt_parser(buff.buff, end, p); - rd->rdata=(void*) txt_rd; + rd->rdata=(void*) txt_rd; if(rd->rdata==0) goto error_parse; if (dnscache_put_func) rdata_buf_len+=sizeof(int)+strlen(txt_rd->txt)+1; @@ -1257,11 +1258,11 @@ struct rdata* get_record(char* name, int type) break; case T_EBL: ebl_rd = dns_ebl_parser(buff.buff, end, p); - rd->rdata=(void*) ebl_rd; + rd->rdata=(void*) ebl_rd; if(rd->rdata==0) goto error_parse; if (dnscache_put_func) rdata_buf_len+=sizeof(unsigned char)+ - 2*sizeof(unsigned int)+ebl_rd->apex_len + 1 + + 2*sizeof(unsigned int)+ebl_rd->apex_len + 1 + ebl_rd->separator_len + 1; *last=rd; last=&(rd->next); @@ -1272,14 +1273,14 @@ struct rdata* get_record(char* name, int type) *last=rd; last=&(rd->next); } - + p+=rdlength; - + } if (dnscache_put_func != NULL) { if (dnscache_put_func(name,type,head,rdata_buf_len,0,min_ttl) < 0) - LM_ERR("Failed to store %s - %d in cache\n",name,type); + LM_ERR("Failed to store %s - %d in cache\n",name,type); } return head; error_boundary: @@ -1444,7 +1445,7 @@ static inline void sort_srvs(struct rdata **head) /* -> calculate running sums (and detect the end) */ weight_sum = rd2srv(rd)->running_sum = rd2srv(rd)->weight; crt = rd; - while( crt && crt->next && + while( crt && crt->next && (rd2srv(rd)->priority==rd2srv(crt->next)->priority) ) { crt = crt->next; weight_sum += rd2srv(crt)->weight; @@ -1507,7 +1508,7 @@ static inline struct hostent* do_srv_lookup(char *name, unsigned short* port, st free_rdata_list(head); return 0; } - LM_DBG("resolving [%s]\n",srv->name); + LM_DBG("resolving [%s]\n",srv->name); he = resolvehost(srv->name, 1); if ( he!=0 ) { LM_DBG("SRV(%s) = %s:%d\n", name, srv->name, srv->port); @@ -1584,7 +1585,7 @@ static inline void filter_and_sort_naptr( struct rdata** head_p, struct rdata** LM_DBG("found valid %.*s -> %s\n", (int)naptr->services_len,naptr->services, naptr->repl); - /* this is a supported service -> add it according to order to the + /* this is a supported service -> add it according to order to the * new head list */ prio = naptr_prio(get_naptr(l)); if (head==0) { @@ -1701,7 +1702,7 @@ struct hostent* sip_resolvehost(str* name, unsigned short* port, int *proto, if (head) free_rdata_list(head); } - LM_DBG("no valid NAPTR record found for %.*s," + LM_DBG("no valid NAPTR record found for %.*s," " trying direct SRV lookup...\n", name->len, name->s); *proto = (is_sips)?PROTO_TLS:PROTO_UDP; @@ -1743,8 +1744,8 @@ struct hostent* sip_resolvehost(str* name, unsigned short* port, int *proto, he = do_srv_lookup( tmp, port ); if (he) return he; - - LM_DBG("no valid SRV record found for %s," + + LM_DBG("no valid SRV record found for %s," " trying A record lookup...\n", tmp); /* set default port */ *port = (is_sips||((*proto)==PROTO_TLS))?SIPS_PORT:SIP_PORT; @@ -1823,6 +1824,10 @@ struct hostent* sip_resolvehost( str* name, unsigned short* port, goto do_srv; } + if ( dns_try_naptr==0 ) { + *proto = (is_sips)?PROTO_TLS:PROTO_UDP; + goto do_srv; + } LM_DBG("no port, no proto -> do NAPTR lookup!\n"); /* no proto, no port -> do NAPTR lookup */ if (name->len >= MAX_DNS_NAME) { @@ -1860,7 +1865,7 @@ struct hostent* sip_resolvehost( str* name, unsigned short* port, if (head) free_rdata_list(head); } - LM_DBG("no valid NAPTR record found for %.*s," + LM_DBG("no valid NAPTR record found for %.*s," " trying direct SRV lookup...\n", name->len, name->s); *proto = (is_sips)?PROTO_TLS:PROTO_UDP; @@ -1910,7 +1915,7 @@ struct hostent* sip_resolvehost( str* name, unsigned short* port, he = do_srv_lookup( tmp, port, dn); if (he) return he; - + LM_DBG("no valid SRV record found for %s, trying A record lookup...\n", tmp); /* set default port */ diff --git a/resolve.h b/resolve.h index f25595ab12a..1a9e10d40a8 100644 --- a/resolve.h +++ b/resolve.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -44,6 +44,7 @@ #include #endif +#include "mem/shm_mem.h" #include "ip_addr.h" #include "proxy.h" @@ -152,6 +153,7 @@ void free_rdata_list(struct rdata* head); extern int dns_try_ipv6; +extern int dns_try_naptr; #define HEX2I(c) \ @@ -167,6 +169,31 @@ extern int dns_try_ipv6; ( ((struct srv_rdata*)(_rdata)->rdata) ) +int check_ip_address(struct ip_addr* ip, str *name, + unsigned short port, unsigned short proto, int resolver); + +struct hostent* sip_resolvehost(str* name, unsigned short* port, + unsigned short *proto, int is_sips, struct dns_node **dn); + +inline struct hostent* resolvehost(char* name, int no_ip_test); + +inline struct hostent* rev_resolvehost(struct ip_addr *ip); + +/*! \brief free the DNS resolver state machine */ +void free_dns_res( struct proxy_l *p ); + +/*! \brief make a perfect copy of a resolver state machine */ +struct dns_node *dns_res_copy(struct dns_node *s); + +/*! \brief taked the next destination from a resolver state machine */ +int get_next_su(struct proxy_l *p, union sockaddr_union* su, int add_to_bl); + + +int resolv_init(); + +int resolv_blacklist_init(); + + /*! \brief converts a str to an ipv4 address, returns the address or 0 on error Warning: the result is a pointer to a statically allocated structure */ @@ -222,10 +249,10 @@ static inline struct ip_addr* str2ip(str* st) if (i<3) goto error_dots; ip.af=AF_INET; ip.len=4; - + return &ip; error_dots: - LM_DBG("too %s dots in [%.*s]\n", (i>3)?"many":"few", + LM_DBG("too %s dots in [%.*s]\n", (i>3)?"many":"few", st->len, st->s); return NULL; error_char: @@ -252,7 +279,7 @@ static inline struct ip_addr* str2ip6(str* st) unsigned short* addr; unsigned char* limit; unsigned char* s; - + /* init */ if ((st->len) && (st->s[0]=='[')){ /* skip over [ ] */ @@ -296,7 +323,7 @@ static inline struct ip_addr* str2ip6(str* st) } if (!double_colon){ /* not ending in ':' */ addr[i]=htons(addr[i]); - i++; + i++; } /* if address contained '::' fix it */ if (addr==addr_end){ @@ -309,7 +336,7 @@ static inline struct ip_addr* str2ip6(str* st) /* DBG("str2ip6: idx1=%d, rest=%d, no_colons=%d, hex=%x\n", idx1, rest, no_colons, hex); - DBG("str2ip6: address %x:%x:%x:%x:%x:%x:%x:%x\n", + DBG("str2ip6: address %x:%x:%x:%x:%x:%x:%x:%x\n", addr_start[0], addr_start[1], addr_start[2], addr_start[3], addr_start[4], addr_start[5], addr_start[6], addr_start[7] ); @@ -330,35 +357,53 @@ static inline struct ip_addr* str2ip6(str* st) error_char: /* - DBG("str2ip6: WARNING: unexpected char %c in [%.*s]\n", *s, st->len, + DBG("str2ip6: WARNING: unexpected char %c in [%.*s]\n", *s, st->len, st->s);*/ return 0; } -int check_ip_address(struct ip_addr* ip, str *name, - unsigned short port, unsigned short proto, int resolver); - -struct hostent* sip_resolvehost(str* name, unsigned short* port, - unsigned short *proto, int is_sips, struct dns_node **dn); - -inline struct hostent* resolvehost(char* name, int no_ip_test); - -inline struct hostent* rev_resolvehost(struct ip_addr *ip); - -/*! \brief free the DNS resolver state machine */ -void free_dns_res( struct proxy_l *p ); - -/*! \brief make a perfect copy of a resolver state machine */ -struct dns_node *dns_res_copy(struct dns_node *s); - -/*! \brief taked the next destination from a resolver state machine */ -int get_next_su(struct proxy_l *p, union sockaddr_union* su, int add_to_bl); +static inline struct proxy_l* shm_clone_proxy(struct proxy_l *sp, + unsigned int move_dn) +{ + struct proxy_l *dp; + dp = (struct proxy_l*)shm_malloc(sizeof(struct proxy_l)); + if (dp==NULL) { + LM_ERR("no more shm memory\n"); + return 0; + } + memset( dp , 0 , sizeof(struct proxy_l)); + + dp->port = sp->port; + dp->proto = sp->proto; + dp->addr_idx = sp->addr_idx; + dp->flags = PROXY_SHM_FLAG; + + /* clone the hostent */ + if (hostent_shm_cpy( &dp->host, &sp->host)!=0) + goto error0; + + /* clone the dns resolver */ + if (sp->dn) { + if (move_dn) { + dp->dn = sp->dn; + sp->dn = 0; + } else { + dp->dn = dns_res_copy(sp->dn); + if (dp->dn==NULL) + goto error1; + } + } -int resolv_init(); + return dp; +error1: + free_shm_hostent(&dp->host); +error0: + shm_free(dp); + return 0; +} -int resolv_blacklist_init(); #endif diff --git a/route.c b/route.c index d38ee69dab1..199be48bc7c 100644 --- a/route.c +++ b/route.c @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -35,7 +35,7 @@ * the ip with all the addresses (andrei) * 2003-10-10 added more operators support to comp_* (<,>,<=,>=,!=) (andrei) * 2004-10-19 added from_uri & to_uri (andrei) - * 2006-03-02 MODULE_T action points to a cmd_export_t struct instead to + * 2006-03-02 MODULE_T action points to a cmd_export_t struct instead to * a function address - more info is accessible (bogdan) * Fixup failure reports the config line (bogdan) * 2006-12-22 support for script and branch flags added (bogdan) @@ -43,12 +43,12 @@ /*! - * \file + * \file * \brief SIP routing engine */ - + #include #include #include @@ -103,7 +103,7 @@ static int fix_actions(struct action* a); /*fwd declaration*/ extern int return_code; -/*! +/*! * \brief Initialize routing lists */ void init_route_lists(void) @@ -160,14 +160,14 @@ int get_script_route_ID_by_name(char *name, struct script_route *sr, int size) } -/*! \brief traverses an expression tree and compiles the REs where necessary) - * \return 0 for ok, <0 if errors +/*! \brief traverses an expression tree and compiles the REs where necessary) + * \return 0 for ok, <0 if errors */ static int fix_expr(struct expr* exp) { regex_t* re; int ret; - + ret=E_BUG; if (exp==0){ LM_CRIT("null pointer\n"); @@ -240,7 +240,7 @@ static int fix_expr(struct expr* exp) -/*! \brief Adds the proxies in the proxy list & resolves the hostnames +/*! \brief Adds the proxies in the proxy list & resolves the hostnames * \return 0 if ok, <0 on error */ static int fix_actions(struct action* a) { @@ -257,7 +257,7 @@ static int fix_actions(struct action* a) int i = 0; str s; pv_elem_t *model=NULL; - pv_elem_t *models[5]; + pv_elem_t *models[5]; xl_level_p xlp; event_id_t ev_id; @@ -328,7 +328,7 @@ static int fix_actions(struct action* a) ret = E_CFG; goto error; } - p = add_proxy( &host,(unsigned short)port, proto); + p = mk_proxy( &host,(unsigned short)port, proto, 0); if (p==0) { LM_ERR("forward/send failed to add proxy"); ret = E_CFG; @@ -355,7 +355,7 @@ static int fix_actions(struct action* a) ret=E_BUG; goto error; } - + t->elem[1].u.data = (void*)model; t->elem[1].type = SCRIPTVAR_ELEM_ST; } @@ -414,6 +414,19 @@ static int fix_actions(struct action* a) return ret; } break; + case FOR_EACH_T: + if (t->elem[2].type != ACTIONS_ST) { + LM_CRIT("bad subtype %d in for-each (should be actions)\n", + t->elem[2].type); + ret = E_BUG; + goto error; + } + + if (t->elem[2].u.data) { + if ((ret=fix_actions((struct action*)t->elem[2].u.data))<0) + return ret; + } + break; case SWITCH_T: if ( (t->elem[1].type==ACTIONS_ST)&&(t->elem[1].u.data) ){ if ((ret=fix_actions((struct action*)t->elem[1].u.data))<0) @@ -434,7 +447,7 @@ static int fix_actions(struct action* a) break; case MODULE_T: cmd = (cmd_export_t*)t->elem[0].u.data; - LM_DBG("fixing %s, line %d\n", cmd->name, t->line); + LM_DBG("fixing %s, %s:%d\n", cmd->name, t->file, t->line); if (cmd->fixup){ if (cmd->param_no==0){ ret=cmd->fixup( 0, 0); @@ -442,9 +455,12 @@ static int fix_actions(struct action* a) } else { for (i=1; i<=cmd->param_no; i++) { - ret=cmd->fixup(&t->elem[i].u.data, i); - t->elem[i].type=MODFIXUP_ST; - if (ret<0) goto error; + /* we only call the fixup for non-null arguments */ + if (t->elem[i].type != NULLV_ST) { + ret=cmd->fixup(&t->elem[i].u.data, i); + t->elem[i].type=MODFIXUP_ST; + if (ret<0) goto error; + } } } } @@ -624,7 +640,7 @@ static int fix_actions(struct action* a) break; /* value */ - if (t->type==CACHE_FETCH_T || + if (t->type==CACHE_FETCH_T || t->type==CACHE_COUNTER_FETCH_T) { if(((pv_spec_p)t->elem[2].u.data)->setf == NULL) { @@ -657,6 +673,14 @@ static int fix_actions(struct action* a) goto error; } } + } else if (t->type==CACHE_ADD_T || t->type==CACHE_SUB_T) { + if(t->elem[4].u.data != NULL && ((pv_spec_p)t->elem[4].u.data)->setf == NULL) + { + LM_ERR("Fourth argument cannot be a read-only pvar\n"); + ret=E_CFG; + goto error; + } + } break; case SET_ADV_ADDR_T: @@ -675,6 +699,21 @@ static int fix_actions(struct action* a) } t->elem[0].u.data = (void*)model; break; + case SET_ADV_PORT_T: + if (t->elem[0].type == STR_ST) { + s.s = (char *)t->elem[0].u.data; + s.len = strlen(s.s); + + if (pv_parse_format(&s ,&model) != 0 || !model) { + LM_ERR("wrong format for [%.*s] advertised port!\n", + t->elem[1].u.s.len, t->elem[1].u.s.s); + ret = E_BUG; + goto error; + } + + t->elem[0].u.data = model; + } + break; case XDBG_T: case XLOG_T: s.s = (char*)t->elem[1].u.data; @@ -695,7 +734,7 @@ static int fix_actions(struct action* a) ret=E_BUG; goto error; } - + t->elem[0].u.data = (void*)model; t->elem[0].type = SCRIPTVAR_ELEM_ST; } @@ -725,8 +764,8 @@ static int fix_actions(struct action* a) LM_ERR("invalid level param\n"); return E_UNSPEC; } - } - else + } + else { xlp->type = 0; switch(s.s[2]) @@ -749,7 +788,7 @@ static int fix_actions(struct action* a) s.len = strlen(s.s); if (pv_parse_format(&s, &model) || model == NULL) { - LM_ERR("wrong fomat [%s] for value param\n",s.s); + LM_ERR("wrong format [%s] for value param\n",s.s); ret=E_BUG; goto error; } @@ -772,7 +811,7 @@ static int fix_actions(struct action* a) } t->elem[0].u.number = ev_id; t->elem[0].type = NUMBER_ST; - if (t->elem[1].u.data && + if (t->elem[1].u.data && ((pv_spec_p)t->elem[1].u.data)->type != PVT_AVP) { LM_ERR("second parameter should be an avp\n"); ret=E_UNSPEC; @@ -788,13 +827,13 @@ static int fix_actions(struct action* a) break; case CONSTRUCT_URI_T: for (i=0;i<5;i++) - { + { s.s = (char*)t->elem[i].u.data; s.len = strlen(s.s); - if(s.len==0) + if(s.len==0) continue; - if(pv_parse_format(&s ,&(models[i])) || models[i]==NULL) + if(pv_parse_format(&s ,&(models[i])) || models[i]==NULL) { LM_ERR("wrong format [%s] for value param!\n",s.s); ret=E_BUG; @@ -803,7 +842,7 @@ static int fix_actions(struct action* a) t->elem[i].u.data = (void*)models[i]; } - + if (((pv_spec_p)t->elem[5].u.data)->type != PVT_AVP) { LM_ERR("Wrong type for the third argument - " @@ -834,14 +873,14 @@ static int fix_actions(struct action* a) } return 0; error: - LM_ERR("fixing failed (code=%d) at cfg line %d\n", ret, t->line); + LM_ERR("fixing failed (code=%d) at %s:%d\n", ret, t->file, t->line); return ret; } inline static int comp_no( int port, void *param, int op, int subtype ) { - + if (subtype!=NUMBER_ST) { LM_CRIT("number expected: %d\n", subtype ); return E_BUG; @@ -866,7 +905,7 @@ inline static int comp_no( int port, void *param, int op, int subtype ) } /*! \brief eval_elem helping function - * \return str op param + * \return str op param */ inline static int comp_strval(struct sip_msg *msg, int op, str* ival, operand_t *opd) @@ -880,7 +919,7 @@ inline static int comp_strval(struct sip_msg *msg, int op, str* ival, if(ival==NULL || ival->s==NULL) goto error; - + res.s = 0; res.len = 0; if(opd->type == SCRIPTVAR_ST) { @@ -953,12 +992,12 @@ inline static int comp_strval(struct sip_msg *msg, int op, str* ival, goto error; } return ret; - + error: return -1; } -/*! \brief eval_elem helping function, returns str op param +/*! \brief eval_elem helping function, returns str op param */ inline static int comp_str(char* str, void* param, int op, int subtype) { @@ -999,7 +1038,7 @@ inline static int comp_str(char* str, void* param, int op, int subtype) goto error; } return ret; - + error: return -1; } @@ -1009,7 +1048,7 @@ inline static int comp_str(char* str, void* param, int op, int subtype) inline static int check_self_op(int op, str* s, unsigned short p) { int ret; - + ret=check_self(s, p, 0); switch(op){ case EQUAL_OP: @@ -1112,7 +1151,7 @@ inline static int comp_ip(struct sip_msg *msg, int op, struct ip_addr* ip, error_op: LM_CRIT("invalid operator %d\n", op); return -1; - + } /*! \brief compare str to str */ @@ -1148,7 +1187,7 @@ inline static int comp_s2s(int op, str *s1, str *s2) rt = strncasecmp(s1->s,s2->s, n); if (rt>0) ret = 1; - else if(rt==0 && s1->len>s1->len) + else if(rt==0 && s1->len>s2->len) ret = 1; else ret = 0; break; @@ -1158,7 +1197,7 @@ inline static int comp_s2s(int op, str *s1, str *s2) rt = strncasecmp(s1->s,s2->s, n); if (rt>0) ret = 1; - else if(rt==0 && s1->len>=s1->len) + else if(rt==0 && s1->len>=s2->len) ret = 1; else ret = 0; break; @@ -1168,7 +1207,7 @@ inline static int comp_s2s(int op, str *s1, str *s2) rt = strncasecmp(s1->s,s2->s, n); if (rt<0) ret = 1; - else if(rt==0 && s1->lenlen) + else if(rt==0 && s1->lenlen) ret = 1; else ret = 0; break; @@ -1178,7 +1217,7 @@ inline static int comp_s2s(int op, str *s1, str *s2) rt = strncasecmp(s1->s,s2->s, n); if (rt<0) ret = 1; - else if(rt==0 && s1->len<=s1->len) + else if(rt==0 && s1->len<=s2->len) ret = 1; else ret = 0; break; @@ -1266,6 +1305,97 @@ inline static int comp_n2n(int op, int n1, int n2) } +static inline const char *op_id_2_string(int op_id) +{ + switch (op_id) { + case EQUAL_OP: + return "EQUAL"; + case MATCH_OP: + return "REGEXP_MATCH"; + case NOTMATCH_OP: + return "REGEXP_NO_MATCH"; + case MATCHD_OP: + return "DYN_REGEXP_MATCH"; + case NOTMATCHD_OP: + return "DYN_REGEXP_NO_MATCH"; + case GT_OP: + return "GREATER_THAN"; + case LT_OP: + return "LESS_THAN"; + case GTE_OP: + return "GREATER_OR_EQUAL"; + case LTE_OP: + return "LESS_OR_EQUAL"; + case DIFF_OP: + return "DIFFERENT_THAN"; + case VALUE_OP: + return "VALUE"; + case NO_OP: + default: + return "NONE"; + } +} + + +static inline const char *expr_type_2_string(int expr_type) +{ + switch (expr_type) { + case STRING_ST: + return "STRING"; + case NET_ST: + return "NET_MASK"; + case NUMBER_ST: + return "NUMBER"; + case IP_ST: + return "IP"; + case RE_ST: + return "REGEXP"; + case PROXY_ST: + return "PROXY"; + case EXPR_ST: + return "EXPRESION"; + case ACTIONS_ST: + return "ACTION"; + case CMD_ST: + return "FUNCTION"; + case MODFIXUP_ST: + return "MOD_FIXUP"; + case MYSELF_ST: + return "MYSELF"; + case STR_ST: + return "STR"; + case SOCKID_ST: + return "SOCKET"; + case SOCKETINFO_ST: + return "SOCKET_INFO"; + case SCRIPTVAR_ST: + return "VARIABLE"; + case NULLV_ST: + return "NULL"; + case BLACKLIST_ST: + return "BLACKLIST"; + case SCRIPTVAR_ELEM_ST: + return "VARIABLE_ELEMENT"; + case NOSUBTYPE: + default: + return"NONE"; + } +} + +static inline const char *val_type_2_string(int val_type) +{ + if (val_type&PV_VAL_STR) + return "STRING_VAL"; + if (val_type&PV_VAL_INT) + return "INTEGER_VAL"; + if (val_type&PV_VAL_NULL) + return "NULL_VAL"; + if (val_type&PV_VAL_EMPTY) + return "EMPTY_VAL"; + return "NO_VAL"; +} + + inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left, operand_t *right) { @@ -1276,13 +1406,13 @@ inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left, pv_value_t lvalue; pv_value_t rvalue; int type; - + lstr.s = 0; lstr.len = 0; rstr.s = 0; rstr.len = 0; ln = 0; rn =0; if(pv_get_spec_value(msg, left->v.spec, &lvalue)!=0) { - LM_CRIT("cannot get left var value\n"); + LM_ERR("cannot get left var value\n"); goto error; } if(right->type==NULLV_ST) @@ -1302,12 +1432,13 @@ inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left, lstr = lvalue.rs; ln = lvalue.ri; type = 0; + rvalue.flags = 0; /*just for err printing purposes */ if(right->type == SCRIPTVAR_ST) { if(pv_get_spec_value(msg, right->v.spec, &rvalue)!=0) { - LM_CRIT("cannot get right var value\n"); + LM_ERR("cannot get right var value\n"); goto error; } if(rvalue.flags&PV_VAL_NULL || lvalue.flags&PV_VAL_NULL ) { @@ -1315,14 +1446,11 @@ inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left, return (op==EQUAL_OP)?1:0; return (op==DIFF_OP)?1:0; } - + if(op==MATCH_OP||op==NOTMATCH_OP) { if(!((rvalue.flags&PV_VAL_STR) && (lvalue.flags&PV_VAL_STR))) - { - LM_CRIT("invalid operation %d/%d\n", op, right->type); - goto error; - } + goto error_op; if(op==MATCH_OP) return comp_s2s(MATCHD_OP, &lstr, &rvalue.rs); else @@ -1337,11 +1465,8 @@ inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left, /* comparing string */ rstr = rvalue.rs; type =1; - } else { - LM_CRIT("invalid operation %d/%d!\n", op, - right->type); - goto error; - } + } else + goto error_op; } else { /* null against a not-null constant */ if(lvalue.flags&PV_VAL_NULL) @@ -1349,20 +1474,13 @@ inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left, if(right->type == NUMBER_ST) { if(!(lvalue.flags&PV_VAL_INT)) - { - LM_CRIT("invalid operation %d/%d/%d!!\n", op, - right->type, lvalue.flags); - goto error; - } + goto error_op; /* comparing int */ type =2; rn = right->v.n; } else if(right->type == STR_ST) { if(!(lvalue.flags&PV_VAL_STR)) - { - LM_CRIT("invalid operation %d/%d!!!\n", op, right->type); - goto error; - } + goto error_op; /* comparing string */ type =1; rstr = right->v.s; @@ -1370,10 +1488,7 @@ inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left, if(op==MATCH_OP || op==NOTMATCH_OP) { if(!(lvalue.flags&PV_VAL_STR) || right->type != RE_ST) - { - LM_CRIT("invalid operation %d/%d\n", op, right->type); - goto error; - } + goto error_op; return comp_s2s(op, &lstr, (str*)right->v.expr); } /* comparing others */ @@ -1382,22 +1497,26 @@ inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left, } if(type==1) { /* compare str */ - LM_DBG("str %d : %.*s\n", op, lstr.len, ZSW(lstr.s)); + LM_DBG("str %d : %.*s\n", op, lstr.len, ZSW(lstr.s)); return comp_s2s(op, &lstr, &rstr); } else if(type==2) { - LM_DBG("int %d : %d / %d\n", op, ln, rn); + LM_DBG("int %d : %d / %d\n", op, ln, rn); return comp_n2n(op, ln, rn); - } else { - LM_CRIT("invalid operation %d/%d\n", op, right->type); } - + /* default is error */ + +error_op: + LM_WARN("invalid %s operation: left is %s/%s, right is %s/%s\n", + op_id_2_string(op), + expr_type_2_string(left->type), val_type_2_string(lvalue.flags), + expr_type_2_string(right->type), val_type_2_string(rvalue.flags) ); error: return -1; } -/*! \brief - * \return 0/1 (false/true) or -1 on error, -127 EXPR_DROP +/*! \brief + * \return 0/1 (false/true) or -1 on error, -127 EXPR_DROP */ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) { @@ -1411,13 +1530,13 @@ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) pv_value_t rval; char *p; int i,n; - + ret=E_BUG; if (e->type!=ELEM_T){ LM_CRIT("invalid type\n"); goto error; } - + if(val) memset(val, 0, sizeof(pv_value_t)); switch(e->left.type){ @@ -1540,7 +1659,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) if(e->right.v.data) eval_expr((struct expr*)e->right.v.data,msg,&rval); /* retr=eval_expr((struct expr*)e->right.v.data,msg,&rval); */ - + if(lval.flags&PV_TYPE_INT) { if( (rval.flags&PV_VAL_NULL) ) @@ -1571,7 +1690,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; - } else + } else ival = lval.ri / rval.ri; break; case MULT_OP: @@ -1584,7 +1703,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) pv_value_destroy(&lval); pv_value_destroy(&rval); return 0; - } else + } else ival = lval.ri % rval.ri; break; case BAND_OP: @@ -1697,13 +1816,13 @@ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) } break; case SRCPORT_O: - ret=comp_no(msg->rcv.src_port, + ret=comp_no(msg->rcv.src_port, e->right.v.data, /* e.g., 5060 */ e->op, /* e.g. == */ e->right.type /* 5060 is number */); break; case DSTPORT_O: - ret=comp_no(msg->rcv.dst_port, e->right.v.data, e->op, + ret=comp_no(msg->rcv.dst_port, e->right.v.data, e->op, e->right.type); break; case PROTO_O: @@ -1771,7 +1890,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) memcpy(val, &lval, sizeof(pv_value_t)); if(lval.flags&PV_VAL_STR) { - if(!((lval.flags&PV_VAL_PKG) + if(!((lval.flags&PV_VAL_PKG) || (lval.flags&PV_VAL_SHM))) { if(val!=NULL) @@ -1793,7 +1912,7 @@ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) } return 1; } - if(lval.flags==PV_VAL_NONE + if(lval.flags==PV_VAL_NONE || (lval.flags & PV_VAL_NULL) || (lval.flags & PV_VAL_EMPTY)) return 0; @@ -1827,19 +1946,19 @@ static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val) -/*! \return ret= 0/1 (true/false) , -1 on error or EXPR_DROP (-127) */ +/*! \return ret= 0/1 (false/true) , -1 on error or EXPR_DROP (-127) */ int eval_expr(struct expr* e, struct sip_msg* msg, pv_value_t *val) { static int rec_lev=0; int ret; - + rec_lev++; if (rec_lev>MAX_REC_LEV){ LM_CRIT("too many expressions (%d)\n", rec_lev); ret=-1; goto skip; } - + if (e->type==ELEM_T){ ret=eval_elem(e, msg, val); }else if (e->type==EXP_T){ @@ -1901,15 +2020,15 @@ int add_actions(struct action* a, struct action** head) if ((ret=fix_actions(a))!=0) goto error; push(a,head); return 0; - + error: return ret; } -/*! \brief fixes all action tables - * \return 0 if ok , <0 on error +/*! \brief fixes all action tables + * \return 0 if ok , <0 on error */ int fix_rls(void) { @@ -2020,6 +2139,10 @@ static int check_actions(struct action *a, int r_type) if (check_actions((struct action*)a->elem[1].u.data, r_type)!=0) goto error; break; + case FOR_EACH_T: + if (check_actions((struct action*)a->elem[2].u.data, r_type)!=0) + goto error; + break; case SWITCH_T: aitem = (struct action*)a->elem[1].u.data; for( ; aitem ; aitem=aitem->next ) { @@ -2054,7 +2177,7 @@ static int check_actions(struct action *a, int r_type) /*! \brief check all routing tables for compatiblity between * route types and called module functions; - * \return 0 if ok , <0 on error + * \return 0 if ok , <0 on error */ int check_rls(void) { @@ -2119,7 +2242,7 @@ int check_rls(void) LM_ERR("check failed for timer_route\n"); return ret; } - + } for(i = 1; i< EVENT_RT_NO; i++) { @@ -2130,7 +2253,7 @@ int check_rls(void) LM_ERR("check failed for event_route\n"); return ret; } - + } @@ -2181,6 +2304,56 @@ void print_rl(void) } } + +int is_script_func_used( char *name, int param_no) +{ + unsigned int i; + + for( i=0; iMAX_ACTION_ELEMS) { - LM_ERR("too many action elements at line %d for %d", line, type); + LM_ERR("too many action elements at %s:%d for %d", + file, line, type); return 0; } @@ -117,9 +119,10 @@ struct action* mk_action(int type, int n, action_elem_t *elem, int line) } a->line = line; + a->file = file; a->next=0; return a; - + error: LM_CRIT("pkg memory allocation failure\n"); return 0; @@ -132,7 +135,7 @@ struct action* append_action(struct action* a, struct action* b) struct action *t; if (b==0) return a; if (a==0) return b; - + for(t=a;t->next;t=t->next); t->next=b; return a; @@ -258,7 +261,7 @@ void print_expr(struct expr* exp) LM_DBG("", exp->op); } switch(exp->right.type){ - case NOSUBTYPE: + case NOSUBTYPE: /* LM_DBG("N/A"); */ break; case STRING_ST: @@ -307,7 +310,7 @@ void print_expr(struct expr* exp) print_expr(exp->right.v.expr); LM_DBG(" )"); break; - case NOT_OP: + case NOT_OP: LM_DBG("NOT( "); print_expr(exp->left.v.expr); LM_DBG(" )"); @@ -395,7 +398,7 @@ void print_expr(struct expr* exp) default: LM_DBG("UNKNOWN_EXP[%d] ", exp->op); } - + }else{ LM_ERR("unknown type\n"); } @@ -411,6 +414,9 @@ void print_action(struct action* t) case SEND_T: LM_DBG("send("); break; + case ASSERT_T: + LM_DBG("assert("); + break; case DROP_T: LM_DBG("drop("); break; @@ -625,13 +631,64 @@ void print_action(struct action* t) else LM_DBG("); "); } - + void print_actions(struct action* a) { while(a) { print_action(a); a = a->next; } -} +} + + +static int is_mod_func_in_expr(struct expr *e, char *name, int param_no) +{ + if (e->type==ELEM_T) { + if (e->left.type==ACTION_O) + if (is_mod_func_used((struct action*)e->right.v.data,name,param_no)==1) + return 1; + } else if (e->type==EXP_T) { + if (e->left.v.expr && is_mod_func_in_expr(e->left.v.expr,name,param_no)==1) + return 1; + if (e->right.v.expr && is_mod_func_in_expr(e->right.v.expr,name,param_no)==1) + return 1; + } + return 0; +} +int is_mod_func_used(struct action *a, char *name, int param_no) +{ + cmd_export_t *cmd; + while(a) { + if (a->type==MODULE_T) { + /* first param is the name of the function */ + cmd = (cmd_export_t*)a->elem[0].u.data; + LM_DBG("checking %s against %s\n",name,cmd->name); + if (strcasecmp(cmd->name, name)==0 && + (param_no==cmd->param_no || param_no==-1) ) + return 1; + } + + if (a->type==IF_T || a->type==WHILE_T) + if (is_mod_func_in_expr((struct expr*)a->elem[0].u.data,name,param_no)==1) + return 1; + + /* follow all leads from actions than may have sub-blocks of instructions */ + if (a->elem[0].type==ACTIONS_ST) + if (is_mod_func_used((struct action*)a->elem[0].u.data,name,param_no)==1) + return 1; + + if (a->elem[1].type==ACTIONS_ST) + if (is_mod_func_used((struct action*)a->elem[1].u.data,name,param_no)==1) + return 1; + + if (a->elem[2].type==ACTIONS_ST) + if (is_mod_func_used((struct action*)a->elem[2].u.data,name,param_no)==1) + return 1; + + a = a->next; + } + + return 0; +} diff --git a/route_struct.h b/route_struct.h index e392a9c0ef7..a9006abdfe2 100644 --- a/route_struct.h +++ b/route_struct.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -31,7 +31,7 @@ */ /*! - * \file + * \file * \brief SIP routing engine - structure management */ @@ -44,25 +44,25 @@ * Other important values (no macros for them yet): * expr true = 1 * expr false = 0 (used only inside the expression and if evaluator) - * + * * action continue or if used in condition true = 1 * action drop/quit/stop script processing = 0 * action error or if used in condition false = -1 (<0 and !=EXPR_DROP) - * + * */ /*! \todo Add documentation for all ENUMs in this file. */ enum { EXP_T=1, ELEM_T }; enum { AND_OP=1, OR_OP, NOT_OP, EVAL_OP, PLUS_OP, MINUS_OP, DIV_OP, MULT_OP, MODULO_OP, BAND_OP, BOR_OP, BXOR_OP, BNOT_OP, BLSHIFT_OP, BRSHIFT_OP }; -enum { EQUAL_OP=20, MATCH_OP, NOTMATCH_OP, MATCHD_OP, NOTMATCHD_OP, +enum { EQUAL_OP=20, MATCH_OP, NOTMATCH_OP, MATCHD_OP, NOTMATCHD_OP, GT_OP, LT_OP, GTE_OP, LTE_OP, DIFF_OP, VALUE_OP, NO_OP }; enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O, DSTIP_O, DSTPORT_O, PROTO_O, AF_O, MSGLEN_O, DEFAULT_O, ACTION_O, EXPR_O, NUMBER_O, NUMBERV_O, STRINGV_O, RETCODE_O, SCRIPTVAR_O}; -enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T, - SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, +enum { FORWARD_T=1, SEND_T, ASSERT_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T, + SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, SET_PORT_T, SET_URI_T, IF_T, MODULE_T, SET_DEBUG_T, SETFLAG_T, RESETFLAG_T, ISFLAGSET_T , SETSFLAG_T, RESETSFLAG_T, ISSFLAGSET_T , @@ -82,7 +82,7 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T, RETURN_T, EXIT_T, SWITCH_T, CASE_T, DEFAULT_T, SBREAK_T, - WHILE_T, + WHILE_T, FOR_EACH_T, SET_DSTURI_T, SET_DSTHOST_T, SET_DSTPORT_T, RESET_DSTURI_T, ISDSTURISET_T, EQ_T, COLONEQ_T, PLUSEQ_T, MINUSEQ_T, DIVEQ_T, MULTEQ_T, MODULOEQ_T, BANDEQ_T, BOREQ_T, BXOREQ_T, USE_BLACKLIST_T, UNUSE_BLACKLIST_T, @@ -111,7 +111,7 @@ typedef struct operand { int n; pv_spec_t* spec; void* data; - } v; + } v; } operand_t, *operand_p; @@ -135,13 +135,14 @@ typedef struct action_elem_ { /*! \brief increase MAX_ACTION_ELEMS to support more module function parameters if you change this define, you need also to change the assignment in - the action.c file + the action.c file */ #define MAX_ACTION_ELEMS 7 struct action{ int type; /* forward, drop, log, send ...*/ action_elem_t elem[MAX_ACTION_ELEMS]; int line; + char *file; struct action* next; }; @@ -149,13 +150,15 @@ struct action{ struct expr* mk_exp(int op, struct expr* left, struct expr* right); struct expr* mk_elem(int op, int leftt, void *leftd, int rightt, void *rightd); -struct action* mk_action(int type, int n, action_elem_t *elem, int line); +struct action* mk_action(int type, int n, action_elem_t *elem, + int line, char *file); struct action* append_action(struct action* a, struct action* b); void print_action(struct action* a); void print_expr(struct expr* exp); void print_actions(struct action* a); +int is_mod_func_used(struct action *a, char *name, int param_no); diff --git a/rw_locking.h b/rw_locking.h index c42a8b8c531..6f2266b243c 100644 --- a/rw_locking.h +++ b/rw_locking.h @@ -50,6 +50,7 @@ inline static void lock_destroy_rw(rw_lock_t *_lock) #define lock_start_write(_lock) \ do { \ + __label__ again; \ again: \ lock_get((_lock)->lock); \ /* wait for the other writers */ \ @@ -72,6 +73,7 @@ inline static void lock_destroy_rw(rw_lock_t *_lock) #define lock_start_read(_lock) \ do { \ + __label__ again; \ again: \ lock_get((_lock)->lock); \ if ((_lock)->w_flag) { \ diff --git a/script_cb.c b/script_cb.c index 956c2921e4f..da9384f6e9c 100644 --- a/script_cb.c +++ b/script_cb.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -24,7 +24,7 @@ * 2003-03-29 cleaning pkg allocation introduced (jiri) * 2003-03-19 replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei) * 2005-02-13 script callbacks devided into request and reply types (bogdan) - * 2009-05-21 keep the callback lists in the same order as callbacks + * 2009-05-21 keep the callback lists in the same order as callbacks were registered (bogdan) */ @@ -50,9 +50,11 @@ static struct script_cb *parse_err_cb=0; static unsigned int cb_id=0; +raw_processing_func pre_processing_cb = NULL; +raw_processing_func post_processing_cb = NULL; static inline int add_callback( struct script_cb **list, - cb_function f, void *param) + cb_function f, void *param, int prio) { struct script_cb *last_cb; struct script_cb *new_cb; @@ -66,20 +68,31 @@ static inline int add_callback( struct script_cb **list, new_cb->id = cb_id++; new_cb->param = param; new_cb->next = NULL; - /* link at the end of the list - it is important to keep the order of - register time, as this reflects the order of loading/init the modules - -bogdan */ + new_cb->prio = prio; + + /* descending priority sorting; equal priorities are inserted at the end + it is important to keep the order at register time, as this reflects the + order of loading/init the modules --bogdan */ if (*list==NULL) { *list = new_cb; + } else if ((*list)->prio < prio) { + new_cb->next = *list; + *list = new_cb; } else { - for( last_cb=*list ; last_cb->next!=NULL ; last_cb=last_cb->next); + for (last_cb = *list; + last_cb->next && last_cb->next->prio >= prio; + last_cb = last_cb->next) + ; + + new_cb->next = last_cb->next; last_cb->next = new_cb; } + return 0; } -int register_script_cb( cb_function f, int type, void *param ) +int __register_script_cb( cb_function f, int type, void *param, int prio) { /* type checkings */ if ( (type&(REQ_TYPE_CB|RPL_TYPE_CB|PARSE_ERR_CB))==0 ) { @@ -93,27 +106,27 @@ int register_script_cb( cb_function f, int type, void *param ) } if (type&PARSE_ERR_CB) { - if (add_callback( &parse_err_cb, f, param)<0) + if (add_callback( &parse_err_cb, f, param, prio)<0) goto add_error; } if (type&REQ_TYPE_CB) { /* callback for request script */ if (type&PRE_SCRIPT_CB) { - if (add_callback( &pre_req_cb, f, param)<0) + if (add_callback( &pre_req_cb, f, param, prio)<0) goto add_error; } else if (type&POST_SCRIPT_CB) { - if (add_callback( &post_req_cb, f, param)<0) + if (add_callback( &post_req_cb, f, param, prio)<0) goto add_error; } } if (type&RPL_TYPE_CB) { /* callback (also) for reply script */ if (type&PRE_SCRIPT_CB) { - if (add_callback( &pre_rpl_cb, f, param)<0) + if (add_callback( &pre_rpl_cb, f, param, prio)<0) goto add_error; } else if (type&POST_SCRIPT_CB) { - if (add_callback( &post_rpl_cb, f, param)<0) + if (add_callback( &post_rpl_cb, f, param, prio)<0) goto add_error; } } @@ -150,12 +163,16 @@ void destroy_script_cb(void) static inline int exec_pre_cb( struct sip_msg *msg, struct script_cb *cb) { + int bitmask = SCB_RUN_ALL; + for ( ; cb ; cb=cb->next ) { - /* stop on error */ - if (cb->cbf(msg, cb->param)==0) - return 0; + bitmask &= cb->cbf(msg, cb->param); + + if (bitmask == SCB_DROP_MSG) + break; } - return 1; + + return bitmask; } @@ -193,4 +210,46 @@ int exec_parse_err_cb( struct sip_msg *msg) return exec_post_cb( msg, parse_err_cb); } +/* currently no need for raw processing lists - FIXME to be extended if needed in the future */ +int register_raw_processing_cb(raw_processing_func f,int type) +{ + switch (type) { + case PRE_RAW_PROCESSING: + if (pre_processing_cb != NULL) { + LM_WARN("Overwriting the raw pre processing CB \n"); + } + pre_processing_cb = f; + return 0; + case POST_RAW_PROCESSING: + if (post_processing_cb != NULL) { + LM_WARN("Overwriting the raw post processing CB \n"); + } + post_processing_cb = f; + return 0; + default: + LM_ERR("Unrecognized raw processing CB type %d \n",type); + } + + return -1; +} + +int run_raw_processing_cb(int type,str *data) +{ + switch (type) { + case PRE_RAW_PROCESSING: + if (pre_processing_cb != NULL) { + return pre_processing_cb(data); + } + return 0; + case POST_RAW_PROCESSING: + if (post_processing_cb != NULL) { + return post_processing_cb(data); + } + return 0; + default: + LM_ERR("Unrecognized raw processing CB type %d \n",type); + } + + return -1; +} diff --git a/script_cb.h b/script_cb.h index e5fcbeae66c..64b96a18cc5 100644 --- a/script_cb.h +++ b/script_cb.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -34,8 +34,20 @@ #include "parser/msg_parser.h" +/** + * @return: + * - SCB_DROP_MSG stops the processing (also skips any other callbacks) + * - a combination of the SCB_ flags or SCB_RUN_ALL for any other cases + * + * NB: return values are logically AND'ed + * (one module may wish to skip top route, others may skip post callbacks) + */ typedef int (cb_function)( struct sip_msg *msg, void *param ); +#define SCB_DROP_MSG 0 +#define SCB_RUN_TOP_ROUTE (1<<0) +#define SCB_RUN_POST_CBS (1<<1) +#define SCB_RUN_ALL (SCB_RUN_TOP_ROUTE | SCB_RUN_POST_CBS) #define PRE_SCRIPT_CB (1<<0) #define POST_SCRIPT_CB (1<<1) @@ -43,15 +55,23 @@ typedef int (cb_function)( struct sip_msg *msg, void *param ); #define RPL_TYPE_CB (1<<3) #define PARSE_ERR_CB (1<<4) +typedef int (*raw_processing_func)(str *data); +#define PRE_RAW_PROCESSING (1<<0) +#define POST_RAW_PROCESSING (1<<1) -struct script_cb{ +struct script_cb { cb_function *cbf; struct script_cb *next; unsigned int id; void *param; + int prio; /* allows callback ordering; highest runs first */ }; -int register_script_cb( cb_function f, int type, void *param ); +#define register_script_cb(func, type, param) \ + __register_script_cb(func, type, param, 0) + +/* sorted by priority in descending order (highest prio callback runs first) */ +int __register_script_cb( cb_function f, int type, void *param, int prio); void destroy_script_cb(); int exec_pre_req_cb( struct sip_msg *msg); @@ -62,5 +82,8 @@ int exec_post_rpl_cb( struct sip_msg *msg); int exec_parse_err_cb( struct sip_msg *msg); +int register_raw_processing_cb(raw_processing_func f,int type); +int run_raw_processing_cb(int type,str *data); + #endif diff --git a/script_var.c b/script_var.c index 9695facd226..852ba423cdb 100644 --- a/script_var.c +++ b/script_var.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/script_var.h b/script_var.h index 92276d94cee..005ebca57fc 100644 --- a/script_var.h +++ b/script_var.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/scripts/db_berkeley/opensips/b2b_sca b/scripts/db_berkeley/opensips/b2b_sca new file mode 100644 index 00000000000..6e5795e9f81 --- /dev/null +++ b/scripts/db_berkeley/opensips/b2b_sca @@ -0,0 +1,10 @@ +METADATA_COLUMNS +id(int) shared_line(str) watchers(str) app1_shared_entity(int) app1_call_state(int) app1_call_info_uri(str) app1_call_info_appearance_uri(str) app1_b2bl_key(str) app2_shared_entity(int) app2_call_state(int) app2_call_info_uri(str) app2_call_info_appearance_uri(str) app2_b2bl_key(str) app3_shared_entity(int) app3_call_state(int) app3_call_info_uri(str) app3_call_info_appearance_uri(str) app3_b2bl_key(str) app4_shared_entity(int) app4_call_state(int) app4_call_info_uri(str) app4_call_info_appearance_uri(str) app4_b2bl_key(str) app5_shared_entity(int) app5_call_state(int) app5_call_info_uri(str) app5_call_info_appearance_uri(str) app5_b2bl_key(str) app6_shared_entity(int) app6_call_state(int) app6_call_info_uri(str) app6_call_info_appearance_uri(str) app6_b2bl_key(str) app7_shared_entity(int) app7_call_state(int) app7_call_info_uri(str) app7_call_info_appearance_uri(str) app7_b2bl_key(str) app8_shared_entity(int) app8_call_state(int) app8_call_info_uri(str) app8_call_info_appearance_uri(str) app8_b2bl_key(str) app9_shared_entity(int) app9_call_state(int) app9_call_info_uri(str) app9_call_info_appearance_uri(str) app9_b2bl_key(str) app10_shared_entity(int) app10_call_state(int) app10_call_info_uri(str) app10_call_info_appearance_uri(str) app10_b2bl_key(str) +METADATA_KEY + +METADATA_READONLY +0 +METADATA_LOGFLAGS +0 +METADATA_DEFAULTS +NIL|NIL|NIL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL diff --git a/scripts/db_berkeley/opensips/cc_agents b/scripts/db_berkeley/opensips/cc_agents new file mode 100644 index 00000000000..402630dbde5 --- /dev/null +++ b/scripts/db_berkeley/opensips/cc_agents @@ -0,0 +1,10 @@ +METADATA_COLUMNS +id(int) agentid(str) location(str) logstate(int) skills(str) last_call_end(int) +METADATA_KEY + +METADATA_READONLY +0 +METADATA_LOGFLAGS +0 +METADATA_DEFAULTS +NIL|NIL|NIL|0|NIL|0 diff --git a/scripts/db_berkeley/opensips/cc_calls b/scripts/db_berkeley/opensips/cc_calls new file mode 100644 index 00000000000..ad5d46e671f --- /dev/null +++ b/scripts/db_berkeley/opensips/cc_calls @@ -0,0 +1,10 @@ +METADATA_COLUMNS +id(int) state(int) ig_cback(int) no_rej(int) setup_time(int) eta(int) last_start(int) recv_time(int) caller_dn(str) caller_un(str) b2buaid(str) flow(str) agent(str) +METADATA_KEY +0 +METADATA_READONLY +0 +METADATA_LOGFLAGS +0 +METADATA_DEFAULTS +NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|''|NIL|NIL diff --git a/scripts/db_berkeley/opensips/cc_cdrs b/scripts/db_berkeley/opensips/cc_cdrs new file mode 100644 index 00000000000..c2586ab1db7 --- /dev/null +++ b/scripts/db_berkeley/opensips/cc_cdrs @@ -0,0 +1,10 @@ +METADATA_COLUMNS +id(int) caller(str) received_timestamp(datetime) wait_time(int) pickup_time(int) talk_time(int) flow_id(str) agent_id(str) call_type(int) rejected(int) fstats(int) cid(int) +METADATA_KEY +0 +METADATA_READONLY +0 +METADATA_LOGFLAGS +0 +METADATA_DEFAULTS +NIL|NIL|NIL|0|0|0|NIL|NULL|-1|0|0|0 diff --git a/scripts/db_berkeley/opensips/cc_flows b/scripts/db_berkeley/opensips/cc_flows new file mode 100644 index 00000000000..55ed0ff5cfb --- /dev/null +++ b/scripts/db_berkeley/opensips/cc_flows @@ -0,0 +1,10 @@ +METADATA_COLUMNS +id(int) flowid(str) priority(int) skill(str) prependcid(str) message_welcome(str) message_queue(str) +METADATA_KEY + +METADATA_READONLY +0 +METADATA_LOGFLAGS +0 +METADATA_DEFAULTS +NIL|NIL|256|NIL|NIL|NULL|NIL diff --git a/scripts/db_berkeley/opensips/dialog b/scripts/db_berkeley/opensips/dialog index 4a47ddc741b..d8cd25dd5a0 100644 --- a/scripts/db_berkeley/opensips/dialog +++ b/scripts/db_berkeley/opensips/dialog @@ -1,5 +1,5 @@ METADATA_COLUMNS -dlg_id(int) callid(str) from_uri(str) from_tag(str) to_uri(str) to_tag(str) mangled_from_uri(str) mangled_to_uri(str) caller_cseq(str) callee_cseq(str) caller_ping_cseq(int) callee_ping_cseq(int) caller_route_set(str) callee_route_set(str) caller_contact(str) callee_contact(str) caller_sock(str) callee_sock(str) state(int) start_time(int) timeout(int) vars(str) profiles(str) script_flags(int) flags(int) +dlg_id(int) callid(str) from_uri(str) from_tag(str) to_uri(str) to_tag(str) mangled_from_uri(str) mangled_to_uri(str) caller_cseq(str) callee_cseq(str) caller_ping_cseq(int) callee_ping_cseq(int) caller_route_set(str) callee_route_set(str) caller_contact(str) callee_contact(str) caller_sock(str) callee_sock(str) state(int) start_time(int) timeout(int) vars(str) profiles(str) script_flags(int) module_flags(int) flags(int) METADATA_KEY METADATA_READONLY @@ -7,4 +7,4 @@ METADATA_READONLY METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|NIL|NIL|NIL|NIL|NIL|NULL|NULL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NULL|NULL|0|0 +NIL|NIL|NIL|NIL|NIL|NIL|NULL|NULL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NULL|NULL|0|0|0 diff --git a/scripts/db_berkeley/opensips/dialplan b/scripts/db_berkeley/opensips/dialplan index 425a4162c58..d1dc1351c85 100644 --- a/scripts/db_berkeley/opensips/dialplan +++ b/scripts/db_berkeley/opensips/dialplan @@ -1,5 +1,5 @@ METADATA_COLUMNS -id(int) dpid(int) pr(int) match_op(int) match_exp(str) match_flags(int) subst_exp(str) repl_exp(str) disabled(int) attrs(str) +id(int) dpid(int) pr(int) match_op(int) match_exp(str) match_flags(int) subst_exp(str) repl_exp(str) timerec(str) disabled(int) attrs(str) METADATA_KEY 0 METADATA_READONLY @@ -7,4 +7,4 @@ METADATA_READONLY METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|0|NIL +NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|0|NIL diff --git a/scripts/db_berkeley/opensips/dispatcher b/scripts/db_berkeley/opensips/dispatcher index 2b0117a4e9b..b417a91edfd 100644 --- a/scripts/db_berkeley/opensips/dispatcher +++ b/scripts/db_berkeley/opensips/dispatcher @@ -1,10 +1,10 @@ METADATA_COLUMNS -id(int) setid(int) destination(str) socket(str) flags(int) weight(int) attrs(str) description(str) +id(int) setid(int) destination(str) socket(str) state(int) weight(int) priority(int) attrs(str) description(str) METADATA_KEY -1 4 5 +1 4 5 6 METADATA_READONLY 0 METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|0|''|NULL|0|1|''|'' +NIL|0|''|NULL|0|1|0|''|'' diff --git a/scripts/db_berkeley/opensips/domain b/scripts/db_berkeley/opensips/domain index 0463a6ed948..dc6d903eb2f 100644 --- a/scripts/db_berkeley/opensips/domain +++ b/scripts/db_berkeley/opensips/domain @@ -1,5 +1,5 @@ METADATA_COLUMNS -id(int) domain(str) last_modified(datetime) +id(int) domain(str) attrs(str) last_modified(datetime) METADATA_KEY 1 METADATA_READONLY @@ -7,4 +7,4 @@ METADATA_READONLY METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|''|'1900-01-01 00:00:01' +NIL|''|NULL|'1900-01-01 00:00:01' diff --git a/scripts/db_berkeley/opensips/dr_carriers b/scripts/db_berkeley/opensips/dr_carriers index debe048ceb9..a4f7dd1a4cc 100644 --- a/scripts/db_berkeley/opensips/dr_carriers +++ b/scripts/db_berkeley/opensips/dr_carriers @@ -1,5 +1,5 @@ METADATA_COLUMNS -id(int) carrierid(str) gwlist(str) flags(int) attrs(str) description(str) +id(int) carrierid(str) gwlist(str) flags(int) state(int) attrs(str) description(str) METADATA_KEY 0 METADATA_READONLY @@ -7,4 +7,4 @@ METADATA_READONLY METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|NIL|NIL|0|''|'' +NIL|NIL|NIL|0|0|''|'' diff --git a/scripts/db_berkeley/opensips/dr_gateways b/scripts/db_berkeley/opensips/dr_gateways index 17c42deadc6..170d81deac1 100644 --- a/scripts/db_berkeley/opensips/dr_gateways +++ b/scripts/db_berkeley/opensips/dr_gateways @@ -1,5 +1,5 @@ METADATA_COLUMNS -id(int) gwid(str) type(int) address(str) strip(int) pri_prefix(str) attrs(str) probe_mode(int) description(str) +id(int) gwid(str) type(int) address(str) strip(int) pri_prefix(str) attrs(str) probe_mode(int) state(int) socket(str) description(str) METADATA_KEY 0 METADATA_READONLY @@ -7,4 +7,4 @@ METADATA_READONLY METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|NIL|0|NIL|0|NULL|NULL|0|'' +NIL|NIL|0|NIL|0|NULL|NULL|0|0|NULL|'' diff --git a/scripts/db_berkeley/opensips/dr_gw_lists b/scripts/db_berkeley/opensips/dr_gw_lists deleted file mode 100644 index fe1af479620..00000000000 --- a/scripts/db_berkeley/opensips/dr_gw_lists +++ /dev/null @@ -1,10 +0,0 @@ -METADATA_COLUMNS -id(int) gwlist(str) description(str) -METADATA_KEY -0 -METADATA_READONLY -0 -METADATA_LOGFLAGS -0 -METADATA_DEFAULTS -NIL|NIL|'' diff --git a/scripts/db_berkeley/opensips/dr_partitions b/scripts/db_berkeley/opensips/dr_partitions new file mode 100644 index 00000000000..b826ecadda9 --- /dev/null +++ b/scripts/db_berkeley/opensips/dr_partitions @@ -0,0 +1,10 @@ +METADATA_COLUMNS +id(int) partition_name(str) db_url(str) drd_table(str) drr_table(str) drg_table(str) drc_table(str) ruri_avp(str) gw_id_avp(str) gw_priprefix_avp(str) gw_sock_avp(str) rule_id_avp(str) rule_prefix_avp(str) carrier_id_avp(str) +METADATA_KEY +0 +METADATA_READONLY +0 +METADATA_LOGFLAGS +0 +METADATA_DEFAULTS +NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL diff --git a/scripts/db_berkeley/opensips/location b/scripts/db_berkeley/opensips/location index 972d19c5eec..52b135cba37 100644 --- a/scripts/db_berkeley/opensips/location +++ b/scripts/db_berkeley/opensips/location @@ -1,5 +1,5 @@ METADATA_COLUMNS -id(int) username(str) domain(str) contact(str) received(str) path(str) expires(datetime) q(double) callid(str) cseq(int) last_modified(datetime) flags(int) cflags(int) user_agent(str) socket(str) methods(int) sip_instance(str) +id(int) username(str) domain(str) contact(str) received(str) path(str) expires(datetime) q(double) callid(str) cseq(int) last_modified(datetime) flags(int) cflags(str) user_agent(str) socket(str) methods(int) sip_instance(str) attr(str) METADATA_KEY 1 2 METADATA_READONLY @@ -7,4 +7,4 @@ METADATA_READONLY METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|''|''|''|NULL|NULL|'2020-05-28 21:32:15'|1.0|'Default-Call-ID'|13|'1900-01-01 00:00:01'|0|0|''|NULL|NULL|NULL +NIL|''|''|''|NULL|NULL|'2020-05-28 21:32:15'|1.0|'Default-Call-ID'|13|'1900-01-01 00:00:01'|0|NULL|''|NULL|NULL|NULL|NULL diff --git a/scripts/db_berkeley/opensips/silo b/scripts/db_berkeley/opensips/silo index c164e3d53c5..472ed6bfa56 100644 --- a/scripts/db_berkeley/opensips/silo +++ b/scripts/db_berkeley/opensips/silo @@ -7,4 +7,4 @@ METADATA_READONLY METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|''|''|''|''|0|0|0|'text/plain'|'' +NIL|''|''|''|''|0|0|0|NULL|NIL diff --git a/scripts/db_berkeley/opensips/sip_trace b/scripts/db_berkeley/opensips/sip_trace index e51f4e182d7..4866a15e161 100644 --- a/scripts/db_berkeley/opensips/sip_trace +++ b/scripts/db_berkeley/opensips/sip_trace @@ -1,5 +1,5 @@ METADATA_COLUMNS -id(int) time_stamp(datetime) callid(str) traced_user(str) msg(str) method(str) status(str) fromip(str) toip(str) fromtag(str) direction(str) +id(int) time_stamp(datetime) callid(str) traced_user(str) msg(str) method(str) status(str) from_proto(str) from_ip(str) from_port(int) to_proto(str) to_ip(str) to_port(int) fromtag(str) direction(str) METADATA_KEY 2 METADATA_READONLY @@ -7,4 +7,4 @@ METADATA_READONLY METADATA_LOGFLAGS 0 METADATA_DEFAULTS -NIL|'1900-01-01 00:00:01'|''|NULL|NIL|''|NULL|''|''|''|'' +NIL|'1900-01-01 00:00:01'|''|NULL|NIL|''|NULL|NIL|''|NIL|NIL|''|NIL|''|'' diff --git a/scripts/db_berkeley/opensips/version b/scripts/db_berkeley/opensips/version index 7aed889ee21..ab46fc6d8db 100644 --- a/scripts/db_berkeley/opensips/version +++ b/scripts/db_berkeley/opensips/version @@ -20,12 +20,22 @@ b2b_entities| b2b_entities|1 b2b_logic| b2b_logic|2 +b2b_sca| +b2b_sca|1 cachedb| -cachedb|1 +cachedb|2 carrierfailureroute| carrierfailureroute|2 carrierroute| carrierroute|3 +cc_agents| +cc_agents|1 +METADATA_DEFAULTS +NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|''|NIL|NIL +cc_cdrs| +cc_cdrs|1 +cc_flows| +cc_flows|1 closeddial| closeddial|1 cpl| @@ -33,23 +43,23 @@ cpl|2 dbaliases| dbaliases|2 dialog| -dialog|8 +dialog|10 dialplan| dialplan|4 dispatcher| -dispatcher|5 +dispatcher|7 domain| -domain|2 +domain|3 domainpolicy| domainpolicy|3 dr_carriers| -dr_carriers|1 +dr_carriers|2 dr_gateways| -dr_gateways|5 +dr_gateways|6 dr_groups| dr_groups|2 -METADATA_DEFAULTS -NIL|NIL|'' +dr_partitions| +dr_partitions|1 dr_rules| dr_rules|3 globalblacklist| @@ -63,7 +73,7 @@ imc_rooms|2 load_balancer| load_balancer|2 location| -location|1007 +location|1009 missed_calls| missed_calls|4 pdt| @@ -72,10 +82,10 @@ presentity| presentity|5 pua| pua|8 -registrant| -registrant|1 re_grp| re_grp|2 +registrant| +registrant|1 rls_presentity| rls_presentity|1 rls_watchers| @@ -87,7 +97,7 @@ rtpproxy_sockets|0 silo| silo|6 sip_trace| -sip_trace|3 +sip_trace|4 speed_dial| speed_dial|3 subscriber| diff --git a/scripts/dbtext/opensips/b2b_sca b/scripts/dbtext/opensips/b2b_sca new file mode 100644 index 00000000000..ed1eb0e8810 --- /dev/null +++ b/scripts/dbtext/opensips/b2b_sca @@ -0,0 +1 @@ +id(int,auto) shared_line(string) watchers(string) app1_shared_entity(int,null) app1_call_state(int,null) app1_call_info_uri(string,null) app1_call_info_appearance_uri(string,null) app1_b2bl_key(string,null) app2_shared_entity(int,null) app2_call_state(int,null) app2_call_info_uri(string,null) app2_call_info_appearance_uri(string,null) app2_b2bl_key(string,null) app3_shared_entity(int,null) app3_call_state(int,null) app3_call_info_uri(string,null) app3_call_info_appearance_uri(string,null) app3_b2bl_key(string,null) app4_shared_entity(int,null) app4_call_state(int,null) app4_call_info_uri(string,null) app4_call_info_appearance_uri(string,null) app4_b2bl_key(string,null) app5_shared_entity(int,null) app5_call_state(int,null) app5_call_info_uri(string,null) app5_call_info_appearance_uri(string,null) app5_b2bl_key(string,null) app6_shared_entity(int,null) app6_call_state(int,null) app6_call_info_uri(string,null) app6_call_info_appearance_uri(string,null) app6_b2bl_key(string,null) app7_shared_entity(int,null) app7_call_state(int,null) app7_call_info_uri(string,null) app7_call_info_appearance_uri(string,null) app7_b2bl_key(string,null) app8_shared_entity(int,null) app8_call_state(int,null) app8_call_info_uri(string,null) app8_call_info_appearance_uri(string,null) app8_b2bl_key(string,null) app9_shared_entity(int,null) app9_call_state(int,null) app9_call_info_uri(string,null) app9_call_info_appearance_uri(string,null) app9_b2bl_key(string,null) app10_shared_entity(int,null) app10_call_state(int,null) app10_call_info_uri(string,null) app10_call_info_appearance_uri(string,null) app10_b2bl_key(string,null) diff --git a/scripts/dbtext/opensips/cc_agents b/scripts/dbtext/opensips/cc_agents new file mode 100644 index 00000000000..c89411ca2e3 --- /dev/null +++ b/scripts/dbtext/opensips/cc_agents @@ -0,0 +1 @@ +id(int,auto) agentid(string) location(string) logstate(int) skills(string) last_call_end(int) diff --git a/scripts/dbtext/opensips/cc_calls b/scripts/dbtext/opensips/cc_calls new file mode 100644 index 00000000000..5c144b72ca0 --- /dev/null +++ b/scripts/dbtext/opensips/cc_calls @@ -0,0 +1 @@ +id(int,auto) state(int) ig_cback(int) no_rej(int) setup_time(int) eta(int) last_start(int) recv_time(int) caller_dn(string) caller_un(string) b2buaid(string) flow(string) agent(string) diff --git a/scripts/dbtext/opensips/cc_cdrs b/scripts/dbtext/opensips/cc_cdrs new file mode 100644 index 00000000000..41f73add6b5 --- /dev/null +++ b/scripts/dbtext/opensips/cc_cdrs @@ -0,0 +1 @@ +id(int,auto) caller(string) received_timestamp(int) wait_time(int) pickup_time(int) talk_time(int) flow_id(string) agent_id(string,null) call_type(int) rejected(int) fstats(int) cid(int,null) diff --git a/scripts/dbtext/opensips/cc_flows b/scripts/dbtext/opensips/cc_flows new file mode 100644 index 00000000000..0ab032d6b3e --- /dev/null +++ b/scripts/dbtext/opensips/cc_flows @@ -0,0 +1 @@ +id(int,auto) flowid(string) priority(int) skill(string) prependcid(string) message_welcome(string,null) message_queue(string) diff --git a/scripts/dbtext/opensips/dialog b/scripts/dbtext/opensips/dialog index 6ec42e9ed35..e4fe2b52e94 100644 --- a/scripts/dbtext/opensips/dialog +++ b/scripts/dbtext/opensips/dialog @@ -1 +1 @@ -dlg_id(long,auto) callid(string) from_uri(string) from_tag(string) to_uri(string) to_tag(string) mangled_from_uri(string,null) mangled_to_uri(string,null) caller_cseq(string) callee_cseq(string) caller_ping_cseq(int) callee_ping_cseq(int) caller_route_set(string,null) callee_route_set(string,null) caller_contact(string) callee_contact(string) caller_sock(string) callee_sock(string) state(int) start_time(int) timeout(int) vars(string,null) profiles(string,null) script_flags(int) flags(int) +dlg_id(long) callid(string) from_uri(string) from_tag(string) to_uri(string) to_tag(string) mangled_from_uri(string,null) mangled_to_uri(string,null) caller_cseq(string) callee_cseq(string) caller_ping_cseq(int) callee_ping_cseq(int) caller_route_set(string,null) callee_route_set(string,null) caller_contact(string) callee_contact(string) caller_sock(string) callee_sock(string) state(int) start_time(int) timeout(int) vars(blob,null) profiles(string,null) script_flags(int) module_flags(int) flags(int) diff --git a/scripts/dbtext/opensips/dialplan b/scripts/dbtext/opensips/dialplan index 105f64c2792..383716d059e 100644 --- a/scripts/dbtext/opensips/dialplan +++ b/scripts/dbtext/opensips/dialplan @@ -1 +1 @@ -id(int,auto) dpid(int) pr(int) match_op(int) match_exp(string) match_flags(int) subst_exp(string) repl_exp(string) disabled(int) attrs(string) +id(int,auto) dpid(int) pr(int) match_op(int) match_exp(string) match_flags(int) subst_exp(string) repl_exp(string) timerec(string) disabled(int) attrs(string) diff --git a/scripts/dbtext/opensips/dispatcher b/scripts/dbtext/opensips/dispatcher index e2c7a1bb57c..4cbdcffc2a7 100644 --- a/scripts/dbtext/opensips/dispatcher +++ b/scripts/dbtext/opensips/dispatcher @@ -1 +1 @@ -id(int,auto) setid(int) destination(string) socket(string,null) flags(int) weight(int) attrs(string) description(string) +id(int,auto) setid(int) destination(string) socket(string,null) state(int) weight(int) priority(int) attrs(string) description(string) diff --git a/scripts/dbtext/opensips/domain b/scripts/dbtext/opensips/domain index f9c7ec4bef1..1abf2f19719 100644 --- a/scripts/dbtext/opensips/domain +++ b/scripts/dbtext/opensips/domain @@ -1 +1 @@ -id(int,auto) domain(string) last_modified(int) +id(int,auto) domain(string) attrs(string,null) last_modified(int) diff --git a/scripts/dbtext/opensips/dr_carriers b/scripts/dbtext/opensips/dr_carriers index 156999e22b4..a1c720cd703 100644 --- a/scripts/dbtext/opensips/dr_carriers +++ b/scripts/dbtext/opensips/dr_carriers @@ -1 +1 @@ -id(int,auto) carrierid(string) gwlist(string) flags(int) attrs(string,null) description(string) +id(int,auto) carrierid(string) gwlist(string) flags(int) state(int) attrs(string,null) description(string) diff --git a/scripts/dbtext/opensips/dr_gateways b/scripts/dbtext/opensips/dr_gateways index 1f25149e92b..9ad7eb8d036 100644 --- a/scripts/dbtext/opensips/dr_gateways +++ b/scripts/dbtext/opensips/dr_gateways @@ -1 +1 @@ -id(int,auto) gwid(string) type(int) address(string) strip(int) pri_prefix(string,null) attrs(string,null) probe_mode(int) description(string) +id(int,auto) gwid(string) type(int) address(string) strip(int) pri_prefix(string,null) attrs(string,null) probe_mode(int) state(int) socket(string,null) description(string) diff --git a/scripts/dbtext/opensips/dr_gw_lists b/scripts/dbtext/opensips/dr_gw_lists deleted file mode 100644 index 21070b58c7e..00000000000 --- a/scripts/dbtext/opensips/dr_gw_lists +++ /dev/null @@ -1 +0,0 @@ -id(int,auto) gwlist(string) description(string) diff --git a/scripts/dbtext/opensips/dr_partitions b/scripts/dbtext/opensips/dr_partitions new file mode 100644 index 00000000000..da439109c38 --- /dev/null +++ b/scripts/dbtext/opensips/dr_partitions @@ -0,0 +1 @@ +id(int,auto) partition_name(string) db_url(string) drd_table(string,null) drr_table(string,null) drg_table(string,null) drc_table(string,null) ruri_avp(string,null) gw_id_avp(string,null) gw_priprefix_avp(string,null) gw_sock_avp(string,null) rule_id_avp(string,null) rule_prefix_avp(string,null) carrier_id_avp(string,null) diff --git a/scripts/dbtext/opensips/location b/scripts/dbtext/opensips/location index aae997362f1..839d04244a0 100644 --- a/scripts/dbtext/opensips/location +++ b/scripts/dbtext/opensips/location @@ -1 +1 @@ -id(int,auto) username(string) domain(string) contact(string) received(string,null) path(string,null) expires(int) q(double) callid(string) cseq(int) last_modified(int) flags(int) cflags(int) user_agent(string) socket(string,null) methods(int,null) sip_instance(string,null) +id(int,auto) username(string) domain(string) contact(string) received(string,null) path(string,null) expires(int) q(double) callid(string) cseq(int) last_modified(int) flags(int) cflags(string,null) user_agent(string) socket(string,null) methods(int,null) sip_instance(string,null) attr(string,null) diff --git a/scripts/dbtext/opensips/presentity b/scripts/dbtext/opensips/presentity index cbcb09a4f4c..c8316128e10 100644 --- a/scripts/dbtext/opensips/presentity +++ b/scripts/dbtext/opensips/presentity @@ -1 +1 @@ -id(int,auto) username(string) domain(string) event(string) etag(string) expires(int) received_time(int) body(string) extra_hdrs(string) sender(string) +id(int,auto) username(string) domain(string) event(string) etag(string) expires(int) received_time(int) body(blob) extra_hdrs(blob) sender(string) diff --git a/scripts/dbtext/opensips/rls_presentity b/scripts/dbtext/opensips/rls_presentity index f30e3308e55..dcd2aca3ae9 100644 --- a/scripts/dbtext/opensips/rls_presentity +++ b/scripts/dbtext/opensips/rls_presentity @@ -1 +1 @@ -id(int,auto) rlsubs_did(string) resource_uri(string) content_type(string) presence_state(string) expires(int) updated(int) auth_state(int) reason(string) +id(int,auto) rlsubs_did(string) resource_uri(string) content_type(string) presence_state(blob) expires(int) updated(int) auth_state(int) reason(string) diff --git a/scripts/dbtext/opensips/silo b/scripts/dbtext/opensips/silo index fa4606b9bbc..d138c5325f0 100644 --- a/scripts/dbtext/opensips/silo +++ b/scripts/dbtext/opensips/silo @@ -1 +1 @@ -id(int,auto) src_addr(string) dst_addr(string) username(string) domain(string) inc_time(int) exp_time(int) snd_time(int) ctype(string) body(string) +id(int,auto) src_addr(string) dst_addr(string) username(string) domain(string) inc_time(int) exp_time(int) snd_time(int) ctype(string,null) body(blob) diff --git a/scripts/dbtext/opensips/sip_trace b/scripts/dbtext/opensips/sip_trace index 7d8d9539fa9..98ed25c6e5f 100644 --- a/scripts/dbtext/opensips/sip_trace +++ b/scripts/dbtext/opensips/sip_trace @@ -1 +1 @@ -id(int,auto) time_stamp(int) callid(string) traced_user(string,null) msg(string) method(string) status(string,null) fromip(string) toip(string) fromtag(string) direction(string) +id(int,auto) time_stamp(int) callid(string) traced_user(string,null) msg(string) method(string) status(string,null) from_proto(string) from_ip(string) from_port(int) to_proto(string) to_ip(string) to_port(int) fromtag(string) direction(string) diff --git a/scripts/dbtext/opensips/version b/scripts/dbtext/opensips/version index 59a85f270c2..ee94f03a68c 100644 --- a/scripts/dbtext/opensips/version +++ b/scripts/dbtext/opensips/version @@ -5,39 +5,44 @@ address:5 aliases:1007 b2b_entities:1 b2b_logic:2 -cachedb:1 +b2b_sca:1 +cachedb:2 carrierfailureroute:2 carrierroute:3 +cc_agents:1 +cc_cdrs:1 +cc_flows:1 closeddial:1 cpl:2 dbaliases:2 -dialog:8 +dialog:10 dialplan:4 -dispatcher:5 -domain:2 +dispatcher:7 +domain:3 domainpolicy:3 -dr_carriers:1 -dr_gateways:5 +dr_carriers:2 +dr_gateways:6 dr_groups:2 +dr_partitions:1 dr_rules:3 globalblacklist:2 grp:3 imc_members:2 imc_rooms:2 load_balancer:2 -location:1007 +location:1009 missed_calls:4 pdt:2 presentity:5 pua:8 -registrant:1 re_grp:2 +registrant:1 rls_presentity:1 rls_watchers:2 route_tree:2 rtpproxy_sockets:0 silo:6 -sip_trace:3 +sip_trace:4 speed_dial:3 subscriber:7 uri:2 diff --git a/scripts/dbtext/opensips/xcap b/scripts/dbtext/opensips/xcap index a9f960bc3b4..6d45f1daee7 100644 --- a/scripts/dbtext/opensips/xcap +++ b/scripts/dbtext/opensips/xcap @@ -1 +1 @@ -id(int,auto) username(string) domain(string) doc(string) doc_type(int) etag(string) source(int) doc_uri(string) port(int) +id(int,auto) username(string) domain(string) doc(blob) doc_type(int) etag(string) source(int) doc_uri(string) port(int) diff --git a/scripts/mysql/b2b_sca-create.sql b/scripts/mysql/b2b_sca-create.sql new file mode 100644 index 00000000000..0e2b093519c --- /dev/null +++ b/scripts/mysql/b2b_sca-create.sql @@ -0,0 +1,58 @@ +INSERT INTO version (table_name, table_version) values ('b2b_sca','1'); +CREATE TABLE b2b_sca ( + id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, + shared_line CHAR(64) NOT NULL, + watchers CHAR(255) NOT NULL, + app1_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app1_call_state INT(1) UNSIGNED DEFAULT NULL, + app1_call_info_uri CHAR(128) DEFAULT NULL, + app1_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app1_b2bl_key CHAR(64) DEFAULT NULL, + app2_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app2_call_state INT(1) UNSIGNED DEFAULT NULL, + app2_call_info_uri CHAR(128) DEFAULT NULL, + app2_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app2_b2bl_key CHAR(64) DEFAULT NULL, + app3_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app3_call_state INT(1) UNSIGNED DEFAULT NULL, + app3_call_info_uri CHAR(128) DEFAULT NULL, + app3_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app3_b2bl_key CHAR(64) DEFAULT NULL, + app4_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app4_call_state INT(1) UNSIGNED DEFAULT NULL, + app4_call_info_uri CHAR(128) DEFAULT NULL, + app4_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app4_b2bl_key CHAR(64) DEFAULT NULL, + app5_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app5_call_state INT(1) UNSIGNED DEFAULT NULL, + app5_call_info_uri CHAR(128) DEFAULT NULL, + app5_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app5_b2bl_key CHAR(64) DEFAULT NULL, + app6_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app6_call_state INT(1) UNSIGNED DEFAULT NULL, + app6_call_info_uri CHAR(128) DEFAULT NULL, + app6_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app6_b2bl_key CHAR(64) DEFAULT NULL, + app7_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app7_call_state INT(1) UNSIGNED DEFAULT NULL, + app7_call_info_uri CHAR(128) DEFAULT NULL, + app7_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app7_b2bl_key CHAR(64) DEFAULT NULL, + app8_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app8_call_state INT(1) UNSIGNED DEFAULT NULL, + app8_call_info_uri CHAR(128) DEFAULT NULL, + app8_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app8_b2bl_key CHAR(64) DEFAULT NULL, + app9_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app9_call_state INT(1) UNSIGNED DEFAULT NULL, + app9_call_info_uri CHAR(128) DEFAULT NULL, + app9_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app9_b2bl_key CHAR(64) DEFAULT NULL, + app10_shared_entity INT(1) UNSIGNED DEFAULT NULL, + app10_call_state INT(1) UNSIGNED DEFAULT NULL, + app10_call_info_uri CHAR(128) DEFAULT NULL, + app10_call_info_appearance_uri CHAR(128) DEFAULT NULL, + app10_b2bl_key CHAR(64) DEFAULT NULL, + CONSTRAINT sca_idx UNIQUE (shared_line) +) ENGINE=MyISAM; + diff --git a/scripts/mysql/cachedb_sql-create.sql b/scripts/mysql/cachedb_sql-create.sql index 617d6f48267..5339393ec63 100644 --- a/scripts/mysql/cachedb_sql-create.sql +++ b/scripts/mysql/cachedb_sql-create.sql @@ -1,6 +1,6 @@ -INSERT INTO version (table_name, table_version) values ('cachedb','1'); +INSERT INTO version (table_name, table_version) values ('cachedb','2'); CREATE TABLE cachedb ( - keyname CHAR(255) NOT NULL, + keyname CHAR(255) PRIMARY KEY NOT NULL, value TEXT(512) NOT NULL, counter INT(10) DEFAULT 0 NOT NULL, expires INT(10) UNSIGNED DEFAULT 0 NOT NULL diff --git a/scripts/mysql/call_center-create.sql b/scripts/mysql/call_center-create.sql new file mode 100644 index 00000000000..ff9d2711ada --- /dev/null +++ b/scripts/mysql/call_center-create.sql @@ -0,0 +1,56 @@ +INSERT INTO version (table_name, table_version) values ('cc_flows','1'); +CREATE TABLE cc_flows ( + id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, + flowid CHAR(64) NOT NULL, + priority INT(11) UNSIGNED DEFAULT 256 NOT NULL, + skill CHAR(64) NOT NULL, + prependcid CHAR(32) NOT NULL, + message_welcome CHAR(128) DEFAULT NULL, + message_queue CHAR(128) NOT NULL, + CONSTRAINT unique_flowid UNIQUE (flowid) +) ENGINE=MyISAM; + +INSERT INTO version (table_name, table_version) values ('cc_agents','1'); +CREATE TABLE cc_agents ( + id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, + agentid CHAR(128) NOT NULL, + location CHAR(128) NOT NULL, + logstate INT(10) UNSIGNED DEFAULT 0 NOT NULL, + skills CHAR(255) NOT NULL, + last_call_end INT(11) DEFAULT 0 NOT NULL, + CONSTRAINT unique_agentid UNIQUE (agentid) +) ENGINE=MyISAM; + +INSERT INTO version (table_name, table_version) values ('cc_cdrs','1'); +CREATE TABLE cc_cdrs ( + id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, + caller CHAR(64) NOT NULL, + received_timestamp DATETIME NOT NULL, + wait_time INT(11) UNSIGNED DEFAULT 0 NOT NULL, + pickup_time INT(11) UNSIGNED DEFAULT 0 NOT NULL, + talk_time INT(11) UNSIGNED DEFAULT 0 NOT NULL, + flow_id CHAR(128) NOT NULL, + agent_id CHAR(128) DEFAULT NULL, + call_type INT(11) DEFAULT -1 NOT NULL, + rejected INT(11) UNSIGNED DEFAULT 0 NOT NULL, + fstats INT(11) UNSIGNED DEFAULT 0 NOT NULL, + cid INT(11) UNSIGNED DEFAULT 0 +) ENGINE=MyISAM; + +CREATE TABLE cc_calls ( + id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL, + state INT(11) NOT NULL, + ig_cback INT(11) NOT NULL, + no_rej INT(11) NOT NULL, + setup_time INT(11) NOT NULL, + eta INT(11) NOT NULL, + last_start INT(11) NOT NULL, + recv_time INT(11) NOT NULL, + caller_dn CHAR(128) NOT NULL, + caller_un CHAR(128) NOT NULL, + b2buaid CHAR(128) PRIMARY KEY DEFAULT '' NOT NULL, + flow CHAR(128) NOT NULL, + agent CHAR(128) NOT NULL, + CONSTRAINT unique_id UNIQUE (id) +) ENGINE=MyISAM; + diff --git a/scripts/mysql/dialog-create.sql b/scripts/mysql/dialog-create.sql index 845716407ae..051c276ca84 100644 --- a/scripts/mysql/dialog-create.sql +++ b/scripts/mysql/dialog-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('dialog','8'); +INSERT INTO version (table_name, table_version) values ('dialog','10'); CREATE TABLE dialog ( dlg_id BIGINT(10) UNSIGNED PRIMARY KEY NOT NULL, callid CHAR(255) NOT NULL, @@ -21,9 +21,10 @@ CREATE TABLE dialog ( state INT(10) UNSIGNED NOT NULL, start_time INT(10) UNSIGNED NOT NULL, timeout INT(10) UNSIGNED NOT NULL, - vars TEXT(512) DEFAULT NULL, + vars BLOB(4096) DEFAULT NULL, profiles TEXT(512) DEFAULT NULL, script_flags INT(10) UNSIGNED DEFAULT 0 NOT NULL, + module_flags INT(10) UNSIGNED DEFAULT 0 NOT NULL, flags INT(10) UNSIGNED DEFAULT 0 NOT NULL ) ENGINE=MyISAM; diff --git a/scripts/mysql/dialplan-create.sql b/scripts/mysql/dialplan-create.sql index 9c7b8e7fda4..315ef564c25 100644 --- a/scripts/mysql/dialplan-create.sql +++ b/scripts/mysql/dialplan-create.sql @@ -8,6 +8,7 @@ CREATE TABLE dialplan ( match_flags INT(11) NOT NULL, subst_exp CHAR(64) NOT NULL, repl_exp CHAR(32) NOT NULL, + timerec CHAR(255) NOT NULL, disabled INT(11) DEFAULT 0 NOT NULL, attrs CHAR(32) NOT NULL ) ENGINE=MyISAM; diff --git a/scripts/mysql/dispatcher-create.sql b/scripts/mysql/dispatcher-create.sql index d7c7dc75083..3a0031ca4b5 100644 --- a/scripts/mysql/dispatcher-create.sql +++ b/scripts/mysql/dispatcher-create.sql @@ -1,11 +1,12 @@ -INSERT INTO version (table_name, table_version) values ('dispatcher','5'); +INSERT INTO version (table_name, table_version) values ('dispatcher','7'); CREATE TABLE dispatcher ( id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, setid INT DEFAULT 0 NOT NULL, destination CHAR(192) DEFAULT '' NOT NULL, socket CHAR(128) DEFAULT NULL, - flags INT DEFAULT 0 NOT NULL, + state INT DEFAULT 0 NOT NULL, weight INT DEFAULT 1 NOT NULL, + priority INT DEFAULT 0 NOT NULL, attrs CHAR(128) DEFAULT '' NOT NULL, description CHAR(64) DEFAULT '' NOT NULL ) ENGINE=MyISAM; diff --git a/scripts/mysql/domain-create.sql b/scripts/mysql/domain-create.sql index fdd9a15082c..1e887dd46f9 100644 --- a/scripts/mysql/domain-create.sql +++ b/scripts/mysql/domain-create.sql @@ -1,7 +1,8 @@ -INSERT INTO version (table_name, table_version) values ('domain','2'); +INSERT INTO version (table_name, table_version) values ('domain','3'); CREATE TABLE domain ( id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, domain CHAR(64) DEFAULT '' NOT NULL, + attrs CHAR(255) DEFAULT NULL, last_modified DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL, CONSTRAINT domain_idx UNIQUE (domain) ) ENGINE=MyISAM; diff --git a/scripts/mysql/drouting-create.sql b/scripts/mysql/drouting-create.sql index d3619c0cb8d..26c56f2d24c 100644 --- a/scripts/mysql/drouting-create.sql +++ b/scripts/mysql/drouting-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('dr_gateways','5'); +INSERT INTO version (table_name, table_version) values ('dr_gateways','6'); CREATE TABLE dr_gateways ( id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, gwid CHAR(64) NOT NULL, @@ -8,6 +8,8 @@ CREATE TABLE dr_gateways ( pri_prefix CHAR(16) DEFAULT NULL, attrs CHAR(255) DEFAULT NULL, probe_mode INT(11) UNSIGNED DEFAULT 0 NOT NULL, + state INT(11) UNSIGNED DEFAULT 0 NOT NULL, + socket CHAR(128) DEFAULT NULL, description CHAR(128) DEFAULT '' NOT NULL, CONSTRAINT dr_gw_idx UNIQUE (gwid) ) ENGINE=MyISAM; @@ -25,12 +27,13 @@ CREATE TABLE dr_rules ( description CHAR(128) DEFAULT '' NOT NULL ) ENGINE=MyISAM; -INSERT INTO version (table_name, table_version) values ('dr_carriers','1'); +INSERT INTO version (table_name, table_version) values ('dr_carriers','2'); CREATE TABLE dr_carriers ( id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, carrierid CHAR(64) NOT NULL, gwlist CHAR(255) NOT NULL, flags INT(11) UNSIGNED DEFAULT 0 NOT NULL, + state INT(11) UNSIGNED DEFAULT 0 NOT NULL, attrs CHAR(255) DEFAULT '', description CHAR(128) DEFAULT '' NOT NULL, CONSTRAINT dr_carrier_idx UNIQUE (carrierid) @@ -45,3 +48,21 @@ CREATE TABLE dr_groups ( description CHAR(128) DEFAULT '' NOT NULL ) ENGINE=MyISAM; +INSERT INTO version (table_name, table_version) values ('dr_partitions','1'); +CREATE TABLE dr_partitions ( + id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, + partition_name CHAR(255) NOT NULL, + db_url CHAR(255) NOT NULL, + drd_table CHAR(255), + drr_table CHAR(255), + drg_table CHAR(255), + drc_table CHAR(255), + ruri_avp CHAR(255), + gw_id_avp CHAR(255), + gw_priprefix_avp CHAR(255), + gw_sock_avp CHAR(255), + rule_id_avp CHAR(255), + rule_prefix_avp CHAR(255), + carrier_id_avp CHAR(255) +) ENGINE=MyISAM; + diff --git a/scripts/mysql/msilo-create.sql b/scripts/mysql/msilo-create.sql index 691e5cbdc7a..72768e362fc 100644 --- a/scripts/mysql/msilo-create.sql +++ b/scripts/mysql/msilo-create.sql @@ -8,8 +8,8 @@ CREATE TABLE silo ( inc_time INT DEFAULT 0 NOT NULL, exp_time INT DEFAULT 0 NOT NULL, snd_time INT DEFAULT 0 NOT NULL, - ctype CHAR(32) DEFAULT 'text/plain' NOT NULL, - body BLOB DEFAULT '' NOT NULL + ctype CHAR(255) DEFAULT NULL, + body BLOB NOT NULL ) ENGINE=MyISAM; CREATE INDEX account_idx ON silo (username, domain); diff --git a/scripts/mysql/presence-create.sql b/scripts/mysql/presence-create.sql index b8b40d1e0ce..161a5f95560 100644 --- a/scripts/mysql/presence-create.sql +++ b/scripts/mysql/presence-create.sql @@ -92,3 +92,7 @@ CREATE TABLE pua ( extra_headers TEXT ) ENGINE=MyISAM; +CREATE INDEX del1_idx ON pua (pres_uri, event); +CREATE INDEX del2_idx ON pua (expires); +CREATE INDEX update_idx ON pua (pres_uri, pres_id, flag, event); + diff --git a/scripts/mysql/siptrace-create.sql b/scripts/mysql/siptrace-create.sql index 47a06ef624d..4779d8c16b0 100644 --- a/scripts/mysql/siptrace-create.sql +++ b/scripts/mysql/siptrace-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('sip_trace','3'); +INSERT INTO version (table_name, table_version) values ('sip_trace','4'); CREATE TABLE sip_trace ( id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, time_stamp DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL, @@ -7,14 +7,18 @@ CREATE TABLE sip_trace ( msg TEXT NOT NULL, method CHAR(32) DEFAULT '' NOT NULL, status CHAR(128) DEFAULT NULL, - fromip CHAR(50) DEFAULT '' NOT NULL, - toip CHAR(50) DEFAULT '' NOT NULL, + from_proto CHAR(5) NOT NULL, + from_ip CHAR(50) DEFAULT '' NOT NULL, + from_port INT(5) UNSIGNED NOT NULL, + to_proto CHAR(5) NOT NULL, + to_ip CHAR(50) DEFAULT '' NOT NULL, + to_port INT(5) UNSIGNED NOT NULL, fromtag CHAR(64) DEFAULT '' NOT NULL, direction CHAR(4) DEFAULT '' NOT NULL ) ENGINE=MyISAM; CREATE INDEX traced_user_idx ON sip_trace (traced_user); CREATE INDEX date_idx ON sip_trace (time_stamp); -CREATE INDEX fromip_idx ON sip_trace (fromip); +CREATE INDEX fromip_idx ON sip_trace (from_ip); CREATE INDEX callid_idx ON sip_trace (callid); diff --git a/scripts/mysql/usrloc-create.sql b/scripts/mysql/usrloc-create.sql index cf4f7bb1ad0..dfaf09b1535 100644 --- a/scripts/mysql/usrloc-create.sql +++ b/scripts/mysql/usrloc-create.sql @@ -1,22 +1,23 @@ -INSERT INTO version (table_name, table_version) values ('location','1007'); +INSERT INTO version (table_name, table_version) values ('location','1009'); CREATE TABLE location ( id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, username CHAR(64) DEFAULT '' NOT NULL, domain CHAR(64) DEFAULT '' NOT NULL, contact CHAR(255) DEFAULT '' NOT NULL, received CHAR(128) DEFAULT NULL, - path CHAR(128) DEFAULT NULL, + path CHAR(255) DEFAULT NULL, expires DATETIME DEFAULT '2020-05-28 21:32:15' NOT NULL, q FLOAT(10,2) DEFAULT 1.0 NOT NULL, callid CHAR(255) DEFAULT 'Default-Call-ID' NOT NULL, cseq INT(11) DEFAULT 13 NOT NULL, last_modified DATETIME DEFAULT '1900-01-01 00:00:01' NOT NULL, flags INT(11) DEFAULT 0 NOT NULL, - cflags INT(11) DEFAULT 0 NOT NULL, + cflags CHAR(255) DEFAULT NULL, user_agent CHAR(255) DEFAULT '' NOT NULL, socket CHAR(64) DEFAULT NULL, methods INT(11) DEFAULT NULL, sip_instance CHAR(255) DEFAULT NULL, + attr CHAR(255) DEFAULT NULL, CONSTRAINT account_contact_idx UNIQUE (username, domain, contact, callid) ) ENGINE=MyISAM; diff --git a/scripts/opensipsctl b/scripts/opensipsctl index b1a69af4747..b7b5bd21540 100755 --- a/scripts/opensipsctl +++ b/scripts/opensipsctl @@ -1289,25 +1289,27 @@ dispatcher() { ;; addgw) shift - if [ $# -lt 3 ] ; then + if [ $# -lt 6 ] ; then merr "too few parameters" usage_dispatcher exit 1 fi - if [ $# -gt 3 ] ; then - DISPATCHER_DESCRIPTION=$4 + if [ $# -gt 6 ] ; then + DISPATCHER_DESCRIPTION=$7 else DISPATCHER_DESCRIPTION="" fi DISPATCHER_SETID=$1 DISPATCHER_DESTINATION=$2 - DISPATCHER_FLAGS=$3 + DISPATCHER_SOCKET=$3 + DISPATCHER_STATE=$4 + DISPATCHER_WEIGHT=$5 + DISPATCHER_ATTRS=$6 + + QUERY="insert into $DISPATCHER_TABLE ($DISPATCHER_SETID_COLUMN, $DISPATCHER_DESTINATION_COLUMN, $DISPATCHER_SOCKET_COLUMN, $DISPATCHER_STATE_COLUMN, $DISPATCHER_WEIGHT_COLUMN, $DISPATCHER_ATTRS_COLUMN, $DISPATCHER_DESCRIPTION_COLUMN) VALUES ($DISPATCHER_SETID, '$DISPATCHER_DESTINATION', '$DISPATCHER_SOCKET', $DISPATCHER_STATE, $DISPATCHER_WEIGHT, '$DISPATCHER_ATTRS', '$DISPATCHER_DESCRIPTION');" - QUERY="insert into $DISPATCHER_TABLE \ - ( $DISPATCHER_SETID_COLUMN, $DISPATCHER_DESTINATION_COLUMN, $DISPATCHER_FLAGS_COLUMN, $DISPATCHER_DESCRIPTION_COLUMN ) \ - VALUES ($DISPATCHER_SETID,'$DISPATCHER_DESTINATION',$DISPATCHER_FLAGS,'$DISPATCHER_DESCRIPTION');" $DBCMD "$QUERY" if [ $? -ne 0 ] ; then @@ -1400,7 +1402,7 @@ dr() { exit 1 fi - $CTLCMD ds_reload + $CTLCMD dr_reload ;; rmgw) shift @@ -1450,7 +1452,7 @@ dr() { exit 1 fi - $CTLCMD ds_reload + $CTLCMD dr_reload ;; rmcr) shift @@ -1498,7 +1500,7 @@ dr() { exit 1 fi - $CTLCMD ds_reload + $CTLCMD dr_reload ;; rmgrp) shift @@ -1550,7 +1552,7 @@ dr() { exit 1 fi - $CTLCMD ds_reload + $CTLCMD dr_reload ;; rmgrule) shift @@ -2616,6 +2618,34 @@ tls_ca() { fi } +##### ================================================ ##### +### trap with gdb opensips processes +# + +opensips_trap() { + if [ -z "$GDB" ] ; then + merr "'gdb' tool not found: set GDB variable to correct tool path" + exit + fi + DATE=`/bin/date +%Y%m%d_%H%M%S` + LOG_FILE=/tmp/gdb_opensips_$DATE + minfo "Trap file: $LOG_FILE" + $CTLCMD ps > $LOG_FILE + echo -n "Trapping OpenSIPS with gdb: " + PID_TIMESTAMP_VECTOR=`sed -e 's/.*PID=\([0-9]*\).*/\1/' $LOG_FILE` + minfo "$PID_TIMESTAMP_VECTOR" + for pid in $PID_TIMESTAMP_VECTOR + do + echo -n "." + PID=`echo $pid | cut -d '-' -f 1` + echo "" >> $LOG_FILE + echo "---start $PID -----------------------------------------------------" >> $LOG_FILE + $GDB opensips $PID -batch --eval-command="bt full" 2>&1 >> $LOG_FILE + echo "---end $PID -------------------------------------------------------" >> $LOG_FILE + done + echo "." +} + # ##### ================================================ ##### ### main command switch @@ -2755,6 +2785,11 @@ case $1 in tls_ca "$@" ;; + trap) + require_ctlengine + opensips_trap + ;; + start) opensips_start ;; diff --git a/scripts/opensipsctl.8 b/scripts/opensipsctl.8 index e55dad6a942..3386f29029c 100644 --- a/scripts/opensipsctl.8 +++ b/scripts/opensipsctl.8 @@ -91,6 +91,21 @@ remove an alias (*) .B alias_db help help message .TP +.B dispatcher show +show dispatcher gateways +.TP +.B dispatcher reload +reload dispatcher gateways +.TP +.B dispatcher dump +show in memory dispatcher gateways +.TP +.B dispatcher addgw [description] +add gateway +.TP +.B dispatcher rmgw +delete gateway +.TP .B speeddial show show speeddial details .TP diff --git a/scripts/opensipsctl.base b/scripts/opensipsctl.base index d3918539fc2..c4564f82d4d 100644 --- a/scripts/opensipsctl.base +++ b/scripts/opensipsctl.base @@ -62,6 +62,15 @@ if [ -z "$AWK" ] ; then fi AWK="$TOOLPATH" fi +if [ -z "$GDB" ] ; then + locate_tool gdb + if [ -z "$TOOLPATH" ] ; then + # no gdb + GDB="" + else + GDB="$TOOLPATH" + fi +fi if [ -z "$MD5" ]; then locate_tool md5sum md5 if [ -z "$TOOLPATH" ] ; then @@ -273,7 +282,10 @@ fi DISPATCHER_ID_COLUMN=id DISPATCHER_SETID_COLUMN=setid DISPATCHER_DESTINATION_COLUMN=destination -DISPATCHER_FLAGS_COLUMN=flags +DISPATCHER_SOCKET_COLUMN=socket +DISPATCHER_STATE_COLUMN=state +DISPATCHER_WEIGHT_COLUMN=weight +DISPATCHER_ATTRS_COLUMN=attrs DISPATCHER_DESCRIPTION_COLUMN=description # drouting tables @@ -356,9 +368,10 @@ REGISTRANT_FORCED_SOCKET_COLUMN=forced_socket usage_base() { echo - mecho " -- command 'start|stop|restart'" + mecho " -- command 'start|stop|restart|trap'" echo cat < + dispatcher addgw [description] .......................... add gateway dispatcher rmgw ................ delete gateway EOF diff --git a/scripts/opensipsctl.fifo b/scripts/opensipsctl.fifo index c41146555c5..f0bc782e0fb 100644 --- a/scripts/opensipsctl.fifo +++ b/scripts/opensipsctl.fifo @@ -50,8 +50,7 @@ fifo_cmd() merr "fifo_cmd must take at least command name as parameter" exit 1 fi - name=opensips_receiver_$$ - path=$CHROOT_DIR/tmp/$name + if [ ! -w $OSIPS_FIFO ]; then merr "Error opening OpenSIPS's FIFO $OSIPS_FIFO" merr "Make sure you have the line 'modparam(\"mi_fifo\", \"fifo_name\", \"$OSIPS_FIFO\")' in your config" @@ -61,14 +60,15 @@ fifo_cmd() fi exit 2 fi - if ! test -p $path; then - mkfifo $path - if [ $? -ne 0 ] ; then - merr "error opening read fifo $path" - exit 3 - fi - chmod a+w $path - fi + + # generate a random and unique filename + while : + do + suffix=$(od -An -N4 -tx4 /dev/urandom | tr -d " ") + (mkfifo --mode=a+w $CHROOT_DIR/tmp/osips_rply_$suffix) &>/dev/null && break + done + name=osips_rply_$suffix + path=$CHROOT_DIR/tmp/$name # construct the command now CMD=":$1:$name\n"; diff --git a/scripts/opensipsctlrc b/scripts/opensipsctlrc index a8446dd6a7f..c9d8b1cda19 100644 --- a/scripts/opensipsctlrc +++ b/scripts/opensipsctlrc @@ -59,6 +59,9 @@ # awk tool # AWK="awk" +# gdb tool +# GDB="gdb" + # grep tool # GREP="grep" @@ -88,7 +91,8 @@ # dispatcher dialplan drouting nathelper load_balancer" # opensips extra modules -# EXTRA_MODULES="imc cpl siptrace domainpolicy carrierroute userblacklist b2b registrant" +# EXTRA_MODULES="imc cpl siptrace domainpolicy carrierroute userblacklist +# b2b registrant call_center" ## type of aliases used: DB - database aliases; UL - usrloc aliases @@ -132,3 +136,4 @@ ## Extra start options - default is: not set # example: start opensips with 64MB share memory: STARTOPTIONS="-m 64" # STARTOPTIONS= + diff --git a/scripts/opensipsdbctl b/scripts/opensipsdbctl index a231d2bc00f..4f9bff251d7 100755 --- a/scripts/opensipsdbctl +++ b/scripts/opensipsdbctl @@ -10,7 +10,7 @@ PATH=$PATH:/usr/local/sbin/ # for testing only, please don't enable this in production environments # as this introduce security risks -TEST="false" +TEST="true" ### include resource files, if any if [ -f /etc/opensips/opensipsctlrc ]; then diff --git a/scripts/opensipsdbctl.base b/scripts/opensipsdbctl.base index 5c0b70c788c..09ed61697cf 100644 --- a/scripts/opensipsdbctl.base +++ b/scripts/opensipsdbctl.base @@ -8,6 +8,9 @@ DBNAME=${DBNAME:-opensips} # address of database server DBHOST=${DBHOST:-localhost} +# port of database server +DBPORT=${DBPORT:-3306} + # user with full privileges over DBNAME database DBRWUSER=${DBRWUSER:-opensips} @@ -27,7 +30,7 @@ INSTALL_PRESENCE_TABLES=${INSTALL_PRESENCE_TABLES:-ask} # Used by dbtext and db_berkeley to define tables to be created, used by # postgres to do the grants STANDARD_TABLES=${STANDARD_TABLES:-version acc dbaliases domain grp uri speed_dial pdt subscriber location re_grp address address missed_calls usr_preferences aliases silo dialog dispatcher dialplan dr_gateways dr_rules dr_groups rtpproxy_sockets load_balancer} -EXTRA_TABLES=${EXTRA_TABLES:-imc_members imc_rooms cpl sip_trace domainpolicy carrierroute route_tree carrierfailureroute userblacklist globalblacklist} +EXTRA_TABLES=${EXTRA_TABLES:-imc_members imc_rooms cpl sip_trace domainpolicy carrierroute route_tree carrierfailureroute userblacklist globalblacklist registrant call_center} PRESENCE_TABLES=${PRESENCE_TABLES:-presentity active_watchers watchers xcap pua rls_presentity rls_watchers} # SQL definitions @@ -58,7 +61,7 @@ SED=${SED:-sed} # define what modules should be installed STANDARD_MODULES=${STANDARD_MODULES:-standard acc domain group permissions registrar usrloc msilo alias_db uri_db rtpproxy speeddial avpops auth_db pdt dialog dispatcher dialplan drouting load_balancer } -EXTRA_MODULES=${EXTRA_MODULES:-imc cpl siptrace domainpolicy carrierroute userblacklist} +EXTRA_MODULES=${EXTRA_MODULES:-imc cpl siptrace domainpolicy carrierroute userblacklist b2b registrant call_center} ############################################################ diff --git a/scripts/opensipsdbctl.mysql b/scripts/opensipsdbctl.mysql index 4e9f9d84b1e..bc8e0fa3393 100644 --- a/scripts/opensipsdbctl.mysql +++ b/scripts/opensipsdbctl.mysql @@ -38,9 +38,14 @@ fi # automatic testing. #PW="" +if ! [ -z "$DBPORT" ]; then + PORT_OPT="-P$DBPORT" +else + PORT_OPT= +fi -CMD="mysql -h $DBHOST -u$DBROOTUSER " -DUMP_CMD="mysqldump -h $DBHOST -u$DBROOTUSER -c -t " +CMD="mysql -h $DBHOST $PORT_OPT -u$DBROOTUSER " +DUMP_CMD="mysqldump -h $DBHOST $PORT_OPT -u$DBROOTUSER -c -t " ################################################################# @@ -109,6 +114,11 @@ db_charset_test() ALLCHARSETS=`echo "show character set" | $CMD | $AWK '{print $1}' | $SED -e 1d | $GREP -iv "utf8" | $GREP -iv "ucs2"` fi + if [ -z "$ALLCHARSETS" -o -z "$CURRCHARSET" ]; then + mwarn "Failed to get the available and used character sets" + exit 1; + fi + tries=0; while [ `echo "$ALLCHARSETS" | $GREP -icw $CURRCHARSET` = "0" ] @@ -260,7 +270,7 @@ if [ $? -ne 0 ] ; then echo " -- Migrating $3 to $1.....SKIPPED (no source)" return 0 fi - echo "ERROR: failed to migrate $3 to $1!!!" + echo "ERROR: failed to migrate $3 to $1 ($X)!!!" echo -n "Skip it and continue (y/n)? " read INPUT if [ "$INPUT" = "y" ] || [ "$INPUT" = "Y" ] @@ -284,7 +294,8 @@ fi dst_db=$2 src_db=$1 - + +## ACC module migrate_table ${dst_db}.acc \ "id,method,from_tag,to_tag,callid,sip_code,sip_reason,time,duration,setuptime,created" \ ${src_db}.acc \ @@ -295,149 +306,144 @@ migrate_table ${dst_db}.missed_calls \ ${src_db}.missed_calls \ "?id,?method,?from_tag,?to_tag,?callid,?sip_code,?sip_reason,?time" -migrate_table ${dst_db}.aliases \ - "id,username,domain,contact,received,path,expires,q,callid,cseq,last_modified,flags,cflags,user_agent,socket,methods" \ - ${src_db}.aliases \ - "?id,?username,?domain,?contact,?received,?path,?expires,?q,?callid,?cseq,?last_modified,?flags,?cflags,?user_agent,?socket,?methods" - +## ALIAS_DB module migrate_table ${dst_db}.dbaliases \ "id,alias_username,alias_domain,username,domain" \ ${src_db}.dbaliases \ "?id,?alias_username,?alias_domain,?username,?domain" -migrate_table ${dst_db}.grp \ - "id,username,domain,grp,last_modified" \ - ${src_db}.grp \ - "?id,?username,?domain,?grp,?last_modified" - -migrate_table ${dst_db}.re_grp \ - "id,reg_exp,group_id" \ - ${src_db}.re_grp \ - "?id,?reg_exp,?group_id" - -migrate_table ${dst_db}.silo \ - "id,src_addr,dst_addr,username,domain,inc_time,exp_time,snd_time,ctype,body" \ - ${src_db}.silo \ - "?id,?src_addr,?dst_addr,?username,?domain,?inc_time,?exp_time,?snd_time,?ctype,?body" - -migrate_table ${dst_db}.domain \ - "id,domain,last_modified" \ - ${src_db}.domain \ - "?id,?domain,?last_modified" - -migrate_table ${dst_db}.uri \ - "id,username,domain,uri_user,last_modified" \ - ${src_db}.uri \ - "?id,?username,?domain,?uri_user,?last_modified" +## AUTH_DB module +migrate_table ${dst_db}.subscriber \ + "id,username,domain,password,email_address,ha1,ha1b,rpid" \ + ${src_db}.subscriber \ + "?id,?username,?domain,?password,?email_address,?ha1,?ha1b,?rpid" +## AVPOPS module migrate_table ${dst_db}.usr_preferences \ "id,uuid,username,domain,attribute,type,value,last_modified" \ ${src_db}.usr_preferences \ "?id,?uuid,?username,?domain,?attribute,?type,?value,?last_modified" -migrate_table ${dst_db}.address \ - "id,grp,ip,mask,port,proto,pattern,context_info" \ - ${src_db}.address \ - "?id,?grp,?ip,?mask,?port,?proto,?pattern,?context_info" +## B2B modules +# runtime data, nothing to migrate -migrate_table ${dst_db}.speed_dial \ - "id,username,domain,sd_username,sd_domain,new_uri,fname,lname,description" \ - ${src_db}.speed_dial \ - "?id,?username,?domain,?sd_username,?sd_domain,?new_uri,?fname,?lname,?description" +## CACHEDB_SQL module +migrate_table ${dst_db}.cachedb \ + "keyname,value,counter,expires" \ + ${src_db}.cachedb \ + "?keyname,?value,?counter,?expires" -migrate_table ${dst_db}.pdt \ - "id,sdomain,prefix,domain" \ - ${src_db}.pdt \ - "?id,?sdomain,?prefix,?domain" +## CLOSEDDIAL module +migrate_table ${dst_db}.closeddial \ + "id,username,domain,cd_username,cd_domain,group_id,new_uri" \ + ${src_db}.closeddial \ + "?id,?username,?domain,?cd_username,?cd_domain,?group_id,?new_uri" -migrate_table ${dst_db}.subscriber \ - "id,username,domain,password,email_address,ha1,ha1b,rpid" \ - ${src_db}.subscriber \ - "?id,?username,?domain,?password,?email_address,?ha1,?ha1b,?rpid" - -migrate_table ${dst_db}.load_balancer \ - "id,group_id,dst_uri,resources,probe_mode,description" \ - ${src_db}.load_balancer \ - "?id,?group_id,?dst_uri,?resources,?probe_mode,?description" \ - -migrate_table ${dst_db}.dispatcher \ - "id,setid,destination,flags,weight,attrs,description" \ - ${src_db}.dispatcher \ - "?id,?setid,?destination,?flags,?weight,?attrs,?description" +## DIALOG modules +# runtime data, nothing to migrate +## DIALPLAN module migrate_table ${dst_db}.dialplan \ "id,dpid,pr,match_op,match_exp,subst_exp,repl_exp,attrs" \ ${src_db}.dialplan \ "?id,?dpid,?pr,?match_op,?match_exp,?subst_exp,?repl_exp,?attrs" -migrate_table ${dst_db}.rtpproxy_sockets \ - "id,rtpproxy_sock,set_id" \ - ${src_db}.nh_sockets \ - "?id,?rtpproxy_sock,?set_id" +## DISPATCHER module (changes here, the flags and state columns) +migrate_table ${dst_db}.dispatcher \ + "id,setid,destination,weight,attrs,description" \ + ${src_db}.dispatcher \ + "?id,?setid,?destination,?weight,?attrs,?description" + +## DOMAIN module +migrate_table ${dst_db}.domain \ + "id,domain,last_modified" \ + ${src_db}.domain \ + "?id,?domain,?last_modified" +## DROUTING module migrate_table ${dst_db}.dr_gateways \ - "gwid,type,address,strip,pri_prefix,attrs,probe_mode,description" \ + "id,gwid,type,address,strip,pri_prefix,attrs,probe_mode,description" \ ${src_db}.dr_gateways \ - "?gwid,?type,?address,?strip,?pri_prefix,?attrs,?probe_mode,?description" + "?id,?gwid,?type,?address,?strip,?pri_prefix,?attrs,?probe_mode,?description" migrate_table ${dst_db}.dr_rules \ "ruleid,groupid,prefix,timerec,priority,routeid,gwlist,attrs,description" \ ${src_db}.dr_rules \ "?ruleid,?groupid,?prefix,?timerec,?priority,?routeid,?gwlist,?attrs,?description" -drr_query=`sql_query "" "select count(*) from ${dst_db}.dr_rules where gwlist like '%;%';" 2>&1` - -if [ $? -ne 0 ] ; then - echo $drr_query | $GREP "ERROR 1146" > /dev/null - if [ $? -neq 0 ] ; then - echo "ERROR: Failed to check dr_rules for unsupported gwlist types" - echo -n "Skip it and continue (y/n)? " - read INPUT - if [ "$INPUT" = "n" ] || [ "$INPUT" = "N" ] - then - exit 1 - fi - fi -fi - -drr_query=`echo $drr_query | head -n 2` -if [ $drr_query -gt 0 ]; -then - mwarn "You currently have rules with gwlists that are not supported any more starting from OpenSIPS 1.8. See the updated DROUTING documentation" -fi - migrate_table ${dst_db}.dr_groups \ "id,username,domain,groupid,description" \ ${src_db}.dr_groups \ "?id,?username,?domain,?groupid,?description" migrate_table ${dst_db}.dr_carriers \ - "id,gwlist,description" \ + "id,carrierid,gwlist,flags,attrs,description" \ ${src_db}.dr_carriers \ - "?id,?gwlist,?description" + "?id,?carrierid,?gwlist,?flags,?attrs,?description" -if [ "$HAS_EXTRA" = "yes" ] ; then - -migrate_table ${dst_db}.cpl \ - "id,username,domain,cpl_xml,cpl_bin" \ - ${src_db}.cpl \ - "?id,?username,?domain,?cpl_xml,?cpl_bin" +## GROUP module +migrate_table ${dst_db}.grp \ + "id,username,domain,grp,last_modified" \ + ${src_db}.grp \ + "?id,?username,?domain,?grp,?last_modified" -migrate_table ${dst_db}.sip_trace \ - "id,time_stamp,callid,traced_user,msg,method,status,fromip,toip,fromtag,direction" \ - ${src_db}.sip_trace \ - "?id,?time_stamp,?callid,?traced_user,?msg,?method,?status,?fromip,?toip, ?fromtag,?direction" +migrate_table ${dst_db}.re_grp \ + "id,reg_exp,group_id" \ + ${src_db}.re_grp \ + "?id,?reg_exp,?group_id" -migrate_table ${dst_db}.imc_rooms \ - "id,name,domain,flag" \ - ${src_db}.imc_rooms \ - "?id,?name,?domain,?flag" +## LOAD_BALANCER module +migrate_table ${dst_db}.load_balancer \ + "id,group_id,dst_uri,resources,probe_mode,description" \ + ${src_db}.load_balancer \ + "?id,?group_id,?dst_uri,?resources,?probe_mode,?description" \ -migrate_table ${dst_db}.imc_members \ - "id,username,domain,room,flag" \ - ${src_db}.imc_members \ - "?id,?username,?domain,?room,?flag" +## MSILO module +migrate_table ${dst_db}.silo \ + "id,src_addr,dst_addr,username,domain,inc_time,exp_time,snd_time,ctype,body" \ + ${src_db}.silo \ + "?id,?src_addr,?dst_addr,?username,?domain,?inc_time,?exp_time,?snd_time,?ctype,?body" + +## PDT module +migrate_table ${dst_db}.pdt \ + "id,sdomain,prefix,domain" \ + ${src_db}.pdt \ + "?id,?sdomain,?prefix,?domain" + +## PERMISSION module +migrate_table ${dst_db}.address \ + "id,grp,ip,mask,port,proto,pattern,context_info" \ + ${src_db}.address \ + "?id,?grp,?ip,?mask,?port,?proto,?pattern,?context_info" + +## REGISTRAR module +migrate_table ${dst_db}.aliases \ + "id,username,domain,contact,received,path,expires,q,callid,cseq,last_modified,flags,cflags,user_agent,socket,methods" \ + ${src_db}.aliases \ + "?id,?username,?domain,?contact,?received,?path,?expires,?q,?callid,?cseq,?last_modified,?flags,?cflags,?user_agent,?socket,?methods" +## RTPPROXY module +migrate_table ${dst_db}.rtpproxy_sockets \ + "id,rtpproxy_sock,set_id" \ + ${src_db}.nh_sockets \ + "?id,?rtpproxy_sock,?set_id" + +## SPEEDDIAL module +migrate_table ${dst_db}.speed_dial \ + "id,username,domain,sd_username,sd_domain,new_uri,fname,lname,description" \ + ${src_db}.speed_dial \ + "?id,?username,?domain,?sd_username,?sd_domain,?new_uri,?fname,?lname,?description" + +## URI_DB module +migrate_table ${dst_db}.uri \ + "id,username,domain,uri_user,last_modified" \ + ${src_db}.uri \ + "?id,?username,?domain,?uri_user,?last_modified" + + +if [ "$HAS_EXTRA" = "yes" ] ; then + +## CARRIERROUTE module migrate_table ${dst_db}.carrierroute \ "id,carrier,domain,scan_prefix,flags,mask,prob,strip,rewrite_host,rewrite_prefix,rewrite_suffix,description" \ ${src_db}.carrierroute \ @@ -453,11 +459,45 @@ migrate_table ${dst_db}.route_tree \ ${src_db}.route_tree \ "?id,?carrier" +## CPL module +migrate_table ${dst_db}.cpl \ + "id,username,domain,cpl_xml,cpl_bin" \ + ${src_db}.cpl \ + "?id,?username,?domain,?cpl_xml,?cpl_bin" + +## DOMAINPOLICY module migrate_table ${dst_db}.domainpolicy \ "id,rule,type,att,val,description" \ ${src_db}.domainpolicy \ "?id,?rule,?type,?att,?val,?description" +## IMC module +migrate_table ${dst_db}.imc_rooms \ + "id,name,domain,flag" \ + ${src_db}.imc_rooms \ + "?id,?name,?domain,?flag" + +migrate_table ${dst_db}.imc_members \ + "id,username,domain,room,flag" \ + ${src_db}.imc_members \ + "?id,?username,?domain,?room,?flag" + +## PRESENCE modules +# runtime data only, nothing to migrate + +## REGISTRANT module +migrate_table ${dst_db}.sip_trace \ + "id,registrar,proxy,aor,third_party_registrant,username,password,binding_URI,binding_params,expiry,forced_socket" \ + ${src_db}.sip_trace \ + "?id,?registrar,?proxy,?aor,?third_party_registrant,?username,?password,?binding_URI,?binding_params,?expiry,?forced_socket" + +## SIPTRACE module +migrate_table ${dst_db}.sip_trace \ + "id,time_stamp,callid,traced_user,msg,method,status,fromip,toip,fromtag,direction" \ + ${src_db}.sip_trace \ + "?id,?time_stamp,?callid,?traced_user,?msg,?method,?status,?fromip,?toip, ?fromtag,?direction" + +## USERBLACKLIST module migrate_table ${dst_db}.userblacklist \ "id,username,domain,prefix,whitelist" \ ${src_db}.userblacklist \ diff --git a/scripts/opensipsdbctl.pgsql b/scripts/opensipsdbctl.pgsql index 98c10c58b7e..2628ce01b17 100644 --- a/scripts/opensipsdbctl.pgsql +++ b/scripts/opensipsdbctl.pgsql @@ -50,8 +50,14 @@ if [ -z "$DBROOTUSER" ]; then fi fi -CMD="psql -q -h $DBHOST -U $DBROOTUSER " -DUMP_CMD="pg_dump -h $DBHOST -U $DBROOTUSER -c" +if ! [ -z "$DBPORT" ]; then + PORT_OPT="-p$DBPORT" +else + PORT_OPT= +fi + +CMD="psql -q -h $DBHOST $PORT_OPT -U $DBROOTUSER " +DUMP_CMD="pg_dump -h $DBHOST $PORT_OPT -U $DBROOTUSER -c" ################################################################# diff --git a/scripts/oracle/b2b_sca-create.sql b/scripts/oracle/b2b_sca-create.sql new file mode 100644 index 00000000000..9c9ef5697fe --- /dev/null +++ b/scripts/oracle/b2b_sca-create.sql @@ -0,0 +1,66 @@ +INSERT INTO version (table_name, table_version) values ('b2b_sca','1'); +CREATE TABLE b2b_sca ( + id NUMBER(10) PRIMARY KEY, + shared_line VARCHAR2(64), + watchers VARCHAR2(255), + app1_shared_entity NUMBER(10) DEFAULT NULL, + app1_call_state NUMBER(10) DEFAULT NULL, + app1_call_info_uri VARCHAR2(128) DEFAULT NULL, + app1_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app1_b2bl_key VARCHAR2(64) DEFAULT NULL, + app2_shared_entity NUMBER(10) DEFAULT NULL, + app2_call_state NUMBER(10) DEFAULT NULL, + app2_call_info_uri VARCHAR2(128) DEFAULT NULL, + app2_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app2_b2bl_key VARCHAR2(64) DEFAULT NULL, + app3_shared_entity NUMBER(10) DEFAULT NULL, + app3_call_state NUMBER(10) DEFAULT NULL, + app3_call_info_uri VARCHAR2(128) DEFAULT NULL, + app3_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app3_b2bl_key VARCHAR2(64) DEFAULT NULL, + app4_shared_entity NUMBER(10) DEFAULT NULL, + app4_call_state NUMBER(10) DEFAULT NULL, + app4_call_info_uri VARCHAR2(128) DEFAULT NULL, + app4_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app4_b2bl_key VARCHAR2(64) DEFAULT NULL, + app5_shared_entity NUMBER(10) DEFAULT NULL, + app5_call_state NUMBER(10) DEFAULT NULL, + app5_call_info_uri VARCHAR2(128) DEFAULT NULL, + app5_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app5_b2bl_key VARCHAR2(64) DEFAULT NULL, + app6_shared_entity NUMBER(10) DEFAULT NULL, + app6_call_state NUMBER(10) DEFAULT NULL, + app6_call_info_uri VARCHAR2(128) DEFAULT NULL, + app6_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app6_b2bl_key VARCHAR2(64) DEFAULT NULL, + app7_shared_entity NUMBER(10) DEFAULT NULL, + app7_call_state NUMBER(10) DEFAULT NULL, + app7_call_info_uri VARCHAR2(128) DEFAULT NULL, + app7_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app7_b2bl_key VARCHAR2(64) DEFAULT NULL, + app8_shared_entity NUMBER(10) DEFAULT NULL, + app8_call_state NUMBER(10) DEFAULT NULL, + app8_call_info_uri VARCHAR2(128) DEFAULT NULL, + app8_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app8_b2bl_key VARCHAR2(64) DEFAULT NULL, + app9_shared_entity NUMBER(10) DEFAULT NULL, + app9_call_state NUMBER(10) DEFAULT NULL, + app9_call_info_uri VARCHAR2(128) DEFAULT NULL, + app9_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app9_b2bl_key VARCHAR2(64) DEFAULT NULL, + app10_shared_entity NUMBER(10) DEFAULT NULL, + app10_call_state NUMBER(10) DEFAULT NULL, + app10_call_info_uri VARCHAR2(128) DEFAULT NULL, + app10_call_info_appearance_uri VARCHAR2(128) DEFAULT NULL, + app10_b2bl_key VARCHAR2(64) DEFAULT NULL, + CONSTRAINT b2b_sca_sca_idx UNIQUE (shared_line) +); + +CREATE OR REPLACE TRIGGER b2b_sca_tr +before insert on b2b_sca FOR EACH ROW +BEGIN + auto_id(:NEW.id); +END b2b_sca_tr; +/ +BEGIN map2users('b2b_sca'); END; +/ diff --git a/scripts/oracle/cachedb_sql-create.sql b/scripts/oracle/cachedb_sql-create.sql index cea5888a7c6..6082ab6bca5 100644 --- a/scripts/oracle/cachedb_sql-create.sql +++ b/scripts/oracle/cachedb_sql-create.sql @@ -1,6 +1,6 @@ -INSERT INTO version (table_name, table_version) values ('cachedb','1'); +INSERT INTO version (table_name, table_version) values ('cachedb','2'); CREATE TABLE cachedb ( - keyname VARCHAR2(255), + keyname VARCHAR2(255) PRIMARY KEY, value CLOB(512), counter NUMBER(10) DEFAULT 0 NOT NULL, expires NUMBER(10) DEFAULT 0 NOT NULL diff --git a/scripts/oracle/call_center-create.sql b/scripts/oracle/call_center-create.sql new file mode 100644 index 00000000000..c986a7ae309 --- /dev/null +++ b/scripts/oracle/call_center-create.sql @@ -0,0 +1,88 @@ +INSERT INTO version (table_name, table_version) values ('cc_flows','1'); +CREATE TABLE cc_flows ( + id NUMBER(10) PRIMARY KEY, + flowid VARCHAR2(64), + priority NUMBER(10) DEFAULT 256 NOT NULL, + skill VARCHAR2(64), + prependcid VARCHAR2(32), + message_welcome VARCHAR2(128) DEFAULT NULL, + message_queue VARCHAR2(128), + CONSTRAINT cc_flows_unique_flowid UNIQUE (flowid) +); + +CREATE OR REPLACE TRIGGER cc_flows_tr +before insert on cc_flows FOR EACH ROW +BEGIN + auto_id(:NEW.id); +END cc_flows_tr; +/ +BEGIN map2users('cc_flows'); END; +/ +INSERT INTO version (table_name, table_version) values ('cc_agents','1'); +CREATE TABLE cc_agents ( + id NUMBER(10) PRIMARY KEY, + agentid VARCHAR2(128), + location VARCHAR2(128), + logstate NUMBER(10) DEFAULT 0 NOT NULL, + skills VARCHAR2(255), + last_call_end NUMBER(10) DEFAULT 0 NOT NULL, + CONSTRAINT cc_agents_unique_agentid UNIQUE (agentid) +); + +CREATE OR REPLACE TRIGGER cc_agents_tr +before insert on cc_agents FOR EACH ROW +BEGIN + auto_id(:NEW.id); +END cc_agents_tr; +/ +BEGIN map2users('cc_agents'); END; +/ +INSERT INTO version (table_name, table_version) values ('cc_cdrs','1'); +CREATE TABLE cc_cdrs ( + id NUMBER(10) PRIMARY KEY, + caller VARCHAR2(64), + received_timestamp DATE, + wait_time NUMBER(10) DEFAULT 0 NOT NULL, + pickup_time NUMBER(10) DEFAULT 0 NOT NULL, + talk_time NUMBER(10) DEFAULT 0 NOT NULL, + flow_id VARCHAR2(128), + agent_id VARCHAR2(128) DEFAULT NULL, + call_type NUMBER(10) DEFAULT -1 NOT NULL, + rejected NUMBER(10) DEFAULT 0 NOT NULL, + fstats NUMBER(10) DEFAULT 0 NOT NULL, + cid NUMBER(10) DEFAULT 0 +); + +CREATE OR REPLACE TRIGGER cc_cdrs_tr +before insert on cc_cdrs FOR EACH ROW +BEGIN + auto_id(:NEW.id); +END cc_cdrs_tr; +/ +BEGIN map2users('cc_cdrs'); END; +/ +CREATE TABLE cc_calls ( + id NUMBER(10), + state NUMBER(10), + ig_cback NUMBER(10), + no_rej NUMBER(10), + setup_time NUMBER(10), + eta NUMBER(10), + last_start NUMBER(10), + recv_time NUMBER(10), + caller_dn VARCHAR2(128), + caller_un VARCHAR2(128), + b2buaid VARCHAR2(128) PRIMARY KEY DEFAULT '', + flow VARCHAR2(128), + agent VARCHAR2(128), + CONSTRAINT cc_calls_unique_id UNIQUE (id) +); + +CREATE OR REPLACE TRIGGER cc_calls_tr +before insert on cc_calls FOR EACH ROW +BEGIN + auto_id(:NEW.id); +END cc_calls_tr; +/ +BEGIN map2users('cc_calls'); END; +/ diff --git a/scripts/oracle/dialog-create.sql b/scripts/oracle/dialog-create.sql index a9a10ced0f6..75274476a8e 100644 --- a/scripts/oracle/dialog-create.sql +++ b/scripts/oracle/dialog-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('dialog','8'); +INSERT INTO version (table_name, table_version) values ('dialog','10'); CREATE TABLE dialog ( dlg_id BIGINT(10) PRIMARY KEY, callid VARCHAR2(255), @@ -21,9 +21,10 @@ CREATE TABLE dialog ( state NUMBER(10), start_time NUMBER(10), timeout NUMBER(10), - vars CLOB(512) DEFAULT NULL, + vars BLOB(4096) DEFAULT NULL, profiles CLOB(512) DEFAULT NULL, script_flags NUMBER(10) DEFAULT 0 NOT NULL, + module_flags NUMBER(10) DEFAULT 0 NOT NULL, flags NUMBER(10) DEFAULT 0 NOT NULL ); diff --git a/scripts/oracle/dialplan-create.sql b/scripts/oracle/dialplan-create.sql index 65e42863f3a..190bf3eb212 100644 --- a/scripts/oracle/dialplan-create.sql +++ b/scripts/oracle/dialplan-create.sql @@ -8,6 +8,7 @@ CREATE TABLE dialplan ( match_flags NUMBER(10), subst_exp VARCHAR2(64), repl_exp VARCHAR2(32), + timerec VARCHAR2(255), disabled NUMBER(10) DEFAULT 0 NOT NULL, attrs VARCHAR2(32) ); diff --git a/scripts/oracle/dispatcher-create.sql b/scripts/oracle/dispatcher-create.sql index 4183f95f1f3..93975103ce1 100644 --- a/scripts/oracle/dispatcher-create.sql +++ b/scripts/oracle/dispatcher-create.sql @@ -1,11 +1,12 @@ -INSERT INTO version (table_name, table_version) values ('dispatcher','5'); +INSERT INTO version (table_name, table_version) values ('dispatcher','7'); CREATE TABLE dispatcher ( id NUMBER(10) PRIMARY KEY, setid NUMBER(10) DEFAULT 0 NOT NULL, destination VARCHAR2(192) DEFAULT '', socket VARCHAR2(128) DEFAULT NULL, - flags NUMBER(10) DEFAULT 0 NOT NULL, + state NUMBER(10) DEFAULT 0 NOT NULL, weight NUMBER(10) DEFAULT 1 NOT NULL, + priority NUMBER(10) DEFAULT 0 NOT NULL, attrs VARCHAR2(128) DEFAULT '', description VARCHAR2(64) DEFAULT '' ); diff --git a/scripts/oracle/domain-create.sql b/scripts/oracle/domain-create.sql index 46a7b4634f3..9bf5c47c625 100644 --- a/scripts/oracle/domain-create.sql +++ b/scripts/oracle/domain-create.sql @@ -1,7 +1,8 @@ -INSERT INTO version (table_name, table_version) values ('domain','2'); +INSERT INTO version (table_name, table_version) values ('domain','3'); CREATE TABLE domain ( id NUMBER(10) PRIMARY KEY, domain VARCHAR2(64) DEFAULT '', + attrs VARCHAR2(255) DEFAULT NULL, last_modified DATE DEFAULT to_date('1900-01-01 00:00:01','yyyy-mm-dd hh24:mi:ss'), CONSTRAINT domain_domain_idx UNIQUE (domain) ); diff --git a/scripts/oracle/drouting-create.sql b/scripts/oracle/drouting-create.sql index db308a8d68e..e2950ae91b8 100644 --- a/scripts/oracle/drouting-create.sql +++ b/scripts/oracle/drouting-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('dr_gateways','5'); +INSERT INTO version (table_name, table_version) values ('dr_gateways','6'); CREATE TABLE dr_gateways ( id NUMBER(10) PRIMARY KEY, gwid VARCHAR2(64), @@ -8,6 +8,8 @@ CREATE TABLE dr_gateways ( pri_prefix VARCHAR2(16) DEFAULT NULL, attrs VARCHAR2(255) DEFAULT NULL, probe_mode NUMBER(10) DEFAULT 0 NOT NULL, + state NUMBER(10) DEFAULT 0 NOT NULL, + socket VARCHAR2(128) DEFAULT NULL, description VARCHAR2(128) DEFAULT '', CONSTRAINT dr_gateways_dr_gw_idx UNIQUE (gwid) ); @@ -41,12 +43,13 @@ END dr_rules_tr; / BEGIN map2users('dr_rules'); END; / -INSERT INTO version (table_name, table_version) values ('dr_carriers','1'); +INSERT INTO version (table_name, table_version) values ('dr_carriers','2'); CREATE TABLE dr_carriers ( id NUMBER(10) PRIMARY KEY, carrierid VARCHAR2(64), gwlist VARCHAR2(255), flags NUMBER(10) DEFAULT 0 NOT NULL, + state NUMBER(10) DEFAULT 0 NOT NULL, attrs VARCHAR2(255) DEFAULT '', description VARCHAR2(128) DEFAULT '', CONSTRAINT dr_carriers_dr_carrier_idx UNIQUE (carrierid) @@ -77,3 +80,29 @@ END dr_groups_tr; / BEGIN map2users('dr_groups'); END; / +INSERT INTO version (table_name, table_version) values ('dr_partitions','1'); +CREATE TABLE dr_partitions ( + id NUMBER(10) PRIMARY KEY, + partition_name VARCHAR2(255), + db_url VARCHAR2(255), + drd_table VARCHAR2(255), + drr_table VARCHAR2(255), + drg_table VARCHAR2(255), + drc_table VARCHAR2(255), + ruri_avp VARCHAR2(255), + gw_id_avp VARCHAR2(255), + gw_priprefix_avp VARCHAR2(255), + gw_sock_avp VARCHAR2(255), + rule_id_avp VARCHAR2(255), + rule_prefix_avp VARCHAR2(255), + carrier_id_avp VARCHAR2(255) +); + +CREATE OR REPLACE TRIGGER dr_partitions_tr +before insert on dr_partitions FOR EACH ROW +BEGIN + auto_id(:NEW.id); +END dr_partitions_tr; +/ +BEGIN map2users('dr_partitions'); END; +/ diff --git a/scripts/oracle/msilo-create.sql b/scripts/oracle/msilo-create.sql index 1ae2b27c10f..c08dd0b5641 100644 --- a/scripts/oracle/msilo-create.sql +++ b/scripts/oracle/msilo-create.sql @@ -8,8 +8,8 @@ CREATE TABLE silo ( inc_time NUMBER(10) DEFAULT 0 NOT NULL, exp_time NUMBER(10) DEFAULT 0 NOT NULL, snd_time NUMBER(10) DEFAULT 0 NOT NULL, - ctype VARCHAR2(32) DEFAULT 'text/plain', - body BLOB DEFAULT '' + ctype VARCHAR2(255) DEFAULT NULL, + body BLOB ); CREATE OR REPLACE TRIGGER silo_tr diff --git a/scripts/oracle/presence-create.sql b/scripts/oracle/presence-create.sql index 9d9f10e2011..b9658b79eaa 100644 --- a/scripts/oracle/presence-create.sql +++ b/scripts/oracle/presence-create.sql @@ -132,3 +132,7 @@ END pua_tr; / BEGIN map2users('pua'); END; / +CREATE INDEX pua_del1_idx ON pua (pres_uri, event); +CREATE INDEX pua_del2_idx ON pua (expires); +CREATE INDEX pua_update_idx ON pua (pres_uri, pres_id, flag, event); + diff --git a/scripts/oracle/siptrace-create.sql b/scripts/oracle/siptrace-create.sql index d083e2d9627..173226a08e5 100644 --- a/scripts/oracle/siptrace-create.sql +++ b/scripts/oracle/siptrace-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('sip_trace','3'); +INSERT INTO version (table_name, table_version) values ('sip_trace','4'); CREATE TABLE sip_trace ( id NUMBER(10) PRIMARY KEY, time_stamp DATE DEFAULT to_date('1900-01-01 00:00:01','yyyy-mm-dd hh24:mi:ss'), @@ -7,8 +7,12 @@ CREATE TABLE sip_trace ( msg CLOB, method VARCHAR2(32) DEFAULT '', status VARCHAR2(128) DEFAULT NULL, - fromip VARCHAR2(50) DEFAULT '', - toip VARCHAR2(50) DEFAULT '', + from_proto VARCHAR2(5), + from_ip VARCHAR2(50) DEFAULT '', + from_port NUMBER(10), + to_proto VARCHAR2(5), + to_ip VARCHAR2(50) DEFAULT '', + to_port NUMBER(10), fromtag VARCHAR2(64) DEFAULT '', direction VARCHAR2(4) DEFAULT '' ); @@ -23,6 +27,6 @@ BEGIN map2users('sip_trace'); END; / CREATE INDEX sip_trace_traced_user_idx ON sip_trace (traced_user); CREATE INDEX sip_trace_date_idx ON sip_trace (time_stamp); -CREATE INDEX sip_trace_fromip_idx ON sip_trace (fromip); +CREATE INDEX sip_trace_fromip_idx ON sip_trace (from_ip); CREATE INDEX sip_trace_callid_idx ON sip_trace (callid); diff --git a/scripts/oracle/usrloc-create.sql b/scripts/oracle/usrloc-create.sql index efb2a1a295d..6eac275ddfe 100644 --- a/scripts/oracle/usrloc-create.sql +++ b/scripts/oracle/usrloc-create.sql @@ -1,22 +1,23 @@ -INSERT INTO version (table_name, table_version) values ('location','1007'); +INSERT INTO version (table_name, table_version) values ('location','1009'); CREATE TABLE location ( id NUMBER(10) PRIMARY KEY, username VARCHAR2(64) DEFAULT '', domain VARCHAR2(64) DEFAULT '', contact VARCHAR2(255) DEFAULT '', received VARCHAR2(128) DEFAULT NULL, - path VARCHAR2(128) DEFAULT NULL, + path VARCHAR2(255) DEFAULT NULL, expires DATE DEFAULT to_date('2020-05-28 21:32:15','yyyy-mm-dd hh24:mi:ss'), q NUMBER(10,2) DEFAULT 1.0 NOT NULL, callid VARCHAR2(255) DEFAULT 'Default-Call-ID', cseq NUMBER(10) DEFAULT 13 NOT NULL, last_modified DATE DEFAULT to_date('1900-01-01 00:00:01','yyyy-mm-dd hh24:mi:ss'), flags NUMBER(10) DEFAULT 0 NOT NULL, - cflags NUMBER(10) DEFAULT 0 NOT NULL, + cflags VARCHAR2(255) DEFAULT NULL, user_agent VARCHAR2(255) DEFAULT '', socket VARCHAR2(64) DEFAULT NULL, methods NUMBER(10) DEFAULT NULL, sip_instance VARCHAR2(255) DEFAULT NULL, + attr VARCHAR2(255) DEFAULT NULL, CONSTRAINT location_account_contact_idx UNIQUE (username, domain, contact, callid) ); diff --git a/scripts/osipsconsole b/scripts/osipsconsole index 8197ea279d2..021959888df 100755 --- a/scripts/osipsconsole +++ b/scripts/osipsconsole @@ -138,7 +138,8 @@ my @EXTRA_TABLES = ('imc_members', 'imc_rooms', 'cpl', 'sip_trace', 'domainpolicy', 'carrierroute', 'route_tree', 'carrierfailureroute', 'userblacklist', 'globalblacklist'); -my @EXTRA_MODULES = ('imc', 'cpl', 'siptrace', 'domainpolicy', 'carrierroute', 'userblacklist'); +my @EXTRA_MODULES = ('imc', 'cpl', 'siptrace', 'domainpolicy', 'carrierroute', + 'userblacklist', 'b2b', 'registrant', 'call_center'); my @PRESENCE_TABLES = ('presentity', 'active_watchers', 'watchers', 'xcap', 'pua'); @@ -258,7 +259,6 @@ while ( $#content gt -1 ){ } } elsif ( $arr[0] eq "MI_CONNECTOR" ) { - print "bla"; $MI_CONNECTOR = $arr[1]; @list = split(":",$arr[1]); $CTLENGINE = $list[0]; @@ -396,6 +396,10 @@ if ( $DBHOST eq "" ) { $DBHOST = "localhost"; } +if ( $DBPORT eq "" ) { + $DBPORT = "3306"; +} + if ( $DBRWUSER eq "" ) { $DBRWUSER = "opensips"; } @@ -694,7 +698,10 @@ if ( not defined $DISPATCHER_TABLE ){ my %dispatcher_table = ('DISPATCHER_ID_COLUMN' => 'id', 'DISPATCHER_SETID_COLUMN' => 'setid', 'DISPATCHER_DESTINATION_COLUMN' => 'destination', - 'DISPATCHER_FLAGS_COLUMN' => 'flags', + 'DISPATCHER_SOCKET_COLUMN' => 'socket', + 'DISPATCHER_STATE_COLUMN' => 'state', + 'DISPATCHER_WEIGHT_COLUMN' => 'weight', + 'DISPATCHER_ATTRS_COLUMN' => 'attrs', 'DISPATCHER_DESCRIPTION_COLUMN' => 'description' ); @@ -891,16 +898,16 @@ sub usage_address() { #dispatcher sub usage_dispatcher() { - print " -- command 'dispatcher' - manage dispatcher\n" . - "* Examples: dispatcher addgw 1 sip:1.2.3.1:5050 1 'outbound gateway'\n" . - "* dispatcher addgw 2 sip:1.2.3.4:5050 3 ''\n" . - "* dispatcher rmgw 4\n" . - "dispatcher show ..................... show dispatcher gateways\n" . - "dispatcher reload ................... reload dispatcher gateways\n" . - "dispatcher dump ..................... show in memory dispatcher gateways\n" . - "dispatcher addgw \n" . - "\t\t\t.......................... add gateway\n" . - "dispatcher rmgw ................ delete gateway\n"; + print " -- command 'dispatcher' - manage dispatcher\n" . + "* Examples: dispatcher addgw 1 sip:1.2.3.1:5050 '' 0 50 'og1' 'Outbound Gateway1'\n" . + "* dispatcher addgw 2 sip:1.2.3.4:5050 '' 0 50 'og2' 'Outbound Gateway2'\n" . + "* dispatcher rmgw 4\n" . + "dispatcher show ..................... show dispatcher gateways\n" . + "dispatcher reload ................... reload dispatcher gateways\n" . + "dispatcher dump ..................... show in memory dispatcher gateways\n" . + "dispatcher addgw [description]\n" . + " .......................... add gateway\n" . + "dispatcher rmgw ................ delete gateway\n"; } @@ -1014,7 +1021,7 @@ my $COMMAND=`basename $0`; "db create ....(creates a new database)\n". "db presence .................................(adds the presence related tables)\n". "db extra ....................................(adds the extra tables)\n". - "db migrate ................(migrates DB from 1.5 to 1.6)\n". + "db migrate ................(migrates DB from 1.8 to 1.9)\n". "db drop ......(!entirely deletes tables!)\n". "db reinit ....(!entirely deletes and than re-creates tables!)\n". "db backup ............................(dumps current database to file)\n". @@ -1353,11 +1360,11 @@ sub db_load() { print "Used database is mysql\n"; &validate_dbdata("mysql"); #Connect to the database. - $dbh = DBI->connect("DBI:mysql:database=$DBNAME;host=$DBHOST", + $dbh = DBI->connect("DBI:mysql:database=$DBNAME;host=$DBHOST;port=$DBPORT", "$DBRWUSER", "$DBRWPW", {'PrintError' => 0} ); if ($dbh==NULL) { print "Failed to connect the configured Database ". - "(database=$DBNAME;host=$DBHOST;user=$DBRWUSER)"; + "(database=$DBNAME;host=$DBHOST;port=$DBPORT;user=$DBRWUSER)"; $DBENGINELOADED = 0; return 0; } @@ -2790,11 +2797,11 @@ sub address() { ### DISPATCHER management # sub opensips_dispatcher() { - if ( $#cmd lt 1 ) { + if ( $#cmd lt 6 ) { print "Too few parameters!\n"; &usage_dispatcher(); return; - } elsif ( $#cmd gt 5 ) { + } elsif ( $#cmd gt 8 ) { print "Too many parameters!\n"; &usage_dispatcher(); return; @@ -2835,45 +2842,72 @@ sub opensips_dispatcher() { elsif ($cmd[1] =~ /^addgw$/) { - my ( $DISPATCHER_DESCRIPTION, $DISPATCHER_SETID, $DISPATCHER_DESTINATION, $DISPATCHER_FLAGS); + my ( $DISPATCHER_SETID, $DISPATCHER_DESTINATION, $DISPATCHER_SOCKET, $DISPATCHER_STATE, $DISPATCHER_WEIGHT, $DISPATCHER_ATTRS, $DISPATCHER_DESCRIPTION); - if ( $#cmd lt 5 ) { + if ( $#cmd lt 7 ) { print "Too few parameters!\n"; &usage_dispatcher(); return; } - if ( $#cmd gt 5 ) { + if ( $#cmd gt 8 ) { print "Too many parameters!\n"; &usage_dispatcher(); return; } - if ( $#cmd gt 3 ) { - $DISPATCHER_DESCRIPTION = $cmd[5]; + if ( $#cmd gt 7 ) { + $DISPATCHER_DESCRIPTION = $cmd[8]; } else { $DISPATCHER_DESCRIPTION = ""; } $DISPATCHER_SETID = $cmd[2]; $DISPATCHER_DESTINATION = $cmd[3]; - $DISPATCHER_FLAGS = $cmd[4]; + $DISPATCHER_SOCKET = $cmd[4]; + $DISPATCHER_STATE = $cmd[5]; + $DISPATCHER_WEIGHT = $cmd[6]; + $DISPATCHER_ATTRS = $cmd[7]; if ( $DBENGINE =~ /^DB_BERKELEY$/ ) { - my $key = join(" ",$DISPATCHER_SETID,$DISPATCHER_FLAGS); + my $key = join(" ",$DISPATCHER_SETID,$DISPATCHER_STATE); my $value = join(" ",$DISPATCHER_DESTINATION,$DISPATCHER_DESCRIPTION); &bdb_insert($DISPATCHER_TABLE,$key,$value); } elsif ( $DBENGINE =~ /^DBTEXT$/ ) { - system ("$DBTEXTCMD"," INSERT INTO $DISPATCHER_TABLE ( $dispatcher_table{'DISPATCHER_SETID_COLUMN'}, - $dispatcher_table{'DISPATCHER_DESTINATION_COLUMN'}, $dispatcher_table{'DISPATCHER_FLAGS_COLUMN'}, - $dispatcher_table{'DISPATCHER_DESCRIPTION_COLUMN'} ) - VALUES ($DISPATCHER_SETID,\'$DISPATCHER_DESTINATION\',$DISPATCHER_FLAGS,\'$DISPATCHER_DESCRIPTION\') "); + system ("$DBTEXTCMD"," INSERT INTO $DISPATCHER_TABLE ( + $dispatcher_table{'DISPATCHER_SETID_COLUMN'}, + $dispatcher_table{'DISPATCHER_DESTINATION_COLUMN'}, + $dispatcher_table{'DISPATCHER_SOCKET_COLUMN'}, + $dispatcher_table{'DISPATCHER_STATE_COLUMN'}, + $dispatcher_table{'DISPATCHER_WEIGHT_COLUMN'}, + $dispatcher_table{'DISPATCHER_ATTRS_COLUMN'}, + $dispatcher_table{'DISPATCHER_DESCRIPTION_COLUMN'} ) + VALUES ( + $DISPATCHER_SETID, + \'$DISPATCHER_DESTINATION\', + \'$DISPATCHER_SOCKET\', + $DISPATCHER_STATE, + $DISPATCHER_WEIGHT, + \'$DISPATCHER_ATTRS\', + \'$DISPATCHER_DESCRIPTION\') "); } else { - $sth = $dbh->prepare( " INSERT INTO $DISPATCHER_TABLE ( $dispatcher_table{'DISPATCHER_SETID_COLUMN'}, - $dispatcher_table{'DISPATCHER_DESTINATION_COLUMN'}, $dispatcher_table{'DISPATCHER_FLAGS_COLUMN'}, - $dispatcher_table{'DISPATCHER_DESCRIPTION_COLUMN'} ) - VALUES ($DISPATCHER_SETID,\'$DISPATCHER_DESTINATION\',$DISPATCHER_FLAGS,\'$DISPATCHER_DESCRIPTION\') " ); + $sth = $dbh->prepare( " INSERT INTO $DISPATCHER_TABLE ( + $dispatcher_table{'DISPATCHER_SETID_COLUMN'}, + $dispatcher_table{'DISPATCHER_DESTINATION_COLUMN'}, + $dispatcher_table{'DISPATCHER_SOCKET_COLUMN'}, + $dispatcher_table{'DISPATCHER_STATE_COLUMN'}, + $dispatcher_table{'DISPATCHER_WEIGHT_COLUMN'}, + $dispatcher_table{'DISPATCHER_ATTRS_COLUMN'}, + $dispatcher_table{'DISPATCHER_DESCRIPTION_COLUMN'} ) + VALUES ( + $DISPATCHER_SETID, + \'$DISPATCHER_DESTINATION\', + \'$DISPATCHER_SOCKET\', + $DISPATCHER_STATE, + $DISPATCHER_WEIGHT, + \'$DISPATCHER_ATTRS\', + \'$DISPATCHER_DESCRIPTION\') " ); #execute the query $sth->execute( ); @@ -2882,7 +2916,7 @@ sub opensips_dispatcher() { $sth->finish(); } - &mi_comm('ds_reload'); + &mi_comm('ds_reload'); } @@ -6333,7 +6367,7 @@ sub mysql_migrate_table(){ # 4 paremeters (dst_table, dst_cols, src_table, src_c $src_cols=`echo $src_cols | sed s/?/$src_table./g `; if ( $PW eq "" ) { - $X = system("mysql -h $DBHOST -u$DBROOTUSER -e \"INSERT INTO $dst_table ($dst_cols) SELECT $src_cols FROM $src_table\""); + $X = system("mysql -h $DBHOST -P $DBPORT -u$DBROOTUSER -e \"INSERT INTO $dst_table ($dst_cols) SELECT $src_cols FROM $src_table\""); if ( $? != 0 ) { system("echo $X | $EGREP \"ERROR 1146\" > /dev/null"); if ( $? != 0 ) { @@ -6347,7 +6381,7 @@ sub mysql_migrate_table(){ # 4 paremeters (dst_table, dst_cols, src_table, src_c } } } else { - $X = system("mysql -h $DBHOST -u$DBROOTUSER -p$PW -e \"INSERT INTO $dst_table ($dst_cols) SELECT $src_cols FROM $src_table\""); + $X = system("mysql -h $DBHOST -P $DBPORT -u$DBROOTUSER -p$PW -e \"INSERT INTO $dst_table ($dst_cols) SELECT $src_cols FROM $src_table\""); if ( $? != 0 ) { system("echo $X | $EGREP \"ERROR 1146\" > /dev/null"); if ( $? != 0 ) { @@ -6381,7 +6415,7 @@ sub opensips_dump() { if ( $DBENGINE =~ /^mysql$/ ) { if ( $PW eq "" ) { - system("mysqldump -h $DBHOST -u$DBROOTUSER -c -t $_[0] > $_[1]"); + system("mysqldump -h $DBHOST -P $DBPORT -u$DBROOTUSER -c -t $_[0] > $_[1]"); if ( $? != 0 ) { print "db dump failed\n"; return; @@ -6390,7 +6424,7 @@ sub opensips_dump() { return; } } else { - system("mysqldump -h $DBHOST -u$DBROOTUSER -p$PW -c -t $_[0] > $_[1]"); + system("mysqldump -h $DBHOST -P $DBPORT -u$DBROOTUSER -p$PW -c -t $_[0] > $_[1]"); if ( $? != 0 ) { print "db dump failed\n"; return; @@ -6450,7 +6484,7 @@ sub opensips_restore() { #pars: # sub mysql_query() { - my $MYSQL_CMD="mysql -h $DBHOST -u$DBROOTUSER "; + my $MYSQL_CMD="mysql -h $DBHOST -P $DBPORT -u$DBROOTUSER "; if ( $#_ > 0 ) { if ( $PW eq "") { system("$MYSQL_CMD -D $_[0] -e \"$_[1]\""); @@ -6534,7 +6568,7 @@ sub db_mysql_query() { # if password not yet queried, query it now #&prompt_pw(); "MySQL password for user '$DBRWUSER@$DBHOST'" - system("$MYSQL -h $DBHOST -u$DBRWUSER \"-p$DBRWPW\" -D $DBNAME -e \"$query\";"); + system("$MYSQL -h $DBHOST -P $DBPORT -u$DBRWUSER \"-p$DBRWPW\" -D $DBNAME -e \"$query\";"); if ( $? != 0 ) { return 1; } else { diff --git a/scripts/osipsconsolerc b/scripts/osipsconsolerc index 89fb4f46a91..970c55c29cb 100644 --- a/scripts/osipsconsolerc +++ b/scripts/osipsconsolerc @@ -64,7 +64,8 @@ # dialplan drouting nathelper load_balancer" # opensips extra modules -# EXTRA_MODULES="imc cpl siptrace domainpolicy carrierroute userblacklist" +# EXTRA_MODULES="imc cpl siptrace domainpolicy carrierroute userblacklist +# b2b registrant call_center" ## type of aliases used: DB - database aliases; UL - usrloc aliases diff --git a/scripts/pi_http/acc-mod b/scripts/pi_http/acc-mod index efa02a457fc..726d38a5802 100644 --- a/scripts/pi_http/acc-mod +++ b/scripts/pi_http/acc-mod @@ -4,7 +4,7 @@ acc DB_QUERY -
id + idupdate method from_tag to_tag @@ -17,6 +17,48 @@ created + add + acc + DB_INSERT + + method + from_tag + to_tag + callid + sip_code + sip_reason + time + duration + setuptime + created + + + update + acc + DB_UPDATE + + id= + + + method + from_tag + to_tag + callid + sip_code + sip_reason + time + duration + setuptime + created + + + delete + acc + DB_DELETE + + id= + + missed_calls @@ -24,7 +66,20 @@ missed_calls DB_QUERY - id + idupdate + method + from_tag + to_tag + callid + sip_code + sip_reason + time + + + add + missed_calls + DB_INSERT + method from_tag to_tag @@ -34,4 +89,27 @@ time + update + missed_calls + DB_UPDATE + + id= + + + method + from_tag + to_tag + callid + sip_code + sip_reason + time + + + delete + missed_calls + DB_DELETE + + id= + + diff --git a/scripts/pi_http/alias_db-mod b/scripts/pi_http/alias_db-mod index 8e92b5e17b7..1f00902d16e 100644 --- a/scripts/pi_http/alias_db-mod +++ b/scripts/pi_http/alias_db-mod @@ -4,11 +4,41 @@ dbaliases DB_QUERY - id + idupdate alias_username alias_domain username domain + add + dbaliases + DB_INSERT + + alias_username + alias_domain + username + domain + + + update + dbaliases + DB_UPDATE + + id= + + + alias_username + alias_domain + username + domain + + + delete + dbaliases + DB_DELETE + + id= + + diff --git a/scripts/pi_http/auth_db-mod b/scripts/pi_http/auth_db-mod index da0ea3ac81a..7890f97bb69 100644 --- a/scripts/pi_http/auth_db-mod +++ b/scripts/pi_http/auth_db-mod @@ -4,7 +4,7 @@ subscriber DB_QUERY - id + idupdate username domain password @@ -14,4 +14,40 @@ rpid + add + subscriber + DB_INSERT + + username + domain + password + email_address + ha1 + ha1b + rpid + + + update + subscriber + DB_UPDATE + + id= + + + username + domain + password + email_address + ha1 + ha1b + rpid + + + delete + subscriber + DB_DELETE + + id= + + diff --git a/scripts/pi_http/avpops-mod b/scripts/pi_http/avpops-mod index d48b578d98a..a11a2732eef 100644 --- a/scripts/pi_http/avpops-mod +++ b/scripts/pi_http/avpops-mod @@ -4,7 +4,7 @@ usr_preferences DB_QUERY - id + idupdate uuid username domain @@ -14,4 +14,40 @@ last_modified + add + usr_preferences + DB_INSERT + + uuid + username + domain + attribute + type + value + last_modified + + + update + usr_preferences + DB_UPDATE + + id= + + + uuid + username + domain + attribute + type + value + last_modified + + + delete + usr_preferences + DB_DELETE + + id= + + diff --git a/scripts/pi_http/b2b-mod b/scripts/pi_http/b2b-mod index 612ff0a6ed0..245e8eb1eaa 100644 --- a/scripts/pi_http/b2b-mod +++ b/scripts/pi_http/b2b-mod @@ -4,7 +4,7 @@ b2b_entities DB_QUERY - id + idupdate type state ruri @@ -33,6 +33,80 @@ leg_sockinfo + add + b2b_entities + DB_INSERT + + type + state + ruri + from_uri + to_uri + from_dname + to_dname + tag0 + tag1 + callid + cseq0 + cseq1 + contact0 + contact1 + route0 + route1 + sockinfo_srv + param + lm + lrc + lic + leg_cseq + leg_route + leg_tag + leg_contact + leg_sockinfo + + + update + b2b_entities + DB_UPDATE + + id= + + + type + state + ruri + from_uri + to_uri + from_dname + to_dname + tag0 + tag1 + callid + cseq0 + cseq1 + contact0 + contact1 + route0 + route1 + sockinfo_srv + param + lm + lrc + lic + leg_cseq + leg_route + leg_tag + leg_contact + leg_sockinfo + + + delete + b2b_entities + DB_DELETE + + id= + + b2b_logic @@ -40,7 +114,7 @@ b2b_logic DB_QUERY - id + idupdate si_key scenario sstate @@ -69,4 +143,78 @@ e3_key + add + b2b_logic + DB_INSERT + + si_key + scenario + sstate + next_sstate + sparam0 + sparam1 + sparam2 + sparam3 + sparam4 + sdp + lifetime + e1_type + e1_sid + e1_from + e1_to + e1_key + e2_type + e2_sid + e2_from + e2_to + e2_key + e3_type + e3_sid + e3_from + e3_to + e3_key + + + update + b2b_logic + DB_UPDATE + + id= + + + si_key + scenario + sstate + next_sstate + sparam0 + sparam1 + sparam2 + sparam3 + sparam4 + sdp + lifetime + e1_type + e1_sid + e1_from + e1_to + e1_key + e2_type + e2_sid + e2_from + e2_to + e2_key + e3_type + e3_sid + e3_from + e3_to + e3_key + + + delete + b2b_logic + DB_DELETE + + id= + + diff --git a/scripts/pi_http/b2b_sca-mod b/scripts/pi_http/b2b_sca-mod new file mode 100644 index 00000000000..b31a28d6397 --- /dev/null +++ b/scripts/pi_http/b2b_sca-mod @@ -0,0 +1,188 @@ + + b2b_sca + show + b2b_sca + DB_QUERY + + idupdate + shared_line + watchers + app1_shared_entity + app1_call_state + app1_call_info_uri + app1_call_info_appearance_uri + app1_b2bl_key + app2_shared_entity + app2_call_state + app2_call_info_uri + app2_call_info_appearance_uri + app2_b2bl_key + app3_shared_entity + app3_call_state + app3_call_info_uri + app3_call_info_appearance_uri + app3_b2bl_key + app4_shared_entity + app4_call_state + app4_call_info_uri + app4_call_info_appearance_uri + app4_b2bl_key + app5_shared_entity + app5_call_state + app5_call_info_uri + app5_call_info_appearance_uri + app5_b2bl_key + app6_shared_entity + app6_call_state + app6_call_info_uri + app6_call_info_appearance_uri + app6_b2bl_key + app7_shared_entity + app7_call_state + app7_call_info_uri + app7_call_info_appearance_uri + app7_b2bl_key + app8_shared_entity + app8_call_state + app8_call_info_uri + app8_call_info_appearance_uri + app8_b2bl_key + app9_shared_entity + app9_call_state + app9_call_info_uri + app9_call_info_appearance_uri + app9_b2bl_key + app10_shared_entity + app10_call_state + app10_call_info_uri + app10_call_info_appearance_uri + app10_b2bl_key + + + add + b2b_sca + DB_INSERT + + shared_line + watchers + app1_shared_entity + app1_call_state + app1_call_info_uri + app1_call_info_appearance_uri + app1_b2bl_key + app2_shared_entity + app2_call_state + app2_call_info_uri + app2_call_info_appearance_uri + app2_b2bl_key + app3_shared_entity + app3_call_state + app3_call_info_uri + app3_call_info_appearance_uri + app3_b2bl_key + app4_shared_entity + app4_call_state + app4_call_info_uri + app4_call_info_appearance_uri + app4_b2bl_key + app5_shared_entity + app5_call_state + app5_call_info_uri + app5_call_info_appearance_uri + app5_b2bl_key + app6_shared_entity + app6_call_state + app6_call_info_uri + app6_call_info_appearance_uri + app6_b2bl_key + app7_shared_entity + app7_call_state + app7_call_info_uri + app7_call_info_appearance_uri + app7_b2bl_key + app8_shared_entity + app8_call_state + app8_call_info_uri + app8_call_info_appearance_uri + app8_b2bl_key + app9_shared_entity + app9_call_state + app9_call_info_uri + app9_call_info_appearance_uri + app9_b2bl_key + app10_shared_entity + app10_call_state + app10_call_info_uri + app10_call_info_appearance_uri + app10_b2bl_key + + + update + b2b_sca + DB_UPDATE + + id= + + + shared_line + watchers + app1_shared_entity + app1_call_state + app1_call_info_uri + app1_call_info_appearance_uri + app1_b2bl_key + app2_shared_entity + app2_call_state + app2_call_info_uri + app2_call_info_appearance_uri + app2_b2bl_key + app3_shared_entity + app3_call_state + app3_call_info_uri + app3_call_info_appearance_uri + app3_b2bl_key + app4_shared_entity + app4_call_state + app4_call_info_uri + app4_call_info_appearance_uri + app4_b2bl_key + app5_shared_entity + app5_call_state + app5_call_info_uri + app5_call_info_appearance_uri + app5_b2bl_key + app6_shared_entity + app6_call_state + app6_call_info_uri + app6_call_info_appearance_uri + app6_b2bl_key + app7_shared_entity + app7_call_state + app7_call_info_uri + app7_call_info_appearance_uri + app7_b2bl_key + app8_shared_entity + app8_call_state + app8_call_info_uri + app8_call_info_appearance_uri + app8_b2bl_key + app9_shared_entity + app9_call_state + app9_call_info_uri + app9_call_info_appearance_uri + app9_b2bl_key + app10_shared_entity + app10_call_state + app10_call_info_uri + app10_call_info_appearance_uri + app10_b2bl_key + + + delete + b2b_sca + DB_DELETE + + id= + + + diff --git a/scripts/pi_http/b2b_sca-table b/scripts/pi_http/b2b_sca-table new file mode 100644 index 00000000000..0749b147a74 --- /dev/null +++ b/scripts/pi_http/b2b_sca-table @@ -0,0 +1,58 @@ + + + b2b_sca + mysql + idDB_INT + shared_lineDB_STR + watchersDB_STR + app1_shared_entityDB_INT + app1_call_stateDB_INT + app1_call_info_uriDB_STR + app1_call_info_appearance_uriDB_STR + app1_b2bl_keyDB_STR + app2_shared_entityDB_INT + app2_call_stateDB_INT + app2_call_info_uriDB_STR + app2_call_info_appearance_uriDB_STR + app2_b2bl_keyDB_STR + app3_shared_entityDB_INT + app3_call_stateDB_INT + app3_call_info_uriDB_STR + app3_call_info_appearance_uriDB_STR + app3_b2bl_keyDB_STR + app4_shared_entityDB_INT + app4_call_stateDB_INT + app4_call_info_uriDB_STR + app4_call_info_appearance_uriDB_STR + app4_b2bl_keyDB_STR + app5_shared_entityDB_INT + app5_call_stateDB_INT + app5_call_info_uriDB_STR + app5_call_info_appearance_uriDB_STR + app5_b2bl_keyDB_STR + app6_shared_entityDB_INT + app6_call_stateDB_INT + app6_call_info_uriDB_STR + app6_call_info_appearance_uriDB_STR + app6_b2bl_keyDB_STR + app7_shared_entityDB_INT + app7_call_stateDB_INT + app7_call_info_uriDB_STR + app7_call_info_appearance_uriDB_STR + app7_b2bl_keyDB_STR + app8_shared_entityDB_INT + app8_call_stateDB_INT + app8_call_info_uriDB_STR + app8_call_info_appearance_uriDB_STR + app8_b2bl_keyDB_STR + app9_shared_entityDB_INT + app9_call_stateDB_INT + app9_call_info_uriDB_STR + app9_call_info_appearance_uriDB_STR + app9_b2bl_keyDB_STR + app10_shared_entityDB_INT + app10_call_stateDB_INT + app10_call_info_uriDB_STR + app10_call_info_appearance_uriDB_STR + app10_b2bl_keyDB_STR + diff --git a/scripts/pi_http/cachedb_sql-mod b/scripts/pi_http/cachedb_sql-mod new file mode 100644 index 00000000000..f7532081e64 --- /dev/null +++ b/scripts/pi_http/cachedb_sql-mod @@ -0,0 +1,42 @@ + + cachedb + show + cachedb + DB_QUERY + + keynameupdate + value + counter + expires + + + add + cachedb + DB_INSERT + + keyname + value + counter + expires + + + update + cachedb + DB_UPDATE + + keyname= + + + value + counter + expires + + + delete + cachedb + DB_DELETE + + keyname= + + + diff --git a/scripts/pi_http/cachedb_sql-table b/scripts/pi_http/cachedb_sql-table new file mode 100644 index 00000000000..05f9409786c --- /dev/null +++ b/scripts/pi_http/cachedb_sql-table @@ -0,0 +1,9 @@ + + + cachedb + mysql + keynameDB_STR + valueDB_BLOB + counterDB_INT + expiresDB_INT + diff --git a/scripts/pi_http/call_center-mod b/scripts/pi_http/call_center-mod new file mode 100644 index 00000000000..6233b564334 --- /dev/null +++ b/scripts/pi_http/call_center-mod @@ -0,0 +1,230 @@ + + cc_flows + show + cc_flows + DB_QUERY + + idupdate + flowid + priority + skill + prependcid + message_welcome + message_queue + + + add + cc_flows + DB_INSERT + + flowid + priority + skill + prependcid + message_welcome + message_queue + + + update + cc_flows + DB_UPDATE + + id= + + + flowid + priority + skill + prependcid + message_welcome + message_queue + + + delete + cc_flows + DB_DELETE + + id= + + + + + cc_agents + show + cc_agents + DB_QUERY + + idupdate + agentid + location + logstate + skills + last_call_end + + + add + cc_agents + DB_INSERT + + agentid + location + logstate + skills + last_call_end + + + update + cc_agents + DB_UPDATE + + id= + + + agentid + location + logstate + skills + last_call_end + + + delete + cc_agents + DB_DELETE + + id= + + + + + cc_cdrs + show + cc_cdrs + DB_QUERY + + idupdate + caller + received_timestamp + wait_time + pickup_time + talk_time + flow_id + agent_id + call_type + rejected + fstats + cid + + + add + cc_cdrs + DB_INSERT + + caller + received_timestamp + wait_time + pickup_time + talk_time + flow_id + agent_id + call_type + rejected + fstats + cid + + + update + cc_cdrs + DB_UPDATE + + id= + + + caller + received_timestamp + wait_time + pickup_time + talk_time + flow_id + agent_id + call_type + rejected + fstats + cid + + + delete + cc_cdrs + DB_DELETE + + id= + + + + + cc_calls + show + cc_calls + DB_QUERY + + id + state + ig_cback + no_rej + setup_time + eta + last_start + recv_time + caller_dn + caller_un + b2buaidupdate + flow + agent + + + add + cc_calls + DB_INSERT + + state + ig_cback + no_rej + setup_time + eta + last_start + recv_time + caller_dn + caller_un + b2buaid + flow + agent + + + update + cc_calls + DB_UPDATE + + b2buaid= + + + id + state + ig_cback + no_rej + setup_time + eta + last_start + recv_time + caller_dn + caller_un + flow + agent + + + delete + cc_calls + DB_DELETE + + b2buaid= + + + diff --git a/scripts/pi_http/call_center-table b/scripts/pi_http/call_center-table new file mode 100644 index 00000000000..32d0b0fa51f --- /dev/null +++ b/scripts/pi_http/call_center-table @@ -0,0 +1,58 @@ + + + cc_flows + mysql + idDB_INT + flowidDB_STR + priorityDB_INT + skillDB_STR + prependcidDB_STR + message_welcomeDB_STR + message_queueDB_STR + + + + cc_agents + mysql + idDB_INT + agentidDB_STR + locationDB_STR + logstateDB_INT + skillsDB_STR + last_call_endDB_INT + + + + cc_cdrs + mysql + idDB_INT + callerDB_STR + received_timestampDB_DATETIME + wait_timeDB_INT + pickup_timeDB_INT + talk_timeDB_INT + flow_idDB_STR + agent_idDB_STR + call_typeDB_INT + rejectedDB_INT + fstatsDB_INT + cidDB_INT + + + + cc_calls + mysql + idDB_INT + stateDB_INT + ig_cbackDB_INT + no_rejDB_INT + setup_timeDB_INT + etaDB_INT + last_startDB_INT + recv_timeDB_INT + caller_dnDB_STR + caller_unDB_STR + b2buaidDB_STR + flowDB_STR + agentDB_STR + diff --git a/scripts/pi_http/carrierroute-mod b/scripts/pi_http/carrierroute-mod index aabdb261e22..d5c28417f91 100644 --- a/scripts/pi_http/carrierroute-mod +++ b/scripts/pi_http/carrierroute-mod @@ -4,7 +4,7 @@ carrierroute DB_QUERY - id + idupdate carrier domain scan_prefix @@ -18,6 +18,50 @@ description + add + carrierroute + DB_INSERT + + carrier + domain + scan_prefix + flags + mask + prob + strip + rewrite_host + rewrite_prefix + rewrite_suffix + description + + + update + carrierroute + DB_UPDATE + + id= + + + carrier + domain + scan_prefix + flags + mask + prob + strip + rewrite_host + rewrite_prefix + rewrite_suffix + description + + + delete + carrierroute + DB_DELETE + + id= + + carrierfailureroute @@ -25,7 +69,40 @@ carrierfailureroute DB_QUERY - id + idupdate + carrier + domain + scan_prefix + host_name + reply_code + flags + mask + next_domain + description + + + add + carrierfailureroute + DB_INSERT + + carrier + domain + scan_prefix + host_name + reply_code + flags + mask + next_domain + description + + + update + carrierfailureroute + DB_UPDATE + + id= + + carrier domain scan_prefix @@ -37,6 +114,13 @@ description + delete + carrierfailureroute + DB_DELETE + + id= + + route_tree @@ -44,8 +128,32 @@ route_tree DB_QUERY - id + idupdate + carrier + + + add + route_tree + DB_INSERT + carrier + update + route_tree + DB_UPDATE + + id= + + + carrier + + + delete + route_tree + DB_DELETE + + id= + + diff --git a/scripts/pi_http/closeddial-mod b/scripts/pi_http/closeddial-mod index f0a074fb13c..3107740110d 100644 --- a/scripts/pi_http/closeddial-mod +++ b/scripts/pi_http/closeddial-mod @@ -4,7 +4,7 @@ closeddial DB_QUERY - id + idupdate username domain cd_username @@ -13,4 +13,38 @@ new_uri + add + closeddial + DB_INSERT + + username + domain + cd_username + cd_domain + group_id + new_uri + + + update + closeddial + DB_UPDATE + + id= + + + username + domain + cd_username + cd_domain + group_id + new_uri + + + delete + closeddial + DB_DELETE + + id= + + diff --git a/scripts/pi_http/cpl-mod b/scripts/pi_http/cpl-mod index 7939a06ddfb..1e2479a188c 100644 --- a/scripts/pi_http/cpl-mod +++ b/scripts/pi_http/cpl-mod @@ -4,11 +4,41 @@ cpl DB_QUERY - id + idupdate username domain cpl_xml cpl_bin + add + cpl + DB_INSERT + + username + domain + cpl_xml + cpl_bin + + + update + cpl + DB_UPDATE + + id= + + + username + domain + cpl_xml + cpl_bin + + + delete + cpl + DB_DELETE + + id= + + diff --git a/scripts/pi_http/dialog-mod b/scripts/pi_http/dialog-mod index f3d82a2e42b..afc6fea8c1b 100644 --- a/scripts/pi_http/dialog-mod +++ b/scripts/pi_http/dialog-mod @@ -3,6 +3,38 @@ show dialog DB_QUERY + + dlg_idupdate + callid + from_uri + from_tag + to_uri + to_tag + mangled_from_uri + mangled_to_uri + caller_cseq + callee_cseq + caller_ping_cseq + callee_ping_cseq + caller_route_set + callee_route_set + caller_contact + callee_contact + caller_sock + callee_sock + state + start_time + timeout + vars + profiles + script_flags + module_flags + flags + + + add + dialog + DB_INSERT dlg_id callid @@ -28,7 +60,49 @@ vars profiles script_flags + module_flags + flags + + + update + dialog + DB_UPDATE + + dlg_id= + + + callid + from_uri + from_tag + to_uri + to_tag + mangled_from_uri + mangled_to_uri + caller_cseq + callee_cseq + caller_ping_cseq + callee_ping_cseq + caller_route_set + callee_route_set + caller_contact + callee_contact + caller_sock + callee_sock + state + start_time + timeout + vars + profiles + script_flags + module_flags flags + delete + dialog + DB_DELETE + + dlg_id= + + diff --git a/scripts/pi_http/dialog-table b/scripts/pi_http/dialog-table index 3ac4497376f..42debe35a94 100644 --- a/scripts/pi_http/dialog-table +++ b/scripts/pi_http/dialog-table @@ -26,5 +26,6 @@ varsDB_BLOB profilesDB_BLOB script_flagsDB_INT + module_flagsDB_INT flagsDB_INT diff --git a/scripts/pi_http/dialplan-mod b/scripts/pi_http/dialplan-mod index cddadf87103..8ddaf3d88c7 100644 --- a/scripts/pi_http/dialplan-mod +++ b/scripts/pi_http/dialplan-mod @@ -4,7 +4,7 @@ dialplan DB_QUERY - id + idupdate dpid pr match_op @@ -12,8 +12,51 @@ match_flags subst_exp repl_exp + timerec disabled attrs + add + dialplan + DB_INSERT + + dpid + pr + match_op + match_exp + match_flags + subst_exp + repl_exp + timerec + disabled + attrs + + + update + dialplan + DB_UPDATE + + id= + + + dpid + pr + match_op + match_exp + match_flags + subst_exp + repl_exp + timerec + disabled + attrs + + + delete + dialplan + DB_DELETE + + id= + + diff --git a/scripts/pi_http/dialplan-table b/scripts/pi_http/dialplan-table index 8c5124c87fc..8442da235d6 100644 --- a/scripts/pi_http/dialplan-table +++ b/scripts/pi_http/dialplan-table @@ -10,6 +10,7 @@ match_flagsDB_INT subst_expDB_STR repl_expDB_STR + timerecDB_STR disabledDB_INT attrsDB_STR diff --git a/scripts/pi_http/dispatcher-mod b/scripts/pi_http/dispatcher-mod index b4c5919c2d6..58aa2448492 100644 --- a/scripts/pi_http/dispatcher-mod +++ b/scripts/pi_http/dispatcher-mod @@ -4,14 +4,53 @@ dispatcher DB_QUERY - id + idupdate setid destination socket - flags + state weight + priority attrs description + add + dispatcher + DB_INSERT + + setid + destination + socket + state + weight + priority + attrs + description + + + update + dispatcher + DB_UPDATE + + id= + + + setid + destination + socket + state + weight + priority + attrs + description + + + delete + dispatcher + DB_DELETE + + id= + + diff --git a/scripts/pi_http/dispatcher-table b/scripts/pi_http/dispatcher-table index 05bb572ec12..ae754407a37 100644 --- a/scripts/pi_http/dispatcher-table +++ b/scripts/pi_http/dispatcher-table @@ -6,8 +6,9 @@ setidDB_INT destinationDB_STR socketDB_STR - flagsDB_INT + stateDB_INT weightDB_INT + priorityDB_INT attrsDB_STR descriptionDB_STR diff --git a/scripts/pi_http/domain-mod b/scripts/pi_http/domain-mod index 0b2c0baee91..99b330960d4 100644 --- a/scripts/pi_http/domain-mod +++ b/scripts/pi_http/domain-mod @@ -4,9 +4,38 @@ domain DB_QUERY - id + idupdate domain + attrs last_modified + add + domain + DB_INSERT + + domain + attrs + last_modified + + + update + domain + DB_UPDATE + + id= + + + domain + attrs + last_modified + + + delete + domain + DB_DELETE + + id= + + diff --git a/scripts/pi_http/domain-table b/scripts/pi_http/domain-table index e0578bbbf9b..e77c8dd7d98 100644 --- a/scripts/pi_http/domain-table +++ b/scripts/pi_http/domain-table @@ -4,5 +4,6 @@ mysql idDB_INT domainDB_STR + attrsDB_STR last_modifiedDB_DATETIME diff --git a/scripts/pi_http/domainpolicy-mod b/scripts/pi_http/domainpolicy-mod index 928cc273102..802dfff7a33 100644 --- a/scripts/pi_http/domainpolicy-mod +++ b/scripts/pi_http/domainpolicy-mod @@ -4,7 +4,7 @@ domainpolicy DB_QUERY - id + idupdate rule type att @@ -12,4 +12,36 @@ description + add + domainpolicy + DB_INSERT + + rule + type + att + val + description + + + update + domainpolicy + DB_UPDATE + + id= + + + rule + type + att + val + description + + + delete + domainpolicy + DB_DELETE + + id= + + diff --git a/scripts/pi_http/drouting-mod b/scripts/pi_http/drouting-mod index d04660ed256..13c88e9a37d 100644 --- a/scripts/pi_http/drouting-mod +++ b/scripts/pi_http/drouting-mod @@ -4,7 +4,7 @@ dr_gateways DB_QUERY - id + idupdate gwid type address @@ -12,9 +12,53 @@ pri_prefix attrs probe_mode + state + socket description + add + dr_gateways + DB_INSERT + + gwid + type + address + strip + pri_prefix + attrs + probe_mode + state + socket + description + + + update + dr_gateways + DB_UPDATE + + id= + + + gwid + type + address + strip + pri_prefix + attrs + probe_mode + state + socket + description + + + delete + dr_gateways + DB_DELETE + + id= + + dr_rules @@ -22,7 +66,7 @@ dr_rules DB_QUERY - ruleid + ruleidupdate groupid prefix timerec @@ -33,6 +77,44 @@ description + add + dr_rules + DB_INSERT + + groupid + prefix + timerec + priority + routeid + gwlist + attrs + description + + + update + dr_rules + DB_UPDATE + + ruleid= + + + groupid + prefix + timerec + priority + routeid + gwlist + attrs + description + + + delete + dr_rules + DB_DELETE + + ruleid= + + dr_carriers @@ -40,14 +122,49 @@ dr_carriers DB_QUERY - id + idupdate carrierid gwlist flags + state attrs description + add + dr_carriers + DB_INSERT + + carrierid + gwlist + flags + state + attrs + description + + + update + dr_carriers + DB_UPDATE + + id= + + + carrierid + gwlist + flags + state + attrs + description + + + delete + dr_carriers + DB_DELETE + + id= + + dr_groups @@ -55,11 +172,112 @@ dr_groups DB_QUERY - id + idupdate username domain groupid description + add + dr_groups + DB_INSERT + + username + domain + groupid + description + + + update + dr_groups + DB_UPDATE + + id= + + + username + domain + groupid + description + + + delete + dr_groups + DB_DELETE + + id= + + + + + dr_partitions + show + dr_partitions + DB_QUERY + + idupdate + partition_name + db_url + drd_table + drr_table + drg_table + drc_table + ruri_avp + gw_id_avp + gw_priprefix_avp + gw_sock_avp + rule_id_avp + rule_prefix_avp + carrier_id_avp + + + add + dr_partitions + DB_INSERT + + partition_name + db_url + drd_table + drr_table + drg_table + drc_table + ruri_avp + gw_id_avp + gw_priprefix_avp + gw_sock_avp + rule_id_avp + rule_prefix_avp + carrier_id_avp + + + update + dr_partitions + DB_UPDATE + + id= + + + partition_name + db_url + drd_table + drr_table + drg_table + drc_table + ruri_avp + gw_id_avp + gw_priprefix_avp + gw_sock_avp + rule_id_avp + rule_prefix_avp + carrier_id_avp + + + delete + dr_partitions + DB_DELETE + + id= + + diff --git a/scripts/pi_http/drouting-table b/scripts/pi_http/drouting-table index c7f1c85a71b..093d07fe8b8 100644 --- a/scripts/pi_http/drouting-table +++ b/scripts/pi_http/drouting-table @@ -10,6 +10,8 @@ pri_prefixDB_STR attrsDB_STR probe_modeDB_INT + stateDB_INT + socketDB_STR descriptionDB_STR @@ -34,6 +36,7 @@ carrieridDB_STR gwlistDB_STR flagsDB_INT + stateDB_INT attrsDB_STR descriptionDB_STR @@ -47,3 +50,22 @@ groupidDB_INT descriptionDB_STR + + + dr_partitions + mysql + idDB_INT + partition_nameDB_STR + db_urlDB_STR + drd_tableDB_STR + drr_tableDB_STR + drg_tableDB_STR + drc_tableDB_STR + ruri_avpDB_STR + gw_id_avpDB_STR + gw_priprefix_avpDB_STR + gw_sock_avpDB_STR + rule_id_avpDB_STR + rule_prefix_avpDB_STR + carrier_id_avpDB_STR + diff --git a/scripts/pi_http/group-mod b/scripts/pi_http/group-mod index 86d2ed9da5d..65ebdf1285f 100644 --- a/scripts/pi_http/group-mod +++ b/scripts/pi_http/group-mod @@ -4,13 +4,43 @@ grp DB_QUERY - id + idupdate username domain grp last_modified + add + grp + DB_INSERT + + username + domain + grp + last_modified + + + update + grp + DB_UPDATE + + id= + + + username + domain + grp + last_modified + + + delete + grp + DB_DELETE + + id= + + re_grp @@ -18,9 +48,35 @@ re_grp DB_QUERY - id + idupdate + reg_exp + group_id + + + add + re_grp + DB_INSERT + reg_exp group_id + update + re_grp + DB_UPDATE + + id= + + + reg_exp + group_id + + + delete + re_grp + DB_DELETE + + id= + + diff --git a/scripts/pi_http/imc-mod b/scripts/pi_http/imc-mod index 74dcde93942..b640fd6d2c0 100644 --- a/scripts/pi_http/imc-mod +++ b/scripts/pi_http/imc-mod @@ -4,12 +4,40 @@ imc_rooms DB_QUERY - id + idupdate name domain flag + add + imc_rooms + DB_INSERT + + name + domain + flag + + + update + imc_rooms + DB_UPDATE + + id= + + + name + domain + flag + + + delete + imc_rooms + DB_DELETE + + id= + + imc_members @@ -17,11 +45,41 @@ imc_members DB_QUERY - id + idupdate + username + domain + room + flag + + + add + imc_members + DB_INSERT + username domain room flag + update + imc_members + DB_UPDATE + + id= + + + username + domain + room + flag + + + delete + imc_members + DB_DELETE + + id= + + diff --git a/scripts/pi_http/load_balancer-mod b/scripts/pi_http/load_balancer-mod index 5517c858126..224f15e8fed 100644 --- a/scripts/pi_http/load_balancer-mod +++ b/scripts/pi_http/load_balancer-mod @@ -4,7 +4,7 @@ load_balancer DB_QUERY - id + idupdate group_id dst_uri resources @@ -12,4 +12,36 @@ description + add + load_balancer + DB_INSERT + + group_id + dst_uri + resources + probe_mode + description + + + update + load_balancer + DB_UPDATE + + id= + + + group_id + dst_uri + resources + probe_mode + description + + + delete + load_balancer + DB_DELETE + + id= + + diff --git a/scripts/pi_http/msilo-mod b/scripts/pi_http/msilo-mod index dcd81122b7f..99466350823 100644 --- a/scripts/pi_http/msilo-mod +++ b/scripts/pi_http/msilo-mod @@ -4,7 +4,7 @@ silo DB_QUERY - id + idupdate src_addr dst_addr username @@ -16,4 +16,44 @@ body + add + silo + DB_INSERT + + src_addr + dst_addr + username + domain + inc_time + exp_time + snd_time + ctype + body + + + update + silo + DB_UPDATE + + id= + + + src_addr + dst_addr + username + domain + inc_time + exp_time + snd_time + ctype + body + + + delete + silo + DB_DELETE + + id= + + diff --git a/scripts/pi_http/pdt-mod b/scripts/pi_http/pdt-mod index e4f4027d099..8581c4292a5 100644 --- a/scripts/pi_http/pdt-mod +++ b/scripts/pi_http/pdt-mod @@ -4,10 +4,38 @@ pdt DB_QUERY - id + idupdate sdomain prefix domain + add + pdt + DB_INSERT + + sdomain + prefix + domain + + + update + pdt + DB_UPDATE + + id= + + + sdomain + prefix + domain + + + delete + pdt + DB_DELETE + + id= + + diff --git a/scripts/pi_http/permissions-mod b/scripts/pi_http/permissions-mod index 766358a84d3..85e98e2f8a5 100644 --- a/scripts/pi_http/permissions-mod +++ b/scripts/pi_http/permissions-mod @@ -4,7 +4,7 @@ address DB_QUERY - id + idupdate grp ip mask @@ -14,4 +14,40 @@ context_info + add + address + DB_INSERT + + grp + ip + mask + port + proto + pattern + context_info + + + update + address + DB_UPDATE + + id= + + + grp + ip + mask + port + proto + pattern + context_info + + + delete + address + DB_DELETE + + id= + + diff --git a/scripts/pi_http/pi_framework-01 b/scripts/pi_http/pi_framework-01 index 08e15432a35..8bda6ebad63 100644 --- a/scripts/pi_http/pi_framework-01 +++ b/scripts/pi_http/pi_framework-01 @@ -14,6 +14,8 @@ Each col will have: - a mandatory 'field' identifying the name of the field - an optional 'value' identifing the given value + - an optional 'link_cmd' identifing the update cmd with prepared values + * only for query_cols for DB_QUERY commands - a mandatory 'operator' only for 'clause_cols' The [clause|query|order_by]_cols can be: - ov : optional with multiple 'col' with optional 'value' diff --git a/scripts/pi_http/pi_framework.xml b/scripts/pi_http/pi_framework.xml index 06195042578..6ebc0807d48 100644 --- a/scripts/pi_http/pi_framework.xml +++ b/scripts/pi_http/pi_framework.xml @@ -94,6 +94,64 @@ valueDB_STR last_modifiedDB_DATETIME + + + b2b_sca + mysql + idDB_INT + shared_lineDB_STR + watchersDB_STR + app1_shared_entityDB_INT + app1_call_stateDB_INT + app1_call_info_uriDB_STR + app1_call_info_appearance_uriDB_STR + app1_b2bl_keyDB_STR + app2_shared_entityDB_INT + app2_call_stateDB_INT + app2_call_info_uriDB_STR + app2_call_info_appearance_uriDB_STR + app2_b2bl_keyDB_STR + app3_shared_entityDB_INT + app3_call_stateDB_INT + app3_call_info_uriDB_STR + app3_call_info_appearance_uriDB_STR + app3_b2bl_keyDB_STR + app4_shared_entityDB_INT + app4_call_stateDB_INT + app4_call_info_uriDB_STR + app4_call_info_appearance_uriDB_STR + app4_b2bl_keyDB_STR + app5_shared_entityDB_INT + app5_call_stateDB_INT + app5_call_info_uriDB_STR + app5_call_info_appearance_uriDB_STR + app5_b2bl_keyDB_STR + app6_shared_entityDB_INT + app6_call_stateDB_INT + app6_call_info_uriDB_STR + app6_call_info_appearance_uriDB_STR + app6_b2bl_keyDB_STR + app7_shared_entityDB_INT + app7_call_stateDB_INT + app7_call_info_uriDB_STR + app7_call_info_appearance_uriDB_STR + app7_b2bl_keyDB_STR + app8_shared_entityDB_INT + app8_call_stateDB_INT + app8_call_info_uriDB_STR + app8_call_info_appearance_uriDB_STR + app8_b2bl_keyDB_STR + app9_shared_entityDB_INT + app9_call_stateDB_INT + app9_call_info_uriDB_STR + app9_call_info_appearance_uriDB_STR + app9_b2bl_keyDB_STR + app10_shared_entityDB_INT + app10_call_stateDB_INT + app10_call_info_uriDB_STR + app10_call_info_appearance_uriDB_STR + app10_b2bl_keyDB_STR + b2b_entities @@ -167,6 +225,64 @@ counterDB_INT expiresDB_INT + + + cc_flows + mysql + idDB_INT + flowidDB_STR + priorityDB_INT + skillDB_STR + prependcidDB_STR + message_welcomeDB_STR + message_queueDB_STR + + + + cc_agents + mysql + idDB_INT + agentidDB_STR + locationDB_STR + logstateDB_INT + skillsDB_STR + last_call_endDB_INT + + + + cc_cdrs + mysql + idDB_INT + callerDB_STR + received_timestampDB_DATETIME + wait_timeDB_INT + pickup_timeDB_INT + talk_timeDB_INT + flow_idDB_STR + agent_idDB_STR + call_typeDB_INT + rejectedDB_INT + fstatsDB_INT + cidDB_INT + + + + cc_calls + mysql + idDB_INT + stateDB_INT + ig_cbackDB_INT + no_rejDB_INT + setup_timeDB_INT + etaDB_INT + last_startDB_INT + recv_timeDB_INT + caller_dnDB_STR + caller_unDB_STR + b2buaidDB_STR + flowDB_STR + agentDB_STR + carrierroute @@ -256,6 +372,7 @@ varsDB_BLOB profilesDB_BLOB script_flagsDB_INT + module_flagsDB_INT flagsDB_INT @@ -270,6 +387,7 @@ match_flagsDB_INT subst_expDB_STR repl_expDB_STR + timerecDB_STR disabledDB_INT attrsDB_STR @@ -281,19 +399,12 @@ setidDB_INT destinationDB_STR socketDB_STR - flagsDB_INT + stateDB_INT weightDB_INT + priorityDB_INT attrsDB_STR descriptionDB_STR - - - domain - mysql - idDB_INT - domainDB_STR - last_modifiedDB_DATETIME - domainpolicy @@ -305,6 +416,15 @@ valDB_STR descriptionDB_STR + + + domain + mysql + idDB_INT + domainDB_STR + attrsDB_STR + last_modifiedDB_DATETIME + dr_gateways @@ -317,6 +437,8 @@ pri_prefixDB_STR attrsDB_STR probe_modeDB_INT + stateDB_INT + socketDB_STR descriptionDB_STR @@ -341,6 +463,7 @@ carrieridDB_STR gwlistDB_STR flagsDB_INT + stateDB_INT attrsDB_STR descriptionDB_STR @@ -354,6 +477,25 @@ groupidDB_INT descriptionDB_STR + + + dr_partitions + mysql + idDB_INT + partition_nameDB_STR + db_urlDB_STR + drd_tableDB_STR + drr_tableDB_STR + drg_tableDB_STR + drc_tableDB_STR + ruri_avpDB_STR + gw_id_avpDB_STR + gw_priprefix_avpDB_STR + gw_sock_avpDB_STR + rule_id_avpDB_STR + rule_prefix_avpDB_STR + carrier_id_avpDB_STR + grp @@ -629,8 +771,12 @@ msgDB_BLOB methodDB_STR statusDB_STR - fromipDB_STR - toipDB_STR + from_protoDB_STR + from_ipDB_STR + from_portDB_INT + to_protoDB_STR + to_ipDB_STR + to_portDB_INT fromtagDB_STR directionDB_STR @@ -700,11 +846,12 @@ cseqDB_INT last_modifiedDB_DATETIME flagsDB_INT - cflagsDB_INT + cflagsDB_STR user_agentDB_STR socketDB_STR methodsDB_INT sip_instanceDB_STR + attrDB_STR missed_calls @@ -770,7 +961,36 @@ missed_calls DB_QUERY - id + idupdate + method + from_tag + to_tag + callid + sip_code + sip_reason + time + + + add + missed_calls + DB_INSERT + + method + from_tag + to_tag + callid + sip_code + sip_reason + time + + + update + missed_calls + DB_UPDATE + + id= + + method from_tag to_tag @@ -780,6 +1000,13 @@ time + delete + missed_calls + DB_DELETE + + id= + + dbaliases @@ -787,13 +1014,43 @@ dbaliases DB_QUERY - id + idupdate + alias_username + alias_domain + username + domain + + + add + dbaliases + DB_INSERT + + alias_username + alias_domain + username + domain + + + update + dbaliases + DB_UPDATE + + id= + + alias_username alias_domain username domain + delete + dbaliases + DB_DELETE + + id= + + subscriber @@ -801,7 +1058,36 @@ subscriber DB_QUERY - id + idupdate + username + domain + password + email_address + ha1 + ha1b + rpid + + + add + subscriber + DB_INSERT + + username + domain + password + email_address + ha1 + ha1b + rpid + + + update + subscriber + DB_UPDATE + + id= + + username domain password @@ -811,6 +1097,13 @@ rpid + delete + subscriber + DB_DELETE + + id= + + usr_preferences @@ -818,7 +1111,36 @@ usr_preferences DB_QUERY - id + idupdate + uuid + username + domain + attribute + type + value + last_modified + + + add + usr_preferences + DB_INSERT + + uuid + username + domain + attribute + type + value + last_modified + + + update + usr_preferences + DB_UPDATE + + id= + + uuid username domain @@ -828,6 +1150,13 @@ last_modified + delete + usr_preferences + DB_DELETE + + id= + + b2b_entities @@ -835,7 +1164,74 @@ b2b_entities DB_QUERY - id + idupdate + type + state + ruri + from_uri + to_uri + from_dname + to_dname + tag0 + tag1 + callid + cseq0 + cseq1 + contact0 + contact1 + route0 + route1 + sockinfo_srv + param + lm + lrc + lic + leg_cseq + leg_route + leg_tag + leg_contact + leg_sockinfo + + + add + b2b_entities + DB_INSERT + + type + state + ruri + from_uri + to_uri + from_dname + to_dname + tag0 + tag1 + callid + cseq0 + cseq1 + contact0 + contact1 + route0 + route1 + sockinfo_srv + param + lm + lrc + lic + leg_cseq + leg_route + leg_tag + leg_contact + leg_sockinfo + + + update + b2b_entities + DB_UPDATE + + id= + + type state ruri @@ -864,6 +1260,13 @@ leg_sockinfo + delete + b2b_entities + DB_DELETE + + id= + + b2b_logic @@ -871,7 +1274,7 @@ b2b_logic DB_QUERY - id + idupdate si_key scenario sstate @@ -900,28 +1303,586 @@ e3_key - - - cachedb - show - cachedb - DB_QUERY - - keyname - value - counter - expires - - - - - carrierroute - show - carrierroute - DB_QUERY + add + b2b_logic + DB_INSERT - id - carrier + si_key + scenario + sstate + next_sstate + sparam0 + sparam1 + sparam2 + sparam3 + sparam4 + sdp + lifetime + e1_type + e1_sid + e1_from + e1_to + e1_key + e2_type + e2_sid + e2_from + e2_to + e2_key + e3_type + e3_sid + e3_from + e3_to + e3_key + + + update + b2b_logic + DB_UPDATE + + id= + + + si_key + scenario + sstate + next_sstate + sparam0 + sparam1 + sparam2 + sparam3 + sparam4 + sdp + lifetime + e1_type + e1_sid + e1_from + e1_to + e1_key + e2_type + e2_sid + e2_from + e2_to + e2_key + e3_type + e3_sid + e3_from + e3_to + e3_key + + + delete + b2b_logic + DB_DELETE + + id= + + + + + b2b_sca + show + b2b_sca + DB_QUERY + + idupdate + shared_line + watchers + app1_shared_entity + app1_call_state + app1_call_info_uri + app1_call_info_appearance_uri + app1_b2bl_key + app2_shared_entity + app2_call_state + app2_call_info_uri + app2_call_info_appearance_uri + app2_b2bl_key + app3_shared_entity + app3_call_state + app3_call_info_uri + app3_call_info_appearance_uri + app3_b2bl_key + app4_shared_entity + app4_call_state + app4_call_info_uri + app4_call_info_appearance_uri + app4_b2bl_key + app5_shared_entity + app5_call_state + app5_call_info_uri + app5_call_info_appearance_uri + app5_b2bl_key + app6_shared_entity + app6_call_state + app6_call_info_uri + app6_call_info_appearance_uri + app6_b2bl_key + app7_shared_entity + app7_call_state + app7_call_info_uri + app7_call_info_appearance_uri + app7_b2bl_key + app8_shared_entity + app8_call_state + app8_call_info_uri + app8_call_info_appearance_uri + app8_b2bl_key + app9_shared_entity + app9_call_state + app9_call_info_uri + app9_call_info_appearance_uri + app9_b2bl_key + app10_shared_entity + app10_call_state + app10_call_info_uri + app10_call_info_appearance_uri + app10_b2bl_key + + + add + b2b_sca + DB_INSERT + + shared_line + watchers + app1_shared_entity + app1_call_state + app1_call_info_uri + app1_call_info_appearance_uri + app1_b2bl_key + app2_shared_entity + app2_call_state + app2_call_info_uri + app2_call_info_appearance_uri + app2_b2bl_key + app3_shared_entity + app3_call_state + app3_call_info_uri + app3_call_info_appearance_uri + app3_b2bl_key + app4_shared_entity + app4_call_state + app4_call_info_uri + app4_call_info_appearance_uri + app4_b2bl_key + app5_shared_entity + app5_call_state + app5_call_info_uri + app5_call_info_appearance_uri + app5_b2bl_key + app6_shared_entity + app6_call_state + app6_call_info_uri + app6_call_info_appearance_uri + app6_b2bl_key + app7_shared_entity + app7_call_state + app7_call_info_uri + app7_call_info_appearance_uri + app7_b2bl_key + app8_shared_entity + app8_call_state + app8_call_info_uri + app8_call_info_appearance_uri + app8_b2bl_key + app9_shared_entity + app9_call_state + app9_call_info_uri + app9_call_info_appearance_uri + app9_b2bl_key + app10_shared_entity + app10_call_state + app10_call_info_uri + app10_call_info_appearance_uri + app10_b2bl_key + + + update + b2b_sca + DB_UPDATE + + id= + + + shared_line + watchers + app1_shared_entity + app1_call_state + app1_call_info_uri + app1_call_info_appearance_uri + app1_b2bl_key + app2_shared_entity + app2_call_state + app2_call_info_uri + app2_call_info_appearance_uri + app2_b2bl_key + app3_shared_entity + app3_call_state + app3_call_info_uri + app3_call_info_appearance_uri + app3_b2bl_key + app4_shared_entity + app4_call_state + app4_call_info_uri + app4_call_info_appearance_uri + app4_b2bl_key + app5_shared_entity + app5_call_state + app5_call_info_uri + app5_call_info_appearance_uri + app5_b2bl_key + app6_shared_entity + app6_call_state + app6_call_info_uri + app6_call_info_appearance_uri + app6_b2bl_key + app7_shared_entity + app7_call_state + app7_call_info_uri + app7_call_info_appearance_uri + app7_b2bl_key + app8_shared_entity + app8_call_state + app8_call_info_uri + app8_call_info_appearance_uri + app8_b2bl_key + app9_shared_entity + app9_call_state + app9_call_info_uri + app9_call_info_appearance_uri + app9_b2bl_key + app10_shared_entity + app10_call_state + app10_call_info_uri + app10_call_info_appearance_uri + app10_b2bl_key + + + delete + b2b_sca + DB_DELETE + + id= + + + + + cachedb + show + cachedb + DB_QUERY + + keynameupdate + value + counter + expires + + + add + cachedb + DB_INSERT + + keyname + value + counter + expires + + + update + cachedb + DB_UPDATE + + keyname= + + + value + counter + expires + + + delete + cachedb + DB_DELETE + + keyname= + + + + + cc_flows + show + cc_flows + DB_QUERY + + idupdate + flowid + priority + skill + prependcid + message_welcome + message_queue + + + add + cc_flows + DB_INSERT + + flowid + priority + skill + prependcid + message_welcome + message_queue + + + update + cc_flows + DB_UPDATE + + id= + + + flowid + priority + skill + prependcid + message_welcome + message_queue + + + delete + cc_flows + DB_DELETE + + id= + + + + + cc_agents + show + cc_agents + DB_QUERY + + idupdate + agentid + location + logstate + skills + last_call_end + + + add + cc_agents + DB_INSERT + + agentid + location + logstate + skills + last_call_end + + + update + cc_agents + DB_UPDATE + + id= + + + agentid + location + logstate + skills + last_call_end + + + delete + cc_agents + DB_DELETE + + id= + + + + + cc_cdrs + show + cc_cdrs + DB_QUERY + + idupdate + caller + received_timestamp + wait_time + pickup_time + talk_time + flow_id + agent_id + call_type + rejected + fstats + cid + + + add + cc_cdrs + DB_INSERT + + caller + received_timestamp + wait_time + pickup_time + talk_time + flow_id + agent_id + call_type + rejected + fstats + cid + + + update + cc_cdrs + DB_UPDATE + + id= + + + caller + received_timestamp + wait_time + pickup_time + talk_time + flow_id + agent_id + call_type + rejected + fstats + cid + + + delete + cc_cdrs + DB_DELETE + + id= + + + + + cc_calls + show + cc_calls + DB_QUERY + + id + state + ig_cback + no_rej + setup_time + eta + last_start + recv_time + caller_dn + caller_un + b2buaidupdate + flow + agent + + + add + cc_calls + DB_INSERT + + state + ig_cback + no_rej + setup_time + eta + last_start + recv_time + caller_dn + caller_un + b2buaid + flow + agent + + + update + cc_calls + DB_UPDATE + + b2buaid= + + + id + state + ig_cback + no_rej + setup_time + eta + last_start + recv_time + caller_dn + caller_un + flow + agent + + + delete + cc_calls + DB_DELETE + + b2buaid= + + + + + carrierroute + show + carrierroute + DB_QUERY + + idupdate + carrier + domain + scan_prefix + flags + mask + prob + strip + rewrite_host + rewrite_prefix + rewrite_suffix + description + + + add + carrierroute + DB_INSERT + + carrier + domain + scan_prefix + flags + mask + prob + strip + rewrite_host + rewrite_prefix + rewrite_suffix + description + + + update + carrierroute + DB_UPDATE + + id= + + + carrier domain scan_prefix flags @@ -934,6 +1895,13 @@ description + delete + carrierroute + DB_DELETE + + id= + + carrierfailureroute @@ -941,7 +1909,7 @@ carrierfailureroute DB_QUERY - id + idupdate carrier domain scan_prefix @@ -953,6 +1921,46 @@ description + add + carrierfailureroute + DB_INSERT + + carrier + domain + scan_prefix + host_name + reply_code + flags + mask + next_domain + description + + + update + carrierfailureroute + DB_UPDATE + + id= + + + carrier + domain + scan_prefix + host_name + reply_code + flags + mask + next_domain + description + + + delete + carrierfailureroute + DB_DELETE + + id= + + route_tree @@ -960,10 +1968,34 @@ route_tree DB_QUERY - id + idupdate + carrier + + + add + route_tree + DB_INSERT + carrier + update + route_tree + DB_UPDATE + + id= + + + carrier + + + delete + route_tree + DB_DELETE + + id= + + closeddial @@ -971,7 +2003,19 @@ closeddial DB_QUERY - id + idupdate + username + domain + cd_username + cd_domain + group_id + new_uri + + + add + closeddial + DB_INSERT + username domain cd_username @@ -980,6 +2024,28 @@ new_uri + update + closeddial + DB_UPDATE + + id= + + + username + domain + cd_username + cd_domain + group_id + new_uri + + + delete + closeddial + DB_DELETE + + id= + + cpl @@ -987,19 +2053,81 @@ cpl DB_QUERY - id + idupdate + username + domain + cpl_xml + cpl_bin + + + add + cpl + DB_INSERT + + username + domain + cpl_xml + cpl_bin + + + update + cpl + DB_UPDATE + + id= + + username domain cpl_xml cpl_bin + delete + cpl + DB_DELETE + + id= + + dialog show dialog DB_QUERY + + dlg_idupdate + callid + from_uri + from_tag + to_uri + to_tag + mangled_from_uri + mangled_to_uri + caller_cseq + callee_cseq + caller_ping_cseq + callee_ping_cseq + caller_route_set + callee_route_set + caller_contact + callee_contact + caller_sock + callee_sock + state + start_time + timeout + vars + profiles + script_flags + module_flags + flags + + + add + dialog + DB_INSERT dlg_id callid @@ -1025,9 +2153,51 @@ vars profiles script_flags + module_flags flags + update + dialog + DB_UPDATE + + dlg_id= + + + callid + from_uri + from_tag + to_uri + to_tag + mangled_from_uri + mangled_to_uri + caller_cseq + callee_cseq + caller_ping_cseq + callee_ping_cseq + caller_route_set + callee_route_set + caller_contact + callee_contact + caller_sock + callee_sock + state + start_time + timeout + vars + profiles + script_flags + module_flags + flags + + + delete + dialog + DB_DELETE + + dlg_id= + + dialplan @@ -1035,7 +2205,7 @@ dialplan DB_QUERY - id + idupdate dpid pr match_op @@ -1043,10 +2213,53 @@ match_flags subst_exp repl_exp + timerec disabled attrs + add + dialplan + DB_INSERT + + dpid + pr + match_op + match_exp + match_flags + subst_exp + repl_exp + timerec + disabled + attrs + + + update + dialplan + DB_UPDATE + + id= + + + dpid + pr + match_op + match_exp + match_flags + subst_exp + repl_exp + timerec + disabled + attrs + + + delete + dialplan + DB_DELETE + + id= + + dispatcher @@ -1054,16 +2267,55 @@ dispatcher DB_QUERY - id + idupdate setid destination socket - flags + state weight + priority attrs description + add + dispatcher + DB_INSERT + + setid + destination + socket + state + weight + priority + attrs + description + + + update + dispatcher + DB_UPDATE + + id= + + + setid + destination + socket + state + weight + priority + attrs + description + + + delete + dispatcher + DB_DELETE + + id= + + domain @@ -1071,11 +2323,40 @@ domain DB_QUERY - id + idupdate + domain + attrs + last_modified + + + add + domain + DB_INSERT + + domain + attrs + last_modified + + + update + domain + DB_UPDATE + + id= + + domain + attrs last_modified + delete + domain + DB_DELETE + + id= + + domainpolicy @@ -1083,7 +2364,18 @@ domainpolicy DB_QUERY - id + idupdate + rule + type + att + val + description + + + add + domainpolicy + DB_INSERT + rule type att @@ -1091,14 +2383,70 @@ description - - - dr_gateways - show + update + domainpolicy + DB_UPDATE + + id= + + + rule + type + att + val + description + + + delete + domainpolicy + DB_DELETE + + id= + + + + + dr_gateways + show + dr_gateways + DB_QUERY + + idupdate + gwid + type + address + strip + pri_prefix + attrs + probe_mode + state + socket + description + + + add + dr_gateways + DB_INSERT + + gwid + type + address + strip + pri_prefix + attrs + probe_mode + state + socket + description + + + update dr_gateways - DB_QUERY + DB_UPDATE + + id= + - id gwid type address @@ -1106,9 +2454,18 @@ pri_prefix attrs probe_mode + state + socket description + delete + dr_gateways + DB_DELETE + + id= + + dr_rules @@ -1116,7 +2473,38 @@ dr_rules DB_QUERY - ruleid + ruleidupdate + groupid + prefix + timerec + priority + routeid + gwlist + attrs + description + + + add + dr_rules + DB_INSERT + + groupid + prefix + timerec + priority + routeid + gwlist + attrs + description + + + update + dr_rules + DB_UPDATE + + ruleid= + + groupid prefix timerec @@ -1127,6 +2515,13 @@ description + delete + dr_rules + DB_DELETE + + ruleid= + + dr_carriers @@ -1134,14 +2529,49 @@ dr_carriers DB_QUERY - id + idupdate + carrierid + gwlist + flags + state + attrs + description + + + add + dr_carriers + DB_INSERT + + carrierid + gwlist + flags + state + attrs + description + + + update + dr_carriers + DB_UPDATE + + id= + + carrierid gwlist flags + state attrs description + delete + dr_carriers + DB_DELETE + + id= + + dr_groups @@ -1149,13 +2579,114 @@ dr_groups DB_QUERY - id + idupdate + username + domain + groupid + description + + + add + dr_groups + DB_INSERT + + username + domain + groupid + description + + + update + dr_groups + DB_UPDATE + + id= + + username domain groupid description + delete + dr_groups + DB_DELETE + + id= + + + + + dr_partitions + show + dr_partitions + DB_QUERY + + idupdate + partition_name + db_url + drd_table + drr_table + drg_table + drc_table + ruri_avp + gw_id_avp + gw_priprefix_avp + gw_sock_avp + rule_id_avp + rule_prefix_avp + carrier_id_avp + + + add + dr_partitions + DB_INSERT + + partition_name + db_url + drd_table + drr_table + drg_table + drc_table + ruri_avp + gw_id_avp + gw_priprefix_avp + gw_sock_avp + rule_id_avp + rule_prefix_avp + carrier_id_avp + + + update + dr_partitions + DB_UPDATE + + id= + + + partition_name + db_url + drd_table + drr_table + drg_table + drc_table + ruri_avp + gw_id_avp + gw_priprefix_avp + gw_sock_avp + rule_id_avp + rule_prefix_avp + carrier_id_avp + + + delete + dr_partitions + DB_DELETE + + id= + + grp @@ -1163,13 +2694,43 @@ grp DB_QUERY - id + idupdate + username + domain + grp + last_modified + + + add + grp + DB_INSERT + + username + domain + grp + last_modified + + + update + grp + DB_UPDATE + + id= + + username domain grp last_modified + delete + grp + DB_DELETE + + id= + + re_grp @@ -1177,11 +2738,37 @@ re_grp DB_QUERY - id + idupdate + reg_exp + group_id + + + add + re_grp + DB_INSERT + + reg_exp + group_id + + + update + re_grp + DB_UPDATE + + id= + + reg_exp group_id + delete + re_grp + DB_DELETE + + id= + + imc_rooms @@ -1189,12 +2776,40 @@ imc_rooms DB_QUERY - id + idupdate + name + domain + flag + + + add + imc_rooms + DB_INSERT + + name + domain + flag + + + update + imc_rooms + DB_UPDATE + + id= + + name domain flag + delete + imc_rooms + DB_DELETE + + id= + + imc_members @@ -1202,13 +2817,43 @@ imc_members DB_QUERY - id + idupdate + username + domain + room + flag + + + add + imc_members + DB_INSERT + + username + domain + room + flag + + + update + imc_members + DB_UPDATE + + id= + + username domain room flag + delete + imc_members + DB_DELETE + + id= + + load_balancer @@ -1216,7 +2861,18 @@ load_balancer DB_QUERY - id + idupdate + group_id + dst_uri + resources + probe_mode + description + + + add + load_balancer + DB_INSERT + group_id dst_uri resources @@ -1224,6 +2880,27 @@ description + update + load_balancer + DB_UPDATE + + id= + + + group_id + dst_uri + resources + probe_mode + description + + + delete + load_balancer + DB_DELETE + + id= + + silo @@ -1231,7 +2908,40 @@ silo DB_QUERY - id + idupdate + src_addr + dst_addr + username + domain + inc_time + exp_time + snd_time + ctype + body + + + add + silo + DB_INSERT + + src_addr + dst_addr + username + domain + inc_time + exp_time + snd_time + ctype + body + + + update + silo + DB_UPDATE + + id= + + src_addr dst_addr username @@ -1243,6 +2953,13 @@ body + delete + silo + DB_DELETE + + id= + + pdt @@ -1250,20 +2967,77 @@ pdt DB_QUERY - id + idupdate + sdomain + prefix + domain + + + add + pdt + DB_INSERT + sdomain prefix domain + update + pdt + DB_UPDATE + + id= + + + sdomain + prefix + domain + + + delete + pdt + DB_DELETE + + id= + + address show address - DB_QUERY + DB_QUERY + + idupdate + grp + ip + mask + port + proto + pattern + context_info + + + add + address + DB_INSERT + + grp + ip + mask + port + proto + pattern + context_info + + + update + address + DB_UPDATE + + id= + - id grp ip mask @@ -1273,6 +3047,13 @@ context_info + delete + address + DB_DELETE + + id= + + presentity @@ -1280,7 +3061,40 @@ presentity DB_QUERY - id + idupdate + username + domain + event + etag + expires + received_time + body + extra_hdrs + sender + + + add + presentity + DB_INSERT + + username + domain + event + etag + expires + received_time + body + extra_hdrs + sender + + + update + presentity + DB_UPDATE + + id= + + username domain event @@ -1292,6 +3106,13 @@ sender + delete + presentity + DB_DELETE + + id= + + active_watchers @@ -1299,7 +3120,62 @@ active_watchers DB_QUERY - id + idupdate + presentity_uri + watcher_username + watcher_domain + to_user + to_domain + event + event_id + to_tag + from_tag + callid + local_cseq + remote_cseq + contact + record_route + expires + status + reason + version + socket_info + local_contact + + + add + active_watchers + DB_INSERT + + presentity_uri + watcher_username + watcher_domain + to_user + to_domain + event + event_id + to_tag + from_tag + callid + local_cseq + remote_cseq + contact + record_route + expires + status + reason + version + socket_info + local_contact + + + update + active_watchers + DB_UPDATE + + id= + + presentity_uri watcher_username watcher_domain @@ -1322,6 +3198,13 @@ local_contact + delete + active_watchers + DB_DELETE + + id= + + watchers @@ -1329,7 +3212,20 @@ watchers DB_QUERY - id + idupdate + presentity_uri + watcher_username + watcher_domain + event + status + reason + inserted_time + + + add + watchers + DB_INSERT + presentity_uri watcher_username watcher_domain @@ -1339,6 +3235,29 @@ inserted_time + update + watchers + DB_UPDATE + + id= + + + presentity_uri + watcher_username + watcher_domain + event + status + reason + inserted_time + + + delete + watchers + DB_DELETE + + id= + + xcap @@ -1346,7 +3265,38 @@ xcap DB_QUERY - id + idupdate + username + domain + doc + doc_type + etag + source + doc_uri + port + + + add + xcap + DB_INSERT + + username + domain + doc + doc_type + etag + source + doc_uri + port + + + update + xcap + DB_UPDATE + + id= + + username domain doc @@ -1357,6 +3307,13 @@ port + delete + xcap + DB_DELETE + + id= + + pua @@ -1364,7 +3321,32 @@ pua DB_QUERY - id + idupdate + pres_uri + pres_id + event + expires + desired_expires + flag + etag + tuple_id + watcher_uri + to_uri + call_id + to_tag + from_tag + cseq + record_route + contact + remote_contact + version + extra_headers + + + add + pua + DB_INSERT + pres_uri pres_id event @@ -1386,6 +3368,41 @@ extra_headers + update + pua + DB_UPDATE + + id= + + + pres_uri + pres_id + event + expires + desired_expires + flag + etag + tuple_id + watcher_uri + to_uri + call_id + to_tag + from_tag + cseq + record_route + contact + remote_contact + version + extra_headers + + + delete + pua + DB_DELETE + + id= + + registrant @@ -1393,7 +3410,42 @@ registrant DB_QUERY - id + idupdate + registrar + proxy + aor + third_party_registrant + username + password + binding_URI + binding_params + expiry + forced_socket + + + add + registrant + DB_INSERT + + registrar + proxy + aor + third_party_registrant + username + password + binding_URI + binding_params + expiry + forced_socket + + + update + registrant + DB_UPDATE + + id= + + registrar proxy aor @@ -1406,14 +3458,68 @@ forced_socket + delete + registrant + DB_DELETE + + id= + + aliases show aliases - DB_QUERY + DB_QUERY + + idupdate + username + domain + contact + received + path + expires + q + callid + cseq + last_modified + flags + cflags + user_agent + socket + methods + sip_instance + + + add + aliases + DB_INSERT + + username + domain + contact + received + path + expires + q + callid + cseq + last_modified + flags + cflags + user_agent + socket + methods + sip_instance + + + update + aliases + DB_UPDATE + + id= + - id username domain contact @@ -1432,6 +3538,13 @@ sip_instance + delete + aliases + DB_DELETE + + id= + + rls_presentity @@ -1439,7 +3552,38 @@ rls_presentity DB_QUERY - id + idupdate + rlsubs_did + resource_uri + content_type + presence_state + expires + updated + auth_state + reason + + + add + rls_presentity + DB_INSERT + + rlsubs_did + resource_uri + content_type + presence_state + expires + updated + auth_state + reason + + + update + rls_presentity + DB_UPDATE + + id= + + rlsubs_did resource_uri content_type @@ -1450,6 +3594,13 @@ reason + delete + rls_presentity + DB_DELETE + + id= + + rls_watchers @@ -1457,7 +3608,62 @@ rls_watchers DB_QUERY - id + idupdate + presentity_uri + to_user + to_domain + watcher_username + watcher_domain + event + event_id + to_tag + from_tag + callid + local_cseq + remote_cseq + contact + record_route + expires + status + reason + version + socket_info + local_contact + + + add + rls_watchers + DB_INSERT + + presentity_uri + to_user + to_domain + watcher_username + watcher_domain + event + event_id + to_tag + from_tag + callid + local_cseq + remote_cseq + contact + record_route + expires + status + reason + version + socket_info + local_contact + + + update + rls_watchers + DB_UPDATE + + id= + + presentity_uri to_user to_domain @@ -1480,6 +3686,13 @@ local_contact + delete + rls_watchers + DB_DELETE + + id= + + rtpproxy_sockets @@ -1487,11 +3700,37 @@ rtpproxy_sockets DB_QUERY - id + idupdate + rtpproxy_sock + set_id + + + add + rtpproxy_sockets + DB_INSERT + + rtpproxy_sock + set_id + + + update + rtpproxy_sockets + DB_UPDATE + + id= + + rtpproxy_sock set_id + delete + rtpproxy_sockets + DB_DELETE + + id= + + sip_trace @@ -1499,19 +3738,73 @@ sip_trace DB_QUERY - id + idupdate + time_stamp + callid + traced_user + msg + method + status + from_proto + from_ip + from_port + to_proto + to_ip + to_port + fromtag + direction + + + add + sip_trace + DB_INSERT + + time_stamp + callid + traced_user + msg + method + status + from_proto + from_ip + from_port + to_proto + to_ip + to_port + fromtag + direction + + + update + sip_trace + DB_UPDATE + + id= + + time_stamp callid traced_user msg method status - fromip - toip + from_proto + from_ip + from_port + to_proto + to_ip + to_port fromtag direction + delete + sip_trace + DB_DELETE + + id= + + speed_dial @@ -1519,7 +3812,38 @@ speed_dial DB_QUERY - id + idupdate + username + domain + sd_username + sd_domain + new_uri + fname + lname + description + + + add + speed_dial + DB_INSERT + + username + domain + sd_username + sd_domain + new_uri + fname + lname + description + + + update + speed_dial + DB_UPDATE + + id= + + username domain sd_username @@ -1530,6 +3854,13 @@ description + delete + speed_dial + DB_DELETE + + id= + + version @@ -1541,6 +3872,14 @@ table_version + add + version + DB_INSERT + + table_name + table_version + + uri @@ -1548,13 +3887,43 @@ uri DB_QUERY - id + idupdate + username + domain + uri_user + last_modified + + + add + uri + DB_INSERT + + username + domain + uri_user + last_modified + + + update + uri + DB_UPDATE + + id= + + username domain uri_user last_modified + delete + uri + DB_DELETE + + id= + + userblacklist @@ -1562,13 +3931,43 @@ userblacklist DB_QUERY - id + idupdate + username + domain + prefix + whitelist + + + add + userblacklist + DB_INSERT + + username + domain + prefix + whitelist + + + update + userblacklist + DB_UPDATE + + id= + + username domain prefix whitelist + delete + userblacklist + DB_DELETE + + id= + + globalblacklist @@ -1576,12 +3975,40 @@ globalblacklist DB_QUERY - id + idupdate + prefix + whitelist + description + + + add + globalblacklist + DB_INSERT + + prefix + whitelist + description + + + update + globalblacklist + DB_UPDATE + + id= + + prefix whitelist description + delete + globalblacklist + DB_DELETE + + id= + + location @@ -1589,7 +4016,56 @@ location DB_QUERY - id + idupdate + username + domain + contact + received + path + expires + q + callid + cseq + last_modified + flags + cflags + user_agent + socket + methods + sip_instance + attr + + + add + location + DB_INSERT + + username + domain + contact + received + path + expires + q + callid + cseq + last_modified + flags + cflags + user_agent + socket + methods + sip_instance + attr + + + update + location + DB_UPDATE + + id= + + username domain contact @@ -1606,7 +4082,15 @@ socket methods sip_instance + attr + delete + location + DB_DELETE + + id= + + diff --git a/scripts/pi_http/presence-mod b/scripts/pi_http/presence-mod index 61573d04e40..d535b78d927 100644 --- a/scripts/pi_http/presence-mod +++ b/scripts/pi_http/presence-mod @@ -4,7 +4,7 @@ presentity DB_QUERY - id + idupdate username domain event @@ -16,6 +16,46 @@ sender + add + presentity + DB_INSERT + + username + domain + event + etag + expires + received_time + body + extra_hdrs + sender + + + update + presentity + DB_UPDATE + + id= + + + username + domain + event + etag + expires + received_time + body + extra_hdrs + sender + + + delete + presentity + DB_DELETE + + id= + + active_watchers @@ -23,7 +63,62 @@ active_watchers DB_QUERY - id + idupdate + presentity_uri + watcher_username + watcher_domain + to_user + to_domain + event + event_id + to_tag + from_tag + callid + local_cseq + remote_cseq + contact + record_route + expires + status + reason + version + socket_info + local_contact + + + add + active_watchers + DB_INSERT + + presentity_uri + watcher_username + watcher_domain + to_user + to_domain + event + event_id + to_tag + from_tag + callid + local_cseq + remote_cseq + contact + record_route + expires + status + reason + version + socket_info + local_contact + + + update + active_watchers + DB_UPDATE + + id= + + presentity_uri watcher_username watcher_domain @@ -46,6 +141,13 @@ local_contact + delete + active_watchers + DB_DELETE + + id= + + watchers @@ -53,7 +155,36 @@ watchers DB_QUERY - id + idupdate + presentity_uri + watcher_username + watcher_domain + event + status + reason + inserted_time + + + add + watchers + DB_INSERT + + presentity_uri + watcher_username + watcher_domain + event + status + reason + inserted_time + + + update + watchers + DB_UPDATE + + id= + + presentity_uri watcher_username watcher_domain @@ -63,6 +194,13 @@ inserted_time + delete + watchers + DB_DELETE + + id= + + xcap @@ -70,7 +208,38 @@ xcap DB_QUERY - id + idupdate + username + domain + doc + doc_type + etag + source + doc_uri + port + + + add + xcap + DB_INSERT + + username + domain + doc + doc_type + etag + source + doc_uri + port + + + update + xcap + DB_UPDATE + + id= + + username domain doc @@ -81,6 +250,13 @@ port + delete + xcap + DB_DELETE + + id= + + pua @@ -88,7 +264,60 @@ pua DB_QUERY - id + idupdate + pres_uri + pres_id + event + expires + desired_expires + flag + etag + tuple_id + watcher_uri + to_uri + call_id + to_tag + from_tag + cseq + record_route + contact + remote_contact + version + extra_headers + + + add + pua + DB_INSERT + + pres_uri + pres_id + event + expires + desired_expires + flag + etag + tuple_id + watcher_uri + to_uri + call_id + to_tag + from_tag + cseq + record_route + contact + remote_contact + version + extra_headers + + + update + pua + DB_UPDATE + + id= + + pres_uri pres_id event @@ -110,4 +339,11 @@ extra_headers + delete + pua + DB_DELETE + + id= + + diff --git a/scripts/pi_http/registrant-mod b/scripts/pi_http/registrant-mod index b0fde5d3a60..5d226cf6108 100644 --- a/scripts/pi_http/registrant-mod +++ b/scripts/pi_http/registrant-mod @@ -4,7 +4,7 @@ registrant DB_QUERY - id + idupdate registrar proxy aor @@ -17,4 +17,46 @@ forced_socket + add + registrant + DB_INSERT + + registrar + proxy + aor + third_party_registrant + username + password + binding_URI + binding_params + expiry + forced_socket + + + update + registrant + DB_UPDATE + + id= + + + registrar + proxy + aor + third_party_registrant + username + password + binding_URI + binding_params + expiry + forced_socket + + + delete + registrant + DB_DELETE + + id= + + diff --git a/scripts/pi_http/registrar-mod b/scripts/pi_http/registrar-mod index 0daae421456..c889d96bb68 100644 --- a/scripts/pi_http/registrar-mod +++ b/scripts/pi_http/registrar-mod @@ -4,7 +4,7 @@ aliases DB_QUERY - id + idupdate username domain contact @@ -23,4 +23,58 @@ sip_instance + add + aliases + DB_INSERT + + username + domain + contact + received + path + expires + q + callid + cseq + last_modified + flags + cflags + user_agent + socket + methods + sip_instance + + + update + aliases + DB_UPDATE + + id= + + + username + domain + contact + received + path + expires + q + callid + cseq + last_modified + flags + cflags + user_agent + socket + methods + sip_instance + + + delete + aliases + DB_DELETE + + id= + + diff --git a/scripts/pi_http/rls-mod b/scripts/pi_http/rls-mod index 176af578305..2a6c5f23267 100644 --- a/scripts/pi_http/rls-mod +++ b/scripts/pi_http/rls-mod @@ -4,7 +4,7 @@ rls_presentity DB_QUERY - id + idupdate rlsubs_did resource_uri content_type @@ -15,6 +15,44 @@ reason + add + rls_presentity + DB_INSERT + + rlsubs_did + resource_uri + content_type + presence_state + expires + updated + auth_state + reason + + + update + rls_presentity + DB_UPDATE + + id= + + + rlsubs_did + resource_uri + content_type + presence_state + expires + updated + auth_state + reason + + + delete + rls_presentity + DB_DELETE + + id= + + rls_watchers @@ -22,7 +60,62 @@ rls_watchers DB_QUERY - id + idupdate + presentity_uri + to_user + to_domain + watcher_username + watcher_domain + event + event_id + to_tag + from_tag + callid + local_cseq + remote_cseq + contact + record_route + expires + status + reason + version + socket_info + local_contact + + + add + rls_watchers + DB_INSERT + + presentity_uri + to_user + to_domain + watcher_username + watcher_domain + event + event_id + to_tag + from_tag + callid + local_cseq + remote_cseq + contact + record_route + expires + status + reason + version + socket_info + local_contact + + + update + rls_watchers + DB_UPDATE + + id= + + presentity_uri to_user to_domain @@ -45,4 +138,11 @@ local_contact + delete + rls_watchers + DB_DELETE + + id= + + diff --git a/scripts/pi_http/rtpproxy-mod b/scripts/pi_http/rtpproxy-mod index 973d00ce515..592fd09ec26 100644 --- a/scripts/pi_http/rtpproxy-mod +++ b/scripts/pi_http/rtpproxy-mod @@ -4,9 +4,35 @@ rtpproxy_sockets DB_QUERY - id + idupdate rtpproxy_sock set_id + add + rtpproxy_sockets + DB_INSERT + + rtpproxy_sock + set_id + + + update + rtpproxy_sockets + DB_UPDATE + + id= + + + rtpproxy_sock + set_id + + + delete + rtpproxy_sockets + DB_DELETE + + id= + + diff --git a/scripts/pi_http/siptrace-mod b/scripts/pi_http/siptrace-mod index a5606a50451..336087b8a33 100644 --- a/scripts/pi_http/siptrace-mod +++ b/scripts/pi_http/siptrace-mod @@ -4,17 +4,71 @@ sip_trace DB_QUERY - id + idupdate time_stamp callid traced_user msg method status - fromip - toip + from_proto + from_ip + from_port + to_proto + to_ip + to_port fromtag direction + add + sip_trace + DB_INSERT + + time_stamp + callid + traced_user + msg + method + status + from_proto + from_ip + from_port + to_proto + to_ip + to_port + fromtag + direction + + + update + sip_trace + DB_UPDATE + + id= + + + time_stamp + callid + traced_user + msg + method + status + from_proto + from_ip + from_port + to_proto + to_ip + to_port + fromtag + direction + + + delete + sip_trace + DB_DELETE + + id= + + diff --git a/scripts/pi_http/siptrace-table b/scripts/pi_http/siptrace-table index ae535bd6568..996e54c3db6 100644 --- a/scripts/pi_http/siptrace-table +++ b/scripts/pi_http/siptrace-table @@ -9,8 +9,12 @@ msgDB_BLOB methodDB_STR statusDB_STR - fromipDB_STR - toipDB_STR + from_protoDB_STR + from_ipDB_STR + from_portDB_INT + to_protoDB_STR + to_ipDB_STR + to_portDB_INT fromtagDB_STR directionDB_STR diff --git a/scripts/pi_http/speeddial-mod b/scripts/pi_http/speeddial-mod index bf98ee81ac6..34a45d3719c 100644 --- a/scripts/pi_http/speeddial-mod +++ b/scripts/pi_http/speeddial-mod @@ -4,7 +4,7 @@ speed_dial DB_QUERY - id + idupdate username domain sd_username @@ -15,4 +15,42 @@ description + add + speed_dial + DB_INSERT + + username + domain + sd_username + sd_domain + new_uri + fname + lname + description + + + update + speed_dial + DB_UPDATE + + id= + + + username + domain + sd_username + sd_domain + new_uri + fname + lname + description + + + delete + speed_dial + DB_DELETE + + id= + + diff --git a/scripts/pi_http/standard-mod b/scripts/pi_http/standard-mod index bb678b82295..a41de814b66 100644 --- a/scripts/pi_http/standard-mod +++ b/scripts/pi_http/standard-mod @@ -8,4 +8,12 @@ table_version + add + version + DB_INSERT + + table_name + table_version + + diff --git a/scripts/pi_http/uri_db-mod b/scripts/pi_http/uri_db-mod index d3eeff55003..f9449d3d58e 100644 --- a/scripts/pi_http/uri_db-mod +++ b/scripts/pi_http/uri_db-mod @@ -4,11 +4,41 @@ uri DB_QUERY - id + idupdate username domain uri_user last_modified + add + uri + DB_INSERT + + username + domain + uri_user + last_modified + + + update + uri + DB_UPDATE + + id= + + + username + domain + uri_user + last_modified + + + delete + uri + DB_DELETE + + id= + + diff --git a/scripts/pi_http/userblacklist-mod b/scripts/pi_http/userblacklist-mod index c6309bef714..d97a1c9f460 100644 --- a/scripts/pi_http/userblacklist-mod +++ b/scripts/pi_http/userblacklist-mod @@ -4,13 +4,43 @@ userblacklist DB_QUERY - id + idupdate username domain prefix whitelist + add + userblacklist + DB_INSERT + + username + domain + prefix + whitelist + + + update + userblacklist + DB_UPDATE + + id= + + + username + domain + prefix + whitelist + + + delete + userblacklist + DB_DELETE + + id= + + globalblacklist @@ -18,10 +48,38 @@ globalblacklist DB_QUERY - id + idupdate prefix whitelist description + add + globalblacklist + DB_INSERT + + prefix + whitelist + description + + + update + globalblacklist + DB_UPDATE + + id= + + + prefix + whitelist + description + + + delete + globalblacklist + DB_DELETE + + id= + + diff --git a/scripts/pi_http/usrloc-mod b/scripts/pi_http/usrloc-mod index a52a03ef76c..9ea3e6bf788 100644 --- a/scripts/pi_http/usrloc-mod +++ b/scripts/pi_http/usrloc-mod @@ -4,7 +4,7 @@ location DB_QUERY - id + idupdate username domain contact @@ -21,6 +21,63 @@ socket methods sip_instance + attr + add + location + DB_INSERT + + username + domain + contact + received + path + expires + q + callid + cseq + last_modified + flags + cflags + user_agent + socket + methods + sip_instance + attr + + + update + location + DB_UPDATE + + id= + + + username + domain + contact + received + path + expires + q + callid + cseq + last_modified + flags + cflags + user_agent + socket + methods + sip_instance + attr + + + delete + location + DB_DELETE + + id= + + diff --git a/scripts/pi_http/usrloc-table b/scripts/pi_http/usrloc-table index d4d8e2cac95..d983ffab71e 100644 --- a/scripts/pi_http/usrloc-table +++ b/scripts/pi_http/usrloc-table @@ -14,9 +14,10 @@ cseqDB_INT last_modifiedDB_DATETIME flagsDB_INT - cflagsDB_INT + cflagsDB_STR user_agentDB_STR socketDB_STR methodsDB_INT sip_instanceDB_STR + attrDB_STR diff --git a/scripts/postgres/acc-create.sql b/scripts/postgres/acc-create.sql index 2e4c1228c18..c2017d1e412 100644 --- a/scripts/postgres/acc-create.sql +++ b/scripts/postgres/acc-create.sql @@ -13,6 +13,7 @@ CREATE TABLE acc ( created TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL ); +ALTER SEQUENCE acc_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX acc_callid_idx ON acc (callid); INSERT INTO version (table_name, table_version) values ('missed_calls','4'); @@ -27,5 +28,6 @@ CREATE TABLE missed_calls ( time TIMESTAMP WITHOUT TIME ZONE NOT NULL ); +ALTER SEQUENCE missed_calls_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX missed_calls_callid_idx ON missed_calls (callid); diff --git a/scripts/postgres/alias_db-create.sql b/scripts/postgres/alias_db-create.sql index d62ebcbfc12..03c14624355 100644 --- a/scripts/postgres/alias_db-create.sql +++ b/scripts/postgres/alias_db-create.sql @@ -8,5 +8,6 @@ CREATE TABLE dbaliases ( CONSTRAINT dbaliases_alias_idx UNIQUE (alias_username, alias_domain) ); +ALTER SEQUENCE dbaliases_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX dbaliases_target_idx ON dbaliases (username, domain); diff --git a/scripts/postgres/auth_db-create.sql b/scripts/postgres/auth_db-create.sql index 7aea00ebe43..60de20609c6 100644 --- a/scripts/postgres/auth_db-create.sql +++ b/scripts/postgres/auth_db-create.sql @@ -11,5 +11,6 @@ CREATE TABLE subscriber ( CONSTRAINT subscriber_account_idx UNIQUE (username, domain) ); +ALTER SEQUENCE subscriber_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX subscriber_username_idx ON subscriber (username); diff --git a/scripts/postgres/avpops-create.sql b/scripts/postgres/avpops-create.sql index 9af32c5614b..e049ba9407a 100644 --- a/scripts/postgres/avpops-create.sql +++ b/scripts/postgres/avpops-create.sql @@ -10,6 +10,7 @@ CREATE TABLE usr_preferences ( last_modified TIMESTAMP WITHOUT TIME ZONE DEFAULT '1900-01-01 00:00:01' NOT NULL ); +ALTER SEQUENCE usr_preferences_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX usr_preferences_ua_idx ON usr_preferences (uuid, attribute); CREATE INDEX usr_preferences_uda_idx ON usr_preferences (username, domain, attribute); CREATE INDEX usr_preferences_value_idx ON usr_preferences (value); diff --git a/scripts/postgres/b2b-create.sql b/scripts/postgres/b2b-create.sql index 835eed75309..0f718652d4e 100644 --- a/scripts/postgres/b2b-create.sql +++ b/scripts/postgres/b2b-create.sql @@ -30,6 +30,7 @@ CREATE TABLE b2b_entities ( CONSTRAINT b2b_entities_b2b_entities_idx UNIQUE (type, tag0, tag1, callid) ); +ALTER SEQUENCE b2b_entities_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX b2b_entities_b2b_entities_param ON b2b_entities (param); INSERT INTO version (table_name, table_version) values ('b2b_logic','2'); @@ -64,3 +65,4 @@ CREATE TABLE b2b_logic ( CONSTRAINT b2b_logic_b2b_logic_idx UNIQUE (si_key) ); +ALTER SEQUENCE b2b_logic_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/b2b_sca-create.sql b/scripts/postgres/b2b_sca-create.sql new file mode 100644 index 00000000000..10ddf4bbd3e --- /dev/null +++ b/scripts/postgres/b2b_sca-create.sql @@ -0,0 +1,59 @@ +INSERT INTO version (table_name, table_version) values ('b2b_sca','1'); +CREATE TABLE b2b_sca ( + id SERIAL PRIMARY KEY NOT NULL, + shared_line VARCHAR(64) NOT NULL, + watchers VARCHAR(255) NOT NULL, + app1_shared_entity INTEGER DEFAULT NULL, + app1_call_state INTEGER DEFAULT NULL, + app1_call_info_uri VARCHAR(128) DEFAULT NULL, + app1_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app1_b2bl_key VARCHAR(64) DEFAULT NULL, + app2_shared_entity INTEGER DEFAULT NULL, + app2_call_state INTEGER DEFAULT NULL, + app2_call_info_uri VARCHAR(128) DEFAULT NULL, + app2_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app2_b2bl_key VARCHAR(64) DEFAULT NULL, + app3_shared_entity INTEGER DEFAULT NULL, + app3_call_state INTEGER DEFAULT NULL, + app3_call_info_uri VARCHAR(128) DEFAULT NULL, + app3_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app3_b2bl_key VARCHAR(64) DEFAULT NULL, + app4_shared_entity INTEGER DEFAULT NULL, + app4_call_state INTEGER DEFAULT NULL, + app4_call_info_uri VARCHAR(128) DEFAULT NULL, + app4_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app4_b2bl_key VARCHAR(64) DEFAULT NULL, + app5_shared_entity INTEGER DEFAULT NULL, + app5_call_state INTEGER DEFAULT NULL, + app5_call_info_uri VARCHAR(128) DEFAULT NULL, + app5_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app5_b2bl_key VARCHAR(64) DEFAULT NULL, + app6_shared_entity INTEGER DEFAULT NULL, + app6_call_state INTEGER DEFAULT NULL, + app6_call_info_uri VARCHAR(128) DEFAULT NULL, + app6_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app6_b2bl_key VARCHAR(64) DEFAULT NULL, + app7_shared_entity INTEGER DEFAULT NULL, + app7_call_state INTEGER DEFAULT NULL, + app7_call_info_uri VARCHAR(128) DEFAULT NULL, + app7_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app7_b2bl_key VARCHAR(64) DEFAULT NULL, + app8_shared_entity INTEGER DEFAULT NULL, + app8_call_state INTEGER DEFAULT NULL, + app8_call_info_uri VARCHAR(128) DEFAULT NULL, + app8_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app8_b2bl_key VARCHAR(64) DEFAULT NULL, + app9_shared_entity INTEGER DEFAULT NULL, + app9_call_state INTEGER DEFAULT NULL, + app9_call_info_uri VARCHAR(128) DEFAULT NULL, + app9_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app9_b2bl_key VARCHAR(64) DEFAULT NULL, + app10_shared_entity INTEGER DEFAULT NULL, + app10_call_state INTEGER DEFAULT NULL, + app10_call_info_uri VARCHAR(128) DEFAULT NULL, + app10_call_info_appearance_uri VARCHAR(128) DEFAULT NULL, + app10_b2bl_key VARCHAR(64) DEFAULT NULL, + CONSTRAINT b2b_sca_sca_idx UNIQUE (shared_line) +); + +ALTER SEQUENCE b2b_sca_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/cachedb_sql-create.sql b/scripts/postgres/cachedb_sql-create.sql index 5cff96ae882..84fda61e1e4 100644 --- a/scripts/postgres/cachedb_sql-create.sql +++ b/scripts/postgres/cachedb_sql-create.sql @@ -1,6 +1,6 @@ -INSERT INTO version (table_name, table_version) values ('cachedb','1'); +INSERT INTO version (table_name, table_version) values ('cachedb','2'); CREATE TABLE cachedb ( - keyname VARCHAR(255) NOT NULL, + keyname VARCHAR(255) PRIMARY KEY NOT NULL, value TEXT NOT NULL, counter INTEGER DEFAULT 0 NOT NULL, expires INTEGER DEFAULT 0 NOT NULL diff --git a/scripts/postgres/call_center-create.sql b/scripts/postgres/call_center-create.sql new file mode 100644 index 00000000000..c354b5d9dc1 --- /dev/null +++ b/scripts/postgres/call_center-create.sql @@ -0,0 +1,60 @@ +INSERT INTO version (table_name, table_version) values ('cc_flows','1'); +CREATE TABLE cc_flows ( + id SERIAL PRIMARY KEY NOT NULL, + flowid VARCHAR(64) NOT NULL, + priority INTEGER DEFAULT 256 NOT NULL, + skill VARCHAR(64) NOT NULL, + prependcid VARCHAR(32) NOT NULL, + message_welcome VARCHAR(128) DEFAULT NULL, + message_queue VARCHAR(128) NOT NULL, + CONSTRAINT cc_flows_unique_flowid UNIQUE (flowid) +); + +ALTER SEQUENCE cc_flows_id_seq MAXVALUE 2147483647 CYCLE; +INSERT INTO version (table_name, table_version) values ('cc_agents','1'); +CREATE TABLE cc_agents ( + id SERIAL PRIMARY KEY NOT NULL, + agentid VARCHAR(128) NOT NULL, + location VARCHAR(128) NOT NULL, + logstate INTEGER DEFAULT 0 NOT NULL, + skills VARCHAR(255) NOT NULL, + last_call_end INTEGER DEFAULT 0 NOT NULL, + CONSTRAINT cc_agents_unique_agentid UNIQUE (agentid) +); + +ALTER SEQUENCE cc_agents_id_seq MAXVALUE 2147483647 CYCLE; +INSERT INTO version (table_name, table_version) values ('cc_cdrs','1'); +CREATE TABLE cc_cdrs ( + id SERIAL PRIMARY KEY NOT NULL, + caller VARCHAR(64) NOT NULL, + received_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, + wait_time INTEGER DEFAULT 0 NOT NULL, + pickup_time INTEGER DEFAULT 0 NOT NULL, + talk_time INTEGER DEFAULT 0 NOT NULL, + flow_id VARCHAR(128) NOT NULL, + agent_id VARCHAR(128) DEFAULT NULL, + call_type INTEGER DEFAULT -1 NOT NULL, + rejected INTEGER DEFAULT 0 NOT NULL, + fstats INTEGER DEFAULT 0 NOT NULL, + cid INTEGER DEFAULT 0 +); + +ALTER SEQUENCE cc_cdrs_id_seq MAXVALUE 2147483647 CYCLE; +CREATE TABLE cc_calls ( + id SERIAL NOT NULL, + state INTEGER NOT NULL, + ig_cback INTEGER NOT NULL, + no_rej INTEGER NOT NULL, + setup_time INTEGER NOT NULL, + eta INTEGER NOT NULL, + last_start INTEGER NOT NULL, + recv_time INTEGER NOT NULL, + caller_dn VARCHAR(128) NOT NULL, + caller_un VARCHAR(128) NOT NULL, + b2buaid VARCHAR(128) PRIMARY KEY DEFAULT '' NOT NULL, + flow VARCHAR(128) NOT NULL, + agent VARCHAR(128) NOT NULL, + CONSTRAINT cc_calls_unique_id UNIQUE (id) +); + +ALTER SEQUENCE cc_calls_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/carrierroute-create.sql b/scripts/postgres/carrierroute-create.sql index fd01c12f56d..84f85f2d7e1 100644 --- a/scripts/postgres/carrierroute-create.sql +++ b/scripts/postgres/carrierroute-create.sql @@ -14,6 +14,7 @@ CREATE TABLE carrierroute ( description VARCHAR(255) DEFAULT NULL ); +ALTER SEQUENCE carrierroute_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('carrierfailureroute','2'); CREATE TABLE carrierfailureroute ( id SERIAL PRIMARY KEY NOT NULL, @@ -28,9 +29,11 @@ CREATE TABLE carrierfailureroute ( description VARCHAR(255) DEFAULT NULL ); +ALTER SEQUENCE carrierfailureroute_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('route_tree','2'); CREATE TABLE route_tree ( id SERIAL PRIMARY KEY NOT NULL, carrier VARCHAR(64) DEFAULT NULL ); +ALTER SEQUENCE route_tree_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/closeddial-create.sql b/scripts/postgres/closeddial-create.sql index 9d488693e3d..3ec976d7596 100644 --- a/scripts/postgres/closeddial-create.sql +++ b/scripts/postgres/closeddial-create.sql @@ -10,6 +10,7 @@ CREATE TABLE closeddial ( CONSTRAINT closeddial_cd_idx1 UNIQUE (username, domain, cd_domain, cd_username, group_id) ); +ALTER SEQUENCE closeddial_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX closeddial_cd_idx2 ON closeddial (group_id); CREATE INDEX closeddial_cd_idx3 ON closeddial (cd_username); CREATE INDEX closeddial_cd_idx4 ON closeddial (username); diff --git a/scripts/postgres/cpl-create.sql b/scripts/postgres/cpl-create.sql index 68c17a64c22..3806ac4a16f 100644 --- a/scripts/postgres/cpl-create.sql +++ b/scripts/postgres/cpl-create.sql @@ -8,3 +8,4 @@ CREATE TABLE cpl ( CONSTRAINT cpl_account_idx UNIQUE (username, domain) ); +ALTER SEQUENCE cpl_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/dialog-create.sql b/scripts/postgres/dialog-create.sql index 5aa5cd55633..b3390bc08f3 100644 --- a/scripts/postgres/dialog-create.sql +++ b/scripts/postgres/dialog-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('dialog','8'); +INSERT INTO version (table_name, table_version) values ('dialog','10'); CREATE TABLE dialog ( dlg_id BIGINT PRIMARY KEY NOT NULL, callid VARCHAR(255) NOT NULL, @@ -21,9 +21,10 @@ CREATE TABLE dialog ( state INTEGER NOT NULL, start_time INTEGER NOT NULL, timeout INTEGER NOT NULL, - vars TEXT DEFAULT NULL, + vars BYTEA DEFAULT NULL, profiles TEXT DEFAULT NULL, script_flags INTEGER DEFAULT 0 NOT NULL, + module_flags INTEGER DEFAULT 0 NOT NULL, flags INTEGER DEFAULT 0 NOT NULL ); diff --git a/scripts/postgres/dialplan-create.sql b/scripts/postgres/dialplan-create.sql index 8f591c0dda8..71ffe94eb84 100644 --- a/scripts/postgres/dialplan-create.sql +++ b/scripts/postgres/dialplan-create.sql @@ -8,7 +8,9 @@ CREATE TABLE dialplan ( match_flags INTEGER NOT NULL, subst_exp VARCHAR(64) NOT NULL, repl_exp VARCHAR(32) NOT NULL, + timerec VARCHAR(255) NOT NULL, disabled INTEGER DEFAULT 0 NOT NULL, attrs VARCHAR(32) NOT NULL ); +ALTER SEQUENCE dialplan_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/dispatcher-create.sql b/scripts/postgres/dispatcher-create.sql index 72fa55b59f5..a67943a7963 100644 --- a/scripts/postgres/dispatcher-create.sql +++ b/scripts/postgres/dispatcher-create.sql @@ -1,12 +1,14 @@ -INSERT INTO version (table_name, table_version) values ('dispatcher','5'); +INSERT INTO version (table_name, table_version) values ('dispatcher','7'); CREATE TABLE dispatcher ( id SERIAL PRIMARY KEY NOT NULL, setid INTEGER DEFAULT 0 NOT NULL, destination VARCHAR(192) DEFAULT '' NOT NULL, socket VARCHAR(128) DEFAULT NULL, - flags INTEGER DEFAULT 0 NOT NULL, + state INTEGER DEFAULT 0 NOT NULL, weight INTEGER DEFAULT 1 NOT NULL, + priority INTEGER DEFAULT 0 NOT NULL, attrs VARCHAR(128) DEFAULT '' NOT NULL, description VARCHAR(64) DEFAULT '' NOT NULL ); +ALTER SEQUENCE dispatcher_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/domain-create.sql b/scripts/postgres/domain-create.sql index ac1bf6a8315..b248e6975f8 100644 --- a/scripts/postgres/domain-create.sql +++ b/scripts/postgres/domain-create.sql @@ -1,8 +1,10 @@ -INSERT INTO version (table_name, table_version) values ('domain','2'); +INSERT INTO version (table_name, table_version) values ('domain','3'); CREATE TABLE domain ( id SERIAL PRIMARY KEY NOT NULL, domain VARCHAR(64) DEFAULT '' NOT NULL, + attrs VARCHAR(255) DEFAULT NULL, last_modified TIMESTAMP WITHOUT TIME ZONE DEFAULT '1900-01-01 00:00:01' NOT NULL, CONSTRAINT domain_domain_idx UNIQUE (domain) ); +ALTER SEQUENCE domain_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/domainpolicy-create.sql b/scripts/postgres/domainpolicy-create.sql index b93ccccb672..c10001ace9e 100644 --- a/scripts/postgres/domainpolicy-create.sql +++ b/scripts/postgres/domainpolicy-create.sql @@ -9,5 +9,6 @@ CREATE TABLE domainpolicy ( CONSTRAINT domainpolicy_rav_idx UNIQUE (rule, att, val) ); +ALTER SEQUENCE domainpolicy_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX domainpolicy_rule_idx ON domainpolicy (rule); diff --git a/scripts/postgres/drouting-create.sql b/scripts/postgres/drouting-create.sql index 67e0834d9ed..aebad33e55a 100644 --- a/scripts/postgres/drouting-create.sql +++ b/scripts/postgres/drouting-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('dr_gateways','5'); +INSERT INTO version (table_name, table_version) values ('dr_gateways','6'); CREATE TABLE dr_gateways ( id SERIAL PRIMARY KEY NOT NULL, gwid VARCHAR(64) NOT NULL, @@ -8,10 +8,13 @@ CREATE TABLE dr_gateways ( pri_prefix VARCHAR(16) DEFAULT NULL, attrs VARCHAR(255) DEFAULT NULL, probe_mode INTEGER DEFAULT 0 NOT NULL, + state INTEGER DEFAULT 0 NOT NULL, + socket VARCHAR(128) DEFAULT NULL, description VARCHAR(128) DEFAULT '' NOT NULL, CONSTRAINT dr_gateways_dr_gw_idx UNIQUE (gwid) ); +ALTER SEQUENCE dr_gateways_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('dr_rules','3'); CREATE TABLE dr_rules ( ruleid SERIAL PRIMARY KEY NOT NULL, @@ -25,17 +28,20 @@ CREATE TABLE dr_rules ( description VARCHAR(128) DEFAULT '' NOT NULL ); -INSERT INTO version (table_name, table_version) values ('dr_carriers','1'); +ALTER SEQUENCE dr_rules_ruleid_seq MAXVALUE 2147483647 CYCLE; +INSERT INTO version (table_name, table_version) values ('dr_carriers','2'); CREATE TABLE dr_carriers ( id SERIAL PRIMARY KEY NOT NULL, carrierid VARCHAR(64) NOT NULL, gwlist VARCHAR(255) NOT NULL, flags INTEGER DEFAULT 0 NOT NULL, + state INTEGER DEFAULT 0 NOT NULL, attrs VARCHAR(255) DEFAULT '', description VARCHAR(128) DEFAULT '' NOT NULL, CONSTRAINT dr_carriers_dr_carrier_idx UNIQUE (carrierid) ); +ALTER SEQUENCE dr_carriers_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('dr_groups','2'); CREATE TABLE dr_groups ( id SERIAL PRIMARY KEY NOT NULL, @@ -45,3 +51,23 @@ CREATE TABLE dr_groups ( description VARCHAR(128) DEFAULT '' NOT NULL ); +ALTER SEQUENCE dr_groups_id_seq MAXVALUE 2147483647 CYCLE; +INSERT INTO version (table_name, table_version) values ('dr_partitions','1'); +CREATE TABLE dr_partitions ( + id SERIAL PRIMARY KEY NOT NULL, + partition_name VARCHAR(255) NOT NULL, + db_url VARCHAR(255) NOT NULL, + drd_table VARCHAR(255), + drr_table VARCHAR(255), + drg_table VARCHAR(255), + drc_table VARCHAR(255), + ruri_avp VARCHAR(255), + gw_id_avp VARCHAR(255), + gw_priprefix_avp VARCHAR(255), + gw_sock_avp VARCHAR(255), + rule_id_avp VARCHAR(255), + rule_prefix_avp VARCHAR(255), + carrier_id_avp VARCHAR(255) +); + +ALTER SEQUENCE dr_partitions_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/group-create.sql b/scripts/postgres/group-create.sql index 9d421d1364a..3e0d470714d 100644 --- a/scripts/postgres/group-create.sql +++ b/scripts/postgres/group-create.sql @@ -8,6 +8,7 @@ CREATE TABLE grp ( CONSTRAINT grp_account_group_idx UNIQUE (username, domain, grp) ); +ALTER SEQUENCE grp_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('re_grp','2'); CREATE TABLE re_grp ( id SERIAL PRIMARY KEY NOT NULL, @@ -15,5 +16,6 @@ CREATE TABLE re_grp ( group_id INTEGER DEFAULT 0 NOT NULL ); +ALTER SEQUENCE re_grp_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX re_grp_group_idx ON re_grp (group_id); diff --git a/scripts/postgres/imc-create.sql b/scripts/postgres/imc-create.sql index 86a05332977..b2e1540df74 100644 --- a/scripts/postgres/imc-create.sql +++ b/scripts/postgres/imc-create.sql @@ -7,6 +7,7 @@ CREATE TABLE imc_rooms ( CONSTRAINT imc_rooms_name_domain_idx UNIQUE (name, domain) ); +ALTER SEQUENCE imc_rooms_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('imc_members','2'); CREATE TABLE imc_members ( id SERIAL PRIMARY KEY NOT NULL, @@ -17,3 +18,4 @@ CREATE TABLE imc_members ( CONSTRAINT imc_members_account_room_idx UNIQUE (username, domain, room) ); +ALTER SEQUENCE imc_members_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/load_balancer-create.sql b/scripts/postgres/load_balancer-create.sql index 40d2d84e51a..96580bbd6e8 100644 --- a/scripts/postgres/load_balancer-create.sql +++ b/scripts/postgres/load_balancer-create.sql @@ -8,5 +8,6 @@ CREATE TABLE load_balancer ( description VARCHAR(128) DEFAULT '' NOT NULL ); +ALTER SEQUENCE load_balancer_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX load_balancer_dsturi_idx ON load_balancer (dst_uri); diff --git a/scripts/postgres/msilo-create.sql b/scripts/postgres/msilo-create.sql index f59e64f01aa..d1f1bcf7041 100644 --- a/scripts/postgres/msilo-create.sql +++ b/scripts/postgres/msilo-create.sql @@ -8,9 +8,10 @@ CREATE TABLE silo ( inc_time INTEGER DEFAULT 0 NOT NULL, exp_time INTEGER DEFAULT 0 NOT NULL, snd_time INTEGER DEFAULT 0 NOT NULL, - ctype VARCHAR(32) DEFAULT 'text/plain' NOT NULL, - body BYTEA DEFAULT '' NOT NULL + ctype VARCHAR(255) DEFAULT NULL, + body BYTEA NOT NULL ); +ALTER SEQUENCE silo_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX silo_account_idx ON silo (username, domain); diff --git a/scripts/postgres/pdt-create.sql b/scripts/postgres/pdt-create.sql index 100f31f041b..b9f3e0a289e 100644 --- a/scripts/postgres/pdt-create.sql +++ b/scripts/postgres/pdt-create.sql @@ -7,3 +7,4 @@ CREATE TABLE pdt ( CONSTRAINT pdt_sdomain_prefix_idx UNIQUE (sdomain, prefix) ); +ALTER SEQUENCE pdt_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/permissions-create.sql b/scripts/postgres/permissions-create.sql index 84af056dd16..0d9ddfdf0e7 100644 --- a/scripts/postgres/permissions-create.sql +++ b/scripts/postgres/permissions-create.sql @@ -10,3 +10,4 @@ CREATE TABLE address ( context_info VARCHAR(32) DEFAULT NULL ); +ALTER SEQUENCE address_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/presence-create.sql b/scripts/postgres/presence-create.sql index de1887658bb..486ca7047fa 100644 --- a/scripts/postgres/presence-create.sql +++ b/scripts/postgres/presence-create.sql @@ -13,6 +13,7 @@ CREATE TABLE presentity ( CONSTRAINT presentity_presentity_idx UNIQUE (username, domain, event, etag) ); +ALTER SEQUENCE presentity_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('active_watchers','10'); CREATE TABLE active_watchers ( id SERIAL PRIMARY KEY NOT NULL, @@ -39,6 +40,7 @@ CREATE TABLE active_watchers ( CONSTRAINT active_watchers_active_watchers_idx UNIQUE (presentity_uri, callid, to_tag, from_tag) ); +ALTER SEQUENCE active_watchers_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('watchers','4'); CREATE TABLE watchers ( id SERIAL PRIMARY KEY NOT NULL, @@ -52,6 +54,7 @@ CREATE TABLE watchers ( CONSTRAINT watchers_watcher_idx UNIQUE (presentity_uri, watcher_username, watcher_domain, event) ); +ALTER SEQUENCE watchers_id_seq MAXVALUE 2147483647 CYCLE; INSERT INTO version (table_name, table_version) values ('xcap','4'); CREATE TABLE xcap ( id SERIAL PRIMARY KEY NOT NULL, @@ -66,6 +69,7 @@ CREATE TABLE xcap ( CONSTRAINT xcap_account_doc_type_idx UNIQUE (username, domain, doc_type, doc_uri) ); +ALTER SEQUENCE xcap_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX xcap_source_idx ON xcap (source); INSERT INTO version (table_name, table_version) values ('pua','8'); @@ -92,3 +96,8 @@ CREATE TABLE pua ( extra_headers TEXT ); +ALTER SEQUENCE pua_id_seq MAXVALUE 2147483647 CYCLE; +CREATE INDEX pua_del1_idx ON pua (pres_uri, event); +CREATE INDEX pua_del2_idx ON pua (expires); +CREATE INDEX pua_update_idx ON pua (pres_uri, pres_id, flag, event); + diff --git a/scripts/postgres/registrant-create.sql b/scripts/postgres/registrant-create.sql index 499d9227dfe..454b6e36277 100644 --- a/scripts/postgres/registrant-create.sql +++ b/scripts/postgres/registrant-create.sql @@ -14,3 +14,4 @@ CREATE TABLE registrant ( CONSTRAINT registrant_aor_idx UNIQUE (aor) ); +ALTER SEQUENCE registrant_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/registrar-create.sql b/scripts/postgres/registrar-create.sql index a6713237f3f..16e00fa0309 100644 --- a/scripts/postgres/registrar-create.sql +++ b/scripts/postgres/registrar-create.sql @@ -20,3 +20,4 @@ CREATE TABLE aliases ( CONSTRAINT aliases_alias_idx UNIQUE (username, domain, contact, callid) ); +ALTER SEQUENCE aliases_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/rls-create.sql b/scripts/postgres/rls-create.sql index 78caedf368b..65b732c3fba 100644 --- a/scripts/postgres/rls-create.sql +++ b/scripts/postgres/rls-create.sql @@ -12,6 +12,7 @@ CREATE TABLE rls_presentity ( CONSTRAINT rls_presentity_rls_presentity_idx UNIQUE (rlsubs_did, resource_uri) ); +ALTER SEQUENCE rls_presentity_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX rls_presentity_updated_idx ON rls_presentity (updated); INSERT INTO version (table_name, table_version) values ('rls_watchers','2'); @@ -40,3 +41,4 @@ CREATE TABLE rls_watchers ( CONSTRAINT rls_watchers_rls_watcher_idx UNIQUE (presentity_uri, callid, to_tag, from_tag) ); +ALTER SEQUENCE rls_watchers_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/rtpproxy-create.sql b/scripts/postgres/rtpproxy-create.sql index c507bec37f3..52d8522ef05 100644 --- a/scripts/postgres/rtpproxy-create.sql +++ b/scripts/postgres/rtpproxy-create.sql @@ -5,3 +5,4 @@ CREATE TABLE rtpproxy_sockets ( set_id INTEGER NOT NULL ); +ALTER SEQUENCE rtpproxy_sockets_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/siptrace-create.sql b/scripts/postgres/siptrace-create.sql index 5b01e2c0f23..8ab4d6ad237 100644 --- a/scripts/postgres/siptrace-create.sql +++ b/scripts/postgres/siptrace-create.sql @@ -1,4 +1,4 @@ -INSERT INTO version (table_name, table_version) values ('sip_trace','3'); +INSERT INTO version (table_name, table_version) values ('sip_trace','4'); CREATE TABLE sip_trace ( id SERIAL PRIMARY KEY NOT NULL, time_stamp TIMESTAMP WITHOUT TIME ZONE DEFAULT '1900-01-01 00:00:01' NOT NULL, @@ -7,14 +7,19 @@ CREATE TABLE sip_trace ( msg TEXT NOT NULL, method VARCHAR(32) DEFAULT '' NOT NULL, status VARCHAR(128) DEFAULT NULL, - fromip VARCHAR(50) DEFAULT '' NOT NULL, - toip VARCHAR(50) DEFAULT '' NOT NULL, + from_proto VARCHAR(5) NOT NULL, + from_ip VARCHAR(50) DEFAULT '' NOT NULL, + from_port INTEGER NOT NULL, + to_proto VARCHAR(5) NOT NULL, + to_ip VARCHAR(50) DEFAULT '' NOT NULL, + to_port INTEGER NOT NULL, fromtag VARCHAR(64) DEFAULT '' NOT NULL, direction VARCHAR(4) DEFAULT '' NOT NULL ); +ALTER SEQUENCE sip_trace_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX sip_trace_traced_user_idx ON sip_trace (traced_user); CREATE INDEX sip_trace_date_idx ON sip_trace (time_stamp); -CREATE INDEX sip_trace_fromip_idx ON sip_trace (fromip); +CREATE INDEX sip_trace_fromip_idx ON sip_trace (from_ip); CREATE INDEX sip_trace_callid_idx ON sip_trace (callid); diff --git a/scripts/postgres/speeddial-create.sql b/scripts/postgres/speeddial-create.sql index 9964fdb7a74..12689cf8ff3 100644 --- a/scripts/postgres/speeddial-create.sql +++ b/scripts/postgres/speeddial-create.sql @@ -12,3 +12,4 @@ CREATE TABLE speed_dial ( CONSTRAINT speed_dial_speed_dial_idx UNIQUE (username, domain, sd_domain, sd_username) ); +ALTER SEQUENCE speed_dial_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/uri_db-create.sql b/scripts/postgres/uri_db-create.sql index 80f7baab2a7..f599f36ee6f 100644 --- a/scripts/postgres/uri_db-create.sql +++ b/scripts/postgres/uri_db-create.sql @@ -8,3 +8,4 @@ CREATE TABLE uri ( CONSTRAINT uri_account_idx UNIQUE (username, domain, uri_user) ); +ALTER SEQUENCE uri_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/scripts/postgres/userblacklist-create.sql b/scripts/postgres/userblacklist-create.sql index 4acbccf787e..7c2e6439c3b 100644 --- a/scripts/postgres/userblacklist-create.sql +++ b/scripts/postgres/userblacklist-create.sql @@ -7,6 +7,7 @@ CREATE TABLE userblacklist ( whitelist SMALLINT DEFAULT 0 NOT NULL ); +ALTER SEQUENCE userblacklist_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX userblacklist_userblacklist_idx ON userblacklist (username, domain, prefix); INSERT INTO version (table_name, table_version) values ('globalblacklist','2'); @@ -17,5 +18,6 @@ CREATE TABLE globalblacklist ( description VARCHAR(255) DEFAULT NULL ); +ALTER SEQUENCE globalblacklist_id_seq MAXVALUE 2147483647 CYCLE; CREATE INDEX globalblacklist_globalblacklist_idx ON globalblacklist (prefix); diff --git a/scripts/postgres/usrloc-create.sql b/scripts/postgres/usrloc-create.sql index 8729d0f3bc3..4902b733670 100644 --- a/scripts/postgres/usrloc-create.sql +++ b/scripts/postgres/usrloc-create.sql @@ -1,22 +1,24 @@ -INSERT INTO version (table_name, table_version) values ('location','1007'); +INSERT INTO version (table_name, table_version) values ('location','1009'); CREATE TABLE location ( id SERIAL PRIMARY KEY NOT NULL, username VARCHAR(64) DEFAULT '' NOT NULL, domain VARCHAR(64) DEFAULT '' NOT NULL, contact VARCHAR(255) DEFAULT '' NOT NULL, received VARCHAR(128) DEFAULT NULL, - path VARCHAR(128) DEFAULT NULL, + path VARCHAR(255) DEFAULT NULL, expires TIMESTAMP WITHOUT TIME ZONE DEFAULT '2020-05-28 21:32:15' NOT NULL, q REAL DEFAULT 1.0 NOT NULL, callid VARCHAR(255) DEFAULT 'Default-Call-ID' NOT NULL, cseq INTEGER DEFAULT 13 NOT NULL, last_modified TIMESTAMP WITHOUT TIME ZONE DEFAULT '1900-01-01 00:00:01' NOT NULL, flags INTEGER DEFAULT 0 NOT NULL, - cflags INTEGER DEFAULT 0 NOT NULL, + cflags VARCHAR(255) DEFAULT NULL, user_agent VARCHAR(255) DEFAULT '' NOT NULL, socket VARCHAR(64) DEFAULT NULL, methods INTEGER DEFAULT NULL, sip_instance VARCHAR(255) DEFAULT NULL, + attr VARCHAR(255) DEFAULT NULL, CONSTRAINT location_account_contact_idx UNIQUE (username, domain, contact, callid) ); +ALTER SEQUENCE location_id_seq MAXVALUE 2147483647 CYCLE; diff --git a/sctp_server.c b/sctp_server.c index d5d03b4a1f5..b4f7ed80f2e 100644 --- a/sctp_server.c +++ b/sctp_server.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -68,13 +68,14 @@ int sctp_server_init(struct socket_info* sock_info) LM_ERR("could not init sockaddr_union\n"); goto error; } - - sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_SEQPACKET, 0); + + sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_SEQPACKET, + IPPROTO_SCTP); if (sock_info->socket==-1){ LM_ERR("socket: %s [%d]\n", strerror(errno), errno); goto error; } - + optval=1; if (setsockopt(sock_info->socket, SOL_SOCKET, SO_REUSEADDR , (void*)&optval, sizeof(optval)) ==-1){ @@ -85,7 +86,7 @@ int sctp_server_init(struct socket_info* sock_info) #ifdef DISABLE_NAGLE /* turns of Nagle-like algorithm/chunk-bundling.*/ optval=1; - if (setsockopt(sock_info->socket, IPPROTO_SCTP, SCTP_NODELAY, + if (setsockopt(sock_info->socket, IPPROTO_SCTP, SCTP_NODELAY, (void*)&optval, sizeof(optval))==-1){ LM_WARN("setsockopt %s\n", strerror(errno)); /* continues since this is not critical */ @@ -93,13 +94,13 @@ int sctp_server_init(struct socket_info* sock_info) #endif /* tos */ - + /* this sockopt causes a kernel panic in some sctp implementations. * commenting it out. -gmarmon */ - + /* optval=tos; - if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, + if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, sizeof(optval)) ==-1){ LM_WARN("setsockopt tos: %s\n", strerror(errno)); } @@ -118,10 +119,10 @@ int sctp_server_init(struct socket_info* sock_info) /*if ( probe_max_receive_buffer(sock_info->socket)==-1) goto error; */ - + if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){ LM_ERR("bind(%x, %p, %d) on %s: %s\n", - sock_info->socket, &addr->s, + sock_info->socket, &addr->s, (unsigned)sockaddru_len(*addr), sock_info->address_str.s, strerror(errno)); @@ -135,8 +136,8 @@ int sctp_server_init(struct socket_info* sock_info) if(listen(sock_info->socket, LISTEN_BACKLOG)<0){ LM_ERR("listen(%x, %d) on %s: %s\n", sock_info->socket, - LISTEN_BACKLOG, - sock_info->address_str.s, + LISTEN_BACKLOG, + sock_info->address_str.s, strerror(errno)); goto error; } @@ -150,7 +151,7 @@ int sctp_server_init(struct socket_info* sock_info) -int sctp_server_rcv_loop() +int sctp_server_rcv_loop(void) { int len; #ifdef DYN_BUF @@ -186,7 +187,7 @@ int sctp_server_rcv_loop() #endif fromlen=sockaddru_len(bind_address->su); len = sctp_recvmsg(bind_address->socket, buf, BUF_SIZE, &from->s, &fromlen, &sinfo, 0); - + if (len==-1){ if (errno==EAGAIN){ LM_DBG("packet with bad checksum received\n"); @@ -217,19 +218,19 @@ int sctp_server_rcv_loop() LM_INFO("dropping 0 port packet from %s\n", tmp); continue; } - - + + /* receive_msg must free buf too!*/ receive_msg(buf, len, &ri); - + /* skip: do other stuff */ - + } /* if (from) pkg_free(from); return 0; */ - + error: if (from) pkg_free(from); return -1; diff --git a/sctp_server.h b/sctp_server.h index e950b12a70e..7fb9da8b366 100644 --- a/sctp_server.h +++ b/sctp_server.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History diff --git a/serialize.c b/serialize.c index 46fdedb241d..1be092167ca 100644 --- a/serialize.c +++ b/serialize.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -165,7 +165,7 @@ int serialize_branches(struct sip_msg *msg, int clean_before ) memset(enc_info.s, 0, enc_info.len); p = enc_info.s; - LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u>\n", + LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u>\n", branch.len, branch.s, dst_uri.len, dst_uri.s, path.len, path.s, diff --git a/serialize.h b/serialize.h index 284a22e508f..99ebd682248 100644 --- a/serialize.h +++ b/serialize.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/sliblist.c b/sliblist.c new file mode 100644 index 00000000000..7588c932a74 --- /dev/null +++ b/sliblist.c @@ -0,0 +1,148 @@ +/* + * $Id$ + * + * A simple linked list implementation. + * + * Copyright (C) 2013 VoIP Embedded, Inc. + * + * sliblist is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version + * + * sliblist is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History + * ------ + * 2013-02-25 initial implementation (osas) + */ + +#include + +#include "sliblist.h" + +struct slinkedl_list { + struct slinkedl_element *head; + struct slinkedl_element *tail; + slinkedl_alloc_f *alloc; + slinkedl_dealloc_f *dealloc; +}; + +struct slinkedl_element { + void *data; + struct slinkedl_element *next; +}; + + +slinkedl_list_t* slinkedl_init(slinkedl_alloc_f *alloc, + slinkedl_dealloc_f *dealloc) +{ + slinkedl_list_t *list; + if (alloc==NULL || dealloc==NULL) return NULL; + list = (*alloc)(sizeof(slinkedl_list_t)); + if (list) { + memset(list, 0, sizeof(slinkedl_list_t)); + list->alloc = alloc; + list->dealloc = dealloc; + } + return list; +} + + +void slinkedl_list_init(slinkedl_list_t* list) +{ + if (!list) return; + + memset(list, 0, sizeof(slinkedl_list_t)); + return; +} + + +void *slinkedl_prepend(slinkedl_list_t *list, size_t e_size) +{ + slinkedl_element_t *element; + + if (!list || !e_size) return NULL; + element = (slinkedl_element_t*)(list->alloc(sizeof(slinkedl_element_t) + + e_size)); + if (!element) return NULL; + + element->next = list->head; + element->data = (void*)(element + 1); + list->head = element; + if (element->next) { + } else { + /* This is an empty list */ + list->tail = element; + } + return (element->data); +} + + +void *slinkedl_append(slinkedl_list_t *list, size_t e_size) +{ + slinkedl_element_t *element; + + if (!list || !e_size) return NULL; + element = (slinkedl_element_t*)(list->alloc(sizeof(slinkedl_element_t) + + e_size)); + if (!element) return NULL; + + element->next = NULL; + element->data = (void*)(element + 1); + if (list->tail) { + list->tail->next = element; + list->tail = element; + } else { + /* This is an empty list */ + list->head = element; + list->tail = element; + } + return (element->data); +} + + +int slinkedl_traverse(slinkedl_list_t *list, + slinkedl_run_data_f func, void *data, void *r_data) +{ + int ret; + slinkedl_element_t *element; + + if (!list) return -1; + if (!func) return -2; + + element = list->head; + while(element){ + ret = (*func)(element->data, data, r_data); + if (ret!=0) return ret; + element = element->next; + } + return 0; +} + + +void slinkedl_list_destroy(slinkedl_list_t *list) +{ + slinkedl_element_t *element; + slinkedl_dealloc_f *dealloc; + + if (!list) return; + element = list->head; + while(element){ + list->head = element->next; + list->dealloc(element); + element = list->head; + } + dealloc = list->dealloc; + (*dealloc)(list); + + return; +} + diff --git a/sliblist.h b/sliblist.h new file mode 100644 index 00000000000..5d741a19159 --- /dev/null +++ b/sliblist.h @@ -0,0 +1,156 @@ +/* + * $Id$ + * + * A simple linked list implementation. + * + * Copyright (C) 2013 VoIP Embedded, Inc. + * + * sliblist is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version + * + * sliblist is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 2013-02-25 initial implementation (osas) + */ + + +#ifndef S_LIB_LIST_H +#define S_LIB_LIST_H + +#include +#include + + +/** + * Structure defining the simple linked list. + */ +typedef struct slinkedl_list slinkedl_list_t; + +/** + * Structure defining an elemnt of a simple linked list. + */ +typedef struct slinkedl_element slinkedl_element_t; + + +/** + * Memory allocator to be used in list operations. + * + * @param size Size of the memory block to be allocated. + * @return A pointer to the requsted memory block. + * NULL on error; + * non NULL on success. + */ +void *(slinkedl_alloc) (size_t size); +typedef void *(slinkedl_alloc_f) (size_t size); + +/** + * Memory de-allocator to be used in list operations. + * + * @param ptr Ponter to the emmory block to be freeed. + */ +void (slinkedl_dealloc) (void *ptr); +typedef void (slinkedl_dealloc_f) (void *ptr); + + +/** + * Function to be called by slinkedl_traverse while traversing the list. + * + * @param e_data pointer to data stored by the current element. + * @param data pointer to given data to work with. + * @param r_data pointer to data returned by this function. + * return <0 on error and exit list traversal; + * return 0 on no action on current list elemnt and + * continue list traversal; + * return >0 on action successfuly completed on current list element + * and exit list traversal. + * @see slinkedl_traverse() + */ +int (slinkedl_run_data) (void *e_data, void *data, void *r_data); +typedef int (slinkedl_run_data_f) (void *e_data, void *data, void *r_data); + + +/** + * List initializer. + * This function MUST be called in order to initialize a list. + * It's role is to allocate memory for the list structure and + * initialize it's internal structure. + * + * @param alloc pointer to the memory allocator function. + * @param dealloc pointer to the memory deallocator function. + * @return The pointer to the list structure. + * - NULL on error (alloc and dealloc must be non NULL); + * - non NULL on success. + */ +slinkedl_list_t* slinkedl_init(slinkedl_alloc_f *alloc, + slinkedl_dealloc_f *dealloc); + +/** + * Insert a list elemnt at the beginning of the list. + * One block of memory will be allocated for the whole element. + * The memory will be allocated using the memory allocator + * provided to the list during initialization. + * + * @param list The list to operate on. + * @param e_size size of the element data to be store by the new element. + * @return A pointer to a block of memory with size e_size. + * - NULL on error; + * - non NULL on success. + * The application will use the returned pointer to populate + * the memory block with it's data. + * @see slinkedl_init() + */ +void *slinkedl_prepend(slinkedl_list_t *list, size_t e_size); + +/** + * Insert a list elemnt at the end of the list. + * One block of memory will be allocated for the whole element. + * The memory will be allocated using the memory allocator + * provided to the list during initialization. + * + * @param list The list to operate on. + * @param e_size size of the element data to be store by the new element. + * @return A pointer to a block of memory with size e_size. + * - NULL on error; + * - non NULL on success. + * The application will use the returned pointer to populate + * the memory block with it's data. + * @see slinkedl_init() + */ +void *slinkedl_append(slinkedl_list_t *list, size_t e_size); + +/** + * Traverse the list and execute run_data for each element, + * until run_data returns a non zero value or the extent of the list + * is reached. + * + * @psram lit The list to traverse. + * @param run_data The funtion to operate on each list element. + * @param data The data to be used by run_data function. + * @parama r_data The data returned by run_data function. + * @return The return code from last run_data call. + * @see slinkedl_run_data() + */ +int slinkedl_traverse(slinkedl_list_t *list, + slinkedl_run_data_f run_data, void *data, void *r_data); + +/** + * Destroy the list. + * Any element in the list will be silently destroyed. + * If you want to perform some actions on list elemnts before destroying it, + * use slinkedl_traverse(). + * + * @param list The list to be distroyed. + */ +void slinkedl_list_destroy(slinkedl_list_t *list); + +#endif + diff --git a/socket_info.c b/socket_info.c index 3665ca0af9b..3b3019e55fc 100644 --- a/socket_info.c +++ b/socket_info.c @@ -1,4 +1,5 @@ -/* $Id$ +/* + * $Id$ * * Copyright (C) 2001-2003 FhG Fokus * @@ -14,14 +15,14 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * This file contains code that initializes and handles ser listen addresses * lists (struct socket_info). It is used mainly on startup. - * + * * History: * -------- * 2003-10-22 created by andrei @@ -102,13 +103,13 @@ /* another helper function, it just creates a socket_info struct */ -static inline struct socket_info* new_sock_info( char* name, +inline struct socket_info* new_sock_info( char* name, unsigned short port, unsigned short proto, char *adv_name, unsigned short adv_port, unsigned short children,enum si_flags flags) { struct socket_info* si; - + si=(struct socket_info*) pkg_malloc(sizeof(struct socket_info)); if (si==0) goto error; memset(si, 0, sizeof(struct socket_info)); @@ -124,7 +125,7 @@ static inline struct socket_info* new_sock_info( char* name, /* advertised socket information */ /* Make sure the adv_sock_string is initialized, because if there is - * no adv_sock_name, no other code will initialize it! + * no adv_sock_name, no other code will initialize it! */ si->adv_sock_str.s=NULL; si->adv_sock_str.len=0; @@ -229,27 +230,27 @@ struct socket_info* grep_sock_info(str* host, unsigned short port, list=&udp_listen; else list=get_sock_info_list(c_proto); - + if (list==0){ LM_WARN("unknown proto %d\n", c_proto); goto not_found; /* false */ } for (si=*list; si; si=si->next){ LM_DBG("checking if host==us: %d==%d && " - " [%.*s] == [%.*s]\n", + " [%.*s] == [%.*s]\n", h_len, si->name.len, h_len, hname, si->name.len, si->name.s ); if (port) { - LM_DBG("checking if port %d matches port %d\n", + LM_DBG("checking if port %d matches port %d\n", si->port_no, port); if (si->port_no!=port && si->adv_port!=port) { continue; } } - if ( (h_len==si->name.len) && + if ( (h_len==si->name.len) && (strncasecmp(hname, si->name.s, si->name.len)==0) /*slower*/) /* comp. must be case insensitive, host names @@ -257,7 +258,7 @@ struct socket_info* grep_sock_info(str* host, unsigned short port, * ipv6 addresses if we are lucky*/ goto found; /* Check if the adv. name of this socket matches */ - if ( (h_len==si->adv_name_str.len) && + if ( (h_len==si->adv_name_str.len) && (strncasecmp(hname, si->adv_name_str.s, si->adv_name_str.len)==0) /*slower*/) /* comp. must be case insensitive, host names @@ -278,8 +279,8 @@ struct socket_info* grep_sock_info(str* host, unsigned short port, #endif /* ipv4 */ if ( (!(si->flags&SI_IS_IP)) && - (h_len==si->address_str.len) && - (memcmp(hname, si->address_str.s, + (h_len==si->address_str.len) && + (memcmp(hname, si->address_str.s, si->address_str.len)==0) ) goto found; @@ -308,7 +309,7 @@ struct socket_info* find_si(struct ip_addr* ip, unsigned short port, struct socket_info* si; struct socket_info** list; unsigned short c_proto; - + c_proto=proto?proto:PROTO_UDP; do{ /* get the proper sock_list */ @@ -316,7 +317,7 @@ struct socket_info* find_si(struct ip_addr* ip, unsigned short port, list=&udp_listen; else list=get_sock_info_list(c_proto); - + if (list==0){ LM_WARN("unknown proto %d\n", c_proto); goto not_found; /* false */ @@ -346,7 +347,7 @@ int new_sock2list(char* name, unsigned short port, unsigned short proto, enum si_flags flags, struct socket_info** list) { struct socket_info* si; - + si=new_sock_info(name, port, proto, adv_name, adv_port, children, flags); if (si==0){ LM_ERR("new_sock_info failed\n"); @@ -368,7 +369,7 @@ int add_listen_iface(char* name, unsigned short port, unsigned short proto, { struct socket_info** list; unsigned short c_proto; - + c_proto=(proto)?proto:PROTO_UDP; do{ list=get_sock_info_list(c_proto); @@ -423,7 +424,7 @@ int add_interfaces(char* if_name, int family, unsigned short port, struct ip_addr addr; int ret; enum si_flags flags; - + #ifdef HAVE_SOCKADDR_SA_LEN #ifndef MAX #define MAX(a,b) ( ((a)>(b))?(a):(b)) @@ -453,7 +454,7 @@ int add_interfaces(char* if_name, int family, unsigned short port, /* try a bigger array*/ pkg_free(ifc.ifc_req); } - + last=(char*)ifc.ifc_req+ifc.ifc_len; for(p=(char*)ifc.ifc_req; pifr_addr.sa_family);*/ continue; } - + /*get flags*/ ifrcopy=ifr; if (ioctl(s, SIOCGIFFLAGS, &ifrcopy)!=-1){ /* ignore errors */ /* ignore down ifs only if listening on all of them*/ - if (if_name==0){ + if (if_name==0){ /* if if not up, skip it*/ if (!(ifrcopy.ifr_flags & IFF_UP)) continue; } } - - - + + + if ((if_name==0)|| (strncmp(if_name, ifr.ifr_name, sizeof(ifr.ifr_name))==0)){ - + /*add address*/ - sockaddr2ip_addr(&addr, + sockaddr2ip_addr(&addr, (struct sockaddr*)(p+(long)&((struct ifreq*)0)->ifr_addr)); if ((tmp=ip_addr2a(&addr))==0) goto error; /* check if loopback */ - if (ifrcopy.ifr_flags & IFF_LOOPBACK) + if (ifrcopy.ifr_flags & IFF_LOOPBACK) flags|=SI_IS_LO; /* add it to one of the lists */ if (new_sock2list(tmp, port, proto, 0, 0, 0, flags, list)!=0){ @@ -529,9 +530,9 @@ int add_interfaces(char* if_name, int family, unsigned short port, } -/* fixes a socket list => resolve addresses, +/* fixes a socket list => resolve addresses, * interface names, fills missing members, remove duplicates */ -static int fix_socket_list(struct socket_info **list) +int fix_socket_list(struct socket_info **list) { struct socket_info* si; struct socket_info* l; @@ -540,10 +541,10 @@ static int fix_socket_list(struct socket_info **list) int len; struct hostent* he; char** h; - + /* try to change all the interface names into addresses * --ugly hack */ - + for (si=*list;si;){ next=si->next; if (add_interfaces(si->name.s, AF_INET, si->port_no, @@ -611,7 +612,7 @@ static int fix_socket_list(struct socket_info **list) LM_ERR("add_alias failed\n"); } } - hostent2ip_addr(&si->address, he, 0); /*convert to ip_addr + hostent2ip_addr(&si->address, he, 0); /*convert to ip_addr format*/ if ((tmp=ip_addr2a(&si->address))==0) goto error; if (si->address.af == AF_INET6) { @@ -722,7 +723,7 @@ static int fix_socket_list(struct socket_info **list) #endif /* USE_MCAST */ #ifdef EXTRA_DEBUG - printf(" %.*s [%s]:%s%s\n", si->name.len, + printf(" %.*s [%s]:%s%s\n", si->name.len, si->name.s, si->address_str.s, si->port_no_str.s, si->flags & SI_IS_MCAST ? " mcast" : ""); #endif @@ -747,7 +748,7 @@ static int fix_socket_list(struct socket_info **list) (strncmp(l->name.s, si->name.s, si->name.len)!=0)) ) add_alias(l->name.s, l->name.len, l->port_no, l->proto); - + /* remove l*/ sock_listrm(list, l); free_sock_info(l); @@ -760,7 +761,7 @@ static int fix_socket_list(struct socket_info **list) /* Remove invalid multicast entries */ si=*list; while(si){ - if ((si->flags & SI_IS_MCAST) && + if ((si->flags & SI_IS_MCAST) && ((si->proto == PROTO_TCP) #ifdef USE_TLS || (si->proto == PROTO_TLS) @@ -770,7 +771,7 @@ static int fix_socket_list(struct socket_info **list) #endif )){ LM_WARN("removing entry %s:%s [%s]:%s\n", - get_proto_name(si->proto), si->name.s, + get_proto_name(si->proto), si->name.s, si->address_str.s, si->port_no_str.s); l = si; si=si->next; @@ -794,7 +795,7 @@ static int fix_socket_list(struct socket_info **list) int fix_all_socket_lists(void) { struct utsname myname; - + if ((udp_listen==0) #ifdef USE_TCP && (tcp_listen==0) @@ -866,13 +867,13 @@ int fix_all_socket_lists(void) if ((udp_listen==0) #ifdef USE_TCP - && (tcp_listen==0) + && (tcp_listen==0 || tcp_disable) #ifdef USE_TLS - && (tls_listen==0) + && (tls_listen==0 || tls_disable) #endif #endif #ifdef USE_SCTP - && (sctp_listen==0) + && (sctp_listen==0 || sctp_disable) #endif ){ LM_ERR("no listening sockets\n"); @@ -887,7 +888,7 @@ int fix_all_socket_lists(void) /* * This function will retrieve a list of all ip addresses and ports that OpenSER * is listening on, with respect to the transport protocol specified with - * 'protocol'. + * 'protocol'. * * The first parameter, ipList, is a pointer to a pointer. It will be assigned a * new block of memory holding the IP Addresses and ports being listened to with @@ -901,9 +902,9 @@ int fix_all_socket_lists(void) * - ipList[0] will be the first octet of the first ip address * - ipList[3] will be the last octet of the first ip address. * - iplist[4] will be the port of the first ip address - * - - * - iplist[5] will be the first octet of the first ip address, - * - and so on. + * - + * - iplist[5] will be the first octet of the first ip address, + * - and so on. * * The function will return the number of sockets which were found. This can be * used to index into ipList. @@ -924,10 +925,10 @@ int get_socket_list_from_proto(int **ipList, int protocol) { int numberOfSockets = 0; int currentRow = 0; - /* I hate to use #ifdefs, but this is necessary because of the way + /* I hate to use #ifdefs, but this is necessary because of the way * get_sock_info_list() is defined. */ #ifndef USE_TCP - if (protocol == PROTO_TCP) + if (protocol == PROTO_TCP) { return 0; } @@ -979,34 +980,34 @@ int get_socket_list_from_proto(int **ipList, int protocol) { continue; } - (*ipList)[currentRow*(num_ip_octets + 1) ] = + (*ipList)[currentRow*(num_ip_octets + 1) ] = si->address.u.addr[0]; - (*ipList)[currentRow*(num_ip_octets + 1)+1] = + (*ipList)[currentRow*(num_ip_octets + 1)+1] = si->address.u.addr[1]; - (*ipList)[currentRow*(num_ip_octets + 1)+2] = + (*ipList)[currentRow*(num_ip_octets + 1)+2] = si->address.u.addr[2]; - (*ipList)[currentRow*(num_ip_octets + 1)+3] = + (*ipList)[currentRow*(num_ip_octets + 1)+3] = si->address.u.addr[3]; - (*ipList)[currentRow*(num_ip_octets + 1)+4] = + (*ipList)[currentRow*(num_ip_octets + 1)+4] = si->port_no; - + currentRow++; } return numberOfSockets; } -/* +/* * Takes a 'line' (from the proc file system), parses out the ipAddress, * address, and stores the number of bytes waiting in 'rx_queue' * * Returns 1 on success, and 0 on a failed parse. * * Note: The format of ipAddress is as defined in the comments of - * get_socket_list_from_proto() in this file. + * get_socket_list_from_proto() in this file. * */ -static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue) +static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue) { int i; @@ -1020,7 +1021,7 @@ static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue) /* Example line from /proc/net/tcp or /proc/net/udp: * - * sl local_address rem_address st tx_queue rx_queue + * sl local_address rem_address st tx_queue rx_queue * 21: 5A0A0B0A:CAC7 1C016E0A:0016 01 00000000:00000000 * * Algorithm: @@ -1035,16 +1036,16 @@ static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue) for (i = 0; i < 4; i++) { - currColonLocation = strchr(currentLocationInLine, ':'); + currColonLocation = strchr(currentLocationInLine, ':'); /* We didn't find all the needed ':', so fail. */ if (currColonLocation == NULL) { return 0; } - /* Parse out the integer, keeping the location of the next + /* Parse out the integer, keeping the location of the next * non-numerical character. */ - parsedInteger[i] = + parsedInteger[i] = (int) strtol(++currColonLocation, &nextNonNumericalChar, 16); @@ -1054,8 +1055,8 @@ static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue) if (nextNonNumericalChar == currColonLocation) { return 0; } - - /* Reset the currentLocationInLine to the last non-numerical + + /* Reset the currentLocationInLine to the last non-numerical * character, so that next iteration of this loop, we can find * the next colon location. */ currentLocationInLine = nextNonNumericalChar; @@ -1065,9 +1066,9 @@ static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue) /* Extract out the segments of the IP Address. They are stored in * reverse network byte order. */ for (i = 0; i < NUM_IP_OCTETS; i++) { - - ipAddress[i] = - parsedInteger[0] & (ipOctetExtractionMask << i*8); + + ipAddress[i] = + parsedInteger[0] & (ipOctetExtractionMask << i*8); ipAddress[i] >>= i*8; @@ -1076,20 +1077,20 @@ static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue) ipAddress[NUM_IP_OCTETS] = parsedInteger[1]; *rx_queue = parsedInteger[3]; - + return 1; - + } /* - * Returns 1 if ipOne was found in ipArray, and 0 otherwise. + * Returns 1 if ipOne was found in ipArray, and 0 otherwise. * - * The format of ipOne and ipArray are described in the comments of + * The format of ipOne and ipArray are described in the comments of * get_socket_list_from_proto() in this file. * * */ -static int match_ip_and_port(int *ipOne, int *ipArray, int sizeOf_ipArray) +static int match_ip_and_port(int *ipOne, int *ipArray, int sizeOf_ipArray) { int curIPAddrIdx; int curOctetIdx; @@ -1101,10 +1102,10 @@ static int match_ip_and_port(int *ipOne, int *ipArray, int sizeOf_ipArray) /* Check for octets that don't match. If one is found, skip the * rest. */ for (curOctetIdx = 0; curOctetIdx < NUM_IP_OCTETS + 1; curOctetIdx++) { - + /* We've encoded a 2D array as a 1D array. So find out * our position in the 1D array. */ - ipArrayIndex = + ipArrayIndex = curIPAddrIdx * (NUM_IP_OCTETS + 1) + curOctetIdx; if (ipOne[curOctetIdx] != ipArray[ipArrayIndex]) { @@ -1134,14 +1135,14 @@ static int match_ip_and_port(int *ipOne, int *ipArray, int sizeOf_ipArray) * - if forTCP is zero, the check involves only the UDP transport. * * Note: This only works on linux systems supporting the /proc/net/[tcp|udp] - * interface. On other systems, zero will always be returned. + * interface. On other systems, zero will always be returned. */ static int get_used_waiting_queue( - int forTCP, int *interfaceList, int listSize) + int forTCP, int *interfaceList, int listSize) { FILE *fp; char *fileToOpen; - + char lineBuffer[MAX_PROC_BUFFER]; int ipAddress[NUM_IP_OCTETS+1]; int rx_queue; @@ -1156,7 +1157,7 @@ static int get_used_waiting_queue( } else { fileToOpen = "/proc/net/udp"; } - + fp = fopen(fileToOpen, "r"); if (fp == NULL) { @@ -1173,7 +1174,7 @@ static int get_used_waiting_queue( /* Parse out the ip address, port, and rx_queue. */ if(parse_proc_net_line(lineBuffer, ipAddress, &rx_queue)) { - /* Only add rx_queue if the line just parsed corresponds + /* Only add rx_queue if the line just parsed corresponds * to an interface we are listening on. We do this * check because it is possible that this system has * other network interfaces that OpenSER has been told @@ -1191,11 +1192,11 @@ static int get_used_waiting_queue( /* * Returns the sum of the number of bytes waiting to be consumed on all network - * interfaces and transports that OpenSIPS is listening on. + * interfaces and transports that OpenSIPS is listening on. * * Note: This currently only works on systems supporting the /proc/net/[tcp|udp] * interface. On other systems, zero will always be returned. To change - * this in the future, add an equivalent for get_used_waiting_queue(). + * this in the future, add an equivalent for get_used_waiting_queue(). */ int get_total_bytes_waiting(int only_proto) { @@ -1241,14 +1242,14 @@ void print_all_socket_lists(void) struct socket_info *si; struct socket_info** list; unsigned short proto; - - + + proto=PROTO_UDP; do{ list=get_sock_info_list(proto); for(si=list?*list:0; si; si=si->next){ printf(" %s: %s [%s]:%s%s\n", get_proto_name(proto), - si->name.s, si->address_str.s, si->port_no_str.s, + si->name.s, si->address_str.s, si->port_no_str.s, si->flags & SI_IS_MCAST ? " mcast" : ""); } }while((proto=next_proto(proto))); @@ -1259,12 +1260,12 @@ void print_aliases(void) { struct host_alias* a; - for(a=aliases; a; a=a->next) + for(a=aliases; a; a=a->next) if (a->port) - printf(" %s: %.*s:%d\n", get_proto_name(a->proto), + printf(" %s: %.*s:%d\n", get_proto_name(a->proto), a->alias.len, a->alias.s, a->port); else - printf(" %s: %.*s:*\n", get_proto_name(a->proto), + printf(" %s: %.*s:*\n", get_proto_name(a->proto), a->alias.len, a->alias.s); } @@ -1285,7 +1286,7 @@ int probe_max_sock_buff(int sock,int buff_choice,int buff_max,int buff_increment int phase=0; int buff_opt; char *info; - + if (buff_choice == 0) { info = "rcv"; @@ -1320,7 +1321,7 @@ int probe_max_sock_buff(int sock,int buff_choice,int buff_max,int buff_increment /* increase size; double in initial phase, add linearly later */ if (phase==0) optval <<= 1; else optval+=buff_increment; if (optval > maxbuffer){ - if (phase==1) break; + if (phase==1) break; else { phase=1; optval >>=1; continue; } } LM_DBG("trying : %d\n", optval ); @@ -1331,9 +1332,9 @@ int probe_max_sock_buff(int sock,int buff_choice,int buff_max,int buff_increment " for %d, phase %d: %s\n", optval, phase, strerror(errno)); /* if setting buffer size failed and still in the aggressive phase, try less aggressively; otherwise give up */ - if (phase==0) { phase=1; optval >>=1 ; continue; } + if (phase==0) { phase=1; optval >>=1 ; continue; } else break; - } + } /* verify if change has taken effect */ /* Linux note -- otherwise I would never know that; funny thing: Linux doubles size for which we asked in setsockopt */ @@ -1350,11 +1351,11 @@ int probe_max_sock_buff(int sock,int buff_choice,int buff_max,int buff_increment LM_DBG("setting buf has no effect\n"); /* if setting buffer size failed and still in the aggressive phase, try less aggressively; otherwise give up */ - if (phase==0) { phase=1; optval >>=1 ; continue; } + if (phase==0) { phase=1; optval >>=1 ; continue; } else break; - } + } } - + } /* for ... */ foptvallen=sizeof(foptval); if (getsockopt( sock, SOL_SOCKET, buff_opt, (void*) &foptval, diff --git a/socket_info.h b/socket_info.h index f2afe5e2b32..7ba987e14ad 100644 --- a/socket_info.h +++ b/socket_info.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to" the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to" the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -33,7 +33,7 @@ #include -#include "ip_addr.h" +#include "ip_addr.h" #include "dprint.h" #include "globals.h" #include "ut.h" @@ -55,16 +55,22 @@ extern struct socket_info* sctp_listen; int add_listen_iface(char* name, unsigned short port, unsigned short proto, char *adv_name, unsigned short adv_port, unsigned short children, enum si_flags flags); +inline struct socket_info * +new_sock_info(char* name, unsigned short port, unsigned short proto, + char *adv_name, unsigned short adv_port, + unsigned short children, enum si_flags flags); + int fix_all_socket_lists(); +int fix_socket_list(struct socket_info **); /* - * This function will retrieve a list of all ip addresses and ports that - * OpenSIPS is listening on, with respect to the transport protocol specified + * This function will retrieve a list of all ip addresses and ports that + * OpenSIPS is listening on, with respect to the transport protocol specified * with 'protocol'. * - * The first parameter, ipList, is a pointer to a pointer. It will be assigned - * new block of memory holding the IP Addresses and ports being listened to - * with respect to 'protocol'. The array maps a 2D array into a 1 dimensional + * The first parameter, ipList, is a pointer to a pointer. It will be assigned + * new block of memory holding the IP Addresses and ports being listened to + * with respect to 'protocol'. The array maps a 2D array into a 1 dimensional * space, and is layed out as follows: * * The first NUM_IP_OCTETS indices will be the IP address, and the next index @@ -78,14 +84,14 @@ int fix_all_socket_lists(); * - iplist[5] will be the first octet of the first ip address, * - and so on. * - * The function will return the number of sockets which were found. This can + * The function will return the number of sockets which were found. This can * be used to index into ipList. * * NOTE: This function assigns a block of memory equal to: * * returnedValue * (NUM_IP_OCTETS + 1) * sizeof(int); * - * Therefore it is CRUCIAL that you free ipList when you are done with + * Therefore it is CRUCIAL that you free ipList when you are done with * its contents, to avoid a nasty memory leak. */ int get_socket_list_from_proto(int **ipList, int protocol); @@ -94,9 +100,9 @@ int get_socket_list_from_proto(int **ipList, int protocol); * Returns the sum of the number of bytes waiting to be consumed on all network * interfaces and transports that OpenSIPS is listening on. * - * Note: This currently only works on systems supporting the - * /proc/net/[tcp|udp] interface. On other systems, zero will always - * be returned. Details of why this is so can be found in + * Note: This currently only works on systems supporting the + * /proc/net/[tcp|udp] interface. On other systems, zero will always + * be returned. Details of why this is so can be found in * network_stats.c */ int get_total_bytes_waiting(int only_proto); @@ -121,7 +127,7 @@ struct socket_info* find_si(struct ip_addr* ip, unsigned short port, static inline struct socket_info** get_sock_info_list(unsigned short proto) { - + switch(proto){ case PROTO_UDP: return &udp_listen; @@ -238,7 +244,7 @@ inline static int parse_proto(unsigned char* s, long len, int* proto) (((unsigned int)(b))<<8)+ \ ((unsigned int)(c)) ) | 0x20202020) unsigned int i; - + /* must support 3-char arrays for udp, tcp, tls, * must support 4-char arrays for sctp */ *proto=PROTO_NONE; @@ -288,11 +294,11 @@ inline static int parse_phostport(char* s, int slen, char** host, int* hlen, int bracket; str tmp; char* end; - + first=second=0; bracket=0; end = s + slen; - + /* find the first 2 ':', ignoring possible ipv6 addresses * (substrings between []) */ @@ -317,7 +323,7 @@ inline static int parse_phostport(char* s, int slen, char** host, int* hlen, } if (p==s) return -1; if (*(p-1)==':') goto error_colons; - + if (first==0){ /* no ':' => only host */ *host=s; *hlen=(int)(p-s); @@ -367,7 +373,7 @@ inline static int parse_phostport(char* s, int slen, char** host, int* hlen, /* function will write the proto as string, starting from the p pointer. The - new resulting proto will be returned (where writting ended) */ + new resulting proto will be returned (where writing ended) */ static inline char* proto2str(int proto, char *p) { switch (proto) { diff --git a/sr_module.c b/sr_module.c index c996b9da251..845dd2ac684 100644 --- a/sr_module.c +++ b/sr_module.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -88,12 +88,12 @@ int register_builtin_modules(void) ret=0; #ifdef STATIC_TM - ret=register_module(&tm_exports,"built-in", 0); + ret=register_module(&tm_exports,"built-in", 0); if (ret<0) return ret; #endif #ifdef STATIC_EXEC - ret=register_module(&exec_exports,"built-in", 0); + ret=register_module(&exec_exports,"built-in", 0); if (ret<0) return ret; #endif @@ -103,15 +103,15 @@ int register_builtin_modules(void) #endif #ifdef STATIC_AUTH - ret=register_module(&auth_exports, "built-in", 0); + ret=register_module(&auth_exports, "built-in", 0); if (ret<0) return ret; #endif - + #ifdef STATIC_RR ret=register_module(&rr_exports, "built-in", 0); if (ret<0) return ret; #endif - + #ifdef STATIC_USRLOC ret=register_module(&usrloc_exports, "built-in", 0); if (ret<0) return ret; @@ -121,19 +121,17 @@ int register_builtin_modules(void) ret=register_module(&sl_exports, "built-in", 0); if (ret<0) return ret; #endif - + return ret; } - - /* registers a module, register_f= module register functions * returns <0 on error, 0 on success */ int register_module(struct module_exports* e, char* path, void* handle) { int ret; struct sr_module* mod; - + ret=-1; /* add module to the list */ @@ -160,6 +158,15 @@ int register_module(struct module_exports* e, char* path, void* handle) } } + /* register all module dependencies */ + if (e->deps) { + ret = add_module_dependencies(mod); + if (ret != 0) { + LM_CRIT("failed to add module dependencies [%d]\n", ret); + return ret; + } + } + return 0; error: return ret; @@ -263,7 +270,7 @@ int sr_load_module(char* path) /* searches the module list and returns pointer to the "name" function or - * 0 if not found + * 0 if not found * flags parameter is OR value of all flags that must match */ cmd_function find_export(char* name, int param_no, int flags) @@ -307,7 +314,7 @@ cmd_export_t* find_cmd_export_t(char* name, int param_no, int flags) /* - * searches the module list and returns pointer to "name" function in module + * searches the module list and returns pointer to "name" function in module * "mod" or 0 if not found * flags parameter is OR value of all flags that must match */ @@ -390,7 +397,7 @@ static int init_mod_child( struct sr_module* m, int rank, char *type ) return -1; if (m->exports && m->exports->init_child_f) { - LM_DBG("type=%s, rank=%d, module=%s\n", + LM_DBG("type=%s, rank=%d, module=%s\n", type, rank, m->exports->name); if (m->exports->init_child_f(rank)<0) { LM_ERR("failed to initializing module %s, rank %d\n", @@ -425,6 +432,7 @@ int init_child(int rank) case PROC_TIMER: type = "PROC_TIMER"; break; case PROC_MODULE: type = "PROC_MODULE"; break; case PROC_TCP_MAIN: type = "PROC_TCP_MAIN"; break; + case PROC_BIN: type = "PROC_BIN"; break; } if (!type) { @@ -444,23 +452,38 @@ int init_child(int rank) which modules are loaded in config file */ -static int init_mod( struct sr_module* m ) +static int init_mod( struct sr_module* m, int skip_others) { + struct sr_module_dep *dep; + if (m) { /* iterate through the list; if error occurs, propagate it up the stack */ - if (init_mod(m->next)!=0) return -1; - if (m->exports==0) + if (!skip_others && init_mod(m->next, 0) != 0) + return -1; + + /* our module might have been already loaded through dependencies! */ + if (m->is_loaded) + return 0; + + if (!m->exports) return 0; + + /* make sure certain modules get loaded before this one */ + for (dep = m->sr_deps; dep; dep = dep->next) { + if (!dep->mod->is_loaded) + init_mod(dep->mod, 1); + } + if (m->exports->init_f) { LM_DBG("initializing module %s\n", m->exports->name); if (m->exports->init_f()!=0) { - LM_ERR("failed to initialize" - " module %s\n", m->exports->name); + LM_ERR("failed to initialize module %s\n", m->exports->name); return -1; } } + /* no init function -- proceed further */ #ifdef STATISTICS if (m->exports->stats) { @@ -481,6 +504,8 @@ static int init_mod( struct sr_module* m ) } } + m->is_loaded = 1; + /* proceed with success */ return 0; } else { @@ -495,7 +520,18 @@ static int init_mod( struct sr_module* m ) */ int init_modules(void) { - return init_mod(modules); + int ret; + + if (solve_module_dependencies(modules) != 0) { + LM_ERR("failed to solve module dependencies\n"); + return -1; + } + + ret = init_mod(modules, 0); + + free_module_dependencies(modules); + + return ret; } /* Returns 1 if the module with name 'name' is loaded, and zero otherwise. */ @@ -575,7 +611,7 @@ int start_module_procs(void) exit(-1); } - if (send_status_code(0) < 0) + if (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); } else diff --git a/sr_module.h b/sr_module.h index 4a7f88634d8..fad98866ff5 100644 --- a/sr_module.h +++ b/sr_module.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -54,6 +54,10 @@ #include "version.h" #include "route.h" +typedef struct param_export_ param_export_t; + +#include "sr_module_deps.h" + typedef struct module_exports* (*module_register)(); typedef int (*cmd_function)(struct sip_msg*, char*, char*, char*, char*, char*, char*); typedef int (*fixup_function)(void** param, int param_no); @@ -82,6 +86,7 @@ typedef int (*mod_proc_wrapper)(); #define PROC_TIMER -1 /* Timer attendant process */ #define PROC_MODULE -2 /* Extra process requested by modules */ #define PROC_TCP_MAIN -4 /* TCP main process */ +#define PROC_BIN -8 /* Any binary interface listener */ #define DEFAULT_DLFLAGS 0 /* value that signals to module loader to use default dlopen flags in opensips */ @@ -129,17 +134,37 @@ struct proc_export_ { unsigned int flags; }; +typedef struct dep_export_ { + module_dependency_t md[MAX_MOD_DEPS]; + modparam_dependency_t mpd[]; +} dep_export_t; typedef struct cmd_export_ cmd_export_t; -typedef struct param_export_ param_export_t; typedef struct proc_export_ proc_export_t; + +struct sr_module{ + char* path; + void* handle; + int is_loaded; + struct module_exports* exports; + + /* a list of module dependencies */ + struct sr_module_dep *sr_deps; + + struct sr_module* next; +}; + + struct module_exports{ char* name; /*!< null terminated module name */ + enum module_type type; char *version; /*!< module version */ char *compile_flags; /*!< compile flags used on the module */ unsigned int dlflags; /*!< flags for dlopen */ - + + dep_export_t *deps; /*!< module and modparam dependencies */ + cmd_export_t* cmds; /*!< null terminated array of the exported commands */ param_export_t* params; /*!< null terminated array of the exported @@ -167,17 +192,6 @@ struct module_exports{ }; - - - -struct sr_module{ - char* path; - void* handle; - struct module_exports* exports; - struct sr_module* next; -}; - - struct sr_module* modules; /*!< global module list*/ int register_builtin_modules(); diff --git a/sr_module_deps.c b/sr_module_deps.c new file mode 100644 index 00000000000..6abd1c22e9b --- /dev/null +++ b/sr_module_deps.c @@ -0,0 +1,318 @@ +/* + * $Id$ + * + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2014-05-12 removed all module ordering requirements at script level (liviu) + */ + +#include +#include + +#include "dprint.h" +#include "error.h" +#include "mem/mem.h" +#include "pt.h" + +#include "sr_module_deps.h" + +/* the list head of unsolved module dependencies: struct sr_module ----> "module_name" */ +static struct sr_module_dep unsolved_deps; + +#define mod_type_to_string(type) \ + (type == MOD_TYPE_NULL ? NULL : \ + type == MOD_TYPE_SQLDB ? "sqldb module" : \ + type == MOD_TYPE_CACHEDB ? "cachedb module" : \ + type == MOD_TYPE_AAA ? "aaa module" : \ + "module") + +module_dependency_t *alloc_module_dep(enum module_type mod_type, char *mod_name, + enum dep_type dep_type) +{ + module_dependency_t *md; + + /* also allocate a zeroed entry in the end */ + md = pkg_malloc(2 * sizeof *md); + if (!md) { + LM_ERR("out of pkg\n"); + return NULL; + } + + memset(md, 0, 2 * sizeof *md); + md->mod_type = mod_type; + md->mod_name = mod_name; + md->type = dep_type; + + return md; +} + +module_dependency_t *get_deps_sqldb_url(param_export_t *param) +{ + char *db_url = *(char **)param->param_pointer; + + if (param->type & USE_FUNC_PARAM) + return alloc_module_dep(MOD_TYPE_SQLDB, NULL, DEP_WARN); + + if (!db_url || strlen(db_url) == 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_SQLDB, NULL, DEP_WARN); +} + +static int add_module_dependency(struct sr_module *mod, module_dependency_t *dep, + char *script_param) +{ + struct sr_module_dep *md; + int len; + + LM_DBG("adding type %d dependency %s - (%s %s)\n", dep->type, + mod->exports->name, mod_type_to_string(dep->mod_type), + dep->mod_name); + + len = dep->mod_name ? strlen(dep->mod_name) : 0; + + md = pkg_malloc(sizeof *md + len + 1); + if (!md) { + LM_CRIT("out of pkg mem\n"); + return -1; + } + memset(md, 0, sizeof *md + len + 1); + + md->mod = mod; + md->mod_type = dep->mod_type; + md->type = dep->type; + if (dep->mod_name) { + md->dep.s = (char *)(md + 1); + md->dep.len = len; + memcpy(md->dep.s, dep->mod_name, len); + } + + if (script_param) + md->script_param = script_param; + + md->next = unsolved_deps.next; + unsolved_deps.next = md; + + return 0; +} + +/* + * register all OpenSIPS module dependencies of a single module parameter + */ +int add_modparam_dependencies(struct sr_module *mod, param_export_t *param) +{ + struct sr_module_dep *it, *tmp; + module_dependency_t *md; + modparam_dependency_t *mpd; + struct module_dependency *(*get_deps_f)(param_export_t *param) = NULL; + + if (!mod->exports->deps) + return 0; + + /* lookup this parameter's dependency fetching function */ + for (mpd = mod->exports->deps->mpd; mpd->script_param; mpd++) { + if (strcmp(mpd->script_param, param->name) == 0) + get_deps_f = mpd->get_deps_f; + } + + /* 98% of OpenSIPS's modparams will stop here */ + if (!get_deps_f) + return 0; + + /* clear previous entries in case this parameter is set multiple times */ + for (it = &unsolved_deps; it->next; it = it->next) { + if (strcmp(it->next->mod->exports->name, mod->exports->name) == 0 && + (it->next->script_param && + strcmp(it->next->script_param, param->name) == 0)) { + + tmp = it->next; + it->next = it->next->next; + pkg_free(tmp); + } + } + + md = get_deps_f(param); + if (!md) + return 0; + + LM_DBG("adding modparam dependencies:\n"); + for (; md->mod_type != MOD_TYPE_NULL; md++) { + LM_DBG("dependency found: %s ---> ( %s %s )\n", mod->exports->name, + mod_type_to_string(md->mod_type), md->mod_name); + + if (add_module_dependency(mod, md, param->name) != 0) { + LM_ERR("failed to add dep!\n"); + return E_BUG; + } + } + + return 0; +} + +/* + * register all OpenSIPS module dependencies of a single module + */ +int add_module_dependencies(struct sr_module *mod) +{ + module_dependency_t *md; + + for (md = mod->exports->deps->md; md->mod_type != MOD_TYPE_NULL; md++) { + if (add_module_dependency(mod, md, NULL) != 0) { + LM_ERR("failed to add mod dep\n"); + return -1; + } + } + + return 0; +} + +int solve_module_dependencies(struct sr_module *modules) +{ + struct sr_module_dep *md, *it; + struct sr_module *this, *mod; + enum module_type mod_type; + enum dep_type dep_type; + int dep_solved; + + /* + * now that we've loaded all shared libraries, + * we can attempt to solve each dependency + */ + for (it = unsolved_deps.next; it; ) { + md = it; + it = it->next; + + LM_DBG("solving dependency %s -> %s %.*s\n", md->mod->exports->name, + mod_type_to_string(md->mod_type), md->dep.len, md->dep.s); + + dep_type = md->type; + + /* + * for generic dependencies (e.g. dialog depends on MOD_TYPE_SQLDB), + * first load all modules of given type + */ + if (!md->dep.s) { + this = md->mod; + mod_type = md->mod_type; + + for (dep_solved = 0, mod = modules; mod; mod = mod->next) { + if (mod != this && mod->exports->type == mod_type) { + if (!md) { + md = pkg_malloc(sizeof *md); + if (!md) { + LM_ERR("no more pkg\n"); + return -1; + } + memset(md, 0, sizeof *md); + } + + /* + * re-purpose this structure by linking it into a module's + * list of dependencies (will be used at init time) + * + * md->mod used to point to (highlighted with []): + * [sr_module A] ---> "mod_name" + * + * now, the dependency is solved. md->mod will point to: + * sr_module A ---> [sr_module B] + */ + md->mod = mod; + md->next = this->sr_deps; + this->sr_deps = md; + + md = NULL; + dep_solved++; + } + } + } else { + for (dep_solved = 0, mod = modules; mod; mod = mod->next) { + if (strcmp(mod->exports->name, md->dep.s) == 0) { + + /* quick sanity check */ + if (mod->exports->type != md->mod_type) + LM_BUG("[%.*s %d] -> [%s %d]\n", md->dep.len, md->dep.s, + md->mod_type, mod->exports->name, + mod->exports->type); + + /* same re-purposing technique as above */ + md->next = md->mod->sr_deps; + md->mod->sr_deps = md; + md->mod = mod; + + dep_solved++; + break; + } + } + } + + /* treat unmet dependencies using the intended behaviour */ + if (!dep_solved) { + switch (dep_type) { + case DEP_SILENT: + LM_DBG("module %s depends on %s%s%s%.*s, but %s loaded!\n", + md->mod->exports->name, + md->dep.len == 0 ? + ((md->mod_type == MOD_TYPE_SQLDB || + md->mod_type == MOD_TYPE_AAA) ? "an " : + md->mod_type == MOD_TYPE_CACHEDB ? "a " : "") : "", + mod_type_to_string(md->mod_type), + md->dep.len == 0 ? "" : " ", + md->dep.len, md->dep.s, + md->dep.len == 0 ? "none was" : "it was not"); + break; + case DEP_WARN: + case DEP_ABORT: + LM_WARN("module %s depends on %s%s%s%.*s, but %s loaded!\n", + md->mod->exports->name, + md->dep.len == 0 ? + ((md->mod_type == MOD_TYPE_SQLDB || + md->mod_type == MOD_TYPE_AAA) ? "an " : + md->mod_type == MOD_TYPE_CACHEDB ? "a " : "") : "", + mod_type_to_string(md->mod_type), + md->dep.len == 0 ? "" : " ", + md->dep.len, md->dep.s, + md->dep.len == 0 ? "none was" : "it was not"); + break; + } + + pkg_free(md); + if (dep_type == DEP_ABORT) + return -1; + } + } + + return 0; +} + +/* after all modules are properly loaded, free all sr_module_dep structures */ +void free_module_dependencies(struct sr_module *modules) +{ + struct sr_module_dep *aux; + struct sr_module *mod; + + for (mod = modules; mod; mod = mod->next) { + while (mod->sr_deps) { + aux = mod->sr_deps; + mod->sr_deps = aux->next; + pkg_free(aux); + } + } +} diff --git a/sr_module_deps.h b/sr_module_deps.h new file mode 100644 index 00000000000..884088a75d9 --- /dev/null +++ b/sr_module_deps.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2014 OpenSIPS Solutions + * + * This file is part of opensips, a free SIP server. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * History: + * ------- + * 2014-05-12 removed all module ordering requirements at script level (liviu) + */ + +#ifndef SR_MODULE_DEPS_H +#define SR_MODULE_DEPS_H + +#include "sr_module.h" + +/* + * Description: + * + * - the core module dependencies code simply helps rearrange the module loading + * order so that the dependencies of each OpenSIPS module are satisfied + * + * - a module may specify dependencies in two ways: + * * module -> module (if X -> Y, load Y before X) - most common + * * modparam -> module (if a parameter of module X has a certain value, + * ensure module Y loads first) + * + * - a dependency can be of two types: + * * straightforward dependency ("acc" depends on "tm") + * * generic dependency ("acc" depends on any MOD_TYPE_SQLDB module) + * + * - both module and modparam dependencies are populated within exports->deps + * + * - for the latter, a function must be provided for each modparam: + * * input: the parameter's populated param_export_t struct + * * output: NULL / module dependency resulted from the value of the modparam + * + * when dependencies are not satisfied (e.g. depending module not present), + * OpenSIPS may throw a warning, abort or not do anything at all + * + * For a complete usage example, please refer to the "acc" module + * + * Developer Notes: + * - circular module dependencies are possible and not detected! + * - it is up to the module writers to prevent such side effects + */ + +#define MAX_MOD_DEPS 10 + +/* core + module level structures */ +enum module_type { + MOD_TYPE_NULL, /* for iteration purposes */ + MOD_TYPE_DEFAULT, + MOD_TYPE_SQLDB, + MOD_TYPE_CACHEDB, + MOD_TYPE_AAA, +}; + +/* behaviour at startup if the dependency is not met */ +enum dep_type { + DEP_SILENT, /* load re-ordering only if possible */ + DEP_WARN, /* load re-ordering, and a warning if module not found */ + DEP_ABORT, /* load re-ordering, and shut down if module not found */ +}; + +typedef struct module_dependency { + enum module_type mod_type; + char *mod_name; /* as found in "module_exports" */ + enum dep_type type; +} module_dependency_t; + +typedef struct modparam_dependency { + char *script_param; /* module parameter at script level */ + + /* return value must be allocated in pkg memory! */ + struct module_dependency *(*get_deps_f)(param_export_t *param); +} modparam_dependency_t; + +/* helps to avoid duplicate code when writing "get_deps_f" functions */ +module_dependency_t *alloc_module_dep(enum module_type mod_type, char *mod_name, + enum dep_type dep_type); + +/* commonly used modparam dependency functions */ + +/** + * get_deps_sqldb_url - commonly used by modules which use SQL DB URLs + * + * Behaviour: + * - imposes a generic MOD_TYPE_SQLDB dependency only when the URL is set + * (strlen(url) > 0) + */ +module_dependency_t *get_deps_sqldb_url(param_export_t *param); + +/* core level structures and functions */ +struct sr_module_dep { + struct sr_module *mod; + char *script_param; + enum module_type mod_type; + enum dep_type type; + str dep; + + struct sr_module_dep *next; +}; + +int add_modparam_dependencies(struct sr_module *mod, param_export_t *param); +int add_module_dependencies(struct sr_module *mod); + +int solve_module_dependencies(struct sr_module *modules); +void free_module_dependencies(struct sr_module *modules); + +#endif diff --git a/statistics.c b/statistics.c index 302580ee9a9..5df38d7440b 100644 --- a/statistics.c +++ b/statistics.c @@ -53,14 +53,19 @@ #ifdef STATISTICS static stats_collector *collector = NULL; +static int stats_ready; static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param); +static struct mi_root *mi_list_stats(struct mi_root *cmd, void *param); static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param); static mi_export_t mi_stat_cmds[] = { { "get_statistics", "prints the statistics (all, group or one) realtime values.", mi_get_stats, 0 , 0, 0 }, + { "list_statistics", + "lists all the registered statistics and their types", + mi_list_stats, 0 , 0, 0 }, { "reset_statistics", "resets the value of a statistic variable", mi_reset_stats, 0 , 0, 0 }, { 0, 0, 0, 0, 0, 0} @@ -81,17 +86,17 @@ gen_lock_t *stat_lock = 0; * Returns the statistic associated with 'numerical_code' and 'out_codes'. * Specifically: * - * - if out_codes is nonzero, then the stat_var for the number of messages + * - if out_codes is nonzero, then the stat_var for the number of messages * _sent out_ with the 'numerical_code' will be returned if it exists. - * - otherwise, the stat_var for the number of messages _received_ with the - * 'numerical_code' will be returned, if the stat exists. + * - otherwise, the stat_var for the number of messages _received_ with the + * 'numerical_code' will be returned, if the stat exists. */ stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int out_codes) { static char msg_code[INT2STR_MAX_LEN+4]; str stat_name; - stat_name.s = int2bstr( (unsigned long)numerical_code, msg_code, + stat_name.s = int2bstr( (unsigned long)numerical_code, msg_code, &stat_name.len); stat_name.s[stat_name.len++] = '_'; @@ -162,9 +167,9 @@ int register_udp_load_stat(str *name, stat_var **s, int children) } memset((*s)->u.val,0,sizeof(stat_val)); - if ( (stat_name = build_stat_name(name,"load")) == 0 || + if ( (stat_name = build_stat_name(name,"load")) == 0 || register_stat2("load",stat_name,(stat_var**)calc_udp_load, - STAT_IS_FUNC,*s) != 0) { + STAT_IS_FUNC, *s, 0) != 0) { LM_ERR("failed to add load stat\n"); return -1; } @@ -190,7 +195,7 @@ int register_tcp_load_stat(stat_var **s) memset((*s)->u.val,0,sizeof(stat_val)); if (register_stat2("load","tcp-load",(stat_var**)calc_tcp_load, - STAT_IS_FUNC,*s) != 0) { + STAT_IS_FUNC, *s, 0) != 0) { LM_ERR("failed to add load stat\n"); return -1; } @@ -218,8 +223,10 @@ static inline module_stats* get_stat_module( str *module) return 0; } +#define add_stat_module(module) \ + __add_stat_module(module, 0) -static inline module_stats* add_stat_module( char *module) +static inline module_stats* __add_stat_module( char *module, int unsafe) { module_stats *amods; module_stats *mods; @@ -228,8 +235,13 @@ static inline module_stats* add_stat_module( char *module) if ( (module==0) || ((len = strlen(module))==0 ) ) return 0; - amods = (module_stats*)shm_realloc( collector->amodules, - (collector->mod_no+1)*sizeof(module_stats) ); + amods = unsafe ? + (module_stats*)shm_realloc_unsafe( collector->amodules, + (collector->mod_no+1)*sizeof(module_stats)) + : + (module_stats*)shm_realloc( collector->amodules, + (collector->mod_no+1)*sizeof(module_stats)); + if (amods==0) { LM_ERR("no more shm memory\n"); return 0; @@ -296,7 +308,7 @@ int init_stats_collector(void) char *s; /* init the collector */ - collector = (stats_collector*)shm_malloc(sizeof(stats_collector)); + collector = (stats_collector*)shm_malloc_unsafe(sizeof(stats_collector)); if (collector==0) { LM_ERR("no more shm mem\n"); goto error; @@ -307,7 +319,7 @@ int init_stats_collector(void) for ( psn=pending_name_list ; psn ; psn=next ) { next = psn->next; - s = (char*)shm_malloc( psn->name->len ); + s = (char*)shm_malloc_unsafe( psn->name->len ); if (s==NULL) { LM_ERR("no more shm mem (%d)\n", psn->name->len); goto error; @@ -318,6 +330,16 @@ int init_stats_collector(void) pkg_free(psn); } + /* + * register shm statistics in an unsafe manner, as some allocators + * would actually attempt to update these statistics + * during their "safe" allocations -- Liviu + */ + if (__register_module_stats( "shmem", shm_stats, 1) != 0) { + LM_ERR("failed to register sh_mem statistics\n"); + goto error; + } + #ifdef NO_ATOMIC_OPS /* init BIG (really BIG) lock */ stat_lock = lock_alloc(); @@ -344,11 +366,7 @@ int init_stats_collector(void) LM_ERR("failed to register core statistics\n"); goto error; } - /* register sh_mem statistics */ - if (register_module_stats( "shmem", shm_stats)!=0 ) { - LM_ERR("failed to register sh_mem statistics\n"); - goto error; - } + /* register sh_mem statistics */ if (register_module_stats( "net", net_stats)!=0 ) { LM_ERR("failed to register network statistics\n"); @@ -364,6 +382,7 @@ int init_stats_collector(void) /* mark it as dynamic, so it will require locking */ dy_mod->is_dyn = 1 ; + stats_ready = 1; LM_DBG("statistics manager successfully initialized\n"); return 0; @@ -424,11 +443,19 @@ void destroy_stats_collector(void) return; } +int stats_are_ready(void) +{ + return stats_ready; +} /********************* Create/Register STATS functions ***********************/ +/** + * Note: certain statistics (e.g. shm statistics) require different handling, + * hence the parameter + */ int register_stat2( char *module, char *name, stat_var **pvar, - unsigned short flags, void *ctx) + unsigned short flags, void *ctx, int unsafe) { module_stats* mods; stat_var **shash; @@ -439,13 +466,19 @@ int register_stat2( char *module, char *name, stat_var **pvar, int name_len; if (module==0 || name==0 || pvar==0) { - LM_ERR("invalid parameters module=%p, name=%p, pvar=%p \n", + LM_ERR("invalid parameters module=%p, name=%p, pvar=%p \n", module, name, pvar); goto error; } name_len = strlen(name); - stat = (stat_var*)shm_malloc(sizeof(stat_var) + ((flags&STAT_SHM_NAME)==0)*name_len); + stat = unsafe ? + (stat_var*)shm_malloc_unsafe(sizeof(stat_var) + + ((flags&STAT_SHM_NAME)==0)*name_len) + : + (stat_var*)shm_malloc(sizeof(stat_var) + + ((flags&STAT_SHM_NAME)==0)*name_len); + if (stat==0) { LM_ERR("no more shm memory\n"); goto error; @@ -453,7 +486,9 @@ int register_stat2( char *module, char *name, stat_var **pvar, memset( stat, 0, sizeof(stat_var) ); if ( (flags&STAT_IS_FUNC)==0 ) { - stat->u.val = (stat_val*)shm_malloc(sizeof(stat_val)); + stat->u.val = unsafe ? + (stat_val*)shm_malloc_unsafe(sizeof(stat_val)) : + (stat_val*)shm_malloc(sizeof(stat_val)); if (stat->u.val==0) { LM_ERR("no more shm memory\n"); goto error1; @@ -473,7 +508,7 @@ int register_stat2( char *module, char *name, stat_var **pvar, smodule.len = strlen(module); mods = get_stat_module(&smodule); if (mods==0) { - mods = add_stat_module(module); + mods = __add_stat_module(module, 1); if (mods==0) { LM_ERR("failed to add new module\n"); goto error2; @@ -504,12 +539,29 @@ int register_stat2( char *module, char *name, stat_var **pvar, for( it=shash[hash] ; it ; it=stat->hnext ) { if ( (it->name.len==stat->name.len) && (strncasecmp( it->name.s, stat->name.s, stat->name.len)==0) ) { - /* duplicate found -> drop current stat and return the + /* duplicate found -> drop current stat and return the * found one */ lock_stop_write((rw_lock_t *)collector->rwl); - if (flags&STAT_SHM_NAME) shm_free(stat->name.s); - if ((flags&STAT_IS_FUNC)==0) shm_free(stat->u.val); - shm_free(stat); + + if (unsafe) { + if (flags&STAT_SHM_NAME) + shm_free_unsafe(stat->name.s); + + if ((flags&STAT_IS_FUNC)==0) + shm_free_unsafe(stat->u.val); + + shm_free_unsafe(stat); + + } else { + if (flags&STAT_SHM_NAME) + shm_free(stat->name.s); + + if ((flags&STAT_IS_FUNC)==0) + shm_free(stat->u.val); + + shm_free(stat); + } + *pvar = it; return 0; } @@ -542,15 +594,24 @@ int register_stat2( char *module, char *name, stat_var **pvar, lock_stop_write((rw_lock_t *)collector->rwl); return 0; + error2: if ( (flags&STAT_IS_FUNC)==0 ) { - shm_free(*pvar); + if (unsafe) + shm_free_unsafe(*pvar); + else + shm_free(*pvar); *pvar = 0; } error1: - shm_free(stat); + if (unsafe) + shm_free_unsafe(stat); + else + shm_free(stat); error: - *pvar = 0; + if ( (flags&STAT_IS_FUNC)==0 ) + *pvar = 0; + return -1; } @@ -571,16 +632,14 @@ int register_dynamic_stat( str *name, stat_var **pvar) memcpy( p, name->s, name->len); p[name->len] = 0; - ret = register_stat2( DYNAMIC_MODULE_NAME, p, pvar, - 0/*flags*/, NULL/*ctx*/); + ret = register_stat( DYNAMIC_MODULE_NAME, p, pvar, 0/*flags*/); pkg_free(p); return ret; } - -int register_module_stats(char *module, stat_export_t *stats) +int __register_module_stats(char *module, stat_export_t *stats, int unsafe) { int ret; @@ -588,8 +647,8 @@ int register_module_stats(char *module, stat_export_t *stats) return 0; for( ; stats->name ; stats++) { - ret = register_stat( module, stats->name, stats->stat_pointer, - stats->flags); + ret = register_stat2( module, stats->name, stats->stat_pointer, + stats->flags, NULL, unsafe); if (ret!=0) { LM_CRIT("failed to add statistic\n"); return -1; @@ -632,29 +691,88 @@ stat_var* get_stat( str *name ) return 0; } +int mi_stat_name(str *mod, str *stat, str *out) +{ + static str tmp_buf = {0, 0}; + char *tmp; + + if (mod) { + tmp = pkg_realloc(tmp_buf.s, mod->len + stat->len + 1); + if (!tmp) { + LM_ERR("no more pkg memory\n"); + return -1; + } + tmp_buf.s = tmp; + + memcpy(tmp_buf.s, mod->s, mod->len); + tmp_buf.len = mod->len; + tmp_buf.s[tmp_buf.len++] = ':'; + + memcpy(tmp_buf.s + tmp_buf.len, stat->s, stat->len); + tmp_buf.len += stat->len; + + out->len = tmp_buf.len; + out->s = tmp_buf.s; + } else { + out->len = stat->len; + out->s = stat->s; + } + return 0; +} + +int mi_print_stat(struct mi_node *rpl, str *mod, str *stat, unsigned long val) +{ + str tmp_buf; + + if (mi_stat_name(mod, stat, &tmp_buf) < 0) { + LM_ERR("cannot get stat name\n"); + return -1; + } + + if (!addf_mi_node_child(rpl, MI_DUP_NAME, tmp_buf.s, tmp_buf.len, "%lu", val)) { + LM_ERR("cannot add stat\n"); + return -1; + } + return 0; +} + /***************************** MI STUFF ********************************/ inline static int mi_add_stat(struct mi_node *rpl, stat_var *stat) { - struct mi_node *node; + return mi_print_stat(rpl, &collector->amodules[stat->mod_idx].name, + &stat->name, get_stat_val(stat)); +} - node = addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu", - collector->amodules[stat->mod_idx].name.len, - collector->amodules[stat->mod_idx].name.s, - stat->name.len, stat->name.s, - get_stat_val(stat) ); +inline static int mi_list_stat(struct mi_node *rpl, str *mod, stat_var *stat) +{ + str tmp_buf; + char *buf; - if (node==0) + if (mi_stat_name(mod, &stat->name, &tmp_buf) < 0) { + LM_ERR("cannot get stat name\n"); return -1; + } + + if (stat->flags & STAT_IS_FUNC) + buf = "function"; + if (stat->flags & STAT_NO_RESET) + buf = "non-incremental"; + else + buf = "incremental"; + + if (!addf_mi_node_child(rpl, MI_DUP_NAME, tmp_buf.s, tmp_buf.len, "%s", buf)) { + LM_ERR("cannot add stat\n"); + return -1; + } return 0; } inline static int mi_add_module_stats(struct mi_node *rpl, module_stats *mods) { - struct mi_node *node; stat_var *stat; int ret = 0; @@ -662,14 +780,31 @@ inline static int mi_add_module_stats(struct mi_node *rpl, lock_start_read((rw_lock_t *)collector->rwl); for( stat=mods->head ; stat ; stat=stat->lnext) { - node = addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu", - mods->name.len, mods->name.s, - stat->name.len, stat->name.s, - get_stat_val(stat) ); - if (node==0) { - ret = -1; + ret = mi_print_stat(rpl, &mods->name, &stat->name, + get_stat_val(stat)); + if (ret < 0) + break; + } + + if (mods->is_dyn) + lock_stop_read((rw_lock_t *)collector->rwl); + + return ret; +} + +inline static int mi_list_module_stats(struct mi_node *rpl, + module_stats *mods) +{ + stat_var *stat; + int ret = 0; + + if (mods->is_dyn) + lock_start_read((rw_lock_t *)collector->rwl); + + for( stat=mods->head ; stat ; stat=stat->lnext) { + ret = mi_list_stat(rpl, &mods->name, stat); + if (ret < 0) break; - } } if (mods->is_dyn) @@ -739,6 +874,62 @@ static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param) } +static struct mi_root *mi_list_stats(struct mi_root *cmd, void *param) +{ + struct mi_root *rpl_tree; + struct mi_node *rpl; + struct mi_node *arg; + module_stats *mods; + stat_var *stat; + str val; + int i; + + rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); + if (rpl_tree==0) + return 0; + rpl = &rpl_tree->node; + + if (cmd->node.kids == NULL) { + for( i=0 ; imod_no ;i++ ) { + if (mi_list_module_stats( rpl, &collector->amodules[i] )!=0) + goto error; + } + } else { + for( arg=cmd->node.kids ; arg ; arg=arg->next) { + if (arg->value.len==0) + continue; + val = arg->value; + if ( val.len>1 && val.s[val.len-1]==':') { + /* add module statistics */ + val.len--; + mods = get_stat_module( &val ); + if (mods==0) + continue; + if (mi_list_module_stats( rpl, mods )!=0) + goto error; + } else { + /* add only one statistic */ + stat = get_stat( &val ); + if (stat==0) + continue; + if (mi_list_stat(rpl,NULL, stat)!=0) + goto error; + } + } + } + + if (rpl->kids==0) { + free_mi_tree(rpl_tree); + return init_mi_tree( 404, "Statistics Not Found", 20); + } + + return rpl_tree; +error: + free_mi_tree(rpl_tree); + return 0; +} + + static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param) { diff --git a/statistics.h b/statistics.h index b975f7f51bb..e23e4811c99 100644 --- a/statistics.h +++ b/statistics.h @@ -103,6 +103,7 @@ typedef struct stat_export_ { char *build_stat_name( str* prefix, char *var_name); int init_stats_collector(); +int stats_are_ready(); /* for code which is statistics-dependent */ int register_udp_load_stat(str *name, stat_var **ctx, int children); int register_tcp_load_stat(stat_var **ctx); @@ -110,14 +111,17 @@ int register_tcp_load_stat(stat_var **ctx); void destroy_stats_collector(); #define register_stat(_mod,_name,_pvar,_flags) \ - register_stat2(_mod,_name,_pvar,_flags, 0) + register_stat2(_mod,_name,_pvar,_flags, NULL, 0) -int register_stat2( char *module, char *name, stat_var **pvar, - unsigned short flags, void* context); +int register_stat2( char *module, char *name, stat_var **pvar, + unsigned short flags, void* context, int unsafe); int register_dynamic_stat( str *name, stat_var **pvar); -int register_module_stats(char *module, stat_export_t *stats); +#define register_module_stats(mod, stats) \ + __register_module_stats(mod, stats, 0) + +int __register_module_stats(char *module, stat_export_t *stats, int unsafe); int clone_pv_stat_name(str *name, str *clone); @@ -129,10 +133,10 @@ unsigned int get_stat_val( stat_var *var ); * Returns the statistic associated with 'numerical_code' and 'is_a_reply'. * Specifically: * - * - if in_codes is nonzero, then the stat_var for the number of messages + * - if in_codes is nonzero, then the stat_var for the number of messages * _received_ with the 'numerical_code' will be returned if it exists. - * - otherwise, the stat_var for the number of messages _sent_ with the - * 'numerical_code' will be returned, if the stat exists. + * - otherwise, the stat_var for the number of messages _sent_ with the + * 'numerical_code' will be returned, if the stat exists. */ stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int in_codes); @@ -146,6 +150,7 @@ extern gen_lock_t *stat_lock; #define init_stats_collector() 0 #define destroy_stats_collector() #define register_module_stats(_mod,_stats) 0 + #define __register_module_stats(_mod,_stats, unsafe) 0 #define register_stat( _mod, _name, _pvar, _flags) 0 #define register_dynamic_stat( _name, _pvar) 0 #define get_stat( _name ) 0 @@ -153,6 +158,7 @@ extern gen_lock_t *stat_lock; #define get_stat_var_from_num_code( _n_code, _in_code) NULL #define register_udp_load_stat( _a, _b, _c) 0 #define register_tcp_load_stat( _a) 0 + #define stats_are_ready() 0 #define clone_pv_stat_name( _name, _clone) 0 #endif diff --git a/str.h b/str.h index 23836e95ea6..f7077a950f3 100644 --- a/str.h +++ b/str.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/strcommon.c b/strcommon.c index 03d86ca3fbf..48c9b5112ab 100644 --- a/strcommon.c +++ b/strcommon.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * @@ -220,7 +220,7 @@ int unescape_user(str *sin, str *sout) *at = 0; sout->len = at - sout->s; - + LM_DBG("unescaped string is <%s>\n", sout->s); return 0; } diff --git a/strcommon.h b/strcommon.h index 6e69de16e4e..1d64f75e03b 100644 --- a/strcommon.h +++ b/strcommon.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ diff --git a/tags.h b/tags.h index b1952bddcdd..a31ddf0c5b2 100644 --- a/tags.h +++ b/tags.h @@ -15,20 +15,20 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * + * * - utility for generating to-tags * in SER, to-tags consist of two parts: a fixed part * which is bound to server instance and variable part * which is bound to request -- that helps to recognize, * who generated the to-tag in loops through the same * server -- in such cases, fixed part is constant, but - * the variable part varies because it depends on + * the variable part varies because it depends on * the via header - * + * * History: * -------- * 2003-02-18 changed TOTAG_LEN into TOTAG_VALUE_LEN, to solve @@ -52,7 +52,7 @@ #define TOTAG_VALUE_LEN (MD5_LEN+CRC16_LEN+1) -/*! \brief +/*! \brief * Generate variable part of to-tag for a request; * it will have length of CRC16_LEN, sufficiently * long buffer must be passed to the function */ @@ -70,12 +70,12 @@ static inline void calc_crc_suffix( struct sip_msg *msg, char *tag_suffix) crcitt_string_array( tag_suffix, suffix_source, ss_nr ); } -inline static void init_tags( char *tag, char **suffix, +inline static void init_tags( char *tag, char **suffix, char *signature, char separator ) { str src[3]; struct socket_info* si; - + si=get_first_socket(); src[0].s=signature; src[0].len=strlen(signature); /* if we are not listening on anything we shouldn't be here */ diff --git a/tcp_conn.h b/tcp_conn.h index 0e68d062ff9..456e8d02d65 100644 --- a/tcp_conn.h +++ b/tcp_conn.h @@ -23,7 +23,7 @@ * History: * -------- * 2003-01-29 tcp buffer size ++-ed to allow for 0-terminator - * 2003-06-30 added tcp_connection flags & state (andrei) + * 2003-06-30 added tcp_connection flags & state (andrei) * 2003-10-27 tcp port aliases support added (andrei) * 2012-01-19 added TCP keepalive support */ @@ -50,15 +50,26 @@ #define DEFAULT_TCP_SEND_TIMEOUT 10 /*!< If a send can't write for more then 10s, timeout */ #define DEFAULT_TCP_CONNECT_TIMEOUT 10 /*!< If a connect doesn't complete in this time, timeout */ #define DEFAULT_TCP_MAX_CONNECTIONS 2048 /*!< Maximum number of connections */ -#define TCP_CHILD_TIMEOUT 5 /*!< After 5 seconds, the child "returns" +#define TCP_CHILD_TIMEOUT 5 /*!< After 5 seconds, the child "returns" the connection to the tcp master process */ #define TCP_MAIN_SELECT_TIMEOUT 5 /*!< how often "tcp main" checks for timeout*/ #define TCP_CHILD_SELECT_TIMEOUT 2 /*!< the same as above but for children */ +#define TCP_CHILD_MAX_MSG_CHUNK 4 /*!< the max number of chunks that a child accepts + until the message is read completely - anything + above will lead to the connection being closed - + considered an attack */ +#define TCP_CHILD_MAX_MSG_TIME 4 /*!< the max number of seconds that a child waits + until the message is read completely - anything + above will lead to the connection being closed - + considered an attack */ + /* tcp connection flags */ #define F_CONN_NON_BLOCKING 1 #define F_CONN_REMOVED 2 /*!< no longer in "main" listen fd list */ +#define F_CONN_NOT_CONNECTED 4 /*!< a connection in pending state, + waiting to be connected */ /* keepalive */ @@ -93,18 +104,18 @@ enum tcp_req_errors { TCP_REQ_INIT, TCP_REQ_OK, TCP_READ_ERROR, enum tcp_req_states { H_SKIP_EMPTY, H_SKIP, H_LF, H_LFCR, H_BODY, H_STARTWS, H_CONT_LEN1, H_CONT_LEN2, H_CONT_LEN3, H_CONT_LEN4, H_CONT_LEN5, H_CONT_LEN6, H_CONT_LEN7, H_CONT_LEN8, H_CONT_LEN9, H_CONT_LEN10, - H_CONT_LEN11, H_CONT_LEN12, H_CONT_LEN13, H_L_COLON, - H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE , H_PING_CRLFCRLF, + H_CONT_LEN11, H_CONT_LEN12, H_CONT_LEN13, H_L_COLON, + H_CONT_LEN_BODY, H_CONT_LEN_BODY_PARSE , H_PING_CRLFCRLF, H_SKIP_EMPTY_CR_FOUND, H_SKIP_EMPTY_CRLF_FOUND, H_SKIP_EMPTY_CRLFCR_FOUND }; -enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, +enum tcp_conn_states { S_CONN_ERROR=-2, S_CONN_BAD=-1, S_CONN_OK=0, S_CONN_INIT, S_CONN_EOF, S_CONN_ACCEPT, S_CONN_CONNECT }; /* fd communication commands */ -enum conn_cmds { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE, - CONN_GET_FD, CONN_NEW }; +enum conn_cmds { CONN_DESTROY=-3, CONN_ERROR=-2, CONN_EOF=-1, CONN_RELEASE, + CONN_GET_FD, CONN_NEW, ASYNC_CONNECT, ASYNC_WRITE }; /* CONN_RELEASE, EOF, ERROR, DESTROY can be used by "reader" processes * CONN_GET_FD, NEW, ERROR only by writers */ @@ -112,12 +123,12 @@ struct tcp_req{ struct tcp_req* next; /* sockaddr ? */ char buf[TCP_BUF_SIZE+1]; /*!< bytes read so far (+0-terminator)*/ - char* start; /*!< where the message starts, after all the empty lines are skipped*/ - char* pos; /*!< current position in buf */ - char* parsed; /*!< last parsed position */ - char* body; /*!< body position */ + char* start; /*!< where the message starts, after all the empty lines are skipped*/ + char* pos; /*!< current position in buf */ + char* parsed; /*!< last parsed position */ + char* body; /*!< body position */ unsigned int content_len; - unsigned short has_content_len; /*!< 1 if content_length was parsed ok*/ + unsigned short has_content_len; /*!< 1 if content_length was parsed ok*/ unsigned short complete; /*!< 1 if one req has been fully read, 0 otherwise*/ unsigned int bytes_to_go; /*!< how many bytes we have still to read from the body*/ enum tcp_req_errors error; @@ -138,6 +149,13 @@ struct tcp_conn_alias{ }; +struct tcp_send_chunk{ + char *buf; /* buffer that needs to be sent out */ + char *pos; /* the position that we should be writing next */ + int len; /* length of the buffer */ + int ticks; /* time at which this chunk was initially + attempted to be written */ +}; /*! \brief TCP connection structure */ struct tcp_connection{ @@ -146,7 +164,6 @@ struct tcp_connection{ gen_lock_t write_lock; int id; /*!< id (unique!) used to retrieve a specific connection when reply-ing*/ struct receive_info rcv; /*!< src & dst ip, ports, proto a.s.o*/ - struct tcp_req req; /*!< request data */ volatile int refcnt; enum sip_protos type; /*!< PROTO_TCP or a protocol over it, e.g. TLS */ int flags; /*!< connection related flags */ @@ -161,16 +178,24 @@ struct tcp_connection{ struct tcp_connection* c_prev; /*!< Child prev (use locally */ struct tcp_conn_alias con_aliases[TCP_CON_MAX_ALIASES]; /*!< Aliases for this connection */ int aliases; /*!< Number of aliases, at least 1 */ + struct tcp_req *con_req; /*!< Per connection req buffer */ + unsigned int msg_attempts; /*!< how many read attempts we have done for the last request */ + struct tcp_send_chunk **async_chunks; /*!< the chunks that need to be written on this + connection when it will become writable */ + int async_chunks_no; /* the total number of chunks pending to be written */ + int oldest_chunk; /* the oldest chunk in our write list */ }; #define init_tcp_req( r) \ do{ \ - memset( (r), 0, sizeof(struct tcp_req)); \ (r)->parsed=(r)->pos=(r)->start=(r)->buf; \ (r)->error=TCP_REQ_OK;\ (r)->state=H_SKIP_EMPTY; \ + (r)->body=0; \ + (r)->complete=(r)->content_len=(r)->has_content_len=0; \ + (r)->bytes_to_go=0; \ }while(0) @@ -194,17 +219,23 @@ struct tcp_connection{ if ((c)->prev) (c)->prev->next=(c)->next; \ }while(0) +#define TCPCONN_GET_PART(_id) (_id%TCP_PARTITION_SIZE) +#define TCP_PART(_id) (tcp_parts[TCPCONN_GET_PART(_id)]) -#define TCPCONN_LOCK lock_get(tcpconn_lock); -#define TCPCONN_UNLOCK lock_release(tcpconn_lock); +#define TCPCONN_LOCK(_id) \ + lock_get(tcp_parts[TCPCONN_GET_PART(_id)].tcpconn_lock); +#define TCPCONN_UNLOCK(_id) \ + lock_release(tcp_parts[TCPCONN_GET_PART(_id)].tcpconn_lock); #define TCP_ALIAS_HASH_SIZE 1024 #define TCP_ID_HASH_SIZE 1024 +#define TCP_PARTITION_SIZE 32 + static inline unsigned tcp_addr_hash(struct ip_addr* ip, unsigned short port) { if(ip->len==4) return (ip->u.addr32[0]^port)&(TCP_ALIAS_HASH_SIZE-1); - else if (ip->len==16) + else if (ip->len==16) return (ip->u.addr32[0]^ip->u.addr32[1]^ip->u.addr32[2]^ ip->u.addr32[3]^port) & (TCP_ALIAS_HASH_SIZE-1); else{ diff --git a/tcp_init.h b/tcp_init.h index 0ad0fbed19c..6cb6bb69fdb 100644 --- a/tcp_init.h +++ b/tcp_init.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/tcp_main.c b/tcp_main.c index dc80f4bbd80..33effc83a63 100644 --- a/tcp_main.c +++ b/tcp_main.c @@ -27,7 +27,7 @@ * 2003-02-20 s/lock_t/gen_lock_t/ to avoid a conflict on solaris (andrei) * 2003-02-25 Nagle is disabled if -DDISABLE_NAGLE (andrei) * 2003-03-29 SO_REUSEADDR before calling bind to allow - * server restart, Nagle set on the (hopefuly) + * server restart, Nagle set on the (hopefuly) * correct socket (jiri) * 2003-03-31 always try to find the corresponding tcp listen socket for * a temp. socket and store in in *->bind_address: added @@ -42,7 +42,7 @@ * does not inc refcnt by itself anymore (andrei) * 2003-11-07 different unix sockets are used for fd passing * to/from readers/writers (andrei) - * 2003-11-17 handle_new_connect & tcp_connect will close the + * 2003-11-17 handle_new_connect & tcp_connect will close the * new socket if tcpconn_new return 0 (e.g. out of mem) (andrei) * 2003-11-28 tcp_blocking_write & tcp_blocking_connect added (andrei) * 2004-11-08 dropped find_tcp_si and replaced with find_si (andrei) @@ -112,7 +112,7 @@ #include "daemonize.h" #ifdef USE_TLS #include "tls/tls_server.h" -#endif +#endif #define local_malloc pkg_malloc #define local_free pkg_free @@ -121,9 +121,9 @@ #include "io_wait.h" #include /* must be included after io_wait.h if SIGIO_RT is used */ +enum fd_types { F_NONE=0, F_SOCKINFO=1 /* a tcp_listen fd */, + F_TCPCONN=2, F_TCPCHILD=4, F_PROC=8}; -enum fd_types { F_NONE, F_SOCKINFO /* a tcp_listen fd */, - F_TCPCONN, F_TCPCHILD, F_PROC }; struct tcp_child { pid_t pid; @@ -154,14 +154,18 @@ int tcp_keepinterval = 0; static int tcp_connections_no=0; /*!< current number of open connections */ -/*! \brief connection hash table (after ip&port) , includes also aliases */ -struct tcp_conn_alias** tcpconn_aliases_hash=0; -/*! \brief connection hash table (after connection id) */ -struct tcp_connection** tcpconn_id_hash=0; -gen_lock_t* tcpconn_lock=0; +struct tcp_partition { + /*! \brief connection hash table (after ip&port), includes also aliases */ + struct tcp_conn_alias** tcpconn_aliases_hash; + /*! \brief connection hash table (after connection id) */ + struct tcp_connection** tcpconn_id_hash; + gen_lock_t* tcpconn_lock; +}; + +struct tcp_partition tcp_parts[TCP_PARTITION_SIZE]; struct tcp_child *tcp_children=0; -static int* connection_id=0; /*!< unique for each connection, used for +static int* connection_id=0; /*!< unique for each connection, used for quickly finding the corresponding connection for a reply */ int unix_tcp_sock = -1; @@ -196,7 +200,7 @@ static inline int init_sock_keepalive(int s) LM_WARN("init_sock_keepalive: failed to enable SO_KEEPALIVE: %s\n", strerror(errno)); return -1; } - LM_INFO("-- TCP keepalive enabled on socket"); + LM_INFO("-- TCP keepalive enabled on socket\n"); } #endif #ifdef HAVE_TCP_KEEPINTVL @@ -231,7 +235,7 @@ static int init_sock_opt(int s) { int flags; int optval; - + #ifdef DISABLE_NAGLE flags=1; if ( (tcp_proto_no!=-1) && (setsockopt(s, tcp_proto_no , TCP_NODELAY, @@ -272,11 +276,12 @@ static int init_sock_opt(int s) /*! \brief blocking connect on a non-blocking fd; it will timeout after - * tcp_connect_timeout + * tcp_connect_timeout * if BLOCKING_USE_SELECT and HAVE_SELECT are defined it will internally * use select() instead of poll (bad if fd > FD_SET_SIZE, poll is preferred) */ -static int tcp_blocking_connect(int fd, const struct sockaddr *servaddr, socklen_t addrlen) +static int tcp_blocking_connect(int fd, const struct sockaddr *servaddr, + socklen_t addrlen) { int n; #if defined(HAVE_SELECT) && defined(BLOCKING_USE_SELECT) @@ -294,7 +299,7 @@ static int tcp_blocking_connect(int fd, const struct sockaddr *servaddr, socklen int poll_err; char *ip; unsigned short port; - + poll_err=0; to=tcp_connect_timeout; ticks=get_ticks(); @@ -308,11 +313,11 @@ static int tcp_blocking_connect(int fd, const struct sockaddr *servaddr, socklen } if (errno!=EINPROGRESS && errno!=EALREADY){ get_su_info( servaddr, ip, port); - LM_ERR("[sever=%s:%d] (%d) %s\n",ip, port, errno, strerror(errno)); + LM_ERR("[server=%s:%d] (%d) %s\n",ip, port, errno, strerror(errno)); goto error; } }else goto end; - + /* poll/select loop */ #if defined(HAVE_SELECT) && defined(BLOCKING_USE_SELECT) FD_ZERO(&orig_set); @@ -325,7 +330,7 @@ static int tcp_blocking_connect(int fd, const struct sockaddr *servaddr, socklen elapsed=(get_ticks()-ticks)*TIMER_TICK; if (elapsedrcv.src_su=*su; - + c->refcnt=0; su2ip_addr(&c->rcv.src_ip, su); c->rcv.src_port=su_getport(su); @@ -473,7 +479,6 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, } print_ip("tcpconn_new: new tcp connection to: ", &c->rcv.src_ip, "\n"); LM_DBG("on port %d, type %d\n", c->rcv.src_port, type); - init_tcp_req(&c->req); c->id=(*connection_id)++; c->rcv.proto_reserved1=0; /* this will be filled before receive_message*/ c->rcv.proto_reserved2=0; @@ -490,16 +495,251 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, c->timeout=get_ticks()+tcp_con_lifetime; } c->flags|=F_CONN_REMOVED; - + + if (tcp_async) { + c->async_chunks = shm_malloc(sizeof(struct tcp_send_chunk *) * + tcp_async_max_postponed_chunks); + if (c->async_chunks == NULL) { + LM_ERR("No more SHM for send chunks pointers \n"); + goto error; + } + } + tcp_connections_no++; return c; - + error: if (c) shm_free(c); return 0; } +/* returns : + * 0 - in case of success + * -1 - in case there was an internal error + * -2 - in case our chunks buffer is full + * and we need to let the connection go + */ +static inline int add_write_chunk(struct tcp_connection *con,char *buf,int len, + int lock) +{ + struct tcp_send_chunk *c; + + c = shm_malloc(sizeof(struct tcp_send_chunk) + len); + if (!c) { + LM_ERR("No more SHM\n"); + return -1; + } + + c->len = len; + c->ticks = get_ticks(); + c->buf = (char *)(c+1); + memcpy(c->buf,buf,len); + c->pos = c->buf; + + if (lock) + lock_get(&con->write_lock); + + if (con->async_chunks_no == tcp_async_max_postponed_chunks) { + LM_ERR("We have reached the limit of max async postponed chunks\n"); + if (lock) + lock_release(&con->write_lock); + shm_free(c); + return -2; + } + + con->async_chunks[con->async_chunks_no++] = c; + if (con->async_chunks_no == 1) + con->oldest_chunk = c->ticks; + + if (lock) + lock_release(&con->write_lock); + + return 0; +} + +#define ASYNC_TCP_CONN ((struct tcp_connection *)-1) +#define ASYNC_TCP_CONN_ERR ((struct tcp_connection *)-2) + +static inline struct tcp_connection * async_connect_or_pass(int fd, + union sockaddr_union *server,socklen_t addrlen, + struct socket_info *send_sock,char *buf, int len, + int type,unsigned int max_us) +{ + int n; +#if defined(HAVE_SELECT) && defined(BLOCKING_USE_SELECT) + fd_set sel_set; + fd_set orig_set; + struct timeval timeout; +#else + struct pollfd pf; +#endif + unsigned int elapsed,to; + int err; + unsigned int err_len; + int poll_err; + char *ip; + unsigned short port; + struct timeval begin; + struct tcp_connection* con=NULL; + long response[2]; + + poll_err=0; + elapsed = 0; + to = max_us; + + if (gettimeofday(&(begin), NULL)) { + LM_ERR("Failed to get TCP connect start time\n"); + goto pass_to_main; + } + +again: + n=connect(fd, &server->s, addrlen); + if (n==-1) { + if (errno==EINTR){ + elapsed=get_time_diff(&begin); + if (elapseds, ip, port); + LM_ERR("[server=%s:%d] (%d) %s\n",ip, port, errno, strerror(errno)); + goto error; + } + } else goto local_success; + + /* let's poll for a little */ +#if defined(HAVE_SELECT) && defined(BLOCKING_USE_SELECT) + FD_ZERO(&orig_set); + FD_SET(fd, &orig_set); +#else + pf.fd=fd; + pf.events=POLLOUT; +#endif + + while(1){ + elapsed=get_time_diff(&begin); + if (elapseds, ip, port); + LM_ERR("poll/select failed:[server=%s:%d] (%d) %s\n", + ip, port, errno, strerror(errno)); + goto error; + }else if (n==0) /* timeout */ continue; +#if defined(HAVE_SELECT) && defined(BLOCKING_USE_SELECT) + if (FD_ISSET(fd, &sel_set)) +#else + if (pf.revents&(POLLERR|POLLHUP|POLLNVAL)){ + LM_ERR("poll error: flags %x\n", pf.revents); + poll_err=1; + } +#endif + { + err_len=sizeof(err); + getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_len); + if ((err==0) && (poll_err==0)) goto local_success; + if (err!=EINPROGRESS && err!=EALREADY){ + get_su_info(&server->s, ip, port); + LM_ERR("failed to retrieve SO_ERROR [server=%s:%d] (%d) %s\n", + ip, port, err, strerror(err)); + goto error; + } + } + } + +pass_to_main: + LM_DBG("Should now pass the socket to TCP main \n"); + /* create a new dummy connection */ + con=tcpconn_new(fd, server, send_sock, type, S_CONN_INIT); + if (con == 0) { + LM_ERR("tcpconn_new failed, closing the socket\n"); + goto error; + } + if (add_write_chunk(con,buf,len,0) < 0) { + LM_ERR("Failed to add the initial write chunk\n"); + /* FIXME - seems no more SHM now ... + * continue the async connect process ? */ + } + + response[0]=(long)con; + response[1]=ASYNC_CONNECT; + n=send_fd(unix_tcp_sock, response, sizeof(response), con->s); + if (n<=0) { + LM_ERR("Failed to send the socket to main for async connection \n"); + goto error; + } + return ASYNC_TCP_CONN; +local_success: + con=tcpconn_new(fd, server, send_sock, type, S_CONN_CONNECT); + if (con == 0) { + LM_ERR("tcpconn_new failed, closing the socket\n"); + goto error; + } + return con; +error: + if (con) + shm_free(con); + return ASYNC_TCP_CONN_ERR; +} + +struct tcp_connection* tcpconn_async_connect(struct socket_info* send_sock, + union sockaddr_union* server, int type,char *buf, unsigned len, + unsigned int max_us) +{ + int s; + union sockaddr_union my_name; + socklen_t my_name_len; + struct tcp_connection* con; + + s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0); + if (s==-1){ + LM_ERR("socket: (%d) %s\n", errno, strerror(errno)); + return ASYNC_TCP_CONN_ERR; + } + if (init_sock_opt(s)<0){ + LM_ERR("init_sock_opt failed\n"); + close(s); + return ASYNC_TCP_CONN_ERR; + } + my_name_len = sockaddru_len(send_sock->su); + memcpy( &my_name, &send_sock->su, my_name_len); + su_setport( &my_name, 0); + if (bind(s, &my_name.s, my_name_len )!=0) { + LM_ERR("bind failed (%d) %s\n", errno,strerror(errno)); + close(s); + return ASYNC_TCP_CONN_ERR; + } + con = async_connect_or_pass(s,server,sockaddru_len(*server),send_sock, + buf,len,type,max_us); + if (con == ASYNC_TCP_CONN_ERR) { + /* internal error */ + LM_ERR("Internal error encountered when connecting\n"); + close(s); + return con; + } else { + /* either we connected on our own - or we failed to connect + * but we succesfully passed socket to main */ + return con; + } +} struct tcp_connection* tcpconn_connect(struct socket_info* send_sock, union sockaddr_union* server, int type) @@ -549,21 +789,21 @@ struct tcp_connection* tcpconn_add(struct tcp_connection *c) unsigned hash; if (c){ - TCPCONN_LOCK; + TCPCONN_LOCK(c->id); /* add it at the begining of the list*/ hash=tcp_id_hash(c->id); c->id_hash=hash; - tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev); - + tcpconn_listadd(TCP_PART(c->id).tcpconn_id_hash[hash], c, id_next, id_prev); + hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port); /* set the first alias */ c->con_aliases[0].port=c->rcv.src_port; c->con_aliases[0].hash=hash; c->con_aliases[0].parent=c; - tcpconn_listadd(tcpconn_aliases_hash[hash], &c->con_aliases[0], + tcpconn_listadd(TCP_PART(c->id).tcpconn_aliases_hash[hash], &c->con_aliases[0], next, prev); c->aliases++; - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(c->id); LM_DBG("hashes: %d, %d\n", hash, c->id_hash); return c; }else{ @@ -577,15 +817,22 @@ struct tcp_connection* tcpconn_add(struct tcp_connection *c) void _tcpconn_rm(struct tcp_connection* c) { int r; - tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev); + + tcpconn_listrm(TCP_PART(c->id).tcpconn_id_hash[c->id_hash], c, + id_next, id_prev); /* remove all the aliases */ for (r=0; raliases; r++) - tcpconn_listrm(tcpconn_aliases_hash[c->con_aliases[r].hash], - &c->con_aliases[r], next, prev); + tcpconn_listrm(TCP_PART(c->id).tcpconn_aliases_hash[c->con_aliases[r].hash], + &c->con_aliases[r], next, prev); lock_destroy(&c->write_lock); #ifdef USE_TLS if (c->type==PROTO_TLS) tls_tcpconn_clean(c); #endif + + for (r=0;rasync_chunks_no;r++) { + shm_free(c->async_chunks[r]); + } + shm_free(c); } @@ -594,13 +841,14 @@ void _tcpconn_rm(struct tcp_connection* c) void tcpconn_rm(struct tcp_connection* c) { int r; - TCPCONN_LOCK; - tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev); + TCPCONN_LOCK(c->id); + tcpconn_listrm(TCP_PART(c->id).tcpconn_id_hash[c->id_hash], c, + id_next, id_prev); /* remove all the aliases */ for (r=0; raliases; r++) - tcpconn_listrm(tcpconn_aliases_hash[c->con_aliases[r].hash], - &c->con_aliases[r], next, prev); - TCPCONN_UNLOCK; + tcpconn_listrm(TCP_PART(c->id).tcpconn_aliases_hash[c->con_aliases[r].hash], + &c->con_aliases[r], next, prev); + TCPCONN_UNLOCK(c->id); lock_destroy(&c->write_lock); #ifdef USE_TLS if ((c->type==PROTO_TLS)&&(c->extra_data)) tls_tcpconn_clean(c); @@ -609,41 +857,24 @@ void tcpconn_rm(struct tcp_connection* c) } -/*! \brief finds a connection, if id=0 uses the ip addr & port (host byte order) +/*! \brief finds a connection, if id=0 return NULL * \note WARNING: unprotected (locks) use tcpconn_get unless you really * know what you are doing */ -struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port) +static struct tcp_connection* _tcpconn_find(int id) { struct tcp_connection *c; - struct tcp_conn_alias* a; unsigned hash; - -#ifdef EXTRA_DEBUG - LM_DBG("%d port %d\n",id, port); - if (ip) print_ip("tcpconn_find: ip ", ip, "\n"); -#endif + if (id){ hash=tcp_id_hash(id); - for (c=tcpconn_id_hash[hash]; c; c=c->id_next){ + for (c=TCP_PART(id).tcpconn_id_hash[hash]; c; c=c->id_next){ #ifdef EXTRA_DEBUG LM_DBG("c=%p, c->id=%d, port=%d\n",c, c->id, c->rcv.src_port); print_ip("ip=", &c->rcv.src_ip, "\n"); #endif if ((id==c->id)&&(c->state!=S_CONN_BAD)) return c; } - }else if (ip){ - hash=tcp_addr_hash(ip, port); - for (a=tcpconn_aliases_hash[hash]; a; a=a->next){ -#ifdef EXTRA_DEBUG - LM_DBG("a=%p, c=%p, c->id=%d, alias port= %d port=%d\n", - a, a->parent, a->parent->id, a->port, a->parent->rcv.src_port); - print_ip("ip=",&a->parent->rcv.src_ip,"\n"); -#endif - if ( (a->parent->state!=S_CONN_BAD) && (port==a->port) && - (ip_addr_cmp(ip, &a->parent->rcv.src_ip)) ) - return a->parent; - } } return 0; } @@ -655,14 +886,50 @@ struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, int timeout) { struct tcp_connection* c; - TCPCONN_LOCK; - c=_tcpconn_find(id, ip, port); - if (c) { - c->refcnt++; - c->timeout=get_ticks()+timeout; + struct tcp_conn_alias* a; + unsigned hash; + int part; + + if (id) { + part = id; + TCPCONN_LOCK(part); + if ( (c=_tcpconn_find(part))!=NULL ) + goto found; + TCPCONN_UNLOCK(part); } - TCPCONN_UNLOCK; + + /* continue search based on IP + port */ +#ifdef EXTRA_DEBUG + LM_DBG("%d port %d\n",id, port); + if (ip) print_ip("tcpconn_find: ip ", ip, "\n"); +#endif + if (ip){ + hash=tcp_addr_hash(ip, port); + for( part=0 ; partnext) { +#ifdef EXTRA_DEBUG + LM_DBG("a=%p, c=%p, c->id=%d, alias port= %d port=%d\n", + a, a->parent, a->parent->id, a->port, a->parent->rcv.src_port); + print_ip("ip=",&a->parent->rcv.src_ip,"\n"); +#endif + c = a->parent; + if ( (c->state!=S_CONN_BAD) && (port==a->port) && + (ip_addr_cmp(ip, &c->rcv.src_ip)) ) + goto found; + } + TCPCONN_UNLOCK(part); + } + } + + return NULL; + +found: + c->refcnt++; + c->timeout=get_ticks()+timeout; + TCPCONN_UNLOCK(part); return c; + } @@ -674,17 +941,17 @@ int tcpconn_add_alias(int id, int port, int proto) struct tcp_connection* c; unsigned hash; struct tcp_conn_alias* a; - + a=0; /* fix the port */ port=port?port:((proto==PROTO_TLS)?SIPS_PORT:SIP_PORT); - TCPCONN_LOCK; + TCPCONN_LOCK(id); /* check if alias already exists */ - c=_tcpconn_find(id, 0, 0); + c=_tcpconn_find(id); if (c){ hash=tcp_addr_hash(&c->rcv.src_ip, port); /* search the aliases for an already existing one */ - for (a=tcpconn_aliases_hash[hash]; a; a=a->next){ + for (a=TCP_PART(id).tcpconn_aliases_hash[hash]; a; a=a->next){ if ( (a->parent->state!=S_CONN_BAD) && (port==a->port) && (ip_addr_cmp(&c->rcv.src_ip, &a->parent->rcv.src_ip)) ){ /* found */ @@ -696,27 +963,27 @@ int tcpconn_add_alias(int id, int port, int proto) c->con_aliases[c->aliases].parent=c; c->con_aliases[c->aliases].port=port; c->con_aliases[c->aliases].hash=hash; - tcpconn_listadd(tcpconn_aliases_hash[hash], + tcpconn_listadd(TCP_PART(id).tcpconn_aliases_hash[hash], &c->con_aliases[c->aliases], next, prev); c->aliases++; }else goto error_not_found; ok: - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(id); #ifdef EXTRA_DEBUG if (a) LM_DBG("alias already present\n"); else LM_DBG("alias port %d for hash %d, id %d\n", port, hash, c->id); #endif return 0; error_aliases: - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(id); LM_ERR("too many aliases for connection %p (%d)\n", c, c->id); return -1; error_not_found: - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(id); LM_ERR("no connection found for id %d\n",id); return -1; error_sec: - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(id); LM_ERR("possible port hijack attempt\n"); LM_ERR("alias already present and points to another connection " "(%d : %d and %d : %d)\n", a->parent->id, port, c->id, port); @@ -727,21 +994,100 @@ int tcpconn_add_alias(int id, int port, int proto) void tcpconn_ref(struct tcp_connection* c) { - TCPCONN_LOCK; + TCPCONN_LOCK(c->id); c->refcnt++; /* FIXME: atomic_dec */ - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(c->id); } void tcpconn_put(struct tcp_connection* c) { - TCPCONN_LOCK; + TCPCONN_LOCK(c->id); c->refcnt--; /* FIXME: atomic_dec */ - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(c->id); } +/* called under the TCP connection write lock */ +int async_tsend_stream(struct tcp_connection *c, + int fd, char* buf, unsigned int len, int timeout) +{ + int written; + int n; + struct pollfd pf; + long response[2]; + + pf.fd=fd; + pf.events=POLLOUT; + written=0; + +again: + n=send(fd, buf, len, +#ifdef HAVE_MSG_NOSIGNAL + MSG_NOSIGNAL +#else + 0 +#endif + ); + + if (n<0){ + if (errno==EINTR) goto again; + else if (errno!=EAGAIN && errno!=EWOULDBLOCK) { + LM_ERR("Failed first TCP async send : (%d) %s\n", + errno, strerror(errno)); + return -1; + } else + goto poll_loop; + } + written+=n; + if (nrefcnt++; /* safe to do it w/o locking, it's not yet available to the rest of the world */ fd=c->s; - + /* send the new tcpconn to "tcp main" */ response[0]=(long)c; response[1]=CONN_NEW; @@ -811,10 +1179,46 @@ int tcp_send(struct socket_info* send_sock, int type, char* buf, unsigned len, LM_ERR("failed send_fd: %s (%d)\n", strerror(errno), errno); n=-1; goto end; - } + } goto send_it; } get_fd: + if (c->flags & F_CONN_NOT_CONNECTED) { + /* the connection is currently in the process of getting + * connected - let's append our send chunk as well - just in + * case we ever manage to get through */ + LM_DBG("We have acquired a TCP connection which is still pending to connect - delaying write \n"); + n = add_write_chunk(c,buf,len,1); + if (n < 0) { + LM_ERR("Failed to add another write chunk to %p\n",c); + if (n == -2) { + /* write chunk buffer reached max - close this + * connection now */ + tcpconn_put(c); + c->state=S_CONN_BAD; + c->timeout=0; + /* tell "main" it should drop this */ + response[0]=(long)c; + response[1]=CONN_ERROR; + n=send_all(unix_tcp_sock, response, sizeof(response)); + if (n<=0){ + LM_ERR("return failed (write):%s (%d)\n", + strerror(errno), errno); + } + return -1; + } else { + /* we failed due to internal errors - put the + * connection back */ + tcpconn_put(c); + return -1; + } + } + + /* we succesfully added our write chunk - success */ + tcpconn_put(c); + return len; + } + get_time_difference(get,tcpthreshold,tcp_timeout_con_get); /* todo: see if this is not the same process holding * c and if so send directly on c->fd */ @@ -825,7 +1229,7 @@ int tcp_send(struct socket_info* send_sock, int type, char* buf, unsigned len, start_expire_timer(rcv,tcpthreshold); n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ - LM_ERR("failed to get fd(write):%s (%d)\n", + LM_ERR("failed to get fd(write):%s (%d)\n", strerror(errno), errno); n=-1; get_time_difference(rcv,tcpthreshold,tcp_timeout_receive_fd); @@ -852,9 +1256,9 @@ int tcp_send(struct socket_info* send_sock, int type, char* buf, unsigned len, goto end; } LM_DBG("after receive_fd: c= %p n=%d fd=%d\n",c, n, fd); - - - + + + send_it: LM_DBG("sending...\n"); lock_get(&c->write_lock); @@ -866,9 +1270,13 @@ int tcp_send(struct socket_info* send_sock, int type, char* buf, unsigned len, { /* n=tcp_blocking_write(c, fd, buf, len); */ start_expire_timer(snd,tcpthreshold); - n=tsend_stream(fd, buf, len, tcp_send_timeout*1000); + if (tcp_async) { + n=async_tsend_stream(c,fd,buf,len,tcp_async_local_write_timeout); + } else { + n=tsend_stream(fd, buf, len, tcp_send_timeout*1000); get_time_difference(snd,tcpthreshold,tcp_timeout_send); stop_expire_timer(get,tcpthreshold,"tcp ops",buf,(int)len,1); + } } lock_release(&c->write_lock); LM_DBG("after write: c= %p n=%d fd=%d\n",c, n, fd); @@ -917,7 +1325,7 @@ int tcp_init(struct socket_info* sock_info) } } #endif - + addr=&sock_info->su; /* sock_info->proto=PROTO_TCP; */ if (init_su(addr, &sock_info->address, sock_info->port_no)<0){ @@ -939,11 +1347,11 @@ int tcp_init(struct socket_info* sock_info) #endif -#if !defined(TCP_DONT_REUSEADDR) +#if !defined(TCP_DONT_REUSEADDR) /* Stevens, "Network Programming", Section 7.5, "Generic Socket * Options": "...server started,..a child continues..on existing * connection..listening server is restarted...call to bind fails - * ... ALL TCP servers should specify the SO_REUSEADDRE option + * ... ALL TCP servers should specify the SO_REUSEADDRE option * to allow the server to be restarted in this situation * * Indeed, without this option, the server can't restart. @@ -958,7 +1366,7 @@ int tcp_init(struct socket_info* sock_info) #endif /* tos */ optval = tos; - if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, + if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, sizeof(optval)) ==-1){ LM_WARN("setsockopt tos: %s\n", strerror(errno)); /* continue since this is not critical */ @@ -974,7 +1382,7 @@ int tcp_init(struct socket_info* sock_info) init_sock_keepalive(sock_info->socket); if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){ LM_ERR("bind(%x, %p, %d) on %s:%d : %s\n", - sock_info->socket, &addr->s, + sock_info->socket, &addr->s, (unsigned)sockaddru_len(*addr), sock_info->address_str.s, sock_info->port_no, @@ -983,13 +1391,13 @@ int tcp_init(struct socket_info* sock_info) } if (listen(sock_info->socket, tcp_listen_backlog)==-1){ LM_ERR("listen(%x, %p, %d) on %s: %s\n", - sock_info->socket, &addr->s, + sock_info->socket, &addr->s, (unsigned)sockaddru_len(*addr), sock_info->address_str.s, strerror(errno)); goto error; } - + return 0; error: if (sock_info->socket!=-1){ @@ -1001,12 +1409,13 @@ int tcp_init(struct socket_info* sock_info) -static int send2child(struct tcp_connection* tcpconn) +static int send2child(struct tcp_connection* tcpconn,int rw) { int i; int min_busy; int idx; - + long response[2]; + min_busy=tcp_children[0].busy; idx=0; for (i=0; is)<=0){ LM_ERR("send_fd failed\n"); return -1; } - + return 0; } @@ -1052,7 +1463,8 @@ static inline int handle_new_connect(struct socket_info* si) struct tcp_connection* tcpconn; socklen_t su_len; int new_sock; - + int id; + /* got a connection on r */ su_len=sizeof(su); new_sock=accept(si->socket, &(su.s), &su_len); @@ -1073,30 +1485,31 @@ static inline int handle_new_connect(struct socket_info* si) close(new_sock); return 1; /* success, because the accept was succesfull */ } - + /* add socket to list */ tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT); if (tcpconn){ tcpconn->refcnt++; /* safe, not yet available to the outside world */ tcpconn_add(tcpconn); - LM_DBG("new connection: %p %d flags: %04x\n", + LM_DBG("new connection: %p %d flags: %04x\n", tcpconn, tcpconn->s, tcpconn->flags); /* pass it to a child */ - if(send2child(tcpconn)<0){ + if(send2child(tcpconn,IO_WATCH_READ)<0){ LM_ERR("no children available\n"); - TCPCONN_LOCK; + id = tcpconn->id; + TCPCONN_LOCK(id); tcpconn->refcnt--; if (tcpconn->refcnt==0){ close(tcpconn->s); _tcpconn_rm(tcpconn); }else tcpconn->timeout=0; /* force expire */ - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(id); } }else{ /*tcpconn==0 */ LM_ERR("tcpconn_new failed, closing socket\n"); close(new_sock); - + } return 1; /* accept() was succesfull */ } @@ -1107,10 +1520,11 @@ static inline int handle_new_connect(struct socket_info* si) static void tcpconn_destroy(struct tcp_connection* tcpconn) { int fd; + int id = tcpconn->id; - TCPCONN_LOCK; /*avoid races w/ tcp_send*/ + TCPCONN_LOCK(id); /*avoid races w/ tcp_send*/ tcpconn->refcnt--; - if (tcpconn->refcnt==0){ + if (tcpconn->refcnt==0){ LM_DBG("destroying connection %p, flags %04x\n", tcpconn, tcpconn->flags); fd=tcpconn->s; @@ -1126,18 +1540,18 @@ static void tcpconn_destroy(struct tcp_connection* tcpconn) /* force timeout */ tcpconn->timeout=0; tcpconn->state=S_CONN_BAD; - LM_DBG("delaying (%p, flags %04x) ...\n", - tcpconn, tcpconn->flags); - + LM_DBG("delaying (%p, flags %04x) ref = %d ...\n", + tcpconn, tcpconn->flags, tcpconn->refcnt); + } - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(id); } /*! \brief * handles an io event on one of the watched tcp connections - * + * * \param tcpconn - pointer to the tcp_connection for which we have an io ev. * \param fd_i - index in the fd_array table (needed for delete) * \return handle_* return convention, but on success it always returns 0 @@ -1146,13 +1560,16 @@ static void tcpconn_destroy(struct tcp_connection* tcpconn) * tcp_main is not interested in further io events that might be * queued for this fd) */ -inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, int fd_i) +inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, int fd_i,int event_type) { int fd; - - /* is refcnt!=0 really necessary? + int err; + int id; + unsigned int err_len; + + /* is refcnt!=0 really necessary? * No, in fact it's a bug: I can have the following situation: a send only - * tcp connection used by n processes simultaneously => refcnt = n. In + * tcp connection used by n processes simultaneously => refcnt = n. In * the same time I can have a read event and this situation is perfectly * valid. -- andrei */ @@ -1166,26 +1583,76 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, int fd_i) return -1; } #endif - /* pass it to child, so remove it from the io watch list */ - LM_DBG("data available on %p %d\n", tcpconn, tcpconn->s); - if (io_watch_del(&io_h, tcpconn->s, fd_i, 0)==-1) goto error; - tcpconn->flags|=F_CONN_REMOVED; - tcpconn_ref(tcpconn); /* refcnt ++ */ - if (send2child(tcpconn)<0){ - LM_ERR("no children available\n"); - TCPCONN_LOCK; - tcpconn->refcnt--; - if (tcpconn->refcnt==0){ - fd=tcpconn->s; - _tcpconn_rm(tcpconn); - close(fd); - }else tcpconn->timeout=0; /* force expire*/ - TCPCONN_UNLOCK; - } - return 0; /* we are not interested in possibly queued io events, - the fd was either passed to a child, or closed */ -error: - return -1; + if (event_type == IO_WATCH_READ) { + /* pass it to child, so remove it from the io watch list */ + LM_DBG("data available on %p %d\n", tcpconn, tcpconn->s); + if (io_watch_del(&io_h, tcpconn->s, fd_i, 0,IO_WATCH_READ)==-1) + return -1; + tcpconn->flags|=F_CONN_REMOVED; + tcpconn_ref(tcpconn); /* refcnt ++ */ + if (send2child(tcpconn,IO_WATCH_READ)<0){ + LM_ERR("no children available\n"); + id = tcpconn->id; + TCPCONN_LOCK(id); + tcpconn->refcnt--; + if (tcpconn->refcnt==0){ + fd=tcpconn->s; + _tcpconn_rm(tcpconn); + close(fd); + }else tcpconn->timeout=0; /* force expire*/ + TCPCONN_UNLOCK(id); + } + return 0; /* we are not interested in possibly queued io events, + the fd was either passed to a child, or closed */ + } else { + LM_DBG("connection %p fd %d is now writable\n", tcpconn, tcpconn->s); + /* we received a write event */ + if (tcpconn->flags & F_CONN_NOT_CONNECTED) { + /* we're coming from an async connect & write + * let's see if we connected succesfully*/ + err_len=sizeof(err); + getsockopt(tcpconn->s, SOL_SOCKET, SO_ERROR, &err, &err_len); + if (err != 0) { + LM_DBG("Failed connection attempt\n"); + tcpconn_ref(tcpconn); + io_watch_del(&io_h, tcpconn->s, -1, IO_FD_CLOSING, + IO_WATCH_READ|IO_WATCH_WRITE); + tcpconn->flags|=F_CONN_REMOVED; + tcpconn_destroy(tcpconn); + return 0; + } + + /* we succesfully connected - further treat this case as if we + * were coming from an async write */ + tcpconn->flags &=~F_CONN_NOT_CONNECTED; + LM_DBG("Succesfully completed previous async connect\n"); + + goto async_write; + } else { + /* we're coming from an async write - + * just pass to child and have it write + * our TCP chunks */ +async_write: + /* no more write events for now */ + if (io_watch_del(&io_h, tcpconn->s, fd_i, 0,IO_WATCH_WRITE)==-1) + return -1; + tcpconn->flags|=F_CONN_REMOVED; + tcpconn_ref(tcpconn); /* refcnt ++ */ + if (send2child(tcpconn,IO_WATCH_WRITE)<0){ + LM_ERR("no children available\n"); + id = tcpconn->id; + TCPCONN_LOCK(id); + tcpconn->refcnt--; + if (tcpconn->refcnt==0){ + fd=tcpconn->s; + _tcpconn_rm(tcpconn); + close(fd); + }else tcpconn->timeout=0; /* force expire*/ + TCPCONN_UNLOCK(id); + } + return 0; + } + } } @@ -1195,14 +1662,14 @@ void force_tcp_conn_lifetime(struct receive_info *rcv, unsigned int timeout) struct tcp_connection* con; unsigned int lifetime = get_ticks() + timeout; - TCPCONN_LOCK; - con =_tcpconn_find(rcv->proto_reserved1, 0, 0); + TCPCONN_LOCK(rcv->proto_reserved1); + con =_tcpconn_find(rcv->proto_reserved1); if (!con) { LM_ERR("Strange, tcp conn not found (id=%d)\n",rcv->proto_reserved1); } else { con->lifetime = lifetime; } - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(rcv->proto_reserved1); } @@ -1225,7 +1692,7 @@ static inline void set_tcp_timeout(struct tcp_connection *c) /*! \brief handles io from a tcp child process * \param tcp_c - pointer in the tcp_children array, to the entry for - * which an io event was detected + * which an io event was detected * \param fd_i - fd index in the fd_array (usefull for optimizing * io_watch_deletes) * \return handle_* return convention: -1 on error, 0 on EAGAIN (no more @@ -1238,7 +1705,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) long response[2]; int cmd; int bytes; - + if (tcp_c->unix_sock<=0){ /* (we can't have a fd==0, 0 is never closed )*/ LM_CRIT("fd %d for %d (pid %d, ser no %d)\n", tcp_c->unix_sock, @@ -1252,10 +1719,10 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) if (bytes==0){ /* EOF -> bad, child has died */ LM_DBG("dead tcp child %d (pid %d, no %d)" - " (shutting down?)\n", (int)(tcp_c-&tcp_children[0]), + " (shutting down?)\n", (int)(tcp_c-&tcp_children[0]), tcp_c->pid, tcp_c->proc_no ); /* don't listen on it any more */ - io_watch_del(&io_h, tcp_c->unix_sock, fd_i, 0); + io_watch_del(&io_h, tcp_c->unix_sock, fd_i, 0,IO_WATCH_READ); goto error; /* eof. so no more io here, it's ok to return error */ }else if (bytes<0){ /* EAGAIN is ok if we try to empty the buffer @@ -1278,7 +1745,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) goto end; } } - + LM_DBG("reader response= %lx, %ld from %d \n", response[0], response[1], (int)(tcp_c-&tcp_children[0])); cmd=response[1]; @@ -1293,7 +1760,20 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) switch(cmd){ case CONN_RELEASE: tcp_c->busy--; - if (tcpconn->state==S_CONN_BAD){ + if (tcpconn->state==S_CONN_BAD){ + tcpconn_destroy(tcpconn); + break; + } + /* update the timeout (lifetime) */ + set_tcp_timeout( tcpconn ); + tcpconn_put(tcpconn); + /* must be after the de-ref*/ + io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn,IO_WATCH_READ); + tcpconn->flags&=~F_CONN_REMOVED; + break; + case ASYNC_WRITE: + tcp_c->busy--; + if (tcpconn->state==S_CONN_BAD){ tcpconn_destroy(tcpconn); break; } @@ -1301,10 +1781,8 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) set_tcp_timeout( tcpconn ); tcpconn_put(tcpconn); /* must be after the de-ref*/ - io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn); + io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn,IO_WATCH_WRITE); tcpconn->flags&=~F_CONN_REMOVED; - LM_DBG("cmd CONN_RELEASE %p refcnt= %d\n", - tcpconn, tcpconn->refcnt); break; case CONN_ERROR: case CONN_DESTROY: @@ -1330,14 +1808,14 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) /*! \brief handles io from a "generic" ser process (get fd or new_fd from a tcp_send) - * + * * \param p - pointer in the ser processes array (pt[]), to the entry for * which an io event was detected * \param fd_i - fd index in the fd_array (usefull for optimizing * io_watch_deletes) * \return handle_* return convention: * - -1 on error reading from the fd, - * - 0 on EAGAIN or when no more io events are queued + * - 0 on EAGAIN or when no more io events are queued * (receive buffer empty), * - >0 on successfull reads from the fd (the receive buffer might * be non-empty). @@ -1350,15 +1828,15 @@ inline static int handle_ser_child(struct process_table* p, int fd_i) int bytes; int ret; int fd; - + ret=-1; if (p->unix_sock<=0){ /* (we can't have a fd==0, 0 is never closed )*/ - LM_CRIT("fd %d for %d (pid %d)\n", + LM_CRIT("fd %d for %d (pid %d)\n", p->unix_sock, (int)(p-&pt[0]), p->pid); goto error; } - + /* get all bytes and the fd (if transmitted) * (this is a SOCK_STREAM so read is not atomic) */ bytes=receive_fd(p->unix_sock, response, sizeof(response), &fd, @@ -1370,13 +1848,13 @@ inline static int handle_ser_child(struct process_table* p, int fd_i) LM_DBG("dead child %d, pid %d" " (shutting down?)\n", (int)(p-&pt[0]), p->pid); /* don't listen on it any more */ - io_watch_del(&io_h, p->unix_sock, fd_i, 0); + io_watch_del(&io_h, p->unix_sock, fd_i, 0,IO_WATCH_READ); goto error; /* child dead => no further io events from it */ }else if (bytes<0){ /* EAGAIN is ok if we try to empty the buffer * e.g: SIGIO_RT overflow mode or EPOLL ET */ if ((errno!=EAGAIN) && (errno!=EWOULDBLOCK)){ - LM_CRIT("read from child %d (pid %d): %s [%d]\n", + LM_CRIT("read from child %d (pid %d): %s [%d]\n", (int)(p-&pt[0]), p->pid, strerror(errno), errno); ret=-1; }else{ @@ -1406,7 +1884,8 @@ inline static int handle_ser_child(struct process_table* p, int fd_i) switch(cmd){ case CONN_ERROR: if (!(tcpconn->flags & F_CONN_REMOVED) && (tcpconn->s!=-1)){ - io_watch_del(&io_h, tcpconn->s, -1, IO_FD_CLOSING); + io_watch_del(&io_h, tcpconn->s, -1, IO_FD_CLOSING, + IO_WATCH_READ|IO_WATCH_WRITE); tcpconn->flags|=F_CONN_REMOVED; } tcpconn_destroy(tcpconn); /* will close also the fd */ @@ -1433,7 +1912,37 @@ inline static int handle_ser_child(struct process_table* p, int fd_i) tcpconn_add(tcpconn); /* update the timeout*/ tcpconn->timeout=get_ticks()+tcp_con_lifetime; - io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn); + io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn,IO_WATCH_READ); + tcpconn->flags&=~F_CONN_REMOVED; + break; + case ASYNC_CONNECT: + /* connection is not yet linked to hash = not yet + * available to the outside world */ + if (fd==-1){ + LM_CRIT(" cmd CONN_NEW: no fd received\n"); + break; + } + tcpconn->flags|=F_CONN_NOT_CONNECTED; + tcpconn->s=fd; + /* add tcpconn to the list*/ + tcpconn_add(tcpconn); + /* update the timeout*/ + tcpconn->timeout=get_ticks()+tcp_con_lifetime; + /* only maintain the socket in the IO_WATCH_WRITE watcher + * while we have stuff to write - otherwise we're going to get + * useless events */ + io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn,IO_WATCH_WRITE); + tcpconn->flags&=~F_CONN_REMOVED; + break; + case ASYNC_WRITE: + if (tcpconn->state==S_CONN_BAD){ + tcpconn_destroy(tcpconn); + break; + } + /* update the timeout (lifetime) */ + set_tcp_timeout( tcpconn ); + /* must be after the de-ref*/ + io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn,IO_WATCH_WRITE); tcpconn->flags&=~F_CONN_REMOVED; break; default: @@ -1453,23 +1962,23 @@ inline static int handle_ser_child(struct process_table* p, int fd_i) * \param fm - pointer to a fd hash entry * \param idx - index in the fd_array (or -1 if not known) * \return -1 on error - * 0 on EAGAIN or when by some other way it is known that no more + * 0 on EAGAIN or when by some other way it is known that no more * io events are queued on the fd (the receive buffer is empty). * Usefull to detect when there are no more io events queued for * sigio_rt, epoll_et, kqueue. * >0 on successfull read from the fd (when there might be more io * queued -- the receive buffer might still be non-empty) */ -inline static int handle_io(struct fd_map* fm, int idx) -{ +inline static int handle_io(struct fd_map* fm, int idx,int event_type) +{ int ret; - + switch(fm->type){ case F_SOCKINFO: ret=handle_new_connect((struct socket_info*)fm->data); break; case F_TCPCONN: - ret=handle_tcpconn_ev((struct tcp_connection*)fm->data, idx); + ret=handle_tcpconn_ev((struct tcp_connection*)fm->data, idx,event_type); break; case F_TCPCHILD: ret=handle_tcp_child((struct tcp_child*)fm->data, idx); @@ -1481,7 +1990,7 @@ inline static int handle_io(struct fd_map* fm, int idx) LM_CRIT("empty fd map\n"); goto error; default: - LM_CRIT("uknown fd type %d\n", fm->type); + LM_CRIT("uknown fd type %d\n", fm->type); goto error; } return ret; @@ -1489,50 +1998,67 @@ inline static int handle_io(struct fd_map* fm, int idx) return -1; } - +/* + * iterates through all TCP connections and closes expired ones + * + * Note: runs once per second at most + */ +#define tcpconn_timeout(last_sec, close_all) \ + do { \ + int now; \ + now = get_ticks(); \ + if (last_sec != now) { \ + last_sec = now; \ + __tcpconn_timeout(close_all); \ + } \ + } while (0) /*! \brief very inefficient for now - FIXME * keep in sync with tcpconn_destroy, the "delete" part should be * the same except for io_watch_del.. * \todo FIXME (very inefficient for now) */ -static inline void tcpconn_timeout(int force) +static inline void __tcpconn_timeout(int force) { struct tcp_connection *c, *next; - unsigned int ticks; + unsigned int ticks,part; unsigned h; int fd; - - + + ticks=get_ticks(); - TCPCONN_LOCK; /* fixme: we can lock only on delete IMO */ - for(h=0; hid_next; - if (force ||((c->refcnt==0) && (ticks>c->timeout))) { - if (!force) - LM_DBG("timeout for hash=%d - %p" - " (%d > %d)\n", h, c, ticks, c->timeout); - fd=c->s; + + for( part=0 ; partid_next; + if (force ||((c->refcnt==0) && (ticks>c->timeout))) { + if (!force) + LM_DBG("timeout for hash=%d - %p" + " (%d > %d)\n", h, c, ticks, c->timeout); + fd=c->s; #ifdef USE_TLS - if (c->type==PROTO_TLS) - tls_close(c, fd); + if (c->type==PROTO_TLS) + tls_close(c, fd); #endif - _tcpconn_rm(c); - if ((!force)&&(fd>0)&&(c->refcnt==0)) { - if (!(c->flags & F_CONN_REMOVED)){ - io_watch_del(&io_h, fd, -1, IO_FD_CLOSING); - c->flags|=F_CONN_REMOVED; + _tcpconn_rm(c); + if ((!force)&&(fd>0)&&(c->refcnt==0)) { + if (!(c->flags & F_CONN_REMOVED)){ + io_watch_del(&io_h, fd, -1, IO_FD_CLOSING, + IO_WATCH_READ|IO_WATCH_WRITE); + c->flags|=F_CONN_REMOVED; + } + close(fd); } - close(fd); + tcp_connections_no--; } - tcp_connections_no--; + c=next; } - c=next; } + TCPCONN_UNLOCK(part); } - TCPCONN_UNLOCK; } @@ -1540,6 +2066,7 @@ static inline void tcpconn_timeout(int force) /*! \brief tcp main loop */ void tcp_main_loop(void) { + static unsigned int last_sec = 0; int flags; struct socket_info* si; int r; @@ -1555,7 +2082,7 @@ void tcp_main_loop(void) /* add all the sockets we listens on for connections */ for (si=tcp_listen; si; si=si->next){ if ((si->proto==PROTO_TCP) &&(si->socket!=-1)){ - if (io_watch_add(&io_h, si->socket, F_SOCKINFO, si)<0){ + if (io_watch_add(&io_h, si->socket, F_SOCKINFO, si,IO_WATCH_READ)<0){ LM_CRIT("failed to add listen socket to the fd list\n"); goto error; } @@ -1567,7 +2094,7 @@ void tcp_main_loop(void) if (!tls_disable){ for (si=tls_listen; si; si=si->next){ if ((si->proto==PROTO_TLS) && (si->socket!=-1)){ - if (io_watch_add(&io_h, si->socket, F_SOCKINFO, si)<0){ + if (io_watch_add(&io_h, si->socket, F_SOCKINFO, si,IO_WATCH_READ)<0){ LM_CRIT("failed to add tls listen socket to the fd list\n"); goto error; } @@ -1580,10 +2107,10 @@ void tcp_main_loop(void) /* add all the unix sockets used for communcation with other opensips * processes (get fd, new connection a.s.o) */ for (r=1; r0) - if (io_watch_add(&io_h, pt[r].unix_sock, F_PROC, &pt[r])<0){ + if (r!=process_no && pt[r].unix_sock>0) + if (io_watch_add(&io_h, pt[r].unix_sock, F_PROC, &pt[r],IO_WATCH_READ)<0){ LM_CRIT("failed to add process %d (%s) unix socket " "to the fd list\n", r, pt[r].desc); goto error; @@ -1606,29 +2133,29 @@ void tcp_main_loop(void) } /* add socket for listening */ if (io_watch_add(&io_h, tcp_children[r].unix_sock, F_TCPCHILD, - &tcp_children[r]) <0){ + &tcp_children[r],IO_WATCH_READ) <0){ LM_CRIT("failed to add tcp child %d unix socket to " "the fd list\n", r); goto error; } } } - + /* main loop */ switch(io_h.poll_method){ case POLL_POLL: while(1){ /* wait and process IO */ - io_wait_loop_poll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); + io_wait_loop_poll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); /* remove old connections */ - tcpconn_timeout(0); + tcpconn_timeout(last_sec, 0); } break; #ifdef HAVE_SELECT case POLL_SELECT: while(1){ io_wait_loop_select(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); - tcpconn_timeout(0); + tcpconn_timeout(last_sec, 0); } break; #endif @@ -1636,7 +2163,7 @@ void tcp_main_loop(void) case POLL_SIGIO_RT: while(1){ io_wait_loop_sigio_rt(&io_h, TCP_MAIN_SELECT_TIMEOUT); - tcpconn_timeout(0); + tcpconn_timeout(last_sec, 0); } break; #endif @@ -1644,13 +2171,13 @@ void tcp_main_loop(void) case POLL_EPOLL_LT: while(1){ io_wait_loop_epoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); - tcpconn_timeout(0); + tcpconn_timeout(last_sec, 0); } break; case POLL_EPOLL_ET: while(1){ io_wait_loop_epoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 1); - tcpconn_timeout(0); + tcpconn_timeout(last_sec, 0); } break; #endif @@ -1658,7 +2185,7 @@ void tcp_main_loop(void) case POLL_KQUEUE: while(1){ io_wait_loop_kqueue(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); - tcpconn_timeout(0); + tcpconn_timeout(last_sec, 0); } break; #endif @@ -1666,12 +2193,12 @@ void tcp_main_loop(void) case POLL_DEVPOLL: while(1){ io_wait_loop_devpoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); - tcpconn_timeout(0); + tcpconn_timeout(last_sec, 0); } break; #endif default: - LM_CRIT("no support for poll method %s (%d)\n", + LM_CRIT("no support for poll method %s (%d)\n", poll_method_name(io_h.poll_method), io_h.poll_method); goto error; } @@ -1686,24 +2213,31 @@ void tcp_main_loop(void) /*! \brief cleanup before exit */ void destroy_tcp(void) { - if (tcpconn_id_hash){ - tcpconn_timeout(1); /* force close/expire for all active tcpconns*/ - shm_free(tcpconn_id_hash); - tcpconn_id_hash=0; - } - if (connection_id){ - shm_free(connection_id); - connection_id=0; + int part; + + if (tcp_parts[0].tcpconn_id_hash) + __tcpconn_timeout(1); /* force close/expire for all active tcpconns*/ + + if (connection_id){ + shm_free(connection_id); + connection_id=0; + } + + for ( part=0 ; partnext, r++); @@ -1806,13 +2345,13 @@ int tcp_init_children(int *chd_rank, int *startup_done) if (! tls_disable) for (si=tls_listen; si; si=si->next, r++); #endif - + tcp_max_fd_no=counted_processes*2 +r-1 /* timer */ +3; /* stdin/out/err*/ tcp_max_fd_no+=tcp_max_connections; - + /* create the tcp sock_info structures */ /* copy the sockets --moved to main_loop*/ - + if (register_tcp_load_stat( &load_p )!=0) { LM_ERR("failed to init tcp load statistics\n"); goto error; @@ -1828,7 +2367,7 @@ int tcp_init_children(int *chd_rank, int *startup_done) LM_ERR("socketpair failed: %s\n", strerror(errno)); goto error; } - + (*chd_rank)++; pid=internal_fork("SIP receiver TCP"); if (pid<0){ @@ -1856,13 +2395,18 @@ int tcp_init_children(int *chd_rank, int *startup_done) LM_ERR("failed to send status code\n"); clean_write_pipeend(); + *startup_done = -1; exit(-1); } - + /* was startup route executed so far ? */ if (startup_done!=NULL && *startup_done==0 && r==0) { LM_DBG("runing startup for first TCP\n"); if(run_startup_route()< 0) { + *startup_done = -1; + if (send_status_code(-1) < 0) + LM_ERR("failed to send status code\n"); + clean_write_pipeend(); LM_ERR("Startup route processing failed\n"); exit(-1); } @@ -1889,85 +2433,97 @@ struct mi_root *mi_list_tcp_conns(struct mi_root *cmd, void *param) struct mi_node* node; struct mi_attr *attr; struct tcp_connection *conn; - unsigned long ctime; - unsigned int i,n; + time_t _ts; + char date_buf[MI_DATE_BUF_LEN]; + int date_buf_len; + unsigned int i,n,part; char proto[4]; char *p; int len; + if (tcp_disable) + return init_mi_tree( 404, MI_SSTR("TCP support disabled")); + rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK)); if (rpl_tree==NULL) return 0; - ctime = (long)time(NULL); - - TCPCONN_LOCK; - - for( i=0,n=0 ; iid_next ) { - /* add one node for each conn */ - node = add_mi_node_child(&rpl_tree->node, 0, - MI_SSTR("Connection"), 0, 0 ); - if (node==0) - goto error; + for( part=0 ; partid_next ) { + /* add one node for each conn */ + node = add_mi_node_child(&rpl_tree->node, 0, + MI_SSTR("Connection"), 0, 0 ); + if (node==0) + goto error; - /* add ID */ - p = int2str((unsigned long)conn->id, &len); - attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("ID"), p, len); - if (attr==0) - goto error; + /* add ID */ + p = int2str((unsigned long)conn->id, &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("ID"), p, len); + if (attr==0) + goto error; - /* add type/proto */ - p = proto2str(conn->type, proto); - attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Type"), - proto, (int)(long)(p-proto)); - if (attr==0) - goto error; + /* add type/proto */ + p = proto2str(conn->type, proto); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Type"), + proto, (int)(long)(p-proto)); + if (attr==0) + goto error; - /* add state */ - p = int2str((unsigned long)conn->state, &len); - attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("State"), p, len); - if (attr==0) - goto error; + /* add state */ + p = int2str((unsigned long)conn->state, &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("State"), p, len); + if (attr==0) + goto error; - /* add Source */ - attr = addf_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Source"), - "%s:%d",ip_addr2a(&conn->rcv.src_ip), conn->rcv.src_port); - if (attr==0) - goto error; + /* add Source */ + attr = addf_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Source"), + "%s:%d",ip_addr2a(&conn->rcv.src_ip), conn->rcv.src_port); + if (attr==0) + goto error; - /* add Destination */ - attr = addf_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Destination"), - "%s:%d",ip_addr2a(&conn->rcv.dst_ip), conn->rcv.dst_port); - if (attr==0) - goto error; + /* add Destination */ + attr = addf_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Destination"), + "%s:%d",ip_addr2a(&conn->rcv.dst_ip), conn->rcv.dst_port); + if (attr==0) + goto error; - /* add timeout */ - p = int2str((unsigned long)conn->timeout+ctime, &len); - attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Timeout"), p,len); - if (attr==0) - goto error; + /* add timeout */ + _ts = (time_t)conn->timeout + startup_time; + date_buf_len = strftime(date_buf, MI_DATE_BUF_LEN - 1, + "%Y-%m-%d %H:%M:%S", localtime(&_ts)); + if (date_buf_len != 0) { + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Timeout"), + date_buf, date_buf_len); + } else { + p = int2str((unsigned long)_ts, &len); + attr = add_mi_attr( node, MI_DUP_VALUE, MI_SSTR("Timeout"), p,len); + } + if (attr==0) + goto error; - /* add lifetime */ - p = int2str((unsigned long)conn->lifetime, &len); - attr = add_mi_attr( node, MI_DUP_VALUE, - MI_SSTR("Pending lifetime"), p, len); - if (attr==0) - goto error; + /* add lifetime */ + p = int2str((unsigned long)conn->lifetime, &len); + attr = add_mi_attr( node, MI_DUP_VALUE, + MI_SSTR("Pending lifetime"), p, len); + if (attr==0) + goto error; - n++; - /* at each 50 conns, flush the tree */ - if ( (n % 50) == 0 ) - flush_mi_tree(rpl_tree); + n++; + /* at each 50 conns, flush the tree */ + if ( (n % 50) == 0 ) + flush_mi_tree(rpl_tree); + } } - } - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(part); + } return rpl_tree; error: - TCPCONN_UNLOCK; + TCPCONN_UNLOCK(part); LM_ERR("failed to add node\n"); free_mi_tree(rpl_tree); return 0; diff --git a/tcp_read.c b/tcp_read.c index 7a294baa4a1..2e3027822de 100644 --- a/tcp_read.c +++ b/tcp_read.c @@ -24,7 +24,7 @@ * 2002-12-?? created by andrei. * 2003-02-10 zero term before calling receive_msg & undo afterward (andrei) * 2003-05-13 l: (short form of Content-Length) is now recognized (andrei) - * 2003-07-01 tcp_read & friends take no a single tcp_connection + * 2003-07-01 tcp_read & friends take no a single tcp_connection * parameter & they set c->state to S_CONN_EOF on eof (andrei) * 2003-07-04 fixed tcp EOF handling (possible infinite loop) (andrei) * 2005-07-05 migrated to the new io_wait code (andrei) @@ -68,29 +68,32 @@ #include "forward.h" #include "pt.h" -enum fd_types { F_NONE, F_TCPMAIN, F_TCPCONN }; /*!< types used in io_wait* */ +enum fd_types { F_NONE=0, F_TCPMAIN=1, F_TCPCONN=2 }; /*!< types used in io_wait* */ static struct tcp_connection* tcp_conn_lst=0; /*!< list of tcp connections handled by this process */ static io_wait_h io_w; /* io_wait handler*/ static int tcpmain_sock=-1; +/* buffer to be used for reading all TCP SIP messages + detached from the actual con - in order to improve + paralelism ( process the SIP message while the con + can be sent back to main to do more stuff */ +struct tcp_req current_req; /*! \brief reads next available bytes * \return number of bytes read, 0 on EOF or -1 on error, * on EOF it also sets c->state to S_CONN_EOF * (to distinguish from reads that would block which could return 0) - * sets also r->error + * sets also r->error */ -int tcp_read(struct tcp_connection *c) +int tcp_read(struct tcp_connection *c,struct tcp_req *r) { int bytes_free, bytes_read; - struct tcp_req *r; int fd; - r=&c->req; fd=c->fd; bytes_free=TCP_BUF_SIZE- (int)(r->pos - r->buf); - + if (bytes_free==0){ LM_ERR("buffer overrun, dropping\n"); r->error=TCP_REQ_OVERRUN; @@ -133,20 +136,19 @@ int tcp_read(struct tcp_connection *c) * when either r->body!=0 or r->state==H_BODY => * all headers have been read. It should be called in a while loop. * returns < 0 if error or 0 if EOF */ -int tcp_read_headers(struct tcp_connection *c) +int tcp_read_headers(struct tcp_connection *c,struct tcp_req *r) { unsigned int remaining; int bytes; char *p; - struct tcp_req* r; - + #define crlf_default_skip_case \ case '\n': \ r->state=H_LF; \ break; \ default: \ r->state=H_SKIP - + #define content_len_beg_case \ case ' ': \ case '\t': \ @@ -165,7 +167,7 @@ int tcp_read_headers(struct tcp_connection *c) if (!r->has_content_len) r->state=H_L_COLON; \ else r->state=H_SKIP; \ break - + #define change_state(upper, lower, newstate)\ switch(*p){ \ case upper: \ @@ -173,7 +175,7 @@ int tcp_read_headers(struct tcp_connection *c) r->state=(newstate); break; \ crlf_default_skip_case; \ } - + #define change_state_case(state0, upper, lower, newstate)\ case state0: \ change_state(upper, lower, newstate); \ @@ -181,21 +183,20 @@ int tcp_read_headers(struct tcp_connection *c) break - r=&c->req; /* if we still have some unparsed part, parse it first, don't do the read*/ if (r->parsedpos){ bytes=0; }else{ #ifdef USE_TLS if (c->type==PROTO_TLS) - bytes=tls_read(c); + bytes=tls_read(c,r); else #endif - bytes=tcp_read(c); + bytes=tcp_read(c,r); if (bytes<=0) return bytes; } p=r->parsed; - + while(ppos && r->error==TCP_REQ_OK){ switch((unsigned char)r->state){ case H_BODY: /* read the body*/ @@ -208,7 +209,7 @@ int tcp_read_headers(struct tcp_connection *c) goto skip; } break; - + case H_SKIP: /* find lf, we are in this state if we are not interested * in anything till end of line*/ @@ -220,7 +221,7 @@ int tcp_read_headers(struct tcp_connection *c) p=r->pos; } break; - + case H_LF: /* terminate on LF CR LF or LF LF */ switch (*p){ @@ -244,7 +245,7 @@ int tcp_read_headers(struct tcp_connection *c) } break; content_len_beg_case; - default: + default: r->state=H_SKIP; } p++; @@ -268,7 +269,7 @@ int tcp_read_headers(struct tcp_connection *c) }else r->state=H_SKIP; p++; break; - + case H_STARTWS: switch (*p){ content_len_beg_case; @@ -290,9 +291,9 @@ int tcp_read_headers(struct tcp_connection *c) case '\t': /* skip empty lines */ break; - case 'C': - case 'c': - r->state=H_CONT_LEN1; + case 'C': + case 'c': + r->state=H_CONT_LEN1; r->start=p; break; case 'l': @@ -349,7 +350,7 @@ int tcp_read_headers(struct tcp_connection *c) change_state_case(H_CONT_LEN11, 'G', 'g', H_CONT_LEN12); change_state_case(H_CONT_LEN12, 'T', 't', H_CONT_LEN13); change_state_case(H_CONT_LEN13, 'H', 'h', H_L_COLON); - + case H_L_COLON: switch(*p){ case ' ': @@ -362,7 +363,7 @@ int tcp_read_headers(struct tcp_connection *c) }; p++; break; - + case H_CONT_LEN_BODY: switch(*p){ case ' ': @@ -386,7 +387,7 @@ int tcp_read_headers(struct tcp_connection *c) } p++; break; - + case H_CONT_LEN_BODY_PARSE: switch(*p){ case '0': @@ -419,7 +420,7 @@ int tcp_read_headers(struct tcp_connection *c) } p++; break; - + default: LM_CRIT("unexpected state %d\n", r->state); abort(); @@ -430,8 +431,104 @@ int tcp_read_headers(struct tcp_connection *c) return bytes; } +void release_tcpconn(struct tcp_connection* c, long state, int unix_sock) +{ + long response[2]; + + LM_DBG(" releasing con %p, state %ld, fd=%d, id=%d\n", + c, state, c->fd, c->id); + LM_DBG(" extra_data %p\n", c->extra_data); + if (c->con_req) { + pkg_free(c->con_req); + c->con_req = NULL; + } + + /* release req & signal the parent */ + if (c->fd!=-1) close(c->fd); + /* errno==EINTR, EWOULDBLOCK a.s.o todo */ + response[0]=(long)c; + response[1]=state; + if (send_all(unix_sock, response, sizeof(response))<=0) + LM_ERR("send_all failed\n"); +} + +/* Responsible for writing the TCP send chunks - called under con write lock + * * if returns >= 0 : it keeps the connection for further usage + * or releases it manually + * * if returns < 0 : the connection should be released by the + * upper layer + */ +int tcp_write_async_req(struct tcp_connection* con) +{ + int n,left; + struct tcp_send_chunk *chunk; + + if (con->async_chunks_no == 0) { + LM_DBG("The connection has been triggered " + " for a write event - but we have no pending write chunks\n"); + return 0; + } + +next_chunk: + chunk=con->async_chunks[0]; +again: + left = (int)((chunk->buf+chunk->len)-chunk->pos); + LM_DBG("Trying to send %d bytes from chunk %p in conn %p - %d %d \n", + left,chunk,con,chunk->ticks,get_ticks()); + n=send(con->fd, chunk->pos, left, +#ifdef HAVE_MSG_NOSIGNAL + MSG_NOSIGNAL +#else + 0 +#endif + ); + + if (n<0) { + if (errno==EINTR) + goto again; + else if (errno==EAGAIN || errno==EWOULDBLOCK) { + LM_DBG("Can't finish to write chunk %p on conn %p\n", + chunk,con); + release_tcpconn(con, ASYNC_WRITE, tcpmain_sock); + return 0; + } else { + LM_ERR("Error occured while sending async chunk %d (%s)\n", + errno,strerror(errno)); + return CONN_ERROR; + } + } + + if (n < left) { + /* partial write */ + chunk->pos+=n; + goto again; + } else { + /* written a full chunk - move to the next one, if any */ + shm_free(chunk); + con->async_chunks_no--; + if (con->async_chunks_no == 0) { + LM_DBG("We have finished writing all our async chunks in %p\n",con); + con->oldest_chunk=0; + release_tcpconn(con, CONN_RELEASE, tcpmain_sock); + return 0; + } else { + LM_DBG("We still have %d chunks pending on %p\n", + con->async_chunks_no,con); + memmove(&con->async_chunks[0],&con->async_chunks[1], + con->async_chunks_no * sizeof(struct tcp_send_chunk*)); + con->oldest_chunk = con->async_chunks[0]->ticks; + goto next_chunk; + } + } +} +/* Responsible for reading the request + * * if returns >= 0 : it keeps the connection for further usage + * or releases it manually + * * if returns < 0 : the connection should be released by the + * upper layer + */ int tcp_read_req(struct tcp_connection* con, int* bytes_read) { int bytes; @@ -439,169 +536,261 @@ int tcp_read_req(struct tcp_connection* con, int* bytes_read) int resp; long size; struct tcp_req* req; -/* int s; */ char c; - - bytes=-1; - total_bytes=0; - resp=CONN_RELEASE; - /* s=con->fd; */ - req=&con->req; + struct receive_info local_rcv; + char *msg_buf; + int msg_len; + + bytes=-1; + total_bytes=0; + resp=CONN_RELEASE; + + if (con->con_req) { + req=con->con_req; + LM_DBG("Using the per connection buff \n"); + } else { + LM_DBG("Using the global ( per process ) buff \n"); + req=¤t_req; + } + #ifdef USE_TLS - if (con->type==PROTO_TLS){ - if (tls_fix_read_conn(con)!=0){ - resp=CONN_ERROR; - goto end_req; - } - if(con->state!=S_CONN_OK) goto end_req; /* not enough data */ + if (con->type==PROTO_TLS){ + if (tls_fix_read_conn(con)!=0){ + resp=CONN_ERROR; + goto end_req; } + if(con->state!=S_CONN_OK) goto end_req; /* not enough data */ + } #endif again: - if(req->error==TCP_REQ_OK){ - bytes=tcp_read_headers(con); -#ifdef EXTRA_DEBUG - /* if timeout state=0; goto end__req; */ - LM_DBG("read= %d bytes, parsed=%d, state=%d, error=%d\n", - bytes, (int)(req->parsed-req->start), req->state, - req->error ); - LM_DBG("last char=0x%02X, parsed msg=\n%.*s\n", - *(req->parsed-1), (int)(req->parsed-req->start), - req->start); -#endif - if (bytes==-1){ - LM_ERR("failed to read \n"); - resp=CONN_ERROR; - goto end_req; - } - total_bytes+=bytes; - /* eof check: - * is EOF if eof on fd and req. not complete yet, - * if req. is complete we might have a second unparsed - * request after it, so postpone release_with_eof - */ - if ((con->state==S_CONN_EOF) && (req->complete==0)) { - LM_DBG("EOF\n"); - resp=CONN_EOF; - goto end_req; - } - - } - if (req->error!=TCP_REQ_OK){ - LM_ERR("bad request, state=%d, error=%d " - "buf:\n%.*s\nparsed:\n%.*s\n", req->state, req->error, - (int)(req->pos-req->buf), req->buf, - (int)(req->parsed-req->start), req->start); - LM_DBG("- received from: port %d\n", con->rcv.src_port); - print_ip("- received from: ip ",&con->rcv.src_ip, "\n"); + if(req->error==TCP_REQ_OK){ + bytes=tcp_read_headers(con,req); +//#ifdef EXTRA_DEBUG + /* if timeout state=0; goto end__req; */ + LM_DBG("read= %d bytes, parsed=%d, state=%d, error=%d\n", + bytes, (int)(req->parsed-req->start), req->state, + req->error ); + LM_DBG("last char=0x%02X, parsed msg=\n%.*s\n", + *(req->parsed-1), (int)(req->parsed-req->start), + req->start); +//#endif + if (bytes==-1){ + LM_ERR("failed to read \n"); resp=CONN_ERROR; goto end_req; } - if (req->complete){ + total_bytes+=bytes; + /* eof check: + * is EOF if eof on fd and req. not complete yet, + * if req. is complete we might have a second unparsed + * request after it, so postpone release_with_eof + */ + if ((con->state==S_CONN_EOF) && (req->complete==0)) { + LM_DBG("EOF\n"); + resp=CONN_EOF; + goto end_req; + } + + } + if (req->error!=TCP_REQ_OK){ + LM_ERR("bad request, state=%d, error=%d " + "buf:\n%.*s\nparsed:\n%.*s\n", req->state, req->error, + (int)(req->pos-req->buf), req->buf, + (int)(req->parsed-req->start), req->start); + LM_DBG("- received from: port %d\n", con->rcv.src_port); + print_ip("- received from: ip ",&con->rcv.src_ip, "\n"); + resp=CONN_ERROR; + goto end_req; + } + if (req->complete){ #ifdef EXTRA_DEBUG - LM_DBG("end of header part\n"); - LM_DBG("- received from: port %d\n", con->rcv.src_port); - print_ip("- received from: ip ", &con->rcv.src_ip, "\n"); - LM_DBG("headers:\n%.*s.\n",(int)(req->body-req->start), req->start); + LM_DBG("end of header part\n"); + LM_DBG("- received from: port %d\n", con->rcv.src_port); + print_ip("- received from: ip ", &con->rcv.src_ip, "\n"); + LM_DBG("headers:\n%.*s.\n",(int)(req->body-req->start), req->start); #endif - if (req->has_content_len){ - LM_DBG("content-length= %d\n", req->content_len); + if (req->has_content_len){ + LM_DBG("content-length= %d\n", req->content_len); #ifdef EXTRA_DEBUG - LM_DBG("body:\n%.*s\n", req->content_len,req->body); + LM_DBG("body:\n%.*s\n", req->content_len,req->body); #endif - }else{ - req->error=TCP_REQ_BAD_LEN; - LM_ERR("content length not present or unparsable\n"); - resp=CONN_ERROR; - goto end_req; - } - /* if we are here everything is nice and ok*/ - update_stat( pt[process_no].load, +1 ); - resp=CONN_RELEASE; + }else{ + req->error=TCP_REQ_BAD_LEN; + LM_ERR("content length not present or unparsable\n"); + resp=CONN_ERROR; + goto end_req; + } + + /* update the timeout - we succesfully read the request */ + con->timeout=get_ticks()+tcp_max_msg_time; + + /* if we are here everything is nice and ok*/ + update_stat( pt[process_no].load, +1 ); + resp=CONN_RELEASE; #ifdef EXTRA_DEBUG - LM_DBG("calling receive_msg(%p, %d, )\n", - req->start, (int)(req->parsed-req->start)); + LM_DBG("calling receive_msg(%p, %d, )\n", + req->start, (int)(req->parsed-req->start)); #endif - /* rcv.bind_address should always be !=0 */ - bind_address=con->rcv.bind_address; - /* just for debugging use sendipv4 as receiving socket FIXME*/ - /* - if (con->rcv.dst_ip.af==AF_INET6){ - bind_address=sendipv6_tcp; - }else{ - bind_address=sendipv4_tcp; + /* rcv.bind_address should always be !=0 */ + bind_address=con->rcv.bind_address; + /* just for debugging use sendipv4 as receiving socket FIXME*/ + /* + if (con->rcv.dst_ip.af==AF_INET6){ + bind_address=sendipv6_tcp; + }else{ + bind_address=sendipv4_tcp; + } + */ + con->rcv.proto_reserved1=con->id; /* copy the id */ + c=*req->parsed; /* ugly hack: zero term the msg & save the + previous char, req->parsed should be ok + because we always alloc BUF_SIZE+1 */ + *req->parsed=0; + + /* prepare for next request */ + size=req->pos-req->parsed; + + if (req->state==H_PING_CRLFCRLF) { + /* we send the reply */ + if (tcp_send( con->rcv.bind_address, con->rcv.proto,CRLF, + CRLF_LEN, &(con->rcv.src_su), con->rcv.proto_reserved1) < 0) { + LM_ERR("CRLF pong - tcp_send() failed\n"); } - */ - con->rcv.proto_reserved1=con->id; /* copy the id */ - c=*req->parsed; /* ugly hack: zero term the msg & save the - previous char, req->parsed should be ok - because we always alloc BUF_SIZE+1 */ - *req->parsed=0; - - if (req->state==H_PING_CRLFCRLF) { - if (tcp_send( con->rcv.bind_address, con->rcv.proto,CRLF, - CRLF_LEN, &(con->rcv.src_su), con->rcv.proto_reserved1) < 0) { - LM_ERR("CRLF pong - tcp_send() failed\n"); + + if (!size) { + /* we can release the connection */ + io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING,IO_WATCH_READ); + tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); + if (con->state==S_CONN_EOF) + release_tcpconn(con, CONN_EOF, tcpmain_sock); + else + release_tcpconn(con, CONN_RELEASE, tcpmain_sock); + } + } else { + msg_buf = req->start; + msg_len = req->parsed-req->start; + local_rcv = con->rcv; + + if (!size) { + /* did not read any more things - we can release the connection */ + LM_DBG("We're releasing the connection in state %d \n",con->state); + + if (req != ¤t_req) { + /* we have the buffer in the connection tied buff - + * detach it , release the conn and free it afterwards */ + con->con_req = NULL; } - } else if (receive_msg(req->start, req->parsed-req->start, - &con->rcv)<0) { - *req->parsed=c; - resp=CONN_ERROR; - update_stat( pt[process_no].load, -1 ); - goto end_req; + + io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING,IO_WATCH_READ); + tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); + /* if we have EOF, signal that to MAIN as well + * otherwise - just pass it back */ + if (con->state==S_CONN_EOF) + release_tcpconn(con, CONN_EOF, tcpmain_sock); + else + release_tcpconn(con, CONN_RELEASE, tcpmain_sock); + } else { + LM_DBG("We still have things on the pipe - keeping connection \n"); } - *req->parsed=c; - - update_stat( pt[process_no].load, -1 ); - /* prepare for next request */ - size=req->pos-req->parsed; - if (size) memmove(req->buf, req->parsed, size); + if (receive_msg(msg_buf, msg_len, + &local_rcv) <0) + LM_ERR("receive_msg failed \n"); + + if (!size && req != ¤t_req) { + /* if we no longer need this tcp_req + * we can free it now */ + pkg_free(req); + } + } + + *req->parsed=c; + + update_stat( pt[process_no].load, -1 ); + + if (size) memmove(req->buf, req->parsed, size); #ifdef EXTRA_DEBUG - LM_DBG("preparing for new request, kept %ld bytes\n", size); + LM_DBG("preparing for new request, kept %ld bytes\n", size); #endif - req->pos=req->buf+size; - req->parsed=req->buf; - req->start=req->buf; - req->body=0; - req->error=TCP_REQ_OK; - req->state=H_SKIP_EMPTY; - req->complete=req->content_len=req->has_content_len=0; - req->bytes_to_go=0; - /* if we still have some unparsed bytes, try to parse them too*/ - if (size) goto again; - else if (con->state==S_CONN_EOF){ - LM_DBG("EOF after reading complete request\n"); - resp=CONN_EOF; + req->pos=req->buf+size; + req->parsed=req->buf; + req->start=req->buf; + req->body=0; + req->error=TCP_REQ_OK; + req->state=H_SKIP_EMPTY; + req->complete=req->content_len=req->has_content_len=0; + req->bytes_to_go=0; + con->msg_attempts = 0; + + /* if we still have some unparsed bytes, try to parse them too*/ + if (size) goto again; + } else { + /* request not complete - check the if the thresholds are exceeded */ + + con->msg_attempts ++; + if (con->msg_attempts == tcp_max_msg_chunks) { + LM_ERR("Made %u read attempts but message is not complete yet - " + "closing connection \n",con->msg_attempts); + resp = CONN_ERROR; + goto end_req; + } + + if (req == ¤t_req) { + /* let's duplicate this - most likely another conn will come in */ + + LM_DBG("We didn't manage to read a full request. Back to child poll\n"); + /* FIXME - PKG or SHM ? */ + con->con_req = pkg_malloc(sizeof(struct tcp_req)); + if (con->con_req == NULL) { + LM_ERR("No more mem for dynamic con request buffer\n"); + resp = CONN_ERROR; + goto end_req; } - + + if (req->pos != req->buf) { + /* we have read some bytes */ + memcpy(con->con_req->buf,req->buf,req->pos-req->buf); + con->con_req->pos = con->con_req->buf + (req->pos-req->buf); + } else { + con->con_req->pos = con->con_req->buf; + } + + if (req->start != req->buf) + con->con_req->start = con->con_req->buf + (req->start-req->buf); + else + con->con_req->start = con->con_req->buf; + + if (req->parsed != req->buf) + con->con_req->parsed = con->con_req->buf + (req->parsed-req->buf); + else + con->con_req->parsed = con->con_req->buf; + + if (req->body != 0) { + con->con_req->body = con->con_req->buf + (req->body-req->buf); + } else + con->con_req->body = 0; + + con->con_req->complete=req->complete; + con->con_req->has_content_len=req->has_content_len; + con->con_req->content_len=req->content_len; + con->con_req->bytes_to_go=req->bytes_to_go; + con->con_req->error = req->error; + con->con_req->state = req->state; + + /* zero out the per process req for the future SIP msg */ + init_tcp_req(¤t_req); } - - + } + + + LM_DBG("tcp_read_req end\n"); end_req: if (bytes_read) *bytes_read=total_bytes; return resp; } - -void release_tcpconn(struct tcp_connection* c, long state, int unix_sock) -{ - long response[2]; - - LM_DBG(" releasing con %p, state %ld, fd=%d, id=%d\n", - c, state, c->fd, c->id); - LM_DBG(" extra_data %p\n", c->extra_data); - /* release req & signal the parent */ - if (c->fd!=-1) close(c->fd); - /* errno==EINTR, EWOULDBLOCK a.s.o todo */ - response[0]=(long)c; - response[1]=state; - if (send_all(unix_sock, response, sizeof(response))<=0) - LM_ERR("send_all failed\n"); -} - - #ifdef DEBUG_TCP_RECEIVE /* old code known to work, kept arround for debuging */ void tcp_receive_loop(int unix_sock) @@ -618,14 +807,14 @@ void tcp_receive_loop(int unix_sock) int maxfd; struct timeval timeout; int ticks; - - + + /* init */ list=con=0; FD_ZERO(&master_set); FD_SET(unix_sock, &master_set); maxfd=unix_sock; - + /* listen on the unix socket for the fd */ for(;;){ timeout.tv_sec=TCP_CHILD_SELECT_TIMEOUT; @@ -634,7 +823,7 @@ void tcp_receive_loop(int unix_sock) nfds=select(maxfd+1, &sel_set, 0 , 0 , &timeout); #ifdef EXTRA_DEBUG for (n=0; nfd, &master_set); tcpconn_listrm(list, con, c_next, c_prev); @@ -735,7 +924,7 @@ void tcp_receive_loop(int unix_sock) } } } - + } } #else /* DEBUG_TCP_RECEIVE */ @@ -749,26 +938,26 @@ void tcp_receive_loop(int unix_sock) * idx - index in the fd_array (or -1 if not known) * return: -1 on error, or when we are not interested any more on reads * from this fd (e.g.: we are closing it ) - * 0 on EAGAIN or when by some other way it is known that no more + * 0 on EAGAIN or when by some other way it is known that no more * io events are queued on the fd (the receive buffer is empty). * Usefull to detect when there are no more io events queued for * sigio_rt, epoll_et, kqueue. * >0 on successfull read from the fd (when there might be more io * queued -- the receive buffer might still be non-empty) */ -inline static int handle_io(struct fd_map* fm, int idx) -{ - int ret; +inline static int handle_io(struct fd_map* fm, int idx,int event_type) +{ + int ret=0; int n; struct tcp_connection* con; - int s; + int s,rw; long resp; - + long response[2]; + switch(fm->type){ case F_TCPMAIN: again: - ret=n=receive_fd(fm->fd, &con, sizeof(con), &s, 0); - LM_DBG("received n=%d con=%p, fd=%d\n", n, con, s); + ret=n=receive_fd(fm->fd, response, sizeof(response), &s, 0); if (n<0){ if (errno == EWOULDBLOCK || errno == EAGAIN){ ret=0; @@ -783,6 +972,9 @@ inline static int handle_io(struct fd_map* fm, int idx) LM_WARN("0 bytes read\n"); break; } + con = (struct tcp_connection *)response[0]; + rw = (int)response[1]; + if (con==0){ LM_CRIT("null pointer\n"); break; @@ -800,30 +992,54 @@ inline static int handle_io(struct fd_map* fm, int idx) release_tcpconn(con, CONN_ERROR, tcpmain_sock); break; /* try to recover */ } - /* must be before io_watch_add, io_watch_add might catch some - * already existing events => might call handle_io and - * handle_io might decide to del. the new connection => - * must be in the list */ - tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev); - con->timeout=get_ticks()+TCP_CHILD_TIMEOUT; - if (io_watch_add(&io_w, s, F_TCPCONN, con)<0){ - LM_CRIT("failed to add new socket to the fd list\n"); - tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); - goto con_error; + + LM_DBG("We have received conn %p with rw %d\n",con,rw); + if (rw & IO_WATCH_READ) { + /* reset the per process TCP req struct */ + init_tcp_req(¤t_req); + /* 0 attempts so far for this SIP MSG */ + con->msg_attempts = 0; + + /* must be before io_watch_add, io_watch_add might catch some + * already existing events => might call handle_io and + * handle_io might decide to del. the new connection => + * must be in the list */ + tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev); + con->timeout=get_ticks()+tcp_max_msg_time; + if (io_watch_add(&io_w, s, F_TCPCONN, con,IO_WATCH_READ)<0){ + LM_CRIT("failed to add new socket to the fd list\n"); + tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); + goto con_error; + } + } else if (rw & IO_WATCH_WRITE) { + LM_DBG("Received con %p ref = %d\n",con,con->refcnt); + lock_get(&con->write_lock); + resp=tcp_write_async_req(con); + if (resp<0) { + lock_release(&con->write_lock); + ret=-1; /* some error occured */ + con->state=S_CONN_BAD; + release_tcpconn(con, resp, tcpmain_sock); + break; + } + + lock_release(&con->write_lock); + ret = 0; } break; case F_TCPCONN: - con=(struct tcp_connection*)fm->data; - resp=tcp_read_req(con, &ret); - if (resp<0){ - ret=-1; /* some error occured */ - io_watch_del(&io_w, con->fd, idx, IO_FD_CLOSING); - tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); - con->state=S_CONN_BAD; - release_tcpconn(con, resp, tcpmain_sock); - }else{ - /* update timeout */ - con->timeout=get_ticks()+TCP_CHILD_TIMEOUT; + if (event_type & IO_WATCH_READ) { + con=(struct tcp_connection*)fm->data; + resp=tcp_read_req(con, &ret); + if (resp<0) { + ret=-1; /* some error occured */ + io_watch_del(&io_w, con->fd, idx, IO_FD_CLOSING, + IO_WATCH_READ|IO_WATCH_WRITE); + tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); + con->state=S_CONN_BAD; + release_tcpconn(con, resp, tcpmain_sock); + break; + } } break; case F_NONE: @@ -832,10 +1048,10 @@ inline static int handle_io(struct fd_map* fm, int idx) fm->fd, fm->type, fm->data); goto error; default: - LM_CRIT("uknown fd type %d\n", fm->type); + LM_CRIT("uknown fd type %d\n", fm->type); goto error; } - + return ret; con_error: con->state=S_CONN_BAD; @@ -853,27 +1069,29 @@ static inline void tcp_receive_timeout(void) struct tcp_connection* con; struct tcp_connection* next; unsigned int ticks; - + ticks=get_ticks(); - for (con=tcp_conn_lst; con; con=next){ + for (con=tcp_conn_lst; con; con=next) { next=con->c_next; /* safe for removing */ - if (con->state<0){ /* kill bad connections */ + if (con->state<0){ /* kill bad connections */ /* S_CONN_BAD or S_CONN_ERROR, remove it */ /* fd will be closed in release_tcpconn */ - io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING); + io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING,IO_WATCH_READ); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); con->state=S_CONN_BAD; release_tcpconn(con, CONN_ERROR, tcpmain_sock); continue; } if (con->timeout<=ticks){ - /* expired, return to "tcp main" */ - LM_DBG("%p expired (%d, %d) lt=%d\n", + LM_DBG("%p expired - (%d, %d) lt=%d\n", con, con->timeout, ticks,con->lifetime); /* fd will be closed in release_tcpconn */ - io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING); + io_watch_del(&io_w, con->fd, -1, IO_FD_CLOSING,IO_WATCH_READ); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); - release_tcpconn(con, CONN_RELEASE, tcpmain_sock); + if (con->msg_attempts) + release_tcpconn(con, CONN_ERROR, tcpmain_sock); + else + release_tcpconn(con, CONN_RELEASE, tcpmain_sock); } } } @@ -882,16 +1100,17 @@ static inline void tcp_receive_timeout(void) void tcp_receive_loop(int unix_sock) { - + /* init */ tcpmain_sock=unix_sock; /* init com. socket */ if (init_io_wait(&io_w, tcp_max_fd_no, tcp_poll_method)<0) goto error; /* add the unix socket */ - if (io_watch_add(&io_w, tcpmain_sock, F_TCPMAIN, 0)<0){ + if (io_watch_add(&io_w, tcpmain_sock, F_TCPMAIN, 0,IO_WATCH_READ)<0){ LM_CRIT("failed to add socket to the fd list\n"); goto error; } + /* main loop */ switch(io_w.poll_method){ case POLL_POLL: @@ -947,7 +1166,7 @@ void tcp_receive_loop(int unix_sock) break; #endif default: - LM_CRIT("no support for poll method %s (%d)\n", + LM_CRIT("no support for poll method %s (%d)\n", poll_method_name(io_w.poll_method), io_w.poll_method); goto error; } diff --git a/tcp_server.h b/tcp_server.h index 329d1ee93e4..09db5385539 100644 --- a/tcp_server.h +++ b/tcp_server.h @@ -15,13 +15,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/*! - * \brief TCP server +/*! + * \brief TCP server */ @@ -35,7 +35,7 @@ extern int tcp_no_new_conn; /* "public" functions*/ -struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, +struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, int timeout); void tcpconn_put(struct tcp_connection* c); int tcp_send(struct socket_info* send_sock, int type, char* buf, unsigned len, diff --git a/test/13.cfg b/test/13.cfg index f6e9345d5d0..29093b087f7 100644 --- a/test/13.cfg +++ b/test/13.cfg @@ -19,7 +19,7 @@ route{ return; }; if (method == "REGISTER") { - if(!cr_route("default", "register", "$rU", "$rU", "call_id", "$avp(s:30)")) { + if(!cr_route("default", "register", "$rU", "$rU", "call_id", "$avp(extra)")) { sl_send_reply("403", "Not allowed"); } sl_send_reply("200", "OK"); diff --git a/test/14.cfg b/test/14.cfg index d2efec331fa..84a76114d36 100644 --- a/test/14.cfg +++ b/test/14.cfg @@ -19,7 +19,7 @@ route{ return; }; if (method == "REGISTER") { - if(!cr_route("default", "register", "$rU", "$rU", "call_id", "$avp(s:30)")) { + if(!cr_route("default", "register", "$rU", "$rU", "call_id", "$avp(extra)")) { sl_send_reply("403", "Not allowed"); } sl_send_reply("200", "OK"); diff --git a/test/2.cfg b/test/2.cfg index f69350e1eb2..66609c8cd26 100644 --- a/test/2.cfg +++ b/test/2.cfg @@ -55,8 +55,8 @@ loadmodule "xlog/xlog.so" modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo") modparam("mi_datagram", "socket_name", "/tmp/opensips.sock") modparam("dialog", "db_mode", 2) -modparam("tm", "fr_inv_timer_avp", "$avp(i:704)") -modparam("auth", "rpid_avp", "$avp(i:302)") +modparam("tm", "fr_inv_timer_avp", "$avp(fr_inv_timer)") +modparam("auth", "rpid_avp", "$avp(rpid)") modparam("sms", "modems", "Nokia [d=/dev/ttyS1;b=9600;m=new;l=30] ") modparam("sms", "networks", "D1 [m=10] ;d2[ m=20]") modparam("sms", "links", "NOKIA[D1;d2]") diff --git a/test/25.cfg b/test/25.cfg index 56cbc29ff45..15a16fafe05 100644 --- a/test/25.cfg +++ b/test/25.cfg @@ -19,8 +19,8 @@ modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo") route { #xlog("user: $rU\n"); - $avp(i:80) = $rU; - $avp(i:81) = $rd; + $avp(req-username) = $rU; + $avp(req-domain) = $rd; if(!lookup ("location")){ sl_send_reply("404", "Not Found"); @@ -32,7 +32,7 @@ route { exit; } - if (!check_user_blacklist("$avp(i:80)", "$avp(i:81)")) { + if (!check_user_blacklist("$avp(req-username)", "$avp(req-domain)")) { xlog("$rU user blacklisted\n"); sl_send_reply("403", "Forbidden"); exit; diff --git a/test/7.cfg b/test/7.cfg index 5dd7acda0c4..2b34e3a87d5 100644 --- a/test/7.cfg +++ b/test/7.cfg @@ -162,7 +162,7 @@ modparam("tm", "via1_matching", 1) modparam("tm", "unix_tx_timeout", 2) modparam("tm", "restart_fr_on_each_reply", 1) modparam("tm", "pass_provisional_replies", 0) -modparam("tm", "fr_inv_timer_avp", "$avp(s:callee_fr_inv_timer)") +modparam("tm", "fr_inv_timer_avp", "$avp(callee_fr_inv_timer)") loadmodule "xlog/xlog.so" modparam("xlog", "buf_size", 4096) @@ -187,7 +187,7 @@ modparam("nathelper", "rtpproxy_disable_tout", 60) modparam("nathelper", "rtpproxy_tout", 1) modparam("nathelper", "rtpproxy_retr", 5) modparam("nathelper", "sipping_method", "OPTIONS") -modparam("nathelper", "received_avp", "$avp(i:801)") +modparam("nathelper", "received_avp", "$avp(received)") loadmodule "textops/textops.so" @@ -209,7 +209,7 @@ modparam("registrar", "retry_after", 0) modparam("registrar", "method_filtering", 0) modparam("registrar", "path_mode", 2) modparam("registrar", "path_use_received", 0) -modparam("registrar", "received_avp", "$avp(i:801)") +modparam("registrar", "received_avp", "$avp(received)") loadmodule "sl/sl.so" modparam("sl", "enable_stats", 1) @@ -221,7 +221,7 @@ modparam("db_mysql", "auto_reconnect", 1) loadmodule "auth/auth.so" modparam("auth", "nonce_expire", 300) modparam("auth", "rpid_suffix", ";party=calling;id-type=subscriber;screen=yes") -modparam("auth", "rpid_avp", "$avp(s:rpid)") +modparam("auth", "rpid_avp", "$avp(rpid)") loadmodule "auth_db/auth_db.so" modparam("auth_db", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") @@ -231,7 +231,7 @@ modparam("auth_db", "password_column", "password") modparam("auth_db", "password_column_2", "ha1b") modparam("auth_db", "calculate_ha1", 1) modparam("auth_db", "use_domain", 0) -modparam("auth_db", "load_credentials", "$avp(s:caller_uuid)=uuid") +modparam("auth_db", "load_credentials", "$avp(caller_uuid)=uuid") loadmodule "uri_db/uri_db.so" modparam("uri_db", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") @@ -266,7 +266,7 @@ modparam("permissions", "source_col", "src_ip") modparam("permissions", "proto_col", "proto") modparam("permissions", "from_col", "from_pattern") modparam("permissions", "tag_col", "tag") -modparam("permissions", "peer_tag_avp", "$avp(s:peer_uuid)") +modparam("permissions", "peer_tag_avp", "$avp(peer_uuid)") loadmodule "lcr/lcr.so" modparam("lcr", "db_url", "mysql://opensips:opensipsrw@localhost/opensips") @@ -282,14 +282,14 @@ modparam("lcr", "strip_column", "strip") modparam("lcr", "prefix_column", "prefix") modparam("lcr", "from_uri_column", "from_uri") modparam("lcr", "priority_column", "priority") -modparam("lcr", "gw_uri_avp", "$avp(i:1400)") -modparam("lcr", "ruri_user_avp", "$avp(i:1402)") -modparam("lcr", "contact_avp", "$avp(i:1401)") -modparam("lcr", "fr_inv_timer_avp", "$avp(s:fr_inv_timer_avp)") +modparam("lcr", "gw_uri_avp", "$avp(gw_uri)") +modparam("lcr", "ruri_user_avp", "$avp(ruri_user)") +modparam("lcr", "contact_avp", "$avp(contact)") +modparam("lcr", "fr_inv_timer_avp", "$avp(fr_inv_timer_avp)") modparam("lcr", "fr_inv_timer", 90) modparam("lcr", "fr_inv_timer_next", 30) -modparam("lcr", "rpid_avp", "$avp(s:rpid)") -modparam("lcr", "flags_avp", "$avp(i:712)") +modparam("lcr", "rpid_avp", "$avp(rpid)") +modparam("lcr", "flags_avp", "$avp(flags)") loadmodule "uac_redirect/uac_redirect.so" modparam("uac_redirect", "default_filter", "accept") @@ -329,7 +329,7 @@ modparam("acc", "acc_from_tag_column", "from_tag") modparam("acc", "detect_direction", 1) modparam("acc", "acc_sip_code_column", "sip_code") modparam("acc", "acc_sip_reason_column", "sip_reason") -modparam("acc", "multi_leg_info", "src_leg=$avp(i:901);dst_leg=$avp(i:902)") +modparam("acc", "multi_leg_info", "src_leg=$avp(src_leg);dst_leg=$avp(dst_leg)") ######################################################################## # Request route 'main' @@ -415,8 +415,8 @@ route[0] route[1] { xlog("L_INFO", "Clear caller preferences - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); - avp_delete("$avp(s:caller_cli)/g"); - avp_delete("$avp(s:clir)/g"); + avp_delete("$avp(caller_cli)/g"); + avp_delete("$avp(clir)/g"); } @@ -426,9 +426,9 @@ route[1] route[2] { xlog("L_INFO", "Clear callee preferences - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); - avp_delete("$avp(s:callee_fr_inv_timer)/g"); - avp_delete("$avp(s:cfu)/g"); - avp_delete("$avp(s:cfc)/g"); + avp_delete("$avp(callee_fr_inv_timer)/g"); + avp_delete("$avp(cfu)/g"); + avp_delete("$avp(cfc)/g"); } @@ -438,11 +438,11 @@ route[2] route[3] { route(1); - xlog("L_INFO", "Load caller preferences for uuid '$avp(s:caller_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Load caller preferences for uuid '$avp(caller_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); # load caller avps - avp_db_load("$avp(s:caller_uuid)", "*"); - avp_copy("$avp(s:cli)", "$avp(s:caller_cli)/d"); - if(is_avp_set("$avp(s:clir)/n") && avp_check("$avp(s:clir)", "eq/i:1")) + avp_db_load("$avp(caller_uuid)", "*"); + avp_copy("$avp(cli)", "$avp(caller_cli)/d"); + if(is_avp_set("$avp(clir)/n") && avp_check("$avp(clir)", "eq/i:1")) { # mark for anonymization setflag(28); @@ -455,27 +455,27 @@ route[3] ######################################################################## route[4] { - xlog("L_INFO", "Load callee preferences for uuid '$avp(s:callee_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Load callee preferences for uuid '$avp(callee_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); # load callee avps - avp_db_load("$avp(s:callee_uuid)", "*"); - if(is_avp_set("$avp(s:cfu)/s")) + avp_db_load("$avp(callee_uuid)", "*"); + if(is_avp_set("$avp(cfu)/s")) { - xlog("L_INFO", "Call-forward-unconditional to '$avp(s:cfu)' found - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Call-forward-unconditional to '$avp(cfu)' found - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); route(8); - avp_delete("$avp(s:caller_uuid)/g"); - avp_copy("$avp(s:callee_uuid)", "$avp(s:caller_uuid)/d"); - avp_pushto("$ru", "$avp(s:cfu)"); + avp_delete("$avp(caller_uuid)/g"); + avp_copy("$avp(callee_uuid)", "$avp(caller_uuid)/d"); + avp_pushto("$ru", "$avp(cfu)"); route(3); route(14); exit; } - if(is_avp_set("$avp(s:ringtimeout)/n")) + if(is_avp_set("$avp(ringtimeout)/n")) { - xlog("L_INFO", "Setting ring timeout to $avp(s:ringtimeout) secs - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); - avp_copy("$avp(s:ringtimeout)", "$avp(s:callee_fr_inv_timer)/d"); + xlog("L_INFO", "Setting ring timeout to $avp(ringtimeout) secs - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + avp_copy("$avp(ringtimeout)", "$avp(callee_fr_inv_timer)/d"); } } @@ -485,8 +485,8 @@ route[4] ######################################################################## route[5] { - xlog("L_INFO", "Setting acc source-leg for uuid '$avp(s:caller_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); - avp_printf("$avp(i:901)", "$avp(s:caller_uuid)|$avp(s:acc_caller_user)|$avp(s:acc_caller_domain)|$avp(s:acc_state)"); + xlog("L_INFO", "Setting acc source-leg for uuid '$avp(caller_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + avp_printf("$avp(src_leg)", "$avp(caller_uuid)|$avp(acc_caller_user)|$avp(acc_caller_domain)|$avp(acc_state)"); } @@ -495,8 +495,8 @@ route[5] ######################################################################## route[6] { - xlog("L_INFO", "Setting acc destination-leg for uuid '$avp(s:callee_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); - avp_printf("$avp(i:902)", "$avp(s:callee_uuid)|$avp(s:acc_callee_user)|$avp(s:acc_callee_domain)"); + xlog("L_INFO", "Setting acc destination-leg for uuid '$avp(callee_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + avp_printf("$avp(dst_leg)", "$avp(callee_uuid)|$avp(acc_callee_user)|$avp(acc_callee_domain)"); } @@ -505,7 +505,7 @@ route[6] ######################################################################## route[7] { - xlog("L_INFO", "Accounting failed request for uuid '$avp(s:caller_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Accounting failed request for uuid '$avp(caller_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); route(5); route(6); resetflag(24); @@ -518,17 +518,17 @@ route[7] ######################################################################## route[8] { - $avp(s:acc_callee_user) = $rU; - $avp(s:acc_callee_domain) = $rd; + $avp(acc_callee_user) = $rU; + $avp(acc_callee_domain) = $rd; route(5); route(6); - avp_delete("$avp(s:acc_caller_user)"); - avp_delete("$avp(s:acc_caller_domain)"); - avp_copy("$avp(s:acc_callee_user)", "$avp(s:acc_caller_user)"); - avp_copy("$avp(s:acc_callee_domain)", "$avp(s:acc_caller_domain)"); - avp_delete("$avp(s:acc_state)/g"); - $avp(s:acc_state) = "cfu"; + avp_delete("$avp(acc_caller_user)"); + avp_delete("$avp(acc_caller_domain)"); + avp_copy("$avp(acc_callee_user)", "$avp(acc_caller_user)"); + avp_copy("$avp(acc_callee_domain)", "$avp(acc_caller_domain)"); + avp_delete("$avp(acc_state)/g"); + $avp(acc_state) = "cfu"; } @@ -616,13 +616,13 @@ route[12] { remove_hf("Remote-Party-ID"); } - if(is_avp_set("$avp(s:caller_cli)/s")) + if(is_avp_set("$avp(caller_cli)/s")) { if(!isflagset(28)) { - xlog("L_INFO", "Set caller CLI '$avp(s:caller_cli)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); - append_hf("P-Asserted-Identity: <$avp(s:caller_cli)>\r\n"); + xlog("L_INFO", "Set caller CLI '$avp(caller_cli)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + append_hf("P-Asserted-Identity: <$avp(caller_cli)>\r\n"); } } @@ -648,8 +648,8 @@ route[12] t_on_failure("2"); if(!isflagset(26)) { - $avp(s:acc_callee_user) = $rU; - $avp(s:acc_callee_domain) = $rd; + $avp(acc_callee_user) = $rU; + $avp(acc_callee_domain) = $rd; route(5); route(6); @@ -682,7 +682,7 @@ route[13] sl_send_reply("100", "Trying"); if(from_gw()) { - $avp(s:caller_uuid) = "0"; + $avp(caller_uuid) = "0"; xlog("L_INFO", "Call from PSTN' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); setflag(23); @@ -691,18 +691,18 @@ route[13] { if(allow_trusted()) { - if(is_avp_set("$avp(s:peer_uuid)/s")) + if(is_avp_set("$avp(peer_uuid)/s")) { # use tag-column from trusted-table as uuid for this caller - avp_copy("$avp(s:peer_uuid)", "$avp(s:caller_uuid)/d"); + avp_copy("$avp(peer_uuid)", "$avp(caller_uuid)/d"); } else { # if no uuid is set, use "0" as default uuid - $avp(s:caller_uuid) = "0"; + $avp(caller_uuid) = "0"; } - xlog("L_INFO", "Call from trusted peer with uuid '$avp(s:caller_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Call from trusted peer with uuid '$avp(caller_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); if(!is_domain_local("$rd")) { @@ -730,9 +730,9 @@ route[13] } } } - $avp(s:acc_caller_user) = $fU; - $avp(s:acc_caller_domain) = $fd; - $avp(s:acc_state) = "call"; + $avp(acc_caller_user) = $fU; + $avp(acc_caller_domain) = $fd; + $avp(acc_state) = "call"; route(3); if(nat_uac_test("19")) @@ -759,21 +759,21 @@ route[14] if(!is_domain_local("$rd")) { setflag(20); - $avp(s:callee_uuid) = "0"; + $avp(callee_uuid) = "0"; route(16); } - avp_delete("$avp(s:callee_uuid)"); - avp_db_query("select uuid from subscriber where username = '$rU'", "$avp(s:callee_uuid)"); - if(is_avp_set("$avp(s:callee_uuid)/s")) + avp_delete("$avp(callee_uuid)"); + avp_db_query("select uuid from subscriber where username = '$rU'", "$avp(callee_uuid)"); + if(is_avp_set("$avp(callee_uuid)/s")) { - xlog("L_INFO", "Callee is local, uuid='$avp(s:callee_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Callee is local, uuid='$avp(callee_uuid)' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); route(15); } else { - $avp(s:callee_uuid) = "0"; + $avp(callee_uuid) = "0"; xlog("L_INFO", "Callee is not local - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); route(16); @@ -792,8 +792,8 @@ route[15] { xlog("L_INFO", "Local user offline - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); - $avp(s:acc_callee_user) = $rU; - $avp(s:acc_callee_domain) = $rd; + $avp(acc_callee_user) = $rU; + $avp(acc_callee_domain) = $rd; route(7); sl_send_reply("404", "User Offline"); @@ -879,8 +879,8 @@ route[17] # For international calls, either "00" or + is prefixed, like # +49123456780 or 0049123456789. # - avp_delete("$avp(s:orig_callee_user)/g"); - $avp(s:orig_callee_user) = $rU; + avp_delete("$avp(orig_callee_user)/g"); + $avp(orig_callee_user) = $rU; if(uri =~ "^sip:(\+[1-9])?[0-9]+@") { # looks like a PSTN number @@ -900,18 +900,18 @@ route[17] { # unknown format, maybe NDC wasn't added before? - xlog("L_INFO", "Not normalized callee '$avp(s:orig_callee_user)' to E.164 format - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Not normalized callee '$avp(orig_callee_user)' to E.164 format - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); return(-1); } # else we have "+" + CC + NDC + SN - xlog("L_INFO", "Normalized callee '$avp(s:orig_callee_user)' to E.164 format '$rU' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Normalized callee '$avp(orig_callee_user)' to E.164 format '$rU' - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); return(1); } else { - xlog("L_INFO", "Not normalized callee '$avp(s:orig_callee_user)' to E.164 format - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); + xlog("L_INFO", "Not normalized callee '$avp(orig_callee_user)' to E.164 format - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); return(-1); } @@ -940,7 +940,7 @@ route[18] xlog("L_INFO", "ENUM query failed - M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n"); # ENUM query failed, revert $rU - avp_pushto("$ru/username", "$avp(s:orig_callee_user)"); + avp_pushto("$ru/username", "$avp(orig_callee_user)"); } } @@ -1060,12 +1060,12 @@ failure_route[2] } if(t_check_status("301|302")) { - avp_delete("$avp(s:acc_caller_user)/g"); - avp_delete("$avp(s:acc_caller_domain)/g"); - avp_delete("$avp(s:acc_state)/g"); - avp_copy("$avp(s:acc_callee_user)", "$avp(s:acc_caller_user)"); - avp_copy("$avp(s:acc_callee_domain)", "$avp(s:acc_caller_domain)"); - $avp(s:acc_state) = "cfc"; + avp_delete("$avp(acc_caller_user)/g"); + avp_delete("$avp(acc_caller_domain)/g"); + avp_delete("$avp(acc_state)/g"); + avp_copy("$avp(acc_callee_user)", "$avp(acc_caller_user)"); + avp_copy("$avp(acc_callee_domain)", "$avp(acc_caller_domain)"); + $avp(acc_state) = "cfc"; setflag(29); if(!get_redirects("1:1")) { @@ -1078,10 +1078,10 @@ failure_route[2] exit; } # get last URI from destination-set and set it as R-URI - avp_delete("$avp(s:tmp)/g"); - $avp(s:tmp) = $ds; - avp_subst("$avp(s:tmp)", "/.*(sip:.+@[^:;>]+).*$/\1/"); - avp_pushto("$ru", "$avp(s:tmp)"); + avp_delete("$avp(tmp)/g"); + $avp(tmp) = $ds; + avp_subst("$avp(tmp)", "/.*(sip:.+@[^:;>]+).*$/\1/"); + avp_pushto("$ru", "$avp(tmp)"); setflag(29); t_on_branch("1"); @@ -1089,15 +1089,15 @@ failure_route[2] route(14); exit; } - if($avp(s:cfc) != NULL) + if($avp(cfc) != NULL) { - avp_delete("$avp(s:acc_caller_user)/g"); - avp_delete("$avp(s:acc_caller_domain)/g"); - avp_delete("$avp(s:acc_state)/g"); - avp_copy("$avp(s:acc_callee_user)", "$avp(s:acc_caller_user)"); - avp_copy("$avp(s:acc_callee_domain)", "$avp(s:acc_caller_domain)"); - $avp(s:acc_state) = "cfc"; - avp_pushto("$ru", "$avp(s:cfc)"); + avp_delete("$avp(acc_caller_user)/g"); + avp_delete("$avp(acc_caller_domain)/g"); + avp_delete("$avp(acc_state)/g"); + avp_copy("$avp(acc_callee_user)", "$avp(acc_caller_user)"); + avp_copy("$avp(acc_callee_domain)", "$avp(acc_caller_domain)"); + $avp(acc_state) = "cfc"; + avp_pushto("$ru", "$avp(cfc)"); setflag(29); t_on_branch("1"); diff --git a/time_rec.c b/time_rec.c index 63326e74685..7da8e814448 100644 --- a/time_rec.c +++ b/time_rec.c @@ -89,7 +89,7 @@ int ac_tm_fill(ac_tm_p _atp, struct tm* _tm) _atp->t.tm_wday = _tm->tm_wday; /* day of the week */ _atp->t.tm_yday = _tm->tm_yday; /* day in the year */ _atp->t.tm_isdst = _tm->tm_isdst; /* daylight saving time */ - + _atp->mweek = ac_get_mweek(_tm); _atp->yweek = ac_get_yweek(_tm); _atp->ywday = ac_get_wday_yr(_tm); @@ -124,10 +124,10 @@ int ac_get_yweek(struct tm* _tm) #ifdef USE_YWEEK_V int days; #endif - + if(!_tm) return -1; - + #ifdef USE_YWEEK_U week = SUN_WEEK(_tm); #else @@ -137,10 +137,10 @@ int ac_get_yweek(struct tm* _tm) #ifdef USE_YWEEK_V days = ((_tm->tm_yday + 7 - (_tm->tm_wday ? _tm->tm_wday-1 : 6)) % 7); - if(days >= 4) + if(days >= 4) week++; - else - if(week == 0) + else + if(week == 0) week = 53; #endif return week; @@ -187,7 +187,7 @@ static ac_maxval_p ac_get_maxval(ac_tm_p _atp) default: _amp.mday = 31; } - + /* maximum occurrences of a week day in the year */ memset(&_tm, 0, sizeof(struct tm)); _tm.tm_year = _atp->t.tm_year; @@ -200,13 +200,13 @@ static ac_maxval_p ac_get_maxval(ac_tm_p _atp) else _v = _tm.tm_wday - _atp->t.tm_wday; _amp.ywday = (int)((_tm.tm_yday-_v)/7) + 1; - + /* maximum number of weeks in the year */ _amp.yweek = ac_get_yweek(&_tm) + 1; - + /* maximum number of the week day in the month */ _amp.mwday=(int)((_amp.mday-1-(_amp.mday-_atp->t.tm_mday)%7)/7)+1; - + /* maximum number of weeks in the month */ _v = (_atp->t.tm_wday + (_amp.mday - _atp->t.tm_mday)%7)%7; #ifdef USE_YWEEK_U @@ -221,13 +221,13 @@ static ac_maxval_p ac_get_maxval(ac_tm_p _atp) int ac_print(ac_tm_p _atp) { - static char *_wdays[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; + static char *_wdays[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; if(!_atp) { printf("\n(null)\n"); return -1; } - + printf("\nSys time: %d\nTime: %02d:%02d:%02d\n", (int)_atp->time, _atp->t.tm_hour, _atp->t.tm_min, _atp->t.tm_sec); printf("Date: %s, %04d-%02d-%02d\n", _wdays[_atp->t.tm_wday], @@ -280,10 +280,10 @@ int tr_byxxx_init(tr_byxxx_p _bxp, int _nr) shm_free(_bxp->xxx); return -1; } - + memset(_bxp->xxx, 0, _nr*sizeof(int)); memset(_bxp->req, 0, _nr*sizeof(int)); - + return 0; } @@ -332,7 +332,7 @@ int tmrec_free(tmrec_p _trp) { if(!_trp) return -1; - + tr_byxxx_free(_trp->byday); tr_byxxx_free(_trp->bymday); tr_byxxx_free(_trp->byyday); @@ -426,7 +426,7 @@ int tr_parse_byday(tmrec_p _trp, char *_in) { if(!_trp || !_in) return -1; - _trp->byday = ic_parse_byday(_in, _trp->flags); + _trp->byday = ic_parse_byday(_in, _trp->flags); return 0; } @@ -434,7 +434,7 @@ int tr_parse_bymday(tmrec_p _trp, char *_in) { if(!_trp || !_in) return -1; - _trp->bymday = ic_parse_byxxx(_in, _trp->flags); + _trp->bymday = ic_parse_byxxx(_in, _trp->flags); return 0; } @@ -442,7 +442,7 @@ int tr_parse_byyday(tmrec_p _trp, char *_in) { if(!_trp || !_in) return -1; - _trp->byyday = ic_parse_byxxx(_in, _trp->flags); + _trp->byyday = ic_parse_byxxx(_in, _trp->flags); return 0; } @@ -450,7 +450,7 @@ int tr_parse_bymonth(tmrec_p _trp, char *_in) { if(!_trp || !_in) return -1; - _trp->bymonth = ic_parse_byxxx(_in, _trp->flags); + _trp->bymonth = ic_parse_byxxx(_in, _trp->flags); return 0; } @@ -458,7 +458,7 @@ int tr_parse_byweekno(tmrec_p _trp, char *_in) { if(!_trp || !_in) return -1; - _trp->byweekno = ic_parse_byxxx(_in, _trp->flags); + _trp->byweekno = ic_parse_byxxx(_in, _trp->flags); return 0; } @@ -472,9 +472,9 @@ int tr_parse_wkst(tmrec_p _trp, char *_in) int tr_print(tmrec_p _trp) { - static char *_wdays[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; + static char *_wdays[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; int i; - + if(!_trp) { printf("\n(null)\n"); @@ -482,7 +482,7 @@ int tr_print(tmrec_p _trp) } printf("Recurrence definition\n-- start time ---\n"); printf("Sys time: %d\n", (int)_trp->dtstart); - printf("Time: %02d:%02d:%02d\n", _trp->ts.tm_hour, + printf("Time: %02d:%02d:%02d\n", _trp->ts.tm_hour, _trp->ts.tm_min, _trp->ts.tm_sec); printf("Date: %s, %04d-%02d-%02d\n", _wdays[_trp->ts.tm_wday], _trp->ts.tm_year+1900, _trp->ts.tm_mon+1, _trp->ts.tm_mday); @@ -535,9 +535,9 @@ time_t ic_parse_datetime(char *_in, struct tm *_tm) { if(!_in || !_tm || strlen(_in)!=15) return 0; - + memset(_tm, 0, sizeof(struct tm)); - _tm->tm_year = _D(_in[0])*1000 + _D(_in[1])*100 + _tm->tm_year = _D(_in[0])*1000 + _D(_in[1])*100 + _D(_in[2])*10 + _D(_in[3]) - 1900; _tm->tm_mon = _D(_in[4])*10 + _D(_in[5]) - 1; _tm->tm_mday = _D(_in[6])*10 + _D(_in[7]); @@ -553,10 +553,10 @@ time_t ic_parse_duration(char *_in) time_t _t, _ft; char *_p; int _fl; - + if(!_in || strlen(_in)<2) return 0; - + if(*_in == 'P' || *_in=='p') { _p = _in+1; @@ -565,9 +565,9 @@ time_t ic_parse_duration(char *_in) _p = _in; _fl = 0; } - + _t = _ft = 0; - + while(*_p) { switch(*_p) @@ -578,7 +578,7 @@ time_t ic_parse_duration(char *_in) case '9': _t = _t*10 + *_p - '0'; break; - + case 'w': case 'W': if(!_fl) @@ -692,7 +692,7 @@ tr_byxxx_p ic_parse_byday(char *_in, char type) case '9': _v = _v*10 + *_p - '0'; break; - + case 's': case 'S': _p++; @@ -825,7 +825,7 @@ tr_byxxx_p ic_parse_byxxx(char *_in, char type) case '9': _v = _v*10 + *_p - '0'; break; - + case '-': _s = -1; break; @@ -861,7 +861,7 @@ int ic_parse_wkst(char *_in) { if(!_in || strlen(_in)!=2) goto error; - + switch(_in[0]) { case 's': @@ -909,7 +909,7 @@ int ic_parse_wkst(char *_in) default: goto error; } - + error: #ifdef USE_YWEEK_U return WDAY_SU; @@ -948,7 +948,7 @@ int check_tmrec(tmrec_p _trp, ac_tm_p _atp, tr_res_p _tsw) /* compute the duration of the recurrence interval */ if(!_IS_SET(_trp->duration)) _trp->duration = _trp->dtend - _trp->dtstart; - + if(_atp->time <= _trp->dtstart+_trp->duration) { if(_tsw) @@ -966,11 +966,11 @@ int check_tmrec(tmrec_p _trp, ac_tm_p _atp, tr_res_p _tsw) } return REC_MATCH; } - + /* after the bound of recurrence */ if(_IS_SET(_trp->until) && _atp->time >= _trp->until + _trp->duration) return REC_NOMATCH; - + /* check if the instance of recurrence matches the 'interval' */ if(check_freq_interval(_trp, _atp)!=REC_MATCH) return REC_NOMATCH; @@ -991,13 +991,13 @@ int check_freq_interval(tmrec_p _trp, ac_tm_p _atp) struct tm _tm; if(!_trp || !_atp) return REC_ERR; - + if(!_IS_SET(_trp->freq)) return REC_NOMATCH; - + if(!_IS_SET(_trp->interval) || _trp->interval==1) return REC_MATCH; - + switch(_trp->freq) { case FREQ_DAILY: @@ -1032,7 +1032,7 @@ int check_freq_interval(tmrec_p _trp, ac_tm_p _atp) return ((_atp->t.tm_year-_trp->ts.tm_year)%_trp->interval==0)? REC_MATCH:REC_NOMATCH; } - + return REC_NOMATCH; } @@ -1040,16 +1040,16 @@ int get_min_interval(tmrec_p _trp) { if(!_trp) return FREQ_NOFREQ; - + if(_trp->freq == FREQ_DAILY || _trp->byday || _trp->bymday || _trp->byyday) return FREQ_DAILY; - if(_trp->freq == FREQ_WEEKLY || _trp->byweekno) + if(_trp->freq == FREQ_WEEKLY || _trp->byweekno) return FREQ_WEEKLY; if(_trp->freq == FREQ_MONTHLY || _trp->bymonth) return FREQ_MONTHLY; if(_trp->freq == FREQ_YEARLY) return FREQ_YEARLY; - + return FREQ_NOFREQ; } @@ -1071,7 +1071,7 @@ int check_min_unit(tmrec_p _trp, ac_tm_p _atp, tr_res_p _tsw) return REC_NOMATCH; break; case FREQ_YEARLY: - if(_trp->ts.tm_mon != _atp->t.tm_mon + if(_trp->ts.tm_mon != _atp->t.tm_mon || _trp->ts.tm_mday != _atp->t.tm_mday) return REC_NOMATCH; break; @@ -1097,7 +1097,7 @@ int check_min_unit(tmrec_p _trp, ac_tm_p _atp, tr_res_p _tsw) } return REC_MATCH; } - + return REC_NOMATCH; } @@ -1108,7 +1108,7 @@ int check_byxxx(tmrec_p _trp, ac_tm_p _atp) if(!_trp || !_atp) return REC_ERR; - if(!_trp->byday && !_trp->bymday && !_trp->byyday && !_trp->bymonth + if(!_trp->byday && !_trp->bymday && !_trp->byyday && !_trp->bymonth && !_trp->byweekno) return REC_MATCH; @@ -1118,7 +1118,7 @@ int check_byxxx(tmrec_p _trp, ac_tm_p _atp) { for(i=0; i<_trp->bymonth->nr; i++) { - if(_atp->t.tm_mon == + if(_atp->t.tm_mon == (_trp->bymonth->xxx[i]*_trp->bymonth->req[i]+12)%12) break; } @@ -1171,7 +1171,7 @@ int check_byxxx(tmrec_p _trp, ac_tm_p _atp) { #ifdef EXTRA_DEBUG LM_DBG("%d==%d && %d==%d\n", _atp->t.tm_wday, - _trp->byday->xxx[i], _atp->ywday+1, + _trp->byday->xxx[i], _atp->ywday+1, (_trp->byday->req[i]+_amp->ywday)%_amp->ywday); #endif if(_atp->t.tm_wday == _trp->byday->xxx[i] && @@ -1185,7 +1185,7 @@ int check_byxxx(tmrec_p _trp, ac_tm_p _atp) { #ifdef EXTRA_DEBUG LM_DBG("%d==%d && %d==%d\n", _atp->t.tm_wday, - _trp->byday->xxx[i], _atp->mwday+1, + _trp->byday->xxx[i], _atp->mwday+1, (_trp->byday->req[i]+_amp->mwday)%_amp->mwday); #endif if(_atp->t.tm_wday == _trp->byday->xxx[i] && diff --git a/timer.c b/timer.c index dc5b037dfc8..5eac62dbf17 100644 --- a/timer.c +++ b/timer.c @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -172,7 +172,7 @@ static inline struct sr_timer* new_sr_timer(char *label, timer_function f, /*register a periodic timer; * ret: <0 on error - * Hint: if you need it in a module, register it from mod_init or it + * Hint: if you need it in a module, register it from mod_init or it * won't work otherwise*/ int register_timer(char *label, timer_function f, void* param, unsigned int interval) @@ -370,7 +370,7 @@ static inline void timer_ticker(struct sr_timer *timer_list, utime_t *drift) utime_t ij; utime_t ij_marker; - /* we need to store the original time as while executing the + /* we need to store the original time as while executing the the handlers, the time may progress, affecting the way we calculate the new expire (expire will include the time taken to run handlers) -bogdan */ @@ -457,6 +457,12 @@ static void run_timer_process(struct sr_timer_process *tpl) multiple = (( TIMER_TICK * 1000000 ) / UTIMER_TICK ) / 1000000; } + if (tpl->utimer_list && tpl->utimer_list->label) { + set_proc_attrs("timer: %s", tpl->utimer_list->label); + } else if (tpl->timer_list && tpl->timer_list->label) { + set_proc_attrs("timer: %s", tpl->timer_list->label); + } + LM_DBG("tv = %ld, %ld , m=%d\n", (long)o_tv.tv_sec,(long)o_tv.tv_usec,multiple); @@ -564,7 +570,7 @@ int start_timer_processes(void) * * The main reason for this change was when a function that relied * on jiffies for its timeouts got called from the timer thread and - * was unable to detect timeouts. + * was unable to detect timeouts. */ if ( (pid=internal_fork("time_keeper"))<0 ) { @@ -601,7 +607,7 @@ int start_timer_processes(void) exit(-1); } - if (send_status_code(0) < 0) + if (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); } else diff --git a/timer.h b/timer.h index 75994c79a35..88c6810163f 100644 --- a/timer.h +++ b/timer.h @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: diff --git a/tls/README b/tls/README index 2c24a66d5bb..2cec8a3f60a 100644 --- a/tls/README +++ b/tls/README @@ -779,7 +779,7 @@ route{ ... # calls to other SIP domains # set the proper SSL context (certificate) for local hosted domains - avp_write("$fd","$avp(i:400)"); + avp_write("$fd","$avp(fd)"); t_relay(); # uses NAPTR and SRV lookups exit; ... diff --git a/tls/doc/tls.sgml b/tls/doc/tls.sgml index b185b7d628a..d551c92392c 100644 --- a/tls/doc/tls.sgml +++ b/tls/doc/tls.sgml @@ -45,6 +45,13 @@ klaus.darilion@nic.at + + Christian + Lahme +
+ christian.lahme@secusmart.com +
+
2005 @@ -58,6 +65,10 @@ 2006 enum.at + + 2013 + Secusmart GmbH + $Revision$ diff --git a/tls/doc/tls_user.sgml b/tls/doc/tls_user.sgml index f9b8db4142e..e68203df16c 100644 --- a/tls/doc/tls_user.sgml +++ b/tls/doc/tls_user.sgml @@ -202,7 +202,7 @@
Dependencies of external libraries - &ser; TLS support requires the following packages: + &ser; TLS v1.0 support requires the following packages: openssl or @@ -216,6 +216,21 @@ + + &ser; TLS v1.1/1.2 support requires the following packages: + + + openssl or + libssl >= 1.0.1e + + + + openssl-dev or + libssl-dev + + + +
@@ -468,6 +483,11 @@ tls_port_no = 5062 Sets the TLS protocol method which can be: + + TLSv1_2 - means &ser; will + accept only TLSv1.2 connections (rfc3261 conformant). + + TLSv1 - means &ser; will accept only TLSv1 connections (rfc3261 conformant). @@ -601,6 +621,33 @@ tls_private_key="/mycerts/private/prik.pem" ... tls_ca_list="/mycerts/certs/ca_list.pem" +... + + + + +
+ <varname>tls_ca_dir</varname>=path + + Directory storing trusted CAs. The path contains the + certificates accepted, each as hash which is linked to + certificate file. + + + See previous chapter for more + information. + + + It's usable only if TLS support was compiled. + + + Default value is "". + + + Set <varname>tls_ca_dir</varname> variable + +... +tls_ca_dir="/mycerts/certs" ... @@ -638,6 +685,48 @@ tls_ciphers_list="NULL"
+
+ <varname>tls_dh_params</varname>=file + + You can specify a file which contains Diffie-Hellman + parameters as a PEM-file. This is needed if you would like + to specify ciphers including Diffie-Hellman mode. + + + It's usable only if TLS support was compiled. + + + It defaults to not set a dh param file. + + + Set <varname>tls_dh_params</varname> variable + + +... +tls_dh_param="/etc/pki/CA/dh1024.pem" +... + + +
+ +
+ <varname>tls_ec_curve</varname>=string + + You can specify an elliptic curve which should be used for + ciphers which demand an elliptic curve. + + + It's usable only if TLS v1.1/1.2 support was compiled. + A list of curves which can be used you can get by + + openssl ecparam -list_curve + + + + It defaults to not set a elliptic curve. + +
+
<varname>tls_verify_client</varname>=number and <varname>tls_require_client_certificate</varname>=number @@ -887,7 +976,7 @@ route{ ... # calls to other SIP domains # set the proper SSL context (certificate) for local hosted domains - avp_write("$fd","$avp(i:400)"); + avp_write("$fd","$avp(fd)"); t_relay(); # uses NAPTR and SRV lookups exit; ... diff --git a/tls/tls_config.c b/tls/tls_config.c index 42ccef79a47..ef98dd985c3 100644 --- a/tls/tls_config.c +++ b/tls/tls_config.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -43,6 +43,8 @@ int tls_require_client_cert = 1; char *tls_cert_file = TLS_CERT_FILE; char *tls_pkey_file = TLS_PKEY_FILE; char *tls_ca_file = TLS_CA_FILE; +char *tls_ca_dir = TLS_CA_DIRECTORY; +char *tls_tmp_dh_file = TLS_DH_PARAMS_FILE; /* defaul cipher=0, this means the DEFAULT ciphers */ char *tls_ciphers_list = 0; /* TLS timeouts; should be low to detect problems fast */ diff --git a/tls/tls_config.h b/tls/tls_config.h index 17d17d85ace..c05672bf133 100644 --- a/tls/tls_config.h +++ b/tls/tls_config.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -39,7 +39,10 @@ enum tls_method { TLS_USE_TLSv1, TLS_USE_SSLv23_cli, TLS_USE_SSLv23_srv, - TLS_USE_SSLv23 + TLS_USE_SSLv23, + TLS_USE_TLSv1_2_cli, + TLS_USE_TLSv1_2_srv, + TLS_USE_TLSv1_2 }; extern int tls_log; @@ -51,6 +54,8 @@ extern int tls_require_client_cert; extern char *tls_cert_file; extern char *tls_pkey_file; extern char *tls_ca_file; +extern char *tls_ca_dir; +extern char *tls_tmp_dh_file; extern char *tls_ciphers_list; extern int tls_handshake_timeout; extern int tls_send_timeout; diff --git a/tls/tls_domain.c b/tls/tls_domain.c index 320c2d69889..ef05e0fc5af 100644 --- a/tls/tls_domain.c +++ b/tls/tls_domain.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -32,7 +32,7 @@ struct tls_domain *tls_default_server_domain = NULL; struct tls_domain *tls_default_client_domain = NULL; /* - * find server domain with given ip and port + * find server domain with given ip and port * return default domain if virtual domain not found */ struct tls_domain * @@ -199,7 +199,7 @@ struct tls_domain *tls_new_domain(int type) } /* - * clean up + * clean up */ void tls_free_domains(void) diff --git a/tls/tls_domain.h b/tls/tls_domain.h index 148b5671e0c..339e74ded2b 100644 --- a/tls/tls_domain.h +++ b/tls/tls_domain.h @@ -18,8 +18,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -42,7 +42,7 @@ enum tls_domain_type { }; /* - * separate configuration per ip:port + * separate configuration per ip:port */ struct tls_domain { int type; @@ -54,6 +54,9 @@ struct tls_domain { char *cert_file; char *pkey_file; char *ca_file; + char *tmp_dh_file; + char *tls_ec_curve; + char *ca_directory; char *ciphers_list; enum tls_method method; struct tls_domain *next; @@ -66,19 +69,19 @@ extern struct tls_domain *tls_default_server_domain; extern struct tls_domain *tls_default_client_domain; /* - * find domain with given ip and port + * find domain with given ip and port */ struct tls_domain *tls_find_server_domain(struct ip_addr *ip, unsigned short port); /* - * find client with given ip and port + * find client with given ip and port */ struct tls_domain *tls_find_client_domain(struct ip_addr *ip, unsigned short port); /* - * find domain with given name + * find domain with given name */ struct tls_domain *tls_find_client_domain_name(str name); @@ -104,7 +107,7 @@ int tls_new_client_domain_name(char *s, int len); struct tls_domain *tls_new_domain(int type); /* - * clean up + * clean up */ void tls_free_domains(void); diff --git a/tls/tls_init.c b/tls/tls_init.c index e716f2a4e18..d2cec3b70bf 100644 --- a/tls/tls_init.c +++ b/tls/tls_init.c @@ -17,13 +17,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include - + #include "tls_init.h" #include "tls_config.h" #include "../dprint.h" @@ -43,20 +43,19 @@ #include #include -#define SER_SSL_SESS_ID ((unsigned char*)"opensips-tls-1.2.0") -#define SER_SSL_SESS_ID_LEN (sizeof(SER_SSL_SESS_ID)-1) - +#define OS_SSL_SESS_ID ((unsigned char*)"opensips-tls-1.11.0") +#define OS_SSL_SESS_ID_LEN (sizeof(OS_SSL_SESS_ID)-1) -#if OPENSSL_VERSION_NUMBER < 0x00907000L +#if OPENSSL_VERSION_NUMBER < 0x10001000L #warning "" #warning "==============================================================" - #warning "Your version of OpenSSL is < 0.9.7." + #warning "Your version of OpenSSL is < 1.0.1." #warning " Upgrade for better compatibility, features and security fixes!" #warning "=============================================================" #warning "" #endif -SSL_METHOD *ssl_methods[TLS_USE_SSLv23 + 1]; +SSL_METHOD *ssl_methods[TLS_USE_TLSv1_2 + 1]; #define VERIFY_DEPTH_S 3 @@ -67,7 +66,7 @@ struct CRYPTO_dynlock_value { gen_lock_t lock; }; -/* This callback is called during each verification process, +/* This callback is called during each verification process, at each step during the chain of certificates (this function is not the certificate_verification one!). */ int verify_callback(int pre_verify_ok, X509_STORE_CTX *ctx) { @@ -81,21 +80,21 @@ int verify_callback(int pre_verify_ok, X509_STORE_CTX *ctx) { LM_NOTICE("cert chain too long ( depth > VERIFY_DEPTH_S)\n"); pre_verify_ok=0; } - + if( pre_verify_ok ) { LM_NOTICE("preverify is good: verify return: %d\n", pre_verify_ok); return pre_verify_ok; } - + err_cert = X509_STORE_CTX_get_current_cert(ctx); - err = X509_STORE_CTX_get_error(ctx); + err = X509_STORE_CTX_get_error(ctx); X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof buf); - + LM_NOTICE("subject = %s\n", buf); LM_NOTICE("verify error:num=%d:%s\n", err, X509_verify_cert_error_string(err)); LM_NOTICE("error code is %d\n", ctx->error); - + switch (ctx->error) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), @@ -145,13 +144,13 @@ int verify_callback(int pre_verify_ok, X509_STORE_CTX *ctx) { case X509_V_ERR_CERT_REJECTED: LM_NOTICE("certificate rejected\n"); break; - + default: LM_NOTICE("something wrong with the cert" " ... error code is %d (check x509_vfy.h)\n", ctx->error); break; } - + LM_NOTICE("verify return:%d\n", pre_verify_ok); return(pre_verify_ok); } @@ -163,7 +162,7 @@ passwd_cb(char *buf, int size, int rwflag, void *filename) #if OPENSSL_VERSION_NUMBER >= 0x00907000L UI *ui; const char *prompt; - + ui = UI_new(); if (ui == NULL) goto err; @@ -179,14 +178,14 @@ passwd_cb(char *buf, int size, int rwflag, void *filename) if (ui) UI_free(ui); return 0; - + #else if( des_read_pw_string(buf, size-1, "Enter Private Key password:", 0) ) { LM_ERR("passwd_cb failed\n"); return 0; } return strlen( buf ); - + #endif } @@ -211,7 +210,8 @@ ser_realloc(void *ptr, size_t size) static void ser_free(void *ptr) { - shm_free(ptr); + if (ptr) + shm_free(ptr); } @@ -219,9 +219,9 @@ int tls_init(struct socket_info *si) { LM_DBG("entered\n"); - + /* - * reuse tcp initialization + * reuse tcp initialization */ if (tcp_init(si) < 0) { LM_ERR("failed to initialize TCP part\n"); @@ -240,8 +240,8 @@ tls_init(struct socket_info *si) } /* - * load a certificate from a file - * (certificate file can be a chain, starting by the user cert, + * load a certificate from a file + * (certificate file can be a chain, starting by the user cert, * and ending in the root CA; if not all needed certs are in this * file, they are looked up in the caFile or caPATH (see verify * function). @@ -263,14 +263,14 @@ load_certificate(SSL_CTX * ctx, char *filename) #define NUM_RETRIES 3 /* - * load a private key from a file + * load a private key from a file */ static int load_private_key(SSL_CTX * ctx, char *filename) { int idx, ret_pwd; LM_DBG("entered\n"); - + SSL_CTX_set_default_passwd_cb(ctx, passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(ctx, filename); @@ -285,24 +285,24 @@ load_private_key(SSL_CTX * ctx, char *filename) continue; } } - + if( ! ret_pwd ) { LM_ERR("unable to load private key file '%s'\n", filename); return -1; } - + if (!SSL_CTX_check_private_key(ctx)) { LM_ERR("key '%s' does not match the public key of the certificate\n", filename); return -1; } - + LM_DBG("key '%s' successfuly loaded\n", filename); return 0; } -/* +/* * Load a caList, to be used to verify the client's certificate. * The list is to be stored in a single file, containing all * the acceptable root certificates. @@ -315,14 +315,93 @@ load_ca(SSL_CTX * ctx, char *filename) LM_ERR("unable to load ca '%s'\n", filename); return -1; } - + LM_DBG("CA '%s' successfuly loaded\n", filename); return 0; } /* - * initialize ssl methods + * Load a caList from a directory instead of a single file. + */ +static int +load_ca_dir(SSL_CTX * ctx, char *directory) +{ + LM_DBG("Entered\n"); + if (!SSL_CTX_load_verify_locations(ctx, 0 , directory)) { + LM_ERR("unable to load ca directory '%s'\n", directory); + return -1; + } + + LM_DBG("CA '%s' successfuly loaded from directory\n", directory); + return 0; +} + + +#if (OPENSSL_VERSION_NUMBER > 0x10001000L) +/* + * Load and set DH params to be used in ephemeral key exchange from a file. + */ +static int +set_dh_params(SSL_CTX * ctx, char *filename) +{ + LM_DBG("Entered\n"); + BIO *bio = BIO_new_file(filename, "r"); + if (!bio) { + LM_ERR("unable to open dh params file '%s'\n", filename); + return -1; + } + + DH *dh = PEM_read_bio_DHparams(bio, 0, 0, 0); + BIO_free(bio); + if (!dh) { + LM_ERR("unable to read dh params from '%s'\n", filename); + return -1; + } + + if (!SSL_CTX_set_tmp_dh(ctx, dh)) { + LM_ERR("unable to set dh params\n"); + return -1; + } + + DH_free(dh); + LM_DBG("DH params from '%s' successfuly set\n", filename); + return 0; +} + + +/* + * Set elliptic curve. + */ +static int set_ec_params(SSL_CTX * ctx, const char* curve_name) +{ + int curve = 0; + if (curve_name) { + curve = OBJ_txt2nid(curve_name); + } + if (curve > 0) { + EC_KEY *ecdh = EC_KEY_new_by_curve_name (curve); + if (! ecdh) { + LM_ERR("unable to create EC curve\n"); + return -1; + } + if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) { + LM_ERR("unable to set tmp_ecdh\n"); + return -1; + } + EC_KEY_free (ecdh); + } + else { + LM_ERR("unable to find the EC curve\n"); + return -1; + } + return 0; +} +#endif + + +/* + * initialize ssl methods */ static void init_ssl_methods(void) @@ -330,22 +409,29 @@ init_ssl_methods(void) LM_DBG("entered\n"); #ifndef OPENSSL_NO_SSL2 - ssl_methods[TLS_USE_SSLv2_cli - 1] = SSLv2_client_method(); - ssl_methods[TLS_USE_SSLv2_srv - 1] = SSLv2_server_method(); - ssl_methods[TLS_USE_SSLv2 - 1] = SSLv2_method(); + ssl_methods[TLS_USE_SSLv2_cli - 1] = (SSL_METHOD*)SSLv2_client_method(); + ssl_methods[TLS_USE_SSLv2_srv - 1] = (SSL_METHOD*)SSLv2_server_method(); + ssl_methods[TLS_USE_SSLv2 - 1] = (SSL_METHOD*)SSLv2_method(); +#endif + + ssl_methods[TLS_USE_SSLv3_cli - 1] = (SSL_METHOD*)SSLv3_client_method(); + ssl_methods[TLS_USE_SSLv3_srv - 1] = (SSL_METHOD*)SSLv3_server_method(); + ssl_methods[TLS_USE_SSLv3 - 1] = (SSL_METHOD*)SSLv3_method(); + + ssl_methods[TLS_USE_TLSv1_cli - 1] = (SSL_METHOD*)TLSv1_client_method(); + ssl_methods[TLS_USE_TLSv1_srv - 1] = (SSL_METHOD*)TLSv1_server_method(); + ssl_methods[TLS_USE_TLSv1 - 1] = (SSL_METHOD*)TLSv1_method(); + + ssl_methods[TLS_USE_SSLv23_cli - 1] = (SSL_METHOD*)SSLv23_client_method(); + ssl_methods[TLS_USE_SSLv23_srv - 1] = (SSL_METHOD*)SSLv23_server_method(); + ssl_methods[TLS_USE_SSLv23 - 1] = (SSL_METHOD*)SSLv23_method(); + +#if OPENSSL_VERSION_NUMBER >= 0x10001000L + ssl_methods[TLS_USE_TLSv1_2_cli - 1] = (SSL_METHOD*)TLSv1_2_client_method(); + ssl_methods[TLS_USE_TLSv1_2_srv - 1] = (SSL_METHOD*)TLSv1_2_server_method(); + ssl_methods[TLS_USE_TLSv1_2 - 1] = (SSL_METHOD*)TLSv1_2_method(); #endif - ssl_methods[TLS_USE_SSLv3_cli - 1] = SSLv3_client_method(); - ssl_methods[TLS_USE_SSLv3_srv - 1] = SSLv3_server_method(); - ssl_methods[TLS_USE_SSLv3 - 1] = SSLv3_method(); - - ssl_methods[TLS_USE_TLSv1_cli - 1] = TLSv1_client_method(); - ssl_methods[TLS_USE_TLSv1_srv - 1] = TLSv1_server_method(); - ssl_methods[TLS_USE_TLSv1 - 1] = TLSv1_method(); - - ssl_methods[TLS_USE_SSLv23_cli - 1] = SSLv23_client_method(); - ssl_methods[TLS_USE_SSLv23_srv - 1] = SSLv23_server_method(); - ssl_methods[TLS_USE_SSLv23 - 1] = SSLv23_method(); } @@ -356,6 +442,35 @@ init_ssl_methods(void) static int init_ssl_ctx_behavior( struct tls_domain *d ) { int verify_mode; + +#if (OPENSSL_VERSION_NUMBER > 0x10001000L) + /* + * set dh params + */ + if (!d->tmp_dh_file) { + LM_DBG("no DH params file for tls[%s:%d] defined, " + "using default '%s'\n", ip_addr2a(&d->addr), d->port, + tls_tmp_dh_file); + d->tmp_dh_file = tls_tmp_dh_file; + } + if (d->tmp_dh_file && set_dh_params(d->ctx, d->tmp_dh_file) < 0) + return -1; + + if (d->tls_ec_curve) { + if (set_ec_params(d->ctx, d->tls_ec_curve) < 0) { + return -1; + } + } + else { + LM_NOTICE("No EC curve defined\n"); + } +#else + if (d->tmp_dh_file || tls_tmp_dh_file) + LM_WARN("DH params file discarded as not supported by your openSSL version\n"); + if (d->tls_ec_curve) + LM_WARN("EC params file discarded as not supported by your openSSL version\n"); +#endif + if( d->ciphers_list != 0 ) { if( SSL_CTX_set_cipher_list(d->ctx, d->ciphers_list) == 0 ) { LM_ERR("failure to set SSL context " @@ -368,13 +483,13 @@ init_ssl_ctx_behavior( struct tls_domain *d ) { LM_DBG( "cipher list null ... setting default\n"); } - /* Set a bunch of options: + /* Set a bunch of options: * do not accept SSLv2 * no session resumption * choose cipher according to server's preference's*/ #if OPENSSL_VERSION_NUMBER >= 0x000907000 - SSL_CTX_set_options(d->ctx, + SSL_CTX_set_options(d->ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE); @@ -384,8 +499,8 @@ init_ssl_ctx_behavior( struct tls_domain *d ) { #endif /* Set verification procedure - * The verification can be made null with SSL_VERIFY_NONE, or - * at least easier with SSL_VERIFY_CLIENT_ONCE instead of + * The verification can be made null with SSL_VERIFY_NONE, or + * at least easier with SSL_VERIFY_CLIENT_ONCE instead of * SSL_VERIFY_FAIL_IF_NO_PEER_CERT. * For extra control, instead of 0, we can specify a callback function: * int (*verify_callback)(int, X509_STORE_CTX *) @@ -395,23 +510,23 @@ init_ssl_ctx_behavior( struct tls_domain *d ) { if (d->type & TLS_DOMAIN_SRV) { /* Server mode: * SSL_VERIFY_NONE - * the server will not send a client certificate request to the + * the server will not send a client certificate request to the * client, so the client will not send a certificate. * SSL_VERIFY_PEER - * the server sends a client certificate request to the client. - * The certificate returned (if any) is checked. If the verification - * process fails, the TLS/SSL handshake is immediately terminated - * with an alert message containing the reason for the verification - * failure. The behaviour can be controlled by the additional + * the server sends a client certificate request to the client. + * The certificate returned (if any) is checked. If the verification + * process fails, the TLS/SSL handshake is immediately terminated + * with an alert message containing the reason for the verification + * failure. The behaviour can be controlled by the additional * SSL_VERIFY_FAIL_IF_NO_PEER_CERT and SSL_VERIFY_CLIENT_ONCE flags. * SSL_VERIFY_FAIL_IF_NO_PEER_CERT - * if the client did not return a certificate, the TLS/SSL handshake - * is immediately terminated with a ``handshake failure'' alert. + * if the client did not return a certificate, the TLS/SSL handshake + * is immediately terminated with a ``handshake failure'' alert. * This flag must be used together with SSL_VERIFY_PEER. * SSL_VERIFY_CLIENT_ONCE - * only request a client certificate on the initial TLS/SSL - * handshake. Do not ask for a client certificate again in case of - * a renegotiation. This flag must be used together with + * only request a client certificate on the initial TLS/SSL + * handshake. Do not ask for a client certificate again in case of + * a renegotiation. This flag must be used together with * SSL_VERIFY_PEER. */ @@ -431,17 +546,17 @@ init_ssl_ctx_behavior( struct tls_domain *d ) { } else { /* Client mode: * SSL_VERIFY_NONE - * if not using an anonymous cipher (by default disabled), the - * server will send a certificate which will be checked. The result - * of the certificate verification process can be checked after the + * if not using an anonymous cipher (by default disabled), the + * server will send a certificate which will be checked. The result + * of the certificate verification process can be checked after the * TLS/SSL handshake using the SSL_get_verify_result(3) function. - * The handshake will be continued regardless of the verification + * The handshake will be continued regardless of the verification * result. * SSL_VERIFY_PEER - * the server certificate is verified. If the verification process - * fails, the TLS/SSL handshake is immediately terminated with an + * the server certificate is verified. If the verification process + * fails, the TLS/SSL handshake is immediately terminated with an * alert message containing the reason for the verification failure. - * If no server certificate is sent, because an anonymous cipher is + * If no server certificate is sent, because an anonymous cipher is * used, SSL_VERIFY_PEER is ignored. * SSL_VERIFY_FAIL_IF_NO_PEER_CERT * ignored @@ -457,13 +572,13 @@ init_ssl_ctx_behavior( struct tls_domain *d ) { LM_WARN("server verification NOT activated. Weaker security.\n"); } } - + SSL_CTX_set_verify( d->ctx, verify_mode, verify_callback); SSL_CTX_set_verify_depth( d->ctx, VERIFY_DEPTH_S); SSL_CTX_set_session_cache_mode( d->ctx, SSL_SESS_CACHE_SERVER ); - SSL_CTX_set_session_id_context( d->ctx, SER_SSL_SESS_ID, - SER_SSL_SESS_ID_LEN ); + SSL_CTX_set_session_id_context( d->ctx, OS_SSL_SESS_ID, + OS_SSL_SESS_ID_LEN ); return 0; } @@ -556,7 +671,7 @@ int tls_init_multithread(void) if (tls_static_locks_no>0) { /* init a lock set & pass locking function to SSL */ - tls_static_locks = lock_set_alloc(tls_static_locks_no); + tls_static_locks = lock_set_alloc(tls_static_locks_no); if (tls_static_locks == NULL) { LM_ERR("Failed to alloc static locks\n"); return -1; @@ -580,7 +695,7 @@ int tls_init_multithread(void) } /* - * called once from main.c (main process) + * called once from main.c (main process) */ int init_tls(void) @@ -598,7 +713,7 @@ init_tls(void) /* * this has to be called before any function calling CRYPTO_malloc, - * CRYPTO_malloc will set allow_customize in openssl to 0 + * CRYPTO_malloc will set allow_customize in openssl to 0 */ if (!CRYPTO_set_mem_functions(ser_malloc, ser_realloc, ser_free)) { LM_ERR("unable to set the memory allocation functions\n"); @@ -631,7 +746,7 @@ init_tls(void) return -1; } - if ( ( i ^ + if ( ( i ^ #ifndef OPENSSL_NO_KRB5 1 #else @@ -645,7 +760,7 @@ init_tls(void) } /* - * now initialize tls default domains + * now initialize tls default domains */ if ( (i=init_tls_domains(tls_default_server_domain)) ) { return i; @@ -654,7 +769,7 @@ init_tls(void) return i; } /* - * now initialize tls virtual domains + * now initialize tls virtual domains */ if ( (i=init_tls_domains(tls_server_domains)) ) { return i; @@ -663,7 +778,7 @@ init_tls(void) return i; } /* - * we are all set + * we are all set */ return 0; } @@ -687,16 +802,16 @@ init_tls_domains(struct tls_domain *d) } /* - * set method + * set method */ if (d->method == TLS_METHOD_UNSPEC) { LM_DBG("no method for tls[%s:%d], using default\n", ip_addr2a(&d->addr), d->port); d->method = tls_method; } - + /* - * create context + * create context */ d->ctx = SSL_CTX_new(ssl_methods[d->method - 1]); if (d->ctx == NULL) { @@ -708,7 +823,7 @@ init_tls_domains(struct tls_domain *d) return -1; /* - * load certificate + * load certificate */ if (!d->cert_file) { LM_NOTICE("no certificate for tls[%s:%d] defined, using default" @@ -717,9 +832,9 @@ init_tls_domains(struct tls_domain *d) } if (load_certificate(d->ctx, d->cert_file) < 0) return -1; - + /* - * load ca + * load ca */ if (!d->ca_file) { LM_NOTICE("no CA for tls[%s:%d] defined, " @@ -729,11 +844,26 @@ init_tls_domains(struct tls_domain *d) } if (d->ca_file && load_ca(d->ctx, d->ca_file) < 0) return -1; + + /* + * load ca from directory + */ + if (!d->ca_directory) { + + LM_NOTICE("no CA for tls[%s:%d] defined, " + "using default '%s'\n", ip_addr2a(&d->addr), d->port, + tls_ca_dir); + d->ca_directory = tls_ca_dir; + } + + if (d->ca_directory && load_ca_dir(d->ctx, d->ca_directory) < 0) + return -1; + d = d->next; } /* - * load all private keys as the last step (may prompt for password) + * load all private keys as the last step (may prompt for password) */ d = dom; while (d) { @@ -750,14 +880,14 @@ init_tls_domains(struct tls_domain *d) } /* - * called from main.c when opensips exits (main process) + * called from main.c when opensips exits (main process) */ void destroy_tls(void) { struct tls_domain *d; LM_DBG("entered\n"); - + d = tls_server_domains; while (d) { if (d->ctx) diff --git a/tls/tls_init.h b/tls/tls_init.h index 22f131f887e..91c7874edf7 100644 --- a/tls/tls_init.h +++ b/tls/tls_init.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -31,12 +31,12 @@ #include "../tcp_conn.h" /* - * just once before cleanup + * just once before cleanup */ void destroy_tls(void); /* - * for each socket + * for each socket */ int tls_init(struct socket_info *si); @@ -47,7 +47,7 @@ int tls_init(struct socket_info *si); int pre_init_tls(void); /* - * just once, initialize the tls subsystem + * just once, initialize the tls subsystem */ int init_tls(void); diff --git a/tls/tls_server.c b/tls/tls_server.c index 433473f9f7b..733e9ef726d 100644 --- a/tls/tls_server.c +++ b/tls/tls_server.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include @@ -61,13 +61,13 @@ /* - * Update ssl structure with new fd + * Update ssl structure with new fd */ static int tls_update_fd(struct tcp_connection *c, int fd) { /* - * must be run from within a lock + * must be run from within a lock */ SSL *ssl; @@ -84,7 +84,7 @@ tls_update_fd(struct tcp_connection *c, int fd) /* - * dump ssl error stack + * dump ssl error stack */ void tls_print_errstack(void) @@ -213,7 +213,7 @@ static void tls_dump_verification_failure(long verification_result) } /* - * Wrapper around SSL_accept, returns -1 on error, 0 on success + * Wrapper around SSL_accept, returns -1 on error, 0 on success */ static int tls_accept(struct tcp_connection *c, short *poll_events) @@ -277,7 +277,7 @@ tls_accept(struct tcp_connection *c, short *poll_events) LM_INFO("TLS connection from %s:%d accept failed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); c->state = S_CONN_BAD; return -1; - + case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; @@ -286,7 +286,7 @@ tls_accept(struct tcp_connection *c, short *poll_events) if (poll_events) *poll_events = POLLOUT; return 0; - + default: c->state = S_CONN_BAD; if (errno == 0) { @@ -306,7 +306,7 @@ tls_accept(struct tcp_connection *c, short *poll_events) /* - * wrapper around SSL_connect, returns 0 on success, -1 on error + * wrapper around SSL_connect, returns 0 on success, -1 on error */ static int tls_connect(struct tcp_connection *c, short *poll_events) @@ -361,7 +361,7 @@ tls_connect(struct tcp_connection *c, short *poll_events) LM_INFO("New TLS connection to %s:%d failed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); c->state = S_CONN_BAD; return -1; - + case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; @@ -370,7 +370,7 @@ tls_connect(struct tcp_connection *c, short *poll_events) if (poll_events) *poll_events = POLLOUT; return 0; - + case SSL_ERROR_SYSCALL: LM_ERR("SSL_ERROR_SYSCALL err=%s(%d)\n", strerror(errno), errno); @@ -389,7 +389,7 @@ tls_connect(struct tcp_connection *c, short *poll_events) } /* - * wrapper around SSL_shutdown, returns -1 on error, 0 on success + * wrapper around SSL_shutdown, returns -1 on error, 0 on success */ static int tls_shutdown(struct tcp_connection *c) @@ -399,7 +399,7 @@ tls_shutdown(struct tcp_connection *c) SSL *ssl; /* - * we do not implement full ssl shutdown + * we do not implement full ssl shutdown */ ssl = (SSL *) c->extra_data; if (ssl == 0) { @@ -420,12 +420,12 @@ tls_shutdown(struct tcp_connection *c) case SSL_ERROR_ZERO_RETURN: c->state = S_CONN_EOF; return 0; - + case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: c->state = S_CONN_EOF; return 0; - + default: LM_ERR("something wrong in SSL:\n"); c->state = S_CONN_BAD; @@ -433,15 +433,15 @@ tls_shutdown(struct tcp_connection *c) return -1; } } - + LM_ERR("bug\n"); return -1; } /* - * Wrapper around SSL_write, returns number of bytes written on success, * - * -1 on error, 0 when it would block + * Wrapper around SSL_write, returns number of bytes written on success, * + * -1 on error, 0 when it would block */ static int tls_write(struct tcp_connection *c, int fd, const void *buf, size_t len, short *poll_events) @@ -449,7 +449,7 @@ tls_write(struct tcp_connection *c, int fd, const void *buf, size_t len, short * int ret, err; /* - * runs within write lock, no need to lock here + * runs within write lock, no need to lock here */ SSL *ssl; @@ -466,7 +466,7 @@ tls_write(struct tcp_connection *c, int fd, const void *buf, size_t len, short * LM_DBG("connection closed cleanly\n"); c->state = S_CONN_EOF; return -1; - + case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; @@ -475,7 +475,7 @@ tls_write(struct tcp_connection *c, int fd, const void *buf, size_t len, short * if (poll_events) *poll_events = POLLOUT; return 0; - + default: LM_ERR("TLS connection to %s:%d write failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS write error:\n"); @@ -491,11 +491,11 @@ tls_write(struct tcp_connection *c, int fd, const void *buf, size_t len, short * /* - * Wrapper around SSL_read + * Wrapper around SSL_read */ /* - * returns number of bytes read, 0 on eof and transits into S_CONN_EOF, -1 - * on error + * returns number of bytes read, 0 on eof and transits into S_CONN_EOF, -1 + * on error */ static int _tls_read(struct tcp_connection *c, void *buf, size_t len) @@ -516,15 +516,15 @@ _tls_read(struct tcp_connection *c, void *buf, size_t len) case SSL_ERROR_ZERO_RETURN: LM_INFO("TLS connection to %s:%d closed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); /* - * mark end of file + * mark end of file */ c->state = S_CONN_EOF; return 0; - + case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return 0; - + case SSL_ERROR_SYSCALL: LM_ERR("SYSCALL error -> (%d) <%s>\n",errno,strerror(errno)); default: @@ -544,10 +544,10 @@ _tls_read(struct tcp_connection *c, void *buf, size_t len) /* * Called when new tcp connection is accepted or connected, create ssl - * data structures here, there is no need to acquire any lock, because the + * data structures here, there is no need to acquire any lock, because the * connection is being created by a new process and on other process has * access to it yet, this is called before adding the tcp_connection - * structure into the hash + * structure into the hash */ int tls_tcpconn_init(struct tcp_connection *c, int sock) @@ -558,12 +558,12 @@ tls_tcpconn_init(struct tcp_connection *c, int sock) int_str val; /* - * new connection within a single process, no lock necessary + * new connection within a single process, no lock necessary */ LM_DBG("entered: Creating a whole new ssl connection\n"); - + /* - * do everything tcpconn_new wouldn't do when TLS + * do everything tcpconn_new wouldn't do when TLS */ c->type = PROTO_TLS; c->rcv.proto = PROTO_TLS; @@ -651,13 +651,13 @@ tls_tcpconn_init(struct tcp_connection *c, int sock) /* - * clean the extra data upon connection shut down + * clean the extra data upon connection shut down */ void tls_tcpconn_clean(struct tcp_connection *c) { /* - * runs within global tcp lock + * runs within global tcp lock */ LM_DBG("entered\n"); @@ -669,15 +669,15 @@ tls_tcpconn_clean(struct tcp_connection *c) /* - * perform one-way shutdown, do not wait fro notify from the remote peer + * perform one-way shutdown, do not wait fro notify from the remote peer */ void tls_close(struct tcp_connection *c, int fd) { /* - * runs within global tcp lock + * runs within global tcp lock */ - LM_DBG("closing TLS connection\n"); + LM_DBG("closing TLS connection\n"); tls_update_fd(c, fd); tls_shutdown(c); } @@ -685,10 +685,10 @@ tls_close(struct tcp_connection *c, int fd) /* - * This is shamelessly stolen tsend_stream from tsend.c + * This is shamelessly stolen tsend_stream from tsend.c */ /* - * fixme: probably does not work correctly + * fixme: probably does not work correctly */ size_t tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, @@ -716,18 +716,18 @@ tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, goto error; timeout = tls_handshake_timeout * 1000; break; - + case S_CONN_CONNECT: if (tls_connect(c, &(pf.events)) < 0) goto error; timeout = tls_handshake_timeout * 1000; break; - + case S_CONN_OK: n = tls_write(c, fd, buf, len, &(pf.events)); timeout = tls_send_timeout * 1000; break; - + default: LM_ERR("TLS broken connection\n"); goto error; @@ -754,28 +754,28 @@ tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, written += n; if (n < len) { /* - * partial write + * partial write */ buf += n; len -= n; } else { /* - * successful full write + * successful full write */ return written; } /* - * + * */ if (pf.events == 0) pf.events = POLLOUT; - + poll_loop: while (1) { /* * keep tls_send_timeout in seconds to be compatible with - * tcp_send_timeout + * tcp_send_timeout */ n = poll(&pf, 1, timeout); if (n < 0) { @@ -788,14 +788,14 @@ tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, goto poll_loop; } else if (n == 0) { /* - * timeout + * timeout */ LM_ERR("TLS send timeout (%d)\n", timeout); goto error; } if (pf.revents & POLLOUT || pf.revents & POLLIN) { /* - * we can read or write again + * we can read or write again */ goto again; } else if (pf.revents & (POLLERR | POLLHUP | POLLNVAL)) { @@ -805,7 +805,7 @@ tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, /* * if POLLPRI or other non-harmful events happened, continue ( * although poll should never signal them since we're not - * interested in them => we should never reach this point) + * interested in them => we should never reach this point) */ } @@ -819,23 +819,21 @@ tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, * about accepting or connecting here, each modification of ssl data * structures has to be protected, another process might ask for the same * connection and attempt write to it which would result in updating the - * ssl structures + * ssl structures */ size_t -tls_read(struct tcp_connection * c) +tls_read(struct tcp_connection * c,struct tcp_req *r) { /* - * no lock acquired + * no lock acquired */ /* - * shamelessly stolen from tcp_read + * shamelessly stolen from tcp_read */ int bytes_free; - struct tcp_req *r; int fd, read; - r = &c->req; fd = c->fd; bytes_free = TCP_BUF_SIZE - (int) (r->pos - r->buf); @@ -847,7 +845,7 @@ tls_read(struct tcp_connection * c) /* * ssl structures may be accessed from several processes, we need to - * protect each access and modification by a lock + * protect each access and modification by a lock */ lock_get(&c->write_lock); tls_update_fd(c, fd); @@ -863,13 +861,13 @@ tls_read(struct tcp_connection * c) * called before tls_read, the this function should attempt tls_accept or * tls_connect depending on the state of the connection, if this function * does not transit a connection into S_CONN_OK then tcp layer would not - * call tcp_read + * call tcp_read */ int tls_fix_read_conn(struct tcp_connection *c) { /* - * no lock acquired + * no lock acquired */ int ret; @@ -878,22 +876,22 @@ tls_fix_read_conn(struct tcp_connection *c) /* * We have to acquire the lock before testing c->state, otherwise a * writer could modify the structure if it gets preempted and has - * something to write + * something to write */ lock_get(&c->write_lock); switch (c->state) { case S_CONN_ACCEPT: ret = tls_update_fd(c, c->fd); - if (!ret) + if (!ret) ret = tls_accept(c, NULL); break; - + case S_CONN_CONNECT: ret = tls_update_fd(c, c->fd); if (!ret) ret = tls_connect(c, NULL); break; - + default: /* fall through */ break; } diff --git a/tls/tls_server.h b/tls/tls_server.h index 7f1a73cfa7a..2739ac677fa 100644 --- a/tls/tls_server.h +++ b/tls/tls_server.h @@ -16,8 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -28,29 +28,29 @@ #include "../tcp_conn.h" /* - * dump ssl error stack + * dump ssl error stack */ void tls_print_errstack(void); /* - * Called when new tcp connection is accepted + * Called when new tcp connection is accepted */ int tls_tcpconn_init(struct tcp_connection *c, int sock); /* - * clean the extra data upon connection shut down + * clean the extra data upon connection shut down */ void tls_tcpconn_clean(struct tcp_connection *c); /* - * shut down the TLS connection + * shut down the TLS connection */ void tls_close(struct tcp_connection *c, int fd); size_t tls_blocking_write(struct tcp_connection *c, int fd, const char *buf, size_t len); -size_t tls_read(struct tcp_connection *c); +size_t tls_read(struct tcp_connection *c,struct tcp_req *r); int tls_fix_read_conn(struct tcp_connection *c); diff --git a/transformations.c b/transformations.c index 6cc4e3a6946..942a1baa7f5 100644 --- a/transformations.c +++ b/transformations.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -27,14 +27,15 @@ #include #include +#include #include #include #include #include "dprint.h" #include "mem/mem.h" -#include "ut.h" -#include "trim.h" +#include "ut.h" +#include "trim.h" #include "dset.h" #include "usr_avp.h" #include "errinfo.h" @@ -68,11 +69,11 @@ int run_transformations(struct sip_msg *msg, trans_t *tr, pv_value_t *val) int ret = 0; if(tr==NULL || val==NULL){ - + LM_DBG("null pointer\n"); return -1; } - + it = tr; while(it) { @@ -110,7 +111,7 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype, { if(str2sint(&val->rs, &val->ri)!=0) return -1; - } else { + } else { if(!(val->flags&PV_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); } @@ -184,6 +185,29 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype, val->rs.s = _tr_buffer; val->rs.len = i; break; + case TR_S_HEX2DEC: + if(val->flags&PV_VAL_INT) + break; /* already converted */ + s = NULL; + if (hexstr2int(val->rs.s, val->rs.len, (unsigned int *)&i) < 0) + return -1; + val->rs.s = int2str(i, &val->rs.len); + val->ri = i; + val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR; + break; + case TR_S_DEC2HEX: + if(!(val->flags&PV_VAL_INT)) + { + if(str2sint(&val->rs, &val->ri)!=0) + return -1; + } + val->rs.len = snprintf(_tr_buffer, TR_BUFFER_SIZE, "%x", val->ri); + if (val->rs.len < 0 || val->rs.len > TR_BUFFER_SIZE) + return -1; + val->ri = 0; + val->rs.s = _tr_buffer; + val->flags = PV_VAL_STR; + break; case TR_S_ESCAPECOMMON: if(!(val->flags&PV_VAL_STR)) val->rs.s = int2str(val->ri, &val->rs.len); @@ -444,6 +468,144 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype, val->flags = PV_VAL_STR; val->rs = st; break; + case TR_S_INDEX: + case TR_S_RINDEX: + /* Ensure it is in string format */ + if(!(val->flags&PV_VAL_STR)) + { + val->rs.s = int2str(val->ri, &val->rs.len); + val->flags |= PV_VAL_STR; + } + + /* Needle to look for in haystack */ + if(tp->type==TR_PARAM_STRING) + { + st = tp->v.s; + } else { + if(pv_get_spec_value(msg, (pv_spec_p)tp->v.data, &v)!=0 + || (!(v.flags&PV_VAL_STR)) || v.rs.len<=0) + { + LM_ERR("index/rindex cannot get p1\n"); + return -1; + } + + st = v.rs; + } + + /* User supplied starting position */ + if (tp->next != NULL) { + if(tp->next->type==TR_PARAM_NUMBER) + { + i = tp->next->v.n; + } else { + if(pv_get_spec_value(msg, (pv_spec_p)tp->next->v.data, &v)!=0 + || (!(v.flags&PV_VAL_INT))) + { + LM_ERR("index/rindex cannot get p2\n"); + return -1; + } + i = v.ri; + } + } else { + /* Default start positions: 0 for index, end of str for rindex */ + i = (subtype == TR_S_INDEX ? 0 : (val->rs.len - 1)); + } + + /* If start is negative base it off end of string + e.g -2 on 10 char str start of 8. */ + if (i < 0 ){ + if ( val->rs.len > 0 ) { + /* Support wrapping on negative index + e.g -2 and -12 index are same on strlen of 10 */ + i = ( (i * -1) % val->rs.len ); + /* No remainder means we start at 0 + otherwise take remainder off the end */ + if ( i > 0) { + i = (val->rs.len - i); + } + } else { + /* Case of searching through an empty string is caught later */ + i = 0; + } + } + + /* Index */ + if (subtype == TR_S_INDEX) { + /* If start index is beyond end of string or + Needle is bigger than haystack return -1 */ + if ( i >= val->rs.len || st.len > (val->rs.len - i)) { + memset(val, 0, sizeof(pv_value_t)); + val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR; + val->ri = -1; + val->rs.s = int2str(val->ri, &val->rs.len); + break; + } + + /* Iterate through string starting at index + After j there are no longer enough characters left to match the needle */ + j = (val->rs.len - st.len); + while (i <= j) { + if (val->rs.s[i] == st.s[0]) { + /* First character matches, do a full comparison + shortcut for single character lookups */ + if (st.len == 1 || strncmp(val->rs.s + i, st.s, st.len) == 0) { + /* Bingo, found it */ + memset(val, 0, sizeof(pv_value_t)); + val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR; + val->ri = i; + val->rs.s = int2str(val->ri, &val->rs.len); + return 0; + } + } + i++; + } + /* Rindex */ + } else { + /* Needle bigger than haystack */ + if ( st.len > val->rs.len ) { + memset(val, 0, sizeof(pv_value_t)); + val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR; + val->ri = -1; + val->rs.s = int2str(val->ri, &val->rs.len); + break; + } + + /* Incase of RINDEX clamp index to end of string */ + if (i >= val->rs.len) { + i = (val->rs.len - 1); + } + + /* Start position does not leave enough characters to match needle, jump ahead */ + if ( st.len > (val->rs.len - i) ) { + /* Minimum start position allowing for matches */ + i = (val->rs.len - st.len); + } + + /* Iterate through string starting at index and going backwards */ + while (i >= 0) { + if (val->rs.s[i] == st.s[0]) { + /* First character matches, do a full comparison + shortcut for single character lookups */ + if (st.len == 1 || strncmp(val->rs.s + i, st.s, st.len) == 0) { + /* Bingo, found it */ + memset(val, 0, sizeof(pv_value_t)); + val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR; + val->ri = i; + val->rs.s = int2str(val->ri, &val->rs.len); + return 0; + } + } + i--; + } + + } + + /* Not found */ + memset(val, 0, sizeof(pv_value_t)); + val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR; + val->ri = -1; + val->rs.s = int2str(val->ri, &val->rs.len); + break; default: LM_ERR("unknown subtype %d\n", subtype); @@ -871,7 +1033,7 @@ static int parse_csv(str *s,csv_t **list) LM_ERR("no more memory"); goto error; } - + /* should be end of string ! */ if (last) { last->next = t;} else {*list = t;} return 0; @@ -887,7 +1049,7 @@ static int parse_csv(str *s,csv_t **list) string +=len+1; } } - + if (last) { last->next = t;} else {*list = t;} last = t; } @@ -937,14 +1099,14 @@ int tr_eval_csv(struct sip_msg *msg, tr_param_t *tp,int subtype, _tr_csv_str.len = val->rs.len; memcpy(_tr_csv_str.s, val->rs.s, val->rs.len); _tr_csv_str.s[_tr_csv_str.len] = '\0'; - + /* reset old values */ if(_tr_csv_list != NULL) { free_csv_list(_tr_csv_list); _tr_csv_list = 0; } - + /* parse csv */ sv = _tr_csv_str; if (parse_csv(&sv,&_tr_csv_list)<0) @@ -1054,7 +1216,7 @@ int tr_eval_sdp(struct sip_msg *msg, tr_param_t *tp,int subtype, _tr_sdp_str.len = val->rs.len; memcpy(_tr_sdp_str.s, val->rs.s, val->rs.len); _tr_sdp_str.s[_tr_sdp_str.len] = '\0'; - + } switch (subtype) @@ -1064,7 +1226,7 @@ int tr_eval_sdp(struct sip_msg *msg, tr_param_t *tp,int subtype, searchLine = *(tp->v.s.s); if(tp->next->type==TR_PARAM_NUMBER) entryNo = tp->next->v.n; - else + else { if(pv_get_spec_value(msg, (pv_spec_p)tp->next->v.data, &v)!=0 || (!(v.flags&PV_VAL_INT))) @@ -1166,7 +1328,7 @@ int tr_eval_ip(struct sip_msg *msg, tr_param_t *tp,int subtype, LM_ERR("Invalid ip address provided for ip.ntop. Binary format expected !\n"); return -1; } - + memcpy(ip.u.addr,val->rs.s,val->rs.len); ip.len = val->rs.len; buffer = ip_addr2a(&ip); @@ -1230,7 +1392,7 @@ int tr_eval_ip(struct sip_msg *msg, tr_param_t *tp,int subtype, val->rs.len = 0; return 0; } - + buffer = ip_addr2a(&ip); val->rs.s = buffer; val->rs.len = strlen(buffer); @@ -1272,7 +1434,7 @@ int tr_eval_re(struct sip_msg *msg, tr_param_t *tp, int subtype, } sv = v.rs; } - LM_DBG("Trying to apply regexp [%.*s] on : [%.*s]\n", + LM_DBG("Trying to apply regexp [%.*s] on : [%.*s]\n", sv.len,sv.s,val->rs.len, val->rs.s); if (reg_buf_len != sv.len || memcmp(reg_buf,sv.s,sv.len) != 0) { LM_DBG("we must compile the regexp\n"); @@ -1357,21 +1519,21 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype, _tr_params_str.len = val->rs.len; memcpy(_tr_params_str.s, val->rs.s, val->rs.len); _tr_params_str.s[_tr_params_str.len] = '\0'; - + /* reset old values */ if(_tr_params_list != NULL) { free_params(_tr_params_list); _tr_params_list = 0; } - + /* parse params */ sv = _tr_params_str; if (parse_params(&sv, CLASS_ANY, &phooks, &_tr_params_list)<0) return -1; } - + if(_tr_params_list==NULL) return -1; @@ -1399,7 +1561,7 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype, } sv = v.rs; } - + for (pit = _tr_params_list; pit; pit=pit->next) { if (pit->name.len==sv.len @@ -1445,7 +1607,7 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype, n--; } } else { - /* ugly hack -- params are in reverse order + /* ugly hack -- params are in reverse order * - first count then find */ i = 0; for (pit = _tr_params_list; pit; pit=pit->next) @@ -1500,7 +1662,7 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype, n--; } } else { - /* ugly hack -- params are in reverse order + /* ugly hack -- params are in reverse order * - first count then find */ i = 0; for (pit = _tr_params_list; pit; pit=pit->next) @@ -1550,7 +1712,7 @@ int tr_eval_paramlist(struct sip_msg *msg, tr_param_t *tp, int subtype, } sv = v.rs; } - + val->ri = 0; for (pit = _tr_params_list; pit; pit=pit->next) { @@ -1661,7 +1823,7 @@ int tr_eval_nameaddr(struct sip_msg *msg, tr_param_t *tp, int subtype, /* search the parameter */ while(topar) { - if(topar->name.len == tp->v.s.len && + if(topar->name.len == tp->v.s.len && strncmp(topar->name.s, tp->v.s.s, topar->name.len)== 0) break; topar = topar->next; @@ -1677,8 +1839,18 @@ int tr_eval_nameaddr(struct sip_msg *msg, tr_param_t *tp, int subtype, else { LM_DBG("We have params\n"); val->rs.s = topar->name.s; - val->rs.len = nameaddr_to_body->last_param->value.s + - nameaddr_to_body->last_param->value.len - val->rs.s; + if (nameaddr_to_body->last_param->value.s==NULL) { + val->rs.len = nameaddr_to_body->last_param->name.s + + nameaddr_to_body->last_param->name.len - val->rs.s; + } else { + val->rs.len = nameaddr_to_body->last_param->value.s + + nameaddr_to_body->last_param->value.len - val->rs.s; + /* compensate the len if the value of the last param is + * a quoted value (include the closing quote in the len) */ + if ( (val->rs.s+val->rs.lenrs.s[val->rs.len]=='"' || val->rs.s[val->rs.len]=='\'' ) ) + val->rs.len++; + } } break; @@ -1704,7 +1876,7 @@ char* parse_transformation(str *in, trans_t **tr) if(in==NULL || in->s==NULL || tr==NULL) return NULL; - + p = in->s; do { while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++; @@ -1962,6 +2134,7 @@ char* tr_parse_string(str* in, trans_t *t) { char *p; char *p0; + char *ps; str name; str s; pv_spec_t *spec = NULL; @@ -2011,6 +2184,12 @@ char* tr_parse_string(str* in, trans_t *t) } else if(name.len==11 && strncasecmp(name.s, "decode.hexa", 11)==0) { t->subtype = TR_S_DECODEHEXA; return p; + } else if(name.len==7 && strncasecmp(name.s, "hex2dec", 7)==0) { + t->subtype = TR_S_HEX2DEC; + return p; + } else if(name.len==7 && strncasecmp(name.s, "dec2hex", 7)==0) { + t->subtype = TR_S_DEC2HEX; + return p; } else if(name.len==13 && strncasecmp(name.s, "escape.common", 13)==0) { t->subtype = TR_S_ESCAPECOMMON; return p; @@ -2029,6 +2208,76 @@ char* tr_parse_string(str* in, trans_t *t) } else if(name.len==14 && strncasecmp(name.s, "unescape.param", 14)==0) { t->subtype = TR_S_UNESCAPEPARAM; return p; + } else if(name.len==5 && strncasecmp(name.s, "index", 5)==0) { + t->subtype = TR_S_INDEX; + if(*p!=TR_PARAM_MARKER) + { + LM_ERR("invalid index transformation: %.*s!\n", in->len, in->s); + goto error; + } + p++; + _tr_parse_sparam(p, p0, tp, spec, ps, in, s); + t->params = tp; + tp = 0; + while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; + if(*p!=TR_PARAM_MARKER && *p!=TR_RBRACKET) + { + LM_ERR("invalid index transformation: %.*s!\n", + in->len, in->s); + goto error; + } + if (*p!=TR_RBRACKET) { + p++; + _tr_parse_nparam(p, p0, tp, spec, n, sign, in, s); + t->params->next = tp; + } else { + t->params->next = NULL; + } + + tp = 0; + while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++; + if(*p!=TR_RBRACKET) + { + LM_ERR("invalid index transformation: %.*s!!\n", + in->len, in->s); + goto error; + } + return p; + } else if(name.len==6 && strncasecmp(name.s, "rindex", 6)==0) { + t->subtype = TR_S_RINDEX; + if(*p!=TR_PARAM_MARKER) + { + LM_ERR("invalid rindex transformation: %.*s!\n", in->len, in->s); + goto error; + } + p++; + _tr_parse_sparam(p, p0, tp, spec, ps, in, s); + t->params = tp; + tp = 0; + while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++; + if(*p!=TR_PARAM_MARKER && *p!=TR_RBRACKET) + { + LM_ERR("invalid rindex transformation: %.*s!\n", + in->len, in->s); + goto error; + } + if (*p!=TR_RBRACKET) { + p++; + _tr_parse_nparam(p, p0, tp, spec, n, sign, in, s); + t->params->next = tp; + } else { + t->params->next = NULL; + } + + tp = 0; + while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++; + if(*p!=TR_RBRACKET) + { + LM_ERR("invalid rindex transformation: %.*s!!\n", + in->len, in->s); + goto error; + } + return p; } else if(name.len==6 && strncasecmp(name.s, "substr", 6)==0) { t->subtype = TR_S_SUBSTR; if(*p!=TR_PARAM_MARKER) @@ -2104,7 +2353,7 @@ char* tr_parse_string(str* in, trans_t *t) goto error; } return p; - } + } LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s, name.len, name.s, name.len); @@ -2554,12 +2803,12 @@ char * tr_parse_csv(str *in, trans_t *t) } return p; } - + LM_ERR("unknown transformation: %.*s/%.*s/%d!\n", in->len, in->s, name.len, name.s, name.len); error: return NULL; - + } char * tr_parse_sdp(str *in, trans_t *t) @@ -2626,7 +2875,7 @@ char * tr_parse_sdp(str *in, trans_t *t) pkg_free(spec); spec = NULL; } - + _tr_parse_nparam(p, p0, tp, spec,n,sign, in, s); if(tp->type==TR_PARAM_NUMBER && tp->v.n<0) { @@ -2642,7 +2891,7 @@ char * tr_parse_sdp(str *in, trans_t *t) in->len, in->s); goto error; } - + return p; } @@ -2700,7 +2949,7 @@ char * tr_parse_ip(str *in, trans_t *t) name.len, name.s, name.len); error: return NULL; - + } char* tr_parse_re(str *in,trans_t *t) diff --git a/transformations.h b/transformations.h index 536f96c9c0f..67767f07375 100644 --- a/transformations.h +++ b/transformations.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -41,11 +41,12 @@ enum _tr_type { TR_NONE=0, TR_STRING, TR_URI, TR_PARAMLIST, TR_NAMEADDR, TR_CSV, TR_SDP,TR_IP, TR_VIA, TR_RE }; -enum _tr_s_subtype { +enum _tr_s_subtype { TR_S_NONE=0, TR_S_LEN, TR_S_INT, TR_S_MD5, TR_S_SUBSTR, - TR_S_SELECT, TR_S_ENCODEHEXA, TR_S_DECODEHEXA, + TR_S_SELECT, TR_S_ENCODEHEXA, TR_S_DECODEHEXA, TR_S_HEX2DEC, TR_S_DEC2HEX, TR_S_ESCAPECOMMON, TR_S_UNESCAPECOMMON, TR_S_ESCAPEUSER, TR_S_UNESCAPEUSER, - TR_S_ESCAPEPARAM, TR_S_UNESCAPEPARAM, TR_S_TOLOWER, TR_S_TOUPPER, TR_S_CRC32 + TR_S_ESCAPEPARAM, TR_S_UNESCAPEPARAM, TR_S_TOLOWER, TR_S_TOUPPER, TR_S_CRC32, + TR_S_INDEX, TR_S_RINDEX }; enum _tr_uri_subtype { TR_URI_NONE=0, TR_URI_USER, TR_URI_HOST, TR_URI_PASSWD, TR_URI_PORT, diff --git a/trim.h b/trim.h index 32c09cf0bfb..252ce6ab650 100644 --- a/trim.h +++ b/trim.h @@ -1,4 +1,4 @@ -/* +/* * $Id$ * * Copyright (C) 2001-2003 FhG Fokus @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -30,7 +30,7 @@ /* * This switch-case statement is used in * trim_leading and trim_trailing. You can - * define characters that should be skipped + * define characters that should be skipped * here. */ #define TRIM_SWITCH(c) switch(c) { \ diff --git a/tsend.c b/tsend.c index 0d18c8daf5c..33894a36d8a 100644 --- a/tsend.c +++ b/tsend.c @@ -21,11 +21,11 @@ * * * send with timeout for stream and datagram sockets - * + * * History: * -------- * 2004-02-26 created by andrei - * 2003-03-03 switched to heavy macro use, added tsend_dgram_ev (andrei) + * 2003-03-03 switched to heavy macro use, added tsend_dgram_ev (andrei) */ #include @@ -70,7 +70,7 @@ poll_loop: \ /* if POLLIN or POLLPRI or other non-harmful events happened, \ * continue ( although poll should never signal them since we're \ * not interested in them => we should never reach this point) */ \ - } + } #define TSEND_ERR_CHECK(f_name)\ @@ -82,7 +82,7 @@ poll_loop: \ goto error; \ }else goto poll_loop; \ } - + /*! \brief sends on fd (which must be O_NONBLOCK); if it cannot send any data @@ -95,7 +95,7 @@ int tsend_stream(int fd, char* buf, unsigned int len, int timeout) { int written; TSEND_INIT; - + written=0; again: n=send(fd, buf, len, @@ -106,13 +106,13 @@ int tsend_stream(int fd, char* buf, unsigned int len, int timeout) #endif ); TSEND_ERR_CHECK("tsend_stream"); - written+=n; - if ((unsigned int)n couldn't send all) * bugs: signals will reset the timer */ -int tsend_dgram(int fd, char* buf, unsigned int len, +int tsend_dgram(int fd, char* buf, unsigned int len, const struct sockaddr* to, socklen_t tolen, int timeout) { TSEND_INIT; again: n=sendto(fd, buf, len, 0, to, tolen); TSEND_ERR_CHECK("tsend_dgram"); - /* we don't care about partial writes: they shouldn't happen on + /* we don't care about partial writes: they shouldn't happen on * a datagram socket */ return n; TSEND_POLL("tsend_datagram"); @@ -143,8 +143,8 @@ int tsend_dgram(int fd, char* buf, unsigned int len, return -1; } - -/*! \brief sends on connected datagram fd (which must be O_NONBLOCK); + +/*! \brief sends on connected datagram fd (which must be O_NONBLOCK); * if it cannot send any data in timeout milliseconds it will return ERROR * \return -1 on error, or number of bytes written * (if less than len => couldn't send all) diff --git a/tsend.h b/tsend.h index e3d2c46c97b..c6deaea5d7a 100644 --- a/tsend.h +++ b/tsend.h @@ -29,7 +29,7 @@ int tsend_stream(int fd, char* buf, unsigned int len, int timeout); -int tsend_dgram(int fd, char* buf, unsigned int len, +int tsend_dgram(int fd, char* buf, unsigned int len, const struct sockaddr* to, socklen_t tolen, int timeout); int tsend_dgram_ev(int fd, const struct iovec* v, int count, int timeout); diff --git a/udp_server.c b/udp_server.c index 5ada21e6598..53f437ea256 100644 --- a/udp_server.c +++ b/udp_server.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -165,18 +165,18 @@ static int setup_mcast_rcvr(int sock, union sockaddr_union* addr) #ifdef USE_IPV6 struct ipv6_mreq mreq6; #endif /* USE_IPV6 */ - + if (addr->s.sa_family==AF_INET){ memcpy(&mreq.imr_multiaddr, &addr->sin.sin_addr, sizeof(struct in_addr)); mreq.imr_interface.s_addr = htonl(INADDR_ANY); - + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq))==-1){ LM_ERR("setsockopt: %s\n", strerror(errno)); return -1; } - + #ifdef USE_IPV6 } else if (addr->s.sa_family==AF_INET6){ memcpy(&mreq6.ipv6mr_multiaddr, &addr->sin6.sin6_addr, @@ -191,7 +191,7 @@ static int setup_mcast_rcvr(int sock, union sockaddr_union* addr) LM_ERR("setsockopt:%s\n", strerror(errno)); return -1; } - + #endif /* USE_IPV6 */ } else { LM_ERR("unsupported protocol family\n"); @@ -221,7 +221,7 @@ int udp_init(struct socket_info* sock_info) LM_ERR("could not init sockaddr_union\n"); goto error; } - + sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_DGRAM, 0); if (sock_info->socket==-1){ LM_ERR("socket: %s\n", strerror(errno)); @@ -236,7 +236,7 @@ int udp_init(struct socket_info* sock_info) } /* tos */ optval=tos; - if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, + if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, sizeof(optval)) ==-1){ LM_WARN("setsockopt tos: %s\n", strerror(errno)); /* continue since this is not critical */ @@ -252,14 +252,14 @@ int udp_init(struct socket_info* sock_info) #endif #ifdef USE_MCAST - if ((sock_info->flags & SI_IS_MCAST) + if ((sock_info->flags & SI_IS_MCAST) && (setup_mcast_rcvr(sock_info->socket, addr)<0)){ goto error; } /* set the multicast options */ if (addr->s.sa_family==AF_INET){ m_optval = mcast_loopback; - if (setsockopt(sock_info->socket, IPPROTO_IP, IP_MULTICAST_LOOP, + if (setsockopt(sock_info->socket, IPPROTO_IP, IP_MULTICAST_LOOP, &m_optval, sizeof(m_optval))==-1){ LM_WARN("setsockopt(IP_MULTICAST_LOOP): %s\n", strerror(errno)); /* it's only a warning because we might get this error if the @@ -275,7 +275,7 @@ int udp_init(struct socket_info* sock_info) } #ifdef USE_IPV6 } else if (addr->s.sa_family==AF_INET6){ - if (setsockopt(sock_info->socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + if (setsockopt(sock_info->socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &mcast_loopback, sizeof(mcast_loopback))==-1){ LM_WARN("setsockopt (IPV6_MULTICAST_LOOP): %s\n", strerror(errno)); /* it's only a warning because we might get this error if the @@ -298,9 +298,9 @@ int udp_init(struct socket_info* sock_info) if (probe_max_sock_buff(sock_info->socket,0,MAX_RECV_BUFFER_SIZE, BUFFER_INCREMENT)==-1) goto error; - + if (bind(sock_info->socket, &addr->s, sockaddru_len(*addr))==-1){ - LM_ERR("bind(%x, %p, %d) on %s: %s\n", sock_info->socket, &addr->s, + LM_ERR("bind(%x, %p, %d) on %s: %s\n", sock_info->socket, &addr->s, (unsigned)sockaddru_len(*addr), sock_info->address_str.s, strerror(errno)); #ifdef USE_IPV6 @@ -417,7 +417,7 @@ int udp_rcv_loop(void) LM_INFO("dropping 0 port packet from %s\n", tmp); continue; } - + update_stat( pt[process_no].load, +1 ); /* receive_msg must free buf too!*/ @@ -434,7 +434,7 @@ int udp_rcv_loop(void) /** * Main UDP send function, called from msg_send. - * \see msg_send + * \see msg_send * \param source send socket * \param buf sent data * \param len data length in bytes diff --git a/udp_server.h b/udp_server.h index 741df923bc4..5202e159dab 100644 --- a/udp_server.h +++ b/udp_server.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/usr_avp.c b/usr_avp.c index c9825b942c7..54888f4acda 100644 --- a/usr_avp.c +++ b/usr_avp.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: @@ -295,7 +295,7 @@ inline void get_avp_val(struct usr_avp *avp, int_str *val) val->s = *((str*)data); } else { /* avp type ID, int value */ - val->n = (long)(avp->data); + val->n = (long)(avp->data); } } @@ -342,7 +342,7 @@ struct usr_avp *search_first_avp( unsigned short flags, if(start==0) { assert( crt_avps!=0 ); - + if (*crt_avps==0) return 0; head = *crt_avps; @@ -460,7 +460,7 @@ inline void destroy_avp_list( struct usr_avp **list ) void reset_avps(void) { assert( crt_avps!=0 ); - + if ( crt_avps!=&global_avps) { crt_avps = &global_avps; } @@ -471,7 +471,7 @@ void reset_avps(void) struct usr_avp** set_avp_list( struct usr_avp **list ) { struct usr_avp **foo; - + assert( crt_avps!=0 ); foo = crt_avps; @@ -483,7 +483,7 @@ static inline int __search_avp_map(str *alias, map_t m) { int **id = (int **)map_find(m, *alias); LM_DBG("looking for [%.*s] avp %s - found %d\n", alias->len, alias->s, - m == avp_map_shm ? "in shm" : "", id ? p2int(*id) : -1); + m == avp_map_shm ? "in shm": "", id ? p2int(*id) : -1); return id ? p2int(*id) : -1; } @@ -582,3 +582,24 @@ int get_avp_id(str *name) } return id; } + + +struct usr_avp *clone_avp_list(struct usr_avp *old) +{ + struct usr_avp *a; + int_str val; + + if (!old) return NULL; + + /* create a copy of the old AVP */ + get_avp_val( old, &val ); + a = new_avp( old->flags, old->id, val); + if (a==NULL) { + LM_ERR("cloning failed, trunking the list\n"); + return NULL; + } + + a->next = clone_avp_list(old->next); + return a; +} + diff --git a/usr_avp.h b/usr_avp.h index 8bdf6a6ab59..7ee296b7fda 100644 --- a/usr_avp.h +++ b/usr_avp.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * TODO (by bogdan) @@ -46,7 +46,7 @@ * 7 avpops module avp was loaded from DB * */ - + #include "str.h" @@ -85,6 +85,7 @@ int init_global_avps(); int init_extra_avps(); struct usr_avp* new_avp(unsigned short flags, int name, int_str val); +struct usr_avp *clone_avp_list(struct usr_avp *old); /* add functions */ int add_avp( unsigned short flags, int id, int_str val); diff --git a/ut.c b/ut.c index 0e4ad0ffc3c..69755ef49f9 100644 --- a/ut.c +++ b/ut.c @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History @@ -74,7 +74,7 @@ int user2uid(int* uid, int* gid, char* user) { char* tmp; struct passwd *pw_entry; - + if (user){ *uid=strtol(user, &tmp, 10); if ((tmp==0) ||(*tmp)){ @@ -97,7 +97,7 @@ int group2gid(int* gid, char* group) { char* tmp; struct group *gr_entry; - + if (group){ *gid=strtol(group, &tmp, 10); if ((tmp==0) ||(*tmp)){ @@ -145,7 +145,7 @@ int parse_reply_codes( str *options_reply_codes_str, aux = sep2; while(*sep1 == ' ') sep1++; - + sep2--; while(*sep2 == ' ') sep2--; @@ -154,7 +154,7 @@ int parse_reply_codes( str *options_reply_codes_str, code_str.len = sep2-sep1+1; if(str2int(&code_str, &code)< 0) { - LM_ERR("Bad format - not am integer [%.*s]\n", + LM_ERR("Bad format - not am integer [%.*s]\n", code_str.len, code_str.s); return -1; } @@ -164,7 +164,7 @@ int parse_reply_codes( str *options_reply_codes_str, } (*options_reply_codes)[index] = code; index++; - + sep1 = aux +1; sep2 = strchr(sep1, ','); } @@ -237,7 +237,7 @@ void base64encode(unsigned char *out, unsigned char *in, int inlen) *out++ = base64digits[fragment]; *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c]; *out++ = '='; - + } } @@ -268,7 +268,7 @@ int base64decode(unsigned char *out,unsigned char *in,int len) break; out[out_len++] = (c1 << 2) | ((c2 & 0x30) >> 4); - + do { c3 = in[i++] & 0xFF; @@ -283,7 +283,7 @@ int base64decode(unsigned char *out,unsigned char *in,int len) out[out_len++] = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); - do + do { c4 = in[i++] & 0xFF; if (c4 == 61) @@ -307,6 +307,6 @@ inline int calc_base64_encode_len(int len) inline int calc_max_base64_decode_len(int len) { - return len*3/4; + return len*3/4; } diff --git a/ut.h b/ut.h index eadef3346ea..3ab9cf2481e 100644 --- a/ut.h +++ b/ut.h @@ -17,8 +17,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -82,6 +82,13 @@ struct sip_msg; for(;(_s_).s[0]==' ';(_s_).s=(_s_).s+1,(_s_).len--);\ }while(0); +/* right and left space trimming without '0' padding */ +#define str_trim_spaces_lr(_s_) \ + do{\ + for(;(_s_).s[(_s_).len-1]==' ';--(_s_).len);\ + for(;(_s_).s[0]==' ';(_s_).s=(_s_).s+1,(_s_).len--);\ + }while(0); + #define translate_pointer( _new_buf , _org_buf , _p) \ ( (_p)?(_new_buf + (_p-_org_buf)):(0) ) @@ -155,7 +162,7 @@ static inline int btostr( char *p, unsigned char val) /* 2^64~= 16*10^18 => 19+1+1 sign + digits + \0 */ #define INT2STR_MAX_LEN (1+19+1+1) -/* INTeger-TO-Buffer-STRing : convers an unsigned long to a string +/* INTeger-TO-Buffer-STRing : convers an unsigned long to a string * IMPORTANT: the provided buffer must be at least INT2STR_MAX_LEN size !! */ static inline char* int2bstr(unsigned long l, char *s, int* len) { @@ -176,7 +183,7 @@ static inline char* int2bstr(unsigned long l, char *s, int* len) } -/* INTeger-TO-STRing : convers an unsigned long to a string +/* INTeger-TO-STRing : convers an unsigned long to a string * returns a pointer to a static buffer containing l in asciiz & sets len */ extern char int2str_buf[INT2STR_MAX_LEN]; static inline char* int2str(unsigned long l, int* len) @@ -215,9 +222,22 @@ static inline char* q_memchr(char* p, int c, unsigned int size) for(;p=p;cursor--){ + if (*cursor==(unsigned char)c) return cursor; + } + return NULL; } - + inline static int reverse_hex2int( char *c, int len ) { @@ -279,7 +299,7 @@ inline static int hexstr2int(char *c, int len, unsigned int *val) /* double output length assumed ; does NOT zero-terminate */ -inline static int string2hex( +inline static int string2hex( /* input */ unsigned char *str, int len, /* output */ char *hex ) { @@ -356,7 +376,7 @@ inline static int hex2int(char hex_digit) <0 is returned on an unescaping error, length of the unescaped string otherwise */ -inline static int un_escape(str *user, str *new_user ) +inline static int un_escape(str *user, str *new_user ) { int i, j, value; int hi, lo; @@ -410,7 +430,7 @@ inline static int un_escape(str *user, str *new_user ) error: new_user->len = j; return -1; -} +} /* @@ -432,7 +452,7 @@ static inline void strlower(str* _s) static inline int str2int(str* _s, unsigned int* _r) { int i; - + *_r = 0; for(i = 0; i < _s->len; i++) { if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) { @@ -442,7 +462,7 @@ static inline int str2int(str* _s, unsigned int* _r) return -1; } } - + return 0; } @@ -453,7 +473,7 @@ static inline int str2sint(str* _s, int* _r) { int i; int s; - + *_r = 0; s = 1; i=0; @@ -498,7 +518,7 @@ static inline int shm_str_dup(str* dst, const str* src) LM_ERR("no shared memory left\n"); return -1; } - + memcpy(dst->s, src->s, src->len); dst->len = src->len; return 0; @@ -515,7 +535,7 @@ static inline int pkg_str_dup(str* dst, const str* src) LM_ERR("no private memory left\n"); return -1; } - + memcpy(dst->s, src->s, src->len); dst->len = src->len; return 0; @@ -531,7 +551,7 @@ static inline int str_strcmp(const str *stra, const str *strb) int blen; int minlen; - if(stra==NULL || strb==NULL || stra->s ==NULL || strb->s==NULL + if(stra==NULL || strb==NULL || stra->s ==NULL || strb->s==NULL || stra->len<0 || strb->len<0) { LM_ERR("bad parameters\n"); @@ -586,7 +606,7 @@ static inline int str_strcasecmp(const str *stra, const str *strb) if (a > b) return 1; } - if (alen < blen) + if (alen < blen) return -1; else if (alen > blen) return 1; @@ -638,7 +658,7 @@ static inline int get_time_diff(struct timeval *begin) seconds = end.tv_sec - begin->tv_sec; useconds = end.tv_usec - begin->tv_usec; mtime = ((seconds) * 1000000 + useconds); - + return mtime; } @@ -648,7 +668,7 @@ static inline int get_time_diff(struct timeval *begin) min_action_time=0; \ memset(longest_action,0,LONGEST_ACTION_SIZE*sizeof(action_time)); \ } \ - } while (0) + } while (0) static inline void log_expiry(int time_diff,int expire, const char *func_info,char *extra_dbg,int dbg_len,int tcp) @@ -716,7 +736,7 @@ static inline void log_expiry(int time_diff,int expire, } } return; -error: +error: evi_free_params(list); } diff --git a/utils/db_berkeley/.gitignore b/utils/db_berkeley/.gitignore new file mode 100644 index 00000000000..1856e3a01d2 --- /dev/null +++ b/utils/db_berkeley/.gitignore @@ -0,0 +1 @@ +bdb_recover diff --git a/utils/db_berkeley/bdb_recover.c b/utils/db_berkeley/bdb_recover.c index 1553fe048c8..0c3e670b8fa 100644 --- a/utils/db_berkeley/bdb_recover.c +++ b/utils/db_berkeley/bdb_recover.c @@ -16,10 +16,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) @@ -34,79 +34,79 @@ char* db_home = NULL; const char *progname; /** - * main -- + * main -- */ int main(int argc, char* argv[]) { int ret, ch, i; - + ret = 0; progname = argv[0]; - + while ((ch = getopt(argc, argv, "s:h:c:C:r:R:")) != EOF) - switch (ch) + switch (ch) { case 's': schema_dir = optarg; load_schema(optarg); break; - + case 'c': /*create */ ret = create(optarg); break; - + case 'C': /*Create all*/ ret = create_all(); break; - + case 'r': /*recover */ ret = recover(optarg); break; - + case 'R': /*recover_all */ ret = sscanf(optarg,"%i", &i); if(ret != 1) return -1; ret = recover_all(i); break; - + case 'h': db_home = optarg; break; - + case '?': default: return(usage()); - + } - + argc -= optind; argv += optind; - + /*free mem; close open files.*/ cleanup(); - + return ret; } /** -* usage -- -* +* usage -- +* */ int usage(void) { - fprintf(stderr, "usage: %s %s\n", progname, + fprintf(stderr, "usage: %s %s\n", progname, "-s schemadir [-h home] [-c tablename]"); - - fprintf(stderr, "usage: %s %s\n", progname, + + fprintf(stderr, "usage: %s %s\n", progname, "-s schemadir [-h home] [-C all]"); - - fprintf(stderr, "usage: %s %s\n", progname, + + fprintf(stderr, "usage: %s %s\n", progname, "-s schemadir [-h home] [-r journal-file]"); - - fprintf(stderr, "usage: %s %s\n", progname, + + fprintf(stderr, "usage: %s %s\n", progname, "-s schemadir [-h home] [-R lastN]"); - + return (EXIT_FAILURE); } @@ -123,16 +123,16 @@ int create(char* tn) tbl_cache_p tbc = NULL; table_p tp = NULL; rc = 0; - + tbc = get_table(tn); if(!tbc) { fprintf(stderr, "[create] Table %s is not supported.\n",tn); return 1; } - + tp = tbc->dtp; db = get_db(tp); - + if(db) { printf("Created table %s\n",tn); @@ -143,7 +143,7 @@ int create(char* tn) fprintf(stderr, "[create] Failed to create table %s\n",tn); rc = 1; } - + return rc; } @@ -152,11 +152,11 @@ int create(char* tn) * create_all -- creates a new Berkeley DB table for only the core tables */ int create_all(void) -{ +{ tbl_cache_p _tbc = tables; int rc; rc = 0; - + #ifdef EXTRA_DEBUG time_t tim1 = time(NULL); time_t tim2; @@ -166,11 +166,11 @@ int create_all(void) while(_tbc) { if(_tbc->dtp) - if((rc = create(_tbc->dtp->name)) != 0 ) + if((rc = create(_tbc->dtp->name)) != 0 ) break; _tbc = _tbc->next; } - + #ifdef EXTRA_DEBUG tim2 = time(NULL); i = tim2 - tim1; @@ -189,7 +189,7 @@ int create_all(void) * parameter tn is optional, * if tablename (tn) is specified returns only jnl files for tablename (tn) * else returns a sorted linkedlist of all files in d - * returns lnode_p + * returns lnode_p * the head linknode points to the latests file. */ lnode_p file_list(char* d, char* tn) @@ -199,34 +199,34 @@ lnode_p file_list(char* d, char* tn) char *fn; char *list[MAXFILES]; char dir[MAX_FILENAME_SIZE]; - struct dirent *dp; + struct dirent *dp; lnode_p h,n; - + h = n = NULL; i = j = 0; - + if(!d) { fprintf(stderr, "[file_list]: null path to schema files.\n"); return NULL; } - + memset(dir, 0, MAX_FILENAME_SIZE); strcpy(dir, d); strcat(dir, "/"); //strcat(dir, "."); dirp = opendir(dir); - + while ((dp = readdir(dirp)) != NULL) { j=0; if (i> (MAXFILES-1) ) continue; - + fn = dp->d_name; - + if (fn[0] == '.') continue; - + if(tn) { /* only looking for jnl files */ @@ -234,17 +234,17 @@ lnode_p file_list(char* d, char* tn) if (!strstr(fn, ".jnl")) continue; if (strncmp(fn, tn, len)) continue; } - + j = strlen(fn) +1; list[i] = malloc(sizeof(char) * j); memset(list[i], 0 , j); strcat(list[i], fn); i++; } - + closedir(dirp); qsort(list, i, sizeof(char*), compare); - + for(j=0;jdtp; - + if(!tbc || !tp) { fprintf(stderr, "[recover]: FAILED to get find metadata for : %s.\n", tn); return 3; } - + while ( fgets(line , MAX_ROW_SIZE, fp) != NULL ) { len = strlen(line); if(line[0] == '#' || line[0] == '\n') continue; - + if(len > 0) line[len-1] = 0; /*chomp trailing \n */ - + v = strchr(line, '|'); len = v - line; - + strncpy(op, line, len); op[len] = 0; - + switch( get_op(op, len) ) { case INSERT: @@ -365,20 +365,20 @@ int recover(char* jfn) insert(tp, v, len); ci++; break; - + case UPDATE: v++; len = strlen(v); update(tp, v, len); cu++; break; - + case DELETE: //v is really the key delete(tp, v, len); cd++; break; - + case UNKNOWN_OP: fprintf(stderr,"[recover]: UnknownOP - Skipping ROW: %s\n",line); cs++; @@ -386,7 +386,7 @@ int recover(char* jfn) } i++; } - + #ifdef EXTRA_DEBUG printf("Processed journal file: %s.\n", jfn); printf("INSERT %i records.\n",ci); @@ -395,19 +395,19 @@ int recover(char* jfn) printf("SKIPed %i records.\n",cs); printf("------------------------\n"); printf("Total %i records.\n",i); - + tim2 = time(NULL); i = tim2 - tim1; printf("took %i sec\n", i); #endif - + fclose(fp); - + return 0; } /** -* recover_all -- Iterates over all core tables in enumerated order for recovery from +* recover_all -- Iterates over all core tables in enumerated order for recovery from * journal files (.jnl). * The parm 'lastn' is the number of journal files needed to be recovered. * Hardcoded to only find MAXFILES. @@ -420,7 +420,7 @@ int recover_all(int lastn) { lnode_p n, h; tbl_cache_p _tbc = tables; - + if(MAXFILES < lastn) return 1; if(!schema_dir) @@ -434,15 +434,15 @@ int recover_all(int lastn) fprintf(stderr, "[recover_all]: null path to db_home.\n"); return 1; } - + while(_tbc) - { + { int j; - + if(_tbc->dtp) h = file_list(db_home, _tbc->dtp->name); n = h; - + /*lastn; move to the oldest of the N*/ for(j=1;jnext != NULL) ) @@ -453,17 +453,17 @@ int recover_all(int lastn) fprintf(stderr, "[recover_all]: Error while recovering: [%s]\n. Continuing..\n",n->p); n = n->prev; } - + while(h) /*free mem*/ { n = h->next; free(h->p); free(h); h = n; } - + _tbc = _tbc->next; } - + return 0; } @@ -472,25 +472,25 @@ int recover_all(int lastn) * extract_key -- uses the internal schema to extract the key from the data * row that was found in the journal. * caller provides inititialize memory for destination key (k). -* data is provided ; key is filled in +* data is provided ; key is filled in */ int extract_key(table_p tp, char* k, char* d) { char *s, *p; char buf[MAX_ROW_SIZE]; int n, len; - + if(!tp || !k || !d) return -1; len=n=0; p = k; - + /*copy data so we can tokenize w.o trampling */ len = strlen(d); strncpy(buf, d, len); buf[len] = 0; - - s = strtok(buf, "|"); - while(s!=NULL && nncols-1) > n) @@ -499,42 +499,42 @@ int extract_key(table_p tp, char* k, char* d) { strncpy(p, s, len); p+=len; - + *p = '|'; p++; } } - + s=strtok(NULL, "|"); n++; } - + *p = 0; return 0; } /** -* delete -- deletes a row from the db we are trying to rebuild +* delete -- deletes a row from the db we are trying to rebuild */ int delete(table_p tp, char* k, int len) { DBT key; DB *db; - + if(!tp || !k) return 1; if((db = get_db(tp)) == NULL) return 2; - + memset(&key, 0, sizeof(DBT)); key.data = k; key.ulen = MAX_ROW_SIZE; key.size = len; - + if ( db->del(db, NULL, &key, 0)) { fprintf(stderr, "[delete] FAILED --> [%.*s] \n", len, k); return 3; } - + return 0; } @@ -546,14 +546,14 @@ int delete(table_p tp, char* k, int len) int _insert(DB* db, char* k, char* v, int klen, int vlen) { DBT key, data; - + if(!db || !k || !v) return 1; - + memset(&key, 0, sizeof(DBT)); key.data = k; key.ulen = MAX_ROW_SIZE; key.size = klen; - + memset(&data, 0, sizeof(DBT)); data.data = v; data.ulen = MAX_ROW_SIZE; @@ -577,20 +577,20 @@ int insert(table_p tp, char* v, int vlen) char k[MAX_ROW_SIZE]; int rc, klen; DB *db; - + if(!tp || !v) return 1; if((db = get_db(tp)) == NULL) return 2; - + memset(k,0,MAX_ROW_SIZE); if( extract_key(tp, k, v) ) { fprintf(stderr, "[insert] failed to extract key for row: %.*s",vlen, v); return 2; } - + klen = strlen(k); rc = _insert(db, k, v, klen, vlen); - + return rc; } @@ -603,16 +603,16 @@ int insert(table_p tp, char* v, int vlen) int update(table_p tp, char* v, int len) { char k[MAX_ROW_SIZE]; - + if(!tp || !v) return 1; - + memset(k,0,MAX_ROW_SIZE); if( extract_key(tp, k, v) ) { fprintf(stderr, "[update] failed to extract key for row: %.*s",len, v); return 2; } - + /* if( delete(tp, k, strlen(k)) ) return 3; */ if( insert(tp, v, len) ) return 4; return 0; @@ -628,7 +628,7 @@ int get_op(char* op, int len) if((len==6) && strstr("INSERT",op) ) return INSERT; if((len==6) && strstr("UPDATE",op) ) return UPDATE; if((len==6) && strstr("DELETE",op) ) return DELETE; - + return UNKNOWN_OP; } @@ -646,38 +646,38 @@ int load_schema(char* d) table_p tp = NULL; FILE * fp = NULL; lnode_p h,n; - + rc=0; h = n = NULL; - + if(!d) { fprintf(stderr, "[load_schema]: null path to schema files.\n"); return 1; } - + tables = (tbl_cache_p)malloc(sizeof(tbl_cache_t)); if(!tables) return 1; - + h = file_list(d, NULL); - + while(h) { n = h->next; - + /*create abs path to journal file (relative to db_home) */ memset(fn, 0 , MAX_FILENAME_SIZE); strcat(fn, d); strcat(fn, "/"); strcat(fn, h->p); - + fp = fopen(fn, "r"); if(!fp) { fprintf(stderr, "[load_schema]: FAILED to load schema file: %s.\n", h->p); break; } - + tn = h->p; tbc = get_table(tn); if(!tbc) @@ -686,9 +686,9 @@ int load_schema(char* d) fprintf(stderr, "[load_schema]: FAILED to load data for table: %s.\n", tn); goto done; } - + tp = tbc->dtp; - + while ( fgets(line1 , MAX_ROW_SIZE, fp) != NULL ) { if ( fgets(line2 , MAX_ROW_SIZE, fp) != NULL ) @@ -701,7 +701,7 @@ int load_schema(char* d) goto done; } } - + if(strstr(line1, METADATA_KEY)) { if(0!=load_metadata_key(tp, line2)) @@ -716,20 +716,20 @@ int load_schema(char* d) fprintf(stderr, "[load_schema]: FAILED to read schema value in table: %s.\n", tn); goto done; } - + } -done: +done: fclose(fp); h = n; } - + while(h) /*free mem*/ { n = h->next; free(h->p); free(h); h = n; } - + return rc; } @@ -755,25 +755,25 @@ tbl_cache_p get_table(char *_s) } _tbc = _tbc->next; } - + _tbc = (tbl_cache_p)malloc(sizeof(tbl_cache_t)); if(!_tbc) return NULL; - + _tp = create_table(_s); - + if(!_tp) { fprintf(stderr, "[get_table]: failed to create table.\n"); free(_tbc); return NULL; } - + _tbc->dtp = _tp; - + if(tables) (tables)->prev = _tbc; - + _tbc->next = tables; tables = _tbc; @@ -788,23 +788,23 @@ table_p create_table(char *_s) { int i; table_p tp = NULL; - + tp = (table_p)malloc(sizeof(table_t)); if(!tp) return NULL; - + i=strlen(_s)+1; tp->name = (char*)malloc(i*sizeof(char)); strncpy(tp->name, _s, i); - + tp->ncols=0; tp->nkeys=0; tp->ro=0; tp->logflags=0; tp->db = NULL; - + for(i=0;icolp[i] = NULL; - + return tp; } @@ -815,39 +815,39 @@ table_p create_table(char *_s) */ int load_metadata_columns(table_p _tp, char* line) { - int ret,n,len; + int n,len; char *s = NULL; char cn[64], ct[16]; column_p col; - ret = n = len = 0; - + n = len = 0; + if(!_tp) return -1; if(_tp->ncols!=0) return 0; - + /* eg: line = "table_name(str) table_version(int)" */ s = strtok(line, " \t"); - while(s!=NULL && nname = (char*)malloc(len * sizeof(char)); strcpy(col->name, cn ); - + /* set type*/ len = strlen( ct )+1; col->type = (char*)malloc(len * sizeof(char)); strcpy(col->type, ct ); - + _tp->colp[n] = col; n++; _tp->ncols++; @@ -867,22 +867,22 @@ int load_metadata_key(table_p _tp, char* line) int ret,n,ci; char *s = NULL; ret = n = ci = 0; - + if(!_tp)return -1; - + s = strtok(line, " \t"); - while(s!=NULL && n< _tp->ncols) + while(s!=NULL && n< _tp->ncols) { ret = sscanf(s,"%i", &ci); if(ret != 1) return -1; - if( _tp->colp[ci] ) + if( _tp->colp[ci] ) { _tp->colp[ci]->kflag = 1; _tp->nkeys++; } n++; s=strtok(NULL, " "); } - + return 0; } @@ -899,36 +899,36 @@ DB* get_db(table_p tp) int rc; DB* db; char dfn[MAX_FILENAME_SIZE]; - + if( !tp) return NULL; if( tp->db) return tp->db; - + memset(dfn, 0, MAX_FILENAME_SIZE); if(db_home) { strcpy(dfn, db_home); strcat(dfn, "/"); } - + /*creation of DB follows*/ strcat(dfn, tp->name); - + if ((rc = db_create(&db, NULL, 0)) != 0) - { + { fprintf(stderr, "[create_table]: error db_create for table: %s.\n",dfn); return NULL; } - + if ((rc = db->open(db, NULL, dfn, NULL, DB_HASH, DB_CREATE, 0664)) != 0) - { + { fprintf(stderr, "[create_table]: error opening %s.\n",dfn); fprintf(stderr, "[create_table]: error msg: %s.\n",db_strerror(rc)); return NULL; } tp->db = db; - + import_schema(tp); - + return db; } @@ -943,25 +943,25 @@ int import_schema(table_p tp) char fn [MAX_FILENAME_SIZE]; FILE * fp = NULL; rc = 0; - + if(!schema_dir) { fprintf(stderr, "[import_schema]: null schema dir.\n"); return 1; } - + if(!tp) { fprintf(stderr, "[import_schema]: null table parameter.\n"); return 1; } - + /*create abs path to journal file (relative to db_home) */ memset(fn, 0 , MAX_FILENAME_SIZE); strcat(fn, schema_dir); strcat(fn, "/"); strcat(fn, tp->name); - + fp = fopen(fn, "r"); if(!fp) { @@ -977,7 +977,7 @@ int import_schema(table_p tp) len2 = strlen(line2)-1; line1[len1] = 0; line2[len2] = 0; - + if((rc = _insert(tp->db, line1, line2, len1, len2) )!=0) { fprintf(stderr, "[import_schema]: FAILED to write schema def into table: %s.\n", tp->name); @@ -989,9 +989,9 @@ int import_schema(table_p tp) fprintf(stderr, "[import_schema]: FAILED to read schema def value in table: %s.\n", tp->name); goto done; } - + } -done: +done: fclose(fp); return rc; } @@ -1017,10 +1017,10 @@ void cleanup(void) free(tp->colp[i]->type); free(tp->colp[i]); } - + if(tp->db) tp->db->close(tp->db, 0); - + free(tp); } free(tables); diff --git a/utils/db_berkeley/bdb_recover.h b/utils/db_berkeley/bdb_recover.h index 5507c0b98a1..e34a8587d4b 100644 --- a/utils/db_berkeley/bdb_recover.h +++ b/utils/db_berkeley/bdb_recover.h @@ -2,7 +2,7 @@ * $Id$ * * recovery for berkeley_db module - * + * * Copyright (C) 2007 Cisco Systems * * This file is part of opensips, a free SIP server. @@ -17,15 +17,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * History: * -------- * 2007-09-19 genesis (wiquan) */ - + #include #include #include @@ -51,7 +51,7 @@ #define METADATA_COLUMNS "METADATA_COLUMNS" /*operations*/ -enum +enum { INSERT, UPDATE, diff --git a/utils/db_oracle/Makefile b/utils/db_oracle/Makefile index b1c8231b1ea..1f1af8ed655 100644 --- a/utils/db_oracle/Makefile +++ b/utils/db_oracle/Makefile @@ -40,13 +40,29 @@ ifeq ($(ORAPATH),) echo $(SYSBASE)/lib64/oracle$(ORAVERDIR) ) endif ifeq ($(ORAPATH),) - ORAPATH=$(shell [ -f $(SYSBASE)/lib/oracle$(ORAVERDIR)/libocci.so ] && \ - echo $(SYSBASE)/lib/oracle$(ORAVERDIR) ) + ORAPATH=$(shell [ -f $(LOCALBASE)/lib64/oracle$(ORAVERDIR)/lib/libocci.so ] && \ + echo $(LOCALBASE)/lib64/oracle$(ORAVERDIR)/lib ) +endif +ifeq ($(ORAPATH),) + ORAPATH=$(shell [ -f $(SYSBASE)/lib64/oracle$(ORAVERDIR)/lib/libocci.so ] && \ + echo $(SYSBASE)/lib64/oracle$(ORAVERDIR)/lib ) +endif +ifeq ($(ORAPATH),) + ORAPATH=$(shell [ -f $(LOCALBASE)/lib/oracle$(ORAVERDIR)/libocci.so ] && \ + echo $(LOCALBASE)/lib/oracle$(ORAVERDIR) ) endif ifeq ($(ORAPATH),) ORAPATH=$(shell [ -f $(SYSBASE)/lib/oracle$(ORAVERDIR)/libocci.so ] && \ echo $(SYSBASE)/lib/oracle$(ORAVERDIR) ) endif +ifeq ($(ORAPATH),) + ORAPATH=$(shell [ -f $(LOCALBASE)/lib/oracle$(ORAVERDIR)/lib/libocci.so ] && \ + echo $(LOCALBASE)/lib/oracle$(ORAVERDIR)/lib ) +endif +ifeq ($(ORAPATH),) + ORAPATH=$(shell [ -f $(SYSBASE)/lib/oracle$(ORAVERDIR)/lib/libocci.so ] && \ + echo $(SYSBASE)/lib/oracle$(ORAVERDIR)/lib ) +endif ifneq ($(ORAPATH),) LIBS +=-L$(ORAPATH) diff --git a/utils/db_oracle/getres.c b/utils/db_oracle/getres.c index 8ccaf4efcdc..8ed27d8e553 100644 --- a/utils/db_oracle/getres.c +++ b/utils/db_oracle/getres.c @@ -93,7 +93,7 @@ static void get_columns(const con_t* con, res_t* _r, dmap_t* _d) { text *name; - status = OCIAttrGet(param, OCI_DTYPE_PARAM, + status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid**)(dvoid*)&name, &len, OCI_ATTR_NAME, con->errhp); if (status != OCI_SUCCESS) goto ora_err; @@ -227,7 +227,7 @@ static void convert_row(const res_t* _res, Str*** _r, const dmap_t* _d) *v = (Str*)&_null; if (t != DB_STR) continue; -#endif +#endif *v = (Str*)&_empty; continue; } diff --git a/utils/db_oracle/outres.c b/utils/db_oracle/outres.c index c5a44f6f780..15bc3a4da18 100644 --- a/utils/db_oracle/outres.c +++ b/utils/db_oracle/outres.c @@ -27,7 +27,7 @@ void out_res(const res_t* _r) pl[i] = ps[i]->len; for(j = 0; j < nr; j++) { ps = _r->rows[j]; - for(i = 0; i < nc; i++) + for(i = 0; i < nc; i++) if(pl[i] < ps[i]->len) pl[i] = ps[i]->len; } diff --git a/utils/db_oracle/util.c b/utils/db_oracle/util.c index 8d942dc19da..e49d805d716 100644 --- a/utils/db_oracle/util.c +++ b/utils/db_oracle/util.c @@ -29,7 +29,7 @@ void __attribute__((noreturn)) oraxit(sword status, const con_t* con) case OCI_ERROR: ecd = 0; if(OCIErrorGet(con->errhp, 1, NULL, &ecd, (OraText*)buf, - sizeof(buf), OCI_HTYPE_ERROR) != OCI_SUCCESS) + sizeof(buf), OCI_HTYPE_ERROR) != OCI_SUCCESS) { snprintf(buf, sizeof(buf), "unknown ORAERR %u", ecd); } diff --git a/utils/opensipsunix/opensipsunix.c b/utils/opensipsunix/opensipsunix.c index 8a23e9a9ba2..360dcb78152 100644 --- a/utils/opensipsunix/opensipsunix.c +++ b/utils/opensipsunix/opensipsunix.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ @@ -70,7 +70,7 @@ int main(int argc, char** argv) fprintf(stderr, "Error while opening socket: %s\n", strerror(errno)); return -1; } - + memset(&from, 0, sizeof(from)); from.sun_family = PF_LOCAL; @@ -98,7 +98,7 @@ int main(int argc, char** argv) memset(&to, 0, sizeof(to)); to.sun_family = PF_LOCAL; strncpy(to.sun_path, argv[1], sizeof(to.sun_path) - 1); - + len = fread(buffer, 1, BUF_SIZE, stdin); if (len) { diff --git a/version.h b/version.h index 52c21d10bf5..8dd783fd35b 100644 --- a/version.h +++ b/version.h @@ -1,7 +1,7 @@ /* * $Id$ * - * version and compile flags macros + * version and compile flags macros * * Copyright (C) 2004 FhG Fokus * @@ -17,18 +17,18 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef version_h #define version_h -#define OPENSIPS_FULL_VERSION NAME " " VERSION " (" ARCH "/" OS ")" +#define OPENSIPS_FULL_VERSION NAME " " VERSION " (" ARCH "/" OS ")" -#ifdef STATS +#ifdef STATISTICS #define STATS_STR "STATS: On" #else #define STATS_STR "STATS: Off" @@ -48,7 +48,7 @@ #ifdef USE_TLS #define USE_TLS_STR ", USE_TLS" -#else +#else #define USE_TLS_STR "" #endif @@ -119,6 +119,12 @@ #define F_MALLOC_STR "" #endif +#ifdef HP_MALLOC +#define HP_MALLOC_STR ", HP_MALLOC" +#else +#define HP_MALLOC_STR "" +#endif + #ifdef USE_SHM_MEM #define USE_SHM_MEM_STR ", USE_SHM_MEM" #else @@ -197,9 +203,9 @@ STATS_STR EXTRA_DEBUG_STR USE_IPV6_STR USE_TCP_STR USE_TLS_STR \ USE_SCTP_STR DISABLE_NAGLE_STR USE_MCAST_STR NO_DEBUG_STR NO_LOG_STR \ SHM_MEM_STR SHM_MMAP_STR PKG_MALLOC_STR VQ_MALLOC_STR F_MALLOC_STR \ - USE_SHM_MEM_STR DBG_QM_MALLOC_STR DBG_F_MALLOC_STR DEBUG_DMALLOC_STR \ - QM_JOIN_FREE_STR FAST_LOCK_STR NOSMP_STR USE_PTHREAD_MUTEX_STR \ - USE_POSIX_SEM_STR USE_SYSV_SEM_STR + HP_MALLOC_STR USE_SHM_MEM_STR DBG_QM_MALLOC_STR DBG_F_MALLOC_STR \ + DEBUG_DMALLOC_STR QM_JOIN_FREE_STR FAST_LOCK_STR NOSMP_STR \ + USE_PTHREAD_MUTEX_STR USE_POSIX_SEM_STR USE_SYSV_SEM_STR #endif diff --git a/xlog.c b/xlog.c index 44f23458d3b..416e6348e4e 100644 --- a/xlog.c +++ b/xlog.c @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -78,7 +78,7 @@ int xlog_2(struct sip_msg* msg, char* lev, char* frm) xlp = (xl_level_p)lev; if(xlp->type==1) { - if(pv_get_spec_value(msg, &xlp->v.sp, &value)!=0 + if(pv_get_spec_value(msg, &xlp->v.sp, &value)!=0 || value.flags&PV_VAL_NULL || !(value.flags&PV_VAL_INT)) { LM_ERR("invalid log level value [%d]\n", value.flags); @@ -153,7 +153,7 @@ int pv_parse_color_name(pv_spec_p sp, str *in) LM_ERR("color name must have two chars\n"); return -1; } - + /* foreground */ switch(in->s[0]) { @@ -165,10 +165,10 @@ int pv_parse_color_name(pv_spec_p sp, str *in) case 'B': case 'P': case 'C': case 'W': break; - default: + default: goto error; } - + /* background */ switch(in->s[1]) { @@ -176,11 +176,11 @@ int pv_parse_color_name(pv_spec_p sp, str *in) case 's': case 'r': case 'g': case 'y': case 'b': case 'p': case 'c': case 'w': - break; - default: + break; + default: goto error; } - + sp->pvp.pvn.type = PV_NAME_INTSTR; sp->pvp.pvn.u.isname.type = AVP_NAME_STR; sp->pvp.pvn.u.isname.name.s = *in; @@ -207,7 +207,7 @@ int pv_parse_color_name(pv_spec_p sp, str *in) LM_ERR("append_sstring overflow\n"); \ goto error;\ } \ - } while(0) + } while(0) int pv_get_color(struct sip_msg *msg, pv_param_t *param, @@ -227,10 +227,10 @@ int pv_get_color(struct sip_msg *msg, pv_param_t *param, p = color; end = p + COL_BUF; - + /* excape sequenz */ append_sstring(p, end, "\033["); - + if(param->pvn.u.isname.name.s.s[0]!='_') { if (islower((int)param->pvn.u.isname.name.s.s[0])) @@ -243,7 +243,7 @@ int pv_get_color(struct sip_msg *msg, pv_param_t *param, param->pvn.u.isname.name.s.s[0] += 32; } } - + /* foreground */ switch(param->pvn.u.isname.name.s.s[0]) { @@ -278,7 +278,7 @@ int pv_get_color(struct sip_msg *msg, pv_param_t *param, LM_ERR("invalid foreground\n"); return pv_get_null(msg, param, res); } - + /* background */ switch(param->pvn.u.isname.name.s.s[1]) { diff --git a/xlog.h b/xlog.h index efcb9315672..80d77524b5b 100644 --- a/xlog.h +++ b/xlog.h @@ -15,8 +15,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */