Renamed tutorials_test to tutorial_tests

This commit is contained in:
Tripon Alexandru-Ionut
2019-06-13 09:48:59 +03:00
committed by Dan Christian Bogos
parent d3d9769034
commit 1ec879deab
36 changed files with 14 additions and 14 deletions

View File

@@ -0,0 +1,141 @@
{
// Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
// Copyright (C) ITsysCOM GmbH
"general": {
"log_level": 7,
"node_id":"CGRKamailio",
"reply_timeout": "5s",
},
"listen": {
"rpc_json": ":2012",
"rpc_gob": ":2013",
"http": ":2080",
},
"stor_db": {
"db_password": "CGRateS.org",
},
"scheduler": {
"enabled": true,
},
"rals": {
"enabled": true,
"thresholds_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"stats_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
},
"cdrs": {
"enabled": true,
"stats_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"sessions_cost_retries": 5,
},
"chargers": {
"enabled": true,
"attributes_conns": [
{"address": "*internal"}
],
},
"sessions": {
"enabled": true,
"rals_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"cdrs_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"resources_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"suppliers_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"attributes_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"stats_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"thresholds_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"chargers_conns": [
{"address": "127.0.0.1:2012", "transport": "*json"},
],
"store_session_costs": true,
"debit_interval": "5s",
"channel_sync_interval":"7s",
},
"kamailio_agent": {
"enabled": true,
"evapi_conns":[
{"address": "127.0.0.1:8448", "reconnects": 5}
],
"sessions_conns": [
{"address": "*internal"},
],
"create_cdr": true,
},
"attributes": {
"enabled": true,
"string_indexed_fields": ["Account"],
},
"resources": {
"enabled": true,
"string_indexed_fields": ["Account"],
},
"stats": {
"enabled": true,
"string_indexed_fields": ["Account","RunID","Destination"],
},
"thresholds": {
"enabled": true,
"string_indexed_fields": ["Account"],
},
"suppliers": {
"enabled": true,
"rals_conns": [
{"address": "*internal"},
],
"resources_conns": [
{"address": "*internal"},
],
"stats_conns": [
{"address": "*internal"},
],
"string_indexed_fields": ["Account"],
},
}

View File

@@ -0,0 +1,175 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: cgrates
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: CGRateS real-time charging system
# Description: Control CGRateS - carrier grade real-time charging system
### END INIT INFO
# Author: DanB <danb@cgrates.org>
#
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="CGRateS real-time charging system"
NAME=cgrates
DAEMON=/usr/bin/cgr-engine
USER=cgrates
GROUP=cgrates
DAEMON_OPTS=""
TUTFOLDER=/usr/share/cgrates/tutorial_tests/kamevapi/cgrates
TMP_DIR=/tmp/cgr_kamevapi/cgrates
SCRIPTNAME=$TUTFOLDER/etc/init.d/$NAME
RUNDIR=$TMP_DIR/run
PIDFILE=$RUNDIR/cgr-engine.pid
STACKTRACE=$RUNDIR/$NAME.strace
ENABLE=true
DAEMON_OPTS="-config_path=$TUTFOLDER/etc/cgrates"
CDREDIR=$TMP_DIR/cdre
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
if [ "$ENABLE" != "true" ]; then
echo "$DESC not yet configured. Edit $DEFAULTS first."
exit 0
fi
# Install the run folder
if [ ! -d $RUNDIR ]; then
mkdir -p $RUNDIR
touch $STACKTRACE
chown -R $USER:$GROUP $RUNDIR
fi
# Install the cdre folder
if [ ! -d $CDREDIR ]; then
mkdir -p $CDREDIR
chown -R $USER:$GROUP $CDREDIR
fi
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
echo "\n### Started at:" `date`>>$STACKTRACE
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test\
|| return 1
start-stop-daemon --start --quiet --chuid $USER:$GROUP --make-pidfile --pidfile $PIDFILE --background\
--startas /bin/bash -- -c "exec $DAEMON $DAEMON_OPTS >> $STACKTRACE 2>&1" \
|| return 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:

