Update upstream source from tag 'upstream/5.6.2'

Update to upstream version '5.6.2'
with Debian dir 1283c7412b
mr10.5.3
Victor Seva 2 years ago
commit fb8efd0ff8

File diff suppressed because it is too large Load Diff

@ -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

@ -5,6 +5,10 @@ various open source projects.
* https://github.com/google/oss-fuzz
Folder for Kamailio project on OSS-Fuzz:
* https://github.com/google/oss-fuzz/tree/master/projects/kamailio
OSS-Fuzz pull request to integrate Kamailio:
* https://github.com/google/oss-fuzz/pull/5279

@ -1,3 +1,4 @@
#include "../config.h"
#include "../parser/sdp/sdp.h"
#include "../parser/parse_uri.c"
#include "../parser/parse_hname2.h"
@ -23,6 +24,11 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
orig_inv.buf = (char*)data;
orig_inv.len = size;
if(size >= 4*BUF_SIZE) {
/* test with larger message than core accepts, but not indefinitely large */
return 0;
}
if (parse_msg(orig_inv.buf, orig_inv.len, &orig_inv) < 0) {
goto cleanup;
}

@ -1,8 +1,14 @@
#include "../config.h"
#include "../parser/parse_uri.c"
int
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
struct sip_uri uri;
if(size >= BUF_SIZE) {
/* test with larger message than core accepts, but not indefinitely large */
return 0;
}
parse_uri(data, size, &uri);
return 0;
}

@ -4,7 +4,7 @@
# Maintainer: Nathan Angelacos <nangel@alpinelinux.org>
pkgname=kamailio
pkgver=5.6.0
pkgver=5.6.2
pkgrel=0
# If building from a git snapshot, specify the gitcommit

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -59,8 +59,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -59,8 +59,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -60,8 +60,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -59,8 +59,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -65,8 +65,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,2 +1,2 @@
kamailio-tls-modules binary: possible-gpl-code-linked-with-openssl
kamailio-tls-modules binary: library-not-linked-against-libc usr/lib/*/kamailio/openssl_mutex_shared/openssl_mutex_shared.so
kamailio-tls-modules binary: library-not-linked-against-libc

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -60,8 +60,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -58,8 +58,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -49,8 +49,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -59,8 +59,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -61,8 +61,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -53,8 +53,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -49,8 +49,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,3 +1,15 @@
kamailio (5.6.2) unstable; urgency=medium
* version set 5.6.2
-- Victor Seva <vseva@debian.org> Thu, 06 Oct 2022 10:35:53 +0200
kamailio (5.6.1) unstable; urgency=medium
* version set 5.6.1
-- Victor Seva <vseva@debian.org> Wed, 06 Jul 2022 09:59:31 +0200
kamailio (5.6.0) unstable; urgency=medium
* version set 5.6.0

@ -1,7 +1,7 @@
Source: kamailio
Section: net
Priority: optional
Maintainer: Debian VoIP Team <pkg-voip-maintainers@lists.alioth.debian.org>
Maintainer: Kamailio Admin Group <kadmin.hq@lists.kamailio.org>
Uploaders:
Victor Seva <vseva@debian.org>,
Build-Depends:
@ -64,8 +64,8 @@ Build-Depends:
zlib1g-dev,
Standards-Version: 4.6.0.1
Homepage: http://www.kamailio.org/
Vcs-Git: https://salsa.debian.org/pkg-voip-team/kamailio.git
Vcs-Browser: https://salsa.debian.org/pkg-voip-team/kamailio/
Vcs-Git: https://github.com/kamailio/kamailio.git
Vcs-Browser: https://github.com/kamailio/kamailio/
Rules-Requires-Root: no
Package: kamailio

@ -1,5 +1,5 @@
%define name kamailio
%define ver 5.6.0
%define ver 5.6.2
%define rel dev1.0%{dist}
%if 0%{?fedora}
@ -21,6 +21,7 @@
%bcond_without nats
%bcond_without perl
%bcond_without phonenum
%bcond_without python2
%bcond_without python3
%bcond_without rabbitmq
%bcond_without redis
@ -55,6 +56,7 @@
%bcond_with nats
%bcond_without perl
%bcond_with phonenum
%bcond_without python2
%bcond_with python3
%bcond_with rabbitmq
%bcond_with redis
@ -90,6 +92,7 @@
%bcond_with nats
%bcond_without perl
%bcond_without phonenum
%bcond_without python2
%bcond_without python3
%bcond_without rabbitmq
%bcond_without redis
@ -135,6 +138,53 @@
%bcond_without nats
%bcond_without perl
%bcond_without phonenum
%bcond_without python2
%bcond_without python3
%bcond_without rabbitmq
%bcond_without redis
%bcond_without ruby
%bcond_without sctp
%bcond_without websocket
%bcond_without xmlrpc
%endif
%if 0%{?rhel} == 9
%if 0%{?centos_ver}
%define dist_name centos
%define dist_version %{?centos}
%define dist .el9.centos
%endif
%if 0%{?almalinux_ver}
%define dist_name centos
%define dist_version %{?almalinux}
%define dist .el9.almalinux
%endif
%if 0%{?rocky_ver}
%define dist_name centos
%define dist_version %{?rocky}
%define dist .el9.rocky
%endif
%if 0%{?centos_ver} == 0 && 0%{?almalinux_ver} == 0 && 0%{?rocky_ver} == 0
%define dist_name rhel
%define dist_version %{?rhel}
%endif
%bcond_without cnxcc
%bcond_with dnssec
%bcond_without evapi
%bcond_without geoip
%bcond_without http_async_client
%bcond_without ims
%bcond_without jansson
%bcond_without json
%bcond_without lua
%bcond_without lwsc
%bcond_without kazoo
%bcond_without memcached
%bcond_without mongodb
%bcond_without nats
%bcond_without perl
%bcond_without phonenum
%bcond_with python2
%bcond_without python3
%bcond_without rabbitmq
%bcond_without redis
@ -163,6 +213,7 @@
%bcond_with nats
%bcond_without perl
%bcond_with phonenum
%bcond_without python2
%bcond_without python3
%bcond_with rabbitmq
%bcond_without redis
@ -239,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
@ -788,12 +839,14 @@ SIP Presence (and RLS, XCAP, etc) support for Kamailio.
%package python
Summary: Python extensions for Kamailio
Group: %{PKGGROUP}
%if %{with python2}
Requires: python2, kamailio = %ver
BuildRequires: python2, python2-devel
%endif
%if %{with python3}
%if 0%{?rhel} == 7
Requires: python36, kamailio = %ver
BuildRequires: python36, python36-devel
%if 0%{?rhel} == 8
Requires: python39, kamailio = %ver
BuildRequires: python39, python39-devel
%else
Requires: python3, kamailio = %ver
BuildRequires: python3, python3-devel
@ -820,7 +873,7 @@ RabbitMQ module for Kamailio.
Summary: RADIUS modules for Kamailio
Group: %{PKGGROUP}
Requires: kamailio = %ver
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} == 8
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} >= 8
Requires: freeradius-client
BuildRequires: freeradius-client-devel
%else
@ -1154,14 +1207,14 @@ sed -i -e 's/python3/python2/' utils/kamctl/dbtextdb/dbtextdb.py
%endif
# on latest dist need to add --atexit=no for Kamailio options. More details GH #2616
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} == 8
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} >= 8
sed -i -e 's|/usr/sbin/kamailio|/usr/sbin/kamailio --atexit=no|' pkg/kamailio/obs/kamailio.service
%endif
%build
ln -s ../obs pkg/kamailio/%{dist_name}/%{dist_version}
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} == 8
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} >= 8
export FREERADIUS=1
%endif
make cfg prefix=/usr \
@ -1176,8 +1229,11 @@ make every-module skip_modules="app_mono db_cassandra db_oracle iptrtpproxy \
%if %{with openssl11}
SSL_BUILDER="pkg-config libssl11" \
%endif
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} == 8
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} >= 8
FREERADIUS=1 \
%endif
%if 0%{?rhel} >= 8
PYTHON3=python3.9 \
%endif
group_include="kstandard kautheph kberkeley kcarrierroute \
%if %{with cnxcc}
@ -1237,7 +1293,10 @@ make every-module skip_modules="app_mono db_cassandra db_oracle iptrtpproxy \
%if %{with phonenum}
kphonenum \
%endif
kpostgres kpresence kpython \
kpostgres kpresence \
%if %{with python2}
kpython \
%endif
%if %{with python3}
kpython3 \
%endif
@ -1277,8 +1336,11 @@ make install-modules-all skip_modules="app_mono db_cassandra db_oracle \
%if %{with openssl11}
SSL_BUILDER="pkg-config libssl11" \
%endif
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} == 8
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel} >= 8
FREERADIUS=1 \
%endif
%if 0%{?rhel} >= 8
PYTHON3=python3.9 \
%endif
group_include="kstandard kautheph kberkeley kcarrierroute \
%if %{with cnxcc}
@ -1338,7 +1400,10 @@ make install-modules-all skip_modules="app_mono db_cassandra db_oracle \
%if %{with phonenum}
kphonenum \
%endif
kpostgres kpresence kpython \
kpostgres kpresence \
%if %{with python2}
kpython \
%endif
%if %{with python3}
kpython3 \
%endif
@ -1401,8 +1466,8 @@ install -m644 pkg/kamailio/%{dist_name}/%{dist_version}/sipcapture.sysconfig \
%if 0%{?suse_version}
%py_compile -O %{buildroot}%{_libdir}/kamailio/kamctl/dbtextdb
%endif
%if 0%{?fedora} || 0%{?rhel} == 8
%py_byte_compile %{__python2} %{buildroot}%{_libdir}/kamailio/kamctl/dbtextdb
%if 0%{?fedora} || 0%{?rhel} >= 8
%py_byte_compile %{__python3} %{buildroot}%{_libdir}/kamailio/kamctl/dbtextdb
%endif
# Removing devel files
@ -1539,6 +1604,7 @@ fi
%doc %{_docdir}/kamailio/modules/README.sdpops
%doc %{_docdir}/kamailio/modules/README.seas
%doc %{_docdir}/kamailio/modules/README.sipcapture
%doc %{_docdir}/kamailio/modules/README.siprepo
%doc %{_docdir}/kamailio/modules/README.sipt
%doc %{_docdir}/kamailio/modules/README.siptrace
%doc %{_docdir}/kamailio/modules/README.siputils
@ -1699,6 +1765,7 @@ fi
%{_libdir}/kamailio/modules/sdpops.so
%{_libdir}/kamailio/modules/seas.so
%{_libdir}/kamailio/modules/sipcapture.so
%{_libdir}/kamailio/modules/siprepo.so
%{_libdir}/kamailio/modules/sipt.so
%{_libdir}/kamailio/modules/siptrace.so
%{_libdir}/kamailio/modules/siputils.so
@ -1766,8 +1833,14 @@ fi
%dir %{_libdir}/kamailio/kamctl/dbtextdb
%{_libdir}/kamailio/kamctl/dbtextdb/dbtextdb.py
%if 0%{?rhel} >= 8 || 0%{?fedora}
%dir %{_libdir}/kamailio/kamctl/dbtextdb/__pycache__
%{_libdir}/kamailio/kamctl/dbtextdb/__pycache__/*.pyc
%endif
%if 0%{?rhel} == 6 || 0%{?rhel} == 7
%{_libdir}/kamailio/kamctl/dbtextdb/dbtextdb.pyc
%{_libdir}/kamailio/kamctl/dbtextdb/dbtextdb.pyo
%endif
%{_mandir}/man5/*
%{_mandir}/man8/*
@ -2133,8 +2206,10 @@ fi
%files python
%defattr(-,root,root)
%if %{with python2}
%doc %{_docdir}/kamailio/modules/README.app_python
%{_libdir}/kamailio/modules/app_python.so
%endif
%if %{with python3}
%doc %{_docdir}/kamailio/modules/README.app_python3
%{_libdir}/kamailio/modules/app_python3.so
@ -2345,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

@ -106,7 +106,7 @@ INSTALL_FLAVOUR=$(FLAVOUR)
# version number
VERSION = 5
PATCHLEVEL = 6
SUBLEVEL = 0
SUBLEVEL = 2
EXTRAVERSION =
# memory manager switcher

@ -38,7 +38,7 @@ mod_list_dbuid=db2_ops uid_auth_db uid_avp_db uid_domain uid_gflags \
uid_uri_db
# - modules for devel purposes
mod_list_devel=malloc_test print print_lib
mod_list_devel=misctest print print_lib
# - modules depending on pcre3 library
mod_list_pcre=dialplan lcr regex

@ -2,6 +2,6 @@
* DO NOT EDIT IT
*/
#define REPO_VER "61e86a"
#define REPO_HASH "61e86a"
#define REPO_VER "54a9c1"
#define REPO_HASH "54a9c1"
#define REPO_STATE ""

