TT#84508 Update upstream source from tag 'upstream/5.3.5'

Update to upstream version '5.3.5'
with Debian dir f25708c255

Change-Id: Iaf7771648a024542974c7cb3744a53d1a4ba6930
changes/40/41140/1
Victor Seva 6 years ago
commit 4f64f36925

File diff suppressed because it is too large Load Diff

@ -13,6 +13,8 @@
<!ENTITY kamwiki "https://www.kamailio.org/wiki/">
<!ENTITY kamwikilink "<ulink url='&kamwiki;'>&kamwiki;</ulink>">
<!ENTITY kamctl "kamctl">
<!ENTITY kamcli "kamcli">
<!ENTITY kamcmd "kamcmd">
<!ENTITY kamailiohome "https://www.kamailio.org/">

@ -240,7 +240,7 @@ function ksr_route_location()
end
-- IP authorization and user uthentication
-- IP authorization and user authentication
function ksr_route_auth()
if not KSR.is_REGISTER() then

@ -7,12 +7,11 @@
## Relevant remarks:
## * return code -255 is used to propagate the 'exit' behaviour to the
## parent route block function. The alternative is to use the native
## Python function os.exit() (or exit()) -- it throws an exception that
## Python function sys.exit() (or exit()) -- it throws an exception that
## is caught by Kamailio and previents the stop of the interpreter.
import sys
import Router.Logger as Logger
import KSR as KSR
# global variables corresponding to defined values (e.g., flags) in kamailio.cfg
@ -28,56 +27,56 @@ FLB_NATSIPPING=7
# global function to instantiate a kamailio class object
# -- executed when kamailio app_python module is initialized
def mod_init():
KSR.info("===== from Python mod init\n");
# dumpObj(KSR);
return kamailio();
KSR.info("===== from Python mod init\n")
# dumpObj(KSR)
return kamailio()
# -- {start defining kamailio class}
class kamailio:
def __init__(self):
KSR.info('===== kamailio.__init__\n');
KSR.info('===== kamailio.__init__\n')
# executed when kamailio child processes are initialized
def child_init(self, rank):
KSR.info('===== kamailio.child_init(%d)\n' % rank);
return 0;
KSR.info('===== kamailio.child_init(%d)\n' % rank)
return 0
# SIP request routing
# -- equivalent of request_route{}
def ksr_request_route(self, msg):
# KSR.info("===== request - from kamailio python script\n");
# KSR.info("===== method [%s] r-uri [%s]\n" % (KSR.pv.get("$rm"),KSR.pv.get("$ru")));
# KSR.info("===== request - from kamailio python script\n")
# KSR.info("===== method [%s] r-uri [%s]\n" % (KSR.pv.get("$rm"),KSR.pv.get("$ru")))
# per request initial checks
if self.ksr_route_reqinit(msg)==-255 :
return 1;
return 1
# NAT detection
if self.ksr_route_natdetect(msg)==-255 :
return 1;
return 1
# CANCEL processing
if KSR.is_CANCEL() :
if KSR.tm.t_check_trans()>0 :
self.ksr_route_relay(msg);
return 1;
self.ksr_route_relay(msg)
return 1
# handle requests within SIP dialogs
if self.ksr_route_withindlg(msg)==-255 :
return 1;
return 1
# -- only initial requests (no To tag)
# handle retransmissions
if KSR.tmx.t_precheck_trans()>0 :
KSR.tm.t_check_trans();
return 1;
KSR.tm.t_check_trans()
return 1
if KSR.tm.t_check_trans()==0 :
return 1;
return 1
# authentication
if self.ksr_route_auth(msg)==-255 :
@ -85,9 +84,9 @@ class kamailio:
# record routing for dialog forming requests (in case they are routed)
# - remove preloaded route headers
KSR.hdr.remove("Route");
KSR.hdr.remove("Route")
if KSR.is_method_in("IS") :
KSR.rr.record_route();
KSR.rr.record_route()
# account only INVITEs
@ -97,24 +96,24 @@ class kamailio:
# dispatch requests to foreign domains
if self.ksr_route_sipout(msg)==-255 :
return 1;
return 1
# # requests for my local domains
# handle registrations
if self.ksr_route_registrar(msg)==-255 :
return 1;
return 1
if KSR.corex.has_ruri_user() < 0 :
# request with no Username in RURI
KSR.sl.sl_send_reply(484,"Address Incomplete");
return 1;
KSR.sl.sl_send_reply(484,"Address Incomplete")
return 1
# user location service
self.ksr_route_location(msg);
self.ksr_route_location(msg)
return 1;
return 1
# wrapper around tm relay function
@ -123,20 +122,20 @@ class kamailio:
# - serial forking, RTP relaying handling, a.s.o.
if KSR.is_method_in("IBSU") :
if KSR.tm.t_is_set("branch_route")<0 :
KSR.tm.t_on_branch("ksr_branch_manage");
KSR.tm.t_on_branch("ksr_branch_manage")
if KSR.is_method_in("ISU") :
if KSR.tm.t_is_set("onreply_route")<0 :
KSR.tm.t_on_reply("ksr_onreply_manage");
KSR.tm.t_on_reply("ksr_onreply_manage")
if KSR.is_INVITE() :
if KSR.tm.t_is_set("failure_route")<0 :
KSR.tm.t_on_failure("ksr_failure_manage");
KSR.tm.t_on_failure("ksr_failure_manage")
if KSR.tm.t_relay()<0 :
KSR.sl.sl_reply_error();
KSR.sl.sl_reply_error()
return -255;
return -255
# Per SIP request initial checks
@ -146,113 +145,113 @@ class kamailio:
# ip is already blocked
KSR.dbg("request from blocked IP - " + KSR.pv.get("$rm")
+ " from " + KSR.pv.get("$fu") + " (IP:"
+ KSR.pv.get("$si") + ":" + str(KSR.pv.get("$sp")) + ")\n");
return -255;
+ KSR.pv.get("$si") + ":" + str(KSR.pv.get("$sp")) + ")\n")
return -255
if KSR.pike.pike_check_req()<0 :
KSR.err("ALERT: pike blocking " + KSR.pv.get("$rm")
+ " from " + KSR.pv.get("$fu") + " (IP:"
+ KSR.pv.get("$si") + ":" + str(KSR.pv.get("$sp")) + ")\n");
KSR.pv.seti("$sht(ipban=>$si)", 1);
return -255;
+ KSR.pv.get("$si") + ":" + str(KSR.pv.get("$sp")) + ")\n")
KSR.pv.seti("$sht(ipban=>$si)", 1)
return -255
if KSR.corex.has_user_agent() > 0 :
ua = KSR.pv.gete("$ua")
if (ua.find("friendly-scanner")!=-1
or ua.find("sipcli")!=-1) :
KSR.sl.sl_send_reply(200, "Processed");
return -255;
KSR.sl.sl_send_reply(200, "Processed")
return -255
if KSR.maxfwd.process_maxfwd(10) < 0 :
KSR.sl.sl_send_reply(483,"Too Many Hops");
return -255;
KSR.sl.sl_send_reply(483,"Too Many Hops")
return -255
if (KSR.is_OPTIONS()
and KSR.is_myself_ruri()
and KSR.corex.has_ruri_user() < 0) :
KSR.sl.sl_send_reply(200,"Keepalive");
return -255;
KSR.sl.sl_send_reply(200,"Keepalive")
return -255
if KSR.sanity.sanity_check(1511, 7)<0 :
KSR.err("Malformed SIP message from "
+ KSR.pv.get("$si") + ":" + str(KSR.pv.get("$sp")) +"\n");
return -255;
+ KSR.pv.get("$si") + ":" + str(KSR.pv.get("$sp")) +"\n")
return -255
# Handle requests within SIP dialogs
def ksr_route_withindlg(self, msg):
if KSR.siputils.has_totag()<0 :
return 1;
return 1
# sequential request withing a dialog should
# take the path determined by record-routing
if KSR.rr.loose_route()>0 :
if self.ksr_route_dlguri(msg)==-255 :
return -255;
return -255
if KSR.is_BYE() :
# do accounting ...
KSR.setflag(FLT_ACC);
KSR.setflag(FLT_ACC)
# ... even if the transaction fails
KSR.setflag(FLT_ACCFAILED);
KSR.setflag(FLT_ACCFAILED)
elif KSR.is_ACK() :
# ACK is forwarded statelessly
if self.ksr_route_natmanage(msg)==-255 :
return -255;
return -255
elif KSR.is_NOTIFY() :
# Add Record-Route for in-dialog NOTIFY as per RFC 6665.
KSR.rr.record_route();
KSR.rr.record_route()
self.ksr_route_relay(msg);
return -255;
self.ksr_route_relay(msg)
return -255
if KSR.is_ACK() :
if KSR.tm.t_check_trans() >0 :
# no loose-route, but stateful ACK;
# no loose-route, but stateful ACK
# must be an ACK after a 487
# or e.g. 404 from upstream server
self.ksr_route_relay(msg);
return -255;
self.ksr_route_relay(msg)
return -255
else:
# ACK without matching transaction ... ignore and discard
return -255;
return -255
KSR.sl.sl_send_reply(404, "Not here");
return -255;
KSR.sl.sl_send_reply(404, "Not here")
return -255
# Handle SIP registrations
def ksr_route_registrar(self, msg):
if not KSR.is_REGISTER() :
return 1;
return 1
if KSR.isflagset(FLT_NATS) :
KSR.setbflag(FLB_NATB);
KSR.setbflag(FLB_NATB)
# do SIP NAT pinging
KSR.setbflag(FLB_NATSIPPING);
KSR.setbflag(FLB_NATSIPPING)
if KSR.registrar.save("location", 0)<0 :
KSR.sl.sl_reply_error();
KSR.sl.sl_reply_error()
return -255;
return -255
# User location service
def ksr_route_location(self, msg):
rc = KSR.registrar.lookup("location");
rc = KSR.registrar.lookup("location")
if rc<0 :
KSR.tm.t_newtran();
KSR.tm.t_newtran()
if rc==-1 or rc==-3 :
KSR.sl.send_reply(404, "Not Found");
return -255;
KSR.sl.send_reply(404, "Not Found")
return -255
elif rc==-2 :
KSR.sl.send_reply(405, "Method Not Allowed");
return -255;
KSR.sl.send_reply(405, "Method Not Allowed")
return -255
# when routing via usrloc, log the missed calls also
if KSR.is_INVITE() :
KSR.setflag(FLT_ACCMISSED);
KSR.setflag(FLT_ACCMISSED)
self.ksr_route_relay(msg);
return -255;
self.ksr_route_relay(msg)
return -255
@ -262,39 +261,39 @@ class kamailio:
if not KSR.is_REGISTER() :
if KSR.permissions.allow_source_address(1)>0 :
# source IP allowed
return 1;
return 1
if KSR.is_REGISTER() or KSR.is_myself_furi() :
# authenticate requests
if KSR.auth_db.auth_check(KSR.pv.get("$fd"), "subscriber", 1)<0 :
KSR.auth.auth_challenge(KSR.pv.get("$fd"), 0);
return -255;
KSR.auth.auth_challenge(KSR.pv.get("$fd"), 0)
return -255
# user authenticated - remove auth header
if not KSR.is_method_in("RP") :
KSR.auth.consume_credentials();
KSR.auth.consume_credentials()
# if caller is not local subscriber, then check if it calls
# a local destination, otherwise deny, not an open relay here
if (not KSR.is_myself_furi()) and (not KSR.is_myself_ruri()) :
KSR.sl.sl_send_reply(403,"Not relaying");
return -255;
KSR.sl.sl_send_reply(403,"Not relaying")
return -255
return 1;
return 1
# Caller NAT detection
def ksr_route_natdetect(self, msg):
KSR.force_rport();
KSR.force_rport()
if KSR.nathelper.nat_uac_test(19)>0 :
if KSR.is_REGISTER() :
KSR.nathelper.fix_nated_register();
KSR.nathelper.fix_nated_register()
elif KSR.siputils.is_first_hop()>0 :
KSR.nathelper.set_contact_alias();
KSR.nathelper.set_contact_alias()
KSR.setflag(FLT_NATS);
KSR.setflag(FLT_NATS)
return 1;
return 1
# RTPProxy control
@ -302,79 +301,79 @@ class kamailio:
if KSR.siputils.is_request()>0 :
if KSR.siputils.has_totag()>0 :
if KSR.rr.check_route_param("nat=yes")>0 :
KSR.setbflag(FLB_NATB);
KSR.setbflag(FLB_NATB)
if (not (KSR.isflagset(FLT_NATS) or KSR.isbflagset(FLB_NATB))) :
return 1;
return 1
KSR.rtpproxy.rtpproxy_manage("co");
KSR.rtpproxy.rtpproxy_manage("co")
if KSR.siputils.is_request()>0 :
if not KSR.siputils.has_totag() :
if KSR.tmx.t_is_branch_route()>0 :
KSR.rr.add_rr_param(";nat=yes");
KSR.rr.add_rr_param(";nat=yes")
if KSR.siputils.is_reply()>0 :
if KSR.isbflagset(FLB_NATB) :
KSR.nathelper.set_contact_alias();
KSR.nathelper.set_contact_alias()
return 1;
return 1
# URI update for dialog requests
def ksr_route_dlguri(self, msg):
if not KSR.isdsturiset() :
KSR.nathelper.handle_ruri_alias();
KSR.nathelper.handle_ruri_alias()
return 1;
return 1
# Routing to foreign domains
def ksr_route_sipout(self, msg):
if KSR.is_myself_ruri() :
return 1;
return 1
KSR.hdr.append("P-Hint: outbound\r\n");
self.ksr_route_relay(msg);
return -255;
KSR.hdr.append("P-Hint: outbound\r\n")
self.ksr_route_relay(msg)
return -255
# Manage outgoing branches
# -- equivalent of branch_route[...]{}
def ksr_branch_manage(self, msg):
KSR.dbg("new branch ["+ str(KSR.pv.get("$T_branch_idx"))
+ "] to "+ KSR.pv.get("$ru") + "\n");
self.ksr_route_natmanage(msg);
return 1;
+ "] to "+ KSR.pv.get("$ru") + "\n")
self.ksr_route_natmanage(msg)
return 1
# Manage incoming replies
# -- equivalent of onreply_route[...]{}
def ksr_onreply_manage(self, msg):
KSR.dbg("incoming reply\n");
scode = KSR.pv.get("$rs");
KSR.dbg("incoming reply\n")
scode = KSR.pv.get("$rs")
if scode>100 and scode<299 :
self.ksr_route_natmanage(msg);
self.ksr_route_natmanage(msg)
return 1;
return 1
# Manage failure routing cases
# -- equivalent of failure_route[...]{}
def ksr_failure_manage(self, msg):
if self.ksr_route_natmanage(msg)==-255 : return 1;
if self.ksr_route_natmanage(msg)==-255 : return 1
if KSR.tm.t_is_canceled()>0 :
return 1;
return 1
return 1;
return 1
# SIP response handling
# -- equivalent of reply_route{}
def ksr_reply_route(self, msg):
KSR.info("===== response - from kamailio python script\n");
return 1;
KSR.info("===== response - from kamailio python script\n")
return 1
# -- {end defining kamailio class}
@ -383,6 +382,5 @@ class kamailio:
# global helper function for debugging purposes
def dumpObj(obj):
for attr in dir(obj):
# KSR.info("obj.%s = %s\n" % (attr, getattr(obj, attr)));
Logger.LM_INFO("obj.%s = %s\n" % (attr, getattr(obj, attr)));
KSR.info("obj.%s = %s\n" % (attr, getattr(obj, attr)))

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

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -5,19 +5,19 @@ After=network-online.target
[Service]
Type=forking
User=kamailio
Group=kamailio
Environment='CFGFILE=/etc/kamailio/kamailio.cfg'
Environment='SHM_MEMORY=64'
Environment='PKG_MEMORY=8'
Environment='USER=kamailio'
Environment='GROUP=kamailio'
EnvironmentFile=-/etc/default/kamailio
EnvironmentFile=-/etc/default/kamailio.d/*
# PIDFile requires a full absolute path
PIDFile=/var/run/kamailio/kamailio.pid
PIDFile=/run/kamailio/kamailio.pid
# ExecStart requires a full absolute path
ExecStart=/usr/sbin/kamailio -P /var/run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP
ExecStart=/usr/sbin/kamailio -P /run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY
Restart=on-failure
# /var/run/kamailio in tmpfs
# /run/kamailio in tmpfs
RuntimeDirectory=kamailio
RuntimeDirectoryMode=0750

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -5,19 +5,19 @@ After=network-online.target
[Service]
Type=forking
User=kamailio
Group=kamailio
Environment='CFGFILE=/etc/kamailio/kamailio.cfg'
Environment='SHM_MEMORY=64'
Environment='PKG_MEMORY=8'
Environment='USER=kamailio'
Environment='GROUP=kamailio'
EnvironmentFile=-/etc/default/kamailio
EnvironmentFile=-/etc/default/kamailio.d/*
# PIDFile requires a full absolute path
PIDFile=/var/run/kamailio/kamailio.pid
PIDFile=/run/kamailio/kamailio.pid
# ExecStart requires a full absolute path
ExecStart=/usr/sbin/kamailio -P /var/run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP
ExecStart=/usr/sbin/kamailio -P /run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY
Restart=on-failure
# /var/run/kamailio in tmpfs
# /run/kamailio in tmpfs
RuntimeDirectory=kamailio
RuntimeDirectoryMode=0750

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -5,19 +5,19 @@ After=network-online.target
[Service]
Type=forking
User=kamailio
Group=kamailio
Environment='CFGFILE=/etc/kamailio/kamailio.cfg'
Environment='SHM_MEMORY=64'
Environment='PKG_MEMORY=8'
Environment='USER=kamailio'
Environment='GROUP=kamailio'
EnvironmentFile=-/etc/default/kamailio
EnvironmentFile=-/etc/default/kamailio.d/*
# PIDFile requires a full absolute path
PIDFile=/var/run/kamailio/kamailio.pid
PIDFile=/run/kamailio/kamailio.pid
# ExecStart requires a full absolute path
ExecStart=/usr/sbin/kamailio -P /var/run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP
ExecStart=/usr/sbin/kamailio -P /run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY
Restart=on-failure
# /var/run/kamailio in tmpfs
# /run/kamailio in tmpfs
RuntimeDirectory=kamailio
RuntimeDirectoryMode=0750

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -5,19 +5,19 @@ After=network-online.target
[Service]
Type=forking
User=kamailio
Group=kamailio
Environment='CFGFILE=/etc/kamailio/kamailio.cfg'
Environment='SHM_MEMORY=64'
Environment='PKG_MEMORY=8'
Environment='USER=kamailio'
Environment='GROUP=kamailio'
EnvironmentFile=-/etc/default/kamailio
EnvironmentFile=-/etc/default/kamailio.d/*
# PIDFile requires a full absolute path
PIDFile=/var/run/kamailio/kamailio.pid
PIDFile=/run/kamailio/kamailio.pid
# ExecStart requires a full absolute path
ExecStart=/usr/sbin/kamailio -P /var/run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP
ExecStart=/usr/sbin/kamailio -P /run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY
Restart=on-failure
# /var/run/kamailio in tmpfs
# /run/kamailio in tmpfs
RuntimeDirectory=kamailio
RuntimeDirectoryMode=0750

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -5,19 +5,19 @@ After=network-online.target
[Service]
Type=forking
User=kamailio
Group=kamailio
Environment='CFGFILE=/etc/kamailio/kamailio.cfg'
Environment='SHM_MEMORY=64'
Environment='PKG_MEMORY=8'
Environment='USER=kamailio'
Environment='GROUP=kamailio'
EnvironmentFile=-/etc/default/kamailio
EnvironmentFile=-/etc/default/kamailio.d/*
# PIDFile requires a full absolute path
PIDFile=/var/run/kamailio/kamailio.pid
PIDFile=/run/kamailio/kamailio.pid
# ExecStart requires a full absolute path
ExecStart=/usr/sbin/kamailio -P /var/run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP
ExecStart=/usr/sbin/kamailio -P /run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY
Restart=on-failure
# /var/run/kamailio in tmpfs
# /run/kamailio in tmpfs
RuntimeDirectory=kamailio
RuntimeDirectoryMode=0750

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -5,19 +5,19 @@ After=network-online.target
[Service]
Type=forking
User=kamailio
Group=kamailio
Environment='CFGFILE=/etc/kamailio/kamailio.cfg'
Environment='SHM_MEMORY=64'
Environment='PKG_MEMORY=8'
Environment='USER=kamailio'
Environment='GROUP=kamailio'
EnvironmentFile=-/etc/default/kamailio
EnvironmentFile=-/etc/default/kamailio.d/*
# PIDFile requires a full absolute path
PIDFile=/var/run/kamailio/kamailio.pid
PIDFile=/run/kamailio/kamailio.pid
# ExecStart requires a full absolute path
ExecStart=/usr/sbin/kamailio -P /var/run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP
ExecStart=/usr/sbin/kamailio -P /run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY
Restart=on-failure
# /var/run/kamailio in tmpfs
# /run/kamailio in tmpfs
RuntimeDirectory=kamailio
RuntimeDirectoryMode=0750

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -1,3 +1,9 @@
kamailio (5.3.5) unstable; urgency=medium
* version set 5.3.5
-- Victor Seva <vseva@debian.org> Mon, 22 Jun 2020 09:18:58 +0200
kamailio (5.3.4) unstable; urgency=medium
* version set 5.3.4

@ -11,6 +11,14 @@
# Group to run as
#GROUP=kamailio
# On systemd, to change username or group please create drop-in
# /etc/systemd/system/kamailio.service.d/10-user_group.conf file, like
# ```
# [Service]
# User=kamuser
# Group=kamgroup
# ```
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
#SHM_MEMORY=64

@ -18,7 +18,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=`basename "$0"`
DESC="Kamailio SIP Server"
HOMEDIR=/var/run/$NAME
HOMEDIR=/run/$NAME
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=/etc/default/$NAME
CFGFILE=/etc/$NAME/kamailio.cfg
@ -112,7 +112,7 @@ if test "$DUMP_CORE" = "yes" ; then
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
# $HOMEDIR can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown ${USER}:${GROUP} $HOMEDIR

@ -5,19 +5,19 @@ After=network-online.target
[Service]
Type=forking
User=kamailio
Group=kamailio
Environment='CFGFILE=/etc/kamailio/kamailio.cfg'
Environment='SHM_MEMORY=64'
Environment='PKG_MEMORY=8'
Environment='USER=kamailio'
Environment='GROUP=kamailio'
EnvironmentFile=-/etc/default/kamailio
EnvironmentFile=-/etc/default/kamailio.d/*
# PIDFile requires a full absolute path
PIDFile=/var/run/kamailio/kamailio.pid
PIDFile=/run/kamailio/kamailio.pid
# ExecStart requires a full absolute path
ExecStart=/usr/sbin/kamailio -P /var/run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP
ExecStart=/usr/sbin/kamailio -P /run/kamailio/kamailio.pid -f $CFGFILE -m $SHM_MEMORY -M $PKG_MEMORY
Restart=on-failure
# /var/run/kamailio in tmpfs
# /run/kamailio in tmpfs
RuntimeDirectory=kamailio
RuntimeDirectoryMode=0750

@ -1,5 +1,5 @@
%define name kamailio
%define ver 5.3.4
%define ver 5.3.5
%define rel dev1.0%{dist}
%if 0%{?fedora}
@ -1109,6 +1109,10 @@ UUID module for Kamailio.
%prep
%setup -n %{name}-%{ver}
# python3 does not exist in RHEL 6 and similar dist.
%if 0%{?rhel} == 6
sed -i -e 's/python3/python2/' utils/kamctl/dbtextdb/dbtextdb.py
%endif
%build
ln -s ../obs pkg/kamailio/%{dist_name}/%{dist_version}
@ -1145,6 +1149,7 @@ make every-module skip_modules="app_mono db_cassandra db_oracle iptrtpproxy \
%if %{with http_async_client}
khttp_async \
%endif
kxhttp_prom \
%if %{with ims}
kims \
%endif
@ -1232,6 +1237,7 @@ make install-modules-all skip_modules="app_mono db_cassandra db_oracle \
%if %{with http_async_client}
khttp_async \
%endif
kxhttp_prom \
%if %{with ims}
kims \
%endif

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

@ -277,9 +277,11 @@ int async_task_run(int idx)
continue;
}
if(ptask->exec!=NULL) {
LM_DBG("task executed [%p] (%p/%p)\n", ptask,
ptask->exec, ptask->param);
LM_DBG("task executed [%p] (%p/%p)\n", (void*)ptask,
(void*)ptask->exec, (void*)ptask->param);
ptask->exec(ptask->param);
} else {
LM_DBG("task with no callback function - ignoring\n");
}
shm_free(ptask);
}

@ -2,6 +2,6 @@
* DO NOT EDIT IT
*/
#define REPO_VER "117ff9"
#define REPO_HASH "117ff9"
#define REPO_VER "9e70e8"
#define REPO_HASH "9e70e8"
#define REPO_STATE ""

