|
@@ -0,0 +1,617 @@
|
|
|
+#!KAMAILIO
|
|
|
+#
|
|
|
+# This config file implements an Online-Charging-Server
|
|
|
+# - web: http://www.kamailio.org
|
|
|
+# - git: http://sip-router.org
|
|
|
+#
|
|
|
+# Refer to the Core CookBook at http://www.kamailio.org/dokuwiki/doku.php
|
|
|
+# for an explanation of possible statements, functions and parameters.
|
|
|
+#
|
|
|
+# Direct your questions about this file to: <[email protected]>.
|
|
|
+#
|
|
|
+# For more information about the various parameters, functions and statements
|
|
|
+# try http://sip-router.org/wiki/ .
|
|
|
+#
|
|
|
+
|
|
|
+import_file "ocs.cfg"
|
|
|
+
|
|
|
+#!ifndef GRANT
|
|
|
+#!define GRANT 600
|
|
|
+#!endif
|
|
|
+#!ifndef MULTIPLIER
|
|
|
+#!define MULTIPLIER 10000
|
|
|
+#!endif
|
|
|
+
|
|
|
+##!define WITH_DEBUG
|
|
|
+
|
|
|
+#!ifdef WITH_XMLRPC
|
|
|
+listen=tcp:127.0.0.1:5080
|
|
|
+#!endif
|
|
|
+
|
|
|
+
|
|
|
+####### Defined Values #########
|
|
|
+# *** Value defines - IDs used later in config
|
|
|
+
|
|
|
+# - flags
|
|
|
+# FLT_ - per transaction (message) flags
|
|
|
+# FLB_ - per branch flags
|
|
|
+
|
|
|
+
|
|
|
+####### Global Parameters #########
|
|
|
+
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+debug=4
|
|
|
+log_stderror=yes
|
|
|
+#!else
|
|
|
+debug=0
|
|
|
+log_stderror=no
|
|
|
+#!endif
|
|
|
+
|
|
|
+memdbg=5
|
|
|
+memlog=5
|
|
|
+
|
|
|
+log_stderror=no
|
|
|
+sip_warning=no
|
|
|
+
|
|
|
+rundir="/var/run/kamailio_ocs"
|
|
|
+
|
|
|
+user_agent_header="User-Agent: TelcoSuite OCS"
|
|
|
+server_header="Server: TelcoSuite OCS"
|
|
|
+
|
|
|
+/* comment the next line to enable the auto discovery of local aliases
|
|
|
+ based on reverse DNS on IPs (default on) */
|
|
|
+auto_aliases=no
|
|
|
+
|
|
|
+check_via=no # (cmd. line: -v)
|
|
|
+dns=no # (cmd. line: -r)
|
|
|
+rev_dns=no # (cmd. line: -R)
|
|
|
+
|
|
|
+# Do SRV-Loadbalancing:
|
|
|
+dns_srv_lb=no
|
|
|
+# Always: Also try IPv6:
|
|
|
+dns_try_ipv6=no
|
|
|
+# Always prefer IPv6:
|
|
|
+dns_cache_flags=6
|
|
|
+# DNS-Based failover
|
|
|
+use_dns_failover = on
|
|
|
+# Query NAPTR-Records as well:
|
|
|
+dns_try_naptr=no
|
|
|
+
|
|
|
+#!ifdef WITH_XMLRPC
|
|
|
+tcp_accept_no_cl=yes
|
|
|
+tcp_rd_buf_size=16384
|
|
|
+tcp_children=3
|
|
|
+#!else
|
|
|
+disable_tcp=yes
|
|
|
+#!endif
|
|
|
+
|
|
|
+children=3
|
|
|
+log_name="[Charging]"
|
|
|
+
|
|
|
+system.shutdownmode = 0 desc "System shutdown mode"
|
|
|
+system.service = "Online-Charging-Server" desc "Function of this server"
|
|
|
+
|
|
|
+# ------------------ module loading ----------------------------------
|
|
|
+mpath="/usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/:/usr/local/lib/kamailio/modules/"
|
|
|
+# (we try both the lib64 and the lib directory)
|
|
|
+
|
|
|
+loadmodule "cdp"
|
|
|
+loadmodule "cdp_avp"
|
|
|
+loadmodule "ims_ocs"
|
|
|
+loadmodule "xlog"
|
|
|
+loadmodule "pv"
|
|
|
+loadmodule "sqlops"
|
|
|
+loadmodule "cfgutils"
|
|
|
+loadmodule "db_mysql"
|
|
|
+loadmodule "textops"
|
|
|
+loadmodule "ctl"
|
|
|
+loadmodule "sl"
|
|
|
+loadmodule "tm"
|
|
|
+loadmodule "kex"
|
|
|
+loadmodule "corex"
|
|
|
+loadmodule "cfg_rpc"
|
|
|
+loadmodule "mi_rpc"
|
|
|
+
|
|
|
+# ----- db_cluster params -----
|
|
|
+
|
|
|
+# ----- ctl params -----
|
|
|
+modparam("ctl", "binrpc", "unix:/var/run/kamailio_ocs/kamailio_ctl")
|
|
|
+
|
|
|
+#!ifdef DB_URL2
|
|
|
+loadmodule "db_cluster"
|
|
|
+# ----- db_cluster params -----
|
|
|
+modparam("db_cluster", "connection", DB_URL)
|
|
|
+modparam("db_cluster", "connection", DB_URL2)
|
|
|
+modparam("db_cluster", "cluster", "cluster1=>con1=2s2s;con2=1s1s")
|
|
|
+#!endif
|
|
|
+
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+loadmodule "debugger"
|
|
|
+modparam("debugger", "mod_hash_size", 5)
|
|
|
+modparam("debugger", "mod_level_mode", 1)
|
|
|
+modparam("debugger", "mod_level", "ims_ocs=3")
|
|
|
+#!endif
|
|
|
+
|
|
|
+#!ifdef WITH_DMQ
|
|
|
+loadmodule "dmq"
|
|
|
+# ----- dmq params -----
|
|
|
+modparam("dmq", "server_address", DMQ_SERVER_ADDRESS)
|
|
|
+modparam("dmq", "notification_address", DMQ_NOTIFICATION_ADDRESS)
|
|
|
+#!endif
|
|
|
+
|
|
|
+loadmodule "htable"
|
|
|
+# ----- htable params -----
|
|
|
+
|
|
|
+#!ifdef WITH_DMQ
|
|
|
+modparam("htable", "enable_dmq", 1)
|
|
|
+# Per User:
|
|
|
+modparam("htable", "htable", "user=>size=16;autoexpire=14400;dmqreplicate=1")
|
|
|
+# Per Call:
|
|
|
+modparam("htable", "htable", "call=>size=16;autoexpire=14400;dmqreplicate=1")
|
|
|
+# Association: Calls/User
|
|
|
+modparam("htable", "htable", "cid=>size=8;autoexpire=14400;dmqreplicate=1")
|
|
|
+#!else
|
|
|
+modparam("htable", "enable_dmq", 0)
|
|
|
+# Per User:
|
|
|
+modparam("htable", "htable", "user=>size=16;autoexpire=14400")
|
|
|
+# Per Call:
|
|
|
+modparam("htable", "htable", "call=>size=16;autoexpire=14400")
|
|
|
+# Association: Calls/User
|
|
|
+modparam("htable", "htable", "cid=>size=8;autoexpire=14400")
|
|
|
+#!endif
|
|
|
+
|
|
|
+# ----- cdp params -----
|
|
|
+modparam("cdp","config_file","/etc/kamailio_ocs/ocs.xml")
|
|
|
+
|
|
|
+# ----- sqlops params -----
|
|
|
+#!ifdef DB_URL2
|
|
|
+modparam("sqlops","sqlcon", "hss_db=>cluster://cluster1")
|
|
|
+#!else
|
|
|
+modparam("sqlops","sqlcon", DB_URL)
|
|
|
+#!endif
|
|
|
+
|
|
|
+#!ifdef WITH_XMLRPC
|
|
|
+loadmodule "xmlrpc"
|
|
|
+# ----- xmlrpc params -----
|
|
|
+modparam("xmlrpc", "route", "XMLRPC");
|
|
|
+modparam("xmlrpc", "url_match", "^/RPC")
|
|
|
+#!endif
|
|
|
+
|
|
|
+route {
|
|
|
+#!ifdef WITH_DMQ
|
|
|
+ if(is_method("KDMQ")) {
|
|
|
+ dmq_handle_message();
|
|
|
+ }
|
|
|
+#!endif
|
|
|
+ drop();
|
|
|
+ exit;
|
|
|
+}
|
|
|
+
|
|
|
+# XMLRPC routing
|
|
|
+#!ifdef WITH_XMLRPC
|
|
|
+route[XMLRPC] {
|
|
|
+ # allow XMLRPC from localhost
|
|
|
+ if ((method=="POST" || method=="GET") && ((src_ip==127.0.0.1)
|
|
|
+#!ifdef XMLRPC_WHITELIST_1
|
|
|
+ || (src_ip == XMLRPC_WHITELIST_1)
|
|
|
+#!endif
|
|
|
+#!ifdef XMLRPC_WHITELIST_2
|
|
|
+ || (src_ip == XMLRPC_WHITELIST_2)
|
|
|
+#!endif
|
|
|
+#!ifdef XMLRPC_WHITELIST_3
|
|
|
+ || (src_ip == XMLRPC_WHITELIST_3)
|
|
|
+#!endif
|
|
|
+ )) {
|
|
|
+ # close connection only for xmlrpclib user agents (there is a bug in
|
|
|
+ # xmlrpclib: it waits for EOF before interpreting the response).
|
|
|
+ if ($hdr(User-Agent) =~ "xmlrpclib")
|
|
|
+ set_reply_close();
|
|
|
+ set_reply_no_connect();
|
|
|
+ dispatch_rpc();
|
|
|
+ exit;
|
|
|
+ }
|
|
|
+ send_reply("403", "Forbidden");
|
|
|
+ exit;
|
|
|
+}
|
|
|
+#!endif
|
|
|
+
|
|
|
+event_route[ocs:ccr-orig] {
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("ORIG: $rm $fu => $ru\n\n");
|
|
|
+#!endif
|
|
|
+ $var(result) = 5012;
|
|
|
+ $var(granted) = 0;
|
|
|
+ $var(final) = 0;
|
|
|
+ $var(multiplier) = MULTIPLIER;
|
|
|
+ $var(id) = 0;
|
|
|
+
|
|
|
+ if (is_method("INVITE")) {
|
|
|
+ if ($fU =~ "^\+[1-9][0-9]+$")
|
|
|
+ $var(from) = $(fU{s.substr,1,0});
|
|
|
+ else
|
|
|
+ $var(from) = $fU;
|
|
|
+
|
|
|
+ sql_pvquery("hss_db", "SELECT impi.id AS impi_id, imsu.id, CAST(imsu.credit*$var(multiplier) as UNSIGNED), imsu.rate_plan_id, imsu.payment_method, imsu.max_concurrent_calls FROM impu LEFT JOIN impi_impu ON impu.id = impi_impu.id_impu LEFT JOIN impi ON impi.id = impi_impu.id_impi LEFT JOIN imsu ON impi.id_imsu = imsu.id WHERE ((impu.type = 0 AND impu.identity='sip:$var(from)@$fd') OR (impu.type = 0 AND impu.identity='sip:+$var(from)@$fd') OR (impu.type = 0 AND impu.identity='tel:$var(from)') OR (impu.type = 0 AND impu.identity='tel:+$var(from)') OR (impu.type = 0 AND impu.identity='tel:+$var(from)') OR (impu.type = 3 AND 'sip:$var(from)@$fd' REGEXP impu.identity) OR (impu.type = 3 AND 'tel:$var(from)' REGEXP impu.identity) OR (impu.type = 3 AND 'tel:+$var(from)' REGEXP impu.identity)) limit 1;", "$var(impi_id),$var(id),$var(credit),$var(ratecard),$var(payment),$var(concurrent_calls)");
|
|
|
+ if ($retcode != 1) {
|
|
|
+ # User not found, send DIAMETER_USER_UNKNOWN
|
|
|
+ $var(result) = 5030;
|
|
|
+ } else {
|
|
|
+ if (($var(impi_id) == 0) || ($var(id) == 0)) {
|
|
|
+ # User not found, send DIAMETER_USER_UNKNOWN
|
|
|
+ $var(result) = 5030;
|
|
|
+ } else {
|
|
|
+ # Remove "+"
|
|
|
+ if ($rU =~ "^\+[1-9][0-9]+$")
|
|
|
+ strip(1);
|
|
|
+
|
|
|
+ $var(destination_impu_id) = 0;
|
|
|
+ sql_pvquery("hss_db", "SELECT id FROM impu WHERE ((type = 0 AND identity='$ru') OR (type = 0 AND identity='tel:$rU') OR (type = 3 AND '$ru' REGEXP identity) OR (type = 3 AND 'tel:$rU' REGEXP identity)) limit 1;", "$var(destination_impu_id)");
|
|
|
+ if ($retcode != 1) {
|
|
|
+ $var(destination_impu_id) = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ sht_lock("user=>$var(id)::current_calls");
|
|
|
+ if ($sht(user=>$var(id)::current_calls) != $null)
|
|
|
+ $sht(user=>$var(id)::current_calls) = $(sht(user=>$var(id)::current_calls){s.int});
|
|
|
+ sht_unlock("user=>$var(id)::current_calls");
|
|
|
+
|
|
|
+ sht_lock("user=>$var(id)::reserved_credit");
|
|
|
+ if ($sht(user=>$var(id)::reserved_credit) != $null)
|
|
|
+ $sht(user=>$var(id)::reserved_credit) = $(sht(user=>$var(id)::reserved_credit){s.int});
|
|
|
+ sht_unlock("user=>$var(id)::reserved_credit");
|
|
|
+
|
|
|
+
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("IMPI: $fu ($var(impi_id))\n");
|
|
|
+ xlog("IMSU-ID: $var(id)\n");
|
|
|
+ xlog("Credit: $var(credit) (Reserved: $sht(user=>$var(id)::reserved_credit))\n");
|
|
|
+ xlog("Rate-Card: $var(ratecard)\n");
|
|
|
+ xlog("Payment: $var(payment)\n");
|
|
|
+ xlog("Concurrent-Calls: $var(concurrent_calls), currently ($sht(user=>$var(id)::current_calls))\n");
|
|
|
+ if ($var(destination_impu_id) > 0) {
|
|
|
+ xlog(">>>>>>>>>>>>>>>>>>>>>> DESTINATION ($ru) IS ONNET ($var(destination_impu_id))!\n");
|
|
|
+ }
|
|
|
+#!endif
|
|
|
+ if (($sht(user=>$var(id)::current_calls) != $null) && ($var(concurrent_calls) >= 0)) {
|
|
|
+ if ($sht(user=>$var(id)::current_calls) >= $var(concurrent_calls)) {
|
|
|
+ $var(result) = 5006; # DIAMETER_RESOURCES_EXCEEDED
|
|
|
+ } else {
|
|
|
+ $sht(cid=>$ci) = $var(id);
|
|
|
+ $var(result) = 2001;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ sht_lock("user=>$var(id)::current_calls");
|
|
|
+ if ($sht(user=>$var(id)::current_calls) == $null) {
|
|
|
+ $sht(user=>$var(id)::current_calls) = 0;
|
|
|
+ }
|
|
|
+ sht_unlock("user=>$var(id)::current_calls");
|
|
|
+ $sht(cid=>$ci) = $var(id);
|
|
|
+ $var(result) = 2001;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($var(result) == "2001") {
|
|
|
+ $var(result) = 5031; # DIAMETER_RATING_FAILED
|
|
|
+ if ($var(destination_impu_id) > 0) {
|
|
|
+ sql_pvquery("hss_db", "SELECT id, description, country_name, iso3166, type, CAST(rate_init*$var(multiplier) as UNSIGNED), rate_init_interval, CAST(rate_follow*$var(multiplier) as UNSIGNED), rate_follow_interval, blocked, max_call_duration FROM call_rates WHERE rate_plan_id = $var(ratecard) AND destination_prefix = 'ONNET' limit 1;", "$var(rate_id),$var(rate_name),$var(country),$var(iso),$var(type),$var(rate_init),$var(rate_init_interval),$var(rate_follow),$var(rate_follow_interval),$var(blocked),$var(maxduration)");
|
|
|
+ if ($retcode == 1) {
|
|
|
+ $var(result) = 2001;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($var(result) == 5031) {
|
|
|
+ if ($rU =~ "^[1-9][0-9]+$") {
|
|
|
+ sql_pvquery("hss_db", "SELECT id, description, country_name, iso3166, type, CAST(rate_init*$var(multiplier) as UNSIGNED), rate_init_interval, CAST(rate_follow*$var(multiplier) as UNSIGNED), rate_follow_interval, blocked, max_call_duration FROM call_rates WHERE rate_plan_id = $var(ratecard) AND destination_prefix = SUBSTRING('$rU', 1, LENGTH(destination_prefix)) ORDER BY LENGTH(destination_prefix) DESC limit 1;", "$var(rate_id),$var(rate_name),$var(country),$var(iso),$var(type),$var(rate_init),$var(rate_init_interval),$var(rate_follow),$var(rate_follow_interval),$var(blocked),$var(maxduration)");
|
|
|
+ if ($retcode == 1) {
|
|
|
+ $var(result) = 2001;
|
|
|
+ } else {
|
|
|
+ $var(result) = 5031; # DIAMETER_RATING_FAILED
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($var(result) == "2001") {
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("Rate-ID: $var(rate_id)\n");
|
|
|
+ xlog("Country: $var(iso): $var(country) ($var(type))\n");
|
|
|
+ xlog("Destination: $var(rate_name) ($rU)\n");
|
|
|
+ xlog("Rate: $var(rate_init)/$var(rate_init_interval), $var(rate_follow)/$var(rate_follow_interval)\n");
|
|
|
+ xlog("Blocked: $var(blocked)\n");
|
|
|
+ xlog("Max-Duration: $var(maxduration)\n");
|
|
|
+#!endif
|
|
|
+ if ($var(blocked) == 1) {
|
|
|
+ $var(result) = 4010; # DIAMETER_END_USER_SERVICE_DENIED
|
|
|
+ } else {
|
|
|
+ $var(used_credit) = 0;
|
|
|
+ if ($var(payment) == 1) {
|
|
|
+ # Prepaid
|
|
|
+ if ($sht(user=>$var(id)::reserved_credit) != $null)
|
|
|
+ $var(current_credit) = $var(credit) - $sht(user=>$var(id)::reserved_credit);
|
|
|
+ else
|
|
|
+ $var(current_credit) = $var(credit);
|
|
|
+ if ($var(rate_init) > $var(current_credit)) {
|
|
|
+ $var(result) = 4012; # DIAMETER_CREDIT_LIMIT_REACHED
|
|
|
+ $var(granted) = 0;
|
|
|
+ $var(used_credit) = 0;
|
|
|
+ } else {
|
|
|
+ $var(used_credit) = $var(rate_init);
|
|
|
+ $var(granted) = $var(rate_init_interval);
|
|
|
+ if (($var(rate_follow) == 0) || ($var(rate_follow_interval) <= 0)) {
|
|
|
+ $var(granted) = GRANT;
|
|
|
+ } else {
|
|
|
+ $var(used_credit) = $var(rate_init);
|
|
|
+ while ($var(granted) < GRANT) {
|
|
|
+ if ($var(rate_follow) > ($var(current_credit) - $var(used_credit))) {
|
|
|
+ $var(final) = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ $var(granted) = $var(granted) + $var(rate_follow_interval);
|
|
|
+ $var(used_credit) = $var(used_credit) + $var(rate_follow);
|
|
|
+ }
|
|
|
+ # If it's not sufficient for the next unit, it's the final unit:
|
|
|
+ if ($var(rate_follow) > ($var(current_credit) - $var(used_credit))) {
|
|
|
+ $var(final) = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ # Postpaid
|
|
|
+ $var(granted) = $var(rate_init_interval);
|
|
|
+ $var(used_credit) = $var(rate_init);
|
|
|
+ if (($var(rate_follow) == 0) || ($var(rate_follow_interval) <= 0)) {
|
|
|
+ $var(granted) = GRANT;
|
|
|
+ } else {
|
|
|
+ while ($var(granted) < GRANT) {
|
|
|
+ $var(granted) = $var(granted) + $var(rate_follow_interval);
|
|
|
+ $var(used_credit) = $var(used_credit) + $var(rate_follow);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($var(result) == "2001") {
|
|
|
+ $sht(call=>$ci::follow_rate) = $(var(rate_follow){s.int});
|
|
|
+ $sht(call=>$ci::follow_unit) = $(var(rate_follow_interval){s.int});
|
|
|
+ $sht(call=>$ci::initial_rate) = $(var(rate_init){s.int});
|
|
|
+ $sht(call=>$ci::initial_unit) = $(var(rate_init_interval){s.int});
|
|
|
+
|
|
|
+ $sht(call=>$ci::reserved_credit) = $(var(used_credit){s.int});
|
|
|
+ $sht(call=>$ci::used_unit) = 0;
|
|
|
+ $sht(call=>$ci::granted_unit) = $var(granted);
|
|
|
+
|
|
|
+ sht_lock("user=>$var(id)::credit");
|
|
|
+ if ($var(payment) == 1)
|
|
|
+ $sht(user=>$var(id)::credit) = $var(credit);
|
|
|
+ else
|
|
|
+ $sht(user=>$var(id)::credit) = -1;
|
|
|
+ sht_unlock("user=>$var(id)::credit");
|
|
|
+
|
|
|
+ sht_lock("user=>$var(id)::reserved_credit");
|
|
|
+ if ($sht(user=>$var(id)::reserved_credit) == $null) {
|
|
|
+ $sht(user=>$var(id)::reserved_credit) = $(var(used_credit){s.int});
|
|
|
+ } else {
|
|
|
+ $sht(user=>$var(id)::reserved_credit) = $sht(user=>$var(id)::reserved_credit) + $(var(used_credit){s.int});
|
|
|
+ }
|
|
|
+ sht_unlock("user=>$var(id)::reserved_credit");
|
|
|
+
|
|
|
+ $sht(call=>$ci::max_units) = $null;
|
|
|
+ if ($var(maxduration) > 0) {
|
|
|
+ $sht(call=>$ci::max_units) = $var(maxduration);
|
|
|
+ if ($var(maxduration) < $var(granted)) {
|
|
|
+ $var(granted) = $var(maxduration);
|
|
|
+ $var(final) = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("Granted $var(granted)s, reserved new credit $var(used_credit)\n");
|
|
|
+#!endif
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $var(result) = 5031; # DIAMETER_RATING_FAILED
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($var(result) == "2001") {
|
|
|
+ sht_lock("user=>$var(id)::current_calls");
|
|
|
+ $sht(user=>$var(id)::current_calls) = $sht(user=>$var(id)::current_calls) + 1;
|
|
|
+ sht_unlock("user=>$var(id)::current_calls");
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("User has now $sht(user=>$var(id)::current_calls) Calls, allowed is $var(concurrent_calls)\n");
|
|
|
+ xlog("INSERT INTO tb_processed_cdrs (imsu_id, impi_id, dest_e164, callid, start, call_rate) VALUES ($var(id), $var(impi_id), '$fU', '$rU', '$ci', now(), $var(id), $var(rate_id))\n");
|
|
|
+#!endif
|
|
|
+ sql_query("hss_db", "INSERT INTO tb_processed_cdrs (imsu_id, impi_id, src_e164, dest_e164, callid, start, call_rate) VALUES ($var(id), $var(impi_id), '$fU', '$rU', '$ci', now(), $var(rate_id));");
|
|
|
+ if ($retcode == -1) {
|
|
|
+ $var(result) = 5012;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (is_method("UPDATE")) {
|
|
|
+ $var(id) = $sht(cid=>$ci);
|
|
|
+ $var(used_credit) = 0;
|
|
|
+ $var(granted) = 0;
|
|
|
+ $var(credit) = $sht(user=>$var(id)::credit);
|
|
|
+ if ($var(credit) >= 0) {
|
|
|
+ # Prepaid
|
|
|
+ if (($sht(call=>$ci::follow_rate) == 0) || ($sht(call=>$ci::follow_unit) <= 0)) {
|
|
|
+ $var(granted) = GRANT;
|
|
|
+ } else {
|
|
|
+ $var(current_credit) = $sht(user=>$var(id)::credit) - $sht(user=>$var(id)::reserved_credit);
|
|
|
+ while ($var(granted) < GRANT) {
|
|
|
+ if ($sht(call=>$ci::follow_rate) > ($var(current_credit) - $var(used_credit))) {
|
|
|
+ $var(final) = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ $var(granted) = $var(granted) + $sht(call=>$ci::follow_unit);
|
|
|
+ $var(used_credit) = $var(used_credit) + $sht(call=>$ci::follow_rate);
|
|
|
+ }
|
|
|
+ # If it's not sufficient for the next unit, it's the final unit:
|
|
|
+ if ($sht(call=>$ci::follow_rate) > ($var(current_credit) - $var(used_credit))) {
|
|
|
+ $var(final) = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ # Postpaid
|
|
|
+ if (($sht(call=>$ci::follow_rate) == 0) || ($sht(call=>$ci::follow_unit) <= 0)) {
|
|
|
+ $var(granted) = GRANT;
|
|
|
+ } else {
|
|
|
+ while ($var(granted) < GRANT) {
|
|
|
+ $var(granted) = $var(granted) + $sht(call=>$ci::follow_unit);
|
|
|
+ $var(used_credit) = $var(used_credit) + $sht(call=>$ci::follow_rate);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $sht(call=>$ci::used_unit) = $sht(call=>$ci::used_unit) + $(hdr(P-Used-Units){s.int});
|
|
|
+ if ($sht(call=>$ci::max_units) > 0) {
|
|
|
+ $var(cur_granted) = $sht(call=>$ci::used_unit) + $var(granted);
|
|
|
+ $var(max_granted) = $sht(call=>$ci::max_units);
|
|
|
+ if ($var(max_granted) > $var(cur_granted)) {
|
|
|
+ $var(granted) = $sht(call=>$ci::max_units) - $sht(call=>$ci::used_unit);
|
|
|
+ $var(final) = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($var(granted) <= 0) {
|
|
|
+ $var(result) = 4012; # DIAMETER_CREDIT_LIMIT_REACHED
|
|
|
+ $var(granted) = 0;
|
|
|
+ } else {
|
|
|
+ $var(granted) = $var(granted) + ($sht(call=>$ci::granted_unit) - $(hdr(P-Used-Units){s.int}));
|
|
|
+ $sht(call=>$ci::granted_unit) = $var(granted);
|
|
|
+ $var(result) = 2001;
|
|
|
+ }
|
|
|
+
|
|
|
+ sht_lock("user=>$var(id)::reserved_credit");
|
|
|
+ $sht(user=>$var(id)::reserved_credit) = $sht(user=>$var(id)::reserved_credit) + $var(used_credit);
|
|
|
+ sht_unlock("user=>$var(id)::reserved_credit");
|
|
|
+
|
|
|
+ $sht(call=>$ci::reserved_credit) = $sht(call=>$ci::reserved_credit) + $var(used_credit);
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("$var(result): Granted $var(granted)s (used $sht(call=>$ci::used_unit)), total granted $sht(call=>$ci::granted_unit), reserved credit $sht(user=>$var(id)::reserved_credit), new $var(used_credit)\n");
|
|
|
+#!endif
|
|
|
+ } else if (is_method("BYE")) {
|
|
|
+ $var(id) = $sht(cid=>$ci);
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("$ci: User $var(id) has $sht(user=>$var(id)::current_calls) Calls, decrementing\n");
|
|
|
+#!endif
|
|
|
+ if ($var(id) != $null) {
|
|
|
+ sht_lock("user=>$var(id)::current_calls");
|
|
|
+ if ($sht(user=>$var(id)::current_calls) <= 0) {
|
|
|
+ $sht(user=>$var(id)::current_calls) = $null;
|
|
|
+ } else {
|
|
|
+ $sht(user=>$var(id)::current_calls) = $sht(user=>$var(id)::current_calls) - 1;
|
|
|
+ }
|
|
|
+ sht_unlock("user=>$var(id)::current_calls");
|
|
|
+ }
|
|
|
+ $var(used) = $sht(call=>$ci::used_unit) + $(hdr(P-Used-Units){s.int});
|
|
|
+ $var(credit) = $sht(user=>$var(id)::credit);
|
|
|
+ if ($var(used) > 0) {
|
|
|
+ $var(used_credit) = $sht(call=>$ci::initial_rate);
|
|
|
+ $var(used) = $var(used) - $sht(call=>$ci::initial_unit);
|
|
|
+ if (($sht(call=>$ci::follow_rate) != 0) && ($sht(call=>$ci::follow_unit) != 0) && ($var(used) > 0)) {
|
|
|
+ while ($var(used) > 0) {
|
|
|
+ $var(used) = $var(used) - $sht(call=>$ci::follow_unit);
|
|
|
+ $var(used_credit) = $var(used_credit) + $sht(call=>$ci::follow_rate);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $var(used) = $sht(call=>$ci::used_unit);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $var(used_credit) = 0;
|
|
|
+ $var(used) = 0;
|
|
|
+ }
|
|
|
+ if (($var(used_credit) > 0) && ($var(credit) > 0)) {
|
|
|
+ sht_lock("user=>$var(id)::credit");
|
|
|
+ $sht(user=>$var(id)::credit) = $sht(user=>$var(id)::credit) - $var(used_credit);
|
|
|
+ sht_unlock("user=>$var(id)::credit");
|
|
|
+ sql_query("hss_db", "UPDATE imsu SET credit=credit - ($var(used_credit)/$var(multiplier)) WHERE id=$var(id);");
|
|
|
+ if ($retcode == -1) {
|
|
|
+ $var(result) = 5012;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $var(duration) = $sht(call=>$ci::used_unit) + $(hdr(P-Used-Units){s.int});
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("Call-Cost: $var(used_credit), Duration $var(duration)\n");
|
|
|
+ xlog("Credit: $sht(user=>$var(id)::credit)\n");
|
|
|
+#!endif
|
|
|
+ sht_lock("user=>$var(id)::reserved_credit");
|
|
|
+ $sht(user=>$var(id)::reserved_credit) = $sht(user=>$var(id)::reserved_credit) - $sht(call=>$ci::reserved_credit);
|
|
|
+ sht_unlock("user=>$var(id)::reserved_credit");
|
|
|
+
|
|
|
+ sql_query("hss_db", "UPDATE tb_processed_cdrs SET connect=DATE_SUB(now(), interval $var(duration) second), stop=now(), duration=$var(duration), price=($var(used_credit)/$var(multiplier)) WHERE callid='$ci';");
|
|
|
+ if ($retcode == -1) {
|
|
|
+ $var(result) = 5012;
|
|
|
+ }
|
|
|
+
|
|
|
+ $var(result) = "2001";
|
|
|
+ }
|
|
|
+
|
|
|
+ ccr_result("$var(result)", "$var(granted)", "$var(final)");
|
|
|
+}
|
|
|
+
|
|
|
+event_route[ocs:ccr-term] {
|
|
|
+ # For the terminating case, we only check the user existence and Line-Limit
|
|
|
+ if ($fU =~ "^\+[1-9][0-9]+$")
|
|
|
+ $var(from) = $(fU{s.substr,1,0});
|
|
|
+ else
|
|
|
+ $var(from) = $fU;
|
|
|
+
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("TERM: $rm $var(from) => $ru\n\n");
|
|
|
+#!endif
|
|
|
+ $var(result) = "5012";
|
|
|
+ $var(granted) = "0";
|
|
|
+ $var(final) = "0";
|
|
|
+
|
|
|
+ if (is_method("INVITE")) {
|
|
|
+ sql_pvquery("hss_db", "SELECT impi.id AS impi_id, imsu.id, imsu.max_concurrent_calls FROM impu LEFT JOIN impi_impu ON impu.id = impi_impu.id_impu LEFT JOIN impi ON impi.id = impi_impu.id_impi LEFT JOIN imsu ON impi.id_imsu = imsu.id WHERE ((impu.type = 0 AND impu.identity='sip:$var(from)@$fd') OR (impu.type = 0 AND impu.identity='sip:+$var(from)@$fd') OR (impu.type = 0 AND impu.identity='tel:$var(from)') OR (impu.type = 0 AND impu.identity='tel:+$var(from)') OR (impu.type = 3 AND 'sip:$var(from)@$fd' REGEXP impu.identity) OR (impu.type = 3 AND 'sip:+$var(from)@$fd' REGEXP impu.identity) OR (impu.type = 3 AND 'tel:$var(from)' REGEXP impu.identity) OR (impu.type = 3 AND 'tel:+$var(from)' REGEXP impu.identity)) limit 1;", "$var(impi_id),$var(id),$var(concurrent_calls)");
|
|
|
+ if ($retcode != 1) {
|
|
|
+ # User not found, send DIAMETER_USER_UNKNOWN
|
|
|
+ $var(result) = 5030;
|
|
|
+ } else {
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("IMPI: $fu ($var(impi_id))\n");
|
|
|
+ xlog("IMSU-ID: $var(id)\n");
|
|
|
+ xlog("Concurrent-Calls: $var(concurrent_calls), currently ($sht(user=>$var(id)::current_calls))\n");
|
|
|
+#!endif
|
|
|
+
|
|
|
+ if (($sht(user=>$var(id)::current_calls) != $null) && ($var(concurrent_calls) >= 0)) {
|
|
|
+ if ($sht(user=>$var(id)::current_calls) >= $var(concurrent_calls)) {
|
|
|
+ $var(result) = 5006; # DIAMETER_RESOURCES_EXCEEDED
|
|
|
+ } else {
|
|
|
+ $sht(cid=>$ci) = $var(id);
|
|
|
+ sht_lock("user=>$var(id)::current_calls");
|
|
|
+ $sht(user=>$var(id)::current_calls) = $sht(user=>$var(id)::current_calls) + 1;
|
|
|
+ sht_unlock("user=>$var(id)::current_calls");
|
|
|
+ $var(result) = 2001;
|
|
|
+ $var(granted) = GRANT;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ sht_lock("user=>$var(id)::current_calls");
|
|
|
+ if ($sht(user=>$var(id)::current_calls) == $null) {
|
|
|
+ $sht(user=>$var(id)::current_calls) = 1;
|
|
|
+ } else {
|
|
|
+ $sht(user=>$var(id)::current_calls) = $sht(user=>$var(id)::current_calls) + 1;
|
|
|
+ }
|
|
|
+ sht_unlock("user=>$var(id)::current_calls");
|
|
|
+ $sht(cid=>$ci) = $var(id);
|
|
|
+ $var(result) = 2001;
|
|
|
+ $var(granted) = GRANT;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (is_method("UPDATE")) {
|
|
|
+ $var(result) = 2001;
|
|
|
+ $var(granted) = GRANT;
|
|
|
+ } else if (is_method("BYE")) {
|
|
|
+ $var(id) = $sht(cid=>$ci);
|
|
|
+#!ifdef WITH_DEBUG
|
|
|
+ xlog("$ci: User $var(id) has $sht(user=>$var(id)::current_calls) Calls, decrementing\n");
|
|
|
+#!endif
|
|
|
+ if ($var(id) != $null) {
|
|
|
+ sht_lock("user=>$var(id)::current_calls");
|
|
|
+ if ($sht(user=>$var(id)::current_calls) <= 0) {
|
|
|
+ $sht(user=>$var(id)::current_calls) = $null;
|
|
|
+ } else {
|
|
|
+ $sht(user=>$var(id)::current_calls) = $sht(user=>$var(id)::current_calls) - 1;
|
|
|
+ }
|
|
|
+ sht_unlock("user=>$var(id)::current_calls");
|
|
|
+ }
|
|
|
+ $var(result) = 2001;
|
|
|
+ }
|
|
|
+ // xlog("$rm: $var(result): $var(granted) units...\n");
|
|
|
+
|
|
|
+ ccr_result("$var(result)", "$var(granted)", "$var(final)");
|
|
|
+}
|