@ -284,7 +284,7 @@ static int cfg_update_defaults(cfg_group_meta_t *meta,
meta->array = array;
clone_done = 1;
}
if(ginst->vars + var->offset) {
if((unsigned long)ginst->vars + var->offset) {
memcpy(ginst->vars + var->offset, new_val, cfg_var_size(var));
} else {
LM_ERR("invalid variable offset\n");

@ -459,7 +459,8 @@ static str log_prefix_str = STR_NULL;
void log_init(void)
{
struct addrinfo hints, *info;
struct addrinfo hints;
struct addrinfo *info = NULL;
int gai_result;
char hostname[1024];

@ -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++;
}

@ -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;

@ -297,7 +297,7 @@ 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;
@ -308,7 +308,7 @@ void pp_define_core(void)
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");
@ -320,7 +320,7 @@ void pp_define_core(void)
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");

@ -1502,7 +1502,8 @@ static int build_iface_list(void)
}
if(strlen(ifaces[index].name)==0 && strlen(name)>0) {
strncpy(ifaces[index].name, name, MAX_IF_LEN-1);
memcpy(ifaces[index].name, name, MAX_IF_LEN-1);
ifaces[index].name[MAX_IF_LEN-1] = '\0';
}
ifaces[index].index = index;

@ -347,6 +347,9 @@ int ksr_version_control(void *handle, char *path)
char **m_flags;
char* error;
#ifdef __FreeBSD__
(void) dlerror();
#endif
m_ver=(char **)dlsym(handle, "module_version");
if ((error=(char *)dlerror())!=0) {
LM_ERR("no version info in module <%s>: %s\n", path, error);

@ -2172,6 +2172,10 @@ int main(int argc, char** argv)
init_tcp_options(); /* set the defaults before the config */
#endif
if (pv_init_buffer()<0) {
goto error;
}
pp_define_core();
/* process command line (cfg. file path etc) */

@ -529,6 +529,11 @@ Note
information given will not be stored in the CDR as they cannot be
accessed by the end of the call when the CDR is logged.
The dialog module needs to be engaged on the dialogs that should be
accounted, that they will be tracked by the server. This is usally done
by calling the function dlg_manage() or setting the dlg_flag. Refer to
the documentation of the dialog module for more information.
Sometimes, dialogs expire because the UA has a problem and a final
message is never transmitted. You can toggle on/off the generation of
CDR-based logging in such cases with only the dlg_vars showing by using
@ -1129,7 +1134,7 @@ modparam("acc", "cdr_start_on_confirmed", 1)
6.34. cdr_facility (integer)
Log facility to which CDR messages are issued to syslog. This allows to
easily seperate CDR-specific logging from the other log messages.
easily separate CDR-specific logging from the other log messages.
Default value is LOG_DAEMON.

@ -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;
}

@ -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;
}

@ -93,25 +93,20 @@ void env_set_totag(struct cell *t, struct sip_msg *reply)
tmb.t_get_reply_totag(t->uas.request, &acc_env.to_tag);
}
int env_set_reason(struct sip_msg *reply, str *buff) {
int i;
char *p;
int env_set_reason(struct sip_msg *reply, str *buff, int code) {
if (reply!=FAKED_REPLY || !buff || !buff->s || buff->len < 20)
return 0;
if (strncmp(buff->s, "SIP/2.0 ", 8) != 0) {
LM_ERR("not a SIP reply\n");
return 0;
}
p = buff->s + 12;
for (i=12;i<buff->len;i++) {
if (*p == '\r' || *p == '\n') {
acc_env.reason.s = buff->s+12;
acc_env.reason.len = i-12;
LM_DBG("reason[%.*s]\n", acc_env.reason.len, acc_env.reason.s);
return 1;
}
p++;
}
/* Set the reason to a pointer in heap memory. It will contain the last seen FAKED_REPLY */
acc_env.reason.s = error_text(code);
acc_env.reason.len = strlen(acc_env.reason.s);
LM_DBG("reason[%.*s]\n", acc_env.reason.len, acc_env.reason.s);
return 0;
}
@ -139,7 +134,8 @@ static inline void env_set_code_status( int code, struct sip_msg *reply)
acc_env.code_s.s =
int2bstr((unsigned long)code, code_buf, &acc_env.code_s.len);
/* reason */
if (acc_env.reason.len == 0) { /* already extracted in case of locally generated replies */
/* In case of an ACK the reply == NULL, but the reason must be set when report_ack is 1 */
if (acc_env.reason.len == 0 || reply==NULL) { /* already extracted in case of locally generated replies */
acc_env.reason.s = error_text(code);
acc_env.reason.len = strlen(acc_env.reason.s);
}
@ -719,7 +715,7 @@ static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps )
LM_DBG("acc callback called for t(%p) event type %d, reply code %d\n",
t, type, ps->code);
if (type&TMCB_RESPONSE_OUT) {
env_set_reason(ps->rpl, &ps->send_buf);
env_set_reason(ps->rpl, &ps->send_buf, ps->code);
acc_onreply( t, ps->req, ps->rpl, ps->code);
} else if (type&TMCB_E2EACK_IN) {
acc_onack( t, t->uas.request, ps->req, ps->code);

@ -324,6 +324,13 @@ if (uri=~"sip:+40") /* calls to Romania */ {
end of the call when the CDR is logged.
</para>
<para>
The dialog module needs to be engaged on the dialogs that should be accounted, that
they will be tracked by the server. This is usally done by calling the function
<emphasis>dlg_manage()</emphasis> or setting the <emphasis>dlg_flag</emphasis>.
Refer to the documentation of the dialog module for more information.
</para>
<para>
Sometimes, dialogs expire because the UA has a problem and a final message is never
transmitted. You can toggle on/off the generation of CDR-based logging in such cases

@ -37,6 +37,26 @@
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;
}

@ -24,25 +24,6 @@
#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

@ -185,9 +185,6 @@ static int child_init(int rank)
* this is called before any process is forked
* so the Python internal state handler
* should be called now.
*
* TODO: is PyOS_AfterFork_Parent() necesary
* in the main process?
*/
#if PY_VERSION_HEX >= 0x03070000
PyOS_BeforeFork() ;
@ -205,11 +202,14 @@ static int child_init(int rank)
return 0;
}
_apy_process_rank = rank;
if (!_ksr_is_main) {
#if PY_VERSION_HEX >= 0x03070000
PyOS_AfterFork_Child();
PyOS_AfterFork_Child();
#else
PyOS_AfterFork();
PyOS_AfterFork();
#endif
}
if (cfg_child_init()) {
return -1;
}

@ -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));

@ -450,12 +450,12 @@ int ki_has_credentials(sip_msg_t *msg, str* srealm)
ret = find_credentials(msg, srealm, HDR_PROXYAUTH_T, &hdr);
if(ret==0) {
LM_DBG("found www credentials with realm [%.*s]\n", srealm->len, srealm->s);
LM_DBG("found proxy credentials with realm [%.*s]\n", srealm->len, srealm->s);
return 1;
}
ret = find_credentials(msg, srealm, HDR_AUTHORIZATION_T, &hdr);
if(ret==0) {
LM_DBG("found proxy credentials with realm [%.*s]\n", srealm->len, srealm->s);
LM_DBG("found www credentials with realm [%.*s]\n", srealm->len, srealm->s);
return 1;
}

@ -25,7 +25,7 @@ Gergely Kovacs
5.6. callid_cache_limit (integer)
5.7. certificate_cache_limit (integer)
5.8. cainfo_path (string)
5.9. accept_pem_certs ([0|1])
5.9. accept_pem_certs (int)
6. Functions
@ -91,7 +91,7 @@ Chapter 1. Admin Guide
5.6. callid_cache_limit (integer)
5.7. certificate_cache_limit (integer)
5.8. cainfo_path (string)
5.9. accept_pem_certs ([0|1])
5.9. accept_pem_certs (int)
6. Functions
@ -174,7 +174,7 @@ Chapter 1. Admin Guide
5.6. callid_cache_limit (integer)
5.7. certificate_cache_limit (integer)
5.8. cainfo_path (string)
5.9. accept_pem_certs ([0|1])
5.9. accept_pem_certs (int)
5.1. privatekey_path (string)
@ -296,11 +296,12 @@ modparam("auth_identity","certificate_cache_limit",4096)
modparam("auth_identity","cainfo_path","/etc/ssl/certs/ca-certificates.crt")
...
5.9. accept_pem_certs ([0|1])
5.9. accept_pem_certs (int)
Note: this parameter is for verifier service.
Enables the acquired certificate processing if it is in PEM format.
Value can be 0 or 1.
This parameter is optional. The default value is "0".

