From c005d4f1955a03533f624bf43c784a669ebf2295 Mon Sep 17 00:00:00 2001 From: DanB Date: Sat, 2 May 2015 18:37:17 +0200 Subject: [PATCH] Tuneups OpenSIPS-SM, adding data/tutorials/osips_async, config updated with defaults --- data/conf/cgrates/cgrates.json | 19 +- data/opensips/etc/opensips/opensips.cfg | 15 +- .../freeswitch/etc/init.d/freeswitch | 2 +- .../cgrates/etc/cgrates/cgrates.json | 94 +++++ .../etc/init.d/.fuse_hidden0000001700000001 | 181 ++++++++++ .../osips_async/cgrates/etc/init.d/cgrates | 181 ++++++++++ .../osips_async/opensips/etc/default/opensips | 27 ++ .../osips_async/opensips/etc/init.d/opensips | 199 ++++++++++ .../opensips/etc/opensips/opensips.cfg | 339 ++++++++++++++++++ sessionmanager/osipssm.go | 57 ++- 10 files changed, 1098 insertions(+), 16 deletions(-) create mode 100644 data/tutorials/osips_async/cgrates/etc/cgrates/cgrates.json create mode 100755 data/tutorials/osips_async/cgrates/etc/init.d/.fuse_hidden0000001700000001 create mode 100755 data/tutorials/osips_async/cgrates/etc/init.d/cgrates create mode 100755 data/tutorials/osips_async/opensips/etc/default/opensips create mode 100755 data/tutorials/osips_async/opensips/etc/init.d/opensips create mode 100644 data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg diff --git a/data/conf/cgrates/cgrates.json b/data/conf/cgrates/cgrates.json index ae63b0520..c1698295e 100644 --- a/data/conf/cgrates/cgrates.json +++ b/data/conf/cgrates/cgrates.json @@ -6,12 +6,18 @@ // This file contains the default configuration hardcoded into CGRateS. // This is what you get when you load CGRateS with an empty configuration file. +// Real-time Charging System for Telecom & ISP environments +// Copyright (C) ITsysCOM GmbH +// +// This file contains the default configuration hardcoded into CGRateS. +// This is what you get when you load CGRateS with an empty configuration file. + //"general": { // "http_skip_tls_veify": false, // if enabled Http Client will accept any TLS certificate // "rounding_decimals": 10, // system level precision for floats // "dbdata_encoding": "msgpack", // encoding used to store object data in strings: // "tpexport_dir": "/var/log/cgrates/tpe", // path towards export folder for offline Tariff Plans -// "default_reqtype": "*rated", // default request type to consider when missing from requests: <""|prepaid|postpaid|pseudoprepaid|rated> +// "default_reqtype": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated> // "default_category": "call", // default Type of Record to consider when missing from requests // "default_tenant": "cgrates.org", // default Tenant to consider when missing from requests // "default_subject": "cgrates", // default rating Subject to consider when missing from requests @@ -64,8 +70,8 @@ //"rater": { // "enabled": false, // enable Rater service: -// "balancer": "", // register to Balancer as worker: <""|internal|x.y.z.y:1234> -// "cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> +// "balancer": "", // register to balancer as worker: <""|internal|x.y.z.y:1234> +// "cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> //}, @@ -77,10 +83,9 @@ //"cdrs": { // "enabled": false, // start the CDR Server service: // "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs -// "rate_cdrs": true, // enable CDR rating calculation // "store_cdrs": true, // store cdrs in storDb -// "rater": "", // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234> -// "cdrstats": "", // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> +// "rater": "", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234> +// "cdrstats": "", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> // "reconnects": 5, // number of reconnect attempts to rater or cdrs // "cdr_replication":[], // replicate the raw CDR to a number of servers //}, @@ -174,12 +179,12 @@ // } //}, - //"sm_freeswitch": { // "enabled": false, // starts SessionManager service: // "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013> // "cdrs": "", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234> // "reconnects": 5, // number of reconnect attempts to rater or cdrs +// "compute_lcr": false, // when enabled it will compute and set cgr_lcr channel variable with least cost route ids // "cdr_extra_fields": [], // extra fields to store in CDRs in case of processing them // "debit_interval": "10s", // interval to perform debits on. // "min_call_duration": "0s", // only authorize calls with allowed duration higher than this diff --git a/data/opensips/etc/opensips/opensips.cfg b/data/opensips/etc/opensips/opensips.cfg index 4fb591f86..559945c8a 100644 --- a/data/opensips/etc/opensips/opensips.cfg +++ b/data/opensips/etc/opensips/opensips.cfg @@ -24,12 +24,14 @@ log_facility=LOG_LOCAL0 fork=yes children=4 +listen=udp:lo:5060 +listen=udp:eth0:5060 auto_aliases=no -disable_tcp=yes +#disable_tcp=yes -disable_tls=yes +#disable_tls=yes ####### Modules Section ######## @@ -45,8 +47,8 @@ loadmodule "sl.so" #### Transaction Module loadmodule "tm.so" -modparam("tm", "fr_timer", 5) -modparam("tm", "fr_inv_timer", 30) +modparam("tm", "fr_timeout", 5) +modparam("tm", "fr_inv_timeout", 30) modparam("tm", "restart_fr_on_each_reply", 0) modparam("tm", "onreply_avp_mode", 1) @@ -119,6 +121,9 @@ loadmodule "cfgutils.so" #### CacheDB Local loadmodule "cachedb_local.so" +#### UDP protocol +loadmodule "proto_udp.so" + ####### Routing Logic ######## @@ -194,7 +199,7 @@ route{ # if caller is not local, then called number must be local if (!uri==myself) { - send_reply("403","Rely forbidden"); + send_reply("403","Relay forbidden"); exit; } } diff --git a/data/tutorials/fs_evsock/freeswitch/etc/init.d/freeswitch b/data/tutorials/fs_evsock/freeswitch/etc/init.d/freeswitch index a1deb52d6..495976527 100755 --- a/data/tutorials/fs_evsock/freeswitch/etc/init.d/freeswitch +++ b/data/tutorials/fs_evsock/freeswitch/etc/init.d/freeswitch @@ -22,7 +22,7 @@ TUTDIR=/usr/share/cgrates/tutorials/fs_evsock/freeswitch SCRIPTNAME=$TUTDIR/etc/init.d/$NAME TMP_DIR=/tmp/cgr_fsevsock/freeswitch CONFDIR=$TUTDIR/etc/$NAME -RUNDIR=$TMP_DIR//run +RUNDIR=$TMP_DIR/run LOGDIR=$TMP_DIR/log PIDFILE=$RUNDIR/$NAME.pid WORKDIR=$TMP_DIR/lib diff --git a/data/tutorials/osips_async/cgrates/etc/cgrates/cgrates.json b/data/tutorials/osips_async/cgrates/etc/cgrates/cgrates.json new file mode 100644 index 000000000..83b03e55e --- /dev/null +++ b/data/tutorials/osips_async/cgrates/etc/cgrates/cgrates.json @@ -0,0 +1,94 @@ +{ + +// Real-time Charging System for Telecom & ISP environments +// Copyright (C) ITsysCOM GmbH +// +// This file contains the default configuration hardcoded into CGRateS. +// This is what you get when you load CGRateS with an empty configuration file. + + +"rater": { + "enabled": true, // enable Rater service: + "cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> +}, + + +"scheduler": { + "enabled": true, // start Scheduler service: +}, + + +"cdrs": { + "enabled": true, // start the CDR Server service: + "rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234> + "cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> +}, + + +"cdr_stats": { + "enabled": true, // starts the cdrstats service: +}, + + +"cdre": { + "*default": { + "cdr_format": "csv", // exported CDRs format + "field_separator": ",", + "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) + "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) + "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT + "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding + "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) + "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export + "mask_length": 0, // length of the destination suffix to be masked + "export_dir": "/tmp/cgr_fsevsock/cgrates/cdre", // path where the exported CDRs will be placed + "header_fields": [], // template of the exported header fields + "content_fields": [ // template of the exported content fields + {"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"}, + {"tag":"RunId", "cdr_field_id": "mediation_runid", "type": "cdrfield", "value": "mediation_runid"}, + {"tag":"Tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "tor"}, + {"tag":"AccId", "cdr_field_id": "accid", "type": "cdrfield", "value": "accid"}, + {"tag":"ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "reqtype"}, + {"tag":"Direction", "cdr_field_id": "direction", "type": "cdrfield", "value": "direction"}, + {"tag":"Tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "tenant"}, + {"tag":"Category", "cdr_field_id": "category", "type": "cdrfield", "value": "category"}, + {"tag":"Account", "cdr_field_id": "account", "type": "cdrfield", "value": "account"}, + {"tag":"Subject", "cdr_field_id": "subject", "type": "cdrfield", "value": "subject"}, + {"tag":"Destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "destination"}, + {"tag":"SetupTime", "cdr_field_id": "setup_time", "type": "cdrfield", "value": "setup_time", "layout": "2006-01-02T15:04:05Z07:00"}, + {"tag":"AnswerTime", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "answer_time", "layout": "2006-01-02T15:04:05Z07:00"}, + {"tag":"Usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "usage"}, + {"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"}, + ], + "trailer_fields": [], // template of the exported trailer fields + } +}, + + +"sm_opensips": { + "enabled": true, // starts SessionManager service: + "listen_udp": "127.0.0.1:2020", // address where to listen for datagram events coming from OpenSIPS + "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013> + "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234> + "debit_interval": "5s", // interval to perform debits on. + "min_call_duration": "0s", // only authorize calls with allowed duration higher than this + "max_call_duration": "3h", // maximum call duration a prepaid call can last + "events_subscribe_interval": "60s", // automatic events subscription to OpenSIPS, 0 to disable it + "mi_addr": "127.0.0.1:8020", // address where to reach OpenSIPS MI to send session disconnects +}, + + +"history_server": { + "enabled": true, // starts History service: . + "history_dir": "/tmp/cgr_osipsasync/cgrates/history", // location on disk where to store history files. +}, + + +"history_agent": { + "enabled": true, // starts History as a client: . + "server": "internal", // address where to reach the master history server: +}, + + +} + diff --git a/data/tutorials/osips_async/cgrates/etc/init.d/.fuse_hidden0000001700000001 b/data/tutorials/osips_async/cgrates/etc/init.d/.fuse_hidden0000001700000001 new file mode 100755 index 000000000..8011a04a5 --- /dev/null +++ b/data/tutorials/osips_async/cgrates/etc/init.d/.fuse_hidden0000001700000001 @@ -0,0 +1,181 @@ +#! /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/fs_evsock/cgrates +TMP_DIR=/tmp/cgr_evsock/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_dir=/usr/share/cgrates/tutorials/fs_evsock/cgrates/etc/cgrates" +HISTDIR=$TMP_DIR/history +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 $USER:$GROUP $CDREDIR +fi +# Install the history folder +if [ ! -d $HISTDIR ]; then + mkdir -p $HISTDIR + chown $USER:$GROUP $HISTDIR +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/osips_async/cgrates/etc/init.d/cgrates b/data/tutorials/osips_async/cgrates/etc/init.d/cgrates new file mode 100755 index 000000000..9539c65cc --- /dev/null +++ b/data/tutorials/osips_async/cgrates/etc/init.d/cgrates @@ -0,0 +1,181 @@ +#! /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/osips_async/$NAME +TMP_DIR=/tmp/cgr_osipsasync/$NAME +SCRIPTNAME=$TUTFOLDER/etc/init.d/$NAME +RUNDIR=$TMP_DIR/run +PIDFILE=$RUNDIR/cgr-engine.pid +STACKTRACE=$RUNDIR/$NAME.strace +ENABLE=true +DAEMON_OPTS="-config_dir=$TUTFOLDER/etc/cgrates" +HISTDIR=$TMP_DIR/history +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 $USER:$GROUP $CDREDIR +fi +# Install the history folder +if [ ! -d $HISTDIR ]; then + mkdir -p $HISTDIR + chown $USER:$GROUP $HISTDIR +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/osips_async/opensips/etc/default/opensips b/data/tutorials/osips_async/opensips/etc/default/opensips new file mode 100755 index 000000000..0671f96a0 --- /dev/null +++ b/data/tutorials/osips_async/opensips/etc/default/opensips @@ -0,0 +1,27 @@ +# +# OpenSIPS startup options +# + +# Set to yes to enable opensips, once configured properly. +RUN_OPENSIPS=yes + +# User to run as +USER=opensips + +# Group to run as +GROUP=opensips + +# Amount of shared memory to allocate for the running OpenSIPS server (in Mb) +S_MEMORY=64 + +# Amount of pkg memory to allocate for the running OpenSIPS server (in Mb) +P_MEMORY=4 + +# Enable the server to leave a core file when it crashes. +# Set this to 'yes' to enable OpenSIPS to leave a core file when it crashes +# or 'no' to disable this feature. This option is case sensitive and only +# accepts 'yes' and 'no' and only in lowercase letters. +# On some systems (e.g. Ubuntu 6.10, Debian 4.0) it is necessary to specify +# a directory for the core files to get a dump. Look into the opensips +# init file for an example configuration. +DUMP_CORE=no diff --git a/data/tutorials/osips_async/opensips/etc/init.d/opensips b/data/tutorials/osips_async/opensips/etc/init.d/opensips new file mode 100755 index 000000000..329025d8c --- /dev/null +++ b/data/tutorials/osips_async/opensips/etc/init.d/opensips @@ -0,0 +1,199 @@ +#! /bin/sh +# +### BEGIN INIT INFO +# Provides: opensips +# Required-Start: $syslog $network $local_fs $time +# Required-Stop: $syslog $network $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start the OpenSIPS SIP server +# Description: Start the OpenSIPS SIP server +### END INIT INFO +# +# TODO: +# The following fields should be added (and completed): +# Should-Start: postgresql mysql radius +# Should-Stop: postgresql mysql radius + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/opensips +NAME=opensips +DESC=opensips +TUTDIR=/usr/share/cgrates/tutorials/osips_async/$NAME +SCRIPTNAME=$TUTDIR/etc/init.d/$NAME +TMP_DIR=/tmp/cgr_osipsasync/$NAME +CFGFILE=$TUTDIR/etc/$NAME/opensips.cfg +M4CFGFILE=/etc/opensips/opensips.m4 +M4ARCHIVEDIR=/etc/opensips/archive +HOMEDIR=$TMP_DIR/run/opensips +PIDFILE=$HOMEDIR/$NAME.pid +DEFAULTS=$TUTDIR/etc/default/opensips +RUN_OPENSIPS=no + +if [ ! -d $HOMEDIR ]; then + mkdir -p $HOMEDIR + chown -R $USER:$GROUP $HOMEDIR +fi + +# Do not start opensips 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 + echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/opensips debug instead" + exit 1 + fi +} + +check_opensips_config () +{ + # Check if opensips configuration is valid before starting the server + set +e + out=$($DAEMON -c 2>&1 > /dev/null) + retcode=$? + set -e + if [ "$retcode" != '0' ]; then + echo "Not starting $DESC: invalid configuration file!" + echo -e "\n$out\n" + 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 opensips 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 opensips and cannot + # write to the file. If the file exists before opensips starts, it + # won't change it's ownership and will be writable for both root + # and opensips, no matter what options are chosen at install time + RADIUS_SEQ_FILE=/var/run/opensips/opensips_radius.seq + if [ -d /var/run/opensips ]; then + chown ${USER}:${GROUP} /var/run/opensips + + 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 +if [ -f $DEFAULTS ]; then + . $DEFAULTS || true +fi + +if [ "$RUN_OPENSIPS" != "yes" ]; then + echo "OpenSIPS not yet configured. Edit /etc/default/opensips first." + exit 0 +fi + +set -e + +S_MEMORY=$((`echo $S_MEMORY | sed -e 's/[^0-9]//g'`)) +P_MEMORY=$((`echo $P_MEMORY | sed -e 's/[^0-9]//g'`)) +[ -z "$USER" ] && USER=opensips +[ -z "$GROUP" ] && GROUP=opensips +[ $S_MEMORY -le 0 ] && S_MEMORY=32 +[ $P_MEMORY -le 0 ] && P_MEMORY=32 + +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 + +OPTIONS="-f $CFGFILE -P $PIDFILE -m $S_MEMORY -M $P_MEMORY -u $USER -g $GROUP" + +case "$1" in + start|debug) + check_opensips_config + create_radius_seqfile + + if [ "$1" != "debug" ]; then + check_fork + fi + + # dirs under /var/run can go away on reboots. + mkdir -p "$HOMEDIR" + chmod 775 "$HOMEDIR" + chown "$USER:$GROUP" "$HOMEDIR" >/dev/null 2>&1 || true + + # Generate config from M4 + if [ -f $M4CFGFILE ]; then + m4 -Q $M4CFGFILE >$CFGFILE.tmp + if [ $? != 0 ]; then + echo "Cannot process m4 macro" + rm "$CFGFILE.tmp" + exit 1 + fi + + [ -e $CFGFILE ] || touch $CFGFILE + + # compare configs + if [ `md5sum $CFGFILE|awk '{print $1}'` != `md5sum $CFGFILE.tmp|awk '{print $1}'` ]; then + mkdir -p "$M4ARCHIVEDIR" + mv "$CFGFILE" "$M4ARCHIVEDIR/$NAME.cfg-`date +%Y%m%d_%H%M%S`" + fi + + mv "$CFGFILE.tmp" "$CFGFILE" + chown $USER:$GROUP $CFGFILE + chmod 640 $CFGFILE + fi + + echo -n "Starting $DESC: $NAME" + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --exec $DAEMON -- $OPTIONS || echo -n " already running" + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \ + --exec $DAEMON + echo "." + ;; + restart|force-reload) + check_opensips_config + create_radius_seqfile + + echo -n "Restarting $DESC: $NAME" + start-stop-daemon --oknodo --stop --quiet --pidfile \ + $PIDFILE --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + $PIDFILE --exec $DAEMON -- $OPTIONS + echo "." + ;; + status) + echo -n "Status of $DESC: " + if [ ! -r "$PIDFILE" ]; then + echo "$NAME is not running." + exit 3 + fi + if read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then + echo "$NAME is running." + exit 0 + else + echo "$NAME is not running but $PIDFILE exists." + exit 1 + fi + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|debug|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg b/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg new file mode 100644 index 000000000..a7961c6d2 --- /dev/null +++ b/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg @@ -0,0 +1,339 @@ + +# +# $Id$ +# +# OpenSIPS residential configuration script +# by OpenSIPS Solutions +# +# This script was generated via "make menuconfig", from +# the "Residential" scenario. +# You can enable / disable more features / functionalities by +# re-generating the scenario with different options.# +# +# Please refer to the Core CookBook at: +# http://www.opensips.org/Resources/DocsCookbooks +# for a explanation of possible statements, functions and parameters. +# + + +####### Global Parameters ######### + +debug=3 +log_stderror=no +log_facility=LOG_LOCAL0 + +fork=yes +children=4 +listen=udp:lo:5060 +listen=udp:eth0:5060 + +auto_aliases=no + +####### Modules Section ######## + +#set module path +mpath="/usr/lib/opensips/modules" + +#### SIGNALING module +loadmodule "signaling.so" + +#### StateLess module +loadmodule "sl.so" + +#### Transaction Module +loadmodule "tm.so" +modparam("tm", "fr_timeout", 5) +modparam("tm", "fr_inv_timeout", 30) +modparam("tm", "restart_fr_on_each_reply", 0) +modparam("tm", "onreply_avp_mode", 1) + +#### Record Route Module +loadmodule "rr.so" +/* do not append from tag to the RR (no need for this script) */ +modparam("rr", "append_fromtag", 0) + +#### MAX ForWarD module +loadmodule "maxfwd.so" + +#### SIP MSG OPerationS module +loadmodule "sipmsgops.so" + +#### FIFO Management Interface +loadmodule "mi_fifo.so" +modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo") +modparam("mi_fifo", "fifo_mode", 0666) + +loadmodule "mi_datagram.so" +modparam("mi_datagram", "socket_name", "udp:127.0.0.1:8020") + + +#### Eventdatagram module +loadmodule "event_datagram.so" + + +#### URI module +loadmodule "uri.so" +modparam("uri", "use_uri_table", 0) + + +#### USeR LOCation module +loadmodule "usrloc.so" +modparam("usrloc", "nat_bflag", "NAT") +modparam("usrloc", "db_mode", 0) + +#### REGISTRAR module +loadmodule "registrar.so" +modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT") + +/* uncomment the next line not to allow more than 10 contacts per AOR */ +#modparam("registrar", "max_contacts", 10) + +#### DIALOG module +loadmodule "dialog.so" +modparam("dialog", "dlg_match_mode", 1) +modparam("dialog", "default_timeout", 21600) # 6 hours timeout +modparam("dialog", "db_mode", 0) + + +#### ACCounting module +loadmodule "acc.so" +/* what special events should be accounted ? */ +modparam("acc", "early_media", 0) +modparam("acc", "report_cancels", 0) +modparam("acc", "cdr_flag", "CDR") +modparam("acc", "evi_flag", "CDR") +modparam("acc", "evi_missed_flag", "CDR") +#modparam("acc", "acc_created_avp_name", "created_avp") +modparam("acc", "evi_extra", + "cgr_reqtype=$avp(cgr_reqtype); + cgr_account=$avp(cgr_account); + cgr_subject=$avp(cgr_subject); + cgr_destination=$avp(cgr_destination); + originalUri=$ou") + +#### CfgUtils module +loadmodule "cfgutils.so" + +#### CacheDB Local +loadmodule "cachedb_local.so" + +#### UDP protocol +loadmodule "proto_udp.so" + + +####### Routing Logic ######## + +startup_route { + subscribe_event("E_OPENSIPS_START", "udp:127.0.0.1:2020"); + raise_event("E_OPENSIPS_START"); +} + +# main request routing logic + +route{ + + + if (!mf_process_maxfwd_header("10")) { + sl_send_reply("483","Too Many Hops"); + exit; + } + + if (has_totag()) { + # sequential request withing a dialog should + # take the path determined by record-routing + if (loose_route()) { + if (is_method("BYE")) { + #setflag(CDR); # do accounting ... + } else if (is_method("INVITE")) { + # even if in most of the cases is useless, do RR for + # re-INVITEs alos, as some buggy clients do change route set + # during the dialog. + record_route(); + } + + + + # route it out to whatever destination was set by loose_route() + # in $du (destination URI). + route(relay); + } else { + + if ( is_method("ACK") ) { + if ( t_check_trans() ) { + # non loose-route, but stateful ACK; must be an ACK after + # a 487 or e.g. 404 from upstream server + t_relay(); + exit; + } else { + # ACK without matching transaction -> + # ignore and discard + exit; + } + } + sl_send_reply("404","Not here"); + } + exit; + } + + # CANCEL processing + if (is_method("CANCEL")) + { + if (t_check_trans()) + t_relay(); + exit; + } + + t_check_trans(); + + if ( !(is_method("REGISTER") ) ) { + + if (from_uri==myself) + + { + + } else { + # if caller is not local, then called number must be local + + if (!uri==myself) { + send_reply("403","Relay forbidden"); + exit; + } + } + + } + + # preloaded route checking + if (loose_route()) { + xlog("L_ERR", + "Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]"); + if (!is_method("ACK")) + sl_send_reply("403","Preload Route denied"); + exit; + } + + # record routing + if (!is_method("REGISTER|MESSAGE")) + record_route(); + + # account only INVITEs + if (is_method("INVITE")) { + # create dialog with timeout + if ( !create_dialog("B") ) { + send_reply("500","Internal Server Error"); + exit; + } + setflag(CDR); + #acc_evi_request("DIALOG_START"); + $avp(cgr_reqtype)="*pseudoprepaid"; + $avp(cgr_account)=$fU; + $avp(cgr_subject)=$fU; + $avp(cgr_destination)=$rU; + route(CGR_AUTH); + } + + if (!uri==myself) { + append_hf("P-hint: outbound\r\n"); + route(relay); + } + + # requests for my domain + + if (is_method("PUBLISH|SUBSCRIBE")) + { + sl_send_reply("503", "Service Unavailable"); + exit; + } + + if (is_method("REGISTER")) + { + if ( 0 ) setflag(TCP_PERSISTENT); + if (!save("location")) + sl_reply_error(); + + exit; + } + + if ($rU==NULL) { + # request with no Username in RURI + sl_send_reply("484","Address Incomplete"); + exit; + } + + # do lookup with method filtering + if (!lookup("location","m")) { + t_newtran(); + t_reply("404", "Not Found"); + exit; + } + + route(relay); +} + +route[CGR_AUTH] { + if $avp(cgr_reqtype)=="*pseudoprepaid" || $avp(cgr_reqtype)=="*prepaid" { #Make sure we got enough balance for the call + $avp(auth_keys) = "cgr_reqtype"; + $avp(auth_vals) = $avp(cgr_reqtype); + $avp(auth_keys) = "callid"; + $avp(auth_vals) = $ci; + $avp(auth_keys) = "from_tag"; + $avp(auth_vals) = $ft; + $avp(auth_keys) = "cgr_account"; + $avp(auth_vals) = $avp(cgr_account); + $avp(auth_keys) = "cgr_subject"; + $avp(auth_vals) = $avp(cgr_subject); + $avp(auth_keys) = "cgr_destination"; + $avp(auth_vals) = $avp(cgr_destination); + $avp(auth_keys) = "created"; + $avp(auth_vals) = $Ts; + raise_event("E_CGR_AUTHORIZE", $avp(auth_keys), $avp(auth_vals)); + $var(accid) = $ci+";"+$ft+";"; + $var(rply_cgr_notify) = $var(accid)+"/"+"cgr_notify"; #Key in localcache for cgr_notify + $var(rply_cgr_maxdur) = $var(accid)+"/"+"cgr_maxdur"; #Key in localcache for cgr_maxdur + $var(ms) = 0; + while($var(ms) < 1000) { # Check for values set every 10 ms for maximum 1 second + if cache_fetch("local", "$var(rply_cgr_notify)", $avp(cgr_notify) ) $var(ms) = 1000; # Break out + $var(ms) = $var(ms) + 10; + usleep("10"); + } + if $avp(cgr_notify) == NULL { # Cannot check it in switch + xlog("Checked cgr_notify variable $var(rply_cgr_notify) got value: $avp(cgr_notify)"); + sl_send_reply("503","Prepaid controller error"); + exit; + } + switch ($avp(cgr_notify)) { + case "SERVER_ERROR": + sl_send_reply("503","Prepaid controller error"); + exit; + case "INSUFFICENT_FUNDS": + sl_send_reply("403", "Payment required"); + exit; + } + if !cache_fetch("local", "$var(rply_cgr_maxdur)", $avp(cgr_maxdur) ) { + sl_send_reply("503","Prepaid controller error on maxdur"); + exit; + } + $DLG_timeout=$avp(cgr_maxdur); + } +} + + +route[relay] { + # for INVITEs enable some additional helper routes + if (is_method("INVITE")) { + t_on_failure("missed_call"); + } + if (!t_relay()) { + send_reply("500","Internal Error"); + }; + exit; +} + + + + +failure_route[missed_call] { + if (t_was_cancelled()) { + exit; + } +} + diff --git a/sessionmanager/osipssm.go b/sessionmanager/osipssm.go index fca6ade3d..01c1d3fd9 100644 --- a/sessionmanager/osipssm.go +++ b/sessionmanager/osipssm.go @@ -31,12 +31,63 @@ import ( "github.com/cgrates/osipsdagram" ) +/* +E_ACC_EVENT +method::INVITE +from_tag::87d02470 +to_tag::a671a98 +callid::05dac0aaa716c9814f855f0e8fee6936@0:0:0:0:0:0:0:0 +sip_code::200 +sip_reason::OK +time::1430579770 +cgr_reqtype::*pseudoprepaid +cgr_account::1002 +cgr_subject::1002 +cgr_destination::1002 +originalUri::sip:1002@172.16.254.77 +duration:: + +# +E_ACC_EVENT +method::BYE +from_tag::a671a98 +to_tag::87d02470 +callid::05dac0aaa716c9814f855f0e8fee6936@0:0:0:0:0:0:0:0 +sip_code::200 +sip_reason::OK +time::1430579797 +cgr_reqtype:: +cgr_account:: +cgr_subject:: +cgr_destination:: +originalUri::sip:1002@172.16.254.1:5060;transport=udp;registering_acc=172_16_254_77 +duration:: + +E_ACC_MISSED_EVENT +method::INVITE +from_tag::1d5efcc1 +to_tag:: +callid::c0965d3f42c720397ca1a5be9619c2ef@0:0:0:0:0:0:0:0 +sip_code::404 +sip_reason::Not Found +time::1430579759 +cgr_reqtype::*pseudoprepaid +cgr_account::1002 +cgr_subject::1002 +cgr_destination::1002 +originalUri::sip:1002@172.16.254.77 +duration:: + +*/ + func NewOSipsSessionManager(smOsipsCfg *config.SmOsipsConfig, rater, cdrsrv engine.Connector) (*OsipsSessionManager, error) { osm := &OsipsSessionManager{cfg: smOsipsCfg, rater: rater, cdrsrv: cdrsrv} osm.eventHandlers = map[string][]func(*osipsdagram.OsipsEvent){ - "E_OPENSIPS_START": []func(*osipsdagram.OsipsEvent){osm.onOpensipsStart}, - "E_ACC_CDR": []func(*osipsdagram.OsipsEvent){osm.onCdr}, - "E_CGR_AUTHORIZE": []func(*osipsdagram.OsipsEvent){osm.onAuthorize}, + "E_OPENSIPS_START": []func(*osipsdagram.OsipsEvent){osm.onOpensipsStart}, + "E_ACC_CDR": []func(*osipsdagram.OsipsEvent){osm.onCdr}, + "E_CGR_AUTHORIZE": []func(*osipsdagram.OsipsEvent){osm.onAuthorize}, + "E_ACC_EVENT": []func(*osipsdagram.OsipsEvent){osm.onCdr}, + "E_ACC_MISSED_EVENT": []func(*osipsdagram.OsipsEvent){osm.onCdr}, } return osm, nil }