# OpenSIPS residential configuration script # by OpenSIPS Solutions ####### Global Parameters ######### log_level=3 log_stderror=no log_facility=LOG_LOCAL0 children=4 listen=udp:lo:5060 listen=udp:eth0:5060 listen=udp:eth1:5060 auto_aliases=no # do not open more than 4096 file descriptors open_files_limit=4096 ####### Modules Section ######## #set module path mpath="/usr/lib/x86_64-linux-gnu/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" #### 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_extra_hdrs", "Hint: credit expired\r\n") modparam("dialog", "dlg_match_mode", 1) modparam("dialog", "default_timeout", 21600) # 6 hours timeout modparam("dialog", "db_mode", 0) #### DbFlatstore module loadmodule "db_flatstore.so" modparam("db_flatstore", "single_file", 1) #### ACCounting module loadmodule "acc.so" modparam("acc", "detect_direction", 1) modparam("acc", "evi_extra", "cgr_reqtype=$avp(cgr_reqtype); cgr_account=$avp(cgr_account); cgr_destination=$avp(cgr_destination); cgr_supplier=$avp(cgr_supplier); cgr_answertime=$dlg_val(atime); dialog_id=$DLG_did") #### CfgUtils module loadmodule "cfgutils.so" #### CacheDB Local loadmodule "cachedb_local.so" #### UDP protocol loadmodule "proto_udp.so" #### Rest client loadmodule "rest_client.so" #### JSON parser loadmodule "json.so" #### Event route loadmodule "event_route.so" ####### Routing Logic ######## startup_route { subscribe_event("E_OPENSIPS_START", "udp:127.0.0.1:2020"); raise_event("E_OPENSIPS_START"); } local_route { if (is_method("BYE") ) { # make sure a LOCAL_DISCONNECT event is triggered on local BYEs acc_evi_request("LOCAL_DISCONNECT"); #FixMe } } ## Send AUTH request to CGRateS engine route[CGR_AUTH_REQ] { # Code to produce the json $json(cgr_auth) := "{}"; $json(cgr_auth/id) = "1"; $json(cgr_auth/method) = "ApierV1.GetMaxUsage"; $json(cgr_auth/params) := "[{}]"; $json(cgr_auth/params[0]/RequestType) = $avp(cgr_reqtype); $json(cgr_auth/params[0]/Account) = $avp(cgr_account); $json(cgr_auth/params[0]/Destination) = $avp(cgr_destination); $json(cgr_auth/params[0]/DialogId) = $DLG_did; async(rest_post("http://127.0.0.1:2080/jsonrpc", "$json(cgr_auth)", "application/json", "$avp(cgr_auth_reply)", "$var(ct)", "$var(rcode)"), CGR_AUTH_REPLY); } ## Process answer received from CGRateS engine route[CGR_AUTH_REPLY] { $json(cgr_auth_reply) := $avp(cgr_auth_reply); if $json(cgr_auth_reply/error) != NULL { xlog("Error received from CGRateS: $json(cgr_auth_reply/error)"); sl_send_reply("503","Charging controller error"); exit; } else if $json(cgr_auth_reply/result) == 0 { sl_send_reply("403","Payment required"); exit; } else if $json(cgr_auth_reply/result) > -1 { $DLG_timeout=$json(cgr_auth_reply/result); } route(CGR_LCR_REQ); } ## Send LCR request to CGRateS engine route[CGR_LCR_REQ] { #{"method":"ApierV1.GetLcr","params":[{"Direction":"","Tenant":"","Category":"","Account":"dan","Subject":"","Destination":"1001","TimeStart":"","Duration":""}],"id":0} # Code to produce the json $json(cgr_lcr) := "{}"; $json(cgr_lcr/id) = "2"; $json(cgr_lcr/method) = "ApierV1.GetLcrSuppliers"; $json(cgr_lcr/params) := "[{}]"; $json(cgr_lcr/params[0]/Account) = $avp(cgr_account); $json(cgr_lcr/params[0]/Destination) = $avp(cgr_destination); async(rest_post("http://127.0.0.1:2080/jsonrpc", "$json(cgr_lcr)", "application/json", "$avp(cgr_lcr_reply)", "$var(ct)", "$var(rcode)"), CGR_LCR_REPLY); } ## Process LCR reply received from CGRateS engine route[CGR_LCR_REPLY] { $json(cgr_lcr_reply) := $avp(cgr_lcr_reply); if $json(cgr_lcr_reply/error) != NULL { xlog("Error received from CGRateS: $json(cgr_lcr_reply/error)"); sl_send_reply("503","Charging controller error"); exit; } $avp(cgr_supplier) = $(json(cgr_lcr_reply/result){s.select,0,,}); route(location); route(relay); } # 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")) { do_accounting("evi"); } 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; } switch ($fU) { case "1001": case "1006": case "1007": $avp(cgr_reqtype) = "*prepaid"; break; case "1002": $avp(cgr_reqtype) = "*postpaid"; break; case "1003": $avp(cgr_reqtype) = "*pseudoprepaid"; break; default: $avp(cgr_reqtype) = "*rated"; } $avp(cgr_account)=$fU; $avp(cgr_destination)=$rU; do_accounting("evi", "missed|failed"); route(CGR_AUTH_REQ); #End of processing } if (!uri==myself) { 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; } route(location); route(relay); } route[relay] { # for INVITEs enable some additional helper routes if (is_method("INVITE") && !has_totag()) { t_on_reply("MSG_REPLY"); #added for completeness not tested t_on_failure("missed_call"); } if (!t_relay()) { send_reply("500","Internal Error"); }; exit; } route[location] { # do lookup with method filtering if (!lookup("location","m")) { t_newtran(); t_reply("404", "Not Found"); exit; } } failure_route[missed_call] { if (t_was_cancelled()) { exit; } } onreply_route[MSG_REPLY]{ if (t_check_status("200") && !$dlg_val(atime)){#so we set it ONLY ONCE $dlg_val(atime)=$Ts; } if (t_check_status("4..")){#CAPTURE ALL ERROR CODES NEGATIVE ASR record $dlg_val(atime)=NULL; } }