@ -1,629 +0,0 @@
<?xml version='1.0'?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbookid/id/g/4.5/docbookx.dtd">
<refentry xml:id="module.auth_identity"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:serdoc="http://sip-router.org/xml/serdoc">
<refmeta>
<refentrytitle>auth_identity</refentrytitle>
<manvolnum>7</manvolnum>
</refmeta>
<refnamediv>
<refname>auth_identity</refname>
<refpurpose>Securely identify originator of SIP messages.</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>
The <command>auth_identity</command> SER module provides
functionalities for securely identifying originators of SIP
messages by implementing the mechanism described in RFC 4474
and known as SIP Identity framework.
</para>
<para>
The module provides two services:
The <emphasis>authorizer</emphasis> authorizes a message and adds
Identity and Identity-Info headers to forwarded requests.
The <emphasis>verifier</emphasis> verifies the identity of a
received message.
</para>
<para>
In order to use the <command>auth_identity</command> module you
have to provide a certificate. More information can be found in
the section
<serdoc:link linkend="module.auth_identity.certificates">Certificates
</serdoc:link> below.
</para>
</refsect1>
<refsect1 xml:id="module.auth_identity.functions">
<title>Functions</title>
<refsect2 xml:id="function.auth_add_identity">
<title>
<function>auth_add_identity</function>
()
</title>
<para>
Allowed in request processing only.
</para>
<para>
The <function>auth_add_identity()</function> function authorizes
a request by adding identity information to it.
</para>
<para>
It calculates a SHA1 hash over certain components of the message
and encrypts it using the private key given through the
<serdoc:modparam
module="auth_identity">privatekey_path</serdoc:modparam>
parameter. The resulting cyphertext is appended to the message
as the content of the Identity header field.
</para>
<para>
To allow the receiver to decypher the identity information, it adds
the URL where the receiver may find the certificate in the
Indentity-Info header field. This URL is set through the
<serdoc:modparam
module="auth_identity">certificate_url</serdoc:modparam>
parameter.
</para>
<para>
<emphasis>Note:</emphasis> After the function has been called,
the following header fields must not be modified:
From, To, Call-ID, CSeq, Date, Contact. Additionally, the
message body must remain unmodified, too.
</para>
</refsect2>
<refsect2 xml:id="function.auth_date_proc">
<title>
<function>auth_date_proc</function>
()
</title>
<para>
Allowed in request processing only.
</para>
<para>
The <function>auth_date_proc()</function> checks the age of a
request to be authroized. If the time given in the Date header
field of the request differs by more than the amount of seconds
given by the
<serdoc:modparam module="auth_identity">msg_timeout</serdoc:modparam>
parameter, the function returns <literal>false</literal>. It also
returns <literal>false</literal> if the certificate used by the
authorizer has expired.
</para>
</refsect2>
<refsect2 xml:id="function.vrfy_check_callid">
<title>
<function>vrfy_check_callid</function>
()
</title>
<para>
Allowed in request processing only.
</para>
<para>
The <function>vrfy_check_callid()</function> checks whether a
request for this call has been processed within the
time given by the
<serdoc:modparam
module="auth_identity">auth_validity_time</serdoc:modparam>
parameter.
</para>
<para>
The function generates a call identifier from the Call-ID and CSqe
header fields and the Tag parameter of the From header field and
compares it with the values stored in the Call-ID cache.
</para>
<para>
It returns <literal>false</literal> if the value is found and thus
the request is replayed or <literal>true</literal> otherwise.
</para>
</refsect2>
<refsect2 xml:id="function.vrfy_check_certificate">
<title>
<function>vrfy_check_certificate</function>
()
</title>
<para>
Allowed in request processing only.
</para>
<para>
The <function>vrfy_check_certificate()</function> function
checks the downloaded certificate and returns <literal>true</literal>
if it is valid or <literal>false</literal> otherwise.
</para>
<para>
A certificate is considered valid if it has not yet expired and
if its subject is identical to the domain part of the URL.
</para>
<!-- XXX Er, which URL? -->
<para>
Before <function>vrfy_check_certificate()</function> can be called,
the function <function>vrfy_check_date()</function> must have been
called and returned <literal>true</literal>.
</para>
</refsect2>
<refsect2 xml:id="function.vrfy_check_date">
<title>
<function>vrfy_check_date</function>
()
</title>
<para>
Allowed in request processing only.
</para>
<para>
The <function>vrfy_check_date()</function> function checks
the date of the request currently being processed. It returns
<literal>false</literal> if the time in the Date header field
of the request differs from the current system time by more than
the number of seconds given by the
<serdoc:modparam
module="auth_identity">auth_validity_time</serdoc:modparam>
parameter.
</para>
</refsect2>
<refsect2 xml:id="function.vrfy_check_msgvalidity">
<title>
<function>vrfy_check_msgvalidity</function>
()
</title>
<para>
Allowed in request processing only.
</para>
<para>
The <function>vrfy_check_msgvalidity()</function> function
checks the integrity of the request currently being processed.
</para>
<para>
It does so by calculating a SHA1 hash over certain parts of the
message and comparing it with the hash value that results from
decrypting the content of the Identity header field using the
certificate previously retrieved using the
<function>vrfy_get_certificate()</function> function.
</para>
<para>
The function returns <literal>true</literal> if the two hashes
match.
</para>
</refsect2>
<refsect2 xml:id="function.vrfy_get_certificate">
<title>
<function>vrfy_get_certificate</function>
()
</title>
<para>
Allowed in request processing only.
</para>
<para>
The <function>vrfy_get_certificate()</function> tries to get
the certificate from the URL given in the Identity-Info header
field of the currently processed request.
</para>
<para>
It returns <literal>true</literal> if the certifcate was
successfully loaded in a format that the module can process or
<literal>false</literal> otherwise.
</para>
</refsect2>
</refsect1>
<refsect1 xml:id="module.auth_identity.parameters">
<title>Module Parameters</title>
<refsect2 xml:id="module.auth_identity.accept_pem_certs">
<title><parameter>accept_pem_certs</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>boolean</serdoc:paramtype>
<serdoc:paramdefault>no</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>accept_pem_certs</parameter> parameter defines,
whether the verifier should process certificates in PEM format.
</para>
</refsect2>
<refsect2 xml:id="module.auth_identity.auth_validity_time">
<title><parameter>auth_validity_time</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>integer</serdoc:paramtype>
<serdoc:paramdefault>3600</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>auth_validity_time</parameter> parameter
sets the maximum age of a verified message.
</para>
</refsect2>
<refsect2 xml:id="module.auth_identity.cainfo_path">
<title><parameter>cainfo_path</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>string</serdoc:paramtype>
<serdoc:paramdefault>""</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>cainfo_path</parameter> paramter contains the
path and name of a file that contains trusted certificates.
</para>
<para>
The file should contain one or more certificates in PEM format
concatenated together. It is necessary if the verifier should
accept self-signed certifcates.
</para>
</refsect2>
<refsect2 xml:id="module.auth_identity.callid_cache_limit">
<title><parameter>callid_cache_limit</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>integer</serdoc:paramtype>
<serdoc:paramdefault>262144</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>callid_cache_limit</parameter> parameter
limits the number of entries in the Call-ID cache.
</para>
<para>
The Call-IDs of previously verified messages are stored in the
Call-ID cache for some time in order to recognize call
replay attacks. The cache uses shared memory. Each entry is
about 100 bytes in size.
</para>
</refsect2>
<refsect2 xml:id="module.auth_identity.certificate_cache_limit">
<title><parameter>certificate_cache_limit</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>integer</serdoc:paramtype>
<serdoc:paramdefault>32768</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>certificate_cache_limit</parameter> parameter
limits the number of entries stored in the certificate cache.
</para>
<para>
Each retrieved certificate is placed in the certificate cache
to speed up processing should it be needed again.
</para>
<para>
The cahce uses shared memory. Each entry is approximately 600
bytes in size.
</para>
</refsect2>
<refsect2 xml:id="module.auth_identity.certificate_path">
<title><parameter>certificate_path</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>string</serdoc:paramtype>
<serdoc:paramdefault>""</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>certificate_path</parameter> parameter must be
set to path and name of the file that contains the certificate
of the authentication service in PEM format.
</para>
<para>
The parameter is required for the authentication service to work.
</para>
</refsect2>
<refsect2 xml:id="module.auth_identity.certificate_url">
<title><parameter>certificate_url</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>string</serdoc:paramtype>
<serdoc:paramdefault>""</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>certificate_url</parameter> parameter must be
set to the URL where a verifier can retrieve the certificate.
The URL will be stored in the Identity-Info header of any
authorized request.
</para>
<para>
The certificate must be available at the given URL in DER
format.
</para>
<para>
The parameter is required for the authentication service to work.
</para>
</refsect2>
<refsect2 xml:id="module.auth_identity.msg_timeout">
<title><parameter>msg_timeout</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>int</serdoc:paramtype>
<serdoc:paramdefault>600</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>msg_timeout</parameter> parameter contains the
maximum age of a request to be authorized in seconds.
</para>
<para>
The authorizer will compare the time given in the Date header field
of the request with its own current time.
</para>
</refsect2>
<refsect2 xml:id="module.auth_identity.privatekey_path">
<title><parameter>privatekey_path</parameter></title>
<serdoc:paraminfo>
<serdoc:paramtype>string</serdoc:paramtype>
<serdoc:paramdefault>""</serdoc:paramdefault>
</serdoc:paraminfo>
<para>
The <parameter>privatekey_path</parameter> must be set to the paht
and name of the file that contains the private key of the
authentication service in PEM format.
</para>
<para>
The parameter is required for the authentication service to work.
</para>
</refsect2>
</refsect1>
<refsect1 id="modules.auth_identity.examples">
<title>Examples</title>
<para>
The <emphasis>authentifier</emphasis> is typically included in the
part of the routing
logic that sends a request to a foreign domain. In the
<filename>ser-oob.cfg</filename> configuration, this is the
<varname>route[OUTBOUND]</varname>. With an authentifier included,
it looks like this:
</para>
<programlisting><![CDATA[
route[OUTBOUND]
{
if ($f.did && !$t.did) {
# Authentication service
if (method=="INVITE" || method=="OPTION") {
# Identity and Identity-info headers must not exist
if (@identity) {
sl_reply("403", "Invalid Identity header");
drop;
}
if (@identity_info) {
sl_reply("403", "Invalid Identity-info header");
drop;
}
if (!auth_date_proc()) {
sl_reply("403", "Invalid Date value");
drop;
}
if (!auth_add_identity()) {
sl_reply("480", "Authentication error");
drop;
}
}
route(FORWARD);
}
}
]]></programlisting>
<para>
The <emphasis>verifier</emphasis> should be run after you discovered
that a request originates from a foreign domain (for your own domains,
you should be doing digest authentication instead).
</para>
<para>
While you should reject any request that does contain an Identity
header but does not verify, it is up to your local policy, what to
do with messages that do not contain an Identity header at all.
You could reject them or divert them to voice mail or any of a number
of other options.
</para>
<para>
The following config snippet rejects any message that does not have
an Identity header.
</para>
<programlisting><![CDATA[
if (method=="INVITE" || method=="OPTIONS") {
if (!@identity) {
sl_reply("428", "Use Identity Header");
drop;
}
if (!@identity_info) {
sl_reply("436", "Bad Identity-Info");
drop;
}
if (!vrfy_check_date()) {
sl_reply("403", "Outdated Date header value");
drop;
}
if (!vrfy_get_certificate()) {
sl_reply("436", "Bad Identity-Info");
drop;
}
if (!vrfy_check_certificate()) {
sl_reply("437", "Unsupported Certificate");
drop;
}
if (!vrfy_check_msgvalidity()) {
sl_reply("438", "Invalid Identity Header");
drop;
}
if (!vrfy_check_callid()) {
sl_reply("403", "Message is replayed");
drop;
}
}
]]></programlisting>
</refsect1>
<refsect1 id="mdoule.auth_identity.how-it-works">
<title>The SIP Identity Mechanism</title>
<para>
The SIP Identity Mechanism is defined in RFC 4474 "Enhancements for
Authenticated Identity Management in the Session Initiation Protocol
(SIP)". Its main purpose is to affirm the identity of the originator
of a request as stated in the From header field of the request.
While basic SIP provides a mechanism for a user agent to proof its
authenticity to the proxy serving the domain of the address used
by the user agent, no such mechanism exists to proof the authenticity
to other proxies or end points. The SIP Identity Mechanism mends this
oversight.
</para>
<para>
The mechanism allows a proxy to cryptographically sign a message as
authentic before sending it to another proxy. It does so after
making sure the sender actually is who he claims and is allowed to
use the address in the context of the message.
</para>
<para>
If the proxy is satisfied, it creates two header fields: Identity and
Identity-Info. The Identity header field contains a signed hash over
the following components of the message:
</para>
<itemizedlist>
<listitem>
the address given in the From header field,
</listitem>
<listitem>
the address given in the To header field,
</listitem>
<listitem>
the Call-ID,
</listitem>
<listitem>
the content of the CSeq header field,
</listitem>
<listitem>
the content of the Date header field,
</listitem>
<listitem>
the address given in the Contact header field if present, and
</listitem>
<listitem>
the body of the message.
</listitem>
</itemizedlist>
<para>
The hash is signed with a certificate for the domain. A URL pointing
to a place where an interested party can download a copy of the
certificate is placed into the Identity-Info header field.
</para>
<para>
If the message arrives at a proxy or user agent that wishes to verify
the authenticity, this device downloads the certificate and itself
forms the hash over the above components. If both hashes match, the
message has been authenticated by the proxy of the domain of the
certificate and has not been tempered with on the way.
</para>
</refsect1>
<refsect1 id="modules.auth_identity.credentials">
<title>Certificates</title>
<para>
In order to use the <command>auth_identity</command> module, you need a
certificate for your domain. There is two options, how to get one: you
buy one from a certification authority or you create your own
certification authority and use a self-signed certificate. If you plan
to provide real inter-domain calls for your domain, you should pick the
first option. Although it is more expensive, it guarantees proper
interaction between domains.
</para>
<para>
Either way, you will end up with a private key and a certificate which
includes the public key for that private key. You can use the same key
and certificate as for the TLS encrypted SIP transport. Because of
this, details on the process of acquiring them can be found in
<serdoc:module>tls</serdoc:module>.
</para>
<para>
Once you have the certificate and private key, you set the module
parameter
<serdoc:modparam module="auth_identity">certificate_path</serdoc:modparam>
to point to the file containing the certificate and
<serdoc:modparam module="auth_identity">privatekey_path</serdoc:modparam>
to point to the file with the private key.
</para>
<para>
Finally, you have to put a public version of your certificate onto
a web server somewhere. This version must be DER encoded and,
obviously, must not contain the private key. You can create this
by issuing
</para>
<programlisting><![CDATA[
# openssl x509 -in your_certificate.crt -outform der -out your_certificate.der
]]></programlisting>
<para>
You then place the DER encoded certificate into a publicly
available directory on your webserver and state the URL to the
file in the parameter
<serdoc:modparam module="auth_identity">certificate_url</serdoc:modparam>.
</para>
</refsect1>
<!--
Compilation sections only go into the Admin Guide since we assume
that if you read a manpage you already have installed the module.
-->
<refsect1 role="admin-guide">
<title>Compilation</title>
<para>
This <command>auth_identity</command> module needs the following
headers and libraries:
</para>
<itemizedlist>
<listitem>
<emphasis>OpenSSL</emphasis> (version 0.9.8 or higher) for
cryptographic functions,
</listitem>
<listitem>
<emphasis>libcURL</emphasis> for HTTP, HTTPS functions.
</listitem>
</itemizedlist>
<para>
If you'd like to use the <emphasis>TLS</emphasis> module, too,
you will have to change <varname>LIB</varname> variable in the
Makefile to the value that is by default commented out.
</para>
</refsect1>
<refsect1>
<title>Known Limitations</title>
<para>
Both authorizer and verifier currently only support SIP requests
except for responses to CANCEL and REGISTER requests.
</para>
<para>
The verifier does not support the subjectAltName extension of
certificates.
</para>
</refsect1>
<refsect1 role="manpage">
<title>Authors</title>
<para>
Written by Gergely Kovacs and Martin Hoffmann.
</para>
</refsect1>
<refsect1 role="manpage">
<title>See Also</title>
<simplelist type="inline">
<member><serdoc:sbin>ser</serdoc:sbin></member>
<member><serdoc:file>ser.cfg</serdoc:file></member>
</simplelist>
</refsect1>
</refentry>
<!-- vim:sw=2 sta et sts=2 ai
-->