View File

@@ -0,0 +1,166 @@
#! /bin/sh
#
### BEGIN INIT INFO
# Provides: kamailio
# Required-Start: $syslog $network $local_fs $remote_fs $time
# Should-Start: $named slapd mysql postgresql snmpd radiusd
# Should-Stop: $named slapd mysql postgresql snmpd radiusd
# Required-Stop: $syslog $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start the Kamailio SIP proxy server
# Description: Start the Kamailio SIP proxy server
### END INIT INFO
. /lib/lsb/init-functions
PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/kamailio
NAME=kamailio
DESC="Kamailio SIP Server"
TUTDIR=/usr/share/cgrates/tutorial_tests/kamevapi/
TMP_DIR=/tmp/cgr_kamevapi/kamailio
HOMEDIR=$TMP_DIR/run/
PIDFILE=$HOMEDIR/$NAME.pid
CFGFILE=$TUTDIR/kamailio/etc/kamailio/kamailio.cfg
USER=kamailio
GROUP=kamailio
# Amount of shared and private memory to allocate
# for the running Kamailio server (in Mb)
SHM_MEMORY=64
PKG_MEMORY=8
DUMP_CORE=no
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
chown -R $USER:$GROUP $HOMEDIR
chmod -R ug=rwX,o= $HOMEDIR
fi
if [ ! -d $LOGDIR ]; then
mkdir -p $LOGDIR
chown -R $USER:$GROUP $LOGDIR
fi
# Do not start kamailio if fork=no is set in the config file
# otherwise the boot process will just stop
check_fork ()
{
if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then
log_failure_msg "Not starting $DESC: fork=no specified in config file; run /etc/init.d/kamailio debug instead"
exit 0
fi
}
check_kamailio_config ()
{
# Check if kamailio configuration is valid before starting the server
set +e
out=$($DAEMON -f $CFGFILE -M $PKG_MEMORY -c 2>&1 > /dev/null)
retcode=$?
set -e
if [ "$retcode" != '0' ]; then
log_failure_msg "Not starting $DESC: invalid configuration file!"
log_failure_msg
log_failure_msg "$out"
log_failure_msg
exit 1
fi
}
create_radius_seqfile ()
{
# Create a radius sequence file to be used by the radius client if
# radius accounting is enabled. This is needed to avoid any issue
# with the file not being writable if kamailio first starts as user
# root because DUMP_CORE is enabled and creates this file as user
# root and then later it switches back to user kamailio and cannot
# write to the file. If the file exists before kamailio starts, it
# won't change it's ownership and will be writable for both root
# and kamailio, no matter what options are chosen at install time
RADIUS_SEQ_FILE=/var/run/kamailio/kamailio_radius.seq
if [ -d /var/run/kamailio ]; then
chown ${USER}:${GROUP} /var/run/kamailio
if [ ! -f $RADIUS_SEQ_FILE ]; then
touch $RADIUS_SEQ_FILE
fi
chown ${USER}:${GROUP} $RADIUS_SEQ_FILE
chmod 660 $RADIUS_SEQ_FILE
fi
}
test -f $DAEMON || exit 0
# Load startup options if available
set -e
SHM_MEMORY=$((`echo $SHM_MEMORY | sed -e 's/[^0-9]//g'`))
PKG_MEMORY=$((`echo $PKG_MEMORY | sed -e 's/[^0-9]//g'`))
[ -z "$USER" ] && USER=kamailio
[ -z "$GROUP" ] && GROUP=kamailio
[ $SHM_MEMORY -le 0 ] && SHM_MEMORY=64
[ $PKG_MEMORY -le 0 ] && PKG_MEMORY=4
if test "$DUMP_CORE" = "yes" ; then
# set proper ulimit
ulimit -c unlimited
# directory for the core dump files
# COREDIR=/home/corefiles
# [ -d $COREDIR ] || mkdir $COREDIR
# chmod 777 $COREDIR
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
# /var/run can be a tmpfs
if [ ! -d $HOMEDIR ]; then
mkdir -p $HOMEDIR
fi
OPTIONS="-f $CFGFILE -P $PIDFILE -m $SHM_MEMORY -M $PKG_MEMORY -u $USER -g $GROUP"
case "$1" in
start|debug)
check_kamailio_config
create_radius_seqfile
if [ "$1" != "debug" ]; then
check_fork
fi
log_daemon_msg "Starting $DESC: $NAME"
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--exec $DAEMON -- $OPTIONS || log_failure_msg " already running"
log_end_msg 0
;;
stop)
log_daemon_msg "Stopping $DESC: $NAME"
start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
--exec $DAEMON
log_end_msg 0
;;
restart|force-reload)
check_kamailio_config
create_radius_seqfile
$0 stop
sleep 1
$0 start
;;
status)
log_daemon_msg "Status of $DESC: "
status_of_proc -p"$PIDFILE" $NAME $NAME
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload|status|debug}" >&2
exit 1
;;
esac
exit 0

