Add tut entry for opensips+diameter

INCOMPLETE
- shared cgrates configuration for three different scenarios
- every scenario has its own opensips configuration. For more info
check README or read comments inside the configuration
- added script for converting unix time to suitable Event-Timestamp
format
- added a dictionary.opensips entry for making Credit-Control diameter
requests possible
This commit is contained in:
ionutboangiu
2024-05-01 16:49:42 +03:00
committed by Dan Christian Bogos
parent 9af344aac7
commit 40eaa8739c
21 changed files with 1958 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
# Prepaid Scenario
1. **INVITE**: 1001 calls 1002.
2. **Send INITIAL_REQUEST CCR**: Before forwarding INVITE, have OpenSIPS send a Diameter Credit-Control INITIAL_REQUEST to authorize the call.
3. **Receive CCA**: Extract CC-Time from the reply's Granted-Service-Unit AVP and (if also authorized) then set the dialog timeout to that value.
4. **ACK**: 1002 answers the call, `dlg_on_answer` handler is triggered.
5. **Send UPDATE_REQUEST CCR**: Send an async Credit-Control request to CGRateS to initiate the session. (see bottom of cfg file to see why, same for the other async calls). No need for further updates as CGRateS will debit based on the configured `debit_interval`.
6. **SEND TERMINATION_REQUEST**: Wait for hangup/timeout. The `handle_hangup/handle_auth` handler will be triggered and send a Diameter Credit-Control TERMINATION_REQUEST. Both of those are almost identical, only differing AVP being Terminate-Cause (6/DIAMETER_AUTH_EXPIRED for timeout AND 1/DIAMETER_LOGOUT for hangup). This will terminate the session as well as process the CDR.
# Postpaid Scenario
The Postpaid scenario is the same as the above except:
- We only send an **EVENT_REQUEST** on `dlg_on_timeout/dlg_on_hangup` handlers to send a ProcessCDR request to CGRateS.
- Inside `dlg_on_answer` the answer time is recorded to calculate usage at the end.
# Accounting Scenario
Attempts to use the `do_accounting` method (part of the OpenSIPS accounting module) to send Accounting-Start and Accounting-Stop requests. Currently, it's only sending Accounting-Start on hangup which is not intended.
# Useful commands
- sudo -u opensips /usr/sbin/opensips -f /etc/opensips/opensips.cfg -m 64 -M 4 -D
- cgr-engine -config_path=/usr/share/cgrates/tutorials/osips_diam/etc/cgrates -logger=*stdout
- cgr-loader -path /usr/share/cgrates/tutorials/osips_diam/tp/ -verbose
- freeDiameterd -dd -c /etc/freeDiameter/freeDiameter.conf
- pjsua_listen --help
- pjsua_listen --accounts 1001,1002
- pjsua_call --help
- pjsua_call --from 1001 --to 1002 --dur 67

View File

@@ -0,0 +1,154 @@
{
"diameter_agent": {
"request_processors": [
{
"id": "AccountingStart",
"filters": ["*eq:~*req.Accounting-Record-Type:1"],
"flags": ["*initiate", "*accounts", "*log"],
"request_fields":[
{"tag": "Category", "path": "*cgreq.Category", "type": "*constant", "value": "call"},
{"tag": "RequestType", "path": "*cgreq.RequestType", "type": "*constant",
"value": "*prepaid", "mandatory": true},
{"tag": "OriginID", "path": "*cgreq.OriginID", "type": "*composed",
"value": "~*req.Session-Id", "mandatory": true},
{"tag": "OriginHost", "path": "*cgreq.OriginHost", "type": "*variable",
"value": "~*req.Origin-Host", "mandatory": true},
{"tag": "Account", "path": "*cgreq.Account", "type": "*variable",
"value": "~*req.User-Name", "mandatory": true},
{"tag": "Subject", "path": "*cgreq.Subject", "type": "*variable",
"value": "~*req.User-Name", "mandatory": true},
{"tag": "Destination", "path": "*cgreq.Destination", "type": "*variable",
"value": "~*req.SIP-AVP", "mandatory": true},
{"tag": "SetupTime", "path": "*cgreq.SetupTime", "type": "*variable",
"value": "~*req.Sip-Call-Setuptime", "mandatory": true},
{"tag": "AnswerTime", "path": "*cgreq.AnswerTime", "type": "*variable",
"value": "~*req.Sip-Call-Created", "mandatory": true},
{"tag": "RemoteAddr" , "path": "*cgreq.RemoteAddr", "type": "*variable",
"value": "~*vars.RemoteHost:s/(.*):\\d+/${1}/"}
],
"reply_fields":[
{
"tag": "Session-Id",
"path": "*rep.Session-Id",
"type": "*variable",
"value": "~*req.Session-Id"
},
{
"tag": "Origin-Host",
"path": "*rep.Origin-Host",
"type": "*variable",
"value": "~*req.Origin-Host"
},
{
"tag": "Origin-Realm",
"path": "*rep.Origin-Realm",
"type": "*variable",
"value": "~*req.Origin-Realm"
},
{
"tag": "Accounting-Record-Type",
"path": "*rep.Accounting-Record-Type",
"type": "*variable",
"value": "~*req.Accounting-Record-Type"
},
{
"tag": "Accounting-Record-Number",
"path": "*rep.Accounting-Record-Number",
"type": "*variable",
"value": "~*req.Accounting-Record-Number"
},
{
"tag": "ResultCode",
"filters": ["*notempty:~*cgrep.Error:"],
"path": "*rep.Result-Code",
"type": "*constant",
"value": "5030",
"blocker": true
},
{
"tag": "ResultCode",
"path": "*rep.Result-Code",
"type": "*constant",
"value": "2001"
}
]
},
{
"id": "AccountingStop",
"filters": ["*string:~*eq.Accounting-Record-Type:4"],
"flags": ["*terminate", "*accounts", "*cdrs", "*log"],
"request_fields":[
{"tag": "Category", "path": "*cgreq.Category", "type": "*constant", "value": "call"},
{"tag": "RequestType", "path": "*cgreq.RequestType", "type": "*constant",
"value": "*prepaid", "mandatory": true},
{"tag": "OriginID", "path": "*cgreq.OriginID", "type": "*variable",
"value": "~*req.Session-Id", "mandatory": true},
{"tag": "OriginHost", "path": "*cgreq.OriginHost", "type": "*variable",
"value": "~*req.Origin-Host", "mandatory": true},
{"tag": "Account", "path": "*cgreq.Account", "type": "*variable",
"value": "~*req.User-Name", "mandatory": true},
{"tag": "Subject", "path": "*cgreq.Subject", "type": "*variable",
"value": "~*req.User-Name", "mandatory": true},
{"tag": "Destination", "path": "*cgreq.Destination", "type": "*variable",
"value": "~*req.Sip-To-Tag", "mandatory": true},
{"tag": "SetupTime", "path": "*cgreq.SetupTime", "type": "*variable",
"value": "~*req.Sip-Call-Setuptime", "mandatory": true},
{"tag": "AnswerTime", "path": "*cgreq.AnswerTime", "type": "*variable",
"value": "~*req.Sip-Call-Created", "mandatory": true},
{"tag": "Usage", "path": "*cgreq.Usage", "type": "*variable",
"value": "~*req.Sip-Call-Duration", "mandatory": true},
{"tag": "RemoteAddr" , "path": "*cgreq.RemoteAddr", "type": "*variable",
"value": "~*vars.RemoteHost:s/(.*):\\d+/${1}/"}
],
"reply_fields":[
{
"tag": "Session-Id",
"path": "*rep.Session-Id",
"type": "*variable",
"value": "~*req.Session-Id"
},
{
"tag": "Origin-Host",
"path": "*rep.Origin-Host",
"type": "*variable",
"value": "~*req.Origin-Host"
},
{
"tag": "Origin-Realm",
"path": "*rep.Origin-Realm",
"type": "*variable",
"value": "~*req.Origin-Realm"
},
{
"tag": "Accounting-Record-Type",
"path": "*rep.Accounting-Record-Type",
"type": "*variable",
"value": "~*req.Accounting-Record-Type"
},
{
"tag": "Accounting-Record-Number",
"path": "*rep.Accounting-Record-Number",
"type": "*variable",
"value": "~*req.Accounting-Record-Number"
},
{
"tag": "ResultCode",
"filters": ["*notempty:~*cgrep.Error:"],
"path": "*rep.Result-Code",
"type": "*constant",
"value": "5030",
"blocker": true
},
{
"tag": "ResultCode",
"path": "*rep.Result-Code",
"type": "*constant",
"value": "2001"
}
]
}
]
}
}