@ -190,11 +190,11 @@ modparam("auth_identity","cainfo_path","/etc/ssl/certs/ca-certificates.crt")
</section>
<section id="accept_pem_certs">
<title><varname>accept_pem_certs</varname> ([0|1])</title>
<title><varname>accept_pem_certs</varname> (int)</title>
<para>Note: this parameter is for verifier service.</para>
<para>
Enables the acquired certificate processing if it is in PEM
format.
format. Value can be 0 or 1.
</para>
<para>
This parameter is optional. The default value is "0".

@ -112,59 +112,59 @@ static cmd_export_t cmds[]={
{"append_branch", (cmd_function)w_append_branch, 0, 0,
0, REQUEST_ROUTE | FAILURE_ROUTE },
{"append_branch", (cmd_function)w_append_branch, 1, fixup_spve_null,
0, REQUEST_ROUTE | FAILURE_ROUTE },
fixup_free_spve_null, REQUEST_ROUTE | FAILURE_ROUTE },
{"append_branch", (cmd_function)w_append_branch, 2, fixup_spve_spve,
0, REQUEST_ROUTE | FAILURE_ROUTE },
fixup_free_spve_spve, REQUEST_ROUTE | FAILURE_ROUTE },
{"send_udp", (cmd_function)w_send_udp, 0, 0,
0, REQUEST_ROUTE | FAILURE_ROUTE },
{"send_udp", (cmd_function)w_send_udp, 1, fixup_spve_null,
0, REQUEST_ROUTE | FAILURE_ROUTE },
fixup_free_spve_null, REQUEST_ROUTE | FAILURE_ROUTE },
{"send_tcp", (cmd_function)w_send_tcp, 0, 0,
0, REQUEST_ROUTE | FAILURE_ROUTE },
{"send_tcp", (cmd_function)w_send_tcp, 1, fixup_spve_null,
0, REQUEST_ROUTE | FAILURE_ROUTE },
fixup_free_spve_null, REQUEST_ROUTE | FAILURE_ROUTE },
{"send_data", (cmd_function)w_send_data, 2, fixup_spve_spve,
0, ANY_ROUTE },
fixup_free_spve_spve, ANY_ROUTE },
{"sendx", (cmd_function)w_sendx, 3, fixup_spve_all,
0, ANY_ROUTE },
fixup_free_spve_all, ANY_ROUTE },
{"is_incoming", (cmd_function)nio_check_incoming, 0, 0,
0, ANY_ROUTE },
{"msg_iflag_set", (cmd_function)w_msg_iflag_set, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{"msg_iflag_reset", (cmd_function)w_msg_iflag_reset, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{"msg_iflag_is_set", (cmd_function)w_msg_iflag_is_set, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{"file_read", (cmd_function)w_file_read, 2, fixup_file_op,
0, ANY_ROUTE },
{"file_write", (cmd_function)w_file_write, 2, fixup_spve_spve,
0, ANY_ROUTE },
{"setxflag", (cmd_function)w_setxflag, 1,fixup_igp_null,
0, ANY_ROUTE },
{"resetxflag", (cmd_function)w_resetxflag, 1,fixup_igp_null,
0, ANY_ROUTE },
{"isxflagset", (cmd_function)w_isxflagset, 1,fixup_igp_null,
0, ANY_ROUTE },
fixup_free_spve_spve, ANY_ROUTE },
{"setxflag", (cmd_function)w_setxflag, 1, fixup_igp_null,
fixup_free_igp_null, ANY_ROUTE },
{"resetxflag", (cmd_function)w_resetxflag, 1, fixup_igp_null,
fixup_free_igp_null, ANY_ROUTE },
{"isxflagset", (cmd_function)w_isxflagset, 1, fixup_igp_null,
fixup_free_igp_null, ANY_ROUTE },
{"set_send_socket", (cmd_function)w_set_send_socket, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{"set_send_socket_name", (cmd_function)w_set_send_socket_name, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{"set_recv_socket", (cmd_function)w_set_recv_socket, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{"set_recv_socket_name", (cmd_function)w_set_recv_socket_name, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{"set_source_address", (cmd_function)w_set_source_address, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{"via_add_srvid", (cmd_function)w_via_add_srvid, 1, fixup_igp_null,
0, ANY_ROUTE },
fixup_free_igp_null, ANY_ROUTE },
{"via_add_xavp_params", (cmd_function)w_via_add_xavp_params, 1, fixup_igp_null,
0, ANY_ROUTE },
fixup_free_igp_null, ANY_ROUTE },
{"via_use_xavp_fields", (cmd_function)w_via_use_xavp_fields, 1, fixup_igp_null,
0, ANY_ROUTE },
fixup_free_igp_null, ANY_ROUTE },
{"is_faked_msg", (cmd_function)w_is_faked_msg, 0, 0,
0, ANY_ROUTE },
{"is_socket_name", (cmd_function)w_is_socket_name, 1, fixup_spve_null,
0, ANY_ROUTE },
fixup_free_spve_null, ANY_ROUTE },
{0, 0, 0, 0, 0, 0}
};

@ -730,7 +730,7 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
type=*p & 0xf;
len=*p>>4;
p++;
if (len & 8){
if ((type!=BINRPC_T_DOUBLE) && (len & 8)){
end_tag=1; /* possible end mark for array or structs */
/* we have to read len bytes and use them as the new len */
p=binrpc_read_int(&len, len&7, p, end, err);

@ -213,7 +213,8 @@ modparam("db_cluster", "max_query_length", 5)
modparam("db_cluster", "connection",
"c1=>mysql://kamailio:kamailiorw@localhost/kamailio1")
modparam("db_cluster", "connection",
"c2=>mysql://kamailio:kamailiorw@localhost/kamailio2")
"c2=>mysql://kamailio:kamailiorw@remotehost/kamailio2")
modparam("db_cluster", "cluster", "k1=>c1=9r9p;c2=9r9p")
modparam("acc", "db_url", "cluster://k1")

@ -204,9 +204,10 @@ modparam("db_cluster", "max_query_length", 5)
<programlisting format="linespecific">
...
modparam("db_cluster", "connection",
"c1=&gt;&defaultdb;1")
"c1=&gt;mysql://kamailio:kamailiorw@localhost/kamailio1")
modparam("db_cluster", "connection",
"c2=&gt;&defaultdb;2")
"c2=&gt;mysql://kamailio:kamailiorw@remotehost/kamailio2")
modparam("db_cluster", "cluster", "k1=&gt;c1=9r9p;c2=9r9p")
modparam("acc", "db_url", "cluster://k1")

@ -446,7 +446,10 @@ 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_vardup = get_dlg_vardup;
dlgb->get_dlg_varstatus = get_dlg_varstatus;
dlgb->get_dlg = dlg_get_msg_dialog;
dlgb->release_dlg = dlg_release;
return 1;
@ -792,7 +795,7 @@ static int child_init(int rank)
/* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
* for the rest of the processes will be the same as DB_MODE_NONE */
if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_POSTCHILDINIT)
dlg_db_mode = DB_MODE_NONE;
/* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
@ -1974,7 +1977,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;
@ -2029,14 +2032,14 @@ static int ki_dlg_var_rm(sip_msg_t *msg, str *name)
static int ki_dlg_var_is_null(sip_msg_t *msg, str *name)
{
dlg_cell_t *dlg;
str *pval;
int ret;
dlg = dlg_get_msg_dialog(msg);
if(dlg==NULL) {
return 1;
}
pval = get_dlg_variable(dlg, name);
if(pval==NULL || pval->s==NULL) {
ret = get_dlg_varstatus(dlg, name);
if(ret==1) {
return 1;
}
return -1;

@ -42,7 +42,7 @@ struct dlg_cb_params {
};
/* callback function prototype */
typedef void (dialog_cb) (struct dlg_cell* dlg, int type,
typedef void (dialog_cb) (struct dlg_cell* dlg, int type,
struct dlg_cb_params * params);
/* function to free the callback param */
typedef void (param_free_cb) (void *param);
@ -54,8 +54,17 @@ typedef int (*register_dlgcb_f)(struct dlg_cell* dlg, int cb_types,
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,
/* method to get a variable value reference from a dialog */
typedef str* (*get_dlg_varref_f)( struct dlg_cell* dlg,
str* key);
/* method to get a variable value static-buffer duplicate from a dialog */
typedef int (*get_dlg_varval_f)( struct dlg_cell* dlg,
str* key, str* val);
/* method to get a variable value pkg-allocated duplicate from a dialog */
typedef int (*get_dlg_vardup_f)( struct dlg_cell* dlg,
str* key, str* val);
/* method to get if a variable value is set or not from a dialog */
typedef int (*get_dlg_varstatus_f)( struct dlg_cell* dlg,
str* key);
#define CONFIRMED_DIALOG_STATE 1

@ -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;

@ -43,12 +43,15 @@ typedef struct dlg_cell *(*get_dlg_f)(struct sip_msg *msg);
typedef void (*release_dlg_f)(struct dlg_cell *dlg);
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_f get_dlg;
release_dlg_f release_dlg;
register_dlgcb_f register_dlgcb;
terminate_dlg_f terminate_dlg;
set_dlg_variable_f set_dlg_var;
get_dlg_varref_f get_dlg_varref;
get_dlg_varval_f get_dlg_varval;
get_dlg_vardup_f get_dlg_vardup;
get_dlg_varstatus_f get_dlg_varstatus;
get_dlg_f get_dlg;
release_dlg_f release_dlg;
};

@ -279,12 +279,15 @@ 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;
if( !dlg || !key || key->len > strlen(key->s))
{
if( !dlg || !key || key->len<=0) {
LM_ERR("BUG - bad parameters\n");
return NULL;
@ -297,10 +300,139 @@ 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<=0) {
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;
}
/**
* set *val to a pkg-allocated buffer where the dlg value is cloned
* - val->s has to be pkg-freed after use
*/
int get_dlg_vardup(struct dlg_cell *dlg, str *key, str *val)
{
str *var = NULL;
val->s = NULL;
val->len = 0;
if( !dlg || !key || key->len<=0) {
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 && var->s) {
val->s = (char*)pkg_malloc(var->len + 1);
if(val->s!=NULL) {
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(val->s) {
return 0;
}
return -2;
}
/**
* return the status if the dlg variable value is set or not
* - 1 - variable is set
* - 0 - variable is not set
*/
int get_dlg_varstatus(struct dlg_cell *dlg, str *key)
{
str* var = NULL;
int ret = 0;
if( !dlg || !key || key->len<=0) {
LM_ERR("BUG - bad parameters\n");
return 0;
}
dlg_lock(d_table, &(d_table->entries[dlg->h_entry]));
var = get_dlg_variable_unsafe(dlg, key);
if(var && var->s) {
ret = 1;
}
dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
return ret;
}
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 +458,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;

@ -25,7 +25,7 @@
* \ingroup dialog
* Module: \ref dialog
*/
#ifndef _DLG_VAR_H_
#define _DLG_VAR_H_
@ -59,9 +59,15 @@ 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 get_dlg_vardup(dlg_cell_t *dlg, str *key, str *val);
int get_dlg_varstatus(dlg_cell_t *dlg, str *key);
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);

@ -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);
}
/**
*
*/

@ -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);
@ -2680,6 +2694,11 @@ int ds_remove_dst(int group, str *address)
setn = 0;
dp = pack_dest(*address, 0, 0, NULL, 0);
if(dp==NULL) {
LM_ERR("failed to pack address: %d %.*s\n", group,
address->len, address->s);
return -1;
}
filter_arg.setid = group;
filter_arg.dest = dp;
filter_arg.setn = &setn;