View File

@@ -0,0 +1,192 @@
# Kamailio-CGRateS related route blocks
# Called on new connection over evapi, should normally be the case of CGRateS engine
event_route[evapi:connection-new] {
$sht(cgrconn=>cgr) = $evapi(srcaddr) + ":" + $evapi(srcport); # Detect presence of at least one connection
}
# Called when the connection with CGRateS closes
event_route[evapi:connection-closed] {
$var(connClosed) = $evapi(srcaddr) + ":" + $evapi(srcport);
if $sht(cgrconn=>cgr) == $var(connClosed) {
$sht(cgrconn=>cgr) = $null;
}
}
# Message received from CGRateS, dispatch it to own route
event_route[evapi:message-received] {
json_get_field("$evapi(msg)", "Event", "$var(Event)");
route($(var(Event){s.rm,"})); # String characters are kept by json_get_field, remove them here
}
# Called by Kamailio on new dialog
event_route[dialog:start] {
route(CGR_CALL_START);
}
# Called by Kamailio on dialog end
event_route[dialog:end] {
route(CGR_CALL_END);
}
# Parse the CGRateS attributes from encoded variable into pseudovariables
route[PARSE_CGRATES_ATTRIBUTES] {
# convert encoded attributes into individual Kamailio pseudovariables
$var(idx) = 0;
while !strempty($(var(cgrAttributes){s.select,$var(idx),,})) {
$avp($(var(cgrAttributes){s.select,$var(idx),,}{s.select,0,:}))
= $(var(cgrAttributes){s.select,$var(idx),,}{s.select,1,:});
$var(idx) = $var(idx) + 1;
}
}
# CGRateS request for session disconnect
route[CGR_SESSION_DISCONNECT] {
json_get_field("$evapi(msg)", "HashEntry", "$var(HashEntry)");
json_get_field("$evapi(msg)", "HashId", "$var(HashId)");
json_get_field("$evapi(msg)", "Reason", "$var(Reason)");
jsonrpc_exec('{"jsonrpc":"2.0","id":1, "method":"dlg.end_dlg","params":[$(var(HashEntry){s.rm,"}),$(var(HashId){s.rm,"})]}');
}
route[CGR_DLG_LIST] {
if $sht(cgrconn=>cgr) == $null {
sl_send_reply("503","Charging controller unreachable");
exit;
}
jsonrpc_exec('{"jsonrpc":"2.0","id":1, "method":"dlg.list","params":[]}');
evapi_relay("{\"event\":\"CGR_DLG_LIST_REPLY\",
\"jsonrpl_body\":$jsonrpl(body)}");
}
# Route to mainly query account password from CGRateS
route[CGRATES_SIMPLEAUTH_REQUEST] {
if $sht(cgrconn=>cgr) == $null {
sl_send_reply("503","Charging controller unreachable");
exit;
}
evapi_async_relay("{\"event\":\"CGR_AUTH_REQUEST\",
\"tr_index\":\"$T(id_index)\",
\"tr_label\":\"$T(id_label)\",
\"cgr_subsystems\":\"*attributes\",
\"cgr_context\":\"simpleauth\",
\"reply_route\":\"CGR_SIMPLEAUTH_REPLY\",
\"Account\":\"$fU\"}");
}
# Route receiving simpleauth replies, sanitizes them and dispatch back into Kamailio inside CGRATES_SIMPLEAUTH_REPLY
route[CGR_SIMPLEAUTH_REPLY] {
json_get_field("$evapi(msg)", "TransactionIndex", "$var(TransactionIndex)");
$var(TransactionIndex) = $(var(TransactionIndex){s.rm,"});
$var(id_index) = $(var(TransactionIndex){s.int});
json_get_field("$evapi(msg)", "TransactionLabel", "$var(TransactionLabel)");
$var(TransactionLabel) = $(var(TransactionLabel){s.rm,"});
$var(id_label) = $(var(TransactionLabel){s.int});
json_get_field("$evapi(msg)", "Attributes", "$var(cgrAttributes)");
$var(cgrAttributes) = $(var(cgrAttributes){s.rm,"});
json_get_field("$evapi(msg)", "Error", "$var(cgrError)");
$var(cgrError) = $(var(cgrError){s.rm,"});
t_continue("$var(id_index)", "$var(id_label)", "CGRATES_SIMPLEAUTH_REPLY"); # Unpark the transaction
}
# Request session auth information from CGRateS
route[CGRATES_SESSIONAUTH_REQUEST] {
# Auth INVITEs with CGRateS
if $sht(cgrconn=>cgr) == $null {
sl_send_reply("503","Charging controller unreachable");
exit;
}
evapi_async_relay("{\"event\":\"CGR_AUTH_REQUEST\",
\"tr_index\":\"$T(id_index)\",
\"tr_label\":\"$T(id_label)\",
\"cgr_subsystems\":\"*attributes;*accounts;*suppliers;*resources;*thresholds\",
\"reply_route\":\"CGR_SESSIONAUTH_REPLY\",
\"Account\":\"$fU\",
\"Destination\":\"$rU\",
\"SetupTime\":\"$TS\"}");
}
# Process SESSIONAUTH_reply from CGRateS
route[CGR_SESSIONAUTH_REPLY] {
json_get_field("$evapi(msg)", "TransactionIndex", "$var(TransactionIndex)");
$var(TransactionIndex) = $(var(TransactionIndex){s.rm,"});
$var(id_index) = $(var(TransactionIndex){s.int});
json_get_field("$evapi(msg)", "TransactionLabel", "$var(TransactionLabel)");
$var(TransactionLabel) = $(var(TransactionLabel){s.rm,"});
$var(id_label) = $(var(TransactionLabel){s.int});
json_get_field("$evapi(msg)", "Attributes", "$var(cgrAttributes)");
$var(cgrAttributes) = $(var(cgrAttributes){s.rm,"});
json_get_field("$evapi(msg)", "ResourceAllocation", "$var(cgrResourceAllocation)");
$var($var(cgrResourceAllocation)) = $(var(cgrResourceAllocation){s.rm,"});
json_get_field("$evapi(msg)", "MaxUsage", "$var(MaxUsage)");
$var(cgrMaxUsage) = $(var(MaxUsage){s.int});
json_get_field("$evapi(msg)", "Suppliers", "$var(cgrSuppliers)");
$var($var(cgrSuppliers)) = $(var(cgrSuppliers){s.rm,"});
json_get_field("$evapi(msg)", "Error", "$var(cgrError)");
$var(cgrError) = $(var(cgrError){s.rm,"});
t_continue("$var(id_index)", "$var(id_label)", "CGRATES_SESSIONAUTH_REPLY"); # Unpark the transaction
}
# Inform CGRateS about CALL_START (start prepaid sessions loops)
route[CGR_CALL_START] {
if $sht(cgrconn=>cgr) == $null {
xlog("Charging controller unreachable");
exit;
}
evapi_relay("{\"event\":\"CGR_CALL_START\",
\"h_entry\":\"$dlg(h_entry)\",
\"h_id\":\"$dlg(h_id)\",
\"cgr_subsystems\":\"*attributes;*accounts;*resources;*thresholds\",
\"OriginID\":\"$dlg_var(cgrOriginID)\",
\"RequestType\":\"$dlg_var(cgrReqType)\",
\"Tenant\":\"$dlg_var(cgrTenant)\",
\"Account\":\"$dlg_var(cgrAccount)\",
\"Destination\":\"$dlg_var(cgrDestination)\",
\"SetupTime\":\"$dlg_var(SetupTime)\",
\"AnswerTime\":\"$TS\"}");
}
# Inform CGRateS about CALL_END (stop debit loops, perform accounting if desired in this way)
route[CGR_CALL_END] {
if $sht(cgrconn=>cgr) == $null {
xlog("Charging controller unreachable");
exit;
}
$var(callDur) = $TS - $dlg(start_ts);
evapi_relay("{\"event\":\"CGR_CALL_END\",
\"cgr_subsystems\":\"*accounts;*resources\",
\"OriginID\":\"$dlg_var(cgrOriginID)\",
\"RequestType\":\"$dlg_var(cgrReqType)\",
\"Tenant\":\"$dlg_var(cgrTenant)\",
\"Account\":\"$dlg_var(cgrAccount)\",
\"Destination\":\"$dlg_var(cgrDestination)\",
\"AnswerTime\":\"$dlg(start_ts)\",
\"PaypalAccount\":\"$dlg_var(paypalAccount)\",
\"SetupTime\":\"$dlg_var(SetupTime)\",
\"Usage\":\"$var(callDur)\"}");
}

View File

@@ -0,0 +1,439 @@
#!KAMAILIO
# Sample demo config for Kamailio-CGRateS communication
# tested against Kamailio 5.1
####### Defined Values #########
#!define FLT_DIALOG 4
#!define FLT_NATS 5
#!define FLB_NATB 6
#!define FLB_NATSIPPING 7
####### Global Parameters #########
debug=2
log_stderror=no
listen=udp:enp0s3:5060
listen=udp:127.0.0.1:5080
listen=udp:127.0.0.1:5060
listen=udp:enp0s3:5080
memdbg=5
memlog=5
log_facility=LOG_LOCAL0
fork=yes
children=4
tcp_connection_lifetime=3605
use_dns_cache=no
dns_try_ipv6=no
dns_retr_time=1
dns_retr_no=1
dns_servers_no=1
dns_use_search_list=no
####### Modules Section ########
mpath="/usr/lib/x86_64-linux-gnu/kamailio/modules/"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "nathelper.so"
loadmodule "htable.so"
loadmodule "auth.so"
loadmodule "evapi.so"
loadmodule "json.so"
loadmodule "dialog.so"
loadmodule "jsonrpcs.so"
# ----------------- setting module-specific parameters ---------------
modparam("evapi", "bind_addr", "127.0.0.1:8448")
# ----- tm params -----
modparam("tm", "failure_reply_mode", 3)
modparam("tm", "fr_timer", 30000)
modparam("tm", "fr_inv_timer", 120000)
# ----- rr params -----
modparam("rr", "enable_full_lr", 0)
modparam("rr", "append_fromtag", 0)
# ----- registrar params -----
modparam("registrar", "method_filtering", 1)
modparam("registrar", "max_expires", 3600)
# ----- dialog params -----
modparam("dialog", "dlg_flag", FLT_DIALOG)
modparam("dialog", "send_bye", 1)
modparam("dialog", "timeout_noreset", 1)
# ----- nathelper params -----
modparam("nathelper", "natping_interval", 30)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
modparam("nathelper", "sipping_from", "sip:pinger@kamailio.org")
# params needed for NAT traversal in other modules
modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)")
modparam("usrloc", "nat_bflag", FLB_NATB)
# ----- htable params -----
modparam("htable", "htable", "cgrconn=>size=1;")
####### Routing Logic ########
include_file "kamailio-cgrates.cfg"
# Main SIP request routing logic
request_route {
# per request initial checks
route(REQINIT);
# NAT detection
route(NATDETECT);
# CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans()) {
route(RELAY);
}
exit;
}
# handle requests within SIP dialogs
route(WITHINDLG);
### only initial requests (no To tag)
# handle retransmissions
if(t_precheck_trans()) {
t_check_trans();
exit;
}
t_check_trans();
# record routing for dialog forming requests (in case they are routed)
# - remove preloaded route headers
remove_hf("Route");
if (is_method("INVITE|SUBSCRIBE"))
record_route();
# Not handling requests towards external domains
if uri != myself {
sl_send_reply("604", "Only local destinations accepted");
exit;
}
### requests for my local domains
# SIMPLE AUTH methods
if is_method("REGISTER|SUBSCRIBE|PUBLISH") {
route(CGRATES_SIMPLEAUTH_REQUEST);
exit;
}
if ($rU==$null) {
# request with no Username in RURI
sl_send_reply("484","Address Incomplete");
exit;
}
if !is_method("INVITE") {
sl_send_reply("503", "Unsupported method");
exit;
}
route(CGRATES_SESSIONAUTH_REQUEST);
exit;
}
# Here will land requests after processing them with CGRateS.
route[CGRATES_SIMPLEAUTH_REPLY] {
if $var(cgrError) != "" {
xlog("CGR_PROFILE_ERROR: $var(cgrError)");
sl_send_reply("503","CGR_ERROR");
exit;
}
# parse the CGRateS attributes
route(PARSE_CGRATES_ATTRIBUTES);
# password based auth
route(AUTH);
if is_method("REGISTER") {
route(REGISTRAR);
exit;
}
# other methods going over location
route(LOCATION);
route(RELAY);
}
# Here will land requests after processing them with CGRateS. Call RELAY or other routes following this route
route[CGRATES_SESSIONAUTH_REPLY] {
if $var(cgrError) != "" {
xlog("CGR_AUTH_ERROR: $var(cgrError)");
sl_send_reply("503","CGR_ERROR");
exit;
}
# parse the CGRateS attributes
route(PARSE_CGRATES_ATTRIBUTES);
# password based auth
route(AUTH);
# track the dialog so we can set it's timeout and channel variables to store in CDRs
# cannot initialize the dialog sooner due to AUTH
dlg_manage();
$dlg_var(SetupTime) = $TS;
$dlg_var(cgrOriginID) = $dlg(callid) + ";" + $dlg(from_tag);
$dlg_var(cgrTenant) = "cgrates.org";
$dlg_var(cgrReqType) = $avp(RequestType);
$dlg_var(cgrAccount) = $fU;
$dlg_var(cgrDestination) = $rU;
$dlg_var(paypalAccount) = $avp(PaypalAccount);
if $var(cgrMaxUsage) != -1 {
if $var(cgrMaxUsage) == 0 { // Not enough balance, do not allow the call to go through
sl_send_reply("403","Insufficient credit");
exit;
} else if !dlg_set_timeout("$var(cgrMaxUsage)") {
sl_send_reply("503","CGR_MAX_USAGE_ERROR");
exit;
}
}
if $var(cgrSuppliers) != "" { # Enforce the supplier variable to the first one received from CGRateS, here more for demo purposes
$dlg_var(cgrSupplier) = $(var(cgrSuppliers){s.select,0,,});
}
# user location service
route(LOCATION);
# send out
route(RELAY);
}
# Wrapper for relaying requests
route[RELAY] {
# enable additional event routes for forwarded requests
# - serial forking, RTP relaying handling, a.s.o.
if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
}
if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");
}
if (is_method("INVITE")) {
if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
}
if (!t_relay()) {
sl_reply_error();
}
exit;
}
# Per SIP request initial checks
route[REQINIT] {
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops");
exit;
}
if(is_method("OPTIONS") && uri==myself && $rU==$null) {
sl_send_reply("200","Keepalive");
exit;
}
if(!sanity_check("1511", "7")) {
xlog("Malformed SIP message from $si:$sp\n");
exit;
}
}
# Handle requests within SIP dialogs
route[WITHINDLG] {
if (!has_totag()) return;
# sequential request withing a dialog should
# take the path determined by record-routing
if (loose_route()) {
route(DLGURI);
if ( is_method("ACK") ) {
# ACK is forwarded statelessy
route(NATMANAGE);
}
else if ( is_method("NOTIFY") ) {
# Add Record-Route for in-dialog NOTIFY as per RFC 6665.
record_route();
}
route(RELAY);
exit;
}
if ( is_method("ACK") ) {
if ( t_check_trans() ) {
# no loose-route, but stateful ACK;
# must be an ACK after a 487
# or e.g. 404 from upstream server
route(RELAY);
exit;
} else {
# ACK without matching transaction ... ignore and discard
exit;
}
}
sl_send_reply("404","Not here");
exit;
}
# Handle SIP registrations
route[REGISTRAR] {
if(isflagset(FLT_NATS)) {
setbflag(FLB_NATB);
}
if (!save("location"))
sl_reply_error();
exit;
}
# User location service
route[LOCATION] {
$avp(oexten) = $rU;
if (!lookup("location")) {
$var(rc) = $rc;
t_newtran();
switch ($var(rc)) {
case -1:
case -3:
send_reply("404", "Not Found");
exit;
case -2:
send_reply("405", "Method Not Allowed");
exit;
}
}
}
# user uthentication
route[AUTH] {
if (is_method("REGISTER")) {
if ( strempty($au) || !pv_www_authenticate("$td", "$avp(Password)", "0") ) {
www_challenge("$td", "0");
exit;
}
} else { # All other methods here
if ( strempty($au) || !pv_proxy_authenticate("$td", "$avp(Password)", "0") ) {
proxy_challenge("$td", "0");
exit;
}
}
consume_credentials();
return;
}
# Caller NAT detection
route[NATDETECT] {
force_rport();
if (nat_uac_test("19")) {
if (is_method("REGISTER")) {
fix_nated_register();
} else {
if(is_first_hop())
set_contact_alias();
}
setflag(FLT_NATS);
}
return;
}
# RTPProxy control and singaling updates for NAT traversal
route[NATMANAGE] {
if (is_request()) {
if(has_totag()) {
if(check_route_param("nat=yes")) {
setbflag(FLB_NATB);
}
}
}
if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB)))
return;
if (is_request()) {
if (!has_totag()) {
if(t_is_branch_route()) {
add_rr_param(";nat=yes");
}
}
}
if (is_reply()) {
if(isbflagset(FLB_NATB)) {
if(is_first_hop())
set_contact_alias();
}
}
return;
}
# URI update for dialog requests
route[DLGURI] {
if(!isdsturiset()) {
handle_ruri_alias();
}
return;
}
# Manage outgoing branches
branch_route[MANAGE_BRANCH] {
route(NATMANAGE);
}
# Manage incoming replies
onreply_route[MANAGE_REPLY] {
if(status=~"[12][0-9][0-9]")
route(NATMANAGE);
}
# Manage failure routing cases
failure_route[MANAGE_FAILURE] {
route(NATMANAGE);
if (t_is_canceled()) {
exit;
}
if (t_check_status("3[0-9][0-9]")) {
t_reply("404","Not found");
exit;
}
}