@ -77,12 +77,15 @@
#define CONTENT_LENGTH "Content-Length: "
#define CONTENT_LENGTH_LEN (sizeof(CONTENT_LENGTH)-1)
#define USER_AGENT "User-Agent: " NAME \
#define SRVAPP_SIGNATURE NAME \
" (" VERSION " (" ARCH "/" OS_QUOTED "))"
#define SRVAPP_SIGNATURE_LEN (sizeof(SRVAPP_SIGNATURE)-1)
#define USER_AGENT "User-Agent: " SRVAPP_SIGNATURE
#define USER_AGENT_LEN (sizeof(USER_AGENT)-1)
#define SERVER_HDR "Server: " NAME \
" (" VERSION " (" ARCH "/" OS_QUOTED "))"
#define SERVER_HDR "Server: " SRVAPP_SIGNATURE
#define SERVER_HDR_LEN (sizeof(SERVER_HDR)-1)
#define MAX_WARNING_LEN 256

@ -38,7 +38,7 @@
#define SREV_NET_DATA_RECV 14
#define SREV_NET_DATA_SEND 15
#define SREV_CB_LIST_SIZE 3
#define SREV_CB_LIST_SIZE 8
typedef struct sr_event_param {
void *data;

@ -109,12 +109,12 @@ typedef int fd_type;
/* maps a fd to some other structure; used in almost all cases
* except epoll and maybe kqueue or /dev/poll */
struct fd_map{
typedef struct fd_map {
int fd; /* fd no */
fd_type type; /* "data" type */
void* data; /* pointer to the corresponding structure */
short events; /* events we are interested int */
};
} fd_map_t;
#ifdef HAVE_KQUEUE
@ -132,7 +132,7 @@ struct fd_map{
/* handler structure */
struct io_wait_handler{
typedef struct io_wait_handler {
enum poll_types poll_method;
int flags;
struct fd_map* fd_hash;
@ -172,13 +172,12 @@ struct io_wait_handler{
fd_set master_wset; /* write set */
int max_fd_select; /* maximum select used fd */
#endif
};
typedef struct io_wait_handler io_wait_h;
} io_wait_h;
/* get the corresponding fd_map structure pointer */
#define get_fd_map(h, fd) (&(h)->fd_hash[(fd)])
/* remove a fd_map structure from the hash; the pointer must be returned
* by get_fd_map or hash_fd_map*/
#define unhash_fd_map(pfm) \
@ -321,7 +320,7 @@ inline static int io_watch_add( io_wait_h* h,
h->fd_array[h->fd_no].events=(ev); /* useless for select */ \
h->fd_array[h->fd_no].revents=0; /* useless for select */ \
}while(0)
#define set_fd_flags(f) \
do{ \
flags=fcntl(fd, F_GETFL); \
@ -336,8 +335,7 @@ inline static int io_watch_add( io_wait_h* h,
goto error; \
} \
}while(0)
struct fd_map* e;
int flags;
#ifdef HAVE_EPOLL
@ -353,7 +351,7 @@ inline static int io_watch_add( io_wait_h* h,
int idx;
int check_io;
struct pollfd pf;
check_io=0; /* set to 1 if we need to check for pre-existing queued
io/data on the fd */
idx=-1;
@ -378,13 +376,13 @@ inline static int io_watch_add( io_wait_h* h,
/* hash sanity check */
e=get_fd_map(h, fd);
if (unlikely(e && (e->type!=0 /*F_NONE*/))){
LM_ERR("trying to overwrite entry %d"
" watched for %x in the hash(%d, %d, %p) with (%d, %d, %p)\n",
fd, events, e->fd, e->type, e->data, fd, type, data);
LM_ERR("trying to overwrite entry %d watched for %x"
" in the hash %p (fd:%d, type:%d, data:%p) with (%d, %d, %p)\n",
fd, events, h, e->fd, e->type, e->data, fd, type, data);
e=0;
goto error;
}
if (unlikely((e=hash_fd_map(h, fd, events, type, data))==0)){
LM_ERR("failed to hash the fd %d\n", fd);
goto error;

@ -71,6 +71,7 @@ union sockaddr_union{
struct sockaddr s;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_storage sas;
};
@ -790,11 +791,14 @@ static inline struct hostent* ip_addr2he(str* name, struct ip_addr* ip)
static char* p_aliases[1];
static char* p_addr[2];
static char address[16];
int len;
p_aliases[0]=0; /* no aliases*/
p_addr[1]=0; /* only one address*/
p_addr[0]=address;
strncpy(hostname, name->s, (name->len<256)?(name->len)+1:256);
len = (name->len<255)?name->len:255;
memcpy(hostname, name->s, len);
hostname[len] = '\0';
if (ip->len>16) return 0;
memcpy(address, ip->u.addr, ip->len);

@ -1025,6 +1025,57 @@ static int sr_kemi_core_is_method_prack(sip_msg_t *msg)
return sr_kemi_core_is_method_type(msg, METHOD_PRACK);
}
/**
*
*/
static int sr_kemi_core_is_method_message(sip_msg_t *msg)
{
return sr_kemi_core_is_method_type(msg, METHOD_MESSAGE);
}
/**
*
*/
static int sr_kemi_core_is_method_kdmq(sip_msg_t *msg)
{
return sr_kemi_core_is_method_type(msg, METHOD_KDMQ);
}
/**
*
*/
static int sr_kemi_core_is_method_get(sip_msg_t *msg)
{
return sr_kemi_core_is_method_type(msg, METHOD_GET);
}
/**
*
*/
static int sr_kemi_core_is_method_post(sip_msg_t *msg)
{
return sr_kemi_core_is_method_type(msg, METHOD_POST);
}
/**
*
*/
static int sr_kemi_core_is_method_put(sip_msg_t *msg)
{
return sr_kemi_core_is_method_type(msg, METHOD_PUT);
}
/**
*
*/
static int sr_kemi_core_is_method_delete(sip_msg_t *msg)
{
return sr_kemi_core_is_method_type(msg, METHOD_DELETE);
}
/**
*
*/
@ -1645,6 +1696,36 @@ static sr_kemi_t _sr_kemi_core[] = {
{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
},
{ str_init(""), str_init("is_MESSAGE"),
SR_KEMIP_BOOL, sr_kemi_core_is_method_message,
{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
},
{ str_init(""), str_init("is_KDMQ"),
SR_KEMIP_BOOL, sr_kemi_core_is_method_kdmq,
{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
},
{ str_init(""), str_init("is_GET"),
SR_KEMIP_BOOL, sr_kemi_core_is_method_get,
{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
},
{ str_init(""), str_init("is_POST"),
SR_KEMIP_BOOL, sr_kemi_core_is_method_post,
{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
},
{ str_init(""), str_init("is_PUT"),
SR_KEMIP_BOOL, sr_kemi_core_is_method_put,
{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
},
{ str_init(""), str_init("is_DELETE"),
SR_KEMIP_BOOL, sr_kemi_core_is_method_delete,
{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
},
{ str_init(""), str_init("is_UDP"),
SR_KEMIP_BOOL, sr_kemi_core_is_proto_udp,
{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,

@ -128,7 +128,7 @@ typedef enum request_method {
#define IFISMETHOD(methodname,firstchar) \
if ( (*tmp==(firstchar) || *tmp==((firstchar) | 32)) && \
strncasecmp( tmp+1, #methodname +1, methodname##_LEN-1)==0 && \
strncasecmp( tmp+1, &#methodname[1], methodname##_LEN-1)==0 && \
*(tmp+methodname##_LEN)==' ') { \
fl->type=SIP_REQUEST; \
fl->u.request.method.len=methodname##_LEN; \

@ -90,7 +90,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
tmp=buffer;
/* is it perhaps a reply, ie does it start with "SIP...." ? */
if ( (*tmp=='S' || *tmp=='s') &&
strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
strncasecmp( tmp+1, &SIP_VERSION[1], SIP_VERSION_LEN-1)==0 &&
(*(tmp+SIP_VERSION_LEN)==' ')) {
fl->type=SIP_REPLY;
fl->flags|=FLINE_FLAG_PROTO_SIP;
@ -98,7 +98,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
tmp=buffer+SIP_VERSION_LEN;
} else if (http_reply_parse != 0 && (*tmp=='H' || *tmp=='h')) {
/* 'HTTP/1.' */
if (strncasecmp( tmp+1, HTTP_VERSION+1, HTTP_VERSION_LEN-1)==0 &&
if (strncasecmp( tmp+1, &HTTP_VERSION[1], HTTP_VERSION_LEN-1)==0 &&
/* [0|1] */
((*(tmp+HTTP_VERSION_LEN)=='0') || (*(tmp+HTTP_VERSION_LEN)=='1')) &&
(*(tmp+HTTP_VERSION_LEN+1)==' ') ){
@ -111,7 +111,7 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
fl->u.reply.version.len=HTTP_VERSION_LEN+1 /*include last digit*/;
tmp=buffer+HTTP_VERSION_LEN+1 /* last digit */;
/* 'HTTP/2' */
} else if (strncasecmp( tmp+1, HTTP2_VERSION+1, HTTP2_VERSION_LEN-1)==0 &&
} else if (strncasecmp( tmp+1, &HTTP2_VERSION[1], HTTP2_VERSION_LEN-1)==0 &&
(*(tmp+HTTP2_VERSION_LEN)==' ')) {
fl->type=SIP_REPLY;
fl->flags|=FLINE_FLAG_PROTO_HTTP;
@ -238,13 +238,13 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
&& (fl->u.request.version.s[0]=='S'
|| fl->u.request.version.s[0]=='s')
&& !strncasecmp(fl->u.request.version.s+1,
SIP_VERSION+1, SIP_VERSION_LEN-1)) {
&SIP_VERSION[1], SIP_VERSION_LEN-1)) {
fl->flags|=FLINE_FLAG_PROTO_SIP;
} else if(fl->u.request.version.len >= HTTP_VERSION_LEN
&& (fl->u.request.version.s[0]=='H'
|| fl->u.request.version.s[0]=='h')
&& !strncasecmp(fl->u.request.version.s+1,
HTTP_VERSION+1, HTTP_VERSION_LEN-1)) {
&HTTP_VERSION[1], HTTP_VERSION_LEN-1)) {
fl->flags|=FLINE_FLAG_PROTO_HTTP;
}
}

@ -125,8 +125,7 @@ struct action* mk_action(enum action_type type, int count, ...)
for (i=0; i<a->count; i++) {
a->val[i].type = va_arg(args, int);
a->val[i].u.data = va_arg(args, void *);
DBG("ACTION_#%d #%d/%d: %d(%x)/ %p\n", a->type, i, a->count, a->val[i].type, a->val[i].type, a->val[i].u.data);
DBG("ACTION type%d, i/count %d/%d: type %d(%x)/ data %p\n", a->type, i, a->count, a->val[i].type, a->val[i].type, a->val[i].u.data);
}
va_end(args);

@ -3668,7 +3668,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i)
_wbufq_non_empty(tcpconn) )){
if (unlikely(TICKS_GE(t, tcpconn->wbuf_q.wr_timeout))){
LM_DBG("wr. timeout on CONN_RELEASE for %p refcnt= %d\n",
tcpconn, atomic_get(&tcpconn->refcnt));
(void*)tcpconn, atomic_get(&tcpconn->refcnt));
/* timeout */
if (unlikely(tcpconn->state==S_CONN_CONNECT)){
#ifdef USE_DST_BLACKLIST

@ -1732,7 +1732,7 @@ static ticks_t tcpconn_read_timeout(ticks_t t, struct timer_ln* tl, void* data)
* idx - index in the fd_array (or -1 if not known)
* return: -1 on error, or when we are not interested any more on reads
* from this fd (e.g.: we are closing it )
* 0 on EAGAIN or when by some other way it is known that no more
* 0 on EAGAIN or when by some other way it is known that no more
* io events are queued on the fd (the receive buffer is empty).
* Usefull to detect when there are no more io events queued for
* sigio_rt, epoll_et, kqueue.
@ -1740,7 +1740,7 @@ static ticks_t tcpconn_read_timeout(ticks_t t, struct timer_ln* tl, void* data)
* queued -- the receive buffer might still be non-empty)
*/
inline static int handle_io(struct fd_map* fm, short events, int idx)
{
{
int ret;
int n;
int read_flags;
@ -1748,10 +1748,11 @@ inline static int handle_io(struct fd_map* fm, short events, int idx)
int s;
long resp;
ticks_t t;
fd_map_t *ee = NULL;
/* update the local config */
cfg_update();
switch(fm->type){
case F_TCPMAIN:
again:
@ -1815,7 +1816,7 @@ repeat_1st_read:
if (unlikely(read_flags & RD_CONN_REPEAT_READ))
goto repeat_1st_read;
#endif /* USE_TLS */
/* must be before io_watch_add, io_watch_add might catch some
* already existing events => might call handle_io and
* handle_io might decide to del. the new connection =>
@ -1828,13 +1829,25 @@ repeat_1st_read:
local_timer_reinit(&con->timer);
local_timer_add(&tcp_reader_ltimer, &con->timer,
S_TO_TICKS(TCP_CHILD_TIMEOUT), t);
if (unlikely(io_watch_add(&io_w, s, POLLIN, F_TCPCONN, con)<0)){
if (unlikely(io_watch_add(&io_w, s, POLLIN, F_TCPCONN, con)<0)) {
LM_CRIT("io_watch_add failed for %p id %d fd %d, state %d, flags %x,"
" main fd %d, refcnt %d ([%s]:%u -> [%s]:%u)\n",
con, con->id, con->fd, con->state, con->flags,
con->s, atomic_get(&con->refcnt),
ip_addr2a(&con->rcv.src_ip), con->rcv.src_port,
ip_addr2a(&con->rcv.dst_ip), con->rcv.dst_port);
ee = get_fd_map(&io_w, s);
if(ee!=0 && ee->type==F_TCPCONN) {
tcp_connection_t *ec;
ec = (tcp_connection_t*)ee->data;
LM_CRIT("existing tcp con %p id %d fd %d, state %d, flags %x,"
" main fd %d, refcnt %d ([%s]:%u -> [%s]:%u)\n",
ec, ec->id, ec->fd, ec->state, ec->flags,
ec->s, atomic_get(&ec->refcnt),
ip_addr2a(&ec->rcv.src_ip), ec->rcv.src_port,
ip_addr2a(&ec->rcv.dst_ip), ec->rcv.dst_port);
}
tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev);
local_timer_del(&tcp_reader_ltimer, &con->timer);
goto con_error;

@ -428,9 +428,9 @@ int udp_rcv_loop()
static char buf [BUF_SIZE+1];
#endif
char *tmp;
union sockaddr_union* from;
unsigned int fromlen;
struct receive_info ri;
union sockaddr_union* fromaddr;
unsigned int fromaddrlen;
receive_info_t rcvi;
sr_event_param_t evp = {0};
#define UDP_RCV_PRINTBUF_SIZE 512
#define UDP_RCV_PRINT_LEN 100
@ -440,17 +440,18 @@ int udp_rcv_loop()
int l;
from=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union));
if (from==0){
fromaddr=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union));
if (fromaddr==0){
PKG_MEM_ERROR;
goto error;
}
memset(from, 0 , sizeof(union sockaddr_union));
ri.bind_address=bind_address; /* this will not change, we do it only once*/
ri.dst_port=bind_address->port_no;
ri.dst_ip=bind_address->address;
ri.proto=PROTO_UDP;
ri.proto_reserved1=ri.proto_reserved2=0;
memset(fromaddr, 0,sizeof(union sockaddr_union));
memset(&rcvi, 0, sizeof(receive_info_t));
/* these do not change, set only once*/
rcvi.bind_address=bind_address;
rcvi.dst_port=bind_address->port_no;
rcvi.dst_ip=bind_address->address;
rcvi.proto=PROTO_UDP;
/* initialize the config framework */
if (cfg_child_init()) goto error;
@ -463,9 +464,9 @@ int udp_rcv_loop()
goto error;
}
#endif
fromlen=sockaddru_len(bind_address->su);
len=recvfrom(bind_address->socket, buf, BUF_SIZE, 0, &from->s,
&fromlen);
fromaddrlen=sizeof(union sockaddr_union);
len=recvfrom(bind_address->socket, buf, BUF_SIZE, 0,
(struct sockaddr*)fromaddr, &fromaddrlen);
if (len==-1){
if (errno==EAGAIN){
LM_DBG("packet with bad checksum received\n");
@ -476,6 +477,11 @@ int udp_rcv_loop()
continue; /* goto skip;*/
else goto error;
}
if(fromaddrlen != (unsigned int)sockaddru_len(bind_address->su)) {
LM_ERR("ignoring data - unexpected from addr len: %u != %u\n",
fromaddrlen, (unsigned int)sockaddru_len(bind_address->su));
continue;
}
/* we must 0-term the messages, receive_msg expects it */
buf[len]=0; /* no need to save the previous char */
@ -498,16 +504,16 @@ int udp_rcv_loop()
LM_DBG("received on udp socket: (%d/%d/%d) [[%.*s]]\n",
j, i, len, j, printbuf);
}
ri.src_su=*from;
su2ip_addr(&ri.src_ip, from);
ri.src_port=su_getport(from);
rcvi.src_su=*fromaddr;
su2ip_addr(&rcvi.src_ip, fromaddr);
rcvi.src_port=su_getport(fromaddr);
if(unlikely(sr_event_enabled(SREV_NET_DGRAM_IN)))
{
void *sredp[3];
sredp[0] = (void*)buf;
sredp[1] = (void*)(&len);
sredp[2] = (void*)(&ri);
sredp[2] = (void*)(&rcvi);
evp.data = (void*)sredp;
if(sr_event_exec(SREV_NET_DGRAM_IN, &evp)<0) {
/* data handled by callback - continue to next packet */
@ -517,8 +523,8 @@ int udp_rcv_loop()
#ifndef NO_ZERO_CHECKS
if (!unlikely(sr_event_enabled(SREV_STUN_IN)) || (unsigned char)*buf != 0x00) {
if (len<MIN_UDP_PACKET) {
tmp=ip_addr2a(&ri.src_ip);
LM_DBG("probing packet received from %s %d\n", tmp, htons(ri.src_port));
tmp=ip_addr2a(&rcvi.src_ip);
LM_DBG("probing packet received from %s %d\n", tmp, htons(rcvi.src_port));
continue;
}
}
@ -530,8 +536,8 @@ int udp_rcv_loop()
continue;
}
#endif
if (ri.src_port==0){
tmp=ip_addr2a(&ri.src_ip);
if (rcvi.src_port==0){
tmp=ip_addr2a(&rcvi.src_ip);
LM_INFO("dropping 0 port packet from %s\n", tmp);
continue;
}
@ -540,24 +546,24 @@ int udp_rcv_loop()
cfg_update();
if (unlikely(sr_event_enabled(SREV_STUN_IN)) && (unsigned char)*buf == 0x00) {
/* stun_process_msg releases buf memory if necessary */
if ((stun_process_msg(buf, len, &ri)) != 0) {
if ((stun_process_msg(buf, len, &rcvi)) != 0) {
continue; /* some error occurred */
}
} else {
/* receive_msg must free buf too!*/
receive_msg(buf, len, &ri);
receive_msg(buf, len, &rcvi);
}
/* skip: do other stuff */
}
/*
if (from) pkg_free(from);
if (fromaddr) pkg_free(fromaddr);
return 0;
*/
error:
if (from) pkg_free(from);
if (fromaddr) pkg_free(fromaddr);
return -1;
}

@ -12,6 +12,12 @@ DEFS+=-DSER
ifeq ($(CROSS_COMPILE),)
XML2CFG=$(shell which xml2-config)
ifeq ($(XML2CFG),)
XML2CFG=$(shell \
if pkg-config --exists libxml-2.0; then \
echo 'pkg-config libxml-2.0'; \
fi)
endif
endif
ifneq ($(XML2CFG),)

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE database PUBLIC "-//kamailio.org//DTD DBSchema V1.1//EN"
"http://kamailio.org/pub/kamailio/dbschema/dtd/1.1/dbschema.dtd" [
<!ENTITY % entities SYSTEM "entities.xml">
%entities;
]>
<!-- Inclusion point for custom extensions for Kamailio -->
<database xmlns:xi="http://www.w3.org/2001/XInclude">
<name>CUSTOM Extensions</name>
<!-- Include extra definitions if found, it is not
an error if they are not present, although it
would produce a warning -->
<xi:include href="extra.xml">
<xi:fallback/>
</xi:include>
<!-- add more extensions here -->
<!-- <xi:include href="more-extras.xml"> -->
</database>

@ -21,6 +21,16 @@
</db:para>
</description>
<column id="id">
<name>id</name>
<type>unsigned int</type>
<size>&table_id_len;</size>
<autoincrement/>
<primary/>
<type db="dbtext">int,auto</type>
<description>unique ID</description>
</column>
<column id="first">
<name>first</name>
<type>int</type>

@ -37,14 +37,14 @@
<column id="action">
<name>action</name>
<type>short</type>
<default/>
<default>0</default>
<description>Action to do (0=blacklisted data, 1=whitelisted data, 2=blacklisted destination).</description>
</column>
<column id="type">
<name>type</name>
<type>short</type>
<default/>
<default>0</default>
<description>Type of data (0=user-agent, 1=country, 2=domain, 3=IP address, 4=user).</description>
</column>

@ -6,7 +6,7 @@
]>
<table id="version" xmlns:xi="http://www.w3.org/2001/XInclude">
<table id="version" xmlns:db="http://docbook.org/ns/docbook">>
<name>version</name>
<version>1</version>
<type db="mysql">&MYSQL_TABLE_TYPE;</type>

@ -26,8 +26,8 @@
* - Module: \ref acc
*/
#ifndef _AAA_DIAMETER_MSG_H
#define _AAA_DIAMETER_MSG_H
#ifndef _ACC_DIAM_MESSAGE_H_
#define _ACC_DIAM_MESSAGE_H_
#include "../../core/str.h"
#include "../../core/mem/mem.h"

@ -10,7 +10,7 @@ Daniel-Constantin Mierla
<miconda@gmail.com>
Copyright © 2010-2019 Daniel-Constantin Mierla (asipto.com)
Copyright © 2010-2019 Daniel-Constantin Mierla (asipto.com)
__________________________________________________________________
Table of Contents
@ -138,7 +138,7 @@ Chapter 1. Admin Guide
Note that 'sr', 'sr.hdr' and 'sr.pv' modules are always registered to
Lua.
Default value is "null".
Default value is “null”.
Example 1.2. Set register parameter
...

@ -10,8 +10,6 @@ Daniel-Constantin Mierla
<miconda@gmail.com>
Edited by
Alex Balashov
<abalashov@evaristesys.com>

@ -1650,45 +1650,45 @@ Chapter 4. Frequently Asked Questions
4.1.
Are there known bugs in the Perl module?
The Perl module does have a few shortcomings that may be regarded as
bugs.
* Missing module functions. Not all functions of other modules are
available for Perl access. The reason for this is a design property
of Kamailio. Making available more functions is work in progress.
* Perl and threads. Perl itself is, when compiled with the correct
parameters, thread safe; unfortunately, not all Perl modules are.
The DBI modules, especially (but not restricted to) DBI::ODBC are
known NOT to be thread safe.
Using DBI::ODBC -- and possibly other non-thread-safe Perl
extensions -- may result in erroneous behavior of Kamailio,
including (but not restricted to) server crashes and wrong routing.
Are there known bugs in the Perl module?
The Perl module does have a few shortcomings that may be regarded as
bugs.
* Missing module functions. Not all functions of other modules are
available for Perl access. The reason for this is a design property
of Kamailio. Making available more functions is work in progress.
* Perl and threads. Perl itself is, when compiled with the correct
parameters, thread safe; unfortunately, not all Perl modules are.
The DBI modules, especially (but not restricted to) DBI::ODBC are
known NOT to be thread safe.
Using DBI::ODBC -- and possibly other non-thread-safe Perl
extensions -- may result in erroneous behavior of Kamailio,
including (but not restricted to) server crashes and wrong routing.
4.2.
Where can I find more about Kamailio?
Where can I find more about Kamailio?
Take a look at https://www.kamailio.org/.
Take a look at https://www.kamailio.org/.
4.3.
Where can I post a question about this module?
Where can I post a question about this module?
First at all check if your question was already answered on one of our
mailing lists:
* User Mailing List -
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users
* Developer Mailing List -
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-dev
First at all check if your question was already answered on one of our
mailing lists:
* User Mailing List -
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users
* Developer Mailing List -
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-dev
E-mails regarding any stable Kamailio release should be sent to
<sr-users@lists.kamailio.org> and e-mails regarding development
versions should be sent to <sr-dev@lists.kamailio.org>.
E-mails regarding any stable Kamailio release should be sent to
<sr-users@lists.kamailio.org> and e-mails regarding development
versions should be sent to <sr-dev@lists.kamailio.org>.
4.4.
How can I report a bug?
How can I report a bug?
Please follow the guidelines provided at:
https://github.com/kamailio/kamailio/issues.
Please follow the guidelines provided at:
https://github.com/kamailio/kamailio/issues.

@ -1806,9 +1806,9 @@ PyObject *sr_apy_kemi_exec_func(PyObject *self, PyObject *args, int idx)
" took too long [%u us] (file:%s func:%s line:%d)\n",
(ket->mname.len>0)?ket->mname.s:"",
(ket->mname.len>0)?".":"", ket->fname.s, tdiff,
(pframe)?PyString_AsString(pframe->f_code->co_filename):"",
(pframe)?PyString_AsString(pframe->f_code->co_name):"",
(pframe)?PyCode_Addr2Line(pframe->f_code, pframe->f_lasti):0);
(pframe && pframe->f_code)?PyString_AsString(pframe->f_code->co_filename):"",
(pframe && pframe->f_code)?PyString_AsString(pframe->f_code->co_name):"",
(pframe && pframe->f_code)?PyCode_Addr2Line(pframe->f_code, pframe->f_lasti):0);
}
}

@ -1814,9 +1814,9 @@ PyObject *sr_apy_kemi_exec_func(PyObject *self, PyObject *args, int idx)
" took too long [%u ms] (file:%s func:%s line:%d)\n",
(ket->mname.len>0)?ket->mname.s:"",
(ket->mname.len>0)?".":"", ket->fname.s, tdiff,
(pframe)?PyBytes_AS_STRING(pframe->f_code->co_filename):"",
(pframe)?PyBytes_AS_STRING(pframe->f_code->co_name):"",
(pframe)?PyCode_Addr2Line(pframe->f_code, pframe->f_lasti):0);
(pframe && pframe->f_code)?PyBytes_AsString(pframe->f_code->co_filename):"",
(pframe && pframe->f_code)?PyBytes_AsString(pframe->f_code->co_name):"",
(pframe && pframe->f_code)?PyCode_Addr2Line(pframe->f_code, pframe->f_lasti):0);
}
}

@ -13,15 +13,15 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _AAA_DIAMETER_MSG_H
#define _AAA_DIAMETER_MSG_H
#ifndef _AUTH_DIAM_MESSAGE_H_
#define _AUTH_DIAM_MESSAGE_H_
#include "../../core/str.h"
#include "../../core/mem/mem.h"

@ -22,8 +22,6 @@ Jan Janak
<jan@iptel.org>
Edited by
Phil Lavin
<phil.lavin@synety.com>

@ -30,6 +30,7 @@
#include "../../core/mem/mem.h"
#include "../../core/parser/parse_hname2.h"
#include "../../core/sr_module.h"
#include "../../core/kemi.h"
#include "../../core/str.h"
#include "../../core/dprint.h"
#include "../../core/error.h"
@ -1064,3 +1065,164 @@ static int w_print_avps(struct sip_msg* msg, char* foo, char *bar)
return ops_print_avp();
}
static int ki_check_avps(struct sip_msg* msg, str* param, str *check)
{
struct fis_param *fparam, *fcheck;
regex_t* re = NULL;
int res;
if((fparam = avpops_parse_pvar(param->s)) == NULL)
{
LM_ERR("unable to get pseudo-variable in param 1\n");
return E_OUT_OF_MEM;
}
/* attr name is mandatory */
if (fparam->u.sval->type==PVT_NULL)
{
LM_ERR("null pseudo-variable in param 1\n");
pkg_free(fparam);
return E_UNSPEC;
}
if((fcheck = avpops_parse_pvar(check->s)) == NULL)
{
LM_ERR("failed to parse checked value \n");
pkg_free(fparam);
return E_UNSPEC;
}
/* if REGEXP op -> compile the expresion */
if(fcheck->ops&AVPOPS_OP_RE)
{
if( (fcheck->opd&AVPOPS_VAL_STR) != 0 )
{
if((re = (regex_t*) pkg_malloc(sizeof(regex_t))) == NULL)
{
PKG_MEM_ERROR;
pkg_free(fparam);
pkg_free(fcheck);
return E_OUT_OF_MEM;
}
LM_DBG("compiling regexp <%.*s>\n", fcheck->u.s.len, fcheck->u.s.s);
if (regcomp(re, fcheck->u.s.s,REG_EXTENDED|REG_ICASE|REG_NEWLINE))
{
LM_ERR("bad re <%.*s>\n", fcheck->u.s.len, fcheck->u.s.s);
pkg_free(fparam);
pkg_free(re);
pkg_free(fcheck);
return E_BAD_RE;
}
fcheck->u.s.s = (char*)re;
}
} else if (fcheck->ops&AVPOPS_OP_FM) {
if (!( fcheck->opd&AVPOPS_VAL_PVAR ||
(!(fcheck->opd&AVPOPS_VAL_PVAR) && fcheck->opd&AVPOPS_VAL_STR) ) )
{
LM_ERR("fast_match operation requires string value or "
"avp name/alias (%d/%d)\n", fcheck->opd, fcheck->ops);
pkg_free(fparam);
pkg_free(fcheck);
return E_UNSPEC;
}
}
res = ops_check_avp(msg, fparam, fcheck);
pkg_free(fparam);
pkg_free(fcheck);
if(re) pkg_free(re);
return res;
}
static int ki_copy_avps(struct sip_msg* msg, str *name1, str *name2)
{
struct fis_param *fname1, *fname2;
char *p = NULL;
int res;
if((fname1 = avpops_parse_pvar(name1->s)) == NULL)
{
LM_ERR("unable to get pseudo-variable in param 1\n");
return E_OUT_OF_MEM;
}
/* attr name is mandatory */
if (fname1->u.sval->type != PVT_AVP)
{
LM_ERR("you must specify only AVP as parameter\n");
pkg_free(fname1);
return E_UNSPEC;
}
/* avp / flags */
if ( (p=strchr(name2->s,'/')) != 0 )
*(p++) = 0;
if((fname2 = avpops_parse_pvar(name2->s)) == NULL)
{
LM_ERR("unable to get pseudo-variable in param 2\n");
return E_OUT_OF_MEM;
}
/* attr name is mandatory */
if (fname2->u.sval->type != PVT_AVP)
{
LM_ERR("you must specify only AVP as parameter\n");
pkg_free(fname1);
pkg_free(fname2);
return E_UNSPEC;
}
/* flags */
for( ; p&&*p ; p++ )
{
switch (*p) {
case 'g':
case 'G':
fname2->ops|=AVPOPS_FLAG_ALL;
break;
case 'd':
case 'D':
fname2->ops|=AVPOPS_FLAG_DELETE;
break;
case 'n':
case 'N':
fname2->ops|=AVPOPS_FLAG_CASTN;
break;
case 's':
case 'S':
fname2->ops|=AVPOPS_FLAG_CASTS;
break;
default:
LM_ERR("bad flag <%c>\n",*p);
pkg_free(fname1);
pkg_free(fname2);
return E_UNSPEC;
}
}
res = ops_copy_avp( msg, fname1, fname2);
pkg_free(fname1);
pkg_free(fname2);
return res;
}
/**
*
*/
/* clang-format off */
static sr_kemi_t sr_kemi_rtpengine_exports[] = {
{ str_init("avpops"), str_init("avp_check"),
SR_KEMIP_INT, ki_check_avps,
{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
},
{ str_init("avpops"), str_init("avp_copy"),
SR_KEMIP_INT, ki_copy_avps,
{ 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_rtpengine_exports);
return 0;
}

@ -6,6 +6,12 @@ NAME=cdp.so
ifeq ($(CROSS_COMPILE),)
XML2CFG=$(shell which xml2-config)
ifeq ($(XML2CFG),)
XML2CFG=$(shell \
if pkg-config --exists libxml-2.0; then \
echo 'pkg-config libxml-2.0'; \
fi)
endif
endif
ifneq ($(XML2CFG),)

@ -40,7 +40,7 @@ void update_gsu_response_timers(cdp_cc_acc_session_t* session, AAAMessage* msg)
AAA_AVP *mscc_avp = mscc_avp_list.head;
while (mscc_avp != NULL ) {
LM_DBG("MSCC AVP code is [%i] and data length is [%i]", mscc_avp->code, mscc_avp->data.len);
LM_DBG("MSCC AVP code is [%i] and data length is [%i]\n", mscc_avp->code, mscc_avp->data.len);
switch (mscc_avp->code) {
case AVP_Granted_Service_Unit:
y = AAAUngroupAVPS(mscc_avp->data);

@ -678,7 +678,8 @@ void add_peer_application(peer *p, int id, int vendor, app_type type)
p->applications[p->applications_cnt].id = id;
p->applications[p->applications_cnt].vendor = vendor;
p->applications[p->applications_cnt].type = type;
LM_DBG("Application %i of maximum %i\n", p->applications_cnt, p->applications_max);
LM_DBG("Application number %i with id %d and vendor %d added, maximum %i\n",
p->applications_cnt, id, vendor, p->applications_max);
p->applications_cnt++;
}
@ -695,7 +696,7 @@ int count_Supported_Vendor_Id_AVPS(AAAMessage *msg)
break;
avp_vendor = AAAFindMatchingAVP(msg,avp_vendor->next,AVP_Supported_Vendor_Id,0,0);
}
LM_DBG("Found %i Supported_Vendor AVPS", avp_vendor_cnt);
LM_DBG("Found %i Supported_Vendor AVPS\n", avp_vendor_cnt);
return avp_vendor_cnt;
}
@ -715,6 +716,12 @@ void save_peer_applications(peer *p,AAAMessage *msg)
supported_vendor_id_avp_cnt = count_Supported_Vendor_Id_AVPS(msg);
if (supported_vendor_id_avp_cnt == 0) {
LM_INFO("No Supported-Vendor-Id AVP found, assuming compability with %d vendor(s) from our CER msg\n",
config->supported_vendors_cnt);
supported_vendor_id_avp_cnt = 1;
}
for(avp=msg->avpList.head;avp;avp = avp->next)
switch (avp->code){
@ -728,6 +735,8 @@ void save_peer_applications(peer *p,AAAMessage *msg)
total_cnt+=2;/* wasteful, but let's skip decoding */
break;
}
LM_DBG("Total count of applications is %d\n", total_cnt);
p->applications_cnt = 0;
p->applications = shm_malloc(sizeof(app_config)*total_cnt);
p->applications_max = total_cnt;
@ -745,7 +754,6 @@ void save_peer_applications(peer *p,AAAMessage *msg)
add_peer_application(p,id,0,DP_AUTHORIZATION);
avp_vendor = AAAFindMatchingAVP(msg,0,AVP_Supported_Vendor_Id,0,0);
while (avp_vendor) {
vendor = get_4bytes(avp_vendor->data.s);
LM_DBG("Found Supported Vendor for Application %i: %i\n", DP_AUTHORIZATION, vendor);
add_peer_application(p,id,vendor,DP_AUTHORIZATION);

@ -396,7 +396,7 @@ again:
*fd = *tmp;
}else{
if(!cmsg)
LM_ERR("receive_fd: no descriptor passed, empty control message");
LM_ERR("receive_fd: no descriptor passed, empty control message\n");
else
LM_ERR("receive_fd: no descriptor passed, cmsg=%p,"
"len=%d\n", cmsg, (unsigned)cmsg->cmsg_len);
@ -768,7 +768,7 @@ int receive_loop(peer *original_peer)
}
LM_DBG("select_recv(): Send pipe says [%p] %d\n",msg,cnt);
if (sp->tcp_socket<0){
LM_ERR("select_recv(): got a signal to send something, but the connection was not opened");
LM_ERR("select_recv(): got a signal to send something, but the connection was not opened\n");
} else {
while( (cnt=write(sp->tcp_socket,msg->buf.s,msg->buf.len))==-1 ) {
if (errno==EINTR)
@ -883,7 +883,7 @@ int peer_connect(peer *p)
/* try to set the local socket used to connect to the peer */
if (p->src_addr.s && p->src_addr.len > 0) {
LM_DBG("peer_connect(): connetting to peer via src addr=%.*s",p->src_addr.len, p->src_addr.s);
LM_DBG("peer_connect(): connecting to peer via src addr=%.*s\n",p->src_addr.len, p->src_addr.s);
memset (&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_socktype = SOCK_STREAM;

@ -258,11 +258,11 @@ int put_task(peer *p, AAAMessage *msg) {
length_percentage = num_tasks/tasks->max*100;
if(length_percentage > workerq_length_threshold_percentage) {
LM_WARN("Queue length has exceeded length threshold percentage"
" [%i] and is length [%i]", length_percentage, num_tasks);
" [%i] and is length [%i]\n", length_percentage, num_tasks);
}
}
//int num_tasks = tasks->end - tasks->start;
//LM_ERR("Added task to task queue. Queue length [%i]", num_tasks);
//LM_ERR("Added task to task queue. Queue length [%i]\n", num_tasks);
return 1;
@ -300,7 +300,7 @@ task_t take_task() {
lock_release(tasks->lock);
//int num_tasks = tasks->end - tasks->start;
//LM_ERR("Taken task from task queue. Queue length [%i]", num_tasks);
//LM_ERR("Taken task from task queue. Queue length [%i]\n", num_tasks);
return t;

@ -8,8 +8,6 @@ Edited by
Jason Penton
Edited by
Richard Good
Copyright © 2006 FhG Fokus
@ -1658,28 +1656,28 @@ Chapter 3. Frequently Asked Questions
3.1.
Where can I find more about Kamailio?
Where can I find more about Kamailio?
Take a look at https://www.kamailio.org/.
Take a look at https://www.kamailio.org/.
3.2.
Where can I post a question about this module?
Where can I post a question about this module?
First at all check if your question was already answered on one of our
mailing lists:
* User Mailing List -
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users
* Developer Mailing List -
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-dev
First at all check if your question was already answered on one of our
mailing lists:
* User Mailing List -
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users
* Developer Mailing List -
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-dev
E-mails regarding any stable Kamailio release should be sent to
<sr-users@lists.kamailio.org> and e-mails regarding development
versions should be sent to <sr-dev@lists.kamailio.org>.
E-mails regarding any stable Kamailio release should be sent to
<sr-users@lists.kamailio.org> and e-mails regarding development
versions should be sent to <sr-dev@lists.kamailio.org>.
3.3.
How can I report a bug?
How can I report a bug?
Please follow the guidelines provided at:
https://github.com/kamailio/kamailio/issues.
Please follow the guidelines provided at:
https://github.com/kamailio/kamailio/issues.

@ -188,18 +188,32 @@ modparam("cnxcc", "credit_check_period", 1)
Associates the call with a customer id and sets the max credit, connect
cost, cost per second, initial pulse and final pulse. The discount is
calculated in pulses (30/6, 1/1, etc) and subtracted from the pool of
calculated in pulses (1/1, 60/1, etc) and subtracted from the pool of
credit.
The customer value can be provided as a string or a variable holding a
string.
string. This value identifies all calls from the same customer.
The maxcredit (float) value is the maximum credit available for the
current call.
The connect (float) value is the connect cost for the current call.
The cps (float) value is the cost per second for the current call.
The ipuse (integer) value is the initial pulse and establishes the
minimum time to be charged. For example, value 1 establishes a charge
per second and value 60 sets a charge per minute. If it is taken as
value 60, even if the duration is 5 seconds, 1 minute will be charged.
The maxcredit, connect and cps can be double (float) or integer values,
they have to be provided as static string values of variables holding
string values.
The fpulse (integer) value is the final pulse and establishes, from the
initial pulse, the time range to be charged. For example, the value 1
establishes a charge per second, 5 sets a charge in blocks of 5
seconds, 60 sets a full minute charge.
The ipulse and fpulse values are integer values, they can be also given
via variables holding integers.
1/1 will make a charge per seconds for the entire call. 60/1 will make
a charge per seconds with the first full minute. 60/60 always perform a
full minute charge.
Return code:
* 1 - successful
@ -210,12 +224,15 @@ modparam("cnxcc", "credit_check_period", 1)
...
cnxcc_set_max_credit("john-doe", "100", "3.0", "0.5", 60, 1);
...
$var(customer) = "john-doe-premium"; # customer id
$var(credit) = "100"; # max credit
$var(connect) = "3.0"; # connect const
$var(cps) = "0.5"; # cost per second
$var(initial_p) = 60; # initial pulse
$var(final_p) = 1; # final pulse
$var(customer) = "john-doe"; # customer id
$var(credit) = "100"; # max credit for all calls with the same
# customer id
$var(connect) = "3.0"; # connect cost or initial cost for the call
$var(cps) = "0.5"; # cost per second
$var(initial_p) = 60; # initial pulse (60 = the first minute will be
# charged even if the call is shorter)
$var(final_p) = 1; # final pulse (after the first minute, it will
# be charge in ranges of 1 second)
cnxcc_set_max_credit("$var(customer)", "$var(credit)", "$var(connect)",
"$var(cps)", "$var(initial_p)", "$var(final_p)");
...

@ -19,10 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include "cnxcc.h"

@ -23,6 +23,8 @@
#ifndef _CNXCC_H
#define _CNXCC_H
#include <time.h>
#include "../../core/str.h"
#define DATETIME_SIZE sizeof("0001-01-01 00:00:00")
@ -37,12 +39,12 @@ static inline unsigned int get_current_timestamp()
static inline int timestamp2isodt(str *dest, unsigned int timestamp)
{
time_t tim;
struct tm *tmPtr;
struct tm tmPtr;
tim = timestamp;
tmPtr = localtime(&tim);
localtime_r(&tim, &tmPtr);
strftime(dest->s, DATETIME_SIZE, "%Y-%m-%d %H:%M:%S", tmPtr);
strftime(dest->s, DATETIME_SIZE, "%Y-%m-%d %H:%M:%S", &tmPtr);
dest->len = DATETIME_LENGTH;
return 0;

@ -27,32 +27,28 @@
#include <sys/ipc.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <ctype.h>
#include "../../core/sr_module.h"
#include "../../core/mod_fix.h"
#include "../../core/dprint.h"
#include "../../core/error.h"
#include "../../core/mem/mem.h"
#include "../../core/shm_init.h"
#include "../../core/mem/shm_mem.h"
#include "../../core/pvar.h"
#include "../../core/locking.h"
#include "../../core/lock_ops.h"
#include "../../core/str_hash.h"
#include "../../core/timer_proc.h"
#include "../../modules/tm/tm_load.h"
#include "../../core/parser/parse_from.h"
#include "../../core/parser/parse_to.h"
#include "../../core/parser/parse_uri.h"
#include "../../core/parser/parse_cseq.h"
#include "../../core/parser/contact/parse_contact.h"
#include "../../core/parser/contact/contact.h"
#include "../../core/parser/parse_rr.h"
#include "../../core/mod_fix.h"
#include "../tm/tm_load.h"
#include "../dialog/dlg_load.h"
#include "../dialog/dlg_hash.h"
#include "../../core/fmsg.h"
#include "../../core/rpc.h"
#include "../../core/rpc_lookup.h"
#include "../../core/kemi.h"
@ -91,6 +87,8 @@ static int __init_hashtable(struct str_hash_table *ht);
*/
static int __shm_str_hash_alloc(struct str_hash_table *ht, int size);
static void __free_credit_data_hash_entry(struct str_hash_entry *e);
static void __free_credit_data(credit_data_t *credit_data, hash_tables_t *hts,
struct str_hash_entry *cd_entry);
/*
* PV management functions
@ -123,6 +121,7 @@ static call_t *__alloc_new_call_by_money(credit_data_t *credit_data,
double cost_per_second, int initial_pulse, int final_pulse);
static void __notify_call_termination(sip_msg_t *msg);
static void __free_call(call_t *call);
static void __delete_call(call_t *call, credit_data_t *credit_data);
static int __has_to_tag(struct sip_msg *msg);
static credit_data_t *__alloc_new_credit_data(
str *client_id, credit_type_t type);
@ -170,7 +169,7 @@ static cmd_export_t cmds[] = {
static param_export_t params[] = {
{"dlg_flag", INT_PARAM, &_data.ctrl_flag },
{"credit_check_period", INT_PARAM, &_data.check_period },
{"redis", STR_PARAM, &_data.redis_cnn_str.s },
{"redis", PARAM_STR, &_data.redis_cnn_str },
{ 0, 0, 0 }
};
/* clang-format on */
@ -262,9 +261,6 @@ static int __mod_init(void)
return -1;
}
if(_data.redis_cnn_str.s)
_data.redis_cnn_str.len = strlen(_data.redis_cnn_str.s);
_data.time.credit_data_by_client =
shm_malloc(sizeof(struct str_hash_table));
_data.time.call_data_by_cid = shm_malloc(sizeof(struct str_hash_table));
@ -284,15 +280,11 @@ static int __mod_init(void)
memset(_data.channel.call_data_by_cid, 0, sizeof(struct str_hash_table));
_data.stats = (stats_t *)shm_malloc(sizeof(stats_t));
if(!_data.stats) {
LM_ERR("Error allocating shared memory stats\n");
SHM_MEM_ERROR;
return -1;
}
_data.stats->active = 0;
_data.stats->dropped = 0;
_data.stats->total = 0;
memset(_data.stats, 0, sizeof(stats_t));
if(__init_hashtable(_data.time.credit_data_by_client) != 0)
return -1;
@ -312,9 +304,7 @@ static int __mod_init(void)
if(__init_hashtable(_data.channel.call_data_by_cid) != 0)
return -1;
cnxcc_lock_init(_data.lock);
cnxcc_lock_init(_data.time.lock);
cnxcc_lock_init(_data.money.lock);
cnxcc_lock_init(_data.channel.lock);
@ -433,21 +423,22 @@ static int __child_init(int rank)
static int __init_hashtable(struct str_hash_table *ht)
{
if(__shm_str_hash_alloc(ht, HT_SIZE) != 0) {
LM_ERR("Error allocating shared memory hashtable\n");
if(ht == NULL)
return -1;
if(__shm_str_hash_alloc(ht, HT_SIZE) != 0)
return -1;
}
str_hash_init(ht);
return 0;
}
static void __dialog_created_callback(
struct dlg_cell *cell, int type, struct dlg_cb_params *params)
struct dlg_cell *cell, int type, struct dlg_cb_params *_params)
{
struct sip_msg *msg = NULL;
msg = params->direction == SIP_REPLY ? params->rpl : params->req;
msg = _params->direction == SIP_REPLY ? _params->rpl : _params->req;
if(msg == NULL) {
LM_ERR("Error getting direction of SIP msg\n");
@ -471,7 +462,7 @@ static void __dialog_created_callback(
}
static void __dialog_confirmed_callback(
struct dlg_cell *cell, int type, struct dlg_cb_params *params)
struct dlg_cell *cell, int type, struct dlg_cb_params *_params)
{
LM_DBG("Dialog confirmed for CID [%.*s]\n", cell->callid.len,
cell->callid.s);
@ -480,7 +471,7 @@ static void __dialog_confirmed_callback(
}
static void __dialog_terminated_callback(
struct dlg_cell *cell, int type, struct dlg_cb_params *params)
struct dlg_cell *cell, int type, struct dlg_cb_params *_params)
{
LM_DBG("Dialog terminated for CID [%.*s]\n", cell->callid.len,
cell->callid.s);
@ -621,7 +612,6 @@ static void __stop_billing(str *callid)
LM_ERR("[%.*s] call pointer is null\n", callid->len, callid->s);
return;
}
if(hts == NULL) {
LM_ERR("[%.*s] result hashtable pointer is null\n", callid->len,
callid->s);
@ -629,13 +619,9 @@ static void __stop_billing(str *callid)
}
cnxcc_lock(hts->lock);
/*
* Search credit_data by client_id
*/
// Search credit_data by client_id
cd_entry = str_hash_get(
hts->credit_data_by_client, call->client_id.s, call->client_id.len);
if(cd_entry == NULL) {
LM_ERR("Credit data not found for CID [%.*s], client-ID [%.*s]\n",
callid->len, callid->s, call->client_id.len, call->client_id.s);
@ -644,117 +630,24 @@ static void __stop_billing(str *callid)
}
credit_data = (credit_data_t *)cd_entry->u.p;
if(credit_data == NULL) {
LM_ERR("[%.*s]: credit_data pointer is null\n", callid->len, callid->s);
cnxcc_unlock(hts->lock);
return;
}
cnxcc_unlock(hts->lock);
/*
* Update calls statistics
*/
cnxcc_lock(_data.lock);
_data.stats->active--;
_data.stats->total--;
cnxcc_unlock(_data.lock);
cnxcc_lock(credit_data->lock);
LM_DBG("Call [%.*s] of client-ID [%.*s], ended\n", callid->len, callid->s,
call->client_id.len, call->client_id.s);
cnxcc_lock(credit_data->lock);
__delete_call(call, credit_data);
/*
* This call just ended and we need to remove it from the summ.
*/
if(call->confirmed) {
credit_data->concurrent_calls--;
credit_data->ended_calls_consumed_amount += call->consumed_amount;
if(_data.redis) {
redis_incr_by_int(credit_data, "concurrent_calls", -1);
redis_incr_by_double(credit_data, "ended_calls_consumed_amount",
call->consumed_amount);
}
}
credit_data->number_of_calls--;
if(_data.redis)
redis_incr_by_int(credit_data, "number_of_calls", -1);
if(credit_data->concurrent_calls < 0) {
LM_ERR("[BUG]: number of concurrent calls dropped to negative value: "
"%d\n",
credit_data->concurrent_calls);
}
if(credit_data->number_of_calls < 0) {
LM_ERR("[BUG]: number of calls dropped to negative value: %d\n",
credit_data->number_of_calls);
}
/*
* Remove (and free) the call from the list of calls of the current credit_data
*/
clist_rm(call, next, prev);
/* return if credit_data is being deallocated.
* the call and the credit data will be freed by terminate_all_calls()
*/
if(credit_data->deallocating) {
return;
}
__free_call(call);
/*
* In case there are no active calls for a certain client, we remove the client-id from the hash table.
* This way, we can save memory for useful clients.
*
*/
if(credit_data->number_of_calls == 0) {
LM_DBG("Removing client [%.*s] and its calls from the list\n",
credit_data->call_list->client_id.len,
credit_data->call_list->client_id.s);
credit_data->deallocating = 1;
cnxcc_lock(hts->lock);
if(_data.redis) {
redis_clean_up_if_last(credit_data);
shm_free(credit_data->str_id);
}
/*
* Remove the credit_data_t from the hash table
*/
str_hash_del(cd_entry);
cnxcc_unlock(hts->lock);
/*
* Free client_id in list's root
*/
shm_free(credit_data->call_list->client_id.s);
shm_free(credit_data->call_list);
/*
* Release the lock since we are going to free the entry down below
*/
cnxcc_unlock(credit_data->lock);
/*
* Free the whole entry
*/
__free_credit_data_hash_entry(cd_entry);
/*
* return without releasing the acquired lock over credit_data. Why? Because we just freed it.
*/
__free_credit_data(credit_data, hts, cd_entry);
return;
}
@ -915,7 +808,7 @@ static void __start_billing(
* Store from-tag value
*/
if(shm_str_dup(&call->sip_data.from_tag, &tags[0]) != 0) {
LM_ERR("No more pkg memory\n");
SHM_MEM_ERROR;
goto exit;
}
@ -923,13 +816,13 @@ static void __start_billing(
* Store to-tag value
*/
if(shm_str_dup(&call->sip_data.to_tag, &tags[1]) != 0) {
LM_ERR("No more pkg memory\n");
SHM_MEM_ERROR;
goto exit;
}
if(shm_str_dup(&call->sip_data.from_uri, from_uri) != 0
|| shm_str_dup(&call->sip_data.to_uri, to_uri) != 0) {
LM_ERR("No more pkg memory\n");
SHM_MEM_ERROR;
goto exit;
}
@ -947,6 +840,78 @@ exit:
cnxcc_unlock(call->lock);
}
static void __delete_call(call_t *call, credit_data_t *credit_data)
{
// Update calls statistics
cnxcc_lock(_data.lock);
_data.stats->active--;
_data.stats->total--;
cnxcc_unlock(_data.lock);
// This call just ended and we need to remove it from the summ.
if(call->confirmed) {
credit_data->concurrent_calls--;
credit_data->ended_calls_consumed_amount += call->consumed_amount;
if(_data.redis) {
redis_incr_by_int(credit_data, "concurrent_calls", -1);
redis_incr_by_double(credit_data, "ended_calls_consumed_amount",
call->consumed_amount);
}
}
credit_data->number_of_calls--;
if(_data.redis)
redis_incr_by_int(credit_data, "number_of_calls", -1);
if(credit_data->concurrent_calls < 0) {
LM_BUG("number of concurrent calls dropped to negative value: %d\n",
credit_data->concurrent_calls);
}
if(credit_data->number_of_calls < 0) {
LM_BUG("number of calls dropped to negative value: %d\n",
credit_data->number_of_calls);
}
// Remove (and free) the call from the list of calls of the current credit_data
clist_rm(call, next, prev);
__free_call(call);
}
// must be called with lock held on credit_data
static void __free_credit_data(credit_data_t *credit_data, hash_tables_t *hts,
struct str_hash_entry *cd_entry)
{
if(credit_data->deallocating) {
LM_DBG("deallocating, skip\n");
return;
}
LM_DBG("Removing client [%.*s] and its calls from the list\n",
credit_data->call_list->client_id.len,
credit_data->call_list->client_id.s);
credit_data->deallocating = 1;
cnxcc_lock(hts->lock);
if(_data.redis) {
redis_clean_up_if_last(credit_data);
shm_free(credit_data->str_id);
}
// Remove the credit_data_t from the hash table
str_hash_del(cd_entry);
cnxcc_unlock(hts->lock);
// Free client_id in list's root
shm_free(credit_data->call_list->client_id.s);
shm_free(credit_data->call_list);
// Release the lock since we are going to free the entry down below
cnxcc_unlock(credit_data->lock);
// Free the whole entry
__free_credit_data_hash_entry(cd_entry);
}
// must be called with lock held on credit_data
/* terminate all calls and remove credit_data */
void terminate_all_calls(credit_data_t *credit_data)
@ -954,6 +919,7 @@ void terminate_all_calls(credit_data_t *credit_data)
call_t *call = NULL, *tmp = NULL;
struct str_hash_entry *cd_entry = NULL;
hash_tables_t *hts = NULL;
unsigned int pending = 0;
switch(credit_data->type) {
case CREDIT_MONEY:
@ -975,57 +941,44 @@ void terminate_all_calls(credit_data_t *credit_data)
credit_data->call_list->client_id.len);
if(cd_entry == NULL) {
LM_WARN("credit data itme not found\n");
LM_WARN("credit data item not found\n");
return;
}
// tell __stop_billing() not to __free_credit_data
credit_data->deallocating = 1;
clist_foreach_safe(credit_data->call_list, call, tmp, next)
{
if(call->sip_data.callid.s != NULL) {
LM_DBG("Killing call with CID [%.*s]\n", call->sip_data.callid.len,
call->sip_data.callid.s);
/*
* Update number of calls forced to end
*/
_data.stats->dropped++;
terminate_call(call);
__free_call(call);
if(call->confirmed) {
LM_DBG("Killing call with CID [%.*s]\n",
call->sip_data.callid.len, call->sip_data.callid.s);
// Update number of calls forced to end
_data.stats->dropped++;
terminate_call(call);
// call memory will be cleaned by __stop_billing() when
// __dialog_terminated_callback() is triggered
} else {
LM_DBG("Non confirmed call with CID[%.*s], setting "
"max_amount:%f to 0\n",
call->sip_data.callid.len, call->sip_data.callid.s,
call->max_amount);
call->max_amount = 0;
pending = 1;
}
} else {
LM_WARN("invalid call structure %p\n", call);
}
}
cnxcc_lock(hts->lock);
if(_data.redis) {
redis_clean_up_if_last(credit_data);
shm_free(credit_data->str_id);
credit_data->deallocating = 0;
if(!pending) {
__free_credit_data(credit_data, hts, cd_entry);
} else {
LM_DBG("credit data item left\n");
cnxcc_unlock(credit_data->lock);
}
/*
* Remove the credit_data_t from the hash table
*/
str_hash_del(cd_entry);
cnxcc_unlock(hts->lock);
/*
* Free client_id in list's root
*/
shm_free(credit_data->call_list->client_id.s);
shm_free(credit_data->call_list);
/*
* Release the lock since we are going to free the entry down below
*/
cnxcc_unlock(credit_data->lock);
/*
* Free the whole entry
*/
__free_credit_data_hash_entry(cd_entry);
}
/*
@ -1089,9 +1042,10 @@ static int __shm_str_hash_alloc(struct str_hash_table *ht, int size)
{
ht->table = shm_malloc(sizeof(struct str_hash_head) * size);
if(!ht->table)
if(!ht->table) {
SHM_MEM_ERROR;
return -1;
}
ht->size = size;
return 0;
}
@ -1110,7 +1064,7 @@ int terminate_call(call_t *call)
call->dlg_h_entry);
data = &call->sip_data;
if(faked_msg_init_with_dlg_info(&data->callid, &data->from_uri,
if(cnxcc_faked_msg_init_with_dlg_info(&data->callid, &data->from_uri,
&data->from_tag, &data->to_uri, &data->to_tag, &dmsg)
!= 0) {
LM_ERR("[%.*s]: error generating faked sip message\n", data->callid.len,
@ -1125,8 +1079,8 @@ int terminate_call(call_t *call)
}
if(!_dlgbinds.terminate_dlg(cell, NULL)) {
LM_DBG("dlg_end_dlg sent to call [%.*s]\n", call->sip_data.callid.len,
call->sip_data.callid.s);
LM_DBG("dlg_end_dlg sent to call [%.*s]\n", cell->callid.len,
cell->callid.s);
if(_data.cs_route_number >= 0)
__notify_call_termination(dmsg);
@ -1197,7 +1151,7 @@ static credit_data_t *__get_or_create_credit_data_entry(
return (credit_data_t *)e->u.p;
no_memory:
LM_ERR("No shared memory left\n");
SHM_MEM_ERROR;
return NULL;
}
@ -1205,17 +1159,13 @@ static credit_data_t *__alloc_new_credit_data(
str *client_id, credit_type_t type)
{
credit_data_t *credit_data = shm_malloc(sizeof(credit_data_t));
;
if(credit_data == NULL)
goto no_memory;
memset(credit_data, 0, sizeof(credit_data_t));
cnxcc_lock_init(credit_data->lock);
credit_data->call_list = shm_malloc(sizeof(call_t));
if(credit_data->call_list == NULL)
goto no_memory;
@ -1231,7 +1181,6 @@ static credit_data_t *__alloc_new_credit_data(
if(_data.redis) {
credit_data->str_id = shm_malloc(client_id->len + 1);
if(!credit_data->str_id)
goto no_memory;
@ -1239,14 +1188,7 @@ static credit_data_t *__alloc_new_credit_data(
snprintf(credit_data->str_id, client_id->len + 1, "%.*s",
client_id->len, client_id->s);
}
credit_data->max_amount = 0;
credit_data->concurrent_calls = 0;
credit_data->consumed_amount = 0;
credit_data->ended_calls_consumed_amount = 0;
credit_data->number_of_calls = 0;
credit_data->type = type;
credit_data->deallocating = 0;
if(!_data.redis)
return credit_data;
@ -1257,7 +1199,7 @@ static credit_data_t *__alloc_new_credit_data(
return credit_data;
no_memory:
LM_ERR("No shared memory left\n");
SHM_MEM_ERROR;
error:
return NULL;
}
@ -1277,9 +1219,10 @@ static call_t *__alloc_new_call_by_money(credit_data_t *credit_data,
call = shm_malloc(sizeof(call_t));
if(call == NULL) {
LM_ERR("No shared memory left\n");
SHM_MEM_ERROR;
goto error;
}
memset(call, 0, sizeof(call_t));
if((!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0)
|| shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0) {
@ -1287,16 +1230,6 @@ static call_t *__alloc_new_call_by_money(credit_data_t *credit_data,
goto error;
}
call->sip_data.to_uri.s = NULL;
call->sip_data.to_uri.len = 0;
call->sip_data.to_tag.s = NULL;
call->sip_data.to_tag.len = 0;
call->sip_data.from_uri.s = NULL;
call->sip_data.from_uri.len = 0;
call->sip_data.from_tag.s = NULL;
call->sip_data.from_tag.len = 0;
call->consumed_amount = initial_pulse * cost_per_second;
call->connect_amount = connect_cost;
call->confirmed = FALSE;
@ -1356,6 +1289,7 @@ static call_t *__alloc_new_call_by_time(
LM_ERR("No shared memory left\n");
goto error;
}
memset(call, 0, sizeof(call_t));
if((!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0)
|| shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0) {
@ -1363,16 +1297,6 @@ static call_t *__alloc_new_call_by_time(
goto error;
}
call->sip_data.to_uri.s = NULL;
call->sip_data.to_uri.len = 0;
call->sip_data.to_tag.s = NULL;
call->sip_data.to_tag.len = 0;
call->sip_data.from_uri.s = NULL;
call->sip_data.from_uri.len = 0;
call->sip_data.from_tag.s = NULL;
call->sip_data.from_tag.len = 0;
call->consumed_amount = 0;
call->confirmed = FALSE;
call->max_amount = max_secs;
@ -1423,9 +1347,10 @@ static call_t *alloc_new_call_by_channel(
call = shm_malloc(sizeof(call_t));
if(call == NULL) {
LM_ERR("No shared memory left\n");
SHM_MEM_ERROR;
goto error;
}
memset(call, 0, sizeof(call_t));
if((!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) != 0)
|| shm_str_dup(&call->sip_data.callid, &msg->callid->body) != 0) {
@ -1433,16 +1358,6 @@ static call_t *alloc_new_call_by_channel(
goto error;
}
call->sip_data.to_uri.s = NULL;
call->sip_data.to_uri.len = 0;
call->sip_data.to_tag.s = NULL;
call->sip_data.to_tag.len = 0;
call->sip_data.from_uri.s = NULL;
call->sip_data.from_uri.len = 0;
call->sip_data.from_tag.s = NULL;
call->sip_data.from_tag.len = 0;
call->consumed_amount = 0;
call->confirmed = FALSE;
call->max_amount = max_chan;
@ -1534,14 +1449,13 @@ static int __add_call_by_cid(str *cid, call_t *call, credit_type_t type)
}
e = shm_malloc(sizeof(struct str_hash_entry));
if(e == NULL) {
LM_ERR("No shared memory left\n");
SHM_MEM_ERROR;
return -1;
}
if(shm_str_dup(&e->key, cid) != 0) {
LM_ERR("No shared memory left\n");
SHM_MEM_ERROR;
return -1;
}
@ -1961,6 +1875,10 @@ static int __set_max_time(sip_msg_t *msg, char *pclient, char *pmaxsecs)
static int ki_update_max_time(sip_msg_t *msg, str *sclient, int secs)
{
credit_data_t *credit_data = NULL;
struct str_hash_table *ht = NULL;
struct str_hash_entry *e = NULL;
double update_fraction = secs;
call_t *call = NULL, *tmp_call = NULL;
set_ctrl_flag(msg);
@ -1985,12 +1903,7 @@ static int ki_update_max_time(sip_msg_t *msg, str *sclient, int secs)
sclient->len, sclient->s, secs, msg->callid->body.len,
msg->callid->body.s);
struct str_hash_table *ht = NULL;
struct str_hash_entry *e = NULL;
ht = _data.time.credit_data_by_client;
double update_fraction = secs;
call_t *call = NULL, *tmp_call = NULL;
cnxcc_lock(_data.time.lock);
e = str_hash_get(ht, sclient->s, sclient->len);

@ -25,7 +25,7 @@
#include "../../core/locking.h"
#include "../../core/atomic_ops.h"
#include "../../core/str_hash.h"
#include "../../core/parser/parse_rr.h"
#include "../../core/flags.h"
#define str_shm_free_if_not_null(_var_) \
if(_var_.s != NULL) { \
@ -35,7 +35,7 @@
}
/*!
* \brief Init a cnxcc_lock
* \brief Init a cnxcc_lock
* \param _entry locked entry
*/
#define cnxcc_lock_init(_entry) \
@ -89,13 +89,15 @@ typedef struct stats
unsigned int dropped;
} stats_t;
typedef enum cnxpvtypes {
typedef enum cnxpvtypes
{
CNX_PV_ACTIVE = 1,
CNX_PV_TOTAL,
CNX_PV_DROPPED
} cnxpvtypes_t;
typedef enum credit_type {
typedef enum credit_type
{
CREDIT_TIME,
CREDIT_MONEY,
CREDIT_CHANNEL
@ -212,7 +214,7 @@ typedef struct credit_data
char *str_id;
// flag to mark this instance in the process of being eliminated
int deallocating : 1;
unsigned int deallocating : 1;
} credit_data_t;

@ -144,9 +144,18 @@ error:
static struct redis *__alloc_redis(char *ip, int port, int db)
{
struct redis *redis = pkg_malloc(sizeof(struct redis));
if(!redis) {
PKG_MEM_ERROR;
return NULL;
}
int len = strlen(ip);
redis->ip = pkg_malloc(len + 1);
if(!redis->ip) {
PKG_MEM_ERROR;
pkg_free(redis);
return NULL;
}
strcpy(redis->ip, ip);
redis->port = port;
@ -226,8 +235,7 @@ static struct redis *__redis_connect(struct redis *redis)
static int __redis_select_db(redisContext *ctxt, int db)
{
redisReply *rpl;
rpl = redisCommand(ctxt, "SELECT %d", db);
redisReply *rpl = redisCommand(ctxt, "SELECT %d", db);
if(!rpl || rpl->type == REDIS_REPLY_ERROR) {
if(!rpl)
@ -245,7 +253,7 @@ static int __redis_select_db(redisContext *ctxt, int db)
static int __redis_exec(
credit_data_t *credit_data, const char *cmd, redisReply **rpl)
{
redisReply *rpl_aux;
redisReply *rpl_aux = NULL;
char cmd_buffer[1024];
*rpl = redisCommand(_data.redis->ctxt, cmd);
@ -300,7 +308,7 @@ int redis_incr_by_double(
int redis_get_double(credit_data_t *credit_data, const char *instruction,
const char *key, double *value)
{
str str_double = {0, 0};
str str_double = STR_NULL;
char buffer[128];
if(redis_get_str(credit_data, instruction, key, &str_double) < 0)
@ -389,6 +397,11 @@ int redis_get_str(credit_data_t *credit_data, const char *instruction,
}
value->s = pkg_malloc(rpl->len);
if(!value->s) {
PKG_MEM_ERROR;
freeReplyObject(rpl);
return -1;
}
value->len = rpl->len;
memcpy(value->s, rpl->str, rpl->len);
@ -516,7 +529,7 @@ int redis_insert_double_value(
int redis_kill_list_member_exists(credit_data_t *credit_data)
{
redisReply *rpl;
redisReply *rpl = NULL;
int exists = 0;
char cmd_buffer[1024];
@ -552,7 +565,7 @@ static void __redis_subscribe_to_kill_list(struct redis *redis)
int redis_publish_to_kill_list(credit_data_t *credit_data)
{
redisReply *rpl;
redisReply *rpl = NULL;
char cmd_buffer[1024];
snprintf(cmd_buffer, sizeof(cmd_buffer), "PUBLISH cnxcc:kill_list %s",
credit_data->str_id);
@ -578,8 +591,8 @@ static void __async_disconnect_cb(const redisAsyncContext *c, int status)
static void __subscription_cb(redisAsyncContext *c, void *r, void *privdata)
{
redisReply *reply = r;
str key;
credit_data_t *credit_data;
str key = STR_NULL;
credit_data_t *credit_data = NULL;
if(reply == NULL) {
LM_ERR("reply is NULL\n");

@ -22,18 +22,16 @@
#include <stdio.h>
#include "../../core/rpc.h"
#include "../../core/rpc_lookup.h"
#include "cnxcc_rpc.h"
#include "cnxcc_mod.h"
extern data_t _data;
void rpc_kill_call(rpc_t *rpc, void *ctx)
{
call_t *call;
hash_tables_t *hts;
str callid;
call_t *call = NULL;
hash_tables_t *hts = NULL;
str callid = STR_NULL;
if(!rpc->scan(ctx, "S", &callid)) {
LM_ERR("%s: error reading RPC param\n", __FUNCTION__);
@ -65,11 +63,12 @@ void rpc_kill_call(rpc_t *rpc, void *ctx)
void rpc_check_client_stats(rpc_t *rpc, void *ctx)
{
call_t *call, *tmp;
call_t *call = NULL, *tmp = NULL;
int index = 0;
str client_id, rows;
str client_id = STR_NULL;
str rows = STR_NULL;
char row_buffer[512];
credit_data_t *credit_data;
credit_data_t *credit_data = NULL;
if(!rpc->scan(ctx, "S", &client_id)) {
LM_ERR("%s: error reading RPC param\n", __FUNCTION__);
@ -98,9 +97,7 @@ void rpc_check_client_stats(rpc_t *rpc, void *ctx)
return;
}
rows.len = 0;
rows.s = pkg_malloc(10);
if(rows.s == NULL)
goto nomem;
@ -137,7 +134,6 @@ void rpc_check_client_stats(rpc_t *rpc, void *ctx)
row_len = strlen(row_buffer);
rows.s = pkg_reallocxf(rows.s, rows.len + row_len);
if(rows.s == NULL) {
cnxcc_unlock(credit_data->lock);
goto nomem;
@ -161,14 +157,14 @@ void rpc_check_client_stats(rpc_t *rpc, void *ctx)
return;
nomem:
LM_ERR("No more pkg memory\n");
PKG_MEM_ERROR;
rpc->fault(ctx, 500, "No more memory\n");
}
static int iterate_over_table(
hash_tables_t *hts, str *result, credit_type_t type)
{
struct str_hash_entry *h_entry, *tmp;
struct str_hash_entry *h_entry = NULL, *tmp = NULL;
char row_buffer[512];
int index = 0;
@ -223,7 +219,6 @@ static int iterate_over_table(
row_len = strlen(row_buffer);
result->s = pkg_reallocxf(result->s, result->len + row_len);
if(result->s == NULL) {
cnxcc_unlock(hts->lock);
goto nomem;
@ -238,21 +233,18 @@ static int iterate_over_table(
return 0;
nomem:
LM_ERR("No more pkg memory\n");
PKG_MEM_ERROR;
return -1;
}
void rpc_active_clients(rpc_t *rpc, void *ctx)
{
str rows;
str rows = STR_NULL;
rows.s = pkg_malloc(10);
if(rows.s == NULL)
goto nomem;
rows.len = 0;
iterate_over_table(&_data.time, &rows, CREDIT_TIME);
iterate_over_table(&_data.money, &rows, CREDIT_MONEY);
@ -266,6 +258,6 @@ void rpc_active_clients(rpc_t *rpc, void *ctx)
return;
nomem:
LM_ERR("No more pkg memory\n");
PKG_MEM_ERROR;
rpc->fault(ctx, 500, "No more memory\n");
}

@ -23,6 +23,8 @@
#ifndef CNXCC_RPC_H_
#define CNXCC_RPC_H_
#include "../../core/rpc.h"
void rpc_active_clients(rpc_t *rpc, void *ctx);
void rpc_kill_call(rpc_t *rpc, void *ctx);
void rpc_active_clients(rpc_t *rpc, void *ctx);

@ -20,9 +20,9 @@
*
*/
#include "../../core/select.h"
#include "../../core/select_buf.h"
#include "../../core/ut.h"
#include "cnxcc_select.h"
#include "cnxcc_mod.h"
extern data_t _data;

@ -23,6 +23,9 @@
#ifndef CNXCC_SELECT_H_
#define CNXCC_SELECT_H_
#include "../../core/str.h"
#include "../../core/select.h"
int sel_root(str *res, select_t *s, struct sip_msg *msg);
int sel_channels(str *res, select_t *s, struct sip_msg *msg);
int sel_channels_count(str *res, select_t *s, struct sip_msg *msg);

@ -20,29 +20,30 @@
*
*/
#include <sys/socket.h>
#include "../../core/parser/msg_parser.h"
#include "../../core/globals.h"
#include <sys/socket.h>
#define FAKED_SIP_MSG_FORMAT \
"OPTIONS sip:you@kamailio.org SIP/2.0\r\nVia: SIP/2.0/UDP " \
"127.0.0.1\r\nFrom: <%.*s>;tag=%.*s\r\nTo: <%.*s>;tag=%.*s\r\nCall-ID: " \
"%.*s\r\nCSeq: 1 OPTIONS\r\nContent-Length: 0\r\n\r\n"
#define FAKED_SIP_MSG_BUF_LEN 1024
char _faked_sip_msg_buf[FAKED_SIP_MSG_BUF_LEN];
static char _faked_sip_msg_buf[FAKED_SIP_MSG_BUF_LEN];
static struct sip_msg _faked_msg;
int faked_msg_init_with_dlg_info(str *callid, str *from_uri, str *from_tag,
str *to_uri, str *to_tag, struct sip_msg **msg)
int cnxcc_faked_msg_init_with_dlg_info(str *callid, str *from_uri,
str *from_tag, str *to_uri, str *to_tag, struct sip_msg **msg)
{
memset(_faked_sip_msg_buf, 0, FAKED_SIP_MSG_BUF_LEN);
memset(&_faked_msg, 0, sizeof(struct sip_msg));
sprintf(_faked_sip_msg_buf, FAKED_SIP_MSG_FORMAT, from_uri->len,
from_uri->s, from_tag->len, from_tag->s, to_uri->len, to_uri->s,
to_tag->len, to_tag->s, callid->len, callid->s);
snprintf(_faked_sip_msg_buf, FAKED_SIP_MSG_BUF_LEN, FAKED_SIP_MSG_FORMAT,
from_uri->len, from_uri->s, from_tag->len, from_tag->s, to_uri->len,
to_uri->s, to_tag->len, to_tag->s, callid->len, callid->s);
LM_DBG("fake msg:\n%s\n", _faked_sip_msg_buf);

@ -22,7 +22,9 @@
#ifndef CNXCC_SIP_MSG_FAKER_H_
#define CNXCC_SIP_MSG_FAKER_H_
int faked_msg_init_with_dlg_info(str *callid, str *from_uri, str *from_tag,
str *to_uri, str *to_tag, struct sip_msg **msg);
#include "../../core/str.h"
int cnxcc_faked_msg_init_with_dlg_info(str *callid, str *from_uri,
str *from_tag, str *to_uri, str *to_tag, struct sip_msg **msg);
#endif /* CNXCC_SIP_MSG_FAKER_H_ */

@ -128,21 +128,37 @@ modparam("cnxcc", "credit_check_period", 1)
<para>
Associates the call with a customer id and sets the max credit,
connect cost, cost per second, initial pulse and final pulse. The discount
is calculated in pulses (30/6, 1/1, etc) and subtracted from the pool
is calculated in pulses (1/1, 60/1, etc) and subtracted from the pool
of credit.
</para>
<para>
The customer value can be provided as a string or a variable holding
a string.
a string. This value identifies all calls from the same customer.
</para>
<para>
The maxcredit (float) value is the maximum credit available for the current call.
</para>
<para>
The connect (float) value is the connect cost for the current call.
</para>
<para>
The cps (float) value is the cost per second for the current call.
</para>
<para>
The ipuse (integer) value is the initial pulse and establishes the minimum
time to be charged. For example, value 1 establishes a charge per second
and value 60 sets a charge per minute. If it is taken as value 60, even
if the duration is 5 seconds, 1 minute will be charged.
</para>
<para>
The maxcredit, connect and cps can be double (float) or integer values, they
have to be provided as static string values of variables holding string
values.
The fpulse (integer) value is the final pulse and establishes, from the initial
pulse, the time range to be charged. For example, the value 1 establishes a charge
per second, 5 sets a charge in blocks of 5 seconds, 60 sets a full minute charge.
</para>
<para>
The ipulse and fpulse values are integer values, they can be also
given via variables holding integers.
1/1 will make a charge per seconds for the entire call. 60/1 will make a
charge per seconds with the first full minute. 60/60 always perform
a full minute charge.
</para>
<para>
<emphasis>Return code:</emphasis>
@ -173,12 +189,15 @@ modparam("cnxcc", "credit_check_period", 1)
...
cnxcc_set_max_credit("john-doe", "100", "3.0", "0.5", 60, 1);
...
$var(customer) = "john-doe-premium"; # customer id
$var(credit) = "100"; # max credit
$var(connect) = "3.0"; # connect const
$var(cps) = "0.5"; # cost per second
$var(initial_p) = 60; # initial pulse
$var(final_p) = 1; # final pulse
$var(customer) = "john-doe"; # customer id
$var(credit) = "100"; # max credit for all calls with the same
# customer id
$var(connect) = "3.0"; # connect cost or initial cost for the call
$var(cps) = "0.5"; # cost per second
$var(initial_p) = 60; # initial pulse (60 = the first minute will be
# charged even if the call is shorter)
$var(final_p) = 1; # final pulse (after the first minute, it will
# be charge in ranges of 1 second)
cnxcc_set_max_credit("$var(customer)", "$var(credit)", "$var(connect)",
"$var(cps)", "$var(initial_p)", "$var(final_p)");
...

@ -7,6 +7,12 @@ NAME=cplc.so
ifeq ($(CROSS_COMPILE),)
XML2CFG=$(shell which xml2-config)
ifeq ($(XML2CFG),)
XML2CFG=$(shell \
if pkg-config --exists libxml-2.0; then \
echo 'pkg-config libxml-2.0'; \
fi)
endif
endif
ifneq ($(XML2CFG),)

@ -13,8 +13,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@ -43,7 +43,7 @@
#include <sys/uio.h> /* iovec */
#define IO_STREAM_CONN_TIMEOUT S_TO_TICKS(120)
#define IO_LISTEN_TIMEOUT 10 /* in s, how often the timer
#define IO_LISTEN_TIMEOUT 10 /* in s, how often the timer
will be run */
#define IO_LISTEN_TX_TIMEOUT 10 /* ms */
@ -86,16 +86,16 @@ typedef int (*send_ev_f)(void* send_h , struct iovec* v, size_t count);
static io_wait_h io_h;
static io_wait_h ctl_io_h;
static int io_read_connections=0;
static struct stream_connection stream_conn_lst; /* list head */
static struct stream_connection* s_conn_new(int sock,
static struct stream_connection* s_conn_new(int sock,
struct ctrl_socket* cs,
union sockaddr_u* from)
{
struct stream_connection* s_c;
s_c=ctl_malloc(sizeof(struct stream_connection));
if (s_c){
memset(s_c, 0, sizeof(struct stream_connection));
@ -139,11 +139,11 @@ inline static int sendv_disc(struct send_handle* sh, struct iovec* v,
char* p;
char* end;
int r;
p=buf;
end=p+DGRAM_BUF_SIZE;
for (r=0; r<count; r++){
if ((p+v[r].iov_len)>end)
if ((p+v[r].iov_len)>end)
goto error_overflow;
memcpy(p, v[r].iov_base, v[r].iov_len);
p+=v[r].iov_len;
@ -162,7 +162,7 @@ error_overflow:
int sock_send_v(void *h, struct iovec* v, size_t count)
{
struct send_handle* sh;
sh=(struct send_handle*)h;
if (sh->type==S_CONNECTED)
return tsend_dgram_ev(sh->fd, v, count, IO_LISTEN_TX_TIMEOUT);
@ -179,7 +179,7 @@ void io_listen_loop(int fd_no, struct ctrl_socket* cs_lst)
int poll_method;
struct ctrl_socket *cs;
int type;
clist_init(&stream_conn_lst, next, prev);
type=F_T_RESERVED;
#if 0
@ -198,7 +198,7 @@ void io_listen_loop(int fd_no, struct ctrl_socket* cs_lst)
poll_method = 0; /* make check for TCP poll method fail */
poll_err = NULL;
#endif
/* set an appropiate poll method */
if (poll_err || (poll_method==0)){
poll_method=choose_poll_method();
@ -213,8 +213,8 @@ void io_listen_loop(int fd_no, struct ctrl_socket* cs_lst)
LOG(L_INFO, "io_listen_loop: using %s io watch method (config)\n",
poll_method_name(poll_method));
}
if (init_io_wait(&io_h, max_fd_no, poll_method)<0)
if (init_io_wait(&ctl_io_h, max_fd_no, poll_method)<0)
goto error;
/* add all the sockets we listen on for connections */
for (cs=cs_lst; cs; cs=cs->next){
@ -239,12 +239,12 @@ void io_listen_loop(int fd_no, struct ctrl_socket* cs_lst)
#endif
case UNKNOWN_SOCK:
LOG(L_CRIT, "BUG: io_listen_loop: bad control socket transport"
" %d\n", cs->transport);
" %d\n", cs->transport);
goto error;
}
DBG("io_listen_loop: adding socket %d, type %d, transport"
" %d (%s)\n", cs->fd, type, cs->transport, cs->name);
if (io_watch_add(&io_h, cs->fd, POLLIN, type, cs)<0){
if (io_watch_add(&ctl_io_h, cs->fd, POLLIN, type, cs)<0){
LOG(L_CRIT, "ERROR: io_listen_loop: init: failed to add"
"listen socket to the fd list\n");
goto error;
@ -255,56 +255,56 @@ void io_listen_loop(int fd_no, struct ctrl_socket* cs_lst)
if (cfg_child_init()) goto error;
/* main loop */
switch(io_h.poll_method){
switch(ctl_io_h.poll_method){
case POLL_POLL:
while(1){
io_wait_loop_poll(&io_h, IO_LISTEN_TIMEOUT, 0);
io_wait_loop_poll(&ctl_io_h, IO_LISTEN_TIMEOUT, 0);
}
break;
#ifdef HAVE_SELECT
case POLL_SELECT:
while(1){
io_wait_loop_select(&io_h, IO_LISTEN_TIMEOUT, 0);
io_wait_loop_select(&ctl_io_h, IO_LISTEN_TIMEOUT, 0);
}
break;
#endif
#ifdef HAVE_SIGIO_RT
case POLL_SIGIO_RT:
while(1){
io_wait_loop_sigio_rt(&io_h, IO_LISTEN_TIMEOUT);
io_wait_loop_sigio_rt(&ctl_io_h, IO_LISTEN_TIMEOUT);
}
break;
#endif
#ifdef HAVE_EPOLL
case POLL_EPOLL_LT:
while(1){
io_wait_loop_epoll(&io_h, IO_LISTEN_TIMEOUT, 0);
io_wait_loop_epoll(&ctl_io_h, IO_LISTEN_TIMEOUT, 0);
}
break;
case POLL_EPOLL_ET:
while(1){
io_wait_loop_epoll(&io_h, IO_LISTEN_TIMEOUT, 1);
io_wait_loop_epoll(&ctl_io_h, IO_LISTEN_TIMEOUT, 1);
}
break;
#endif
#ifdef HAVE_KQUEUE
case POLL_KQUEUE:
while(1){
io_wait_loop_kqueue(&io_h, IO_LISTEN_TIMEOUT, 0);
io_wait_loop_kqueue(&ctl_io_h, IO_LISTEN_TIMEOUT, 0);
}
break;
#endif
#ifdef HAVE_DEVPOLL
case POLL_DEVPOLL:
while(1){
io_wait_loop_devpoll(&io_h, IO_LISTEN_TIMEOUT, 0);
io_wait_loop_devpoll(&ctl_io_h, IO_LISTEN_TIMEOUT, 0);
}
break;
#endif
default:
LOG(L_CRIT, "BUG: io_listen_loop: no support for poll method "
" %s (%d)\n",
poll_method_name(io_h.poll_method), io_h.poll_method);
" %s (%d)\n",
poll_method_name(ctl_io_h.poll_method), ctl_io_h.poll_method);
goto error;
}
/* should never reach this point under normal (non-error) circumstances */
@ -316,12 +316,12 @@ error:
/* handles an io event on one of the watched dgram connections
* (it can read the whole packet)
*
*
* params: cs - pointer to the control socket for which we have an io ev.
* returns: handle_* return convention:
* -1 on error, or when we are not interested any more on reads
* from this fd (e.g.: we are closing it )
* 0 on EAGAIN or when by some other way it is known that no more
* 0 on EAGAIN or when by some other way it is known that no more
* io events are queued on the fd (the receive buffer is empty).
* Usefull to detect when there are no more io events queued for
* sigio_rt, epoll_et, kqueue.
@ -337,7 +337,7 @@ static int handle_ctrl_dgram(struct ctrl_socket* cs)
int ret;
struct send_handle sh;
void* saved_state;
saved_state=0; /* we get always a new datagram */
sh.fd=cs->fd;
sh.type=S_DISCONNECTED;
@ -375,12 +375,12 @@ error:
/* handles an new connect on one of the watched stream connections
*
*
* params: cs - pointer to the control socket for which we have an io ev.
* returns: handle_* return convention:
* -1 on error, or when we are not interested any more on accepts
* from this fd (e.g.: we are closing it )
* 0 on EAGAIN or when by some other way it is known that no more
* 0 on EAGAIN or when by some other way it is known that no more
* io events are queued on the fd (the receive buffer is empty).
* Usefull to detect when there are no more io events queued for
* sigio_rt, epoll_et, kqueue.
@ -395,7 +395,7 @@ static int handle_new_connect(struct ctrl_socket* cs)
unsigned int from_len;
int new_sock;
struct stream_connection* s_conn;
from_len=(cs->transport==UDP_SOCK)?sockaddru_len(cs->u.sa_in):
sizeof(cs->u.sa_un);
again:
@ -430,7 +430,7 @@ again:
s_conn=s_conn_new(new_sock, cs, &from);
if (s_conn){
s_conn_add(s_conn);
io_watch_add(&io_h, s_conn->fd, POLLIN, F_T_READ_STREAM, s_conn);
io_watch_add(&ctl_io_h, s_conn->fd, POLLIN, F_T_READ_STREAM, s_conn);
}else{
LOG(L_ERR, "ERROR: io listen: handle_new_connect:"
" s_conn_new failed\n");
@ -449,14 +449,14 @@ error:
/* handles a read event on one of the accepted connections
*
*
* params: s_c - pointer to the stream_connection for which we have an io ev.
* idx - index in the fd_array -> pass this to io_watch_del for
* idx - index in the fd_array -> pass this to io_watch_del for
* faster deletes
* returns: handle_* return convention:
* -1 on error, or when we are not interested any more on reads
* from this fd (e.g.: we are closing it )
* 0 on EAGAIN or when by some other way it is known that no more
* 0 on EAGAIN or when by some other way it is known that no more
* io events are queued on the fd (the receive buffer is empty).
* Usefull to detect when there are no more io events queued for
* sigio_rt, epoll_et, kqueue.
@ -472,7 +472,7 @@ static int handle_stream_read(struct stream_connection* s_c, int idx)
int bytes_processed;
struct stream_req* r;
struct send_handle sh;
sh.fd=s_c->fd;
sh.type=S_CONNECTED;
sh.from_len=0;
@ -540,17 +540,17 @@ skip:
/* everything went fine, we just have to read more */
s_c->expire=get_ticks_raw()+IO_STREAM_CONN_TIMEOUT; /* update timeout*/
return 1;
no_read:
/* false alarm */
return 0;
close_connection:
io_watch_del(&io_h, s_c->fd, idx, IO_FD_CLOSING);
io_watch_del(&ctl_io_h, s_c->fd, idx, IO_FD_CLOSING);
close(s_c->fd);
s_conn_rm(s_c);
return 0;
error_read:
io_watch_del(&io_h, s_c->fd, idx, IO_FD_CLOSING);
io_watch_del(&ctl_io_h, s_c->fd, idx, IO_FD_CLOSING);
close(s_c->fd);
s_conn_rm(s_c);
return -1;
@ -560,15 +560,15 @@ error_read:
#ifdef USE_FIFO
/* handles a read event on one of the fifos
*
/* handles a read event on one of the fifos
*
* params: s_c - pointer to the stream_connection for which we have an io ev.
* idx - index in the fd_array -> pass this to io_watch_del for
* idx - index in the fd_array -> pass this to io_watch_del for
* faster deletes
* returns: handle_* return convention:
* -1 on error, or when we are not interested any more on reads
* from this fd (e.g.: we are closing it )
* 0 on EAGAIN or when by some other way it is known that no more
* 0 on EAGAIN or when by some other way it is known that no more
* io events are queued on the fd (the receive buffer is empty).
* Usefull to detect when there are no more io events queued for
* sigio_rt, epoll_et, kqueue.
@ -585,7 +585,7 @@ static int handle_fifo_read(struct ctrl_socket* cs, int idx)
struct stream_req* r;
struct send_handle sh;
struct stream_connection* sc;
sh.fd=-1;
sh.type=S_FIFO;
sh.from_len=0;
@ -681,7 +681,7 @@ error:
* params: fm - pointer to a fd hash entry
* idx - index in the fd_array (or -1 if not known)
* return: -1 on error
* 0 on EAGAIN or when by some other way it is known that no more
* 0 on EAGAIN or when by some other way it is known that no more
* io events are queued on the fd (the receive buffer is empty).
* Usefull to detect when there are no more io events queued for
* sigio_rt, epoll_et, kqueue.
@ -731,7 +731,7 @@ void io_listen_who_rpc(rpc_t* rpc, void* ctx)
struct ip_addr ip;
int port;
int i;
i=0;
/* check if called from another process */
if (stream_conn_lst.next==0){
@ -757,7 +757,7 @@ void io_listen_who_rpc(rpc_t* rpc, void* ctx)
case UNIXD_SOCK:
#ifdef USE_FIFO
case FIFO_SOCK:
#endif
#endif
rpc->add(ctx, "ss", "<anonymous unix socket>", "" );
rpc->add(ctx, "ss", sc->parent->name, "");
break;
@ -765,7 +765,7 @@ void io_listen_who_rpc(rpc_t* rpc, void* ctx)
rpc->add(ctx, "ssss", "<bug unknown protocol>",
"", "", "", "");
}
/* idle time
* rpc->add(ctx, "d", TICKS_TO_MS(get_ticks_raw()-
(sc->expire-IO_STREAM_CONN_TIMEOUT)));*/

@ -31,6 +31,7 @@ Daniel-Constantin Mierla
3.4. auto_reconnect (integer)
3.5. insert_delayed (integer)
3.6. update_affected_found (integer)
3.7. opt_ssl_mode (integer)
4. Functions
5. Installation
@ -44,9 +45,10 @@ Daniel-Constantin Mierla
1.4. Set auto_reconnect parameter
1.5. Set insert_delayed parameter
1.6. Set update_affected_found parameter
1.7. Set a my.cnf group in db_url parameter
1.8. Adding a kamailio group to my.cnf
1.9. Using [client] and specific group
1.7. Set opt_ssl_mode parameter
1.8. Set a my.cnf group in db_url parameter
1.9. Adding a kamailio group to my.cnf
1.10. Using [client] and specific group
Chapter 1. Admin Guide
@ -66,6 +68,7 @@ Chapter 1. Admin Guide
3.4. auto_reconnect (integer)
3.5. insert_delayed (integer)
3.6. update_affected_found (integer)
3.7. opt_ssl_mode (integer)
4. Functions
5. Installation
@ -101,6 +104,7 @@ Chapter 1. Admin Guide
3.4. auto_reconnect (integer)
3.5. insert_delayed (integer)
3.6. update_affected_found (integer)
3.7. opt_ssl_mode (integer)
3.1. ping_interval (integer)
@ -181,6 +185,30 @@ modparam("db_mysql", "insert_delayed", 1)
modparam("db_mysql", "update_affected_found", 1)
...
3.7. opt_ssl_mode (integer)
Control how the connection to MySQL server is done in regards to
SSL/TLS. If set to 1, SSL/TLS mode is disabled.
The 'include/mysql.h' starting with MySQL 5.7.11 defines the values for
this option as enum: 'mysql_ssl_mode { SSL_MODE_DISABLED=1,
SSL_MODE_PREFERRED, SSL_MODE_REQUIRED, SSL_MODE_VERIFY_CA,
SSL_MODE_VERIFY_IDENTITY}'.
Note: if the value of this parameter is 1, it enforces
SSL_MODE_DISABLED, any other value is passed to the mysql_options(),
not checking if it is defined.
Note: this option is supported only by libmysqlclient, not by
libmariadbclient.
Default value is 0 (0 - off).
Example 1.7. Set opt_ssl_mode parameter
...
modparam("db_mysql", "opt_ssl_mode", 1)
...
4. Functions
No function exported to be used from configuration file.
@ -207,12 +235,12 @@ modparam("db_mysql", "update_affected_found", 1)
* mysql://user:pass@[group]/db
* mysql://[group]/db
Example 1.7. Set a my.cnf group in db_url parameter
Example 1.8. Set a my.cnf group in db_url parameter
...
modparam("usrloc", "db_url", "mysql://[kamailio]/kamailio)
...
Example 1.8. Adding a kamailio group to my.cnf
Example 1.9. Adding a kamailio group to my.cnf
...
[kamailio]
socket = /path/to/mysql.sock
@ -226,7 +254,7 @@ default-character-set = utf8
both your specific group and the client group, then the value is taken
from the last one.
Example 1.9. Using [client] and specific group
Example 1.10. Using [client] and specific group
...
[client]
socket = /var/run/mysql/mysqld.sock

@ -45,6 +45,7 @@ unsigned int my_server_timezone = 0; /* Use FROM_UNIXTIME() for date conversion
unsigned long my_client_ver = 0;
int db_mysql_unsigned_type = 0;
int db_mysql_opt_ssl_mode = 0;
struct mysql_counters_h mysql_cnts_h;
counter_def_t mysql_cnt_defs[] = {
@ -100,6 +101,7 @@ static param_export_t params[] = {
{"insert_delayed", INT_PARAM, &db_mysql_insert_all_delayed},
{"update_affected_found", INT_PARAM, &db_mysql_update_affected_found},
{"unsigned_type", PARAM_INT, &db_mysql_unsigned_type},
{"opt_ssl_mode", PARAM_INT, &db_mysql_opt_ssl_mode},
{0, 0, 0}
};

@ -178,6 +178,39 @@ modparam("db_mysql", "insert_delayed", 1)
...
modparam("db_mysql", "update_affected_found", 1)
...
</programlisting>
</example>
</section>
<section id="db_mysql.p.opt_ssl_mode">
<title><varname>opt_ssl_mode</varname> (integer)</title>
<para>
Control how the connection to MySQL server is done in regards to SSL/TLS.
If set to 1, SSL/TLS mode is disabled.
</para>
<para>
The 'include/mysql.h' starting with MySQL 5.7.11 defines the values for
this option as enum: 'mysql_ssl_mode { SSL_MODE_DISABLED=1, SSL_MODE_PREFERRED,
SSL_MODE_REQUIRED, SSL_MODE_VERIFY_CA, SSL_MODE_VERIFY_IDENTITY}'.
</para>
<para>
Note: if the value of this parameter is 1, it enforces SSL_MODE_DISABLED,
any other value is passed to the mysql_options(), not checking if it is
defined.
</para>
<para>
Note: this option is supported only by libmysqlclient, not by libmariadbclient.
</para>
<para>
<emphasis>
Default value is 0 (0 - off).
</emphasis>
</para>
<example>
<title>Set <varname>opt_ssl_mode</varname> parameter</title>
<programlisting format="linespecific">
...
modparam("db_mysql", "opt_ssl_mode", 1)
...
</programlisting>
</example>
</section>

@ -40,6 +40,8 @@
#include "../../core/ut.h"
#include "db_mysql.h"
extern int db_mysql_opt_ssl_mode;
/*! \brief
* Create a new connection structure,
* open the MySQL connection and set reference count to 1
@ -49,6 +51,7 @@ struct my_con* db_mysql_new_connection(const struct db_id* id)
struct my_con* ptr;
char *host, *grp, *egrp;
unsigned int connection_flag = 0;
#if MYSQL_VERSION_ID > 50012
#if MYSQL_VERSION_ID > 80000 && ! defined MARIADB_BASE_VERSION
bool rec;
@ -112,6 +115,27 @@ struct my_con* db_mysql_new_connection(const struct db_id* id)
mysql_options(ptr->con, MYSQL_OPT_CONNECT_TIMEOUT, (const void*)&db_mysql_timeout_interval);
mysql_options(ptr->con, MYSQL_OPT_READ_TIMEOUT, (const void*)&db_mysql_timeout_interval);
mysql_options(ptr->con, MYSQL_OPT_WRITE_TIMEOUT, (const void*)&db_mysql_timeout_interval);
#if MYSQL_VERSION_ID > 50710 && !defined(MARIADB_BASE_VERSION)
if(db_mysql_opt_ssl_mode!=0) {
unsigned int optuint = 0;
if(db_mysql_opt_ssl_mode==1) {
if(db_mysql_opt_ssl_mode!=SSL_MODE_DISABLED) {
LM_WARN("ssl mode disabled is not 1 (value %u) - enforcing\n",
SSL_MODE_DISABLED);
}
optuint = SSL_MODE_DISABLED;
} else {
optuint = (unsigned int)db_mysql_opt_ssl_mode;
}
mysql_options(ptr->con, MYSQL_OPT_SSL_MODE, (const void*)&optuint);
}
#else
if(db_mysql_opt_ssl_mode!=0) {
LM_WARN("ssl mode not supported by mysql version (value %u) - ignoring\n",
(unsigned int)db_mysql_opt_ssl_mode);
}
#endif
#if MYSQL_VERSION_ID > 50012
/* set reconnect flag if enabled */
if (db_mysql_auto_reconnect) {

@ -31,6 +31,7 @@
#include <string.h>
#include <time.h>
extern int db_mysql_opt_ssl_mode;
/*
* Close the connection and release memory
@ -70,6 +71,26 @@ int my_con_connect(db_con_t* con)
(const void*)&my_connect_to))
WARN("failed to set MYSQL_OPT_CONNECT_TIMEOUT\n");
}
#if MYSQL_VERSION_ID > 50710 && !defined(MARIADB_BASE_VERSION)
if(db_mysql_opt_ssl_mode!=0) {
unsigned int optuint = 0;
if(db_mysql_opt_ssl_mode==1) {
if(db_mysql_opt_ssl_mode!=SSL_MODE_DISABLED) {
LM_WARN("ssl mode disabled is not 1 (value %u) - enforcing\n",
SSL_MODE_DISABLED);
}
optuint = SSL_MODE_DISABLED;
} else {
optuint = (unsigned int)db_mysql_opt_ssl_mode;
}
mysql_options(mcon->con, MYSQL_OPT_SSL_MODE, (const void*)&optuint);
}
#else
if(db_mysql_opt_ssl_mode!=0) {
LM_WARN("ssl mode not supported by mysql version (value %u) - ignoring\n",
(unsigned int)db_mysql_opt_ssl_mode);
}
#endif
#if MYSQL_VERSION_ID >= 40101
if ((my_client_ver >= 50025) ||

@ -79,6 +79,22 @@
#define DS_ALG_RELWEIGHT 11
#define DS_ALG_PARALLEL 12
/* increment call load */
#define DS_LOAD_INC(dgrp, didx) do { \
lock_get(&(dgrp)->lock); \
(dgrp)->dlist[didx].dload++; \
lock_release(&(dgrp)->lock); \
} while(0)
/* decrement call load */
#define DS_LOAD_DEC(dgrp, didx) do { \
lock_get(&(dgrp)->lock); \
if(likely((dgrp)->dlist[didx].dload > 0)) { \
(dgrp)->dlist[didx].dload--; \
} \
lock_release(&(dgrp)->lock); \
} while(0)
static int _ds_table_version = DS_TABLE_VERSION;
static ds_ht_t *_dsht_load = NULL;
@ -854,7 +870,7 @@ next_line:
/* Update list - should it be sync'ed? */
_ds_list_nr = setn;
*crt_idx = *next_idx;
ds_ht_clear_slots(_dsht_load);
ds_log_sets();
return 0;
@ -1102,7 +1118,6 @@ int ds_load_db(void)
/* update data - should it be sync'ed? */
_ds_list_nr = setn;
*crt_idx = *next_idx;
ds_ht_clear_slots(_dsht_load);
ds_log_sets();
@ -1506,6 +1521,7 @@ int ds_get_leastloaded(ds_set_t *dset)
k = -1;
t = 0x7fffffff; /* high load */
lock_get(&dset->lock); \
for(j = 0; j < dset->nr; j++) {
if(!ds_skip_dst(dset->dlist[j].flags)
&& (dset->dlist[j].attrs.maxload == 0
@ -1517,6 +1533,7 @@ int ds_get_leastloaded(ds_set_t *dset)
}
}
}
lock_release(&dset->lock); \
return k;
}
@ -1538,7 +1555,7 @@ int ds_load_add(struct sip_msg *msg, ds_set_t *dset, int setid, int dst)
msg->callid->body.s);
return -1;
}
dset->dlist[dst].dload++;
DS_LOAD_INC(dset, dst);
return 0;
}
@ -1591,23 +1608,24 @@ int ds_load_replace(struct sip_msg *msg, str *duid)
break;
}
}
/* old destination has not been found: has been removed meanwhile? */
if(olddst == -1) {
ds_unlock_cell(_dsht_load, &msg->callid->body);
LM_ERR("old destination address not found for [%d, %.*s]\n", set,
LM_WARN("old destination address not found for [%d, %.*s]\n", set,
it->duid.len, it->duid.s);
return -1;
}
}
if(newdst == -1) {
/* new destination has not been found: has been removed meanwhile? */
ds_unlock_cell(_dsht_load, &msg->callid->body);
LM_ERR("new destination address not found for [%d, %.*s]\n", set,
duid->len, duid->s);
return -1;
return -2;
}
ds_unlock_cell(_dsht_load, &msg->callid->body);
ds_del_cell(_dsht_load, &msg->callid->body);
if(idx->dlist[olddst].dload > 0)
idx->dlist[olddst].dload--;
if(olddst != -1)
DS_LOAD_DEC(idx, olddst);
if(ds_load_add(msg, idx, set, newdst) < 0) {
LM_ERR("unable to replace destination load [%.*s / %.*s]\n", duid->len,
@ -1646,8 +1664,7 @@ int ds_load_remove_byid(int set, str *duid)
return -1;
}
if(idx->dlist[olddst].dload > 0)
idx->dlist[olddst].dload--;
DS_LOAD_DEC(idx, olddst);
return 0;
}
@ -2301,6 +2318,7 @@ int ds_manage_routes(sip_msg_t *msg, ds_select_state_t *rstate)
int ds_update_dst(struct sip_msg *msg, int upos, int mode)
{
int ret;
socket_info_t *sock = NULL;
sr_xavp_t *rxavp = NULL;
sr_xavp_t *lxavp = NULL;
@ -2313,6 +2331,7 @@ int ds_update_dst(struct sip_msg *msg, int upos, int mode)
}
}
next_dst:
rxavp = xavp_get(&ds_xavp_dst, NULL);
if(rxavp == NULL || rxavp->val.type != SR_XTYPE_XAVP) {
LM_DBG("no xavp with previous destination record\n");
@ -2360,12 +2379,18 @@ int ds_update_dst(struct sip_msg *msg, int upos, int mode)
return 1;
}
if(upos == DS_USE_NEXT) {
if(ds_load_replace(msg, &lxavp->val.v.s) < 0) {
LM_ERR("cannot update load distribution\n");
return -1;
ret = ds_load_replace(msg, &lxavp->val.v.s);
switch(ret) {
case 0:
break;
case -2:
LM_ERR("cannot update load with %.*s, skipping dst.\n", lxavp->val.v.s.len, lxavp->val.v.s.s);
goto next_dst;
default:
LM_ERR("cannot update load distribution\n");
return -1;
}
}
return 1;
}
@ -2416,7 +2441,7 @@ int ds_add_dst(int group, str *address, int flags)
_ds_list_nr = setn;
*crt_idx = *next_idx;
ds_ht_clear_slots(_dsht_load);
ds_log_sets();
return 0;
@ -2471,7 +2496,7 @@ int ds_remove_dst(int group, str *address)
_ds_list_nr = setn;
*crt_idx = *next_idx;
ds_ht_clear_slots(_dsht_load);
ds_log_sets();
return 0;

@ -14,8 +14,6 @@ Edited by
Marius Ovidiu Bucur
Edited by
Charles Chance
Copyright © 2011 Marius Bucur

@ -14,8 +14,6 @@ Otmar Lendl
<otmar.lendl@enum.at>
Edited by
Klaus Darilion
<klaus.darilion@enum.at>

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

Loading…
Cancel
Save