Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kamailio: Add support for Media Relay Sets and Application Server Sets #2844

Merged
merged 5 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 74 additions & 47 deletions kamailio/trunks/config/kamailio.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,14 @@ request_route {
route(TRANSFORMATE_IN);
}

# Set dlg_var(ddiId) for incoming bounced calls
if ($var(is_from_inside) == 2) {
$var(header) = 'X-Info-DdiId';
route(PARSE_MANDATORY_X_HEADER);
$dlg_var(ddiId) = $var(header-value);
remove_hf("X-Info-DdiId");
}

# Inspect new request
route(CLASSIFY);

Expand Down Expand Up @@ -552,12 +560,15 @@ request_route {
route[IS_FROM_INSIDE] {

# 4 possible sources:
# - is_from_as = ds_is_from_list("1");
# - is_from_as = lookup in ApplicationServers table
# - is_from_users = ($si == $var(usersAddress) && $sp == "5060");
# - is_from_trunks = (src_ip == myself && !is_from_users);
# - is_from_carriers = none of above

if (ds_is_from_list("1") || ($si == $var(usersAddress) && $sp == "5060")) {
$xavp(as) = $null;
sql_xquery("cb", "SELECT id FROM ApplicationServers WHERE ip='$si'", "as");

if ($xavp(as=>id) != $null || ($si == $var(usersAddress) && $sp == "5060")) {
$var(is_from_inside) = 1; # as / users
} else if (src_ip == myself) {
$var(is_from_inside) = 2; # trunks
Expand All @@ -578,16 +589,16 @@ route[CHECK_BOUNCE] {
#!endif

$xavp(ra) = $null;
sql_xquery("cb", "SELECT type FROM DDIs WHERE DDIE164='$rU'", "ra");
if ($xavp(ra=>type) != $null) {
sql_xquery("cb", "SELECT id, type FROM DDIs WHERE DDIE164='$rU'", "ra");
if ($xavp(ra=>id) != $null) {
if ($xavp(ra=>type) == 'out') {
xnotice("[$dlg_var(cidhash)] CHECK-BOUNCE: Call is to one of my outbound DDIs, do not bounce\n");
} else {
xnotice("[$dlg_var(cidhash)] CHECK-BOUNCE: Call is to one of my inbound DDIs, bounce call\n");
$dlg_var(bounced) = '1';
insert_hf("X-Info-DdiId: $xavp(ra=>id)\r\n");
}
}

}

route[REQINIT] {
Expand Down Expand Up @@ -1006,19 +1017,19 @@ route[SELECT_NEXT_GW] {
}

# Obtain info about selected GW
sql_xquery("cb", "SELECT C.mediaRelaySetsId, C.calculateCost, CS.sendPAI, CS.sendRPID, CS.authNeeded, CS.authUser, CS.authPassword, CS.carrierId, CS.fromUser, CS.fromDomain, PT.ip, CS.transport FROM CarrierServers CS JOIN Carriers C ON CS.carrierId=C.id LEFT JOIN ProxyTrunks PT ON PT.id=C.proxyTrunkId WHERE CS.id=$avp(carrierServerId)", "ra");
sql_xquery("cb", "SELECT C.mediaRelaySetId AS carrierMediaRelaySetId, C.calculateCost, CS.sendPAI, CS.sendRPID, CS.authNeeded, CS.authUser, CS.authPassword, CS.carrierId, CS.fromUser, CS.fromDomain, PT.ip, CS.transport FROM CarrierServers CS JOIN Carriers C ON CS.carrierId=C.id LEFT JOIN ProxyTrunks PT ON PT.id=C.proxyTrunkId WHERE CS.id=$avp(carrierServerId)", "ra");

if ( $(xavp(ra=>carrierId){s.len}) ) {
$dlg_var(carrierId) = $xavp(ra=>carrierId);
$dlg_var(carrierServerId) = $avp(carrierServerId);
$dlg_var(calculateCost) = $xavp(ra=>calculateCost);
xinfo("[$dlg_var(cidhash)] SELECT-NEXT-GW: carrierId: $dlg_var(carrierId)\n");
if ($xavp(ra=>mediaRelaySetsId) != $null) {
$dlg_var(mediaRelaySetsId) = $xavp(ra=>mediaRelaySetsId);
xinfo("[$dlg_var(cidhash)] SELECT-NEXT-GW: carrier#$dlg_var(carrierId) has non-NULL mediaRelaySetsId ($dlg_var(mediaRelaySetsId)), use it\n");
if ($xavp(ra=>carrierMediaRelaySetId) != $null) {
$dlg_var(mediaRelaySetId) = $xavp(ra=>carrierMediaRelaySetId);
xinfo("[$dlg_var(cidhash)] SELECT-NEXT-GW: carrier#$dlg_var(carrierId) has non-NULL mediaRelaySetId ($dlg_var(mediaRelaySetId)), use it\n");
} else {
$dlg_var(mediaRelaySetsId) = $dlg_var(companyMediaRelaySetsId);
xinfo("[$dlg_var(cidhash)] SELECT-NEXT-GW: carrier#$dlg_var(carrierId) has NULL mediaRelaySetsId, use company's set ($dlg_var(mediaRelaySetsId))\n");
$dlg_var(mediaRelaySetId) = $dlg_var(companyMediaRelaySetsId);
xinfo("[$dlg_var(cidhash)] SELECT-NEXT-GW: carrier#$dlg_var(carrierId) has NULL mediaRelaySetId, use company's set ($dlg_var(mediaRelaySetId))\n");
}
} else {
xerr("[$dlg_var(cidhash)] SELECT-NEXT-GW: Error obtaining 'carrierId' for carrierServerId '$avp(carrierServerId)'\n");
Expand Down Expand Up @@ -1210,7 +1221,6 @@ route[MATCH_DDI] {
$var(number) = $rU;

while ($var(i)<$dbr(ra=>rows)) {

$var(ddiProviderCandidate) = $dbr(ra=>[$var(i), 0]);
$dlg_var(brandId) = $dbr(ra=>[$var(i), 1]);
$var(transformation) = $dbr(ra=>[$var(i), 2]);
Expand Down Expand Up @@ -1260,7 +1270,7 @@ route[MATCH_DDI] {

# Sets tr_* and ddiProviderMediaRelaySetsId of final matched DDIProvider
route[GET_INFO_FROM_DDIPROVIDER] {
sql_query("cb", "SELECT CONCAT(transformationRuleSetId, 1) AS callee_in, CONCAT(transformationRuleSetId, 0) AS caller_in, CONCAT(transformationRuleSetId, 2) AS caller_out, CONCAT(transformationRuleSetId, 3) AS callee_out, mediaRelaySetsId FROM DDIProviders WHERE id='$dlg_var(ddiProviderId)'", "rc");
sql_query("cb", "SELECT CONCAT(transformationRuleSetId, 1) AS callee_in, CONCAT(transformationRuleSetId, 0) AS caller_in, CONCAT(transformationRuleSetId, 2) AS caller_out, CONCAT(transformationRuleSetId, 3) AS callee_out, mediaRelaySetId FROM DDIProviders WHERE id='$dlg_var(ddiProviderId)'", "rc");
$dlg_var(tr_callee_in) = $dbr(rc=>[0, 0]);
$dlg_var(tr_caller_in) = $dbr(rc=>[0, 1]);
$dlg_var(tr_caller_out) = $dbr(rc=>[0, 2]);
Expand Down Expand Up @@ -1477,7 +1487,7 @@ route[APPLY_TRANSFORMATION] {
route[GET_INFO_FROM_MATCHED_DDI] {
if ($dlg_var(type) == 'unassigned') return;

sql_xquery("cb", "SELECT c.mediaRelaySetsId, c.maxCalls AS maxCallsCompany, b.maxCalls AS maxCallsBrand, d.recordCalls, c.distributeMethod, AppS.ip AS asAddress, d.routeType, d.residentialDeviceId, d.retailAccountId, d.faxId FROM DDIs d JOIN Companies c ON d.companyId=c.id LEFT JOIN ApplicationServers AppS ON AppS.id=c.applicationServerId JOIN Brands b ON c.brandId=b.id WHERE d.DDIE164='$rU'", "ra");
sql_xquery("cb", "SELECT c.mediaRelaySetId AS companyMediaRelaySetId, c.maxCalls AS maxCallsCompany, b.maxCalls AS maxCallsBrand, d.recordCalls, c.distributeMethod, c.applicationServerSetId, d.routeType, d.residentialDeviceId, d.retailAccountId, d.faxId FROM DDIs d JOIN Companies c ON d.companyId=c.id JOIN Brands b ON c.brandId=b.id WHERE d.id='$dlg_var(ddiId)'", "ra");

# Matched DDI
$dlg_var(maxCallsCompany) = $xavp(ra=>maxCallsCompany);
Expand All @@ -1490,14 +1500,14 @@ route[GET_INFO_FROM_MATCHED_DDI] {

# Distribute method
$dlg_var(distributeMethod) = $xavp(ra=>distributeMethod);
$avp(asAddress) = $xavp(ra=>asAddress);
$dlg_var(applicationServerSetId) = $xavp(ra=>applicationServerSetId);

if ($dlg_var(ddiProviderMediaRelaySetsId) != $null) {
$dlg_var(mediaRelaySetsId) = $dlg_var(ddiProviderMediaRelaySetsId);
xinfo("[$dlg_var(cidhash)] GET-INFO-FROM-MATCHED-DDI: ddiProvider#$dlg_var(ddiProviderId) has non-NULL mediaRelaySetsId ($dlg_var(mediaRelaySetsId)), use it\n");
$dlg_var(mediaRelaySetId) = $dlg_var(ddiProviderMediaRelaySetsId);
xinfo("[$dlg_var(cidhash)] GET-INFO-FROM-MATCHED-DDI: ddiProvider#$dlg_var(ddiProviderId) has non-NULL mediaRelaySetId ($dlg_var(mediaRelaySetId)), use it\n");
} else {
$dlg_var(mediaRelaySetsId) = $xavp(ra=>mediaRelaySetsId);
xinfo("[$dlg_var(cidhash)] GET-INFO-FROM-MATCHED-DDI: ddiProvider#$dlg_var(ddiProviderId) has NULL mediaRelaySetsId, use company's set ($dlg_var(mediaRelaySetsId))\n");
$dlg_var(mediaRelaySetId) = $xavp(ra=>companyMediaRelaySetId);
xinfo("[$dlg_var(cidhash)] GET-INFO-FROM-MATCHED-DDI: ddiProvider#$dlg_var(ddiProviderId) has NULL mediaRelaySetId, use company's set ($dlg_var(mediaRelaySetId))\n");
}

# Save endpointId for CDR accounting
Expand All @@ -1523,11 +1533,11 @@ route[GET_INFO_FROM_MATCHED_DDI] {
}

route[GET_INFO_FROM_COMPANY] {
sql_xquery("cb", "SELECT D.domain, C.billingMethod, C.mediaRelaySetsId, C.maxCalls AS maxCallsCompany, B.maxCalls AS maxCallsBrand FROM Companies C LEFT JOIN Domains D ON C.domainId=D.id JOIN Brands B ON C.brandId=B.id WHERE C.id='$dlg_var(companyId)'", "ra");
sql_xquery("cb", "SELECT D.domain, C.billingMethod, C.mediaRelaySetId, C.maxCalls AS maxCallsCompany, B.maxCalls AS maxCallsBrand FROM Companies C LEFT JOIN Domains D ON C.domainId=D.id JOIN Brands B ON C.brandId=B.id WHERE C.id='$dlg_var(companyId)'", "ra");

$dlg_var(cgrReqType) = '*' + $xavp(ra=>billingMethod);
$dlg_var(companyDomain) = $xavp(ra=>domain);
$dlg_var(companyMediaRelaySetsId) = $xavp(ra=>mediaRelaySetsId);
$dlg_var(companyMediaRelaySetsId) = $xavp(ra=>mediaRelaySetId);
$dlg_var(maxCallsCompany) = $xavp(ra=>maxCallsCompany);
$dlg_var(maxCallsBrand) = $xavp(ra=>maxCallsBrand);

Expand Down Expand Up @@ -1597,27 +1607,29 @@ route[DISPATCH] {
return;
}

# Static routing to specific AS?
if ($dlg_var(distributeMethod) == 'static') {
$du = "sip:" + $avp(asAddress) + ":6060";
xinfo("[$dlg_var(cidhash)] DISPATCH: Company has static routing enabled\n");
# Dispatch using as-set and strategy
if ($dlg_var(distributeMethod) == 'rr') {
# round robin dispatching on ASs
$var(alg) = 4;
} else {
if ($dlg_var(distributeMethod) == 'hash') {
$avp(hash) = $dlg_var(companyId);
# hash over $avp(hash)
xinfo("[$dlg_var(cidhash)] DISPATCH: Dispatch hashing '$avp(hash)'\n");
$var(alg) = 7;
} else {
# round robin dispatching on ASs (distributeMethod == 'rr')
xinfo("[$dlg_var(cidhash)] DISPATCH: dispatch to any AS (round robin)\n");
$var(alg) = 4;
}
# hash dispatching on ASs (distributedMethod == 'hash')
$avp(hash) = $dlg_var(companyId);
# hash over $avp(hash)
$var(alg) = 7;
}

if(!ds_select_dst("1", "$var(alg)")) {
xerr("[$dlg_var(cidhash)] DISPATCH: No destination found\n");
send_reply("404", "No destination");
exit;
}
# Use default AS-set if none set
if ($dlg_var(applicationServerSetId) == $null) {
xwarn("[$dlg_var(cidhash)] DISPATCH: Use default AS set as none set, this shouldn't happen\n");
$dlg_var(applicationServerSetId) = '0';
} else {
xinfo("[$dlg_var(cidhash)] DISPATCH: Use AS set '$dlg_var(applicationServerSetId)' with $dlg_var(distributeMethod) dispatching algorithm\n");
}

if(!ds_select_dst("$dlg_var(applicationServerSetId)", "$var(alg)")) {
xerr("[$dlg_var(cidhash)] DISPATCH: No destination found\n");
send_reply("404", "No destination");
exit;
}

t_on_failure("MANAGE_FAILURE_AS");
Expand All @@ -1636,7 +1648,7 @@ route[SETUP_KAMUSERS_CALL] {

# Check DDI is routed to a retail account
$xavp(ra) = $null;
sql_xquery("cb", "SELECT RA.name AS username, DS.domain AS domain FROM DDIs D INNER JOIN RetailAccounts RA ON D.retailAccountId=RA.id INNER JOIN Domains DS ON RA.domainId=DS.id WHERE DDIE164='$rU'", "ra");
sql_xquery("cb", "SELECT RA.name AS username, DS.domain AS domain FROM DDIs D INNER JOIN RetailAccounts RA ON D.retailAccountId=RA.id INNER JOIN Domains DS ON RA.domainId=DS.id WHERE D.id='$dlg_var(ddiId)'", "ra");
if ($xavp(ra) == $null) {
xwarn("[$dlg_var(cidhash)] SETUP-KAMUSERS-CALL: $rU retail DDI not assigned to any retail account, reject\n");
send_reply("404", "No destination [SKC]");
Expand Down Expand Up @@ -1745,15 +1757,28 @@ route[CLASSIFY] {
set_dlg_profile("outboundCallsCompany", "$dlg_var(companyId)");
set_dlg_profile("outboundCallsBrand", "$dlg_var(brandId)");
} else {
sql_xquery("cb", "SELECT B.id AS brandId, C.id AS companyId, C.type FROM DDIs D JOIN Brands B ON B.id=D.brandId LEFT JOIN Companies C ON D.companyId=C.id WHERE DDIE164='$rU'", "rp");
if ($dlg_var(ddiId) == $null) {
xerr("[$dlg_var(cidhash)] CLASSIFY: dlg_var(ddiId) is null, this shouldn't happen\n");
send_reply("500", "Internal Server Error");
exit;
}

sql_xquery("cb", "SELECT B.id AS brandId, C.id AS companyId, C.type FROM DDIs D JOIN Brands B ON B.id=D.brandId LEFT JOIN Companies C ON D.companyId=C.id WHERE D.id='$dlg_var(ddiId)'", "rp");
$dlg_var(brandId) = $xavp(rp=>brandId);
$dlg_var(companyId) = $xavp(rp=>companyId);

if ($dlg_var(brandId) != $null && $dlg_var(companyId) == $null) {
if ($dlg_var(brandId) == $null) {
xwarn("[$dlg_var(cidhash)] CLASSIFY: DDI with id '$dlg_var(ddiId)' not found, this is weird\n");
send_reply("500", "Internal Server Error");
exit;
}

if ($dlg_var(companyId) == $null) {
xnotice("[$dlg_var(cidhash)] CLASSIFY: inbound call to unassigned DDI $rU (b$dlg_var(brandId))");
$dlg_var(skipRealtime) = 'yes'; # Skip this call in realtime
$dlg_var(type) = 'unassigned';
$rU = 'noclient';
$dlg_var(applicationServerSetId) = '0';
return;
}

Expand Down Expand Up @@ -2108,7 +2133,7 @@ failure_route[MANAGE_FAILURE_AS] {
xerr("[$dlg_var(cidhash)] MANAGE-FAILURE-AS: Mark AS '$xavp(_dsdst_=>uri)' as inactive\n");
ds_mark_dst("ip");

if($dlg_var(distributeMethod) != 'static' && ds_next_dst()) {
if(ds_next_dst()) {
xinfo("[$dlg_var(cidhash)] MANAGE-FAILURE-AS: going to <$ru> via <$du>\n");

# Reset force_socket again
Expand Down Expand Up @@ -2277,9 +2302,11 @@ route[RTPENGINE] {
if (!is_request() && !is_method("INVITE|UPDATE")) return;
if (!is_request() && is_method("INVITE|UPDATE") && t_check_status("[12][0-9]{2}") && !has_body("application/sdp")) return;

if ($(dlg_var(mediaRelaySetsId){s.len}) > 0 && $dlg_var(mediaRelaySetsId) != 0) {
xinfo("[$dlg_var(cidhash)] RTPENGINE: mediaRelaySetsId: $dlg_var(mediaRelaySetsId)\n");
set_rtpengine_set("$(dlg_var(mediaRelaySetsId){s.int})");
if ($(dlg_var(mediaRelaySetId){s.len}) > 0 && $dlg_var(mediaRelaySetId) != 0) {
xinfo("[$dlg_var(cidhash)] RTPENGINE: call set_rtpengine_set() with $dlg_var(mediaRelaySetId)\n");
set_rtpengine_set("$(dlg_var(mediaRelaySetId){s.int})");
} else {
xinfo("[$dlg_var(cidhash)] RTPENGINE: do not call set_rtpengine_set() as mediaRelaySetId is '$dlg_var(mediaRelaySetId)'\n");
}

$var(rtpengine_opts) = 'replace-session-connection replace-origin ICE=remove RTP/AVP asymmetric trust-address';
Expand Down
Loading