View File

@@ -0,0 +1,139 @@
{
"diameter_agent": {
"request_processors": [
{
"id": "SessionProcessCDR",
"filters": [
"*string:~*vars.*cmd:CCR",
"*string:~*req.CC-Request-Type:4",
"*prefix:~*req.Service-Context-Id:voice"
],
"flags": ["*cdrs", "*log"],
"request_fields":[
{
"tag": "ToR",
"path": "*cgreq.ToR",
"type": "*constant",
"value": "*voice"
},
{
"tag": "OriginID",
"path": "*cgreq.OriginID",
"type": "*variable",
"value": "~*req.Session-Id",
"mandatory": true
},
{
"tag": "OriginHost",
"path": "*cgreq.OriginHost",
"type": "*variable",
"value": "~*req.Origin-Host",
"mandatory": true
},
{
"tag": "RequestType",
"path": "*cgreq.RequestType",
"type": "*constant",
"value": "*postpaid"
},
{
"tag": "Account",
"path": "*cgreq.Account",
"type": "*variable",
"value": "~*req.Service-Information.IMS-Information.Calling-Party-Address",
"mandatory": true
},
{
"tag": "Destination",
"path": "*cgreq.Destination",
"type": "*variable",
"value": "~*req.Service-Information.IMS-Information.Called-Party-Address",
"mandatory": true
},
{
"tag": "AnswerTime",
"path": "*cgreq.AnswerTime",
"type": "*variable",
"value": "~*req.Event-Timestamp",
"mandatory": true
},
{
"tag": "Usage",
"path": "*cgreq.Usage",
"type": "*cc_usage",
"mandatory": true,
"value": "~*req.CC-Request-Number;~*req.Used-Service-Unit.CC-Time:s/(.*)/${1}s/;5m"
},
{
"tag": "LastUsed",
"path": "*cgreq.LastUsed",
"type": "*variable",
"value": "~*req.Used-Service-Unit.CC-Time:s/(.*)/${1}s/",
"mandatory": true
},
{
"tag": "SubscriberID",
"path": "*cgreq.SubscriberId",
"type": "*variable",
"value": "~*req.Subscription-Id.Subscription-Id-Data",
"mandatory": true
}
],
"reply_fields":[
{
"tag": "Session-Id",
"path": "*rep.Session-Id",
"type": "*variable",
"value": "~*req.Session-Id"
},
{
"tag": "Origin-Host",
"path": "*rep.Origin-Host",
"type": "*variable",
"value": "~*req.Origin-Host"
},
{
"tag": "Origin-Realm",
"path": "*rep.Origin-Realm",
"type": "*variable",
"value": "~*req.Origin-Realm"
},
{
"tag": "Auth-Application-Id",
"path": "*rep.Auth-Application-Id",
"type": "*variable",
"value": "~*req.Auth-Application-Id"
},
{
"tag": "CC-Request-Type",
"path": "*rep.CC-Request-Type",
"type": "*variable",
"value": "~*req.CC-Request-Type"
},
{
"tag": "CC-Request-Number",
"path": "*rep.CC-Request-Number",
"type": "*variable",
"value": "~*req.CC-Request-Number"
},
{
"tag": "ResultCode",
"filters": ["*notempty:~*cgrep.Error:"],
"path": "*rep.Result-Code",
"type": "*constant",
"value": "5030",
"blocker": true
},
{
"tag": "ResultCode",
"path": "*rep.Result-Code",
"type": "*constant",
"value": "2001"
}
]
}
]
}
}

View File

@@ -0,0 +1,139 @@
{
"diameter_agent": {
"request_processors": [
{
"id": "SessionAuth",
"filters": [
"*string:~*vars.*cmd:CCR",
"*string:~*req.CC-Request-Type:1",
"*prefix:~*req.Service-Context-Id:voice"
],
"flags": ["*authorize", "*accounts", "*log"],
"request_fields":[
{
"tag": "ToR",
"path": "*cgreq.ToR",
"type": "*constant",
"value": "*voice"
},
{
"tag": "OriginID",
"path": "*cgreq.OriginID",
"type": "*variable",
"value": "~*req.Session-Id",
"mandatory": true
},
{
"tag": "OriginHost",
"path": "*cgreq.OriginHost",
"type": "*variable",
"value": "~*req.Origin-Host",
"mandatory": true
},
{
"tag": "RequestType",
"path": "*cgreq.RequestType",
"type": "*constant",
"value": "*prepaid",
"mandatory": true
},
{
"tag": "Account",
"path": "*cgreq.Account",
"type": "*variable",
"value": "~*req.Service-Information.IMS-Information.Calling-Party-Address",
"mandatory": true
},
{
"tag": "Destination",
"path": "*cgreq.Destination",
"type": "*variable",
"value": "~*req.Service-Information.IMS-Information.Called-Party-Address",
"mandatory": true
},
{
"tag": "SetupTime",
"path": "*cgreq.SetupTime",
"type": "*variable",
"value": "~*req.Event-Timestamp",
"mandatory": true
},
{
"tag": "Usage",
"path": "*cgreq.Usage",
"type": "*variable",
"mandatory": true,
"value": "~*req.Requested-Service-Unit.CC-Time;s"
},
{
"tag": "SubscriberID",
"path": "*cgreq.SubscriberId",
"type": "*variable",
"value": "~*req.Subscription-Id.Subscription-Id-Data",
"mandatory": true
}
],
"reply_fields":[
{
"tag": "Session-Id",
"path": "*rep.Session-Id",
"type": "*variable",
"value": "~*req.Session-Id"
},
{
"tag": "Origin-Host",
"path": "*rep.Origin-Host",
"type": "*variable",
"value": "~*req.Origin-Host"
},
{
"tag": "Origin-Realm",
"path": "*rep.Origin-Realm",
"type": "*variable",
"value": "~*req.Origin-Realm"
},
{
"tag": "Auth-Application-Id",
"path": "*rep.Auth-Application-Id",
"type": "*variable",
"value": "~*req.Auth-Application-Id"
},
{
"tag": "CC-Request-Type",
"path": "*rep.CC-Request-Type",
"type": "*variable",
"value": "~*req.CC-Request-Type"
},
{
"tag": "CC-Request-Number",
"path": "*rep.CC-Request-Number",
"type": "*variable",
"value": "~*req.CC-Request-Number"
},
{
"tag": "ResultCode",
"filters": ["*notempty:~*cgrep.Error:"],
"path": "*rep.Result-Code",
"type": "*constant",
"value": "5030",
"blocker": true
},
{
"tag": "ResultCode",
"path": "*rep.Result-Code",
"type": "*constant",
"value": "2001"
},
{
"tag": "Granted-Units",
"path": "*rep.Granted-Service-Unit.CC-Time",
"type": "*variable",
"value": "~*cgrep.MaxUsage{*duration_seconds}"
}
]
}
]
}
}

