Revert "lrkproxy: Add new features : TURN support, behind_nat support, subset of... master
authorMojtaba Esfandiari.S <mespio@gmail.com>
Sat, 24 Sep 2022 12:40:10 +0000 (16:10 +0330)
committerMojtaba Esfandiari.S <mespio@gmail.com>
Sat, 24 Sep 2022 12:40:10 +0000 (16:10 +0330)
This reverts commit f2b07f2321980e74247cb0c968b98925172f6874.

110 files changed:
.github/workflows/main.yml
.github/workflows/pull_request.yml
etc/kamailio.cfg
pkg/kamailio/deb/bionic/changelog
pkg/kamailio/deb/bionic/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/bookworm/changelog
pkg/kamailio/deb/bookworm/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/bullseye/changelog
pkg/kamailio/deb/bullseye/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/buster/changelog
pkg/kamailio/deb/buster/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/debian/changelog
pkg/kamailio/deb/focal/changelog
pkg/kamailio/deb/focal/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/jammy/changelog
pkg/kamailio/deb/jammy/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/jessie/changelog
pkg/kamailio/deb/jessie/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/precise/changelog
pkg/kamailio/deb/precise/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/sid/changelog
pkg/kamailio/deb/sid/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/stretch/changelog
pkg/kamailio/deb/stretch/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/trusty/changelog
pkg/kamailio/deb/trusty/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/wheezy/changelog
pkg/kamailio/deb/wheezy/kamailio-tls-modules.lintian-overrides
pkg/kamailio/deb/xenial/changelog
pkg/kamailio/deb/xenial/kamailio-tls-modules.lintian-overrides
pkg/kamailio/obs/kamailio.spec
src/core/cfg.lex
src/core/cfg.y
src/core/core_cmd.c
src/core/dprint.c
src/core/ip_addr.c
src/core/ip_addr.h
src/core/kemi.c
src/core/parser/msg_parser.c
src/core/parser/msg_parser.h
src/core/ppcfg.c
src/core/ppcfg.h
src/core/sr_module.c
src/core/sr_module.h
src/core/udp_server.c
src/core/utils/snexpr.h [new file with mode: 0644]
src/main.c
src/modules/acc/acc_cdr.c
src/modules/acc/acc_extra.c
src/modules/acc_json/acc_json_mod.c
src/modules/acc_json/acc_json_mod.h
src/modules/app_python3/python_msgobj.c
src/modules/corex/corex_rpc.c
src/modules/dialog/README
src/modules/dialog/dialog.c
src/modules/dialog/dlg_cb.h
src/modules/dialog/dlg_cseq.c
src/modules/dialog/dlg_handlers.c
src/modules/dialog/dlg_load.h
src/modules/dialog/dlg_var.c
src/modules/dialog/dlg_var.h
src/modules/dialog/doc/dialog_admin.xml
src/modules/dialplan/dialplan.c
src/modules/dispatcher/dispatch.c
src/modules/dmq/README
src/modules/dmq/doc/dmq_admin.xml
src/modules/dmq_usrloc/usrloc_sync.c
src/modules/kex/mod_stats.c
src/modules/posops/README
src/modules/posops/doc/posops_admin.xml
src/modules/pua_dialoginfo/pua_dialoginfo.c
src/modules/pv/README
src/modules/pv/doc/pv_admin.xml
src/modules/pv/pv_core.c
src/modules/pv/pv_time.c
src/modules/pv_headers/pv_headers.c
src/modules/ratelimit/ratelimit.c
src/modules/rtpengine/README
src/modules/rtpengine/doc/rtpengine_admin.xml
src/modules/rtpengine/rtpengine.c
src/modules/sipdump/sipdump_mod.c
src/modules/sipdump/sipdump_pcap.c
src/modules/siptrace/siptrace_hep.c
src/modules/siputils/siputils.c
src/modules/tls/tls_init.c
src/modules/tls_wolfssl/tls_cfg.c
src/modules/tls_wolfssl/tls_config.c
src/modules/tls_wolfssl/tls_domain.h
src/modules/tls_wolfssl/tls_init.c
src/modules/tls_wolfssl/tls_rpc.c
src/modules/tm/README
src/modules/tm/doc/functions.xml
src/modules/tm/t_fwd.c
src/modules/tm/t_lookup.c
src/modules/tm/t_lookup.h
src/modules/tm/timer.c
src/modules/tm/tm.c
src/modules/tm/tm_load.c
src/modules/tm/tm_load.h
src/modules/tmx/t_var.c
src/modules/topos/README
src/modules/topos/doc/topos_admin.xml
src/modules/topos/topos_mod.c
src/modules/topos/tps_msg.c
src/modules/topos/tps_msg.h
src/modules/tsilo/ts_append.c
src/modules/uac/replace.c
src/modules/usrloc/ul_keepalive.c
src/modules/utils/Makefile
src/modules/websocket/ws_conn.c

index 8704cda..10acce3 100644 (file)
@@ -8,6 +8,8 @@ name: build
       - '5.5'
   # Allows you to run this workflow manually from the Actions tab
   workflow_dispatch:
+permissions:
+  contents: read # to fetch code (actions/checkout)
 jobs:
   build:
     runs-on: ubuntu-latest
index 2633e7e..e2f6416 100644 (file)
@@ -6,6 +6,8 @@ name: checks_pr
       - master
   # Allows you to run this workflow manually from the Actions tab
   workflow_dispatch:
+permissions:
+  contents: read # to fetch code (actions/checkout)
 jobs:
   build:
     runs-on: ubuntu-latest
index eb41c14..3915f3e 100644 (file)
@@ -24,7 +24,7 @@
 # *** To run in debug mode:
 #     - define WITH_DEBUG
 #     - debug level increased to 3, logs still sent to syslog
-#     - debugger module loaded with cfgtrace endabled
+#     - debugger module loaded with cfgtrace enabled
 #
 # *** To enable mysql:
 #     - define WITH_MYSQL
@@ -854,7 +854,7 @@ route[NATDETECT] {
        return;
 }
 
