From 85704c65d1dd5aff5f1730bcb75e73569d416dc2 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 24 Jun 2020 16:28:36 +0300 Subject: [PATCH] Added SIP redirect example --- .gitignore | 1 + agents/sipagent.go | 6 + data/tariffplans/sipagent/AccountActions.csv | 3 +- data/tariffplans/sipagent/Chargers.csv | 5 + data/tariffplans/sipagent/Routes.csv | 10 +- data/tutorials/sip_redirect/README.md | 18 ++ .../cgrates/etc/cgrates/cgrates.json | 105 ++++++++++ .../cgrates/etc/cgrates/redirect.json | 141 ++++++++++++++ .../sip_redirect/cgrates/etc/init.d/cgrates | 184 ++++++++++++++++++ .../freeswitch/etc/freeswitch_conf.tar.gz | Bin 0 -> 26861 bytes .../freeswitch/etc/init.d/freeswitch | 145 ++++++++++++++ 11 files changed, 613 insertions(+), 5 deletions(-) create mode 100644 data/tariffplans/sipagent/Chargers.csv create mode 100644 data/tutorials/sip_redirect/README.md create mode 100644 data/tutorials/sip_redirect/cgrates/etc/cgrates/cgrates.json create mode 100644 data/tutorials/sip_redirect/cgrates/etc/cgrates/redirect.json create mode 100755 data/tutorials/sip_redirect/cgrates/etc/init.d/cgrates create mode 100644 data/tutorials/sip_redirect/freeswitch/etc/freeswitch_conf.tar.gz create mode 100755 data/tutorials/sip_redirect/freeswitch/etc/init.d/freeswitch diff --git a/.gitignore b/.gitignore index b4b627791..e31c8e4d3 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ dean* data/vagrant/.vagrant data/vagrant/vagrant_ansible_inventory_default data/tutorials/fs_evsock/freeswitch/etc/freeswitch/ +data/tutorials/sip_redirect/freeswitch/etc/freeswitch/ data/tutorial_tests/fs_evsock/freeswitch/etc/freeswitch/ vendor *.test diff --git a/agents/sipagent.go b/agents/sipagent.go index df8b720be..68507ecea 100644 --- a/agents/sipagent.go +++ b/agents/sipagent.go @@ -119,6 +119,9 @@ func (sa *SIPAgent) serveUDP(stop chan struct{}) (err error) { wg.Done() return } + if "ACK" == sipMessage.MethodFrom("Request") { + return + } var sipAnswer sipingo.Message var err error if sipAnswer, err = sa.handleMessage(sipMessage, saddr.String()); err != nil { @@ -204,6 +207,9 @@ func (sa *SIPAgent) serveTCP(stop chan struct{}) (err error) { wg.Done() continue } + if "ACK" == sipMessage.MethodFrom("Request") { + continue + } var sipAnswer sipingo.Message if sipAnswer, err = sa.handleMessage(sipMessage, conn.LocalAddr().String()); err != nil { continue diff --git a/data/tariffplans/sipagent/AccountActions.csv b/data/tariffplans/sipagent/AccountActions.csv index 44fa1907f..68e8a5ea1 100644 --- a/data/tariffplans/sipagent/AccountActions.csv +++ b/data/tariffplans/sipagent/AccountActions.csv @@ -1,2 +1,3 @@ #Tenant,Account,ActionPlanId,ActionTriggersId,AllowNegative,Disabled -cgrates.org,1001,AP_PACKAGE_10,,, \ No newline at end of file +cgrates.org,1001,AP_PACKAGE_10,,, +cgrates.org,1002,AP_PACKAGE_10,,, \ No newline at end of file diff --git a/data/tariffplans/sipagent/Chargers.csv b/data/tariffplans/sipagent/Chargers.csv new file mode 100644 index 000000000..0d85563cc --- /dev/null +++ b/data/tariffplans/sipagent/Chargers.csv @@ -0,0 +1,5 @@ +#Tenant,ID,FilterIDs,ActivationInterval,RunID,AttributeIDs,Weight +cgrates.org,DEFAULT,,,*default,*none,0 +cgrates.org,route1,,,*raw,*constant:*req.RequestType:*none;*constant:*req.Destination:1003,0 +cgrates.org,route2,,,*raw,*constant:*req.RequestType:*none;*constant:*req.Destination:1004,0 +cgrates.org,route3,,,*raw,*constant:*req.RequestType:*none;*constant:*req.Destination:1005,0 \ No newline at end of file diff --git a/data/tariffplans/sipagent/Routes.csv b/data/tariffplans/sipagent/Routes.csv index d3d0d4197..f1c02a8a9 100644 --- a/data/tariffplans/sipagent/Routes.csv +++ b/data/tariffplans/sipagent/Routes.csv @@ -1,5 +1,7 @@ #Tenant,ID,FilterIDs,ActivationInterval,Sorting,SortingParameters,RouteID,RouteFilterIDs,RouteAccountIDs,RouteRatingPlanIDs,RouteResourceIDs,RouteStatIDs,RouteWeight,RouteBlocker,RouteParameters,Weight -cgrates.org,SPL_ACNT_1001,*string:~*req.Account:1001,2017-11-27T00:00:00Z,*weight,,supplier1,,1001,RP_10CNT,,,20,,cgrates.org,20 -cgrates.org,SPL_ACNT_1001,,,,,supplier2,,1001,RP_20CNT,,,10,,cgrates.net,10 -cgrates.org,SPL_ACNT_1001,,,,,supplier3,,1001,RP_1CNT,,,5,,cgrates.com,5 - +cgrates.org,SPL_ACNT_1001,*string:~*req.Account:1001,2017-11-27T00:00:00Z,*weight,,route1,,1001,RP_10CNT,,,20,,cgrates.org,20 +cgrates.org,SPL_ACNT_1001,,,,,route2,,1001,RP_20CNT,,,10,,cgrates.net,10 +cgrates.org,SPL_ACNT_1001,,,,,route3,,1001,RP_1CNT,,,5,,cgrates.com,5 +cgrates.org,SPL_ACNT_1002,*string:~*req.Account:1002,2017-11-27T00:00:00Z,*weight,,route1,,1002,RP_10CNT,,,20,,1003@192.168.56.203,20 +cgrates.org,SPL_ACNT_1002,,,,,route2,,1002,RP_20CNT,,,10,,1004@192.168.57.203,10 +cgrates.org,SPL_ACNT_1002,,,,,route3,,1002,RP_1CNT,,,5,,1005@192.168.58.203,5 diff --git a/data/tutorials/sip_redirect/README.md b/data/tutorials/sip_redirect/README.md new file mode 100644 index 000000000..e25ec1539 --- /dev/null +++ b/data/tutorials/sip_redirect/README.md @@ -0,0 +1,18 @@ +Tutorial SIP Redirect +================ + +Scenario: +--------- + +- FreeSWITCH with minimal custom configuration. + + - Added following users (with configs in *etc/freeswitch/directory/default*): 1001-prepaid, 1002-postpaid, 1003-pseudoprepaid, 1004-rated, 1006-prepaid, 1007-prepaid. + - Have added inside default dialplan a redirect for the destinatin 1001 to the CGRateS SIPAgent that will populate the Contact header and add X-Identity header + +- **CGRateS** with following components: + + - RALs to calculate the maxusage + - RouteS to get the rounting information + - ChargerS to change the destination for each route + - SIPAgent to comunicate with FreeSWITCH + - SessionS to comunicate with the agent diff --git a/data/tutorials/sip_redirect/cgrates/etc/cgrates/cgrates.json b/data/tutorials/sip_redirect/cgrates/etc/cgrates/cgrates.json new file mode 100644 index 000000000..0e44d990c --- /dev/null +++ b/data/tutorials/sip_redirect/cgrates/etc/cgrates/cgrates.json @@ -0,0 +1,105 @@ +{ + +// Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +// Copyright (C) ITsysCOM GmbH + +"general": { + "log_level": 7, + "node_id":"CGRSIP", +}, + + +"listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080", +}, + + +"stor_db": { + "db_password": "CGRateS.org", +}, + + +"schedulers": { + "enabled": true, +}, + + +"rals": { + "enabled": true, + "thresholds_conns": ["*localhost"], + "stats_conns": ["*localhost"], +}, + + +"cdrs": { + "enabled": true, + "stats_conns": ["*localhost"], + "chargers_conns": ["*internal"], + "rals_conns": ["*localhost"], + "sessions_cost_retries": 5, +}, + + +"chargers": { + "enabled": true, + "attributes_conns": ["*internal"], +}, + + +"sessions": { + "enabled": true, + "rals_conns": ["*localhost"], + "cdrs_conns": ["*localhost"], + "resources_conns": ["*localhost"], + "routes_conns": ["*localhost"], + "attributes_conns": ["*localhost"], + "stats_conns": ["*localhost"], + "thresholds_conns": ["*localhost"], + "chargers_conns": ["*internal"], + "debit_interval": "5s", + "channel_sync_interval":"7s", +}, + + +"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"], +}, + + +"routes": { + "enabled": true, + "resources_conns": ["*internal"], + "stats_conns": ["*internal"], + "rals_conns": ["*internal"], + "string_indexed_fields": ["Account"], +}, + + +"apiers": { + "enabled": true, + "scheduler_conns": ["*internal"], +}, + + +} diff --git a/data/tutorials/sip_redirect/cgrates/etc/cgrates/redirect.json b/data/tutorials/sip_redirect/cgrates/etc/cgrates/redirect.json new file mode 100644 index 000000000..0a6d1c075 --- /dev/null +++ b/data/tutorials/sip_redirect/cgrates/etc/cgrates/redirect.json @@ -0,0 +1,141 @@ +{ + +"sip_agent": { + "enabled": true, // enables the SIP agent: + "listen": "192.168.56.203:6060", // address where to listen for SIP requests + "listen_net": "udp", // network to listen on + "request_processors": [ + { + "id": "Register", + "filters": ["*notstring:~*vars.Method:INVITE"], + "flags": ["*none"], + "request_fields":[], + "reply_fields":[ + {"tag": "Request", "path": "*rep.Request", "type": "*constant", + "value": "SIP/2.0 405 Method Not Allowed"} + ] + }, + { + "id": "RoutesQuery", + "filters": ["*string:~*vars.Method:INVITE"], + "flags": ["*event", "*routes","*stir_initiate","*continue"], + "request_fields":[ + {"tag": "Account", "path": "*cgreq.Account", "type": "*variable", + "value": "~*req.From{*sipuri_user}", "mandatory": true}, + {"tag": "Destination", "path": "*cgreq.Destination", "type": "*variable", + "value": "~*req.To{*sipuri_user}", "mandatory": true}, + {"tag": "SetupTime", "path": "*cgreq.SetupTime", "type": "*variable", + "value": "*now", "mandatory": true}, + {"tag": "Category", "path": "*cgreq.Category", "type": "*variable", + "value": "call", "mandatory": true}, + {"tag": "STIRPublicKeyPath", "path": "*opts.STIRPublicKeyPath", "type": "*constant", + "value": "/usr/share/cgrates/stir/stir_pubkey.pem", "mandatory": true}, + {"tag": "STIRPrivateKeyPath", "path": "*opts.STIRPrivateKeyPath", "type": "*constant", + "value": "/usr/share/cgrates/stir/stir_privatekey.pem", "mandatory": true}, + ], + "reply_fields":[ + ] + }, + { + "id": "RoutesQueryOneRoute", + "filters": ["*string:~*vars.Method:INVITE", + "*gte:~*cgrep.Routes.Count:1", + ], + "flags": ["*none","*continue"], // do not send request to CGRateS + "reply_fields":[ + {"tag": "Request", "path": "*rep.Request", "type": "*constant", + "value": "SIP/2.0 302 Moved Temporarily"}, + {"tag": "Contact", "path": "*rep.Contact", "type": "*composed", + "value":"\"1003\" "}, + + {"tag": "X-Identity", "path": "*rep.X-Identity", "type": "*variable", + "value":"~*cgrep.STIRIdentity[~*cgrep.Routes.SortedRoutes[0].RouteID]"}, + ] + }, + + { + "id": "RoutesQueryTwoRoute", + "filters": ["*string:~*vars.Method:INVITE", + "*gte:~*cgrep.Routes.Count:2", + ], + "flags": ["*none","*continue"], // do not send request to CGRateS + "reply_fields":[ + {"tag": "Contact", "path": "*rep.Contact", "type": "*composed", + "value":",\"1004\" "}, + ] + }, + { + "id": "RoutesQueryThreeRoute", + "filters": ["*string:~*vars.Method:INVITE", + "*gte:~*cgrep.Routes.Count:2", + ], + "flags": ["*none","*continue"], // do not send request to CGRateS + "reply_fields":[ + {"tag": "Contact", "path": "*rep.Contact", "type": "*composed", + "value":",\"1005\" "}, + ] + }, + ] + } + +} diff --git a/data/tutorials/sip_redirect/cgrates/etc/init.d/cgrates b/data/tutorials/sip_redirect/cgrates/etc/init.d/cgrates new file mode 100755 index 000000000..38a63f5ad --- /dev/null +++ b/data/tutorials/sip_redirect/cgrates/etc/init.d/cgrates @@ -0,0 +1,184 @@ +#! /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 +# +# 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/tutorials/sip_redirect/cgrates +TMP_DIR=/tmp/cgr_fsevsock/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 +ERSINDIR=$TMP_DIR/ers/in +ERSOUTDIR=$TMP_DIR/ers/out + +# 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 ers folder +if [ ! -d $ERSINDIR ]; then + mkdir -p $ERSINDIR + chown $USER:$GROUP $ERSINDIR + mkdir -p $ERSOUTDIR + chown $USER:$GROUP $ERSOUTDIR +fi +# Install the cdre folder +if [ ! -d $CDREDIR ]; then + mkdir -p $CDREDIR + chown $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 + +: diff --git a/data/tutorials/sip_redirect/freeswitch/etc/freeswitch_conf.tar.gz b/data/tutorials/sip_redirect/freeswitch/etc/freeswitch_conf.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..51d7bf15b35543edd449667999fed482fb19b0f0 GIT binary patch literal 26861 zcmV)fK&8JQiwFQARP$Z{1MFRGbK1zV-mf>mg6ldT_Uv5(*kJE&d3_EB;unm~8reS1 zhoc�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 + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC=freeswitch +NAME=freeswitch +DAEMON=/usr/bin/freeswitch +USER=freeswitch +GROUP=freeswitch +TUTDIR=/usr/share/cgrates/tutorials/sip_redirect/freeswitch +SCRIPTNAME=$TUTDIR/etc/init.d/$NAME +TMP_DIR=/tmp/cgr_fsevsock/freeswitch +CONFDIR=$TUTDIR/etc/$NAME +RUNDIR=$TMP_DIR/run +LOGDIR=$TMP_DIR/log +PIDFILE=$RUNDIR/$NAME.pid +WORKDIR=$TMP_DIR/lib +DBDIR=$WORKDIR/db/ +DAEMON_ARGS="-rp -conf $CONFDIR -db $DBDIR -log $LOGDIR -u $USER -g $GROUP -nonat -nc" + + +[ -x $DAEMON ] || exit 0 +. /lib/init/vars.sh +. /lib/lsb/init-functions + +if [ ! -d $RUNDIR ]; then + mkdir -p $RUNDIR + chown -R $USER:$GROUP $RUNDIR + chmod -R ug=rwX,o= $RUNDIR +fi + +if [ ! -d $LOGDIR ]; then + mkdir -p $LOGDIR + chown -R $USER:$GROUP $LOGDIR +fi + +if [ ! -d $DBDIR ]; then + mkdir -p $DBDIR + chown -R $USER:$GROUP $DBDIR +fi + +do_start() { + if ! [ -f $CONFDIR/freeswitch.xml ]; then + echo "$NAME is not configured so not starting.">&2 + echo "Please review /usr/share/doc/$NAME/README.Debian">&2 + return 3 + fi + echo $DAEMON_ARGS + start-stop-daemon --start --quiet \ + --pidfile $PIDFILE --exec $DAEMON --name $NAME --user $USER \ + --test > /dev/null \ + || return 1 + ulimit -s 240 + start-stop-daemon --start --quiet \ + --pidfile $PIDFILE --exec $DAEMON --name $NAME --user $USER \ + --chdir $WORKDIR -- $DAEMON_ARGS $DAEMON_OPTS \ + || return 2 + return 0 +} + +stop_fs() { + start-stop-daemon --stop --quiet \ + --pidfile $PIDFILE --name $NAME --user $USER \ + --retry=TERM/30/KILL/5 +} + +stop_fs_children() { + start-stop-daemon --stop --quiet \ + --exec $DAEMON \ + --oknodo --retry=0/30/KILL/5 +} + +do_stop() { + stop_fs + RETVAL="$?" + [ "$RETVAL" -eq 2 ] && return 2 + stop_fs_children + [ "$?" -eq 2 ] && return 2 + rm -f $PIDFILE + return "$RETVAL" +} + +do_reload() { + start-stop-daemon --stop --quiet \ + --pidfile $PIDFILE --name $NAME --user $USER \ + --signal HUP +} + +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) + log_daemon_msg "Reloading $DESC" "$NAME" + do_reload + log_end_msg $? + ;; + restart) + 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 ;; + esac + ;; + *) log_end_msg 1 ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +exit 0