View File

@@ -0,0 +1,126 @@
{
"diameter_agent": {
"request_processors": [
{
"id": "SessionInit",
"filters": [
"*string:~*vars.*cmd:CCR",
"*string:~*req.CC-Request-Type:2",
"*prefix:~*req.Service-Context-Id:voice"
],
"flags": ["*initiate", "*accounts", "*log"],
"request_fields":[
{
"tag": "ToR",
"path": "*cgreq.ToR",
"type": "*constant",
"value": "*voice"
},
{
"tag": "OriginID",
"path": "*cgreq.OriginID",
"type": "*variable",
"value": "~*req.Session-Id",
"mandatory": true
},
{
"tag": "OriginHost",
"path": "*cgreq.OriginHost",
"type": "*variable",
"value": "~*req.Origin-Host",
"mandatory": true
},
{
"tag": "RequestType",
"path": "*cgreq.RequestType",
"type": "*constant",
"value": "*prepaid",
"mandatory": true
},
{
"tag": "Account",
"path": "*cgreq.Account",
"type": "*variable",
"value": "~*req.Service-Information.IMS-Information.Calling-Party-Address",
"mandatory": true
},
{
"tag": "Destination",
"path": "*cgreq.Destination",
"type": "*variable",
"value": "~*req.Service-Information.IMS-Information.Called-Party-Address",
"mandatory": true
},
{
"tag": "AnswerTime",
"path": "*cgreq.AnswerTime",
"type": "*variable",
"value": "~*req.Event-Timestamp",
"mandatory": true
},
{
"tag": "SubscriberID",
"path": "*cgreq.SubscriberId",
"type": "*variable",
"value": "~*req.Subscription-Id.Subscription-Id-Data",
"mandatory": true
}
],
"reply_fields":[
{
"tag": "Session-Id",
"path": "*rep.Session-Id",
"type": "*variable",
"value": "~*req.Session-Id"
},
{
"tag": "Origin-Host",
"path": "*rep.Origin-Host",
"type": "*variable",
"value": "~*req.Origin-Host"
},
{
"tag": "Origin-Realm",
"path": "*rep.Origin-Realm",
"type": "*variable",
"value": "~*req.Origin-Realm"
},
{
"tag": "Auth-Application-Id",
"path": "*rep.Auth-Application-Id",
"type": "*variable",
"value": "~*req.Auth-Application-Id"
},
{
"tag": "CC-Request-Type",
"path": "*rep.CC-Request-Type",
"type": "*variable",
"value": "~*req.CC-Request-Type"
},
{
"tag": "CC-Request-Number",
"path": "*rep.CC-Request-Number",
"type": "*variable",
"value": "~*req.CC-Request-Number"
},
{
"tag": "ResultCode",
"filters": ["*notempty:~*cgrep.Error:"],
"path": "*rep.Result-Code",
"type": "*constant",
"value": "5030",
"blocker": true
},
{
"tag": "ResultCode",
"path": "*rep.Result-Code",
"type": "*constant",
"value": "2001"
}
]
}
]
}
}

View File

@@ -0,0 +1,145 @@
{
"diameter_agent": {
"request_processors": [
{
"id": "SessionTerminate",
"filters": [
"*string:~*vars.*cmd:CCR",
"*string:~*req.CC-Request-Type:3",
"*prefix:~*req.Service-Context-Id:voice"
],
"flags": ["*terminate", "*accounts", "*cdrs", "*log"],
"request_fields":[
{
"tag": "ToR",
"path": "*cgreq.ToR",
"type": "*constant",
"value": "*voice"
},
{
"tag": "OriginID",
"path": "*cgreq.OriginID",
"type": "*variable",
"value": "~*req.Session-Id",
"mandatory": true
},
{
"tag": "OriginHost",
"path": "*cgreq.OriginHost",
"type": "*variable",
"value": "~*req.Origin-Host",
"mandatory": true
},
{
"tag": "RequestType",
"path": "*cgreq.RequestType",
"type": "*constant",
"value": "*prepaid"
},
{
"tag": "Account",
"path": "*cgreq.Account",
"type": "*variable",
"value": "~*req.Service-Information.IMS-Information.Calling-Party-Address",
"mandatory": true
},
{
"tag": "Destination",
"path": "*cgreq.Destination",
"type": "*variable",
"value": "~*req.Service-Information.IMS-Information.Called-Party-Address",
"mandatory": true
},
{
"tag": "AnswerTime",
"path": "*cgreq.AnswerTime",
"type": "*variable",
"value": "~*req.Event-Timestamp",
// "value": "~*req.Service-Information.IMS-Information.Time-Stamps.SIP-Request-Response",
"mandatory": true
},
// would using these assume that an update CCR request is sent at every debit interval?
//
// For now I commented them, and let have this just terminate and debit the cached session.
// {
// "tag": "Usage",
// "path": "*cgreq.Usage",
// "type": "*cc_usage",
// "mandatory": true,
// "value": "~*req.CC-Request-Number;~*req.Used-Service-Unit.CC-Time:s/(.*)/${1}s/;5s"
// },
// {
// "tag": "LastUsed",
// "path": "*cgreq.LastUsed",
// "type": "*variable",
// "value": "~*req.Used-Service-Unit.CC-Time:s/(.*)/${1}s/",
// "mandatory": true
// },
{
"tag": "SubscriberID",
"path": "*cgreq.SubscriberId",
"type": "*variable",
"value": "~*req.Subscription-Id.Subscription-Id-Data",
"mandatory": true
}
],
"reply_fields":[
{
"tag": "Session-Id",
"path": "*rep.Session-Id",
"type": "*variable",
"value": "~*req.Session-Id"
},
{
"tag": "Origin-Host",
"path": "*rep.Origin-Host",
"type": "*variable",
"value": "~*req.Origin-Host"
},
{
"tag": "Origin-Realm",
"path": "*rep.Origin-Realm",
"type": "*variable",
"value": "~*req.Origin-Realm"
},
{
"tag": "Auth-Application-Id",
"path": "*rep.Auth-Application-Id",
"type": "*variable",
"value": "~*req.Auth-Application-Id"
},
{
"tag": "CC-Request-Type",
"path": "*rep.CC-Request-Type",
"type": "*variable",
"value": "~*req.CC-Request-Type"
},
{
"tag": "CC-Request-Number",
"path": "*rep.CC-Request-Number",
"type": "*variable",
"value": "~*req.CC-Request-Number"
},
{
"tag": "ResultCode",
"filters": ["*notempty:~*cgrep.Error:"],
"path": "*rep.Result-Code",
"type": "*constant",
"value": "5030",
"blocker": true
},
{
"tag": "ResultCode",
"path": "*rep.Result-Code",
"type": "*constant",
"value": "2001"
}
]
}
]
}
}