-# RTPProxy control and signaling updates for NAT traversal
+# RTP relaying management and signaling updates for NAT traversal
 route[NATMANAGE] {
 #!ifdef WITH_NAT
        if (is_request()) {
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index ebcf613..316efba 100644 (file)
@@ -1,3 +1,9 @@
+kamailio (5.7.0~dev1) unstable; urgency=medium
+
+  * version set 5.7.0~dev1
+
+ -- Victor Seva <vseva@debian.org>  Sun, 28 Aug 2022 22:36:28 +0200
+
 kamailio (5.7.0~dev0) unstable; urgency=medium
 
   * version set 5.7.0~dev0
index f04c65e..d1e84e6 100644 (file)
@@ -1,2 +1,2 @@
 kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
-kamailio-tls-modules binary: library-not-linked-against-libc */kamailio/openssl_mutex_shared/openssl_mutex_shared.so
+kamailio-tls-modules binary: library-not-linked-against-libc
index a82187d..d1425f6 100644 (file)
@@ -290,7 +290,7 @@ Conflicts:  kamailio-utils < %ver, kamailio-websocket < %ver
 Conflicts:  kamailio-xhttp-pi < %ver, kamailio-xmlops < %ver
 Conflicts:  kamailio-xmlrpc < %ver, kamailio-xmpp < %ver
 Conflicts:  kamailio-uuid < %ver
-BuildRequires:  bison, flex, which, make, gcc, gcc-c++, pkgconfig
+BuildRequires:  bison, flex, which, make, gcc, gcc-c++, pkgconfig, readline-devel
 %if 0%{?rhel} != 6
 Requires:  systemd
 BuildRequires:  systemd-devel
@@ -2420,6 +2420,8 @@ fi
 
 
 %changelog
+* Tue Sep 13 2022 Gustavo Almeida <galmeida@broadvoice.com>
+  - added readline-devel build dependency
 * Sat Aug 31 2019 Sergey Safarov <s.safarov@gmail.com> 5.3.0-dev7
   - Packaged kemix, lost and xhttp_prom modules
 * Sat Mar 30 2019 Sergey Safarov <s.safarov@gmail.com> 5.3.0-0
index a5a595f..cc0afb8 100644 (file)
 /* start conditions */
 %x STRING1 STRING2 STR_BETWEEN COMMENT COMMENT_LN ATTR SELECT AVP_PVAR PVAR_P
 %x PVARID INCLF IMPTF EVRTNAME CFGPRINTMODE CFGPRINTLOADMOD DEFENV_ID DEFENVS_ID
-%x TRYDEFENV_ID TRYDEFENVS_ID LINECOMMENT DEFINE_ID DEFINE_EOL DEFINE_DATA 
-%x IFDEF_ID IFDEF_EOL IFDEF_SKIP
+%x TRYDEFENV_ID TRYDEFENVS_ID LINECOMMENT DEFINE_ID DEFINE_EOL DEFINE_DATA
+%x IFDEF_ID IFDEF_EOL IFDEF_SKIP IFEXP_STM
 
 /* config script types : #!SER  or #!KAMAILIO or #!MAX_COMPAT */
 SER_CFG                        SER
@@ -312,7 +312,7 @@ DOMAIN              domain
 SR_AUTO_ALIASES        auto_aliases
 SR_AUTO_DOMAINS auto_domains
 DNS             dns
-REV_DNS         rev_dns
+REV_DNS         rev_dns|dns_rev_via
 DNS_TRY_IPV6   dns_try_ipv6
 DNS_TRY_NAPTR  dns_try_naptr
 DNS_SRV_LB             dns_srv_lb|dns_srv_loadbalancing
@@ -329,8 +329,8 @@ DNS_SEARCH_FMATCH   dns_search_full_match
 DNS_NAPTR_IGNORE_RFC   dns_naptr_ignore_rfc
 /* dns cache */
 DNS_CACHE_INIT dns_cache_init
-DNS_USE_CACHE  use_dns_cache
-DNS_USE_FAILOVER       use_dns_failover
+DNS_USE_CACHE  use_dns_cache|dns_use_cache
+DNS_USE_FAILOVER       use_dns_failover|dns_use_failover
 DNS_CACHE_FLAGS                dns_cache_flags
 DNS_CACHE_NEG_TTL      dns_cache_negative_ttl
 DNS_CACHE_MIN_TTL      dns_cache_min_ttl
@@ -571,9 +571,12 @@ PREP_START "#!"|"!!"
 DEFINE       "define"|"def"
 IFDEF        ifdef
 IFNDEF       ifndef
+IFEXP        ifexp
 ENDIF        endif
 TRYDEF       "trydefine"|"trydef"
 REDEF        "redefine"|"redef"
+DEFEXP       defexp
+DEFEXPS      defexps
 DEFENV       defenv
 DEFENVS      defenvs
 TRYDEFENV    trydefenv
@@ -1328,15 +1331,23 @@ IMPORTFILE      "import_file"
 
 <INITIAL,CFGPRINTMODE>{PREP_START}{DEFINE}{EAT_ABLE}+  {       count();
                                                                                        ksr_cfg_print_part(yytext);
-                                                                                       pp_define_set_type(0);
+                                                                                       pp_define_set_type(KSR_PPDEF_DEFINE);
                                                                                        state = DEFINE_S; BEGIN(DEFINE_ID); }
 <INITIAL,CFGPRINTMODE>{PREP_START}{TRYDEF}{EAT_ABLE}+  {       count();
                                                                                        ksr_cfg_print_part(yytext);
-                                                                                       pp_define_set_type(1);
+                                                                                       pp_define_set_type(KSR_PPDEF_TRYDEF);
                                                                                        state = DEFINE_S; BEGIN(DEFINE_ID); }
 <INITIAL,CFGPRINTMODE>{PREP_START}{REDEF}{EAT_ABLE}+   {       count();
                                                                                        ksr_cfg_print_part(yytext);
-                                                                                       pp_define_set_type(2);
+                                                                                       pp_define_set_type(KSR_PPDEF_REDEF);
+                                                                                       state = DEFINE_S; BEGIN(DEFINE_ID); }
+<INITIAL,CFGPRINTMODE>{PREP_START}{DEFEXP}{EAT_ABLE}+  {       count();
+                                                                                       ksr_cfg_print_part(yytext);
+                                                                                       pp_define_set_type(KSR_PPDEF_DEFEXP);
+                                                                                       state = DEFINE_S; BEGIN(DEFINE_ID); }
+<INITIAL,CFGPRINTMODE>{PREP_START}{DEFEXPS}{EAT_ABLE}+ {       count();
+                                                                                       ksr_cfg_print_part(yytext);
+                                                                                       pp_define_set_type(KSR_PPDEF_DEFEXPS);
                                                                                        state = DEFINE_S; BEGIN(DEFINE_ID); }
 <DEFINE_ID>{ID}{MINUS}          {      count();
                                                                        ksr_cfg_print_part(yytext);
@@ -1381,6 +1392,9 @@ IMPORTFILE      "import_file"
 <INITIAL,CFGPRINTMODE,IFDEF_SKIP>{PREP_START}{IFNDEF}{EAT_ABLE}+    { count();
                                                                if (pp_ifdef_type(0)) return 1;
                                                                state = IFDEF_S; BEGIN(IFDEF_ID); }
+<INITIAL,CFGPRINTMODE,IFDEF_SKIP>{PREP_START}{IFEXP}{EAT_ABLE}+    { count();
+                                                               if (pp_ifdef_type(1)) return 1;
+                                                               state = IFDEF_S; BEGIN(IFEXP_STM); }
 <IFDEF_ID>{ID}{MINUS}           { count();
                                                                        LM_CRIT(
                                                                                "error at %s line %d: '-' not allowed\n",
@@ -1390,6 +1404,11 @@ IMPORTFILE      "import_file"
 <IFDEF_ID>{ID}                { count();
                                                                pp_ifdef_var(yyleng, yytext);
                                                                state = IFDEF_EOL_S; BEGIN(IFDEF_EOL); }
+<IFEXP_STM>.*{CR}        { count();
+                                                               pp_ifexp_eval(yytext, yyleng);
+                                                               state = IFDEF_EOL_S; BEGIN(IFDEF_EOL);
+                                                               pp_ifdef();
+                                                               }
 <IFDEF_EOL>{EAT_ABLE}*{CR}    { count(); pp_ifdef(); }
 
 <INITIAL,CFGPRINTMODE,IFDEF_SKIP>{PREP_START}{ELSE}{EAT_ABLE}*{CR}    { count(); pp_else(); }
@@ -1656,7 +1675,7 @@ static void ksr_cfg_print_define_module(char *modpath, int modpathlen)
        }
        memcpy(defmod, "MOD_", 4);
        memcpy(defmod+4, modname.s, modname.len);
-       pp_define_set_type(0);
+       pp_define_set_type(KSR_PPDEF_DEFINE);
        if(pp_define(modname.len + 4, defmod)<0) {
                printf("\n# ***** ERROR: unable to set cfg define for module: %s\n",
                                modpath);
@@ -2016,7 +2035,7 @@ ksr_ppdefine_t* pp_get_define(int idx)
        return &pp_defines[idx];
 }
 
-static int pp_lookup(int len, const char *text)
+int pp_lookup(int len, const char *text)
 {
        str var = {(char *)text, len};
        int i;
@@ -2058,11 +2077,11 @@ int pp_define(int len, const char *text)
        pp_define_index = -1;
        ppos = pp_lookup(len, text);
        if(ppos >= 0) {
-               if(pp_define_type==1) {
+               if(pp_define_type==KSR_PPDEF_TRYDEF) {
                        LM_DBG("ignoring - already defined: %.*s\n", len, text);
                        pp_define_index = -2;
                        return 0;
-               } else if(pp_define_type==2) {
+               } else if(pp_define_type==KSR_PPDEF_REDEF) {
                        LM_DBG("redefining: %.*s\n", len, text);
                        pp_define_index = ppos;
                        if(pp_defines[ppos].value.s != NULL) {
@@ -2098,6 +2117,7 @@ int pp_define(int len, const char *text)
 int pp_define_set(int len, char *text, int mode)
 {
        int ppos;
+       char *sval = NULL;
 
        if(pp_define_index == -2) {
                /* #!trydef that should be ignored */
@@ -2135,8 +2155,33 @@ int pp_define_set(int len, char *text, int mode)
                return -1;
        }
 
-       pp_defines[ppos].value.len = len;
-       pp_defines[ppos].value.s = text;
+       if(pp_defines[ppos].dtype == KSR_PPDEF_DEFEXP
+                       || pp_defines[ppos].dtype == KSR_PPDEF_DEFEXPS) {
+               if(pp_defines[ppos].dtype == KSR_PPDEF_DEFEXP) {
+                       sval = pp_defexp_eval(text, len, 0);
+               } else {
+                       sval = pp_defexp_eval(text, len, 1);
+               }
+               if(sval==NULL) {
+                       LM_NOTICE("no value returned to set the defexp [%.*s]\n",
+                               pp_defines[ppos].name.len, pp_defines[ppos].name.s);
+                       return 0;
+               }
+               pp_defines[ppos].value.s = sval;
+               pp_defines[ppos].value.len = strlen(sval);
+       } else {
+               pp_defines[ppos].value.s = (char*)pkg_malloc(len+1);
+               if (pp_defines[ppos].value.s == NULL) {
+                       LM_ERR("no more memory to define %.*s [%d]\n",
+                               pp_defines[ppos].name.len,
+                               pp_defines[ppos].name.s, ppos);
+                       return -1;
+               }
+
+               memcpy(pp_defines[ppos].value.s, text, len);
+               pp_defines[ppos].value.s[len] = '\0';
+               pp_defines[ppos].value.len = len;
+       }
        LM_DBG("### setting define ID [%.*s] value [%.*s] (mode: %d)\n",
                        pp_defines[ppos].name.len,
                        pp_defines[ppos].name.s,
@@ -2178,7 +2223,7 @@ int pp_define_env(const char *text, int len, int qmode, int vmode)
        }
        defvalue.len = strlen(defvalue.s);
 
-       pp_define_set_type(0);
+       pp_define_set_type(KSR_PPDEF_DEFINE);
        if(pp_define(defname.len, defname.s)<0) {
                LM_ERR("cannot set define name [%s]\n", (char*)text);
                return -1;
@@ -2245,6 +2290,11 @@ static void pp_ifdef_var(int len, const char *text)
        pp_ifdef_stack[pp_sptr] ^= (pp_lookup(len, text) < 0);
 }
 
+void pp_ifexp_state(int state)
+{
+       pp_ifdef_stack[pp_sptr] = state;
+}
+
 static void pp_update_state()
 {
        int i;
index 19ba698..02cb7bd 100644 (file)
@@ -2045,14 +2045,38 @@ cfg_var:
 module_stm:
        LOADMODULE STRING {
                LM_DBG("loading module %s\n", $2);
-                       if (load_module($2)!=0) {
+                       if (ksr_load_module($2, NULL)!=0) {
+                               yyerror("failed to load module");
+                       }
+       }
+       | LOADMODULE LPAREN STRING RPAREN {
+               LM_DBG("loading module %s\n", $3);
+                       if (ksr_load_module($3, NULL)!=0) {
+                               yyerror("failed to load module");
+                       }
+       }
+       | LOADMODULE LPAREN STRING COMMA STRING RPAREN {
+               LM_DBG("loading module %s opts %s\n", $3, $5);
+                       if (ksr_load_module($3, $5)!=0) {
                                yyerror("failed to load module");
                        }
        }
        | LOADMODULE error      { yyerror("string expected"); }
        | LOADMODULEX STRING {
                LM_DBG("loading module %s\n", $2);
-                       if (load_modulex($2)!=0) {
+                       if (ksr_load_modulex($2, NULL)!=0) {
+                               yyerror("failed to load module");
+                       }
+       }
+       | LOADMODULEX LPAREN STRING RPAREN {
+               LM_DBG("loading module %s\n", $3);
+                       if (ksr_load_modulex($3, NULL)!=0) {
+                               yyerror("failed to load module");
+                       }
+       }
+       | LOADMODULEX LPAREN STRING COMMA STRING RPAREN {
+               LM_DBG("loading module %s opts %s\n", $3, $5);
+                       if (ksr_load_modulex($3, $5)!=0) {
                                yyerror("failed to load module");
                        }
        }
index c464d36..3c9f08e 100644 (file)
@@ -988,7 +988,8 @@ static void core_sockets_list(rpc_t* rpc, void* c)
                for(si=list?*list:0; si; si=si->next){
                        rpc->struct_add(hr, "{", "socket", &ha);
                        if (si->addr_info_lst){
-                               rpc->struct_add(ha, "ss",
+                               rpc->struct_add(ha, "sss",
+                                               "af", get_af_name(si->address.af),
                                                "proto", get_proto_name(proto),
                                                "address", si->address_str.s);
                                for (ai=si->addr_info_lst; ai; ai=ai->next)
@@ -1003,7 +1004,8 @@ static void core_sockets_list(rpc_t* rpc, void* c)
                                printf("             %s: %s",
                                                get_proto_name(proto),
                                                si->name.s);
-                               rpc->struct_add(ha, "ss",
+                               rpc->struct_add(ha, "sss",
+                                               "af", get_af_name(si->address.af),
                                                "proto", get_proto_name(proto),
                                                "address", si->name.s);
                                if (!(si->flags & SI_IS_IP))
index f4780bb..ff63fd9 100644 (file)
@@ -504,7 +504,7 @@ void log_prefix_set(sip_msg_t *msg)
        log_callid_set(msg);
        if(log_prefix_pvs == NULL)
                return;
-       if(msg==NULL || !(IS_SIP(msg) || IS_SIP_REPLY(msg))) {
+       if(msg==NULL || !IS_SIP_MSG(msg)) {
                log_prefix_val = NULL;
                return;
        }
index 77ac233..9c91c60 100644 (file)
@@ -717,6 +717,22 @@ char* get_proto_name(unsigned int proto)
        }
 }
 
+/** get address family name (asciiz).
+ * @param af - address family id
+ * @return  string with the adderess family name or "unknown".
+ */
+char* get_af_name(unsigned int af)
+{
+       switch(af) {
+               case AF_INET:
+                       return "IPv4";
+               case AF_INET6:
+                       return "IPv6";
+               default:
+                       return "unknown";
+       }
+}
+
 
 /**
  * match ip address with net address and bitmask
index 4fcdebb..7f910a4 100644 (file)
@@ -304,6 +304,8 @@ char* get_proto_name(unsigned int proto);
 int get_valid_proto_string(unsigned int iproto, int utype, int vtype,
                str *sproto);
 
+char* get_af_name(unsigned int af);
+
 #ifdef USE_MCAST
 /* Returns 1 if the given address is a multicast address */
 int is_mcast(struct ip_addr* ip);
index 13428d4..d671650 100644 (file)
@@ -3396,7 +3396,12 @@ int sr_kemi_modules_add(sr_kemi_t *klist)
                _sr_kemi_modules[_sr_kemi_modules_size-1].kexp = klist;
        } else {
                LM_DBG("adding module: %.*s\n", klist[0].mname.len, klist[0].mname.s);
-               _sr_kemi_modules[_sr_kemi_modules_size].mname = klist[0].mname;
+               if(pkg_str_dup(&_sr_kemi_modules[_sr_kemi_modules_size].mname,
+                                       &klist[0].mname)<0) {
+                       LM_ERR("failed to clone module name: %.*s\n", klist[0].mname.len,
+                                       klist[0].mname.s);
+                       return -1;
+               }
                _sr_kemi_modules[_sr_kemi_modules_size].kexp = klist;
                _sr_kemi_modules_size++;
        }
index 6455c9e..7a38555 100644 (file)
@@ -623,9 +623,11 @@ int parse_headers(struct sip_msg* const msg, const hdr_flags_t flags, const int
 
 skip:
        msg->unparsed=tmp;
-       if(msg->headers==NULL) {
-               /* nothing parsed - invalid input sip message */
-               goto error1;
+       if(ksr_sip_parser_mode & KSR_SIP_PARSER_MODE_STRICT) {
+               if(msg->headers==NULL) {
+                       /* nothing parsed - invalid input sip message */
+                       goto error1;
+               }
        }
        /* restore original flags */
        msg->parsed_flag |= orig_flag;
index 8b44ce4..595c1be 100644 (file)
@@ -147,11 +147,20 @@ if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \
        (((req)->first_line.type == SIP_REQUEST) &&           \
        ((req)->first_line.flags & FLINE_FLAG_PROTO_SIP))
 
+/* sip request */
+#define IS_SIP_REQUEST(req)                             \
+       (((req)->first_line.type == SIP_REQUEST) &&           \
+       ((req)->first_line.flags & FLINE_FLAG_PROTO_SIP))
+
 /* sip reply */
 #define IS_SIP_REPLY(rpl)                               \
        (((rpl)->first_line.type == SIP_REPLY) &&             \
        ((rpl)->first_line.flags & FLINE_FLAG_PROTO_SIP))
 
+/* sip message */
+#define IS_SIP_MSG(req)                                  \
+       ((req)->first_line.flags & FLINE_FLAG_PROTO_SIP)
+
 /* http request */
 #define IS_HTTP(req)                                    \
        (((req)->first_line.type == SIP_REQUEST) &&           \
index 5a85a40..e8aac78 100644 (file)
 
 #include "mem/mem.h"
 #include "ut.h"
+#include "trim.h"
 #include "re.h"
 #include "pvar.h"
 #include "pvapi.h"
 #include "str_list.h"
 #include "dprint.h"
+#include "utils/snexpr.h"
 
 #include "ppcfg.h"
 #include "fmsg.h"
@@ -167,7 +169,7 @@ found_regexp:
 found_repl:
        defvalue.len = p - defvalue.s;
 
-       pp_define_set_type(0);
+       pp_define_set_type(KSR_PPDEF_DEFINE);
        if(pp_define(defname.len, defname.s)<0) {
                LM_ERR("cannot set define name\n");
                goto error;
@@ -289,6 +291,7 @@ void pp_define_core(void)
        char defval[64];
        char *p;
        int n;
+       str_list_t *sb;
 
        strcpy(defval, NAME);
        p = defval;
@@ -297,40 +300,236 @@ void pp_define_core(void)
                p++;
        }
 
-       n = snprintf(p, 64 - (int)(p-defval), "_%d", VERSIONVAL/1000000);
+       n = snprintf(p, 64 - (int)(p-defval), "_%u", VERSIONVAL/1000000);
        if(n<0 || n>=64 - (int)(p-defval)) {
                LM_ERR("failed to build define token\n");
                return;
        }
-       pp_define_set_type(0);
+       pp_define_set_type(KSR_PPDEF_DEFINE);
        if(pp_define(strlen(defval), defval)<0) {
                LM_ERR("unable to set cfg define: %s\n", defval);
                return;
        }
 
-       n = snprintf(p, 64 - (int)(p-defval), "_%d_%d", VERSIONVAL/1000000,
+       n = snprintf(p, 64 - (int)(p-defval), "_%u_%u", VERSIONVAL/1000000,
                        (VERSIONVAL%1000000)/1000);
        if(n<0 || n>=64 - (int)(p-defval)) {
                LM_ERR("failed to build define token\n");
                return;
        }
-       pp_define_set_type(0);
+       pp_define_set_type(KSR_PPDEF_DEFINE);
        if(pp_define(strlen(defval), defval)<0) {
                LM_ERR("unable to set cfg define: %s\n", defval);
                return;
        }
 
-       n = snprintf(p, 64 - (int)(p-defval), "_%d_%d_%d", VERSIONVAL/1000000,
+       n = snprintf(p, 64 - (int)(p-defval), "_%u_%u_%u", VERSIONVAL/1000000,
                        (VERSIONVAL%1000000)/1000, VERSIONVAL%1000);
        if(n<0 || n>=64 - (int)(p-defval)) {
                LM_ERR("failed to build define token\n");
                return;
        }
-       pp_define_set_type(0);
+       pp_define_set_type(KSR_PPDEF_DEFINE);
        if(pp_define(strlen(defval), defval)<0) {
                LM_ERR("unable to set cfg define: %s\n", defval);
                return;
        }
+
+       strcpy(p, "_VERSION");
+       pp_define_set_type(KSR_PPDEF_DEFINE);
+       if(pp_define(strlen(defval), defval)<0) {
+               LM_ERR("unable to set cfg define: %s\n", defval);
+               return;
+       }
+
+       n = snprintf(defval, 64, "%u", VERSIONVAL);
+       if(n<0 || n>=64) {
+               LM_ERR("failed to build version define value\n");
+               return;
+       }
+       sb = str_list_block_add(&_ksr_substdef_strlist, defval, strlen(defval));
+       if(sb==NULL) {
+               LM_ERR("failed to store version define value\n");
+               return;
+       }
+       if(pp_define_set(sb->s.len, sb->s.s, KSR_PPDEF_NORMAL)<0) {
+               LM_ERR("error setting version define value\n");
+               return;
+       }
+
+       if(pp_define(strlen("OS_NAME"), "OS_NAME")<0) {
+               LM_ERR("unable to set cfg define OS_NAME\n");
+               return;
+       }
+       if(pp_define_set(strlen(OS_QUOTED), OS_QUOTED, KSR_PPDEF_NORMAL)<0) {
+               LM_ERR("error setting OS_NAME define value\n");
+               return;
+       }
+}
+
+static struct snexpr* pp_snexpr_defval(char *vname)
+{
+       int idx = 0;
+       ksr_ppdefine_t *pd = NULL;
+
+       if(vname==NULL) {
+               return NULL;
+       }
+
+       idx = pp_lookup(strlen(vname), vname);
+       if(idx < 0) {
+               LM_DBG("define id [%s] not found - return 0\n", vname);
+               return snexpr_convert_num(0, SNE_OP_CONSTNUM);
+       }
+       pd = pp_get_define(idx);
+       if(pd == NULL) {
+               LM_DBG("define id [%s] at index [%d] not found - return 0\n", vname, idx);
+               return snexpr_convert_num(0, SNE_OP_CONSTNUM);
+       }
+
+       if(pd->value.s != NULL) {
+               LM_DBG("define id [%s] at index [%d] found with value - return [%.*s]\n",
+                               vname, idx, pd->value.len, pd->value.s);
+               if(pd->value.len>=2 && (pd->value.s[0]=='"' || pd->value.s[0]=='\'')
+                               && pd->value.s[0]==pd->value.s[pd->value.len-1]) {
+                       /* strip enclosing quotes for string value */
+                       return snexpr_convert_stzl(pd->value.s+1, pd->value.len-2, SNE_OP_CONSTSTZ);
+               } else {
+                       return snexpr_convert_stzl(pd->value.s, pd->value.len, SNE_OP_CONSTSTZ);
+               }
+       } else {
+               LM_DBG("define id [%s] at index [%d] found without value - return 1\n",
+                               vname, idx);
+               return snexpr_convert_num(1, SNE_OP_CONSTNUM);
+       }
+}
+
+void pp_ifexp_eval(char *exval, int exlen)
+{
+       str exstr;
+       struct snexpr_var_list vars = {0};
+       struct snexpr *e = NULL;
+       struct snexpr *result = NULL;
+       int b = 0;
+
+       exstr.s = exval;
+       exstr.len = exlen;
+       trim(&exstr);
+
+       LM_DBG("evaluating [%.*s]\n", exstr.len, exstr.s);
+
+       e = snexpr_create(exstr.s, exstr.len, &vars, NULL, pp_snexpr_defval);
+       if(e == NULL) {
+               LM_ERR("failed to create expression [%.*s]\n", exstr.len, exstr.s);
+               pp_ifexp_state(0);
+               return;
+       }
+
+       result = snexpr_eval(e);
+
+       if(result==NULL) {
+               LM_ERR("expression evaluation [%.*s] is null\n", exstr.len, exstr.s);
+               pp_ifexp_state(0);
+               goto end;
+       }
+
+       if(result->type == SNE_OP_CONSTNUM) {
+               LM_DBG("expression number result: %g\n", result->param.num.nval);
+               if(result->param.num.nval) {
+                       b = 1;
+               } else {
+                       b = 0;
+               }
+       } else if(result->type == SNE_OP_CONSTSTZ) {
+               if(result->param.stz.sval==NULL || strlen(result->param.stz.sval)==0) {
+                       LM_DBG("expression string result: <%s>\n",
+                                       (result->param.stz.sval)?"empty":"null");
+                       b = 0;
+               } else {
+                       LM_DBG("expression string result: [%s]\n", result->param.stz.sval);
+                       b = 1;
+               }
+       }
+
+       LM_DBG("expression evaluation [%.*s] is [%s]\n", exstr.len, exstr.s,
+                       (b)?"true":"false");
+
+       pp_ifexp_state(b);
+
+       snexpr_result_free(result);
+end:
+       snexpr_destroy(e, &vars);
+}
+
+char *pp_defexp_eval(char *exval, int exlen, int qmode)
+{
+       str exstr;
+       struct snexpr_var_list vars = {0};
+       struct snexpr *e = NULL;
+       struct snexpr *result = NULL;
+       str sval = STR_NULL;
+       char *res = NULL;
+
+       exstr.s = exval;
+       exstr.len = exlen;
+       trim(&exstr);
+
+       LM_DBG("evaluating [%.*s]\n", exstr.len, exstr.s);
+
+       e = snexpr_create(exstr.s, exstr.len, &vars, NULL, pp_snexpr_defval);
+       if(e == NULL) {
+               LM_ERR("failed to create expression [%.*s]\n", exstr.len, exstr.s);
+               return NULL;
+       }
+
+       result = snexpr_eval(e);
+
+       if(result==NULL) {
+               LM_ERR("expression evaluation [%.*s] is null\n", exstr.len, exstr.s);
+               goto end;
+       }
+
+       if(result->type == SNE_OP_CONSTNUM) {
+               LM_DBG("expression number result: %g\n", result->param.num.nval);
+               sval.s = int2str((long)result->param.num.nval, &sval.len);
+               if(sval.s==NULL) {
+                       goto done;
+               }
+       } else if(result->type == SNE_OP_CONSTSTZ) {
+               if(result->param.stz.sval==NULL) {
+                       LM_DBG("expression string result is null\n");
+                       goto done;
+               }
+               LM_DBG("expression string result: [%s]\n", result->param.stz.sval);
+               sval.s = result->param.stz.sval;
+               sval.len = strlen(result->param.stz.sval);
+       }
+
+       if(qmode==1) {
+               res = (char*)pkg_malloc(sval.len + 3);
+       } else {
+               res = (char*)pkg_malloc(sval.len + 1);
+       }
+       if(res==NULL) {
+               PKG_MEM_ERROR;
+               goto done;
+       }
+       if(qmode==1) {
+               res[0] = '"';
+               memcpy(res, sval.s+1, sval.len);
+               res[sval.len+1] = '"';
+               res[sval.len+2] = '\0';
+               LM_DBG("expression quoted string result: [%s]\n", res);
+       } else {
+               memcpy(res, sval.s, sval.len);
+               res[sval.len] = '\0';
+       }
+
+done:
+       snexpr_result_free(result);
+end:
+       snexpr_destroy(e, &vars);
+       return res;
 }
 
 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */
index 00b7aeb..f461535 100644 (file)
 
 #define KSR_PPDEF_NORMAL (0)     /* define normal value */
 #define KSR_PPDEF_QUOTED (1<<0)  /* define quoted value */
+
 #define KSR_PPDEF_VALREQ (0)     /* define with value required (defenv) */
 #define KSR_PPDEF_VALTRY (1<<0)  /* define only if value exists (trydefenv) */
 
+#define KSR_PPDEF_DEFINE  0
+#define KSR_PPDEF_TRYDEF  1
+#define KSR_PPDEF_REDEF   2
+#define KSR_PPDEF_DEFEXP  3
+#define KSR_PPDEF_DEFEXPS 4
+
 typedef struct ksr_ppdefine {
        str name;
        str value;
@@ -40,6 +47,7 @@ int pp_def_qvalue(str *defval, str *outval);
 
 str* pp_get_define_name(int idx);
 ksr_ppdefine_t* pp_get_define(int idx);
+int pp_lookup(int len, const char *text);
 
 int pp_subst_add(char *data);
 int pp_substdef_add(char *data, int mode);
@@ -59,6 +67,10 @@ void pp_define_core(void);
 
 void ksr_cfg_print_initial_state(void);
 
+void pp_ifexp_eval(char *exval, int exlen);
+void pp_ifexp_state(int state);
+char *pp_defexp_eval(char *exval, int exlen, int qmode);
+
 #endif /*_PPCFG_H_*/
 
 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */
index 013598c..d869b8a 100644 (file)
@@ -321,7 +321,7 @@ static int register_module(module_exports_t* e, char* path, void* handle)
        }
        strcpy(defmod, "MOD_");
        strcat(defmod, mod->exports.name);
-       pp_define_set_type(0);
+       pp_define_set_type(KSR_PPDEF_DEFINE);
        if(pp_define(strlen(defmod), defmod)<0) {
                LM_ERR("unable to set cfg define for module: %s\n",
                                mod->exports.name);
@@ -525,6 +525,7 @@ error:
        return -1;
 }
 
+
 /**
  * \brief load a sr module
  *
@@ -537,9 +538,10 @@ error:
  * absolute path (not starting with '/') then will try:
  * \<MODS_DIR\>/mod_path
  * @param mod_path path or module name
+ * @param opts options string
  * @return 0 on success , <0 on error
  */
-int load_module(char* mod_path)
+int ksr_load_module(char* mod_path, char *opts)
 {
        void* handle;
        char* error;
@@ -553,10 +555,15 @@ int load_module(char* mod_path)
        str expref;
        char exbuf[64];
        char* mdir;
+       char *p;
 
 #ifndef RTLD_NOW
 /* for openbsd */
 #define RTLD_NOW DL_LAZY
+#endif
+#ifndef RTLD_GLOBAL
+/* Unsupported! */
+#define RTLD_GLOBAL 0
 #endif
 
        if(ksr_locate_module(mod_path, &path)<0) {
@@ -567,6 +574,17 @@ int load_module(char* mod_path)
 
        retries=2;
        dlflags=RTLD_NOW;
+
+       if(opts!=NULL) {
+               for(p=opts; *p!='\0'; p++) {
+                       if(*p=='G' || *p=='g') {
+                               dlflags |= RTLD_GLOBAL;
+                       } else {
+                               LM_INFO("unknown option: %c\n", *p);
+                       }
+               }
+       }
+
 reload:
        handle=dlopen(path, dlflags); /* resolve all symbols now */
        if (handle==0){
@@ -653,10 +671,11 @@ skip:
        return -1;
 }
 
+
 /**
  *
  */
-int load_modulex(char* mod_path)
+int ksr_load_modulex(char* mod_path, char *opts)
 {
        str seval;
        str sfmt;
@@ -679,7 +698,7 @@ int load_modulex(char* mod_path)
                }
        }
 
-       return load_module(emod);
+       return ksr_load_module(emod, opts);
 }
 
 /**
index 251be93..7235c28 100644 (file)
@@ -336,8 +336,8 @@ extern response_function* mod_response_cbks; /**< response callback array */
 extern int mod_response_cbk_no; /**< size of reponse callbacks array */
 
 int register_builtin_modules(void);
-int load_module(char* path);
-int load_modulex(char* path);
+int ksr_load_module(char* path, char* opts);
+int ksr_load_modulex(char* path, char* opts);
 ksr_cmd_export_t* find_export_record(char* name, int param_no, int flags);
 cmd_function find_export(char* name, int param_no, int flags);
 cmd_function find_mod_export(char* mod, char* name, int param_no, int flags);
index 7c501f0..3edf485 100644 (file)
@@ -349,9 +349,19 @@ int udp_init(struct socket_info* sock_info)
 #endif
 #if defined (__OS_linux)
        if (addr->s.sa_family==AF_INET){
-               /* If pmtu_discovery=1 then set DF bit and do Path MTU discovery
-                * disabled by default.  Specific to IPv4. */
-               optval= (pmtu_discovery) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
+               /* If pmtu_discovery=1 then set DF bit and do Path MTU discovery,
+                * disabled by default. Specific to IPv4. If pmtu_discovery=2
+                * then the datagram will be fragmented if needed according to
+                * path MTU, or will set the don't-fragment flag otherwise */
+               switch (pmtu_discovery) {
+                       case 1: optval=IP_PMTUDISC_DO;
+                       break;
+                       case 2: optval=IP_PMTUDISC_WANT;
+                       break;
+                       case 0:
+                       default: optval=IP_PMTUDISC_DONT;
+                       break;
+               }
                if(setsockopt(sock_info->socket, IPPROTO_IP, IP_MTU_DISCOVER,
                                (void*)&optval, sizeof(optval)) ==-1){
                        LM_ERR("IPv4 setsockopt: %s\n", strerror(errno));
@@ -359,9 +369,19 @@ int udp_init(struct socket_info* sock_info)
                }
        } else if (addr->s.sa_family==AF_INET6){
                /* IPv6 never fragments but sends ICMPv6 Packet too Big,
-                * If pmtu_discovery=1 then set DF bit and do Path MTU discovery
-                * disabled by default.  Specific to IPv6. */
-               optval= (pmtu_discovery) ? IPV6_PMTUDISC_DO : IPV6_PMTUDISC_DONT;
+                * If pmtu_discovery=1 then set DF bit and do Path MTU discovery,
+                * disabled by default. Specific to IPv6. If pmtu_discovery=2
+                 * then the datagram will be fragmented if needed according to
+                 * path MTU */
+                switch (pmtu_discovery) {
+                       case 1: optval=IPV6_PMTUDISC_DO;
+                       break;
+                       case 2: optval=IPV6_PMTUDISC_WANT;
+                       break;
+                       case 0:
+                       default: optval=IPV6_PMTUDISC_DONT;
+                       break;
+               }
                if(setsockopt(sock_info->socket, IPPROTO_IPV6,
                                IPV6_MTU_DISCOVER,
                                (void*)&optval, sizeof(optval)) ==-1){
diff --git a/src/core/utils/snexpr.h b/src/core/utils/snexpr.h
new file mode 100644 (file)
index 0000000..d6e853f
--- /dev/null
@@ -0,0 +1,1427 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Serge Zaitsev
+ * Copyright (c) 2022 Daniel-Constantin Mierla
+ *
+ * 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 restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _SNEXPR_H_
+#define _SNEXPR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ctype.h> /* for isspace */
+#include <limits.h>
+#include <math.h> /* for pow */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SNEXPR_TOP (1 << 0)
+#define SNEXPR_TOPEN (1 << 1)
+#define SNEXPR_TCLOSE (1 << 2)
+#define SNEXPR_TNUMBER (1 << 3)
+#define SNEXPR_TSTRING (1 << 4)
+#define SNEXPR_TWORD (1 << 5)
+#define SNEXPR_TDEFAULT (SNEXPR_TOPEN | SNEXPR_TNUMBER | SNEXPR_TSTRING | SNEXPR_TWORD)
+
+#define SNEXPR_UNARY (1 << 16)
+#define SNEXPR_COMMA (1 << 17)
+#define SNEXPR_EXPALLOC (1 << 18)
+#define SNEXPR_VALALLOC (1 << 19)
+#define SNEXPR_VALASSIGN (1 << 20)
+
+
+/*
+ * Simple expandable vector implementation
+ */
+static int sne_vec_expand(char **buf, int *length, int *cap, int memsz)
+{
+       if(*length + 1 > *cap) {
+               void *ptr;
+               int n = (*cap == 0) ? 1 : *cap << 1;
+               ptr = realloc(*buf, n * memsz);
+               if(ptr == NULL) {
+                       return -1; /* allocation failed */
+               }
+               *buf = (char *)ptr;
+               *cap = n;
+       }
+       return 0;
+}
+#define sne_vec(T)   \
+       struct       \
+       {            \
+               T *buf;  \
+               int len; \
+               int cap; \
+       }
+#define sne_vec_init() \
+       {              \
+               NULL, 0, 0 \
+       }
+#define sne_vec_len(v) ((v)->len)
+#define sne_vec_unpack(v) \
+       (char **)&(v)->buf, &(v)->len, &(v)->cap, sizeof(*(v)->buf)
+#define sne_vec_push(v, val) \
+       sne_vec_expand(sne_vec_unpack(v)) ? -1 : ((v)->buf[(v)->len++] = (val), 0)
+#define sne_vec_nth(v, i) (v)->buf[i]
+#define sne_vec_peek(v) (v)->buf[(v)->len - 1]
+#define sne_vec_pop(v) (v)->buf[--(v)->len]
+#define sne_vec_free(v) (free((v)->buf), (v)->buf = NULL, (v)->len = (v)->cap = 0)
+#define sne_vec_foreach(v, var, iter)                                             \
+       if((v)->len > 0)                                                          \
+               for((iter) = 0; (iter) < (v)->len && (((var) = (v)->buf[(iter)]), 1); \
+                               ++(iter))
+
+/*
+ * Expression data types
+ */
+struct snexpr;
+struct snexpr_func;
+struct snexpr_var;
+
+enum snexpr_type
+{
+       SNE_OP_UNKNOWN,
+       SNE_OP_UNARY_MINUS,
+       SNE_OP_UNARY_LOGICAL_NOT,
+       SNE_OP_UNARY_BITWISE_NOT,
+
+       SNE_OP_POWER,
+       SNE_OP_DIVIDE,
+       SNE_OP_MULTIPLY,
+       SNE_OP_REMAINDER,
+
+       SNE_OP_PLUS,
+       SNE_OP_MINUS,
+
+       SNE_OP_SHL,
+       SNE_OP_SHR,
+
+       SNE_OP_LT,
+       SNE_OP_LE,
+       SNE_OP_GT,
+       SNE_OP_GE,
+       SNE_OP_EQ,
+       SNE_OP_NE,
+
+       SNE_OP_BITWISE_AND,
+       SNE_OP_BITWISE_OR,
+       SNE_OP_BITWISE_XOR,
+
+       SNE_OP_LOGICAL_AND,
+       SNE_OP_LOGICAL_OR,
+
+       SNE_OP_ASSIGN,
+       SNE_OP_COMMA,
+
+       SNE_OP_CONSTNUM,
+       SNE_OP_CONSTSTZ,
+       SNE_OP_VAR,
+       SNE_OP_FUNC,
+};
+
+static int prec[] = {0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 6, 7,
+               8, 9, 10, 11, 12, 0, 0, 0, 0};
+
+typedef sne_vec(struct snexpr) sne_vec_expr_t;
+typedef void (*snexprfn_cleanup_t)(struct snexpr_func *f, void *context);
+typedef struct snexpr* (*snexprfn_t)(struct snexpr_func *f, sne_vec_expr_t *args, void *context);
+
+typedef struct snexpr* (*snexternval_cbf_t)(char *vname);
+
+static snexternval_cbf_t _snexternval_cbf = NULL;
+
+struct snexpr
+{
+       enum snexpr_type type;
+       unsigned int eflags;
+       union
+       {
+               struct
+               {
+                       float nval;
+               } num;
+               struct
+               {
+                       char *sval;
+               } stz;
+               struct
+               {
+                       struct snexpr_var *vref;
+               } var;
+               struct
+               {
+                       sne_vec_expr_t args;
+               } op;
+               struct
+               {
+                       struct snexpr_func *f;
+                       sne_vec_expr_t args;
+                       void *context;
+               } func;
+       } param;
+};
+
+#define snexpr_init()                \
+       {                                \
+               .type = (enum snexpr_type)0, \
+               .eflags = 0u                 \
+       }
+
+struct snexpr_string
+{
+       const char *s;
+       int n;
+};
+struct snexpr_arg
+{
+       int oslen;
+       int eslen;
+       sne_vec_expr_t args;
+};
+
+typedef sne_vec(struct snexpr_string) sne_vec_str_t;
+typedef sne_vec(struct snexpr_arg) sne_vec_arg_t;
+
+static int snexpr_is_unary(enum snexpr_type op)
+{
+       return op == SNE_OP_UNARY_MINUS || op == SNE_OP_UNARY_LOGICAL_NOT
+                  || op == SNE_OP_UNARY_BITWISE_NOT;
+}
+
+static int snexpr_is_binary(enum snexpr_type op)
+{
+       return !snexpr_is_unary(op) && op != SNE_OP_CONSTNUM && op != SNE_OP_CONSTSTZ
+                && op != SNE_OP_VAR && op != SNE_OP_FUNC && op != SNE_OP_UNKNOWN;
+}
+
+static int snexpr_prec(enum snexpr_type a, enum snexpr_type b)
+{
+       int left = snexpr_is_binary(a) && a != SNE_OP_ASSIGN && a != SNE_OP_POWER
+                          && a != SNE_OP_COMMA;
+       return (left && prec[a] >= prec[b]) || (prec[a] > prec[b]);
+}
+
+#define isfirstvarchr(c) \
+       (((unsigned char)c >= '@' && c != '^' && c != '|') || c == '$')
+#define isvarchr(c)                                                            \
+       (((unsigned char)c >= '@' && c != '^' && c != '|') || c == '$' || c == '#' \
+                       || (c >= '0' && c <= '9'))
+
+static struct
+{
+       const char *s;
+       const enum snexpr_type op;
+} OPS[] = {
+               {"-u", SNE_OP_UNARY_MINUS},
+               {"!u", SNE_OP_UNARY_LOGICAL_NOT},
+               {"^u", SNE_OP_UNARY_BITWISE_NOT},
+               {"**", SNE_OP_POWER},
+               {"*", SNE_OP_MULTIPLY},
+               {"/", SNE_OP_DIVIDE},
+               {"%", SNE_OP_REMAINDER},
+               {"+", SNE_OP_PLUS},
+               {"-", SNE_OP_MINUS},
+               {"<<", SNE_OP_SHL},
+               {">>", SNE_OP_SHR},
+               {"<", SNE_OP_LT},
+               {"<=", SNE_OP_LE},
+               {">", SNE_OP_GT},
+               {">=", SNE_OP_GE},
+               {"==", SNE_OP_EQ},
+               {"!=", SNE_OP_NE},
+               {"&", SNE_OP_BITWISE_AND},
+               {"|", SNE_OP_BITWISE_OR},
+               {"^", SNE_OP_BITWISE_XOR},
+               {"&&", SNE_OP_LOGICAL_AND},
+               {"||", SNE_OP_LOGICAL_OR},
+               {"=", SNE_OP_ASSIGN},
+               {",", SNE_OP_COMMA},
+
+               /* These are used by lexer and must be ignored by parser, so we put
+       them at the end */
+               {"-", SNE_OP_UNARY_MINUS},
+               {"!", SNE_OP_UNARY_LOGICAL_NOT},
+               {"^", SNE_OP_UNARY_BITWISE_NOT},
+};
+
+static enum snexpr_type snexpr_op(const char *s, size_t len, int unary)
+{
+       for(unsigned int i = 0; i < sizeof(OPS) / sizeof(OPS[0]); i++) {
+               if(strlen(OPS[i].s) == len && strncmp(OPS[i].s, s, len) == 0
+                               && (unary == -1 || snexpr_is_unary(OPS[i].op) == unary)) {
+                       return OPS[i].op;
+               }
+       }
+       return SNE_OP_UNKNOWN;
+}
+
+static float snexpr_parse_number(const char *s, size_t len)
+{
+       float num = 0;
+       unsigned int frac = 0;
+       unsigned int digits = 0;
+       for(unsigned int i = 0; i < len; i++) {
+               if(s[i] == '.' && frac == 0) {
+                       frac++;
+                       continue;
+               }
+               if(isdigit(s[i])) {
+                       digits++;
+                       if(frac > 0) {
+                               frac++;
+                       }
+                       num = num * 10 + (s[i] - '0');
+               } else {
+                       return NAN;
+               }
+       }
+       while(frac > 1) {
+               num = num / 10;
+               frac--;
+       }
+       return (digits > 0 ? num : NAN);
+}
+
+/*
+ * Functions
+ */
+struct snexpr_func
+{
+       const char *name;
+       snexprfn_t f;
+       snexprfn_cleanup_t cleanup;
+       size_t ctxsz;
+};
+
+static struct snexpr_func *snexpr_func_find(
+               struct snexpr_func *funcs, const char *s, size_t len)
+{
+       for(struct snexpr_func *f = funcs; f->name; f++) {
+               if(strlen(f->name) == len && strncmp(f->name, s, len) == 0) {
+                       return f;
+               }
+       }
+       return NULL;
+}
+
+/*
+ * Variables
+ */
+struct snexpr_var
+{
+       unsigned int evflags;
+       char *name;
+       union
+       {
+               float nval;
+               char *sval;
+       } v;
+       struct snexpr_var *next;
+};
+
+struct snexpr_var_list
+{
+       struct snexpr_var *head;
+};
+
+static struct snexpr_var *snexpr_var_find(
+               struct snexpr_var_list *vars, const char *s, size_t len)
+{
+       struct snexpr_var *v = NULL;
+       if(len == 0 || !isfirstvarchr(*s)) {
+               return NULL;
+       }
+       for(v = vars->head; v; v = v->next) {
+               if(strlen(v->name) == len && strncmp(v->name, s, len) == 0) {
+                       return v;
+               }
+       }
+       v = (struct snexpr_var *)calloc(1, sizeof(struct snexpr_var) + len + 1);
+       if(v == NULL) {
+               return NULL; /* allocation failed */
+       }
+       memset(v, 0, sizeof(struct snexpr_var) + len + 1);
+       v->next = vars->head;
+       v->name = (char *)v + sizeof(struct snexpr_var);
+       strncpy(v->name, s, len);
+       v->name[len] = '\0';
+       vars->head = v;
+       return v;
+}
+
+static int to_int(float x)
+{
+       if(isnan(x)) {
+               return 0;
+       } else if(isinf(x) != 0) {
+               return INT_MAX * isinf(x);
+       } else {
+               return (int)x;
+       }
+}
+
+
+static struct snexpr *snexpr_convert_num(float value, unsigned int ctype)
+{
+       struct snexpr *e = (struct snexpr *)malloc(sizeof(struct snexpr));
+       if(e == NULL) {
+               return NULL;
+       }
+       memset(e, 0, sizeof(struct snexpr));
+
+       if(ctype == SNE_OP_CONSTSTZ) {
+               e->eflags |= SNEXPR_EXPALLOC | SNEXPR_VALALLOC;
+               e->type = SNE_OP_CONSTSTZ;
+               asprintf(&e->param.stz.sval, "%g", value);
+               return e;
+       }
+
+       e->eflags |= SNEXPR_EXPALLOC;
+       e->type = SNE_OP_CONSTNUM;
+       e->param.num.nval = value;
+       return e;
+}
+
+static struct snexpr *snexpr_convert_stzl(char *value, size_t len, unsigned int ctype)
+{
+       struct snexpr *e = NULL;
+       if(value==NULL) {
+               return NULL;
+       }
+       e = (struct snexpr *)malloc(sizeof(struct snexpr));
+       if(e == NULL) {
+               return NULL;
+       }
+       memset(e, 0, sizeof(struct snexpr));
+
+       if(ctype == SNE_OP_CONSTNUM) {
+               e->eflags |= SNEXPR_EXPALLOC;
+               e->type = SNE_OP_CONSTNUM;
+               e->param.num.nval = snexpr_parse_number(value, len);
+               return e;
+       }
+
+       e->param.stz.sval = (char *)malloc(len + 1);
+       if(e->param.stz.sval == NULL) {
+               free(e);
+               return NULL;
+       }
+       e->eflags |= SNEXPR_EXPALLOC | SNEXPR_VALALLOC;
+       e->type = SNE_OP_CONSTSTZ;
+       memcpy(e->param.stz.sval, value, len);
+       e->param.stz.sval[len] = '\0';
+       return e;
+}
+
+static struct snexpr *snexpr_convert_stz(char *value, unsigned int ctype)
+{
+       if(value==NULL) {
+               return NULL;
+       }
+
+       return snexpr_convert_stzl(value, strlen(value), ctype);
+}
+
+static struct snexpr *snexpr_concat_strz(char *value0, char *value1)
+{
+       struct snexpr *e = (struct snexpr *)malloc(sizeof(struct snexpr));
+       if(e == NULL) {
+               return NULL;
+       }
+       memset(e, 0, sizeof(struct snexpr));
+
+       e->param.stz.sval = (char *)malloc(strlen(value0) + strlen(value1) + 1);
+       if(e->param.stz.sval == NULL) {
+               free(e);
+               return NULL;
+       }
+       e->eflags |= SNEXPR_EXPALLOC | SNEXPR_VALALLOC;
+       e->type = SNE_OP_CONSTSTZ;
+       strcpy(e->param.stz.sval, value0);
+       strcat(e->param.stz.sval, value1);
+       return e;
+}
+
+static void snexpr_result_free(struct snexpr *e)
+{
+       if(e == NULL) {
+               return;
+       }
+       if((e->eflags & SNEXPR_VALALLOC) && (e->type == SNE_OP_CONSTSTZ)
+                       && (e->param.stz.sval != NULL)) {
+               free(e->param.stz.sval);
+       }
+       if(!(e->eflags & SNEXPR_EXPALLOC)) {
+               return;
+       }
+       free(e);
+}
+
+#define snexpr_eval_check_val(val, vtype) do { \
+               if(val==NULL || val->type != vtype) { \
+                       goto error; \
+               } \
+       } while(0)
+
+#define snexpr_eval_check_null(val, vtype) do { \
+               if(val==NULL) { \
+                       goto error; \
+               } \
+       } while(0)
+
+#define snexpr_eval_cmp(_CMPOP_) do { \
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]); \
+                       snexpr_eval_check_null(rv0, SNE_OP_CONSTNUM); \
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]); \
+                       snexpr_eval_check_null(rv1, SNE_OP_CONSTNUM); \
+                       if(rv0->type == SNE_OP_CONSTSTZ) { \
+                               /* string comparison */ \
+                               if(rv1->type == SNE_OP_CONSTNUM) { \
+                                       tv = snexpr_convert_num(rv1->param.num.nval, SNE_OP_CONSTSTZ); \
+                                       snexpr_result_free(rv1); \
+                                       rv1 = tv; \
+                                       snexpr_eval_check_val(rv1, SNE_OP_CONSTSTZ); \
+                               } \
+                               lv = snexpr_concat_strz(rv0->param.stz.sval, rv1->param.stz.sval); \
+                               if(strcmp(rv0->param.stz.sval, rv1->param.stz.sval) _CMPOP_ 0) { \
+                                       lv = snexpr_convert_num(1, SNE_OP_CONSTNUM); \
+                               } else { \
+                                       lv = snexpr_convert_num(0, SNE_OP_CONSTNUM); \
+                               } \
+                       } else { \
+                               /* number comparison */ \
+                               if(rv1->type == SNE_OP_CONSTSTZ) { \
+                                       tv = snexpr_convert_stz(rv1->param.stz.sval, SNE_OP_CONSTNUM); \
+                                       snexpr_result_free(rv1); \
+                                       rv1 = tv; \
+                                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM); \
+                               } \
+                               lv = snexpr_convert_num( \
+                                               rv0->param.num.nval _CMPOP_ rv1->param.num.nval, SNE_OP_CONSTNUM); \
+                       } \
+       } while(0)
+
+static struct snexpr *snexpr_eval(struct snexpr *e)
+{
+       float n;
+       struct snexpr *lv = NULL;
+       struct snexpr *rv0 = NULL;
+       struct snexpr *rv1 = NULL;
+       struct snexpr *tv = NULL;
+
+       switch(e->type) {
+               case SNE_OP_UNARY_MINUS:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(-(rv0->param.num.nval), SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_UNARY_LOGICAL_NOT:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(!(rv0->param.num.nval), SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_UNARY_BITWISE_NOT:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(~(to_int(rv0->param.num.nval)), SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_POWER:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       powf(rv0->param.num.nval, rv1->param.num.nval),
+                                       SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_MULTIPLY:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       rv0->param.num.nval * rv1->param.num.nval, SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_DIVIDE:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       if(rv1->param.num.nval == 0) {
+                               goto error;
+                       }
+                       lv = snexpr_convert_num(
+                                       rv0->param.num.nval / rv1->param.num.nval, SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_REMAINDER:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       fmodf(rv0->param.num.nval, rv1->param.num.nval),
+                                       SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_PLUS:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_null(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_null(rv1, SNE_OP_CONSTNUM);
+                       if(rv0->type == SNE_OP_CONSTSTZ) {
+                               /* string concatenation */
+                               if(rv1->type == SNE_OP_CONSTNUM) {
+                                       tv = snexpr_convert_num(rv1->param.num.nval, SNE_OP_CONSTSTZ);
+                                       snexpr_result_free(rv1);
+                                       rv1 = tv;
+                                       snexpr_eval_check_val(rv1, SNE_OP_CONSTSTZ);
+                               }
+                               lv = snexpr_concat_strz(rv0->param.stz.sval, rv1->param.stz.sval);
+                       } else {
+                               /* add */
+                               if(rv1->type == SNE_OP_CONSTSTZ) {
+                                       tv = snexpr_convert_stz(rv1->param.stz.sval, SNE_OP_CONSTNUM);
+                                       snexpr_result_free(rv1);
+                                       rv1 = tv;
+                                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                               }
+                               lv = snexpr_convert_num(
+                                               rv0->param.num.nval + rv1->param.num.nval, SNE_OP_CONSTNUM);
+                       }
+                       goto done;
+               case SNE_OP_MINUS:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       rv0->param.num.nval - rv1->param.num.nval, SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_SHL:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       to_int(rv0->param.num.nval) << to_int(rv1->param.num.nval),
+                                       SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_SHR:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       to_int(rv0->param.num.nval) >> to_int(rv1->param.num.nval),
+                                       SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_LT:
+                       snexpr_eval_cmp(<);
+                       goto done;
+               case SNE_OP_LE:
+                       snexpr_eval_cmp(<=);
+                       goto done;
+               case SNE_OP_GT:
+                       snexpr_eval_cmp(>);
+                       goto done;
+               case SNE_OP_GE:
+                       snexpr_eval_cmp(>=);
+                       goto done;
+               case SNE_OP_EQ:
+                       snexpr_eval_cmp(==);
+                       goto done;
+               case SNE_OP_NE:
+                       snexpr_eval_cmp(!=);
+                       goto done;
+               case SNE_OP_BITWISE_AND:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       to_int(rv0->param.num.nval) & to_int(rv1->param.num.nval),
+                                       SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_BITWISE_OR:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       to_int(rv0->param.num.nval) | to_int(rv1->param.num.nval),
+                                       SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_BITWISE_XOR:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       snexpr_eval_check_val(rv0, SNE_OP_CONSTNUM);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_val(rv1, SNE_OP_CONSTNUM);
+                       lv = snexpr_convert_num(
+                                       to_int(rv0->param.num.nval) ^ to_int(rv1->param.num.nval),
+                                       SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_LOGICAL_AND:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       n = rv0->param.num.nval;
+                       if(n != 0) {
+                               rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                               n = rv1->param.num.nval;
+                               if(n != 0) {
+                                       lv = snexpr_convert_num(n, SNE_OP_CONSTNUM);
+                                       goto done;
+                               }
+                       }
+                       lv = snexpr_convert_num(0, SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_LOGICAL_OR:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       n = rv0->param.num.nval;
+                       if(n != 0 && !isnan(n)) {
+                               lv = snexpr_convert_num(n, SNE_OP_CONSTNUM);
+                               goto done;
+                       } else {
+                               rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                               n = rv1->param.num.nval;
+                               if(n != 0) {
+                                       lv = snexpr_convert_num(n, SNE_OP_CONSTNUM);
+                                       goto done;
+                               }
+                       }
+                       lv = snexpr_convert_num(0, SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_ASSIGN:
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       snexpr_eval_check_null(rv1, SNE_OP_CONSTNUM);
+                       if(sne_vec_nth(&e->param.op.args, 0).type == SNE_OP_VAR) {
+                               if(e->param.op.args.buf[0].param.var.vref->evflags & SNEXPR_VALALLOC) {
+                                       if(e->param.op.args.buf[0].param.var.vref->v.sval!=NULL) {
+                                               free(e->param.op.args.buf[0].param.var.vref->v.sval);
+                                               e->param.op.args.buf[0].param.var.vref->v.sval = NULL;
+                                       }
+                                       e->param.op.args.buf[0].param.var.vref->evflags &= ~(SNEXPR_TSTRING|SNEXPR_VALALLOC);
+                               }
+                               if(rv1->type == SNE_OP_CONSTSTZ) {
+                                       e->param.op.args.buf[0].param.var.vref->v.sval = strdup(rv1->param.stz.sval);
+                                       e->param.op.args.buf[0].param.var.vref->evflags |= SNEXPR_VALASSIGN|SNEXPR_TSTRING|SNEXPR_VALALLOC;
+                                       lv = snexpr_convert_stz(rv1->param.stz.sval, SNE_OP_CONSTSTZ);
+                               } else {
+                                       n = rv1->param.num.nval;
+                                       e->param.op.args.buf[0].param.var.vref->v.nval = n;
+                                       e->param.op.args.buf[0].param.var.vref->evflags |= SNEXPR_VALASSIGN;
+                                       lv = snexpr_convert_num(n, SNE_OP_CONSTNUM);
+                               }
+                       }
+                       goto done;
+               case SNE_OP_COMMA:
+                       rv0 = snexpr_eval(&e->param.op.args.buf[0]);
+                       rv1 = snexpr_eval(&e->param.op.args.buf[1]);
+                       if(rv1->type == SNE_OP_CONSTSTZ) {
+                               lv = snexpr_convert_stz(rv1->param.stz.sval, SNE_OP_CONSTSTZ);
+                       } else {
+                               lv = snexpr_convert_num(rv1->param.num.nval, SNE_OP_CONSTNUM);
+                       }
+                       goto done;
+               case SNE_OP_CONSTNUM:
+                       lv = snexpr_convert_num(e->param.num.nval, SNE_OP_CONSTNUM);
+                       goto done;
+               case SNE_OP_CONSTSTZ:
+                       lv = snexpr_convert_stz(e->param.stz.sval, SNE_OP_CONSTSTZ);
+                       goto done;
+               case SNE_OP_VAR:
+                       if((_snexternval_cbf == NULL)
+                                       || (e->param.var.vref->evflags & SNEXPR_VALASSIGN)) {
+                               if(e->param.var.vref->evflags & SNEXPR_TSTRING) {
+                                       lv = snexpr_convert_stz(e->param.var.vref->v.sval, SNE_OP_CONSTSTZ);
+                               } else {
+                                       snexpr_convert_num(e->param.var.vref->v.nval, SNE_OP_CONSTNUM);
+                               }
+                       } else {
+                               lv = _snexternval_cbf(e->param.var.vref->name);
+                       }
+                       goto done;
+               case SNE_OP_FUNC:
+                       rv0 = e->param.func.f->f(e->param.func.f, &e->param.func.args,
+                                                       e->param.func.context);
+                       if(rv0->type == SNE_OP_CONSTSTZ) {
+                               lv = snexpr_convert_stz(rv0->param.stz.sval, SNE_OP_CONSTSTZ);
+                       } else {
+                               lv = snexpr_convert_num(rv0->param.num.nval, SNE_OP_CONSTNUM);
+                       }
+                       goto done;
+               default:
+                       lv = snexpr_convert_num(NAN, SNE_OP_CONSTNUM);
+                       goto done;
+       }
+
+done:
+       if(rv0 != NULL) {
+               snexpr_result_free(rv0);
+       }
+       if(rv1 != NULL) {
+               snexpr_result_free(rv1);
+       }
+       return lv;
+
+error:
+       if(rv0 != NULL) {
+               snexpr_result_free(rv0);
+       }
+       if(rv1 != NULL) {
+               snexpr_result_free(rv1);
+       }
+       return NULL;
+
+}
+
+static int snexpr_next_token(const char *s, size_t len, int *flags)
+{
+       unsigned int i = 0;
+       char b;
+       int bsf = 0;
+       if(len == 0) {
+               return 0;
+       }
+       char c = s[0];
+       if(c == '#') {
+               for(; i < len && s[i] != '\n'; i++)
+                       ;
+               return i;
+       } else if(c == '\n') {
+               for(; i < len && isspace(s[i]); i++)
+                       ;
+               if(*flags & SNEXPR_TOP) {
+                       if(i == len || s[i] == ')') {
+                               *flags = *flags & (~SNEXPR_COMMA);
+                       } else {
+                               *flags = SNEXPR_TNUMBER | SNEXPR_TSTRING | SNEXPR_TWORD | SNEXPR_TOPEN
+                                                | SNEXPR_COMMA;
+                       }
+               }
+               return i;
+       } else if(isspace(c)) {
+               while(i < len && isspace(s[i]) && s[i] != '\n') {
+                       i++;
+               }
+               return i;
+       } else if(isdigit(c)) {
+               if((*flags & SNEXPR_TNUMBER) == 0) {
+                       return -1; // unexpected number
+               }
+               *flags = SNEXPR_TOP | SNEXPR_TCLOSE;
+               while((c == '.' || isdigit(c)) && i < len) {
+                       i++;
+                       c = s[i];
+               }
+               return i;
+       } else if(c == '"' || c == '\'') {
+               if((*flags & SNEXPR_TSTRING) == 0) {
+                       return -1; // unexpected string
+               }
+               if(i == len - 1) {
+                       return -1; // invalud start of string
+               }
+               *flags = SNEXPR_TOP | SNEXPR_TCLOSE;
+               b = c;
+               i++;
+               c = s[i];
+               while(i < len && (bsf==1 || c != b)) {
+                       if(bsf == 0 && c == '\\') {
+                               bsf = 1;
+                       } else {
+                               bsf = 0;
+                       }
+                       i++;
+                       c = s[i];
+               }
+               return i + 1;
+       } else if(isfirstvarchr(c)) {
+               if((*flags & SNEXPR_TWORD) == 0) {
+                       return -2; // unexpected word
+               }
+               *flags = SNEXPR_TOP | SNEXPR_TOPEN | SNEXPR_TCLOSE;
+               while((isvarchr(c)) && i < len) {
+                       i++;
+                       c = s[i];
+               }
+               return i;
+       } else if(c == '(' || c == ')') {
+               if(c == '(' && (*flags & SNEXPR_TOPEN) != 0) {
+                       *flags = SNEXPR_TNUMBER | SNEXPR_TSTRING | SNEXPR_TWORD | SNEXPR_TOPEN
+                                        | SNEXPR_TCLOSE;
+               } else if(c == ')' && (*flags & SNEXPR_TCLOSE) != 0) {
+                       *flags = SNEXPR_TOP | SNEXPR_TCLOSE;
+               } else {
+                       return -3; // unexpected parenthesis
+               }
+               return 1;
+       } else {
+               if((*flags & SNEXPR_TOP) == 0) {
+                       if(snexpr_op(&c, 1, 1) == SNE_OP_UNKNOWN) {
+                               return -4; // missing expected operand
+                       }
+                       *flags = SNEXPR_TNUMBER | SNEXPR_TSTRING | SNEXPR_TWORD | SNEXPR_TOPEN
+                                        | SNEXPR_UNARY;
+                       return 1;
+               } else {
+                       int found = 0;
+                       while(!isvarchr(c) && !isspace(c) && c != '(' && c != ')'
+                                       && i < len) {
+                               if(snexpr_op(s, i + 1, 0) != SNE_OP_UNKNOWN) {
+                                       found = 1;
+                               } else if(found) {
+                                       break;
+                               }
+                               i++;
+                               c = s[i];
+                       }
+                       if(!found) {
+                               return -5; // unknown operator
+                       }
+                       *flags = SNEXPR_TNUMBER | SNEXPR_TSTRING | SNEXPR_TWORD | SNEXPR_TOPEN;
+                       return i;
+               }
+       }
+}
+
+#define SNEXPR_PAREN_ALLOWED 0
+#define SNEXPR_PAREN_EXPECTED 1
+#define SNEXPR_PAREN_FORBIDDEN 2
+
+static int snexpr_bind(const char *s, size_t len, sne_vec_expr_t *es)
+{
+       enum snexpr_type op = snexpr_op(s, len, -1);
+       if(op == SNE_OP_UNKNOWN) {
+               return -1;
+       }
+
+       if(snexpr_is_unary(op)) {
+               if(sne_vec_len(es) < 1) {
+                       return -1;
+               }
+               struct snexpr arg = sne_vec_pop(es);
+               struct snexpr unary = snexpr_init();
+               unary.type = op;
+               sne_vec_push(&unary.param.op.args, arg);
+               sne_vec_push(es, unary);
+       } else {
+               if(sne_vec_len(es) < 2) {
+                       return -1;
+               }
+               struct snexpr b = sne_vec_pop(es);
+               struct snexpr a = sne_vec_pop(es);
+               struct snexpr binary = snexpr_init();
+               binary.type = op;
+               if(op == SNE_OP_ASSIGN && a.type != SNE_OP_VAR) {
+                       return -1; /* Bad assignment */
+               }
+               sne_vec_push(&binary.param.op.args, a);
+               sne_vec_push(&binary.param.op.args, b);
+               sne_vec_push(es, binary);
+       }
+       return 0;
+}
+
+static struct snexpr snexpr_constnum(float value)
+{
+       struct snexpr e = snexpr_init();
+       e.type = SNE_OP_CONSTNUM;
+       e.param.num.nval = value;
+       return e;
+}
+
+static struct snexpr snexpr_varref(struct snexpr_var *v)
+{
+       struct snexpr e = snexpr_init();
+       e.type = SNE_OP_VAR;
+       e.param.var.vref = v;
+       return e;
+}
+
+static struct snexpr snexpr_conststr(const char *value, int len)
+{
+       struct snexpr e = snexpr_init();
+       char *p;
+       int i;
+       int bsf = 0;
+       if(len < 2) {
+               len = 0;
+       } else {
+               /* skip the quotes */
+               len -= 2;
+       }
+       e.type = SNE_OP_CONSTSTZ;
+       e.param.stz.sval = malloc(len + 1);
+       if(e.param.stz.sval) {
+               if(len > 0) {
+                       /* do not copy the quotes - start from value[1] */
+                       p = e.param.stz.sval;
+                       for(i=0; i<len; i++) {
+                               if(bsf==0 && value[i+1]=='\\') {
+                                       bsf = 1;
+                               } else if(bsf==1) {
+                                       bsf = 0;
+                                       switch(value[i+1]) {
+                                               case 'n':
+                                                       *p = '\n';
+                                               break;
+                                               case 'r':
+                                                       *p = '\r';
+                                               break;
+                                               case 't':
+                                                       *p = '\t';
+                                               break;
+                                               default:
+                                                       *p = value[i+1];
+                                       }
+                                       p++;
+                               } else {
+                                       bsf = 0;
+                                       *p = value[i+1];
+                                       p++;
+                               }
+                       }
+                       *p = '\0';
+               } else {
+                       e.param.stz.sval[0] = '\0';
+               }
+       }
+       return e;
+}
+
+static struct snexpr snexpr_binary(
+               enum snexpr_type type, struct snexpr a, struct snexpr b)
+{
+       struct snexpr e = snexpr_init();
+       e.type = type;
+       sne_vec_push(&e.param.op.args, a);
+       sne_vec_push(&e.param.op.args, b);
+       return e;
+}
+
+static inline void snexpr_copy(struct snexpr *dst, struct snexpr *src)
+{
+       int i;
+       struct snexpr arg;
+       dst->type = src->type;
+       if(src->type == SNE_OP_FUNC) {
+               dst->param.func.f = src->param.func.f;
+               sne_vec_foreach(&src->param.func.args, arg, i)
+               {
+                       struct snexpr tmp = snexpr_init();
+                       snexpr_copy(&tmp, &arg);
+                       sne_vec_push(&dst->param.func.args, tmp);
+               }
+               if(src->param.func.f->ctxsz > 0) {
+                       dst->param.func.context = calloc(1, src->param.func.f->ctxsz);
+               }
+       } else if(src->type == SNE_OP_CONSTNUM) {
+               dst->param.num.nval = src->param.num.nval;
+       } else if(src->type == SNE_OP_VAR) {
+               dst->param.var.vref = src->param.var.vref;
+       } else {
+               sne_vec_foreach(&src->param.op.args, arg, i)
+               {
+                       struct snexpr tmp = snexpr_init();
+                       snexpr_copy(&tmp, &arg);
+                       sne_vec_push(&dst->param.op.args, tmp);
+               }
+       }
+}
+
+static void snexpr_destroy_args(struct snexpr *e);
+
+static struct snexpr *snexpr_create(const char *s, size_t len,
+               struct snexpr_var_list *vars, struct snexpr_func *funcs,
+               snexternval_cbf_t evcbf)
+{
+       float num;
+       struct snexpr_var *v;
+       const char *id = NULL;
+       size_t idn = 0;
+
+       struct snexpr *result = NULL;
+
+       _snexternval_cbf = evcbf;
+
+       sne_vec_expr_t es = sne_vec_init();
+       sne_vec_str_t os = sne_vec_init();
+       sne_vec_arg_t as = sne_vec_init();
+
+       struct macro
+       {
+               char *name;
+               sne_vec_expr_t body;
+       };
+       sne_vec(struct macro) macros = sne_vec_init();
+
+       int flags = SNEXPR_TDEFAULT;
+       int paren = SNEXPR_PAREN_ALLOWED;
+       for(;;) {
+               int n = snexpr_next_token(s, len, &flags);
+               if(n == 0) {
+                       break;
+               } else if(n < 0) {
+                       goto cleanup;
+               }
+               const char *tok = s;
+               s = s + n;
+               len = len - n;
+               if(*tok == '#') {
+                       continue;
+               }
+               if(flags & SNEXPR_UNARY) {
+                       if(n == 1) {
+                               switch(*tok) {
+                                       case '-':
+                                               tok = "-u";
+                                               break;
+                                       case '^':
+                                               tok = "^u";
+                                               break;
+                                       case '!':
+                                               tok = "!u";
+                                               break;
+                                       default:
+                                               goto cleanup;
+                               }
+                               n = 2;
+                       }
+               }
+               if(*tok == '\n' && (flags & SNEXPR_COMMA)) {
+                       flags = flags & (~SNEXPR_COMMA);
+                       n = 1;
+                       tok = ",";
+               }
+               if(isspace(*tok)) {
+                       continue;
+               }
+               int paren_next = SNEXPR_PAREN_ALLOWED;
+
+               if(idn > 0) {
+                       if(n == 1 && *tok == '(') {
+                               int i;
+                               int has_macro = 0;
+                               struct macro m;
+                               sne_vec_foreach(&macros, m, i)
+                               {
+                                       if(strlen(m.name) == idn && strncmp(m.name, id, idn) == 0) {
+                                               has_macro = 1;
+                                               break;
+                                       }
+                               }
+                               if((idn == 1 && id[0] == '$') || has_macro
+                                               || snexpr_func_find(funcs, id, idn) != NULL) {
+                                       struct snexpr_string str = {id, (int)idn};
+                                       sne_vec_push(&os, str);
+                                       paren = SNEXPR_PAREN_EXPECTED;
+                               } else {
+                                       goto cleanup; /* invalid function name */
+                               }
+                       } else if((v = snexpr_var_find(vars, id, idn)) != NULL) {
+                               sne_vec_push(&es, snexpr_varref(v));
+                               paren = SNEXPR_PAREN_FORBIDDEN;
+                       }
+                       id = NULL;
+                       idn = 0;
+               }
+
+               if(n == 1 && *tok == '(') {
+                       if(paren == SNEXPR_PAREN_EXPECTED) {
+                               struct snexpr_string str = {"{", 1};
+                               sne_vec_push(&os, str);
+                               struct snexpr_arg arg = {sne_vec_len(&os), sne_vec_len(&es), sne_vec_init()};
+                               sne_vec_push(&as, arg);
+                       } else if(paren == SNEXPR_PAREN_ALLOWED) {
+                               struct snexpr_string str = {"(", 1};
+                               sne_vec_push(&os, str);
+                       } else {
+                               goto cleanup; // Bad call
+                       }
+               } else if(paren == SNEXPR_PAREN_EXPECTED) {
+                       goto cleanup; // Bad call
+               } else if(n == 1 && *tok == ')') {
+                       int minlen = (sne_vec_len(&as) > 0 ? sne_vec_peek(&as).oslen : 0);
+                       while(sne_vec_len(&os) > minlen && *sne_vec_peek(&os).s != '('
+                                       && *sne_vec_peek(&os).s != '{') {
+                               struct snexpr_string str = sne_vec_pop(&os);
+                               if(snexpr_bind(str.s, str.n, &es) == -1) {
+                                       goto cleanup;
+                               }
+                       }
+                       if(sne_vec_len(&os) == 0) {
+                               goto cleanup; // Bad parens
+                       }
+                       struct snexpr_string str = sne_vec_pop(&os);
+                       if(str.n == 1 && *str.s == '{') {
+                               str = sne_vec_pop(&os);
+                               struct snexpr_arg arg = sne_vec_pop(&as);
+                               if(sne_vec_len(&es) > arg.eslen) {
+                                       sne_vec_push(&arg.args, sne_vec_pop(&es));
+                               }
+                               if(str.n == 1 && str.s[0] == '$') {
+                                       if(sne_vec_len(&arg.args) < 1) {
+                                               sne_vec_free(&arg.args);
+                                               goto cleanup; /* too few arguments for $() function */
+                                       }
+                                       struct snexpr *u = &sne_vec_nth(&arg.args, 0);
+                                       if(u->type != SNE_OP_VAR) {
+                                               sne_vec_free(&arg.args);
+                                               goto cleanup; /* first argument is not a variable */
+                                       }
+                                       for(struct snexpr_var *v = vars->head; v; v = v->next) {
+                                               if(v == u->param.var.vref) {
+                                                       struct macro m = {v->name, arg.args};
+                                                       sne_vec_push(&macros, m);
+                                                       break;
+                                               }
+                                       }
+                                       sne_vec_push(&es, snexpr_constnum(0));
+                               } else {
+                                       int i = 0;
+                                       int found = -1;
+                                       struct macro m;
+                                       sne_vec_foreach(&macros, m, i)
+                                       {
+                                               if(strlen(m.name) == (size_t)str.n
+                                                               && strncmp(m.name, str.s, str.n) == 0) {
+                                                       found = i;
+                                               }
+                                       }
+                                       if(found != -1) {
+                                               m = sne_vec_nth(&macros, found);
+                                               struct snexpr root = snexpr_constnum(0);
+                                               struct snexpr *p = &root;
+                                               /* Assign macro parameters */
+                                               for(int j = 0; j < sne_vec_len(&arg.args); j++) {
+                                                       char varname[4];
+                                                       snprintf(varname, sizeof(varname) - 1, "$%d",
+                                                                       (j + 1));
+                                                       struct snexpr_var *v =
+                                                                       snexpr_var_find(vars, varname, strlen(varname));
+                                                       struct snexpr ev = snexpr_varref(v);
+                                                       struct snexpr assign = snexpr_binary(
+                                                                       SNE_OP_ASSIGN, ev, sne_vec_nth(&arg.args, j));
+                                                       *p = snexpr_binary(
+                                                                       SNE_OP_COMMA, assign, snexpr_constnum(0));
+                                                       p = &sne_vec_nth(&p->param.op.args, 1);
+                                               }
+                                               /* Expand macro body */
+                                               for(int j = 1; j < sne_vec_len(&m.body); j++) {
+                                                       if(j < sne_vec_len(&m.body) - 1) {
+                                                               *p = snexpr_binary(SNE_OP_COMMA, snexpr_constnum(0),
+                                                                               snexpr_constnum(0));
+                                                               snexpr_copy(&sne_vec_nth(&p->param.op.args, 0),
+                                                                               &sne_vec_nth(&m.body, j));
+                                                       } else {
+                                                               snexpr_copy(p, &sne_vec_nth(&m.body, j));
+                                                       }
+                                                       p = &sne_vec_nth(&p->param.op.args, 1);
+                                               }
+                                               sne_vec_push(&es, root);
+                                               sne_vec_free(&arg.args);
+                                       } else {
+                                               struct snexpr_func *f = snexpr_func_find(funcs, str.s, str.n);
+                                               struct snexpr bound_func = snexpr_init();
+                                               bound_func.type = SNE_OP_FUNC;
+                                               bound_func.param.func.f = f;
+                                               bound_func.param.func.args = arg.args;
+                                               if(f->ctxsz > 0) {
+                                                       void *p = calloc(1, f->ctxsz);
+                                                       if(p == NULL) {
+                                                               goto cleanup; /* allocation failed */
+                                                       }
+                                                       bound_func.param.func.context = p;
+                                               }
+                                               sne_vec_push(&es, bound_func);
+                                       }
+                               }
+                       }
+                       paren_next = SNEXPR_PAREN_FORBIDDEN;
+               } else if(!isnan(num = snexpr_parse_number(tok, n))) {
+                       sne_vec_push(&es, snexpr_constnum(num));
+                       paren_next = SNEXPR_PAREN_FORBIDDEN;
+               } else if(*tok == '"' || *tok == '\'') {
+                       sne_vec_push(&es, snexpr_conststr(tok, n));
+                       paren_next = SNEXPR_PAREN_FORBIDDEN;
+               } else if(snexpr_op(tok, n, -1) != SNE_OP_UNKNOWN) {
+                       enum snexpr_type op = snexpr_op(tok, n, -1);
+                       struct snexpr_string o2 = {NULL, 0};
+                       if(sne_vec_len(&os) > 0) {
+                               o2 = sne_vec_peek(&os);
+                       }
+                       for(;;) {
+                               if(n == 1 && *tok == ',' && sne_vec_len(&os) > 0) {
+                                       struct snexpr_string str = sne_vec_peek(&os);
+                                       if(str.n == 1 && *str.s == '{') {
+                                               struct snexpr e = sne_vec_pop(&es);
+                                               sne_vec_push(&sne_vec_peek(&as).args, e);
+                                               break;
+                                       }
+                               }
+                               enum snexpr_type type2 = snexpr_op(o2.s, o2.n, -1);
+                               if(!(type2 != SNE_OP_UNKNOWN && snexpr_prec(op, type2))) {
+                                       struct snexpr_string str = {tok, n};
+                                       sne_vec_push(&os, str);
+                                       break;
+                               }
+
+                               if(snexpr_bind(o2.s, o2.n, &es) == -1) {
+                                       goto cleanup;
+                               }
+                               (void)sne_vec_pop(&os);
+                               if(sne_vec_len(&os) > 0) {
+                                       o2 = sne_vec_peek(&os);
+                               } else {
+                                       o2.n = 0;
+                               }
+                       }
+               } else {
+                       if(n > 0 && !isdigit(*tok)) {
+                               /* Valid identifier, a variable or a function */
+                               id = tok;
+                               idn = n;
+                       } else {
+                               goto cleanup; // Bad variable name, e.g. '2.3.4' or '4ever'
+                       }
+               }
+               paren = paren_next;
+       }
+
+       if(idn > 0) {
+               sne_vec_push(&es, snexpr_varref(snexpr_var_find(vars, id, idn)));
+       }
+
+       while(sne_vec_len(&os) > 0) {
+               struct snexpr_string rest = sne_vec_pop(&os);
+               if(rest.n == 1 && (*rest.s == '(' || *rest.s == ')')) {
+                       goto cleanup; // Bad paren
+               }
+               if(snexpr_bind(rest.s, rest.n, &es) == -1) {
+                       goto cleanup;
+               }
+       }
+
+       result = (struct snexpr *)calloc(1, sizeof(struct snexpr));
+       if(result != NULL) {
+               if(sne_vec_len(&es) == 0) {
+                       result->type = SNE_OP_CONSTNUM;
+               } else {
+                       *result = sne_vec_pop(&es);
+               }
+       }
+
+       int i, j;
+       struct macro m;
+       struct snexpr e;
+       struct snexpr_arg a;
+cleanup:
+       sne_vec_foreach(&macros, m, i)
+       {
+               struct snexpr e;
+               sne_vec_foreach(&m.body, e, j)
+               {
+                       snexpr_destroy_args(&e);
+               }
+               sne_vec_free(&m.body);
+       }
+       sne_vec_free(&macros);
+
+       sne_vec_foreach(&es, e, i)
+       {
+               snexpr_destroy_args(&e);
+       }
+       sne_vec_free(&es);
+
+       sne_vec_foreach(&as, a, i)
+       {
+               sne_vec_foreach(&a.args, e, j)
+               {
+                       snexpr_destroy_args(&e);
+               }
+               sne_vec_free(&a.args);
+       }
+       sne_vec_free(&as);
+
+       /*sne_vec_foreach(&os, o, i) {sne_vec_free(&m.body);}*/
+       sne_vec_free(&os);
+       if(result==NULL) {
+               _snexternval_cbf = NULL;
+       }
+
+       return result;
+}
+
+static void snexpr_destroy_args(struct snexpr *e)
+{
+       int i;
+       struct snexpr arg;
+       if(e->type == SNE_OP_FUNC) {
+               sne_vec_foreach(&e->param.func.args, arg, i)
+               {
+                       snexpr_destroy_args(&arg);
+               }
+               sne_vec_free(&e->param.func.args);
+               if(e->param.func.context != NULL) {
+                       if(e->param.func.f->cleanup != NULL) {
+                               e->param.func.f->cleanup(
+                                               e->param.func.f, e->param.func.context);
+                       }
+                       free(e->param.func.context);
+               }
+       } else if(e->type != SNE_OP_CONSTNUM && e->type != SNE_OP_CONSTSTZ
+                       && e->type != SNE_OP_VAR) {
+               sne_vec_foreach(&e->param.op.args, arg, i)
+               {
+                       snexpr_destroy_args(&arg);
+               }
+               sne_vec_free(&e->param.op.args);
+       }
+}
+
+static void snexpr_destroy(struct snexpr *e, struct snexpr_var_list *vars)
+{
+       _snexternval_cbf = NULL;
+
+       if(e != NULL) {
+               snexpr_destroy_args(e);
+               free(e);
+       }
+       if(vars != NULL) {
+               for(struct snexpr_var *v = vars->head; v;) {
+                       struct snexpr_var *next = v->next;
+                       if(v->evflags & SNEXPR_VALALLOC) {
+                               free(v->v.sval);
+                       }
+                       free(v);
+                       v = next;
+               }
+       }
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _SNEXPR_H_ */
index c6855e2..f2ffe02 100644 (file)
@@ -2286,7 +2286,7 @@ int main(int argc, char** argv)
                                        } else {
                                                tmp_len = strlen(optarg);
                                        }
-                                       pp_define_set_type(0);
+                                       pp_define_set_type(KSR_PPDEF_DEFINE);
                                        if(pp_define(tmp_len, optarg)<0) {
                                                fprintf(stderr, "error at define param: -A %s\n",
                                                                optarg);
@@ -2446,7 +2446,7 @@ int main(int argc, char** argv)
                                                fprintf(stderr, "bad load module parameter\n");
                                                goto error;
                                        }
-                                       if (load_module(optarg)!=0) {
+                                       if (ksr_load_module(optarg, NULL)!=0) {
                                                LM_ERR("failed to load the module: %s\n", optarg);
                                                goto error;
                                        }
index b54e3a3..ab1938a 100644 (file)
@@ -96,9 +96,8 @@ int cdr_core2strar( struct dlg_cell* dlg,
                int* unused,
                char* types)
 {
-       str* start = NULL;
-       str* end = NULL;
-       str* duration = NULL;
+       str dlgvals[MAX_CDR_CORE]; /* start, end, duration */
+       int i;
 
        if( !dlg || !values || !types)
        {
@@ -106,18 +105,40 @@ int cdr_core2strar( struct dlg_cell* dlg,
                return 0;
        }
 
-       start = dlgb.get_dlg_var( dlg, (str*)&cdr_start_str);
-       end = dlgb.get_dlg_var( dlg, (str*)&cdr_end_str);
-       duration = dlgb.get_dlg_var( dlg, (str*)&cdr_duration_str);
-
-       values[0] = ( start != NULL ? *start : empty_string);
-       types[0] = ( start != NULL ? TYPE_DATE : TYPE_NULL);
-
-       values[1] = ( end != NULL ? *end : empty_string);
-       types[1] = ( end != NULL ? TYPE_DATE : TYPE_NULL);
-
-       values[2] = ( duration != NULL ? *duration : empty_string);
-       types[2] = ( duration != NULL ? TYPE_DOUBLE : TYPE_NULL);
+       dlgb.get_dlg_varval(dlg, &cdr_start_str, &dlgvals[0]); /* start */
+       dlgb.get_dlg_varval(dlg, &cdr_end_str, &dlgvals[1]); /* end */
+       dlgb.get_dlg_varval(dlg, &cdr_duration_str, &dlgvals[2]); /* duration */
+
+       for(i=0; i<MAX_CDR_CORE; i++) {
+               if (dlgvals[i].s!=NULL) {
+                       values[i].s = (char *)pkg_malloc(dlgvals[i].len + 1);
+                       if (values[i].s == NULL ) {
+                               PKG_MEM_ERROR;
+                               /* cleanup already allocated memory and
+                                * return that we didn't do anything */
+                               for (i = i-1; i >= 0; i--) {
+                                       if (NULL != values[i].s){
+                                               pkg_free(values[i].s);
+                                               values[i].s = NULL;
+                                       }
+                               }
+                               return 0;
+                       }
+                       memcpy(values[i].s, dlgvals[i].s, dlgvals[i].len);
+                       values[i].s[dlgvals[i].len] = '\0';
+                       values[i].len = dlgvals[i].len;
+                       if(i!=2) {
+                               /* [0] - start; [1] - end */
+                               types[i] = TYPE_DATE;
+                       } else {
+                               /* [2] - duration */
+                               types[i] = TYPE_DOUBLE;
+                       }
+               } else {
+                       values[i] = empty_string;
+                       types[i] = TYPE_NULL;
+               }
+       }
 
        return MAX_CDR_CORE;
 }
@@ -130,8 +151,9 @@ static db_val_t *db_cdr_vals = NULL;
 static int db_write_cdr( struct dlg_cell* dialog,
                struct sip_msg* message)
 {
-       int m = 0;
-       int n = 0;
+       int attr_cnt = 0;
+       int core_cnt = 0;
+       int extra_cnt = 0;
        int i;
        db_func_t *df=NULL;
        db1_con_t *dh=NULL;
@@ -155,12 +177,13 @@ static int db_write_cdr( struct dlg_cell* dialog,
        dh = (db1_con_t*)vh;
 
        /* get default values */
-       m = cdr_core2strar( dialog,
+       core_cnt = cdr_core2strar( dialog,
                        cdr_value_array,
                        cdr_int_array,
                        cdr_type_array);
+       attr_cnt += core_cnt;
 
-       for(i=0; i<m; i++) {
+       for(i=0; i<core_cnt; i++) {
                db_cdr_keys[i] = &cdr_attrs[i];
                /* reset errno, some strtoX don't reset it */
                errno = 0;
@@ -219,23 +242,24 @@ static int db_write_cdr( struct dlg_cell* dialog,
        /* get extra values */
        if (message)
        {
-               n += extra2strar( cdr_extra,
+               extra_cnt = extra2strar( cdr_extra,
                                message,
-                               cdr_value_array + m,
-                               cdr_int_array + m,
-                               cdr_type_array + m);
-               m += n;
+                               cdr_value_array + attr_cnt,
+                               cdr_int_array + attr_cnt,
+                               cdr_type_array + attr_cnt);
+               attr_cnt += extra_cnt;;
        } else if (cdr_expired_dlg_enable){
                LM_WARN( "fallback to dlg_only search because of message doesn't exist.\n");
-               m += extra2strar_dlg_only( cdr_extra,
+               extra_cnt = extra2strar_dlg_only( cdr_extra,
                                dialog,
-                               cdr_value_array + m,
-                               cdr_int_array + m,
-                               cdr_type_array +m,
+                               cdr_value_array + attr_cnt,
+                               cdr_int_array + attr_cnt,
+                               cdr_type_array + attr_cnt,
                                &dlgb);
+               attr_cnt += extra_cnt;
        }
 
-       for( ; i<m; i++) {
+       for( ; i<attr_cnt; i++) {
                db_cdr_keys[i] = &cdr_attrs[i];
 
                if (cdr_extra_nullable == 1 && cdr_type_array[i] == TYPE_NULL) {
@@ -253,29 +277,31 @@ static int db_write_cdr( struct dlg_cell* dialog,
        }
 
        if(acc_db_insert_mode==1 && df->insert_delayed!=NULL) {
-               if (df->insert_delayed(dh, db_cdr_keys, db_cdr_vals, m) < 0) {
+               if (df->insert_delayed(dh, db_cdr_keys, db_cdr_vals, attr_cnt) < 0) {
                        LM_ERR("failed to insert delayed into database\n");
                        goto error;
                }
        } else if(acc_db_insert_mode==2 && df->insert_async!=NULL) {
-               if (df->insert_async(dh, db_cdr_keys, db_cdr_vals, m) < 0) {
+               if (df->insert_async(dh, db_cdr_keys, db_cdr_vals, attr_cnt) < 0) {
                        LM_ERR("failed to insert async into database\n");
                        goto error;
                }
        } else {
-               if (df->insert(dh, db_cdr_keys, db_cdr_vals, m) < 0) {
+               if (df->insert(dh, db_cdr_keys, db_cdr_vals, attr_cnt) < 0) {
                        LM_ERR("failed to insert into database\n");
                        goto error;
                }
        }
 
-       /* Free memory allocated by acc_extra.c/extra2strar */
-       free_strar_mem( &(cdr_type_array[m-n]), &(cdr_value_array[m-n]), n, m);
+       /* Free memory allocated by core+extra attrs */
+       free_strar_mem( &(cdr_type_array[0]), &(cdr_value_array[0]),
+                       attr_cnt, attr_cnt);
        return 0;
 
 error:
-       /* Free memory allocated by acc_extra.c/extra2strar */
-       free_strar_mem( &(cdr_type_array[m-n]), &(cdr_value_array[m-n]), n, m);
+       /* Free memory allocated by core+extra attrs */
+       free_strar_mem( &(cdr_type_array[0]), &(cdr_value_array[0]),
+                       attr_cnt, attr_cnt);
        return -1;
 }
 
@@ -311,7 +337,7 @@ static int log_write_cdr( struct dlg_cell* dialog,
                                cdr_type_array + message_index);
        } else if (cdr_expired_dlg_enable){
                LM_DBG("fallback to dlg_only search because of message does not exist.\n");
-               message_index += extra2strar_dlg_only( cdr_extra,
+               extra_index += extra2strar_dlg_only( cdr_extra,
                                dialog,
                                cdr_value_array + message_index,
                                cdr_int_array + message_index,
@@ -394,9 +420,9 @@ static int write_cdr( struct dlg_cell* dialog,
 
        /* Skip cdr if cdr_skip dlg_var exists */
        if (cdr_skip.len > 0) {
-               str* nocdr_val = 0;
-               nocdr_val = dlgb.get_dlg_var( dialog, &cdr_skip);
-               if ( nocdr_val ){
+               str nocdr_val = {0};
+               dlgb.get_dlg_varval(dialog, &cdr_skip, &nocdr_val);
+               if (nocdr_val.s){
                        LM_DBG( "cdr_skip dlg_var set, skip cdr!");
                        return 0;
                }
@@ -414,7 +440,7 @@ static int string2time( str* time_str, struct timeval* time_value)
        int dot_position = -1;
        char zero_terminated_value[TIME_STR_BUFFER_SIZE];
 
-       if( !time_str)
+       if(!time_str || !time_str->s)
        {
                LM_ERR( "time_str is empty!");
                return -1;
@@ -491,18 +517,20 @@ static int set_duration( struct dlg_cell* dialog)
        struct timeval end_time;
        struct timeval duration_time;
        str duration_str;
+       str dval = {0};
 
-       if( !dialog)
-       {
+       if( !dialog) {
                LM_ERR("dialog is empty!\n");
                return -1;
        }
 
-       if ( string2time( dlgb.get_dlg_var( dialog, (str*)&cdr_start_str), &start_time) < 0) {
+       dlgb.get_dlg_varval(dialog, &cdr_start_str, &dval);
+       if (string2time(&dval, &start_time) < 0) {
                LM_ERR( "failed to extract start time\n");
                return -1;
        }
-       if ( string2time( dlgb.get_dlg_var( dialog, (str*)&cdr_end_str), &end_time) < 0) {
+       dlgb.get_dlg_varval( dialog, &cdr_end_str, &dval);
+       if ( string2time(&dval, &end_time) < 0) {
                LM_ERR( "failed to extract end time\n");
                return -1;
        }
@@ -514,10 +542,7 @@ static int set_duration( struct dlg_cell* dialog)
                return -1;
        }
 
-       if( dlgb.set_dlg_var( dialog,
-                               (str*)&cdr_duration_str,
-                               (str*)&duration_str) != 0)
-       {
+       if( dlgb.set_dlg_var(dialog, &cdr_duration_str, &duration_str) != 0) {
                LM_ERR( "failed to set duration time");
                return -1;
        }
index 5c29cc7..6205ba1 100644 (file)
@@ -266,8 +266,9 @@ int extra2strar_dlg_only(struct acc_extra *extra, struct dlg_cell* dlg, str *val
                int *int_arr, char *type_arr, const struct dlg_binds* p_dlgb)
 {
        //string value;
-       str* value = 0;
+       str dval = {0};
        int n=0;
+       int i;
 
        if( !dlg || !val_arr || !int_arr || !type_arr || !p_dlgb)
        {
@@ -288,17 +289,30 @@ int extra2strar_dlg_only(struct acc_extra *extra, struct dlg_cell* dlg, str *val
                type_arr[n] = TYPE_NULL;
 
                str key = extra->spec.pvp.pvn.u.isname.name.s;
-               if ( key.len == 0 || !key.s)
-               {
+               if (key.len == 0 || !key.s) {
                        n++; extra = extra->next; continue;
                }
-               /* get the value */
-               value = p_dlgb->get_dlg_var( dlg, &key);
+               /* get the dialog var value */
+               p_dlgb->get_dlg_varval(dlg, &key, &dval);
 
-               if (value)
-               {
-                       val_arr[n].s = value->s;
-                       val_arr[n].len = value->len;
+               if (dval.s) {
+                       val_arr[n].s = (char *)pkg_malloc(dval.len + 1);
+                       if (val_arr[n].s == NULL ) {
+                               PKG_MEM_ERROR;
+                               /* cleanup already allocated memory and
+                                * return that we didn't do anything */
+                               for (i = 0; i < n ; i++) {
+                                       if (NULL != val_arr[i].s){
+                                               pkg_free(val_arr[i].s);
+                                               val_arr[i].s = NULL;
+                                       }
+                               }
+                               n = 0;
+                               goto done;
+                       }
+                       memcpy(val_arr[n].s, dval.s, dval.len);
+                       val_arr[n].s[dval.len] = '\0';
+                       val_arr[n].len = dval.len;
                        type_arr[n] = TYPE_STR;
                }
 
index 42d29c8..7e0698f 100644 (file)
 
 MODULE_VERSION
 
+static str acc_method_key = str_init("method");
+static str acc_fromtag_key = str_init("from_tag");
+static str acc_totag_key = str_init("to_tag");
+static str acc_callid_key = str_init("callid");
+static str acc_sipcode_key = str_init("sip_code");
+static str acc_sipreason_key = str_init("sip_reason");
+static str acc_time_key = str_init("time");
+
+static str cdr_start_str = str_init("start_time");
+static str cdr_end_str = str_init("end_time");
+static str cdr_duration_str = str_init("duration");
+
+static char acc_time_format_buf[ACC_TIME_FORMAT_SIZE];
+static char *acc_time_format = "%Y-%m-%d %H:%M:%S";
+
+static int acc_log_level = L_NOTICE;
+static int acc_log_facility = LOG_DAEMON;
+static int cdr_log_level = L_NOTICE;
+static int cdr_log_facility = LOG_DAEMON;
+
 static int mod_init(void);
 static void destroy(void);
 static int child_init(int rank);
@@ -81,37 +101,41 @@ str cdr_json_pre_encoded_prefix = {0, 0};
 static cmd_export_t cmds[] = {{0, 0, 0, 0, 0, 0}};
 
 
-static param_export_t params[] = {{"acc_flag", INT_PARAM, &acc_flag},
-               {"acc_missed_flag", INT_PARAM, &acc_missed_flag},
-               {"acc_extra", PARAM_STRING, &acc_extra_str},
-               {"acc_pre_encoded_prefix", PARAM_STRING, &acc_json_pre_encoded_prefix_str},
-               {"acc_time_mode", INT_PARAM, &acc_time_mode},
-               {"acc_time_format", PARAM_STRING, &acc_time_format},
-               {"acc_log_level", INT_PARAM, &acc_log_level},
-               {"acc_log_facility", PARAM_STRING, &acc_log_facility_str},
-               {"acc_output_mqueue", PARAM_STRING, &acc_output_mqueue_str},
-               {"acc_output_syslog", INT_PARAM, &acc_output_syslog},
-               {"cdr_extra", PARAM_STRING, &cdr_extra_str},
-               {"cdr_pre_encoded_prefix", PARAM_STRING, &cdr_json_pre_encoded_prefix_str},
-               {"cdr_enable", INT_PARAM, &cdr_enable},
-               {"cdr_expired_dlg_enable", INT_PARAM, &cdr_expired_dlg_enable},
-               {"cdr_log_level", INT_PARAM, &cdr_log_level},
-               {"cdr_log_facility", PARAM_STRING, &cdr_log_facility_str},
-               {"cdr_output_mqueue", PARAM_STRING, &cdr_output_mqueue_str},
-               {"cdr_output_syslog", INT_PARAM, &cdr_output_syslog}, {0, 0, 0}};
+static param_export_t params[] = {
+       {"acc_flag", INT_PARAM, &acc_flag},
+       {"acc_missed_flag", INT_PARAM, &acc_missed_flag},
+       {"acc_extra", PARAM_STRING, &acc_extra_str},
+       {"acc_pre_encoded_prefix", PARAM_STRING, &acc_json_pre_encoded_prefix_str},
+       {"acc_time_mode", INT_PARAM, &acc_time_mode},
+       {"acc_time_format", PARAM_STRING, &acc_time_format},
+       {"acc_log_level", INT_PARAM, &acc_log_level},
+       {"acc_log_facility", PARAM_STRING, &acc_log_facility_str},
+       {"acc_output_mqueue", PARAM_STRING, &acc_output_mqueue_str},
+       {"acc_output_syslog", INT_PARAM, &acc_output_syslog},
+       {"cdr_extra", PARAM_STRING, &cdr_extra_str},
+       {"cdr_pre_encoded_prefix", PARAM_STRING, &cdr_json_pre_encoded_prefix_str},
+       {"cdr_enable", INT_PARAM, &cdr_enable},
+       {"cdr_expired_dlg_enable", INT_PARAM, &cdr_expired_dlg_enable},
+       {"cdr_log_level", INT_PARAM, &cdr_log_level},
+       {"cdr_log_facility", PARAM_STRING, &cdr_log_facility_str},
+       {"cdr_output_mqueue", PARAM_STRING, &cdr_output_mqueue_str},
+       {"cdr_output_syslog", INT_PARAM, &cdr_output_syslog},
+
+       {0, 0, 0}
+};
 
 
 struct module_exports exports = {
-               "acc_json", 
-                DEFAULT_DLFLAGS, /* dlopen flags */
-               cmds,            /* exported functions */
-               params,          /* exported params */
-               0,               /* exported RPC methods */
-               0,               /* exported pseudo-variables */
-               0,               /* response function */
-               mod_init,        /* initialization module */
-               child_init,      /* per-child init function */
-               destroy          /* destroy function */
+       "acc_json",
+       DEFAULT_DLFLAGS, /* dlopen flags */
+       cmds,            /* exported functions */
+       params,          /* exported params */
+       0,               /* exported RPC methods */
+       0,               /* exported pseudo-variables */
+       0,               /* response function */
+       mod_init,        /* initialization module */
+       child_init,      /* per-child init function */
+       destroy          /* destroy function */
 };
 
 
@@ -286,14 +310,13 @@ int acc_json_send_request(struct sip_msg *req, acc_info_t *inf)
                } else {
                        t = gmtime(&inf->env->ts);
                }
-               if(strftime(acc_time_format_buf, ACC_TIME_FORMAT_SIZE, acc_time_format,
-                                  t)
+               if(strftime(acc_time_format_buf, ACC_TIME_FORMAT_SIZE, acc_time_format, t)
                                <= 0) {
                        acc_time_format_buf[0] = '\0';
                }
-               json_object_set_new(object, "time", json_string(acc_time_format_buf));
+               json_object_set_new(object, acc_time_key.s, json_string(acc_time_format_buf));
        } else { // default acc_time_mode==1
-               json_object_set_new(object, "time", json_integer(inf->env->ts));
+               json_object_set_new(object, acc_time_key.s, json_integer(inf->env->ts));
        }
 
        LM_DBG("text[%.*s]\n", inf->env->text.len, inf->env->text.s);
@@ -452,14 +475,13 @@ int cdr_json_write(struct dlg_cell *dlg, struct sip_msg *req, cdr_info_t *inf)
                                inf->tarr + attr_cnt);
                attr_cnt += extra_cnt;
        } else if (cdr_expired_dlg_enable){
-               int dlg_index = 0;
-               dlg_index += accb.get_extra_dlg_attrs( cdr_extra,
+               extra_cnt += accb.get_extra_dlg_attrs( cdr_extra,
                                dlg,
                                inf->varr + attr_cnt,
                                inf->iarr + attr_cnt,
                                inf->tarr + attr_cnt,
                                &dlgb);
-               attr_cnt += dlg_index;
+               attr_cnt += extra_cnt;
        }
 
        struct acc_extra *extra = cdr_extra;
@@ -516,7 +538,7 @@ int cdr_json_write(struct dlg_cell *dlg, struct sip_msg *req, cdr_info_t *inf)
                json_object_clear(object);
                json_decref(object);
        }
-       /* free memory allocated by get_extra_attrs */
-       free_strar_mem(&(inf->tarr[core_cnt]), &(inf->varr[core_cnt]), extra_cnt, attr_cnt);
+       /* free memory allocated by cdr core+extra attrs */
+       free_strar_mem(&(inf->tarr[0]), &(inf->varr[0]), attr_cnt, attr_cnt);
        return 1;
 }
index 25a3ac1..62c3350 100644 (file)
 #ifndef _ACC_JSON_MOD_H_
 #define _ACC_JSON_MOD_H_
 
-str acc_method_key = str_init("method");
-str acc_fromtag_key = str_init("from_tag");
-str acc_totag_key = str_init("to_tag");
-str acc_callid_key = str_init("callid");
-str acc_sipcode_key = str_init("sip_code");
-str acc_sipreason_key = str_init("sip_reason");
-str acc_time_key = str_init("time");
-
-str cdr_start_str = str_init("start_time");
-str cdr_end_str = str_init("end_time");
-str cdr_duration_str = str_init("duration");
-
 #define ACC_TIME_FORMAT_SIZE 128
-static char acc_time_format_buf[ACC_TIME_FORMAT_SIZE];
-char *acc_time_format = "%Y-%m-%d %H:%M:%S";
-
-int acc_log_level = L_NOTICE;
-int acc_log_facility = LOG_DAEMON;
-int cdr_log_level = L_NOTICE;
-int cdr_log_facility = LOG_DAEMON;
 
 #endif
index 5a263ea..db6da6a 100644 (file)
@@ -72,20 +72,17 @@ static PyObject *msg_rewrite_ruri(msgobject *self, PyObject *args)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if ((self->msg->first_line).type != SIP_REQUEST) {
                PyErr_SetString(PyExc_RuntimeError, "Not a request message - rewrite is not possible.\n");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if(!PyArg_ParseTuple(args, "s:rewrite_ruri", &nuri.s))
@@ -107,20 +104,17 @@ static PyObject *msg_set_dst_uri(msgobject *self, PyObject *args)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if ((self->msg->first_line).type != SIP_REQUEST) {
                PyErr_SetString(PyExc_RuntimeError, "Not a request message - set destination is not possible.\n");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if(!PyArg_ParseTuple(args, "s:set_dst_uri", &ruri.s))
@@ -129,8 +123,8 @@ static PyObject *msg_set_dst_uri(msgobject *self, PyObject *args)
        ruri.len = strlen(ruri.s);
 
        if (set_dst_uri(self->msg, &ruri) < 0) {
-               LM_ERR("Error in set_dst_uri\n");
                PyErr_SetString(PyExc_RuntimeError, "Error in set_dst_uri\n");
+               return NULL;
        }
        /* dst_uri changes, so it makes sense to re-use the current uri for
         * forking */
@@ -147,14 +141,12 @@ static PyObject *msg_getHeader(msgobject *self, PyObject *args)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if(!PyArg_ParseTuple(args, "s:getHeader", &hname.s))
@@ -191,22 +183,19 @@ PyObject *msg_call_function(msgobject *self, PyObject *args)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        i = PySequence_Size(args);
        if (i < 1 || i > 3) {
                PyErr_SetString(PyExc_RuntimeError, "call_function() should " \
                                "have from 1 to 3 arguments");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if(!PyArg_ParseTuple(args, "s|ss:call_function", &fname, &arg1, &arg2))
@@ -215,8 +204,7 @@ PyObject *msg_call_function(msgobject *self, PyObject *args)
        fexport = find_export_record(fname, i - 1, 0);
        if (fexport == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "no such function");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        act = mk_action(MODULE2_T, 4 /* number of (type, value) pairs */,
@@ -229,38 +217,34 @@ PyObject *msg_call_function(msgobject *self, PyObject *args)
        if (act == NULL) {
                PyErr_SetString(PyExc_RuntimeError,
                                "action structure could not be created");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (fexport->fixup != NULL) {
                if (i >= 3) {
                        rval = fexport->fixup(&(act->val[3].u.data), 2);
                        if (rval < 0) {
-                               PyErr_SetString(PyExc_RuntimeError, "Error in fixup (2)");
-                               Py_INCREF(Py_None);
                                pkg_free(act);
-                               return Py_None;
+                               PyErr_SetString(PyExc_RuntimeError, "Error in fixup (2)");
+                               return NULL;
                        }
                        act->val[3].type = MODFIXUP_ST;
                }
                if (i >= 2) {
                        rval = fexport->fixup(&(act->val[2].u.data), 1);
                        if (rval < 0) {
-                               PyErr_SetString(PyExc_RuntimeError, "Error in fixup (1)");
-                               Py_INCREF(Py_None);
                                pkg_free(act);
-                               return Py_None;
+                               PyErr_SetString(PyExc_RuntimeError, "Error in fixup (1)");
+                               return NULL;
                        }
                        act->val[2].type = MODFIXUP_ST;
                }
                if (i == 1) {
                        rval = fexport->fixup(0, 0);
                        if (rval < 0) {
-                               PyErr_SetString(PyExc_RuntimeError, "Error in fixup (0)");
-                               Py_INCREF(Py_None);
                                pkg_free(act);
-                               return Py_None;
+                               PyErr_SetString(PyExc_RuntimeError, "Error in fixup (0)");
+                               return NULL;
                        }
                }
        }
@@ -306,14 +290,12 @@ static PyObject *msg_getType(msgobject *self, PyObject *unused)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        switch ((self->msg->first_line).type)
@@ -340,21 +322,19 @@ static PyObject *msg_getMethod(msgobject *self, PyObject *unused)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if ((self->msg->first_line).type != SIP_REQUEST) {
                PyErr_SetString(PyExc_RuntimeError, "Not a request message - no method available.\n");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
+
        rval = &((self->msg->first_line).u.request.method);
        return PyUnicode_FromStringAndSize(rval->s, rval->len);
 }
@@ -365,20 +345,17 @@ static PyObject *msg_getStatus(msgobject *self, PyObject *unused)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if ((self->msg->first_line).type != SIP_REPLY) {
                PyErr_SetString(PyExc_RuntimeError, "Not a non-reply message - no status available.\n");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        rval = &((self->msg->first_line).u.reply.status);
@@ -391,20 +368,17 @@ static PyObject *msg_getRURI(msgobject *self, PyObject *unused)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if ((self->msg->first_line).type != SIP_REQUEST) {
                PyErr_SetString(PyExc_RuntimeError, "Not a request message - RURI is not available.\n");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        rval = &((self->msg->first_line).u.request.uri);
@@ -417,14 +391,12 @@ static PyObject *msg_get_src_address(msgobject *self, PyObject *unused)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        src_ip = PyUnicode_FromString(ip_addr2a(&self->msg->rcv.src_ip));
@@ -457,14 +429,12 @@ static PyObject *msg_get_dst_address(msgobject *self, PyObject *unused)
 
        if (self == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        if (self->msg == NULL) {
                PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
-               Py_INCREF(Py_None);
-               return Py_None;
+               return NULL;
        }
 
        dst_ip = PyUnicode_FromString(ip_addr2a(&self->msg->rcv.dst_ip));
index 12fd804..67aabde 100644 (file)
@@ -65,7 +65,8 @@ static void corex_rpc_list_sockets(rpc_t* rpc, void* ctx)
                                return;
                        }
 
-                       if(rpc->struct_add(th, "ss{",
+                       if(rpc->struct_add(th, "sss{",
+                               "AF",   get_af_name(proto),
                                "PROTO",        get_valid_proto_name(proto),
                                "NAME",         si->name.s,
                                "ADDRLIST",  &ih)<0)
index 27d5f44..d850087 100644 (file)
@@ -116,6 +116,7 @@ Julien Klingenmeyer
               6.63. keep_proxy_rr (string)
               6.64. bye_early_code (int)
               6.65. bye_early_reason (string)
+              6.66. dlg_ctxiuid_mode (int)
 
         7. Functions
 
@@ -264,30 +265,31 @@ Julien Klingenmeyer
    1.63. Set dlg_keep_proxy_rr parameter
    1.64. Set bye_early_code parameter
    1.65. Set bye_early_reason parameter
-   1.66. set_dlg_profile usage
-   1.67. unset_dlg_profile usage
-   1.68. is_in_profile usage
-   1.69. get_profile_size usage
-   1.70. dlg_isflagset usage
-   1.71. dlg_setflag usage
-   1.72. dlg_resetflag usage
-   1.73. dlg_bye usage
-   1.74. dlg_refer usage
-   1.75. dlg_manage usage
-   1.76. dlg_bridge usage
-   1.77. dlg_get usage
-   1.78. dlg_get_var usage
-   1.79. dlg_set_var usage
-   1.80. is_known_dlg() usage
-   1.81. dlg_set_timeout usage
-   1.82. dlg_set_timeout_by_profile usage
-   1.83. dlg_set_property usage
-   1.84. dlg_remote_profile usage
-   1.85. dlg_set_ruri() usage
-   1.86. dlg_db_load_callid() usage
-   1.87. dlg_db_load_extra() usage
-   1.88. dlg_reset_property usage
-   1.89. dlg_req_within usage
+   1.66. Set dlg_ctxiuid_mode parameter
+   1.67. set_dlg_profile usage
+   1.68. unset_dlg_profile usage
+   1.69. is_in_profile usage
+   1.70. get_profile_size usage
+   1.71. dlg_isflagset usage
+   1.72. dlg_setflag usage
+   1.73. dlg_resetflag usage
+   1.74. dlg_bye usage
+   1.75. dlg_refer usage
+   1.76. dlg_manage usage
+   1.77. dlg_bridge usage
+   1.78. dlg_get usage
+   1.79. dlg_get_var usage
+   1.80. dlg_set_var usage
+   1.81. is_known_dlg() usage
+   1.82. dlg_set_timeout usage
+   1.83. dlg_set_timeout_by_profile usage
+   1.84. dlg_set_property usage
+   1.85. dlg_remote_profile usage
+   1.86. dlg_set_ruri() usage
+   1.87. dlg_db_load_callid() usage
+   1.88. dlg_db_load_extra() usage
+   1.89. dlg_reset_property usage
+   1.90. dlg_req_within usage
 
 Chapter 1. Admin Guide
 
@@ -369,6 +371,7 @@ Chapter 1. Admin Guide
         6.63. keep_proxy_rr (string)
         6.64. bye_early_code (int)
         6.65. bye_early_reason (string)
+        6.66. dlg_ctxiuid_mode (int)
 
    7. Functions
 
@@ -607,6 +610,7 @@ Chapter 1. Admin Guide
    6.63. keep_proxy_rr (string)
    6.64. bye_early_code (int)
    6.65. bye_early_reason (string)
+   6.66. dlg_ctxiuid_mode (int)
 
 6.1. enable_stats (integer)
 
@@ -1496,6 +1500,19 @@ modparam("dialog", "bye_early_code", 503)
 modparam("dialog", "bye_early_reason", "Call terminated")
 ...
 
+6.66. dlg_ctxiuid_mode (int)
+
+   Set dialog context iuid mode, which can specify additional cases when
+   the internal unique id should be set:
+     * 1 - set it when processing CANCEL requests.
+
+   Default value is “0”.
+
+   Example 1.66. Set dlg_ctxiuid_mode parameter
+...
+modparam("dialog", "dlg_ctxiuid_mode", 1)
+...
+
 7. Functions
 
    7.1. set_dlg_profile(profile,[value])
@@ -1539,7 +1556,7 @@ modparam("dialog", "bye_early_reason", "Call terminated")
    This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE
    and FAILURE_ROUTE.
 
-   Example 1.66. set_dlg_profile usage
+   Example 1.67. set_dlg_profile usage
 ...
 set_dlg_profile("inbound_call");
 set_dlg_profile("caller","$fu");
@@ -1558,7 +1575,7 @@ set_dlg_profile("caller","$fu");
    This function can be used from BRANCH_ROUTE, REPLY_ROUTE and
    FAILURE_ROUTE.
 
-   Example 1.67. unset_dlg_profile usage
+   Example 1.68. unset_dlg_profile usage
 ...
 unset_dlg_profile("inbound_call");
 unset_dlg_profile("caller","$fu");
@@ -1581,7 +1598,7 @@ unset_dlg_profile("caller","$fu");
    This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE
    and FAILURE_ROUTE.
 
-   Example 1.68. is_in_profile usage
+   Example 1.69. is_in_profile usage
 ...
 if (is_in_profile("inbound_call")) {
         log("this request belongs to a inbound call\n");
@@ -1611,7 +1628,7 @@ if (is_in_profile("caller","XX")) {
    This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE
    and FAILURE_ROUTE.
 
-   Example 1.69. get_profile_size usage
+   Example 1.70. get_profile_size usage
 ...
 if(get_profile_size("inbound_call","$avp(size)"))
     xlog("currently there are $avp(size) inbound calls\n");
@@ -1630,7 +1647,7 @@ if(get_profile_size("caller","$fu","$avp(size)"))
    This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
    ONREPLY_ROUTE and FAILURE_ROUTE.
 
-   Example 1.70. dlg_isflagset usage
+   Example 1.71. dlg_isflagset usage
 ...
 if(dlg_isflagset("1"))
 {
@@ -1648,7 +1665,7 @@ if(dlg_isflagset("1"))
    This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
    ONREPLY_ROUTE and FAILURE_ROUTE.
 
-   Example 1.71. dlg_setflag usage
+   Example 1.72. dlg_setflag usage
 ...
 dlg_setflag("1");
 ...
@@ -1663,7 +1680,7 @@ dlg_setflag("1");
    This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
    ONREPLY_ROUTE and FAILURE_ROUTE.
 
-   Example 1.72. dlg_resetflag usage
+   Example 1.73. dlg_resetflag usage
 ...
 redlg_setflag("1");
 ...
@@ -1680,7 +1697,7 @@ redlg_setflag("1");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.73. dlg_bye usage
+   Example 1.74. dlg_bye usage
 ...
 dlg_bye("all");
 ...
@@ -1697,7 +1714,7 @@ dlg_bye("all");
    This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
    ONREPLY_ROUTE and FAILURE_ROUTE.
 
-   Example 1.74. dlg_refer usage
+   Example 1.75. dlg_refer usage
 ...
 dlg_refer("caller", "sip:announcement@kamailio.org");
 ...
@@ -1710,7 +1727,7 @@ dlg_refer("caller", "sip:announcement@kamailio.org");
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.75. dlg_manage usage
+   Example 1.76. dlg_manage usage
 ...
 modparam("dialog", "default_timeout", 100)
 ...
@@ -1738,7 +1755,7 @@ request_route {
    This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
    ONREPLY_ROUTE and FAILURE_ROUTE.
 
-   Example 1.76. dlg_bridge usage
+   Example 1.77. dlg_bridge usage
 ...
 dlg_bridge("sip:user@kamailio.org", "sip:annoucement@kamailio.org",
    "sip:kamailio.org:5080");
@@ -1758,7 +1775,7 @@ dlg_bridge("sip:user@kamailio.org", "sip:annoucement@kamailio.org",
    This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
    ONREPLY_ROUTE and FAILURE_ROUTE.
 
-   Example 1.77. dlg_get usage
+   Example 1.78. dlg_get usage
 ...
 if(dlg_get("abcdef", "123", "456"))
 {
@@ -1781,7 +1798,7 @@ if(dlg_get("abcdef", "123", "456"))
    This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
    ONREPLY_ROUTE and FAILURE_ROUTE.
 
-   Example 1.78. dlg_get_var usage
+   Example 1.79. dlg_get_var usage
 ...
 if(dlg_get_var("$var(ci)", "$var(ft)", "456", "test", "$var(tmp)"))
 {
@@ -1804,7 +1821,7 @@ if(dlg_get_var("$var(ci)", "$var(ft)", "456", "test", "$var(tmp)"))
    This function can be used from BRANCH_ROUTE, REQUEST_ROUTE,
    ONREPLY_ROUTE and FAILURE_ROUTE.
 
-   Example 1.79. dlg_set_var usage
+   Example 1.80. dlg_set_var usage
 ...
 if(dlg_set_var("$var(ci)", "$var(ft)", "456", "test", "$var(tmp)"))
 {
@@ -1828,7 +1845,7 @@ if(dlg_set_var("$var(ci)", "$var(ft)", "456", "test", "$var(tmp)"))
    This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, REPLY_ROUTE
    and FAILURE_ROUTE.
 
-   Example 1.80. is_known_dlg() usage
+   Example 1.81. is_known_dlg() usage
 ...
 if(!uri == myself) {
         if(is_known_dlg()) {
@@ -1852,7 +1869,7 @@ if(!uri == myself) {
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.81. dlg_set_timeout usage
+   Example 1.82. dlg_set_timeout usage
 ...
 if(dlg_set_timeout("180", "123", "456"))
 {
@@ -1874,7 +1891,7 @@ if(dlg_set_timeout("180", "123", "456"))
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.82. dlg_set_timeout_by_profile usage
+   Example 1.83. dlg_set_timeout_by_profile usage
 ...
 # All dialogs belonging to user abc123 (tracked via set_dlg_profile())
 # will be timed out in 3 seconds.
@@ -1906,7 +1923,7 @@ dlg_set_timeout_by_profile("users", "abc123", "3");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.83. dlg_set_property usage
+   Example 1.84. dlg_set_property usage
 ...
 dlg_set_property("ka-src");
 dlg_set_property("ka-dst");
@@ -1934,7 +1951,7 @@ dlg_set_property("timeout-noreset");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.84. dlg_remote_profile usage
+   Example 1.85. dlg_remote_profile usage
 ...
 $var(exp) = 3600 + $Ts;
 dlg_remote_profile("add", "caller", "test", "$sruid", "$var(exp)");
@@ -1947,7 +1964,7 @@ dlg_remote_profile("add", "caller", "test", "$sruid", "$var(exp)");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.85. dlg_set_ruri() usage
+   Example 1.86. dlg_set_ruri() usage
 ...
 if(has_totag() and is_present_hf("Route") and uri==myself ) {
         if(dlg_set_ruri()) {
@@ -1963,7 +1980,7 @@ if(has_totag() and is_present_hf("Route") and uri==myself ) {
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.86. dlg_db_load_callid() usage
+   Example 1.87. dlg_db_load_callid() usage
 ...
 if(has_totag()) {
     if(!is_known_dlg()) {
@@ -1982,7 +1999,7 @@ if(has_totag()) {
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.87. dlg_db_load_extra() usage
+   Example 1.88. dlg_db_load_extra() usage
 ...
 if(has_totag()) {
     if(!is_known_dlg()) {
@@ -2008,7 +2025,7 @@ if(has_totag()) {
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.88. dlg_reset_property usage
+   Example 1.89. dlg_reset_property usage
 ...
 dlg_reset_property("ka-src");
 dlg_reset_property("ka-dst");
@@ -2031,7 +2048,7 @@ dlg_reset_property("timeout-noreset");
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.89. dlg_req_within usage
+   Example 1.90. dlg_req_within usage
 ...
         # Send a simple request:
         dlg_req_within("all", "OPTIONS");
index 8eb9f78..d4d2df0 100644 (file)
@@ -154,6 +154,7 @@ str dlg_xavp_cfg = {0};
 int dlg_ka_timer = 0;
 int dlg_ka_interval = 0;
 int dlg_clean_timer = 90;
+int dlg_ctxiuid_mode = 0;
 
 str dlg_lreq_callee_headers = {0};
 
@@ -361,6 +362,8 @@ static param_export_t mod_params[]={
        { "dlg_filter_mode",       INT_PARAM, &dlg_filter_mode          },
        { "bye_early_code",        PARAM_INT, &bye_early_code           },
        { "bye_early_reason",      PARAM_STR, &bye_early_reason         },
+       { "dlg_ctxiuid_mode",      PARAM_INT, &dlg_ctxiuid_mode         },
+
        { 0,0,0 }
 };
 
@@ -478,7 +481,8 @@ int load_dlg( struct dlg_binds *dlgb )
        dlgb->register_dlgcb = register_dlgcb;
        dlgb->terminate_dlg = dlg_bye_all;
        dlgb->set_dlg_var = set_dlg_variable;
-       dlgb->get_dlg_var = get_dlg_variable;
+       dlgb->get_dlg_varref = get_dlg_varref;
+       dlgb->get_dlg_varval = get_dlg_varval;
        dlgb->get_dlg = dlg_get_msg_dialog;
        dlgb->release_dlg = dlg_release;
        return 1;
@@ -1789,7 +1793,7 @@ static str *ki_dlg_get_var_helper(sip_msg_t *msg, str *sc, str *sf, str *st, str
        dlg = get_dlg(sc, sf, st, &dir);
        if(dlg==NULL)
                return val;
-       val = get_dlg_variable(dlg, key);
+       val = get_dlg_varref(dlg, key);
        dlg_release(dlg);
        return val;
 }
@@ -2459,7 +2463,7 @@ static sr_kemi_xval_t* ki_dlg_var_get_mode(sip_msg_t *msg, str *name, int rmode)
                sr_kemi_xval_null(&_sr_kemi_dialog_xval, rmode);
                return &_sr_kemi_dialog_xval;
        }
-       pval = get_dlg_variable(dlg, name);
+       pval = get_dlg_varref(dlg, name);
        if(pval==NULL || pval->s==NULL) {
                sr_kemi_xval_null(&_sr_kemi_dialog_xval, rmode);
                goto done;
@@ -2520,7 +2524,7 @@ static int ki_dlg_var_is_null(sip_msg_t *msg, str *name)
        if(dlg==NULL) {
                return 1;
        }
-       pval = get_dlg_variable(dlg, name);
+       pval = get_dlg_varref(dlg, name);
        if(pval==NULL || pval->s==NULL) {
                return 1;
        }
index bb0037c..d049875 100644 (file)
@@ -55,8 +55,11 @@ typedef int (*set_dlg_variable_f)( struct dlg_cell* dlg,
                                    str* key,
                                    str* val);
 /* method to get a variable from a dialog */
-typedef str* (*get_dlg_variable_f)( struct dlg_cell* dlg,
+typedef str* (*get_dlg_varref_f)( struct dlg_cell* dlg,
                                     str* key);
+/* method to get a variable from a dialog */
+typedef int (*get_dlg_varval_f)( struct dlg_cell* dlg,
+                                    str* key, str* val);
 
 #define CONFIRMED_DIALOG_STATE 1
 
index 70b2b43..d5ffe20 100644 (file)
@@ -131,7 +131,6 @@ int dlg_cseq_update(sip_msg_t *msg)
        unsigned int ninc = 0;
        unsigned int vinc = 0;
        str nval;
-       str *pval;
        sr_cfgenv_t *cenv = NULL;
 
        if(dlg_cseq_prepare_msg(msg)!=0) {
@@ -164,24 +163,17 @@ int dlg_cseq_update(sip_msg_t *msg)
        /* take the increment value from dialog */
        if((dlg->iflags&DLG_IFLAG_CSEQ_DIFF)==DLG_IFLAG_CSEQ_DIFF) {
                /* get dialog variable holding cseq diff */
-               pval = get_dlg_variable(dlg, &_dlg_cseq_diff_var_name);
-               if(pval==NULL || pval->s==NULL || pval->len<=0) {
+               if(get_dlg_variable_uintval(dlg, &_dlg_cseq_diff_var_name, &vinc) < 0) {
                        LM_DBG("dialog marked with cseq diff but no variable set yet\n");
                        goto done;
                }
-               if(str2int(pval, &vinc)<0) {
-                       LM_ERR("invalid dlg cseq diff var value: %.*s\n",
-                                       pval->len, pval->s);
-                       goto done;
-               }
        }
        vinc += ninc;
        if(vinc==0) {
                LM_DBG("nothing to increment\n");
                goto done;
        }
-       nval.s = int2str(vinc, &nval.len);
-       if(set_dlg_variable(dlg, &_dlg_cseq_diff_var_name, &nval) <0) {
+       if(set_dlg_variable_uintval(dlg, &_dlg_cseq_diff_var_name, vinc) <0) {
                LM_ERR("failed to set the dlg cseq diff var\n");
                goto done;
        }
@@ -211,7 +203,6 @@ int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg,
        unsigned int ninc = 0;
        unsigned int vinc = 0;
        str nval;
-       str *pval;
        sr_cfgenv_t *cenv = NULL;
 
        if(dlg_cseq_prepare_msg(msg)!=0) {
@@ -236,18 +227,12 @@ int dlg_cseq_refresh(sip_msg_t *msg, dlg_cell_t *dlg,
                goto done;
        }
 
-       /* get dialog variable holding cseq diff */
-       pval = get_dlg_variable(dlg, &_dlg_cseq_diff_var_name);
-       if(pval==NULL || pval->s==NULL || pval->len<=0) {
+       /* get the value of the dialog variable holding cseq diff */
+       if(get_dlg_variable_uintval(dlg, &_dlg_cseq_diff_var_name, &vinc) < 0) {
                LM_DBG("dialog marked with cseq diff but no variable set yet\n");
                goto done;
        }
 
-       if(str2int(pval, &vinc)<0) {
-               LM_ERR("invalid dlg cseq diff var value: %.*s\n",
-                                       pval->len, pval->s);
-               goto done;
-       }
        if(vinc==0) {
                LM_DBG("nothing to increment\n");
                goto done;
index 39f1f83..81525de 100644 (file)
@@ -72,6 +72,7 @@ extern int       dlg_event_rt[DLG_EVENTRT_MAX];
 extern int       dlg_wait_ack;
 extern int       dlg_enable_dmq;
 extern int       dlg_filter_mode;
+extern int       dlg_ctxiuid_mode;
 int              spiral_detected = -1;
 
 extern struct rr_binds d_rrb;          /*!< binding to record-routing module */
@@ -91,6 +92,9 @@ static unsigned int CURR_DLG_ID  = 0xffffffff;        /*!< current dialog id */
 /*! separator inside the record-route paramter */
 #define DLG_SEPARATOR      '.'
 
+/*! flags for dlg_ctxiuid */
+#define DLG_CTXIUID_MODE_CANCEL 1
+
 int dlg_set_tm_callbacks(tm_cell_t *t, sip_msg_t *req, dlg_cell_t *dlg,
                int mode);
 int dlg_set_tm_waitack(tm_cell_t *t, dlg_cell_t *dlg);
@@ -1258,6 +1262,10 @@ dlg_cell_t *dlg_lookup_msg_dialog(sip_msg_t *msg, unsigned int *dir)
                                msg->callid->body.len, msg->callid->body.s);
                return NULL;
        }
+       if((dlg_ctxiuid_mode & DLG_CTXIUID_MODE_CANCEL) && IS_SIP_REQUEST(msg)
+                       && (msg->first_line.u.request.method_value == METHOD_CANCEL)) {
+               dlg_set_ctx_iuid(dlg);
+       }
        if(dir) *dir = vdir;
        return dlg;
 }
index 8682a84..2a3273c 100644 (file)
@@ -46,7 +46,8 @@ struct dlg_binds {
        register_dlgcb_f  register_dlgcb;
        terminate_dlg_f terminate_dlg;
     set_dlg_variable_f set_dlg_var;
-       get_dlg_variable_f get_dlg_var;
+       get_dlg_varref_f   get_dlg_varref;
+       get_dlg_varval_f   get_dlg_varval;
        get_dlg_f          get_dlg;
        release_dlg_f      release_dlg;
 };
index b2a373a..04a6453 100644 (file)
@@ -279,7 +279,11 @@ void print_lists(struct dlg_cell *dlg) {
        }
 }
 
-str * get_dlg_variable(struct dlg_cell *dlg, str *key)
+/**
+ * return reference to the dlg variable value
+ * - unsafe - use only when it is sure that the value is not updated
+ */
+str* get_dlg_varref(struct dlg_cell *dlg, str *key)
 {
     str* var = NULL;
 
@@ -297,10 +301,80 @@ str * get_dlg_variable(struct dlg_cell *dlg, str *key)
     return var;
 }
 
+/**
+ * set *val to a pv buffer where the dlg value is cloned
+ * - safe to use immediately, before another dlg var get or other operation
+ *   done by the same process exceeds the number of pv buffer slots
+ */
+int get_dlg_varval(struct dlg_cell *dlg, str *key, str *val)
+{
+       str *var = NULL;
+
+       val->s = NULL;
+       val->len = 0;
+
+       if( !dlg || !key || key->len > strlen(key->s)) {
+               LM_ERR("BUG - bad parameters\n");
+               return -1;
+       }
+
+       dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
+       var = get_dlg_variable_unsafe(dlg, key);
+       if(var) {
+               val->len = pv_get_buffer_size();
+               if(val->len < var->len+1) {
+                       LM_ERR("pv buffer too small (%d) - needed %d\n",
+                                       val->len, var->len+1);
+                       val->s = NULL;
+                       val->len = 0;
+                       var = NULL;
+               } else {
+                       val->s = pv_get_buffer();
+                       memcpy(val->s, var->s, var->len);
+                       val->len = var->len;
+                       val->s[val->len] = '\0';
+               }
+       }
+       dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+
+       if(var) {
+               return 0;
+       }
+       return -2;
+}
+
+int get_dlg_variable_uintval(struct dlg_cell *dlg, str *key, unsigned int *uval)
+{
+       str* var = NULL;
+
+       if( !dlg || !key || key->len <=0 || !uval) {
+               LM_ERR("BUG - bad parameters\n");
+               return -1;
+       }
+
+       dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
+       var = get_dlg_variable_unsafe(dlg, key);
+       if(var==NULL || var->s==NULL || var->len<=0) {
+               LM_DBG("no variable set yet\n");
+               goto error;
+       }
+       if(str2int(var, uval)<0) {
+               LM_ERR("invalid unsingned int value: %.*s\n",
+                               var->len, var->s);
+               goto error;
+       }
+       dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+       return 0;
+
+error:
+       dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+       return -1;
+}
+
 int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val)
 {
     int ret = -1;
-    if( !dlg || !key || key->len > strlen(key->s) || (val && val->len > strlen(val->s)))
+    if( !dlg || !key || !key->s || key->len<=0 )
     {
         LM_ERR("BUG - bad parameters\n");
         return -1;
@@ -326,6 +400,18 @@ done:
     return ret;
 }
 
+int set_dlg_variable_uintval(struct dlg_cell *dlg, str *key, unsigned int uval)
+{
+       str sval = STR_NULL;
+
+       sval.s = int2str(uval, &sval.len);
+       if(sval.s==NULL) {
+               return -1;
+       }
+
+       return set_dlg_variable(dlg, key, &sval);
+}
+
 int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 {
        dlg_cell_t *dlg;
index f13fa45..0506099 100644 (file)
@@ -25,7 +25,7 @@
  * \ingroup dialog
  * Module: \ref dialog
  */
-                      
+
 #ifndef _DLG_VAR_H_
 #define _DLG_VAR_H_
 
@@ -59,9 +59,13 @@ typedef struct dlg_var {
        struct dlg_var *next;
 } dlg_var_t;
 
-str* get_dlg_variable(dlg_cell_t *dlg, str *key);
+str* get_dlg_varref(dlg_cell_t *dlg, str *key);
+int get_dlg_varval(dlg_cell_t *dlg, str *key, str *val);
 int set_dlg_variable(dlg_cell_t *dlg, str *key, str *val);
 
+int get_dlg_variable_uintval(struct dlg_cell *dlg, str *key, unsigned int *uval);
+int set_dlg_variable_uintval(struct dlg_cell *dlg, str *key, unsigned int uval);
+
 int pv_parse_dialog_var_name(pv_spec_p sp, str *in);
 
 int pv_get_dlg_variable(sip_msg_t *msg, pv_param_t *param, pv_value_t *res);
index 00c1d4f..162ad96 100644 (file)
@@ -1707,6 +1707,32 @@ modparam("dialog", "bye_early_reason", "Call terminated")
                </example>
        </section>
 
+       <section id="dialog.p.dlg_ctxiuid_mode">
+               <title><varname>dlg_ctxiuid_mode</varname> (int)</title>
+               <para>
+                       Set dialog context iuid mode, which can specify additional cases
+                       when the internal unique id should be set:
+               </para>
+               <itemizedlist>
+                       <listitem><para>
+                               <emphasis>1</emphasis> - set it when processing CANCEL requests.
+                       </para></listitem>
+               </itemizedlist>
+               <para>
+               <emphasis>
+                       Default value is <quote>0</quote>.
+               </emphasis>
+               </para>
+               <example>
+               <title>Set <varname>dlg_ctxiuid_mode</varname> parameter</title>
+               <programlisting format="linespecific">
+...
+modparam("dialog", "dlg_ctxiuid_mode", 1)
+...
+</programlisting>
+               </example>
+       </section>
+
        </section>
 
        <section>
index 7770679..fb57faa 100644 (file)
@@ -61,8 +61,6 @@
 
 MODULE_VERSION
 
-#define DEFAULT_PARAM    "$rU"
-
 static int mod_init(void);
 static int child_init(int rank);
 static void mod_destroy();
@@ -75,14 +73,18 @@ static int dp_reload_f(struct sip_msg* msg);
 static int w_dp_replace(sip_msg_t* msg, char* pid, char* psrc, char* pdst);
 static int w_dp_match(sip_msg_t* msg, char* pid, char* psrc);
 
+static int ki_dp_translate(sip_msg_t* msg, int id, str *input, str *output);
+static int ki_dp_translate_id(sip_msg_t* msg, int id);
+static int ki_dp_translate_vars(sip_msg_t* msg, int id, str *input, str *output);
+
 int dp_replace_fixup(void** param, int param_no);
 int dp_replace_fixup_free(void** param, int param_no);
 
-str attr_pvar_s = STR_NULL;
-pv_spec_t *attr_pvar = NULL;
+str dp_attr_pvar_s = STR_NULL;
+pv_spec_t *dp_attr_pvar = NULL;
 
-str default_param_s = str_init(DEFAULT_PARAM);
-dp_param_p default_par2 = NULL;
+str dp_default_param_s = str_init("$rU");
+dp_param_p dp_default_par2 = NULL;
 
 int dp_fetch_rows = 1000;
 int dp_match_dynamic = 0;
@@ -102,7 +104,7 @@ static param_export_t mod_params[]={
        { "subst_exp_col",      PARAM_STR,      &subst_exp_column },
        { "repl_exp_col",       PARAM_STR,      &repl_exp_column },
        { "attrs_col",          PARAM_STR,      &attrs_column },
-       { "attrs_pvar",     PARAM_STR,  &attr_pvar_s },
+       { "attrs_pvar",     PARAM_STR,  &dp_attr_pvar_s },
        { "fetch_rows",         PARAM_INT,      &dp_fetch_rows },
        { "match_dynamic",      PARAM_INT,      &dp_match_dynamic },
        { "append_branch",      PARAM_INT,      &dp_append_branch },
@@ -148,35 +150,35 @@ static int mod_init(void)
 
        LM_DBG("db_url=%s/%d/%p\n", ZSW(dp_db_url.s), dp_db_url.len,dp_db_url.s);
 
-       if(attr_pvar_s.s && attr_pvar_s.len>0) {
-               attr_pvar = pv_cache_get(&attr_pvar_s);
-               if( (attr_pvar==NULL) ||
-                               ((attr_pvar->type != PVT_AVP) &&
-                                (attr_pvar->type != PVT_XAVP) &&
-                                (attr_pvar->type!=PVT_SCRIPTVAR))) {
+       if(dp_attr_pvar_s.s && dp_attr_pvar_s.len>0) {
+               dp_attr_pvar = pv_cache_get(&dp_attr_pvar_s);
+               if( (dp_attr_pvar==NULL) ||
+                               ((dp_attr_pvar->type != PVT_AVP) &&
+                                (dp_attr_pvar->type != PVT_XAVP) &&
+                                (dp_attr_pvar->type != PVT_SCRIPTVAR))) {
                        LM_ERR("invalid pvar name\n");
                        return -1;
                }
        }
 
-       default_par2 = (dp_param_p)shm_malloc(sizeof(dp_param_t));
-       if(default_par2 == NULL){
+       dp_default_par2 = (dp_param_p)shm_malloc(sizeof(dp_param_t));
+       if(dp_default_par2 == NULL){
                LM_ERR("no shm more memory\n");
                return -1;
        }
-       memset(default_par2, 0, sizeof(dp_param_t));
+       memset(dp_default_par2, 0, sizeof(dp_param_t));
 
        /* emulate "$rU/$rU" as second parameter for dp_translate() */
-       default_param_s.len = strlen(default_param_s.s);
-       default_par2->v.sp[0] = pv_cache_get(&default_param_s);
-       if (default_par2->v.sp[0]==NULL) {
+       dp_default_param_s.len = strlen(dp_default_param_s.s);
+       dp_default_par2->v.sp[0] = pv_cache_get(&dp_default_param_s);
+       if (dp_default_par2->v.sp[0]==NULL) {
                LM_ERR("input pv is invalid\n");
                return -1;
        }
 
-       default_param_s.len = strlen(default_param_s.s);
-       default_par2->v.sp[1] = pv_cache_get(&default_param_s);
-       if (default_par2->v.sp[1]==NULL) {
+       dp_default_param_s.len = strlen(dp_default_param_s.s);
+       dp_default_par2->v.sp[1] = pv_cache_get(&dp_default_param_s);
+       if (dp_default_par2->v.sp[1]==NULL) {
                LM_ERR("output pv is invalid\n");
                return -1;
        }
@@ -212,9 +214,9 @@ static int child_init(int rank)
 static void mod_destroy(void)
 {
        /*destroy shared memory*/
-       if(default_par2){
-               shm_free(default_par2);
-               default_par2 = NULL;
+       if(dp_default_par2){
+               shm_free(dp_default_par2);
+               dp_default_par2 = NULL;
        }
        if(dp_rpc_reload_time!=NULL) {
                shm_free(dp_rpc_reload_time);
@@ -304,11 +306,11 @@ static int dp_update(struct sip_msg * msg, pv_spec_t * dest,
 
 set_attr_pvar:
 
-       if(attr_pvar==NULL || attrs==NULL)
+       if(dp_attr_pvar==NULL || attrs==NULL)
                return 0;
 
        val.rs = *attrs;
-       if(attr_pvar->setf(msg, &attr_pvar->pvp, (int)EQ_T, &val)<0)
+       if(dp_attr_pvar->setf(msg, &dp_attr_pvar->pvp, (int)EQ_T, &val)<0)
        {
                LM_ERR("setting attr pseudo-variable failed\n");
                return -1;
@@ -341,7 +343,7 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2)
                return -2;
        }
 
-       repl_par = (str2!=NULL)? ((dp_param_p)str2):default_par2;
+       repl_par = (str2!=NULL)? ((dp_param_p)str2):dp_default_par2;
        if (dp_get_svalue(msg, repl_par->v.sp[0], &input)!=0){
                LM_ERR("invalid param 2\n");
                return -1;
@@ -349,7 +351,7 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2)
 
        LM_DBG("input is %.*s\n", input.len, input.s);
 
-       outattrs = (!attr_pvar)?NULL:&attrs;
+       outattrs = (!dp_attr_pvar)?NULL:&attrs;
        if (dp_translate_helper(msg, &input, &output, idp, outattrs)!=0) {
                LM_DBG("could not translate %.*s "
                                "with dpid %i\n", input.len, input.s, idp->dp_id);
@@ -491,7 +493,7 @@ static int dp_replace_helper(sip_msg_t *msg, int dpid, str *input,
                return -2;
        }
 
-       outattrs = (!attr_pvar)?NULL:&attrs;
+       outattrs = (!dp_attr_pvar)?NULL:&attrs;
        output = (!pvd)?NULL:&tmp;
        if (dp_translate_helper(msg, input, output, idp, outattrs)!=0) {
                LM_DBG("could not translate %.*s "
@@ -846,11 +848,97 @@ static sr_kemi_t sr_kemi_dialplan_exports[] = {
                { SR_KEMIP_INT, SR_KEMIP_STR, SR_KEMIP_STR,
                        SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
        },
+       { str_init("dialplan"), str_init("dp_translate"),
+               SR_KEMIP_INT, ki_dp_translate_id,
+               { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
+                       SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+       },
+       { str_init("dialplan"), str_init("dp_translate_vars"),
+               SR_KEMIP_INT, ki_dp_translate_vars,
+               { SR_KEMIP_INT, SR_KEMIP_STR, SR_KEMIP_STR,
+                       SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+       },
 
        { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
 };
 /* clang-format on */
 
+static int ki_dp_translate(sip_msg_t* msg, int id, str *input_spv, str *output_spv) {
+       str input, output;
+       dpl_id_p idp;
+       str attrs, *outattrs;
+       pv_spec_t *pvs_i = NULL, *pvs_o = NULL;
+
+       if (!msg)
+               return -1;
+
+       if (input_spv == NULL || input_spv->s == NULL || input_spv->len <= 0 ||
+           output_spv == NULL || output_spv->s == NULL || output_spv->len <= 0) {
+               LM_ERR("invalid destination var name for input or output\n");
+               return -1;
+       }
+
+       if (input_spv == NULL && output_spv == NULL) {
+               pvs_i = pv_cache_get(&dp_default_param_s);
+               pvs_o = pv_cache_get(&dp_default_param_s);
+       } else {
+               pvs_i = pv_cache_get(input_spv);
+               pvs_o = pv_cache_get(output_spv);
+       }
+
+       if (pvs_i == NULL || pvs_o == NULL) {
+               LM_ERR("cannot get pv spec for input or output\n");
+               return -1;
+       }
+
+       if ((pvs_i->type!=PVT_AVP && pvs_i->type!=PVT_XAVP && pvs_i->type!=PVT_SCRIPTVAR &&
+           pvs_i->type!=PVT_RURI && pvs_i->type!=PVT_RURI_USERNAME) ||
+           (pvs_o->type!=PVT_AVP && pvs_o->type!=PVT_XAVP && pvs_o->type!=PVT_SCRIPTVAR &&
+           pvs_o->type!=PVT_RURI && pvs_o->type!=PVT_RURI_USERNAME)) {
+               LM_ERR("type of pv error\n");
+               return -1;
+       }
+
+       if ((idp = select_dpid(id)) ==0 ){
+               LM_DBG("no information available for dpid %i\n", id);
+               return -2;
+       }
+
+       /* get the input */
+       if (dp_get_svalue(msg, pvs_i, &input)!=0){
+               LM_ERR("invalid param 2\n");
+               return -1;
+       }
+
+       LM_DBG("input is %.*s\n", input.len, input.s);
+
+       outattrs = (!dp_attr_pvar)?NULL:&attrs;
+       if (dp_translate_helper(msg, &input, &output, idp, outattrs)!=0) {
+               LM_DBG("could not translate %.*s "
+                               "with dpid %i\n", input.len, input.s, idp->dp_id);
+               return -1;
+       }
+       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, pvs_o, &output, outattrs) !=0){
+               LM_ERR("cannot set the output\n");
+               return -1;
+       }
+
+       return 1;
+
+}
+
+static int ki_dp_translate_id(sip_msg_t* msg, int id) {
+       return ki_dp_translate(msg, id, NULL, NULL);
+}
+
+static int ki_dp_translate_vars(sip_msg_t* msg, int id, str *input, str *output) {
+       return ki_dp_translate(msg, id, input, output);
+}
+
 /**
  *
  */
index 7d81853..8f06f6f 100644 (file)
@@ -2112,16 +2112,20 @@ int ds_select_dst_limit(sip_msg_t *msg, int set, int alg, uint32_t limit,
 typedef struct sorted_ds {
        int idx;
        int priority;
+       int flags;
+       ds_dest_t *dest;
 } sorted_ds_t;
 
-int ds_manage_routes_fill_reodered_xavp(sorted_ds_t *ds_sorted, ds_set_t *idx, ds_select_state_t *rstate)
+int ds_manage_routes_fill_reordered_xavp(sorted_ds_t *ds_sorted, ds_set_t *idx, ds_select_state_t *rstate)
 {
        int i;
        if(!(ds_flags & DS_FAILOVER_ON))
                return 1;
        for(i=0; i < idx->nr && rstate->cnt < rstate->limit; i++) {
-               if(ds_sorted[i].idx < 0 || ds_skip_dst(idx->dlist[i].flags)
-                               || (ds_use_default != 0 && ds_sorted[i].idx == (idx->nr - 1))) {
+
+               if(ds_sorted[i].idx < 0 || ds_skip_dst(ds_sorted[i].flags) || (ds_use_default != 0 && ds_sorted[i].idx == (idx->nr - 1))) {
+                       LM_DBG("[%d|%.*s|idx:%d]skipped %d || %d\n", i, ds_sorted[i].dest->uri.len, ds_sorted[i].dest->uri.s, ds_sorted[i].idx,
+                               ds_sorted[i].idx < 0, ds_skip_dst(ds_sorted[i].flags));
                        continue;
                }
                if(ds_add_xavp_record(idx, ds_sorted[i].idx, rstate->setid, rstate->alg,
@@ -2199,16 +2203,23 @@ int ds_manage_routes_fill_xavp(unsigned int hash, ds_set_t *idx, ds_select_state
 
 void ds_sorted_by_priority(sorted_ds_t * sorted_ds, int size) {
        int i,ii;
+
        for(i=0;i<size;++i) {
                for(ii=1;ii<size;++ii) {
                        sorted_ds_t temp;
                        if(sorted_ds[ii-1].priority < sorted_ds[ii].priority) {
                                temp.idx = sorted_ds[ii].idx;
                                temp.priority = sorted_ds[ii].priority;
+                               temp.flags = sorted_ds[ii].flags;
+                               temp.dest = sorted_ds[ii].dest;
                                sorted_ds[ii].idx = sorted_ds[ii-1].idx;
                                sorted_ds[ii].priority = sorted_ds[ii-1].priority;
+                               sorted_ds[ii].flags = sorted_ds[ii-1].flags;
+                               sorted_ds[ii].dest = sorted_ds[ii-1].dest;
                                sorted_ds[ii-1].idx = temp.idx;
                                sorted_ds[ii-1].priority = temp.priority;
+                               sorted_ds[ii-1].flags = temp.flags;
+                               sorted_ds[ii-1].dest = temp.dest;
                        }
                }
        }
@@ -2232,7 +2243,7 @@ int ds_manage_route_algo13(ds_set_t *idx, ds_select_state_t *rstate) {
                int gw_latency = ds_dest->latency_stats.estimate;
                int gw_inactive = ds_skip_dst(ds_dest->flags);
                // if cc is enabled, the latency is the congestion ms instead of the estimated latency.
-               if (ds_dest->attrs.congestion_control)
+               if(ds_dest->attrs.congestion_control)
                        gw_latency = ds_dest->latency_stats.estimate - ds_dest->latency_stats.average;
                if(!gw_inactive) {
                        if(gw_latency > gw_priority && gw_priority > 0)
@@ -2242,17 +2253,20 @@ int ds_manage_route_algo13(ds_set_t *idx, ds_select_state_t *rstate) {
                                ds_dest->attrs.rpriority = 1;
                        ds_sorted[y].idx = z;
                        ds_sorted[y].priority = ds_dest->attrs.rpriority;
-                       LM_DBG("[active]idx[%d]uri[%.*s]priority[%d-%d=%d]latency[%dms]flag[%d]\n",
-                               z, ds_dest->uri.len, ds_dest->uri.s,
+                       LM_DBG("[active][%d]idx[%d]uri[%.*s]priority[%d-%d=%d]latency[%dms]flag[%d]\n",
+                               y,z, ds_dest->uri.len, ds_dest->uri.s,
                                gw_priority, latency_priority_handicap,
                                ds_dest->attrs.rpriority, gw_latency, ds_dest->flags);
                } else {
                        ds_sorted[y].idx = -1;
                        ds_sorted[y].priority = -1;
-                       LM_DBG("[inactive]idx[%d]uri[%.*s]priority[%d]latency[%dms]flag[%d]",
-                               z, ds_dest->uri.len, ds_dest->uri.s,
+                       LM_DBG("[inactive][%d]idx[%d]uri[%.*s]priority[%d]latency[%dms]flag[%d]\n",
+                               y,-1, ds_dest->uri.len, ds_dest->uri.s,
                                gw_priority, gw_latency, ds_dest->flags);
                }
+               ds_sorted[y].flags = ds_dest->flags;
+               ds_sorted[y].dest = ds_dest;
+
                if(ds_use_default != 0 && idx->nr != 1)
                        z = (z + 1) % (idx->nr - 1);
                else
@@ -2264,7 +2278,7 @@ int ds_manage_route_algo13(ds_set_t *idx, ds_select_state_t *rstate) {
                hash = ds_sorted[0].idx;
                active_priority = ds_sorted[0].priority;
        }
-       ds_manage_routes_fill_reodered_xavp(ds_sorted, idx, rstate);
+       ds_manage_routes_fill_reordered_xavp(ds_sorted, idx, rstate);
        idx->last = (hash + 1) % idx->nr;
        LM_DBG("priority[%d]gateway_selected[%d]next_index[%d]\n", active_priority, hash, idx->last);
        pkg_free(ds_sorted);
index 1e7d6ff..b79a6c2 100644 (file)
@@ -28,6 +28,9 @@ Charles Chance
    1. Admin Guide
 
         1. Overview
+
+              1.1. KDMQ Request
+
         2. Dependencies
 
               2.1. Kamailio Modules
@@ -99,6 +102,9 @@ Chapter 1. Admin Guide
    Table of Contents
 
    1. Overview
+
+        1.1. KDMQ Request
+
    2. Dependencies
 
         2.1. Kamailio Modules
@@ -131,6 +137,8 @@ Chapter 1. Admin Guide
 
 1. Overview
 
+   1.1. KDMQ Request
+
    The DMQ module implements a distributed message queue on top of
    Kamailio in order to facilitate data propagation and replication
    between multiple instances, referred as "nodes" (or "peers").
@@ -161,11 +169,21 @@ Chapter 1. Admin Guide
    the from local list of active nodes, no longer being considered to be
    part of the KDMQ cluster.
 
-   Example 1.1. KDMQ Request Example
+   IMPORTANT: DMQ must be used only between Kamailio instances having same
+   major version. Internal structures can be incompatible between
+   different major versions and can lead to crashes or unexpected
+   behaviour.
+
+1.1. KDMQ Request
+
+   KDMQ messages can have different format and content for R-URI username,
+   headers and body, being specific to each component that leverages DMQ
+   to replicate data, such as htable, dialog or usrloc modules.
 
-   This request is generated for DMQ peers availability notifications.
-   Other messages can be produced by various modules, with different R-URI
-   username and body content, such as htable, dialog or usrloc modules.
+   Next request is generated by DMQ module for peers availability
+   notifications.
+
+   Example 1.1. KDMQ Request Example
 ...
 
 KDMQ sip:notification_peer@192.168.40.15:5090 SIP/2.0
index 661fd4b..d463fac 100644 (file)
        Nodes that are not responding to KDMQ reguests are removed the from local
        list of active nodes, no longer being considered to be part of the KDMQ cluster.
        </para>
-       <example>
-               <title>KDMQ Request Example</title>
+       <para>
+       IMPORTANT: DMQ must be used only between Kamailio instances having same
+       major version. Internal structures can be incompatible between different
+       major versions and can lead to crashes or unexpected behaviour.
+       </para>
+       <section>
+               <title>KDMQ Request</title>
                <para>
-               This request is generated for DMQ peers availability notifications.
-               Other messages can be produced by various modules, with different R-URI
-               username and body content, such as <emphasis>htable</emphasis>,
-               <emphasis>dialog</emphasis> or <emphasis>usrloc</emphasis> modules.
+               KDMQ messages can have different format and content for R-URI username, headers
+               and body, being specific to each component that leverages DMQ to replicate
+               data, such as <emphasis>htable</emphasis>, <emphasis>dialog</emphasis>
+               or <emphasis>usrloc</emphasis> modules.
                </para>
-                <programlisting format="linespecific">
+               <para>
+               Next request is generated by DMQ module for peers availability notifications.
+               </para>
+       <example>
+               <title>KDMQ Request Example</title>
+            <programlisting format="linespecific">
 ...
 
 KDMQ sip:notification_peer@192.168.40.15:5090 SIP/2.0
@@ -77,6 +87,7 @@ sip:192.168.40.17:5060;status=active
 </programlisting>
     </example>
        </section>
+       </section>
 
        <section>
        <title>Dependencies</title>
index 728c3c5..0d6457d 100644 (file)
@@ -681,7 +681,7 @@ int usrloc_dmq_send_multi_contact(ucontact_t* ptr, str aor, int action, dmq_node
        jdoc_contact_group.size += ptr->c.len;
        srjson_AddStrToObject(jdoc, jdoc_contact, "received", ptr->received.s, ptr->received.len);
        jdoc_contact_group.size += ptr->received.len;
-       if (_dmq_usrloc_replicate_socket_info==1) {
+       if (_dmq_usrloc_replicate_socket_info==1 && ptr->sock!=NULL && ptr->sock->sock_str.s!=NULL) {
                srjson_AddStrToObject(jdoc, jdoc_contact, "sock", ptr->sock->sock_str.s, ptr->sock->sock_str.len);
                jdoc_contact_group.size += ptr->sock->sock_str.len;
        }
@@ -709,8 +709,8 @@ int usrloc_dmq_send_multi_contact(ucontact_t* ptr, str aor, int action, dmq_node
        jdoc_contact_group.size += snprintf(NULL,0,"%u", ptr->methods);
        srjson_AddNumberToObject(jdoc, jdoc_contact, "reg_id", ptr->reg_id);
        jdoc_contact_group.size += snprintf(NULL,0,"%d", ptr->reg_id);
-        srjson_AddNumberToObject(jdoc, jdoc_contact, "server_id", ptr->server_id);
-        jdoc_contact_group.size += snprintf(NULL,0,"%d", ptr->server_id);
+       srjson_AddNumberToObject(jdoc, jdoc_contact, "server_id", ptr->server_id);
+       jdoc_contact_group.size += snprintf(NULL,0,"%d", ptr->server_id);
 
        char idx[5];
        jdoc_contact_group.count++;
index 25e3285..dd73bec 100644 (file)
@@ -86,7 +86,14 @@ static const char* rpc_mod_mem_statsx_doc[2] = {
 
 /* test if the current mod info was already printed */
 static int rpc_mod_is_printed_one(mem_counter *stats, mem_counter *current) {
-       mem_counter *iter = stats;
+       mem_counter *iter;
+
+       if ( stats == NULL || current == NULL )
+       {
+               LM_ERR("invalid parameter\n");
+               return 1;
+       }
+       iter = stats;
 
        while (iter && iter != current) {
                if (strcmp(iter->mname, current->mname) == 0) {
index 035f807..e7583ad 100644 (file)
@@ -214,6 +214,9 @@ pos_insert("100", "10");
 
    Set the char at position index to first character in val.
 
+   Important: it changes the character directly in the SIP message buffer,
+   the update being immediately visible.
+
    The idx can be an integer value or a variable holding an integer. If
    the value is negative, the position is counted from the end of the
    buffer.
index 1a38b85..e47d658 100644 (file)
@@ -168,6 +168,10 @@ pos_insert("100", "10");
                        Set the char at position index to first character in val.
                        </para>
                        <para>
+                       Important: it changes the character directly in the SIP message
+                       buffer, the update being immediately visible.
+                       </para>
+                       <para>
                        The idx can be an integer value or a variable holding an integer. If
                        the value is negative, the position is counted from the end of the buffer.
                        </para>
index f9e4b02..50a1029 100644 (file)
@@ -315,11 +315,13 @@ void refresh_pubruri_avps(struct dlginfo_cell *dlginfo, str *uri)
 }
 
 void refresh_local_identity(struct dlg_cell *dlg, str *uri) {
-       str *s = dlg_api.get_dlg_var(dlg, &local_identity_dlg_var);
+       str s = {0};
 
-       if(s != NULL) {
-               uri->s = s->s;
-               uri->len = s->len;
+       dlg_api.get_dlg_varval(dlg, &local_identity_dlg_var, &s);
+
+       if(s.s != NULL) {
+               uri->s = s.s;
+               uri->len = s.len;
                LM_DBG("Found local_identity in dialog '%.*s'\n",
                                uri->len, uri->s);
        }
@@ -364,7 +366,8 @@ __dialog_sendpublish(struct dlg_cell *dlg, int type, struct dlg_cb_params *_para
        }
 
        if(use_pubruri_avps && (refresh_pubruri_avps_flag > -1
-               || (request->flags & (1U<<(unsigned int)refresh_pubruri_avps_flag))))
+               || (request
+                       && (request->flags & (1U<<(unsigned int)refresh_pubruri_avps_flag)))))
        {
                lock_get(&dlginfo->lock);
                refresh_pubruri_avps(dlginfo, &uri);
@@ -575,7 +578,7 @@ struct dlginfo_cell* get_dialog_data(struct dlg_cell *dlg, int type, int disable
 {
        struct dlginfo_cell *dlginfo;
        int len;
-       str* s=NULL;
+       str dval = {0};
 
        // generate new random uuid
        if(sruid_next_safe(&_puadi_sruid) < 0) {
@@ -651,31 +654,41 @@ struct dlginfo_cell* get_dialog_data(struct dlg_cell *dlg, int type, int disable
 
                } else {
                        if(caller_dlg_var.len>0
-                                       && (s = dlg_api.get_dlg_var(dlg, &caller_dlg_var))!=0) {
+                                       && (dlg_api.get_dlg_varval(dlg, &caller_dlg_var, &dval)==0)
+                                       && dval.s!=NULL) {
                                dlginfo->pubruris_caller =
-                                       (struct str_list*)shm_malloc( sizeof(struct str_list) );
+                                       (struct str_list*)shm_malloc(sizeof(struct str_list) + dval.len + 1);
                                if (dlginfo->pubruris_caller==0) {
                                        SHM_MEM_ERROR;
                                        free_dlginfo_cell(dlginfo);
                                        return NULL;
                                }
-                               memset( dlginfo->pubruris_caller, 0, sizeof(struct str_list));
-                               dlginfo->pubruris_caller->s=*s;
+                               memset(dlginfo->pubruris_caller, 0, sizeof(struct str_list));
+                               dlginfo->pubruris_caller->s.s = (char*)dlginfo->pubruris_caller
+                                       + sizeof(sizeof(struct str_list));
+                               memcpy(dlginfo->pubruris_caller->s.s, dval.s, dval.len);
+                               dlginfo->pubruris_caller->s.s[dval.len] = '\0';
+                               dlginfo->pubruris_caller->s.len = dval.len;
                                LM_DBG("Found pubruris_caller in dialog '%.*s'\n",
                                                dlginfo->pubruris_caller->s.len, dlginfo->pubruris_caller->s.s);
                        }
 
                        if(callee_dlg_var.len>0
-                                       && (s = dlg_api.get_dlg_var(dlg, &callee_dlg_var))!=0) {
+                                       && (dlg_api.get_dlg_varval(dlg, &callee_dlg_var, &dval)==0)
+                                       && dval.s!=NULL) {
                                dlginfo->pubruris_callee =
-                                       (struct str_list*)shm_malloc( sizeof(struct str_list) );
+                                       (struct str_list*)shm_malloc(sizeof(struct str_list) + dval.len + 1);
                                if (dlginfo->pubruris_callee==0) {
                                        SHM_MEM_ERROR;
                                        free_dlginfo_cell(dlginfo);
                                        return NULL;
                                }
-                               memset( dlginfo->pubruris_callee, 0, sizeof(struct str_list));
-                               dlginfo->pubruris_callee->s=*s;
+                               memset(dlginfo->pubruris_callee, 0, sizeof(struct str_list));
+                               dlginfo->pubruris_callee->s.s = (char*)dlginfo->pubruris_callee
+                                       + sizeof(sizeof(struct str_list));
+                               memcpy(dlginfo->pubruris_callee->s.s, dval.s, dval.len);
+                               dlginfo->pubruris_callee->s.s[dval.len] = '\0';
+                               dlginfo->pubruris_callee->s.len = dval.len;
                                LM_DBG("Found pubruris_callee in dialog '%.*s'\n",
                                                dlginfo->pubruris_callee->s.len, dlginfo->pubruris_callee->s.s);
                        }
index 28bc21c..4a1f805 100644 (file)
@@ -694,8 +694,11 @@ xavi_child_rm("WhatEver", "FoO");
    at the index idx becomes the first and the ones before it are at the
    end of the list.
 
-   The first parameter has to be the name of XAVP in the root list. The
-   second parameter is the index of the XAVP that becomes the first one.
+   The first parameter has to be the name of XAVP in the root list.
+
+   The second parameter is the index of the XAVP that becomes the first
+   one (if it is greater than the number of XAVPs, modulo operation is
+   done first; if it is negative, it counts from the end of the list).
 
    The parameters can be with variables.
 
index 409ecaa..30b09ea 100644 (file)
@@ -747,8 +747,12 @@ xavi_child_rm("WhatEver", "FoO");
                        </para>
                        <para>
                                The first parameter has to be the name of XAVP in the root list.
+                       </para>
+                       <para>
                                The second parameter is the index of the XAVP that becomes the
-                               first one.
+                               first one (if it is greater than the number of XAVPs, modulo
+                               operation is done first; if it is negative, it counts from the
+                               end of the list).
                        </para>
                        <para>
                                The parameters can be with variables.
index afccbd4..ab5bdc4 100644 (file)
@@ -2128,6 +2128,7 @@ int pv_get_hdr(sip_msg_t *msg,  pv_param_t *param, pv_value_t *res)
        int idx;
        int idxf;
        pv_value_t tv = {0};
+       hdr_field_t thdr = {0};
 
        if(msg==NULL || res==NULL || param==NULL)
                return -1;
@@ -2138,6 +2139,15 @@ int pv_get_hdr(sip_msg_t *msg,  pv_param_t *param, pv_value_t *res)
                        LM_ERR("invalid name\n");
                        return -1;
                }
+               parse_hname2_short(tv.rs.s, tv.rs.s + tv.rs.len, &thdr);
+               if(thdr.type==HDR_ERROR_T) {
+                       LM_ERR("error parsing header name [%.*s]\n", tv.rs.len, tv.rs.s);
+                       return pv_get_null(msg, param, res);
+               }
+               if(thdr.type!=HDR_OTHER_T) {
+                       tv.flags = 0;
+                       tv.ri = thdr.type;
+               }
        } else {
                if(param->pvn.u.isname.type == AVP_NAME_STR) {
                        tv.flags = PV_VAL_STR;
@@ -2162,6 +2172,7 @@ int pv_get_hdrc(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
 {
        pv_value_t tv;
        struct hdr_field *hf;
+       hdr_field_t thdr = {0};
        int hcount;
 
        if(msg==NULL || res==NULL || param==NULL)
@@ -2177,6 +2188,15 @@ int pv_get_hdrc(struct sip_msg *msg,  pv_param_t *param, pv_value_t *res)
                        LM_ERR("invalid name\n");
                        return pv_get_sintval(msg, param, res, hcount);
                }
+               parse_hname2_short(tv.rs.s, tv.rs.s + tv.rs.len, &thdr);
+               if(thdr.type==HDR_ERROR_T) {
+                       LM_ERR("error parsing header name [%.*s]\n", tv.rs.len, tv.rs.s);
+                       return pv_get_sintval(msg, param, res, 0);
+               }
+               if(thdr.type!=HDR_OTHER_T) {
+                       tv.flags = 0;
+                       tv.ri = thdr.type;
+               }
        } else {
                if(param->pvn.u.isname.type == AVP_NAME_STR)
                {
@@ -2223,6 +2243,7 @@ int pv_get_hfl(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
        rr_t *rrb = NULL;
        contact_t *cb = NULL;
        hdr_field_t *hf = NULL;
+       hdr_field_t thdr = {0};
        int n = 0;
        str sval = STR_NULL;
 
@@ -2235,6 +2256,15 @@ int pv_get_hfl(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
                        LM_ERR("invalid name\n");
                        return -1;
                }
+               parse_hname2_short(tv.rs.s, tv.rs.s + tv.rs.len, &thdr);
+               if(thdr.type==HDR_ERROR_T) {
+                       LM_ERR("error parsing header name [%.*s]\n", tv.rs.len, tv.rs.s);
+                       return pv_get_null(msg, param, res);
+               }
+               if(thdr.type!=HDR_OTHER_T) {
+                       tv.flags = 0;
+                       tv.ri = thdr.type;
+               }
        } else {
                if(param->pvn.u.isname.type == AVP_NAME_STR) {
                        tv.flags = PV_VAL_STR;
@@ -2458,6 +2488,7 @@ int pv_get_hflc(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
        rr_t *rrb = NULL;
        contact_t *cb = NULL;
        hdr_field_t *hf = NULL;
+       hdr_field_t thdr = {0};
        int n = 0;
 
        if(msg==NULL || res==NULL || param==NULL)
@@ -2469,6 +2500,15 @@ int pv_get_hflc(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
                        LM_ERR("invalid name\n");
                        return pv_get_sintval(msg, param, res, 0);
                }
+               parse_hname2_short(tv.rs.s, tv.rs.s + tv.rs.len, &thdr);
+               if(thdr.type==HDR_ERROR_T) {
+                       LM_ERR("error parsing header name [%.*s]\n", tv.rs.len, tv.rs.s);
+                       return pv_get_sintval(msg, param, res, 0);
+               }
+               if(thdr.type!=HDR_OTHER_T) {
+                       tv.flags = 0;
+                       tv.ri = thdr.type;
+               }
        } else {
                if(param->pvn.u.isname.type == AVP_NAME_STR) {
                        tv.flags = PV_VAL_STR;
index 4a9cc14..a05134f 100644 (file)
@@ -23,6 +23,8 @@
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <time.h>
 #include <sys/time.h>
 
 #include "pv_time.h"
 
+#if defined(CLOCK_MONOTONIC_RAW)
+#define PV_MONOTONIC_CLOCK CLOCK_MONOTONIC_RAW
+#else
+#define PV_MONOTONIC_CLOCK CLOCK_MONOTONIC
+#endif
+
 int pv_parse_time_name(pv_spec_p sp, str *in)
 {
        if(sp==NULL || in==NULL || in->len<=0)
@@ -306,6 +314,7 @@ int pv_get_timeval(struct sip_msg *msg, pv_param_t *param,
                pv_value_t *res)
 {
        struct timeval tv;
+       struct timespec ts;
        str s;
        struct tm lt;
        char lbuf[64];
@@ -355,7 +364,18 @@ int pv_get_timeval(struct sip_msg *msg, pv_param_t *param,
                                return pv_get_null(msg, param, res);
                        s.s = _timeval_ts_buf;
                        return pv_get_strval(msg, param, res, &s);
-
+               case 6:
+                       if (!clock_gettime(PV_MONOTONIC_CLOCK, &ts)) {
+                               s.len = snprintf(_timeval_ts_buf, 64, "%" PRIu64,
+                                       (u_int64_t)ts.tv_sec * 1000000000 + (u_int64_t)ts.tv_nsec);
+                               if(s.len<0)
+                                       return pv_get_null(msg, param, res);
+                               s.s = _timeval_ts_buf;
+                               return pv_get_strval(msg, param, res, &s);
+                       } else {
+                               LM_ERR("unable to get monotonic clock value\n");
+                               return pv_get_null(msg, param, res);
+                       }
                default:
                        msg_set_time(msg);
                        return pv_get_uintval(msg, param, res, (unsigned int)msg->tval.tv_sec);
@@ -385,6 +405,8 @@ int pv_parse_timeval_name(pv_spec_p sp, str *in)
                                sp->pvp.pvn.u.isname.name.n = 4;
                        else if(strncmp(in->s, "Fn", 2)==0)
                                sp->pvp.pvn.u.isname.name.n = 5;
+                       else if(strncmp(in->s, "Sm", 2)==0)
+                               sp->pvp.pvn.u.isname.name.n = 6;
                        else goto error;
                break;
                default:
index e555e02..b900ae5 100644 (file)
@@ -526,6 +526,7 @@ int handle_msg_branch_cb(struct sip_msg *msg, unsigned int flags, void *cb)
 
 int handle_msg_reply_cb(struct sip_msg *msg, unsigned int flags, void *cb)
 {
+       int vref = 0;
        tm_cell_t *t = NULL;
        sr_xavp_t **backup_xavis = NULL;
        sr_xavp_t **list = NULL;
@@ -534,18 +535,12 @@ int handle_msg_reply_cb(struct sip_msg *msg, unsigned int flags, void *cb)
                return 1;
        LM_DBG("msg:%p previous branch:%d\n", msg, _branch);
 
-       if(tmb.t_check(msg, &_branch) == -1) {
-               LM_ERR("failed find UAC branch\n");
-       } else {
-               t = tmb.t_gett();
-               if(t == NULL || t == T_UNDEFINED) {
-                       LM_DBG("cannot lookup the transaction\n");
-               } else {
-                       LM_DBG("T:%p t_check-branch:%d xavi_list:%p branches:%d\n", t,
-                                       _branch, &t->xavis_list, t->nr_of_outgoings);
-                       list = &t->xavis_list;
-                       backup_xavis = xavi_set_list(&t->xavis_list);
-               }
+       t = tmb.t_find(msg, &_branch, &vref);
+       if(t != NULL && t != T_UNDEFINED) {
+               LM_DBG("T:%p t_check-branch:%d xavi_list:%p branches:%d\n", t,
+                               _branch, &t->xavis_list, t->nr_of_outgoings);
+               list = &t->xavis_list;
+               backup_xavis = xavi_set_list(&t->xavis_list);
        }
 
        pvh_get_branch_index(msg, &_branch);
@@ -560,12 +555,12 @@ int handle_msg_reply_cb(struct sip_msg *msg, unsigned int flags, void *cb)
                xavi_set_list(backup_xavis);
                LM_DBG("restored backup_xavis:%p\n", *backup_xavis);
        }
-       if(t) {
-               tmb.unref_cell(t);
+       if(t != NULL && t != T_UNDEFINED && vref != 0) {
+               /*  t_find() above has the side effect of setting T and
+                       REFerencing T => we must unref and unset it */
+               tmb.t_unset();
                LM_DBG("T:%p unref\n", t);
        }
-       tmb.t_sett(T_UNDEFINED, T_BR_UNDEFINED);
-       LM_DBG("reset tm\n");
 
        return 1;
 }
index efecfaa..4973694 100644 (file)
@@ -42,6 +42,7 @@
 #include "../../core/data_lump_rpl.h"
 #include "../../core/counters.h"
 #include "../../core/rpc_lookup.h"
+#include "../../core/kemi.h"
 #include "rl_statistics.h"
 
 
@@ -199,6 +200,8 @@ static int w_rl_check_forced(struct sip_msg*, char *, char *);
 static int w_rl_check_forced_pipe(struct sip_msg*, char *, char *);
 static int add_queue_params(modparam_t, void *);
 static int add_pipe_params(modparam_t, void *);
+static int ki_rl_check(struct sip_msg *msg);
+static int ki_rl_check_pipe(struct sip_msg *msg, int pipe);
 /* RESERVED for future use
 static int set_load_source(modparam_t, void *);
 */
@@ -1323,3 +1326,33 @@ static rpc_export_t rpc_methods[] = {
        {0, 0, 0, 0}
 };
 
+static sr_kemi_t sr_kemi_ratelimit_exports[] = {
+        { str_init("ratelimit"), str_init("rl_check"),
+                SR_KEMIP_INT, ki_rl_check,
+                { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
+                        SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+        },
+        { str_init("ratelimit"), str_init("rl_check_pipe"),
+                SR_KEMIP_INT, ki_rl_check_pipe,
+                { SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
+                        SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+        },
+        { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
+
+};
+
+static int ki_rl_check(struct sip_msg *msg) {
+       return rl_check(msg, -1);
+}
+
+static int ki_rl_check_pipe(struct sip_msg *msg, int pipe) {
+
+       LM_DBG("trying kemi pipe %d\n", pipe);
+       return rl_check(msg, pipe);
+}
+
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
+        sr_kemi_modules_add(sr_kemi_ratelimit_exports);
+        return 0;
+}
index 4944f8a..fd1e71d 100644 (file)
@@ -2160,6 +2160,10 @@ rtpengine_offer();
           + SIP-source-address - the opposite of trust-address. Restores
             the old default behaviour of ignoring endpoint addresses in
             the SDP body.
+          + received-from=IP - Configure the SIP-source-address IP
+            explicitly, which will be useful when two kamailio is cascaded
+            where first kamailio is handling NAT and second kamailio
+            RTPEngine.
           + replace-origin - flags that IP from the origin description
             (o=) should be also changed.
           + replace-session-connection - flags to change the session-level
index 234fd1f..a91a580 100644 (file)
@@ -2423,6 +2423,11 @@ rtpengine_offer();
                                of ignoring endpoint addresses in the &sdp; body.
                                </para></listitem>
                                <listitem><para>
+                               <emphasis>received-from=IP</emphasis> - Configure the SIP-source-address IP 
+                               explicitly, which will be useful when two kamailio is cascaded where first kamailio
+                               is handling NAT and second kamailio RTPEngine.
+                               </para></listitem>
+                               <listitem><para>
                                <emphasis>replace-origin</emphasis> - flags that IP from the origin
                                description (o=) should be also changed.
                                </para></listitem>
index ab6920c..2a38636 100644 (file)
@@ -120,7 +120,7 @@ enum {
 struct ng_flags_parse {
        int via, to, packetize, transport, directional;
        bencode_item_t *dict, *flags, *direction, *replace, *rtcp_mux, *sdes,
-                      *t38,
+                      *t38,*received_from,
                       *codec, *codec_strip, *codec_offer, *codec_transcode, *codec_mask,
                       *codec_set, *codec_except;
        str call_id, from_tag, to_tag;
@@ -2241,8 +2241,8 @@ static int parse_flags(struct ng_flags_parse *ng_flags, struct sip_msg *msg, enu
 {
        char *e;
        const char *err;
-       str key, val, s;
-
+       str key, val, s , s1;
+       int ip_af = AF_UNSPEC;
        if (!flags_str)
                return 0;
 
@@ -2276,6 +2276,27 @@ static int parse_flags(struct ng_flags_parse *ng_flags, struct sip_msg *msg, enu
                        bencode_list_add_str(ng_flags->replace, &s);
                        goto next;
                }
+               if (str_key_val_prefix(&key, "received-from", &val, &s)) {
+                       ip_af = get_ip_type(s.s);
+                       if (ip_af == AF_INET)
+                       {
+                               s1.s="IP4";
+                               s1.len=3;
+                               bencode_list_add_str(ng_flags->received_from, &s1);
+                               bencode_list_add_str(ng_flags->received_from, &s);
+                       
+                       }else if (ip_af == AF_INET6)
+                       {
+                               s1.s="IP6";
+                               s1.len=3;
+                               bencode_list_add_str(ng_flags->received_from, &s1);
+                               bencode_list_add_str(ng_flags->received_from, &s);
+                       
+                       }
+                       
+                       
+                       goto next;
+               }
                if (str_key_val_prefix(&key, "SDES", &val, &s)) {
                        bencode_list_add_str(ng_flags->sdes, &s);
                        goto next;
@@ -2442,6 +2463,7 @@ static int parse_flags(struct ng_flags_parse *ng_flags, struct sip_msg *msg, enu
                                else if (str_eq(&key, "delete-delay") && val.s)
                                        bencode_dictionary_add_integer(ng_flags->dict, "delete delay", atoi(val.s));
                                break;
+                                               
 
                        case 16:
                                if (str_eq(&key, "UDP/TLS/RTP/SAVP") && !val.s)
@@ -2529,6 +2551,7 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_
 
        body.s = NULL;
        ng_flags.flags = bencode_list(bencbuf);
+       ng_flags.received_from = bencode_list(bencbuf);
 
        if (op == OP_OFFER || op == OP_ANSWER) {
                ng_flags.direction = bencode_list(bencbuf);
@@ -2649,13 +2672,18 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_
                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 (ng_flags.received_from && ng_flags.received_from->child) {
+               bencode_dictionary_add(ng_flags.dict, "received-from", ng_flags.received_from);
+       }
+       else {
+               //item = bencode_list(bencbuf);
+               bencode_dictionary_add(ng_flags.dict, "received-from", ng_flags.received_from);
+               bencode_list_add_string(ng_flags.received_from, (msg->rcv.src_ip.af == AF_INET) ? "IP4" : (
+                       (msg->rcv.src_ip.af == AF_INET6) ? "IP6" :
+                       "?"
+               ) );
+               bencode_list_add_string(ng_flags.received_from, ip_addr2a(&msg->rcv.src_ip));
+       }
 
        if (op == OP_BLOCK_DTMF || op == OP_BLOCK_MEDIA || op == OP_UNBLOCK_DTMF
                        || op == OP_UNBLOCK_MEDIA || op == OP_START_FORWARDING || op == OP_STOP_FORWARDING
index 77c7c86..8e871cc 100644 (file)
@@ -226,8 +226,9 @@ int ki_sipdump_send(sip_msg_t *msg, str *stag)
        isd.tag = *stag;
        isd.protoid = msg->rcv.proto;
        isd.afid = msg->rcv.src_ip.af;
-       isd.src_ip.len = ip_addr2sbufz(&msg->rcv.src_ip, srcip_buf,
+       isd.src_ip.len = ip_addr2sbuf(&msg->rcv.src_ip, srcip_buf,
                        IP_ADDR_MAX_STRZ_SIZE);
+       srcip_buf[isd.src_ip.len] = 0;
        isd.src_ip.s = srcip_buf;
        isd.src_port = msg->rcv.src_port;
        if(msg->rcv.bind_address==NULL
@@ -340,8 +341,9 @@ int sipdump_msg_received(sr_event_param_t *evp)
        isd.protoid = evp->rcv->proto;
        isd.afid = (evp->rcv->bind_address!=NULL
                                && evp->rcv->bind_address->address.af==AF_INET6)?AF_INET6:AF_INET;
-       isd.src_ip.len = ip_addr2sbufz(&evp->rcv->src_ip, srcip_buf,
+       isd.src_ip.len = ip_addr2sbuf(&evp->rcv->src_ip, srcip_buf,
                                        IP_ADDR_MAX_STRZ_SIZE);
+       srcip_buf[isd.src_ip.len] = '\0';
        isd.src_ip.s = srcip_buf;
        isd.src_port = evp->rcv->src_port;
        if(evp->rcv->bind_address==NULL
@@ -420,7 +422,8 @@ int sipdump_msg_sent(sr_event_param_t *evp)
                isd.src_port = (int)evp->dst->send_sock->port_no;
        }
        su2ip_addr(&ip, &evp->dst->to);
-       isd.dst_ip.len = ip_addr2sbufz(&ip, dstip_buf, IP_ADDR_MAX_STRZ_SIZE);
+       isd.dst_ip.len = ip_addr2sbuf(&ip, dstip_buf, IP_ADDR_MAX_STRZ_SIZE);
+       dstip_buf[isd.dst_ip.len] = '\0';
        isd.dst_ip.s = dstip_buf;
        isd.dst_port = (int)su_getport(&evp->dst->to);
 
index e808ff2..0db2697 100644 (file)
@@ -198,8 +198,8 @@ void sipdump_write_pcap(FILE *fs, sipdump_data_t *spd)
                        return;
                }
                memcpy(&v_pcap_ipv6_header.ip6_src, &ip6addr, sizeof(struct in6_addr));
-               if (inet_pton(AF_INET, spd->dst_ip.s, &ip6addr) != 1) {
-                       LM_ERR("failed to parse IPv4 address %s\n", spd->dst_ip.s);
+               if (inet_pton(AF_INET6, spd->dst_ip.s, &ip6addr) != 1) {
+                       LM_ERR("failed to parse IPv6 address %s\n", spd->dst_ip.s);
                        return;
                }
                memcpy(&v_pcap_ipv6_header.ip6_dst, &ip6addr, sizeof(struct in6_addr));
index 6a4fa1f..9a62829 100644 (file)
@@ -187,15 +187,29 @@ int trace_send_hep3_duplicate(str *body, str *from, str *to,
                dst_fin = dst2;
        }
 
-       if(trace_send_sock_str.s) {
-               LM_DBG("send sock activated, grep for the sock_info\n");
-               si = grep_sock_info(&trace_send_sock_uri->host,
-                               trace_send_sock_uri->port_no,
-                               trace_send_sock_uri->proto);
+       si = NULL;
+       if(trace_send_sock_name_str.s) {
+               LM_DBG("send sock name activated - find the sock info\n");
+               if(trace_send_sock_info) {
+                       si = trace_send_sock_info;
+               } else {
+                       si = ksr_get_socket_by_name(&trace_send_sock_name_str);
+               }
+       } else if(trace_send_sock_str.s) {
+               LM_DBG("send sock addr activated - find the sock_info\n");
+               if(trace_send_sock_info) {
+                       si = trace_send_sock_info;
+               } else {
+                       si = grep_sock_info(&trace_send_sock_uri->host,
+                                       trace_send_sock_uri->port_no,
+                                       trace_send_sock_uri->proto);
+               }
+       }
+       if(trace_send_sock_name_str.s || trace_send_sock_str.s) {
                if(!si) {
-                       LM_WARN("cannot grep socket info\n");
+                       LM_WARN("cannot find send socket info\n");
                } else {
-                       LM_DBG("found socket while grep: [%.*s] [%.*s]\n", si->name.len,
+                       LM_DBG("found send socket: [%.*s] [%.*s]\n", si->name.len,
                                        si->name.s, si->address_str.len, si->address_str.s);
                        dst_fin->send_sock = si;
                }
@@ -304,15 +318,29 @@ int trace_send_hep2_duplicate(
                dst_fin = dst2;
        }
 
-       if(trace_send_sock_str.s) {
-               LM_DBG("send sock activated, grep for the sock_info\n");
-               si = grep_sock_info(&trace_send_sock_uri->host,
-                               trace_send_sock_uri->port_no,
-                               trace_send_sock_uri->proto);
+       si = NULL;
+       if(trace_send_sock_name_str.s) {
+               LM_DBG("send sock name activated - find the sock info\n");
+               if(trace_send_sock_info) {
+                       si = trace_send_sock_info;
+               } else {
+                       si = ksr_get_socket_by_name(&trace_send_sock_name_str);
+               }
+       } else if(trace_send_sock_str.s) {
+               LM_DBG("send sock addr activated - find the sock info\n");
+               if(trace_send_sock_info) {
+                       si = trace_send_sock_info;
+               } else {
+                       si = grep_sock_info(&trace_send_sock_uri->host,
+                                       trace_send_sock_uri->port_no,
+                                       trace_send_sock_uri->proto);
+               }
+       }
+       if(trace_send_sock_name_str.s || trace_send_sock_str.s) {
                if(!si) {
-                       LM_WARN("cannot grep socket info\n");
+                       LM_WARN("cannot find send socket info\n");
                } else {
-                       LM_DBG("found socket while grep: [%.*s] [%.*s]\n", si->name.len,
+                       LM_DBG("found send socket: [%.*s] [%.*s]\n", si->name.len,
                                        si->name.s, si->address_str.len, si->address_str.s);
                        dst_fin->send_sock = si;
                }
@@ -536,6 +564,7 @@ int hlog(struct sip_msg *msg, str *correlationid, str *message)
        struct timezone tz;
        struct dest_info dst;
        struct proxy_l *p = NULL;
+       struct socket_info *si;
 
        if(!correlationid) {
                if(msg->callid == NULL && ((parse_headers(msg, HDR_CALLID_F, 0) == -1)
@@ -587,27 +616,31 @@ int hlog(struct sip_msg *msg, str *correlationid, str *message)
        free_proxy(p); /* frees only p content, not p itself */
        pkg_free(p);
 
+       si = NULL;
        if(trace_send_sock_name_str.s) {
-               if(!trace_send_sock_info) {
-                       trace_send_sock_info = ksr_get_socket_by_name(&trace_send_sock_name_str);
+               LM_DBG("send sock name activated - find the sock info\n");
+               if(trace_send_sock_info) {
+                       si = trace_send_sock_info;
+               } else {
+                       si = ksr_get_socket_by_name(&trace_send_sock_name_str);
                }
-               dst.send_sock = trace_send_sock_info;
        } else if(trace_send_sock_str.s) {
-               LM_DBG("send sock activated - find the sock info\n");
+               LM_DBG("send sock addr activated - find the sock info\n");
                if(trace_send_sock_info) {
-                       dst.send_sock = trace_send_sock_info;
+                       si = trace_send_sock_info;
                } else {
-                       dst.send_sock = grep_sock_info(&trace_send_sock_uri->host,
+                       si = grep_sock_info(&trace_send_sock_uri->host,
                                        trace_send_sock_uri->port_no,
                                        trace_send_sock_uri->proto);
                }
-               if(!dst.send_sock) {
-                       LM_WARN("local socket not found for: [%.*s]\n",
-                                       trace_send_sock_str.len, trace_send_sock_str.s);
+       }
+       if(trace_send_sock_name_str.s || trace_send_sock_str.s) {
+               if(!si) {
+                       LM_WARN("cannot find send socket info\n");
                } else {
-                       LM_DBG("using local send socket: [%.*s] [%.*s]\n",
-                                       dst.send_sock->name.len, dst.send_sock->name.s,
-                                       dst.send_sock->address_str.len, dst.send_sock->address_str.s);
+                       LM_DBG("found send socket: [%.*s] [%.*s]\n", si->name.len,
+                                       si->name.s, si->address_str.len, si->address_str.s);
+                       dst.send_sock = si;
                }
        }
 
index e7c5e3d..88ed330 100644 (file)
@@ -118,6 +118,7 @@ static int fixup_get_uri_param(void** param, int param_no);
 static int free_fixup_get_uri_param(void** param, int param_no);
 static int fixup_option(void** param, int param_no);
 
+static int ki_is_gruu(sip_msg_t *msg);
 
 char *contact_flds_separator = DEFAULT_SEPARATOR;
 
@@ -726,11 +727,20 @@ static sr_kemi_t sr_kemi_siputils_exports[] = {
                { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
                        SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
        },
+       { str_init("siputils"), str_init("is_gruu"),
+               SR_KEMIP_INT, ki_is_gruu,
+               { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
+                       SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+       },
 
        { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
 };
 /* clang-format on */
 
+static int ki_is_gruu(sip_msg_t *msg) {
+       return w_is_gruu(msg, NULL, NULL);
+}
+
 /**
  *
  */
index 1b88aa0..e6d0060 100644 (file)
@@ -401,12 +401,6 @@ static void init_ssl_methods(void)
        ssl_methods[TLS_USE_TLSv1_2 - 1] = TLSv1_2_method();
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(LIBRESSL_VERSION_NUMBER)
-       ssl_methods[TLS_USE_TLSv1_3_cli - 1] = TLSv1_3_client_method();
-       ssl_methods[TLS_USE_TLSv1_3_srv - 1] = TLSv1_3_server_method();
-       ssl_methods[TLS_USE_TLSv1_3 - 1] = TLSv1_3_method();
-#endif
-
        /* ranges of TLS versions (require a minimum TLS version) */
        ssl_methods[TLS_USE_TLSv1_PLUS - 1] = (void*)TLS_OP_TLSv1_PLUS;
 
@@ -418,9 +412,6 @@ static void init_ssl_methods(void)
        ssl_methods[TLS_USE_TLSv1_2_PLUS - 1] = (void*)TLS_OP_TLSv1_2_PLUS;
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(LIBRESSL_VERSION_NUMBER)
-       ssl_methods[TLS_USE_TLSv1_3_PLUS - 1] = (void*)TLS_OP_TLSv1_3_PLUS;
-#endif
 #else
        /* openssl 1.1.0+ */
        memset(sr_tls_methods, 0, sizeof(sr_tls_methods));
@@ -472,6 +463,7 @@ static void init_ssl_methods(void)
        sr_tls_methods[TLS_USE_TLSv1_2 - 1].TLSMethodMin = TLS1_2_VERSION;
        sr_tls_methods[TLS_USE_TLSv1_2 - 1].TLSMethodMax = TLS1_2_VERSION;
 
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(LIBRESSL_VERSION_NUMBER)
        sr_tls_methods[TLS_USE_TLSv1_3_cli - 1].TLSMethod = TLS_client_method();
        sr_tls_methods[TLS_USE_TLSv1_3_cli - 1].TLSMethodMin = TLS1_3_VERSION;
        sr_tls_methods[TLS_USE_TLSv1_3_cli - 1].TLSMethodMax = TLS1_3_VERSION;
@@ -481,6 +473,7 @@ static void init_ssl_methods(void)
        sr_tls_methods[TLS_USE_TLSv1_3 - 1].TLSMethod = TLS_method();
        sr_tls_methods[TLS_USE_TLSv1_3 - 1].TLSMethodMin = TLS1_3_VERSION;
        sr_tls_methods[TLS_USE_TLSv1_3 - 1].TLSMethodMax = TLS1_3_VERSION;
+#endif
 
        /* ranges of TLS versions (require a minimum TLS version) */
        sr_tls_methods[TLS_USE_TLSv1_PLUS - 1].TLSMethod = TLS_method();
@@ -492,8 +485,10 @@ static void init_ssl_methods(void)
        sr_tls_methods[TLS_USE_TLSv1_2_PLUS - 1].TLSMethod = TLS_method();
        sr_tls_methods[TLS_USE_TLSv1_2_PLUS - 1].TLSMethodMin = TLS1_2_VERSION;
 
+#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(LIBRESSL_VERSION_NUMBER)
        sr_tls_methods[TLS_USE_TLSv1_3_PLUS - 1].TLSMethod = TLS_method();
        sr_tls_methods[TLS_USE_TLSv1_3_PLUS - 1].TLSMethodMin = TLS1_3_VERSION;
+#endif
 
 #endif
 }
index 1677665..f13ca32 100644 (file)
@@ -135,7 +135,7 @@ cfg_def_t   tls_cfg_def[] = {
        {"force_run", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
                "force loading the tls module even when initial sanity checks fail"},
        {"method",   CFG_VAR_STR | CFG_READONLY, 0, 0, 0, 0,
-               "TLS method used (TLSv1.2, TLSv1.1, TLSv1, SSLv3, SSLv2, SSLv23)"},
+               "TLS method used (TLSv1.3 TLSv1.2, TLSv1.1, TLSv1, SSLv3, SSLv2, SSLv23)"},
        {"server_name",   CFG_VAR_STR | CFG_READONLY, 0, 0, 0, 0,
                "Server name (SNI)"},
        {"server_name_mode", CFG_VAR_INT | CFG_READONLY, 0, 1, 0, 0,
index 1669461..282b4a2 100644 (file)
@@ -125,6 +125,8 @@ static cfg_option_t methods[] = {
        {"TLSv1.1+", .val = TLS_USE_TLSv1_1_PLUS},
        {"TLSv1.2",  .val = TLS_USE_TLSv1_2},
        {"TLSv1.2+", .val = TLS_USE_TLSv1_2_PLUS},
+       {"TLSv1.3",  .val = TLS_USE_TLSv1_3},
+       {"TLSv1.3+", .val = TLS_USE_TLSv1_3_PLUS},
        {0}
 };
 
index f027b86..d7aed00 100644 (file)
 #ifdef SSL_OP_NO_TLSv1
 #  define TLS_OP_TLSv1_1_PLUS (TLS_OP_TLSv1_PLUS   | SSL_OP_NO_TLSv1)
 
-#  ifdef SSL_OP_NO_TLSv1_1
-#    define TLS_OP_TLSv1_2_PLUS (TLS_OP_TLSv1_1_PLUS | SSL_OP_NO_TLSv1_1)
-#  endif /*SSL_OP_NO_TLSv1_1*/
+#ifdef SSL_OP_NO_TLSv1_1
<