@ -1247,7 +1247,7 @@ int ds_ping_check_rplcode(int code)
}
} else {
/* reply class */
if(((*ds_ping_reply_codes)[i] / 100) == code) {
if((*ds_ping_reply_codes)[i] == code / 100) {
return 1;
}
}

@ -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

@ -47,15 +47,25 @@
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>

@ -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++;

@ -180,6 +180,8 @@ void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
STR_SHM_DUP(*passed_rx_session_id, aaa->sessionId->data, "cb_passed_rx_session_id");
LM_DBG("passed rx session id [%.*s]", passed_rx_session_id->len, passed_rx_session_id->s);
dlgb.register_dlgcb_nodlg( data->dlg, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED | DLGCB_RESPONSE_WITHIN | DLGCB_CONFIRMED | DLGCB_FAILED, callback_dialog, (void*) (passed_rx_session_id), free_dialog_data);
} else {
dlgb.release_dlg(data->dlg);
}
result = CSCF_RETURN_TRUE;
} else {

@ -131,45 +131,47 @@ static pv_export_t mod_pvs[] = {
*/
static cmd_export_t cmds[] =
{
{ "is_ip", (cmd_function)w_is_ip, 1, fixup_spve_null, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "is_pure_ip", (cmd_function)w_is_pure_ip, 1, fixup_spve_null, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "is_ipv4", (cmd_function)w_is_ipv4, 1, fixup_spve_null, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "is_ipv6", (cmd_function)w_is_ipv6, 1, fixup_spve_null, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "is_ipv6_reference", (cmd_function)w_is_ipv6_reference, 1, fixup_spve_null, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "ip_type", (cmd_function)w_ip_type, 1, fixup_spve_null, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "is_ip", (cmd_function)w_is_ip, 1,
fixup_spve_null, fixup_free_spve_null, ANY_ROUTE },
{ "is_pure_ip", (cmd_function)w_is_pure_ip, 1,
fixup_spve_null, fixup_free_spve_null, ANY_ROUTE },
{ "is_ipv4", (cmd_function)w_is_ipv4, 1,
fixup_spve_null, fixup_free_spve_null, ANY_ROUTE },
{ "is_ipv6", (cmd_function)w_is_ipv6, 1,
fixup_spve_null, fixup_free_spve_null, ANY_ROUTE },
{ "is_ipv6_reference", (cmd_function)w_is_ipv6_reference, 1,
fixup_spve_null, fixup_free_spve_null, ANY_ROUTE },
{ "ip_type", (cmd_function)w_ip_type, 1,
fixup_spve_null, fixup_free_spve_null, ANY_ROUTE },
{ "detailed_ipv4_type", (cmd_function)w_detailed_ipv4_type, 2,
fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
{ "detailed_ipv6_type", (cmd_function)w_detailed_ipv6_type, 2,
fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
{ "detailed_ip_type", (cmd_function)w_detailed_ip_type, 2,
fixup_detailed_ip_type, fixup_free_detailed_ip_type, ANY_ROUTE },
{ "compare_ips", (cmd_function)w_compare_ips, 2, fixup_spve_spve, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "compare_pure_ips", (cmd_function)w_compare_pure_ips, 2, fixup_spve_spve, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "is_ip_rfc1918", (cmd_function)w_is_ip_rfc1918, 1, fixup_spve_null, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "is_in_subnet", (cmd_function)w_ip_is_in_subnet, 2, fixup_spve_spve, 0,
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
{ "dns_sys_match_ip", (cmd_function)w_dns_sys_match_ip, 2, fixup_spve_spve, 0,
ANY_ROUTE },
{ "dns_int_match_ip", (cmd_function)w_dns_int_match_ip, 2, fixup_spve_spve, 0,
ANY_ROUTE },
{ "dns_query", (cmd_function)w_dns_query, 2, fixup_spve_spve, 0,
ANY_ROUTE },
{ "srv_query", (cmd_function)w_srv_query, 2, fixup_spve_spve, 0,
ANY_ROUTE },
{ "naptr_query", (cmd_function)w_naptr_query, 2, fixup_spve_spve, 0,
ANY_ROUTE },
{ "dns_set_local_ttl", (cmd_function)w_dns_set_local_ttl, 1, fixup_igp_null,
fixup_free_igp_null, ANY_ROUTE },
{ "compare_ips", (cmd_function)w_compare_ips, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE },
{ "compare_pure_ips", (cmd_function)w_compare_pure_ips, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE },
{ "is_ip_rfc1918", (cmd_function)w_is_ip_rfc1918, 1,
fixup_spve_null, fixup_free_spve_null, ANY_ROUTE },
{ "is_in_subnet", (cmd_function)w_ip_is_in_subnet, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE },
{ "dns_sys_match_ip", (cmd_function)w_dns_sys_match_ip, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE },
{ "dns_int_match_ip", (cmd_function)w_dns_int_match_ip, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE },
{ "dns_query", (cmd_function)w_dns_query, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE },
{ "srv_query", (cmd_function)w_srv_query, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE },
{ "naptr_query", (cmd_function)w_naptr_query, 2,
fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE },
{ "dns_set_local_ttl", (cmd_function)w_dns_set_local_ttl, 1,
fixup_igp_null, fixup_free_igp_null, ANY_ROUTE },
{ "bind_ipops", (cmd_function)bind_ipops, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0 }
};
@ -230,8 +232,7 @@ static int fixup_detailed_ip_type(void** param, int param_no)
static int fixup_free_detailed_ip_type(void** param, int param_no)
{
if (param_no == 1) {
//LM_WARN("free function has not been defined for spve\n");
return 0;
return fixup_free_spve_null(param, 1);
}
if (param_no == 2) {

@ -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) {

@ -16,6 +16,12 @@ XML2CFG=$(shell \
echo 'pkg-config libxml-2.0'; \
fi)
endif
CURL_BUILDER=$(shell \
if pkg-config --exists libcurl; then \
echo 'pkg-config libcurl'; \
else \
which curl-config; \
fi)
endif
ifneq ($(XML2CFG),)
@ -26,4 +32,12 @@ else
LIBS+=-L$(LOCALBASE)/lib -lxml2
endif
ifneq ($(CURL_BUILDER),)
DEFS += $(shell $(CURL_BUILDER) --cflags )
LIBS += $(shell $(CURL_BUILDER) --libs)
else
DEFS+=-I$(LOCALBASE)/include
LIBS+=-L$(LOCALBASE)/lib -lcurl
endif
include ../../Makefile.modules

@ -1,7 +1,7 @@
/*
* lost module functions
*
* Copyright (C) 2021 Wolfgang Kampichler
* Copyright (C) 2022 Wolfgang Kampichler
* DEC112, FREQUENTIS AG
*
* This file is part of Kamailio, a free SIP server.
@ -1123,16 +1123,24 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
switch(fsrdata->category) {
case RESPONSE:
if(fsrdata->uri != NULL) {
/* get the first uri element */
if((tmp.s = fsrdata->uri->value) != NULL) {
tmp.len = strlen(fsrdata->uri->value);
if(pkg_str_dup(&uri, &tmp) < 0) {
LM_ERR("could not copy: [%.*s]\n", tmp.len, tmp.s);
goto err;
}
/* get the first sips uri element ... */
if(lost_search_response_list(&fsrdata->uri, &tmp.s, SIPS_S) > 0) {
tmp.len = strlen(tmp.s);
/* or the first sip uri element ... */
} else if(lost_search_response_list(&fsrdata->uri, &tmp.s, SIP_S) > 0) {
tmp.len = strlen(tmp.s);
/* or return error if nothing found */
} else {
LM_ERR("sip/sips uri not found: [%.*s]\n", ret.len, ret.s);
goto err;
}
/* copy uri string */
if(pkg_str_dup(&uri, &tmp) < 0) {
LM_ERR("could not copy: [%.*s]\n", tmp.len, tmp.s);
goto err;
}
} else {
LM_ERR("uri not found: [%.*s]\n", ret.len, ret.s);
LM_ERR("uri element not found: [%.*s]\n", ret.len, ret.s);
goto err;
}
if(fsrdata->mapping != NULL) {

@ -1,7 +1,7 @@
/*
* lost module LoST response parsing functions
*
* Copyright (C) 2021 Wolfgang Kampichler
* Copyright (C) 2022 Wolfgang Kampichler
* DEC112, FREQUENTIS AG
*
* This file is part of Kamailio, a free SIP server.
@ -353,6 +353,40 @@ void lost_reverse_response_list(p_lost_list_t *head)
*head = prev;
}
/*
* lost_search_response_list(list, value, search)
* looks for search string in list object and returns pointer if found
*/
int lost_search_response_list(p_lost_list_t *list, char **val, const char *str)
{
p_lost_list_t cur;
p_lost_list_t next;
if(*list == NULL)
return 0;
if(str == NULL)
return 0;
LM_DBG("### list data search [%s]\n", str);
next = *list;
while((cur = next) != NULL) {
next = cur->next;
if(cur->value != NULL) {
if(strncasecmp(cur->value, str, strlen(str)) == 0) {
*val = cur->value;
LM_DBG("###\t[%s] found\n", cur->value);
return 1;
}
}
}
return 0;
}
/*
* lost_delete_response_list(list)
* removes response list from private memory

@ -1,7 +1,7 @@
/*
* lost module LoST response parsing functions
*
* Copyright (C) 2021 Wolfgang Kampichler
* Copyright (C) 2022 Wolfgang Kampichler
* DEC112, FREQUENTIS AG
*
* This file is part of Kamailio, a free SIP server.
@ -56,6 +56,9 @@
#define ERRORS_NODE (const char *)"errors"
#define SIP_S (const char *)"sip:"
#define SIPS_S (const char *)"sips:"
#define HELD_RESPONSE_REFERENCE 1
#define HELD_RESPONSE_VALUE 2
@ -133,4 +136,7 @@ int is_cid_laquot(char *);
int is_http_laquot(char *);
int is_https_laquot(char *);
/* list search */
int lost_search_response_list(p_lost_list_t *, char **, const char *);
#endif

@ -265,13 +265,13 @@ error:
static int misctest_message_init(void)
{
char tbuf[BUF_SIZE];
char tbuf[4*BUF_SIZE];
FILE *f;
long fsize;
sip_msg_t tmsg = { };
if(misctest_message_data.s!=0 && misctest_message_data.len>0) {
if(misctest_message_data.len>=BUF_SIZE-2) {
if(misctest_message_data.len>=4*BUF_SIZE-2) {
LM_ERR("the data is too big\n");
return -1;
}
@ -297,7 +297,7 @@ static int misctest_message_init(void)
}
fseek(f, 0, SEEK_SET);
if(fsize>=BUF_SIZE-2) {
if(fsize>=4*BUF_SIZE-2) {
LM_ERR("the file data is too big\n");
fclose(f);
return -1;

@ -270,20 +270,21 @@ int msrp_cmap_save(msrp_frame_t *mf)
} else {
for(itb=_msrp_cmap_head->cslots[idx].first; itb; itb=itb->next)
{
if(itb->citemid>it->citemid || itb->next==NULL) {
if(itb->next==NULL) {
itb->next=it;
it->prev = itb;
if(itb->citemid>it->citemid) {
/* insert before current item */
it->next = itb;
if(itb->prev==NULL) {
_msrp_cmap_head->cslots[idx].first = it;
} else {
it->next = itb;
if(itb->prev==NULL) {
_msrp_cmap_head->cslots[idx].first = it;
} else {
itb->prev->next = it;
}
it->prev = itb->prev;
itb->prev = it;
itb->prev->next = it;
}
it->prev = itb->prev;
itb->prev = it;
break;
} else if(itb->next==NULL) {
/* insert after last item */
itb->next=it;
it->prev = itb;
break;
}
}

@ -731,9 +731,11 @@ if(is_rfc1918("$rd")) {
5.9. set_contact_alias([trim])
Adds an “;alias=ip~port~transport” parameter to the contact URI
containing the received ip, port, and transport protocol. The new
contact URI is immediately visible to other modules in the way the
fix_nated_contact() does it.
containing the received ip, port, and transport protocol. The update of
contact URI is signaled to a few other modules in the way the
fix_nated_contact() does it by using the internal flags. The new value
is not visible to pseudo-variables and it does not change the SIP
message buffer.
Meaning of parameters:
* trim - by default, set_contact_alias() will not detect and trim an

@ -878,8 +878,10 @@ if(is_rfc1918("$rd")) {
<para>
Adds an <quote>;alias=ip~port~transport</quote> parameter to the
contact URI containing the received ip, port, and transport protocol.
The new contact URI is immediately visible to other modules in the
way the <function>fix_nated_contact()</function> does it.
The update of contact URI is signaled to a few other modules in the
way the <function>fix_nated_contact()</function> does it by using the
internal flags. The new value is not visible to pseudo-variables and it
does not change the SIP message buffer.
</para>
<para>Meaning of parameters:</para>
<itemizedlist>

@ -35,6 +35,7 @@ Emmanuel Schmidbauer
4.1. nats_url (str)
4.2. num_publish_workers (int)
4.3. subject_queue_group (str)
4.4. event_callback (str)
5. Functions
@ -48,9 +49,10 @@ Emmanuel Schmidbauer
1.1. Set nats_url parameter
1.2. Set num_publish_workers parameter
1.3. Set subject_queue_group parameter
1.4. nats_publish usage
1.5. Example usage of $natsData pseudo variable
1.6. Define the event routes
1.4. Set event_callback parameter
1.5. nats_publish usage
1.6. Example usage of $natsData pseudo variable
1.7. Define the event routes
Chapter 1. Admin Guide
@ -68,6 +70,7 @@ Chapter 1. Admin Guide
4.1. nats_url (str)
4.2. num_publish_workers (int)
4.3. subject_queue_group (str)
4.4. event_callback (str)
5. Functions
@ -115,6 +118,7 @@ Chapter 1. Admin Guide
4.1. nats_url (str)
4.2. num_publish_workers (int)
4.3. subject_queue_group (str)
4.4. event_callback (str)
4.1. nats_url (str)
@ -161,6 +165,24 @@ modparam("nats", "subject_queue_group", "MyQueue1:2021")
modparam("nats", "subject_queue_group", "MyQueue2:2021")
...
4.4. event_callback (str)
Name of the KEMI function to be executed instead of the event route.
Default value is not set.
Example 1.4. Set event_callback parameter
...
modparam("nats", "event_callback", "ksr_nats_event")
-- event callback function implemented in Lua
function ksr_nats_event(evname)
KSR.info("===== nats module received event: " .. evname ..
", data:" .. KSR.pv.gete('$natsData') .. "\n");
return 1;
end
...
5. Functions
5.1. nats_publish(subject, payload)
@ -169,7 +191,7 @@ modparam("nats", "subject_queue_group", "MyQueue2:2021")
Publishes the payload to subject.
Example 1.4. nats_publish usage
Example 1.5. nats_publish usage
...
$var(my_info) = "$ci=" + $ci + " $fU=" + $fU;
nats_publish("mysubject", "$var(my_info)"); # publish $var(my_info) to "mysubjec
@ -178,7 +200,7 @@ t"
6. Pseudo Variables
Example 1.5. Example usage of $natsData pseudo variable
Example 1.6. Example usage of $natsData pseudo variable
...
xlog("L_INFO", "received payload $natsData");
}
@ -191,7 +213,7 @@ t"
received payload. The name of the event-route name must match the
subject of the message.
Example 1.6. Define the event routes
Example 1.7. Define the event routes
...
modparam("nats", "subject_queue_group", "Kamailio-World:2021")
modparam("nats", "subject_queue_group", "MyQueue1:2021")

@ -27,6 +27,7 @@
#include <nats/nats.h>
#include <uv.h>
#include "../../core/str.h"
#define NATS_DEFAULT_URL "nats://localhost:4222"
#define NATS_MAX_SERVERS 10
@ -63,6 +64,8 @@ typedef struct _init_nats_server
typedef struct _nats_on_message
{
int rt;
char *_evname;
str evname;
} nats_on_message, *nats_on_message_ptr;
struct nats_consumer_worker

@ -173,6 +173,37 @@ modparam("nats", "subject_queue_group", "Kamailio-World:2020")
modparam("nats", "subject_queue_group", "Kamailio-World:2021") // this will create two processes for the Kamailio-World subject
modparam("nats", "subject_queue_group", "MyQueue1:2021")
modparam("nats", "subject_queue_group", "MyQueue2:2021")
...
</programlisting>
</example>
</section>
<section>
<title>
<varname>event_callback</varname>
(str)
</title>
<para>
Name of the KEMI function to be executed instead of the event route.
</para>
<para>
<emphasis>Default value is not set.</emphasis>
</para>
<example>
<title>
Set
<varname>event_callback</varname>
parameter
</title>
<programlisting format="linespecific">
...
modparam("nats", "event_callback", "ksr_nats_event")
-- event callback function implemented in Lua
function ksr_nats_event(evname)
KSR.info("===== nats module received event: " .. evname ..
", data:" .. KSR.pv.gete('$natsData') .. "\n");
return 1;
end
...
</programlisting>
</example>
@ -254,4 +285,4 @@ event_route[nats:MyQueue1]
</section>
</chapter>
</chapter>

@ -24,6 +24,8 @@
#include "defs.h"
#include "nats_mod.h"
#include "nats_pub.h"
#include "../../core/kemi.h"
MODULE_VERSION
@ -38,6 +40,7 @@ char *eventData = NULL;
int *nats_pub_worker_pipes_fds = NULL;
int *nats_pub_worker_pipes = NULL;
static str nats_event_callback = STR_NULL;
static nats_evroutes_t _nats_rts;
@ -50,7 +53,10 @@ static param_export_t params[] = {
{"nats_url", PARAM_STRING | USE_FUNC_PARAM, (void *)_init_nats_server_url_add},
{"num_publish_workers", INT_PARAM, &nats_pub_workers_num},
{"subject_queue_group", PARAM_STRING | USE_FUNC_PARAM,
(void *)_init_nats_sub_add}};
(void *)_init_nats_sub_add},
{"event_callback", PARAM_STR, &nats_event_callback},
{0, 0, 0}
};
static cmd_export_t cmds[] = {{"nats_publish", (cmd_function)w_nats_publish_f,
2, fixup_publish_get_value,
@ -73,16 +79,9 @@ static void onMsg(
natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
nats_on_message_ptr on_message = (nats_on_message_ptr)closure;
char *s = (char *)natsMsg_GetSubject(msg);
char *data = (char *)natsMsg_GetData(msg);
if(on_message->rt < 0 || event_rt.rlist[on_message->rt] == NULL) {
LM_INFO("event-route [nats:%s] does not exist\n", s);
goto end;
}
eventData = data;
nats_run_cfg_route(on_message->rt);
end:
nats_run_cfg_route(on_message->rt, &on_message->evname);
eventData = NULL;
natsMsg_Destroy(msg);
}
@ -90,22 +89,25 @@ end:
static void connectedCB(natsConnection *nc, void *closure)
{
char url[NATS_URL_MAX_SIZE];
str evname = str_init("nats:connected");
natsConnection_GetConnectedUrl(nc, url, sizeof(url));
nats_run_cfg_route(_nats_rts.connected);
nats_run_cfg_route(_nats_rts.connected, &evname);
}
static void disconnectedCb(natsConnection *nc, void *closure)
{
char url[NATS_URL_MAX_SIZE];
str evname = str_init("nats:disconnected");
natsConnection_GetConnectedUrl(nc, url, sizeof(url));
nats_run_cfg_route(_nats_rts.disconnected);
nats_run_cfg_route(_nats_rts.disconnected, &evname);
}
static void reconnectedCb(natsConnection *nc, void *closure)
{
char url[NATS_URL_MAX_SIZE];
str evname = str_init("nats:connected");
natsConnection_GetConnectedUrl(nc, url, sizeof(url));
nats_run_cfg_route(_nats_rts.connected);
nats_run_cfg_route(_nats_rts.connected, &evname);
}
static void closedCB(natsConnection *nc, void *closure)
@ -247,9 +249,13 @@ int init_worker(
if(rt < 0 || event_rt.rlist[rt] == NULL) {
LM_INFO("route [%s] does not exist\n", routename);
worker->on_message->rt = -1;
return 0;
} else {
worker->on_message->rt = rt;
}
worker->on_message->rt = rt;
worker->on_message->_evname = malloc(buffsize);
strcpy(worker->on_message->_evname, routename);
worker->on_message->evname.s = worker->on_message->_evname;
worker->on_message->evname.len = strlen(worker->on_message->_evname);
worker->nc = nc;
return 0;
}
@ -298,7 +304,10 @@ int _nats_pub_worker_proc(
!= NATS_OK) {
LM_ERR("could not connect to nats servers [%s]\n",
natsStatus_GetText(s));
} else {
connectedCB(worker->nc->conn, NULL);
}
s = natsOptions_SetEventLoop(worker->nc->opts, (void *)worker->uvLoop,
natsLibuv_Attach, natsLibuv_Read, natsLibuv_Write,
natsLibuv_Detach);
@ -562,6 +571,9 @@ int nats_destroy_workers()
}
}
if(worker->on_message != NULL) {
if (worker->on_message->_evname) {
free(worker->on_message->_evname);
}
shm_free(worker->on_message);
}
shm_free(worker);
@ -654,15 +666,18 @@ int _init_nats_sub_add(modparam_t type, void *val)
/**
* Invoke a event route block
*/
int nats_run_cfg_route(int rt)
int nats_run_cfg_route(int rt, str *evname)
{
struct run_act_ctx ctx;
sr_kemi_eng_t *keng = NULL;
sip_msg_t *fmsg;
sip_msg_t tmsg;
keng = sr_kemi_eng_get();
// check for valid route pointer
if(rt < 0) {
return 0;
if(rt < 0 || !event_rt.rlist[rt]) {
if (keng == NULL) return 0;
}
fmsg = faked_msg_next();
@ -670,6 +685,13 @@ int nats_run_cfg_route(int rt)
fmsg = &tmsg;
set_route_type(EVENT_ROUTE);
init_run_actions_ctx(&ctx);
if (rt < 0 && keng) {
if (sr_kemi_route(keng, fmsg, EVENT_ROUTE,
&nats_event_callback, evname) < 0) {
LM_ERR("error running event route kemi callback\n");
}
return 0;
}
run_top_route(event_rt.rlist[rt], fmsg, 0);
return 0;
}
@ -788,3 +810,35 @@ int nats_pv_get_event_payload(
return eventData == NULL ? pv_get_null(msg, param, res)
: pv_get_strzval(msg, param, res, eventData);
}
/**
*
*/
int ki_nats_publish(sip_msg_t *msg, str *subject, str *payload)
{
return w_nats_publish(msg, *subject, *payload);
}
/**
*
*/
/* clang-format off */
static sr_kemi_t sr_kemi_nats_exports[] = {
{ str_init("nats"), str_init("publish"),
SR_KEMIP_INT, ki_nats_publish,
{ SR_KEMIP_STR, SR_KEMIP_STR, 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 */
/**
*
*/
int mod_register(char *path, int *dlflags, void *p1, void *p2)
{
sr_kemi_modules_add(sr_kemi_nats_exports);
return 0;
}

@ -40,7 +40,7 @@ extern int fixup_publish_get_value(void **param, int param_no);
extern int fixup_publish_get_value_free(void **param, int param_no);
extern void _nats_pub_worker_cb(uv_poll_t *handle, int status, int events);
int nats_run_cfg_route(int rt);
int nats_run_cfg_route(int rt, str *evname);
void nats_init_environment();
int _init_nats_server_url_add(modparam_t type, void *val);

@ -90,6 +90,11 @@ int w_nats_publish_f(sip_msg_t *msg, char *subj, char *payload)
return -1;
}
return w_nats_publish(msg, subj_s, payload_s);
}
int w_nats_publish(sip_msg_t *msg, str subj_s, str payload_s)
{
// round-robin pub workers
pub_worker++;
if(pub_worker >= nats_pub_workers_num) {

@ -38,6 +38,7 @@ typedef struct _nats_pub_delivery
nats_pub_delivery_ptr _nats_pub_delivery_new(str subject, str payload);
void nats_pub_free_delivery_ptr(nats_pub_delivery_ptr ptr);
int w_nats_publish_f(sip_msg_t *msg, char *subj, char *payload);
int w_nats_publish(sip_msg_t *msg, str subj_s, str payload_s);
int fixup_publish_get_value(void **param, int param_no);
int fixup_publish_get_value_free(void **param, int param_no);

@ -1165,6 +1165,7 @@ again:
if(res)
{
if (check_cluster_reply(res, &rsrv)) {
freeReplyObject(res);
goto again;
}
return res;
@ -1175,6 +1176,7 @@ again:
res = redisCommandArgv(rsrv->ctxRedis, argc, argv, argvlen);
if (res) {
if (check_cluster_reply(res, &rsrv)) {
freeReplyObject(res);
goto again;
}
}

@ -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.

@ -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>

@ -69,6 +69,7 @@ void ps_presentity_db_timer_clean(unsigned int ticks, void *param)
int n_db_cols = 0, n_result_cols = 0;
int event_col, etag_col, user_col, domain_col;
int i = 0, num_watchers = 0;
pres_ev_t fake;
presentity_t pres;
str uri = {0, 0}, event, *rules_doc = NULL;
static str query_str;
@ -121,6 +122,7 @@ void ps_presentity_db_timer_clean(unsigned int ticks, void *param)
rows = RES_ROWS(result);
for(i = 0; i < RES_ROW_N(result); i++) {
num_watchers = 0;
values = ROW_VALUES(&rows[i]);
memset(&pres, 0, sizeof(presentity_t));
@ -134,28 +136,33 @@ void ps_presentity_db_timer_clean(unsigned int ticks, void *param)
event.len = strlen(event.s);
pres.event = contains_event(&event, NULL);
if(pres.event == NULL || pres.event->evp == NULL) {
LM_ERR("event not found\n");
goto error;
LM_ERR("event[%.*s] not found\n", STR_FMT(&event));
memset(&fake, 0, sizeof(pres_ev_t));
fake.name = event;
pres.event = &fake;
goto simple_error;
}
if(uandd_to_uri(pres.user, pres.domain, &uri) < 0) {
LM_ERR("constructing uri\n");
goto error;
LM_ERR("constructing uri from [user]=%.*s [domain]=%.*s\n",
STR_FMT(&pres.user), STR_FMT(&pres.domain));
goto simple_error;
}
/* delete from hash table */
if(publ_cache_mode==PS_PCACHE_HYBRID
&& delete_phtable(&uri, pres.event->evp->type) < 0) {
LM_ERR("deleting from presentity hash table\n");
goto error;
LM_ERR("deleting uri[%.*s] event[%.*s] from presentity hash table\n",
STR_FMT(&uri), STR_FMT(&event));
goto simple_error;
}
LM_DBG("found expired publish for [user]=%.*s [domanin]=%.*s\n",
LM_DBG("found expired publish for [user]=%.*s [domain]=%.*s\n",
pres.user.len, pres.user.s, pres.domain.len, pres.domain.s);
if(pres_force_delete == 1) {
if(delete_presentity(&pres, NULL) < 0) {
LM_ERR("Deleting presentity\n");
LM_ERR("Deleting presentity uri[%.*s]\n", STR_FMT(&uri));
goto error;
}
} else if(pres_notifier_processes > 0) {
@ -171,7 +178,7 @@ void ps_presentity_db_timer_clean(unsigned int ticks, void *param)
if(pa_dbf.abort_transaction(pa_db) < 0)
LM_ERR("in abort_transaction\n");
}
goto error;
goto next;
}
if(num_watchers > 0) {
@ -181,12 +188,12 @@ void ps_presentity_db_timer_clean(unsigned int ticks, void *param)
if(pa_dbf.abort_transaction(pa_db) < 0)
LM_ERR("in abort_transaction\n");
}
goto error;
goto next;
}
} else {
if(delete_presentity(&pres, NULL) < 0) {
LM_ERR("Deleting presentity\n");
goto error;
LM_ERR("Deleting presentity uri[%.*s]\n", STR_FMT(&uri));
goto next;
}
}
if(pa_dbf.end_transaction) {
@ -201,22 +208,30 @@ void ps_presentity_db_timer_clean(unsigned int ticks, void *param)
&pres.user, &pres.domain, &rules_doc)
< 0) {
LM_ERR("getting rules doc\n");
goto error;
goto simple_error;
}
if(publ_notify(&pres, uri, NULL, &pres.etag, rules_doc) < 0) {
LM_ERR("sending Notify request\n");
goto error;
}
if(rules_doc) {
if(rules_doc->s)
pkg_free(rules_doc->s);
pkg_free(rules_doc);
rules_doc = NULL;
goto simple_error;
}
}
pkg_free(uri.s);
uri.s = NULL;
simple_error:
if(num_watchers == 0 && delete_presentity(&pres, NULL) < 0) {
LM_ERR("Deleting presentity\n");
}
next:
if(uri.s) {
pkg_free(uri.s);
uri.s = NULL;
}
if(rules_doc) {
if(rules_doc->s) {
pkg_free(rules_doc->s);
}
pkg_free(rules_doc);
rules_doc = NULL;
}
}
} while(db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result) == 1
&& RES_ROW_N(result) > 0);
@ -277,22 +292,23 @@ void ps_ptable_timer_clean(unsigned int ticks, void *param)
pres.etag = ptn->etag;
pres.event = contains_event(&ptn->event, NULL);
if(pres.event == NULL || pres.event->evp == NULL) {
LM_ERR("event not found\n");
goto error;
LM_ERR("event[%.*s] not found\n", STR_FMT(&ptn->event));
goto next;
}
if(uandd_to_uri(pres.user, pres.domain, &uri) < 0) {
LM_ERR("constructing uri\n");
goto error;
LM_ERR("constructing uri from [user]=%.*s [domain]=%.*s\n",
STR_FMT(&pres.user), STR_FMT(&pres.domain));
goto next;
}
LM_DBG("found expired publish for [user]=%.*s [domanin]=%.*s\n",
LM_DBG("found expired publish for [user]=%.*s [domain]=%.*s\n",
pres.user.len, pres.user.s, pres.domain.len, pres.domain.s);
if(pres_force_delete == 1) {
if(ps_ptable_remove(ptn) <0) {
LM_ERR("Deleting presentity\n");
goto error;
goto next;
}
} else {
if(pres.event->get_rules_doc
@ -300,25 +316,28 @@ void ps_ptable_timer_clean(unsigned int ticks, void *param)
&pres.user, &pres.domain, &rules_doc)
< 0) {
LM_ERR("getting rules doc\n");
goto error;
goto next;
}
if(publ_notify(&pres, uri, NULL, &pres.etag, rules_doc) < 0) {
LM_ERR("sending Notify request\n");
goto error;
}
if(rules_doc) {
if(rules_doc->s)
pkg_free(rules_doc->s);
pkg_free(rules_doc);
rules_doc = NULL;
goto next;
}
}
pkg_free(uri.s);
uri.s = NULL;
next:
if(uri.s) {
pkg_free(uri.s);
uri.s = NULL;
}
if(rules_doc) {
if(rules_doc->s) {
pkg_free(rules_doc->s);
}
pkg_free(rules_doc);
rules_doc = NULL;
}
}
error:
for(ptn = ptlist; ptn != NULL; ptn = ptn->next) {
if(ps_ptable_remove(ptn) <0) {
LM_ERR("failed deleting presentity item\n");

@ -559,31 +559,39 @@ 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) {
&& (s = dlg_api.get_dlg_varref(dlg, &caller_dlg_var))!=0) {
dlginfo->pubruris_caller =
(struct str_list*)shm_malloc( sizeof(struct str_list) );
(struct str_list*)shm_malloc(sizeof(struct str_list) + s->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, s->s, s->len);
dlginfo->pubruris_caller->s.s[s->len] = '\0';
dlginfo->pubruris_caller->s.len = s->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) {
&& (s = dlg_api.get_dlg_varref(dlg, &callee_dlg_var))!=0) {
dlginfo->pubruris_callee =
(struct str_list*)shm_malloc( sizeof(struct str_list) );
(struct str_list*)shm_malloc(sizeof(struct str_list) + s->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, s->s, s->len);
dlginfo->pubruris_callee->s.s[s->len] = '\0';
dlginfo->pubruris_callee->s.len = s->len;
LM_DBG("Found pubruris_callee in dialog '%.*s'\n",
dlginfo->pubruris_callee->s.len, dlginfo->pubruris_callee->s.s);
}

@ -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_str(&tv.rs, &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_str(&tv.rs, &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_str(&tv.rs, &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;
@ -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_str(&tv.rs, &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;

@ -220,15 +220,47 @@ static int w_pvh_header_param_exists(
return pvh_header_param_exists(msg, &hname, &value);
}
static int ki_pvh_remove_header_param(struct sip_msg *msg, str *hname, str *toRemove)
{
int idx;
int new_size;
str dst = STR_NULL;
sr_xavp_t *avi = pvh_xavi_get_child(msg, &xavi_name, hname);
for(idx=0; avi != NULL; avi = xavi_get_next(avi)) {
if (avi->val.type == SR_XTYPE_STR && avi->val.v.s.s != NULL) {
if(str_casesearch(&avi->val.v.s, toRemove) != NULL) {
new_size = pvh_remove_header_param_helper(&avi->val.v.s, toRemove, &dst);
if(dst.len == 0) {
LM_DBG("nothing left in the header:%.*s, remove it[%d]\n",
STR_FMT(hname), idx);
if(pvh_remove_header(msg, hname, idx) < 0)
return -1;
} else if(dst.len < 0 || new_size == avi->val.v.s.len) {
LM_DBG("'%.*s' not found at '%.*s'\n", STR_FMT(toRemove),
STR_FMT(&avi->val.v.s));
} else {
LM_DBG("old_value:'%.*s' new_value:'%.*s'\n",
STR_FMT(&avi->val.v.s), STR_FMT(&dst));
if(pvh_set_xavi(msg, &xavi_name, hname, &dst, SR_XTYPE_STR, idx, 0) < 0) {
LM_ERR("can't set new value\n");
return -1;
}
}
} else {
LM_DBG("'%.*s' not found at '%.*s'\n", STR_FMT(toRemove),
STR_FMT(&avi->val.v.s));
}
}
idx++;
}
return 1;
}
static int w_pvh_remove_header_param(struct sip_msg *msg, char *p1, char *p2)
{
int ret = -1;
int idx = 0;
str hname = STR_NULL;
str value = STR_NULL;
sr_xavp_t *avi=NULL;
char tt[header_name_size];
str br_xname = {tt, header_name_size};
if(fixup_get_svalue(msg, (gparam_p)p1, &hname) < 0)
return -1;
@ -236,20 +268,7 @@ static int w_pvh_remove_header_param(struct sip_msg *msg, char *p1, char *p2)
if(p2 && fixup_get_svalue(msg, (gparam_p)p2, &value) < 0)
return -1;
pvh_get_branch_xname(msg, &xavi_name, &br_xname);
avi = xavi_get_child(&br_xname, &hname);
while(avi)
{
if (avi->val.type == SR_XTYPE_STR && avi->val.v.s.s != NULL && _strnstr(avi->val.v.s.s, value.s, avi->val.v.s.len) != NULL) {
ret = pvh_remove_header_param(msg, idx, &hname, &avi->val.v.s, &value) && ret;
}
idx++;
avi = xavi_get_next(avi);
}
return ret;
return ki_pvh_remove_header_param(msg, &hname, &value);
}
/* clang-format off */
@ -594,9 +613,9 @@ static sr_kemi_t pvh_kemi_exports[] = {
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
},
{ str_init("pv_headers"), str_init("pvh_remove_header_param"),
SR_KEMIP_INT, pvh_remove_header_param,
{ SR_KEMIP_INT, SR_KEMIP_STR, SR_KEMIP_STR,
SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE}
SR_KEMIP_INT, ki_pvh_remove_header_param,
{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
},
{{0, 0}, {0, 0}, 0, NULL, {0, 0, 0, 0, 0, 0}}
};

@ -22,7 +22,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "../../core/pvapi.h"
#include "../../core/strutils.h"
#include "pv_headers.h"
@ -381,73 +381,45 @@ int pvh_header_param_exists(struct sip_msg *msg, str *hname, str *hvalue)
return -1;
}
int pvh_remove_header_param(struct sip_msg *msg, int idx, str *hname, str *elements, str *toRemove)
int pvh_remove_header_param_helper(str *orig, const str *toRemove, str *dst)
{
int notTarget, writtenChars;
int notTarget;
int writtenChars = 0;
int offset = 0;
int ret = -1;
char *next_token;
char *saveptr = NULL;
char *token;
char *result = (char*)pkg_malloc(elements->len - toRemove->len);
char *t = (char*)pkg_malloc(elements->len+1);
if (result == NULL || t == NULL)
{
PKG_MEM_ERROR;
goto clean;
}
snprintf(t, elements->len+1, "%s", elements->s);
token = strtok_r(t, ", ", &next_token);
while(token)
{
notTarget = strncmp(token, toRemove->s, toRemove->len);
if (notTarget)
{
writtenChars = snprintf(result + offset, elements->len - offset, "%s", token);
if (writtenChars < 0 || writtenChars >= elements->len - offset)
{
break;
}
offset += writtenChars;
}
token = strtok_r(NULL, ", ", &next_token);
if (token && notTarget && elements->len - offset - toRemove->len > 2)
{
writtenChars = snprintf(result + offset, elements->len - offset, ", ");
if (writtenChars < 0 || writtenChars >= elements->len - offset)
{
break;
}
char t[header_value_size];
char *result = pv_get_buffer();
int maxSize = pv_get_buffer_size();
memset(result, 0, maxSize);
LM_DBG("orig:'%.*s' toRemove:'%.*s'\n", STR_FMT(orig), STR_FMT(toRemove));
strncpy(t, orig->s, orig->len);
t[orig->len] = '\0';
token = strtok_r(t, ", ", &saveptr);
dst->s = NULL; dst->len = -1;
while(token) {
notTarget = strncasecmp(token, toRemove->s, toRemove->len);
LM_DBG("offset:%d token:%s notTarget:%d\n", offset, token, notTarget);
if(notTarget) {
writtenChars = snprintf(result + offset, maxSize - offset, "%s, ", token);
if(writtenChars < 0) break;
offset += writtenChars;
} else {
dst->len = 0; /* we found a token */
}
token = strtok_r(NULL, ", ", &saveptr);
}
if (elements->len-toRemove->len > 0)
{
snprintf(elements->s, (strlen(result)%elements->len)+1, "%s", result);
elements->len = strlen(result);
ret = 1;
}
else
{
ret = pvh_remove_header(msg, hname, idx);
}
clean:
if(t != NULL)
{
pkg_free(t);
t = NULL;
}
if(result != NULL)
{
pkg_free(result);
result = NULL;
if(offset > 0) {
dst->s = result;
if(offset > 2 && result[offset-2] == ',' && result[offset-1] == ' ') {
LM_DBG("remove last separator\n");
offset = offset - 2;
result[offset] = '\0';
}
dst->len = offset;
LM_DBG("offset:%d result:'%.*s'[%d]\n", offset, STR_FMT(dst), dst->len);
}
return ret;
return offset;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save