View File

@@ -0,0 +1,75 @@
{
"general": {
"log_level": 7
},
"listen": {
"rpc_json": ":2012",
"rpc_gob": ":2013",
"http": ":2080"
},
"stor_db": {
"db_password": "CGRateS.org"
},
"schedulers": {
"enabled": true
},
"rals": {
"enabled": true
},
"cdrs": {
"enabled": true,
"chargers_conns": ["*localhost"],
"rals_conns": ["*localhost"],
"sessions_cost_retries": 5
},
"chargers": {
"enabled": true,
"attributes_conns": ["*localhost"]
},
"sessions": {
"enabled": true,
"listen_bijson": "127.0.0.1:2014",
"chargers_conns": ["*localhost"],
"rals_conns": ["*localhost"],
"cdrs_conns": ["*localhost"],
"attributes_conns": ["*localhost"],
"debit_interval": "5s"
},
"attributes": {
"enabled": true,
"string_indexed_fields": ["*req.Account"]
},
"apiers": {
"enabled": true,
"scheduler_conns": ["*localhost"]
},
"diameter_agent": {
"enabled": true,
"listen": "192.168.122.42:3868",
"listen_net": "tcp",
"dictionaries_path": "/usr/share/cgrates/diameter/dict/",
"sessions_conns": ["*bijson_localhost"],
"origin_host": "server.diameter.test",
"origin_realm": "diameter.test",
"vendor_id": 0,
"product_name": "CGRateS",
"concurrent_requests": -1,
"synced_conn_requests": false,
"asr_template": "*asr",
"rar_template": "*rar",
"forced_disconnect": "*asr"
}
}

View File

@@ -0,0 +1,94 @@
APPLICATION 4 Charging Control
ATTRIBUTE Result-Code 268 unsigned32
ATTRIBUTE Value-Digits 447 integer64
ATTRIBUTE Exponent 429 integer32
ATTRIBUTE Unit-Value 445 grouped
{
Value-Digits | REQUIRED | 1
Exponent | REQUIRED | 1
}
ATTRIBUTE Currency-Code 425 unsigned32
ATTRIBUTE CC-Money 413 grouped
{
Unit-Value | REQUIRED | 1
Currency-Code | REQUIRED | 1
}
ATTRIBUTE CC-Request-Number 415 unsigned32
ATTRIBUTE CC-Request-Type 416 unsigned32
ATTRIBUTE CC-Time 420 unsigned32
ATTRIBUTE Granted-Service-Unit 431 grouped
{
CC-Time | OPTIONAL | 1
CC-Money | OPTIONAL | 1
}
ATTRIBUTE Requested-Service-Unit 437 grouped
{
CC-Time | OPTIONAL | 1
CC-Money | OPTIONAL | 1
}
ATTRIBUTE Subscription-Id-Type 450 unsigned32
ATTRIBUTE Subscription-Id-Data 444 string
ATTRIBUTE Subscription-Id 443 grouped
{
Subscription-Id-Type | REQUIRED | 1
Subscription-Id-Data | REQUIRED | 1
}
ATTRIBUTE Used-Service-Unit 446 grouped
{
CC-Time | OPTIONAL | 1
CC-Money | OPTIONAL | 1
}
ATTRIBUTE Service-Context-Id 461 string
VENDOR 10415 TGPP
ATTRIBUTE Calling-Party-Address 831 string 10415
ATTRIBUTE Called-Party-Address 832 string 10415
ATTRIBUTE SIP-Request-Timestamp 2301 unsigned32 10415
ATTRIBUTE SIP-Response-Timestamp 834 string 10415
ATTRIBUTE Time-Stamps 833 grouped 10415
{
SIP-Request-Timestamp | OPTIONAL | 1
SIP-Response-Timestamp | OPTIONAL | 1
}
ATTRIBUTE IMS-Information 876 grouped 10415
{
Calling-Party-Address | OPTIONAL | 1
Called-Party-Address | OPTIONAL | 1
Time-Stamps | OPTIONAL | 1
}
ATTRIBUTE Service-Information 873 grouped 10415
{
IMS-Information | OPTIONAL | 1
}
REQUEST 272 Credit-Control-Request
{
Session-Id | REQUIRED | 1
Origin-Host | REQUIRED | 1
Origin-Realm | REQUIRED | 1
Destination-Realm | REQUIRED | 1
Auth-Application-Id | REQUIRED | 1
Service-Context-Id | REQUIRED | 1
CC-Request-Type | REQUIRED | 1
CC-Request-Number | REQUIRED | 1
Event-Timestamp | OPTIONAL | 1
User-Name | OPTIONAL | 1
Subscription-Id | OPTIONAL | 1
Requested-Service-Unit | OPTIONAL | 1
Used-Service-Unit | OPTIONAL | 1
Service-Information | OPTIONAL | 1
Termination-Cause | OPTIONAL | 1
}
ANSWER 272 Credit-Control-Answer
{
Result-Code | OPTIONAL | 1
Session-Id | OPTIONAL | 1
Origin-Host | OPTIONAL | 1
Origin-Realm | OPTIONAL | 1
CC-Request-Type | OPTIONAL | 1
CC-Request-Number | OPTIONAL | 1
Granted-Service-Unit | OPTIONAL | 1
Route-Record | OPTIONAL | 1
}

View File

@@ -0,0 +1,278 @@
#
# OpenSIPS residential configuration script
# by OpenSIPS Solutions <team@opensips-solutions.com>
#
# 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:
# https://opensips.org/Resources/DocsCookbooks
# for a explanation of possible statements, functions and parameters.
#
####### Global Parameters #########
debug_mode=no
log_stdout=yes
log_level=3
xlog_level=3
stderror_enabled=no
syslog_enabled=yes
syslog_facility=LOG_LOCAL0
udp_workers=4
socket=udp:enp0s3:5060
socket=udp:127.0.0.1:5060
####### 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"
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", "/run/opensips/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)
#### USeR LOCation module
loadmodule "usrloc.so"
modparam("usrloc", "nat_bflag", "NAT")
modparam("usrloc", "working_mode_preset", "single-instance-no-db")
#### REGISTRAR module
loadmodule "registrar.so"
modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")
#modparam("registrar", "max_contacts", 10)
#### ACCounting module
loadmodule "acc.so"
modparam("acc", "early_media", 0)
modparam("acc", "report_cancels", 0)
modparam("acc", "detect_direction", 0)
modparam("acc", "aaa_url", "diameter:/etc/freeDiameter/freeDiameter.conf")
# Adding some AVPs to identify account and destination. No idea what AVP to use
# for destination. Went for SIP-AVP.
modparam("acc", "extra_fields", "aaa: account -> User-Name ; destination -> SIP-AVP")
# Sip-Session
modparam("acc", "service_type", 15)
loadmodule "proto_udp.so"
#### Dialog module
loadmodule "dialog.so"
#### Auth modules (not used in this cfg)
loadmodule "auth.so"
loadmodule "auth_aaa.so"
modparam("auth_aaa", "aaa_url", "diameter:/etc/freeDiameter/freeDiameter.conf")
#### Diameter module
loadmodule "aaa_diameter.so"
modparam("aaa_diameter", "fd_log_level", 0)
modparam("aaa_diameter", "realm", "diameter.test")
modparam("aaa_diameter", "peer_identity", "server")
####### Routing Logic ########
# main request routing logic
route{
if (!mf_process_maxfwd_header(10)) {
send_reply(483,"Too Many Hops");
exit;
}
if (has_totag()) {
# handle hop-by-hop ACK (no routing required)
if ( is_method("ACK") && t_check_trans() ) {
t_relay();
exit;
}
# sequential request within a dialog should
# take the path determined by record-routing
if ( !loose_route() ) {
# we do record-routing for all our traffic, so we should not
# receive any sequential requests without Route hdr.
send_reply(404,"Not here");
exit;
}
if (is_method("BYE")) {
# do accounting even if the transaction fails
do_accounting("log","failed");
}
# route it out to whatever destination was set by loose_route()
# in $du (destination URI).
route(relay);
exit;
}
# CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans())
t_relay();
exit;
}
# absorb retransmissions, but do not create transaction
t_check_trans();
if ( !(is_method("REGISTER") ) ) {
if (is_myself("$fd")) {
} else {
# if caller is not local, then called number must be local
if (!is_myself("$rd")) {
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"))
send_reply(403,"Preload Route denied");
exit;
}
# record routing
if (!is_method("REGISTER|MESSAGE"))
record_route();
# account only INVITEs
if (is_method("INVITE")) {
# if (!aaa_proxy_authorize("$fd")){
# proxy_challenge("$fd");
# exit;
# }
$acc_extra(account) = $fU;
$acc_extra(destination) = $rU;
# this sends an accounting start on hangup/timeout. Not
# sure how to set up accounting to send Accounting-Start
# on answer and Accounting-Stop on hangup.
do_accounting("aaa", "cdr");
}
if (!is_myself("$rd")) {
append_hf("P-hint: outbound\r\n");
route(relay);
}
# requests for my domain
if (is_method("PUBLISH|SUBSCRIBE")) {
send_reply(503, "Service Unavailable");
exit;
}
if (is_method("REGISTER")) {
# store the registration and generate a SIP reply
if (!save("location"))
xlog("failed to register AoR $tu\n");
exit;
}
if ($rU==NULL) {
# request with no Username in RURI
send_reply(484,"Address Incomplete");
exit;
}
# do lookup with method filtering
if (!lookup("location","method-filtering")) {
t_reply(404, "Not Found");
exit;
}
do_accounting("log","missed");
route(relay);
}
route[relay] {
# for INVITEs enable some additional helper routes
if (is_method("INVITE")) {
t_on_branch("per_branch_ops");
t_on_reply("handle_nat");
t_on_failure("missed_call");
}
if (!t_relay()) {
send_reply(500,"Internal Error");
}
exit;
}
branch_route[per_branch_ops] {
xlog("new branch at $ru\n");
}
onreply_route[handle_nat] {
xlog("incoming reply\n");
}
failure_route[missed_call] {
if (t_was_cancelled()) {
exit;
}
# uncomment the following lines if you want to block client
# redirect based on 3xx replies.
##if (t_check_status("3[0-9][0-9]")) {
##t_reply(404,"Not found");
## exit;
##}
}

View File

@@ -0,0 +1,309 @@
#
# OpenSIPS residential configuration script
# by OpenSIPS Solutions <team@opensips-solutions.com>
#
# 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:
# https://opensips.org/Resources/DocsCookbooks
# for a explanation of possible statements, functions and parameters.
#
####### Global Parameters #########
debug_mode=no
log_stdout=yes
log_level=3
xlog_level=3
stderror_enabled=no
syslog_enabled=yes
syslog_facility=LOG_LOCAL0
udp_workers=4
socket=udp:enp0s3:5060
socket=udp:127.0.0.1:5060
####### 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"
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", "/run/opensips/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)
#### USeR LOCation module
loadmodule "usrloc.so"
modparam("usrloc", "nat_bflag", "NAT")
modparam("usrloc", "working_mode_preset", "single-instance-no-db")
#### REGISTRAR module
loadmodule "registrar.so"
modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")
loadmodule "proto_udp.so"
#### Dialog module
loadmodule "dialog.so"
#### Exec module
loadmodule "exec.so"
#### Diameter module
loadmodule "aaa_diameter.so"
modparam("aaa_diameter", "fd_log_level", 0)
modparam("aaa_diameter", "realm", "diameter.test")
modparam("aaa_diameter", "peer_identity", "server")
modparam("aaa_diameter", "aaa_url", "diameter:/etc/freeDiameter/freeDiameter.conf;extra-avps-file:/etc/opensips/dictionary.opensips")
####### Routing Logic ########
# main request routing logic
route{
if (!mf_process_maxfwd_header(10)) {
send_reply(483,"Too Many Hops");
exit;
}
if (has_totag()) {
# handle hop-by-hop ACK (no routing required)
if ( is_method("ACK") && t_check_trans() ) {
t_relay();
exit;
}
# sequential request within a dialog should
# take the path determined by record-routing
if ( !loose_route() ) {
# we do record-routing for all our traffic, so we should not
# receive any sequential requests without Route hdr.
send_reply(404,"Not here");
exit;
}
# if (is_method("BYE")) {
# # do accounting even if the transaction fails
# do_accounting("log","failed");
# }
# route it out to whatever destination was set by loose_route()
# in $du (destination URI).
route(relay);
exit;
}
# CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans())
t_relay();
exit;
}
# absorb retransmissions, but do not create transaction
t_check_trans();
if ( !(is_method("REGISTER") ) ) {
if (is_myself("$fd")) {
} else {
# if caller is not local, then called number must be local
if (!is_myself("$rd")) {
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"))
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();
$dlg_val(callid) = $ci;
$dlg_val(originhost) = $(ou{uri.host});
$dlg_val(originrealm) = $fd;
$dlg_val(setuptime) = $Ts;
$dlg_val(account) = $fU;
$dlg_val(destination) = $rU;
# we need an answer handler to record answertime for cdr processing
dlg_on_answer("handle_answer");
# would probably be a good idea to have a timeout handler also
dlg_on_hangup("handle_hangup");
}
if (!is_myself("$rd")) {
append_hf("P-hint: outbound\r\n");
route(relay);
}
# requests for my domain
if (is_method("PUBLISH|SUBSCRIBE")) {
send_reply(503, "Service Unavailable");
exit;
}
if (is_method("REGISTER")) {
# store the registration and generate a SIP reply
if (!save("location"))
xlog("failed to register AoR $tu\n");
exit;
}
if ($rU==NULL) {
# request with no Username in RURI
send_reply(484,"Address Incomplete");
exit;
}
# do lookup with method filtering
if (!lookup("location","method-filtering")) {
t_reply(404, "Not Found");
exit;
}
route(relay);
}
route[handle_answer] {
$dlg_val(answertime) = $Ts;
xlog("$$dlg_val(answertime) 1 = $dlg_val(answertime)\n");
}
route[handle_hangup] {
$var(duration) = $Ts - $dlg_val(answertime);
exec("/usr/share/cgrates/tutorials/osips_diam/etc/opensips/unix2ntp", "$dlg_val(answertime)", $var(answertime32bit), , );
$var(payload) = "[
{ \"Session-Id\": \"" + $dlg_val(callid) + "\" },
{ \"Origin-Host\": \"client.diameter.test\" },
{ \"Origin-Realm\": \"diameter.test\" },
{ \"Destination-Realm\": \"diameter.test\" },
{ \"Service-Context-Id\": \"voice@OsipsDiamCCR\" },
{ \"CC-Request-Type\": 4 },
{ \"CC-Request-Number\": 0 },
{ \"Termination-Cause\": 1 },
{ \"Event-Timestamp\": \"" + $var(answertime32bit) + "\" },
{ \"User-Name\": \"" + $dlg_val(account) + "\" },
{ \"Subscription-Id\": [
{ \"Subscription-Id-Type\": 0 },
{ \"Subscription-Id-Data\": \"" + $dlg_val(account) + "\" }
]},
{ \"Requested-Service-Unit\": [
{\"CC-Time\": 0}
]},
{ \"Used-Service-Unit\": [
{\"CC-Time\": " + $var(duration) + " }
]},
{ \"Service-Information\": [
{\"IMS-Information\": [
{ \"Calling-Party-Address\": \"" + $dlg_val(account) + "\" },
{ \"Called-Party-Address\": \"" + $dlg_val(destination) + "\" }
]}
]}
]";
dm_send_request(4, 272, $var(payload), $var(rpl_avps));
if ($rc < 1) {
xlog("error processing diameter request (returned $rc), received reply: $var(rpl_avps)");
exit;
}
route(relay);
}
route[relay] {
# for INVITEs enable some additional helper routes
if (is_method("INVITE")) {
t_on_branch("per_branch_ops");
t_on_reply("handle_nat");
t_on_failure("missed_call");
}
if (!t_relay()) {
send_reply(500,"Internal Error");
}
exit;
}
branch_route[per_branch_ops] {
xlog("new branch at $ru\n");
}
onreply_route[handle_nat] {
xlog("incoming reply\n");
}
failure_route[missed_call] {
if (t_was_cancelled()) {
exit;
}
# uncomment the following lines if you want to block client
# redirect based on 3xx replies.
##if (t_check_status("3[0-9][0-9]")) {
##t_reply(404,"Not found");
## exit;
##}
}

View File

@@ -0,0 +1,440 @@
#
# OpenSIPS residential configuration script
# by OpenSIPS Solutions <team@opensips-solutions.com>
#
# 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:
# https://opensips.org/Resources/DocsCookbooks
# for a explanation of possible statements, functions and parameters.
#
####### Global Parameters #########
debug_mode=no
log_stdout = yes
log_level=3
xlog_level=3
stderror_enabled=no
syslog_enabled=yes
syslog_facility=LOG_LOCAL0
udp_workers=4
socket=udp:enp0s3:5060
socket=udp:127.0.0.1:5060
####### 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"
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", "/run/opensips/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)
#### USeR LOCation module
loadmodule "usrloc.so"
modparam("usrloc", "nat_bflag", "NAT")
modparam("usrloc", "working_mode_preset", "single-instance-no-db")
#### REGISTRAR module
loadmodule "registrar.so"
modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")
#modparam("registrar", "max_contacts", 10)
loadmodule "proto_udp.so"
#### Dialog module
loadmodule "dialog.so"
#### Exec module
loadmodule "exec.so"
#### JSON module
loadmodule "json.so"
#### Diameter module
loadmodule "aaa_diameter.so"
modparam("aaa_diameter", "fd_log_level", 0)
modparam("aaa_diameter", "realm", "diameter.test")
modparam("aaa_diameter", "peer_identity", "server")
modparam("aaa_diameter", "aaa_url", "diameter:/etc/freeDiameter/freeDiameter.conf;extra-avps-file:/etc/opensips/dictionary.opensips")
####### Routing Logic ########
# main request routing logic
route{
if (!mf_process_maxfwd_header(10)) {
send_reply(483,"Too Many Hops");
exit;
}
if (has_totag()) {
# handle hop-by-hop ACK (no routing required)
if ( is_method("ACK") && t_check_trans() ) {
t_relay();
exit;
}
# sequential request within a dialog should
# take the path determined by record-routing
if ( !loose_route() ) {
# we do record-routing for all our traffic, so we should not
# receive any sequential requests without Route hdr.
send_reply(404,"Not here");
exit;
}
# route it out to whatever destination was set by loose_route()
# in $du (destination URI).
route(relay);
exit;
}
# CANCEL processing
if (is_method("CANCEL")) {
if (t_check_trans())
t_relay();
exit;
}
# absorb retransmissions, but do not create transaction
t_check_trans();
if ( !(is_method("REGISTER") ) ) {
if (is_myself("$fd")) {
} else {
# if caller is not local, then called number must be local
if (!is_myself("$rd")) {
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"))
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();
# populate dialog variables to use them inside handlers
$dlg_val(setuptime) = $Ts;
$dlg_val(callid) = $ci;
$dlg_val(originhost) = $(ou{uri.host});
$dlg_val(originrealm) = $fd;
$dlg_val(account) = $fU;
$dlg_val(destination) = $rU;
# use the unix2ntp helper script to convert unix time to 32bit format
# for the Event-Timestamp AVP
# can this be done directly inside the cfg file?
exec("/usr/share/cgrates/tutorials/osips_diam/etc/opensips/unix2ntp", "$dlg_val(setuptime)", $var(setuptime32bit), , );
# Send blocking CCR INITIAL_REQUEST and retrieve MaxUsage
$var(payload) = "[
{ \"Session-Id\": \"" + $dlg_val(callid) + "\" },
{ \"Origin-Host\": \"client.diameter.test\" },
{ \"Origin-Realm\": \"diameter.test\" },
{ \"Destination-Realm\": \"diameter.test\" },
{ \"Service-Context-Id\": \"voice@OsipsDiamCCR\" },
{ \"CC-Request-Type\": 1 },
{ \"CC-Request-Number\": 0 },
{ \"Event-Timestamp\": \"" + $var(setuptime32bit) + "\" },
{ \"User-Name\": \"" + $dlg_val(account) + "\" },
{ \"Subscription-Id\": [
{ \"Subscription-Id-Type\": 0 },
{ \"Subscription-Id-Data\": \"" + $dlg_val(account) + "\" }
]},
{ \"Requested-Service-Unit\": [
{\"CC-Time\": 10800}
]},
{ \"Service-Information\": [
{\"IMS-Information\": [
{ \"Calling-Party-Address\": \"" + $dlg_val(account) + "\" },
{ \"Called-Party-Address\": \"" + $dlg_val(destination) + "\" }
]}
]}
]";
# send the diameter request
dm_send_request(4, 272, $var(payload), $var(rpl_avps));
# handle the diameter reply
$json(rpl) := $var(rpl_avps);
if ($rc != 1) {
xlog("L_NOTICE", "failed to send diameter request: rc=$rc\n");
send_reply(403, "Forbidden");
exit;
}
# check Result-Code coming from diameter server
# is there a way to index directly by the name of the key without knowing the index first?
if ($json(rpl[5]/Result-Code) != 2001) {
xlog("L_NOTICE", "failed to authorize session (Result-Code=$json(rpl[5]/Result-Code))\n");
send_reply(403, "Forbidden");
exit;
}
# set dialog timeout based on the received Granted-Service-Unit AVP
$DLG_timeout = $json(rpl[6]/Granted-Service-Unit[0]/CC-Time);
# dialog handlers
# only send async requests due to issue detailed at the bottom of the cfg file
dlg_on_answer("handle_answer");
dlg_on_hangup("handle_hangup");
dlg_on_timeout("handle_timeout");
}
if (!is_myself("$rd")) {
append_hf("P-hint: outbound\r\n");
route(relay);
}
# requests for my domain
if (is_method("PUBLISH|SUBSCRIBE")) {
send_reply(503, "Service Unavailable");
exit;
}
if (is_method("REGISTER")) {
# store the registration and generate a SIP reply
if (!save("location"))
xlog("failed to register AoR $tu\n");
exit;
}
if ($rU==NULL) {
# request with no Username in RURI
send_reply(484,"Address Incomplete");
exit;
}
# do lookup with method filtering
if (!lookup("location","method-filtering")) {
t_reply(404, "Not Found");
exit;
}
route(relay);
}
route[handle_answer] {
$dlg_val(answertime) = $Ts;
exec("/usr/share/cgrates/tutorials/osips_diam/etc/opensips/unix2ntp", "$dlg_val(answertime)", $dlg_val(answertime32bit), , );
$var(payload) = "[
{ \"Session-Id\": \"" + $dlg_val(callid) + "\" },
{ \"Origin-Host\": \"client.diameter.test\" },
{ \"Origin-Realm\": \"diameter.test\" },
{ \"Destination-Realm\": \"diameter.test\" },
{ \"Service-Context-Id\": \"voice@OsipsDiamCCR\" },
{ \"CC-Request-Type\": 2 },
{ \"CC-Request-Number\": 1 },
{ \"Event-Timestamp\": \"" + $dlg_val(answertime32bit) + "\" },
{ \"User-Name\": \"" + $dlg_val(account) + "\" },
{ \"Subscription-Id\": [
{ \"Subscription-Id-Type\": 0 },
{ \"Subscription-Id-Data\": \"" + $dlg_val(account) + "\" }
]},
{ \"Requested-Service-Unit\": [
{\"CC-Time\": 0}
]},
{ \"Service-Information\": [
{\"IMS-Information\": [
{ \"Calling-Party-Address\": \"" + $dlg_val(account) + "\" },
{ \"Called-Party-Address\": \"" + $dlg_val(destination) + "\" }
]}
]}
]";
async(dm_send_request(4, 272, $var(payload), $var(rpl_avps)), dm_reply);
}
route[handle_hangup] {
$var(duration1) = $Ts - $dlg_val(answertime);
$var(payload) = "[
{ \"Session-Id\": \"" + $dlg_val(callid) + "\" },
{ \"Origin-Host\": \"client.diameter.test\" },
{ \"Origin-Realm\": \"diameter.test\" },
{ \"Destination-Realm\": \"diameter.test\" },
{ \"Service-Context-Id\": \"voice@OsipsDiamCCR\" },
{ \"CC-Request-Type\": 3 },
{ \"CC-Request-Number\": 2 },
{ \"Termination-Cause\": 1 },
{ \"Event-Timestamp\": \"" + $dlg_val(answertime32bit) + "\" },
{ \"User-Name\": \"" + $dlg_val(account) + "\" },
{ \"Subscription-Id\": [
{ \"Subscription-Id-Type\": 0 },
{ \"Subscription-Id-Data\": \"" + $dlg_val(account) + "\" }
]},
{ \"Used-Service-Unit\": [
{\"CC-Time\": " + $var(duration1) + " }
]},
{ \"Service-Information\": [
{\"IMS-Information\": [
{ \"Calling-Party-Address\": \"" + $dlg_val(account) + "\" },
{ \"Called-Party-Address\": \"" + $dlg_val(destination) + "\" }
]}
]}
]";
async(dm_send_request(4, 272, $var(payload), $var(rpl_avps)), dm_reply);
}
# should be almost identical to handle_hangup. Sends Termination-Cause 6 (DIAMETER_AUTH_EXPIRED) instead of 1 (DIAMETER_LOGOUT)
route[handle_timeout] {
$var(duration2) = $Ts - $dlg_val(answertime);
$var(payload) = "[
{ \"Session-Id\": \"" + $dlg_val(callid) + "\" },
{ \"Origin-Host\": \"client.diameter.test\" },
{ \"Origin-Realm\": \"diameter.test\" },
{ \"Destination-Realm\": \"diameter.test\" },
{ \"Service-Context-Id\": \"voice@OsipsDiamCCR\" },
{ \"CC-Request-Type\": 3 },
{ \"CC-Request-Number\": 2 },
{ \"Termination-Cause\": 6 },
{ \"Event-Timestamp\": \"" + $dlg_val(answertime32bit) + "\" },
{ \"User-Name\": \"" + $dlg_val(account) + "\" },
{ \"Subscription-Id\": [
{ \"Subscription-Id-Type\": 0 },
{ \"Subscription-Id-Data\": \"" + $dlg_val(account) + "\" }
]},
{ \"Used-Service-Unit\": [
{\"CC-Time\": " + $var(duration2) + " }
]},
{ \"Service-Information\": [
{\"IMS-Information\": [
{ \"Calling-Party-Address\": \"" + $dlg_val(account) + "\" },
{ \"Called-Party-Address\": \"" + $dlg_val(destination) + "\" }
]}
]}
]";
async(dm_send_request(4, 272, $var(payload), $var(rpl_avps)), dm_reply);
}
# async dm reply handler
route[dm_reply] {
$json(rpl) := $var(rpl_avps);
if ($rc != 1 || $json(rpl[5]/Result-Code) != 2001) {
xlog("L_NOTICE", "rc=$rc\nResult-Code=$json(rpl[5]/Result-Code)\nCC-Request-Type=$json(rpl[3]/CC-Request-Type)\n");
exit;
}
}
route[relay] {
# for INVITEs enable some additional helper routes
if (is_method("INVITE")) {
t_on_branch("per_branch_ops");
t_on_reply("handle_nat");
t_on_failure("missed_call");
}
if (!t_relay()) {
send_reply(500,"Internal Error");
}
exit;
}
branch_route[per_branch_ops] {
xlog("new branch at $ru\n");
}
onreply_route[handle_nat] {
xlog("incoming reply\n");
}
failure_route[missed_call] {
if (t_was_cancelled()) {
exit;
}
# uncomment the following lines if you want to block client
# redirect based on 3xx replies.
##if (t_check_status("3[0-9][0-9]")) {
##t_reply(404,"Not found");
## exit;
##}
}
# Tried to add Time-Stamps as an extra field to keep track of SetupTime/AnswerTime and set Event-Timestamp to the time of the event itself. Then the route started to behave weirdly. It was sending only the authorize diameter request and then, when the call was supposed to hangup, it sent the authorize request again.
#
# { \"Time-Stamps\": [
# {\"SIP-Request-Timestamp\": " + $dlg_val(setuptime) + " },
# {\"SIP-Response-Timestamp\": \"" + $dlg_val(answertime32bit) + "\" }
# ]}
# Had to use async diameter requests, because otherwise it would not do anything on hangup/timeout. It would be stuck in an infinite loop with these (still has them, but it works because it's async):
#
# Apr 30 21:37:15 [26704] DBG:tm:timer_routine: timer routine:3,tl=0x7fd0bb345400 next=(nil), timeout=125
# Apr 30 21:37:15 [26704] DBG:tm:delete_handler: removing 0x7fd0bb345350
# Apr 30 21:37:15 [26704] DBG:tm:delete_cell: delete_cell 0x7fd0bb345350: can't delete -- still reffed (-1)
# Apr 30 21:37:15 [26704] DBG:tm:set_timer: relative timeout is 2
# Apr 30 21:37:15 [26704] DBG:tm:insert_timer_unsafe: [3]: 0x7fd0bb345400 (127)
# Apr 30 21:37:15 [26704] DBG:tm:delete_handler: done
# Apr 30 21:37:18 [26704] DBG:tm:timer_routine: timer routine:3,tl=0x7fd0bb345400 next=(nil), timeout=127
# Apr 30 21:37:18 [26704] DBG:tm:delete_handler: removing 0x7fd0bb345350
# Apr 30 21:37:18 [26704] DBG:tm:delete_cell: delete_cell 0x7fd0bb345350: can't delete -- still reffed (-1)
# Apr 30 21:37:18 [26704] DBG:tm:set_timer: relative timeout is 2
# Apr 30 21:37:18 [26704] DBG:tm:insert_timer_unsafe: [3]: 0x7fd0bb345400 (129)
# Apr 30 21:37:18 [26704] DBG:tm:delete_handler: done
# Apr 30 21:37:20 [26704] DBG:tm:timer_routine: timer routine:3,tl=0x7fd0bb345400 next=(nil), timeout=129
# Apr 30 21:37:20 [26704] DBG:tm:delete_handler: removing 0x7fd0bb345350
# Apr 30 21:37:20 [26704] DBG:tm:delete_cell: delete_cell 0x7fd0bb345350: can't delete -- still reffed (-1)
# Apr 30 21:37:20 [26704] DBG:tm:set_timer: relative timeout is 2
# Apr 30 21:37:20 [26704] DBG:tm:insert_timer_unsafe: [3]: 0x7fd0bb345400 (131)
# Apr 30 21:37:20 [26704] DBG:tm:delete_handler: done

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# To be used inside opensips.cfg to convert unix time
# to 32bit before sending it inside a diameter request
# payload as Event-Timestamp.
read unix_time
ntp_offset=2208988800
ntp_time=$((unix_time + ntp_offset))
printf "%08x" "$ntp_time" | xxd -r -p

View File

@@ -0,0 +1,2 @@
#Tenant,Account,ActionPlanId,ActionTriggersId,AllowNegative,Disabled
cgrates.org,1001,AP_PACKAGE_1001,,,
1 #Tenant Account ActionPlanId ActionTriggersId AllowNegative Disabled
2 cgrates.org 1001 AP_PACKAGE_1001

View File

@@ -0,0 +1,2 @@
#Id,ActionsId,TimingId,Weight
AP_PACKAGE_1001,ACT_TOPUP_RST_10,*asap,10
1 #Id ActionsId TimingId Weight
2 AP_PACKAGE_1001 ACT_TOPUP_RST_10 *asap 10

View File

@@ -0,0 +1,2 @@
#ActionsId[0],Action[1],ExtraParameters[2],Filter[3],BalanceId[4],BalanceType[5],Categories[6],DestinationIds[7],RatingSubject[8],SharedGroup[9],ExpiryTime[10],TimingIds[11],Units[12],BalanceWeight[13],BalanceBlocker[14],BalanceDisabled[15],Weight[16]
ACT_TOPUP_RST_10,*topup_reset,,,balance_test,*monetary,,*any,,,*unlimited,,10,10,false,false,10
1 #ActionsId[0] Action[1] ExtraParameters[2] Filter[3] BalanceId[4] BalanceType[5] Categories[6] DestinationIds[7] RatingSubject[8] SharedGroup[9] ExpiryTime[10] TimingIds[11] Units[12] BalanceWeight[13] BalanceBlocker[14] BalanceDisabled[15] Weight[16]
2 ACT_TOPUP_RST_10 *topup_reset balance_test *monetary *any *unlimited 10 10 false false 10

View File

@@ -0,0 +1,2 @@
#Tenant,ID,FilterIDs,ActivationInterval,RunID,AttributeIDs,Weight
cgrates.org,DEFAULT,,,*default,*none,0
1 #Tenant ID FilterIDs ActivationInterval RunID AttributeIDs Weight
2 cgrates.org DEFAULT *default *none 0

View File

@@ -0,0 +1,2 @@
#Id,DestinationId,RatesTag,RoundingMethod,RoundingDecimals,MaxCost,MaxCostStrategy
DR_1002,DST_1002,RT_20CNT,*up,4,0,
1 #Id DestinationId RatesTag RoundingMethod RoundingDecimals MaxCost MaxCostStrategy
2 DR_1002 DST_1002 RT_20CNT *up 4 0

View File

@@ -0,0 +1,2 @@
#Id,Prefix
DST_1002,1002
1 #Id Prefix
2 DST_1002 1002

View File

@@ -0,0 +1,3 @@
#Id,ConnectFee,Rate,RateUnit,RateIncrement,GroupIntervalStart
RT_20CNT,0.4,0.2,60s,60s,0s
RT_20CNT,0,0.1,60s,1s,60s
1 #Id ConnectFee Rate RateUnit RateIncrement GroupIntervalStart
2 RT_20CNT 0.4 0.2 60s 60s 0s
3 RT_20CNT 0 0.1 60s 1s 60s

View File

@@ -0,0 +1,2 @@
#Id,DestinationRatesId,TimingTag,Weight
RP_1001,DR_1002,*any,10
1 #Id DestinationRatesId TimingTag Weight
2 RP_1001 DR_1002 *any 10

View File

@@ -0,0 +1,2 @@
#Tenant,Category,Subject,ActivationTime,RatingPlanId,RatesFallbackSubject
cgrates.org,call,1001,2014-01-14T00:00:00Z,RP_1001,
1 #Tenant Category Subject ActivationTime RatingPlanId RatesFallbackSubject
2 cgrates.org call 1001 2014-01-14T00:00:00Z RP_1001