mirror of
https://github.com/jambonz/sbc-inbound.git
synced 2026-07-04 19:11:47 +00:00
Feature/sip refer (#18)
* support for sip refer to transfer an incoming call * when sending REFER for call transfer, format Refer-To with carrier trunk if applicable * better handling of e164 on Refer-To header
This commit is contained in:
@@ -83,7 +83,18 @@ srf.locals = {...srf.locals,
|
||||
retrieveSet
|
||||
}
|
||||
};
|
||||
srf.locals.getFeatureServer = require('./lib/fs-tracking')(srf, logger);
|
||||
const {
|
||||
wasOriginatedFromCarrier,
|
||||
getApplicationForDidAndCarrier,
|
||||
getOutboundGatewayForRefer
|
||||
} = require('./lib/db-utils')(srf, logger);
|
||||
srf.locals = {
|
||||
...srf.locals,
|
||||
wasOriginatedFromCarrier,
|
||||
getApplicationForDidAndCarrier,
|
||||
getOutboundGatewayForRefer,
|
||||
getFeatureServer: require('./lib/fs-tracking')(srf, logger)
|
||||
};
|
||||
const activeCallIds = srf.locals.activeCallIds;
|
||||
|
||||
const {
|
||||
|
||||
+35
-4
@@ -1,7 +1,7 @@
|
||||
const Emitter = require('events');
|
||||
const {makeRtpEngineOpts, SdpWantsSrtp, makeCallCountKey} = require('./utils');
|
||||
const {forwardInDialogRequests} = require('drachtio-fn-b2b-sugar');
|
||||
const {parseUri, SipError} = require('drachtio-srf');
|
||||
const {parseUri, stringifyUri, SipError} = require('drachtio-srf');
|
||||
const debug = require('debug')('jambonz:sbc-inbound');
|
||||
const MS_TEAMS_USER_AGENT = 'Microsoft.PSTNHub.SIPProxy';
|
||||
const MS_TEAMS_SIP_ENDPOINT = 'sip.pstnhub.microsoft.com';
|
||||
@@ -469,11 +469,42 @@ Duration=${payload.duration} `
|
||||
try {
|
||||
const referTo = req.getParsedHeader('Refer-To');
|
||||
const uri = parseUri(referTo.uri);
|
||||
this.logger.info({uri, referTo}, 'received REFER from feature server');
|
||||
this.logger.info({uri, referTo, headers: req.headers}, 'received REFER from feature server');
|
||||
const arr = /context-(.*)/.exec(uri.user);
|
||||
if (!arr) {
|
||||
this.logger.info(`invalid Refer-To header: ${referTo.uri}`);
|
||||
return res.send(501);
|
||||
/* call transfer requested */
|
||||
const {gateway} = this.req.locals;
|
||||
const referredBy = req.getParsedHeader('Referred-By');
|
||||
if (!referredBy) return res.send(400);
|
||||
const u = parseUri(referredBy.uri);
|
||||
|
||||
let selectedGateway = false;
|
||||
let e164 = false;
|
||||
if (gateway) {
|
||||
/* host of Refer-to to an outbound gateway */
|
||||
const gw = await this.srf.locals.getOutboundGatewayForRefer(gateway.voip_carrier_sid);
|
||||
if (gw) {
|
||||
selectedGateway = true;
|
||||
e164 = gw.e164_leading_plus;
|
||||
uri.host = gw.ipv4;
|
||||
uri.port = gw.port;
|
||||
}
|
||||
}
|
||||
if (!selectedGateway) {
|
||||
uri.host = this.req.source_address;
|
||||
uri.port = this.req.source_port;
|
||||
}
|
||||
if (e164 && !uri.user.startsWith('+')) {
|
||||
uri.user = `+${uri.user}`;
|
||||
}
|
||||
const response = await this.uas.request({
|
||||
method: 'REFER',
|
||||
headers: {
|
||||
'Refer-To': stringifyUri(uri),
|
||||
'Referred-By': stringifyUri(u)
|
||||
}
|
||||
});
|
||||
return res.send(response.status);
|
||||
}
|
||||
res.send(202);
|
||||
|
||||
|
||||
+22
-1
@@ -35,6 +35,13 @@ SELECT * FROM phone_numbers
|
||||
WHERE number = ?
|
||||
AND voip_carrier_sid = ?`;
|
||||
|
||||
const sqlSelectOutboundGatewayForCarrier = `
|
||||
SELECT ipv4, port, e164_leading_plus
|
||||
FROM sip_gateways sg, voip_carriers vc
|
||||
WHERE sg.voip_carrier_sid = ?
|
||||
AND sg.voip_carrier_sid = vc.voip_carrier_sid
|
||||
AND outbound = 1`;
|
||||
|
||||
const gatewayMatchesSourceAddress = (source_address, gw) => {
|
||||
if (32 === gw.netmask && gw.ipv4 === source_address) return true;
|
||||
if (gw.netmask < 32) {
|
||||
@@ -48,6 +55,19 @@ module.exports = (srf, logger) => {
|
||||
const {pool} = srf.locals.dbHelpers;
|
||||
const pp = pool.promise();
|
||||
|
||||
const getOutboundGatewayForRefer = async(voip_carrier_sid) => {
|
||||
try {
|
||||
const [r] = await pp.query(sqlSelectOutboundGatewayForCarrier, [voip_carrier_sid]);
|
||||
if (0 === r.length) return null;
|
||||
|
||||
/* if multiple, prefer a DNS name */
|
||||
const hasDns = r.find((row) => row.ipv4.match(/^[A-Za-z]/));
|
||||
return hasDns || r[0];
|
||||
} catch (err) {
|
||||
logger.error({err}, 'getOutboundGatewayForRefer');
|
||||
}
|
||||
};
|
||||
|
||||
const getApplicationForDidAndCarrier = async(req, voip_carrier_sid) => {
|
||||
const did = normalizeDID(req.calledNumber);
|
||||
|
||||
@@ -125,6 +145,7 @@ module.exports = (srf, logger) => {
|
||||
|
||||
return {
|
||||
wasOriginatedFromCarrier,
|
||||
getApplicationForDidAndCarrier
|
||||
getApplicationForDidAndCarrier,
|
||||
getOutboundGatewayForRefer
|
||||
};
|
||||
};
|
||||
|
||||
+2
-3
@@ -68,8 +68,6 @@ module.exports = function(srf, logger) {
|
||||
blacklistUnknownRealms: true,
|
||||
emitter: new AuthOutcomeReporter(stats)
|
||||
});
|
||||
const {wasOriginatedFromCarrier, getApplicationForDidAndCarrier} = require('./db-utils')(srf, logger);
|
||||
|
||||
|
||||
const initLocals = (req, res, next) => {
|
||||
req.locals = req.locals || {};
|
||||
@@ -113,7 +111,7 @@ module.exports = function(srf, logger) {
|
||||
|
||||
const identifyAccount = async(req, res, next) => {
|
||||
try {
|
||||
|
||||
const {wasOriginatedFromCarrier, getApplicationForDidAndCarrier} = req.srf.locals;
|
||||
const {fromCarrier, gateway, account_sid, application_sid, account} = await wasOriginatedFromCarrier(req);
|
||||
/**
|
||||
* calls come from 3 sources:
|
||||
@@ -133,6 +131,7 @@ module.exports = function(srf, logger) {
|
||||
req.locals = {
|
||||
originator: 'trunk',
|
||||
carrier: gateway.name,
|
||||
gateway,
|
||||
application_sid: sid || gateway.application_sid,
|
||||
account_sid,
|
||||
account,
|
||||
|
||||
Generated
+21
-21
@@ -19,7 +19,7 @@
|
||||
"cidr-matcher": "^2.1.1",
|
||||
"debug": "^4.3.1",
|
||||
"drachtio-fn-b2b-sugar": "0.0.12",
|
||||
"drachtio-srf": "^4.4.55",
|
||||
"drachtio-srf": "^4.4.59",
|
||||
"express": "^4.17.1",
|
||||
"pino": "^6.8.0",
|
||||
"rtpengine-client": "^0.2.0",
|
||||
@@ -1409,9 +1409,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/drachtio-sip": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-sip/-/drachtio-sip-0.6.0.tgz",
|
||||
"integrity": "sha512-C8Y33rVpP0KwmZmBMxBjhbj58kktVFlzc+Od2g6TgOaqeEyF0JhwrHnech+iEtr2A2eKBlA85C9cCRh1+QpoRA==",
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-sip/-/drachtio-sip-0.6.2.tgz",
|
||||
"integrity": "sha512-BkiRZq3Yq2WVSGY3M7Hv4yX4dIW/o0/4xNMcm26IxT71YIRy07UtbQUHaMI3P2HfPu5zK6RoQW2MHrxPXtz6ZQ==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
@@ -1419,9 +1419,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/drachtio-sip/node_modules/eslint-plugin-promise": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz",
|
||||
"integrity": "sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.1.tgz",
|
||||
"integrity": "sha512-XgdcdyNzHfmlQyweOPTxmc7pIsS6dE4MvwhXWMQ2Dxs1XAL2GJDilUsjWen6TWik0aSI+zD/PqocZBblcm9rdA==",
|
||||
"engines": {
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
},
|
||||
@@ -1430,15 +1430,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/drachtio-srf": {
|
||||
"version": "4.4.55",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.4.55.tgz",
|
||||
"integrity": "sha512-wADXzcEdxD748iSK2KepD9LEiA+XW0nE2zNV89azKk0AafZGD0+DLMf1m8IOBnFE30H91pJI74Z8fO652+QB0A==",
|
||||
"version": "4.4.59",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.4.59.tgz",
|
||||
"integrity": "sha512-hrW9bZ8TZR9JQ3pqI+nyrI1eAzEOwHuvm1lNL1fbmZmRddKJzYdylkgVoyURs/OlT/nANy/M43GrQjcGP4psPw==",
|
||||
"dependencies": {
|
||||
"async": "^1.4.2",
|
||||
"debug": "^3.2.7",
|
||||
"delegates": "^0.1.0",
|
||||
"deprecate": "^1.1.1",
|
||||
"drachtio-sip": "^0.6.0",
|
||||
"drachtio-sip": "^0.6.2",
|
||||
"node-noop": "0.0.1",
|
||||
"only": "0.0.2",
|
||||
"sdp-transform": "^2.14.1",
|
||||
@@ -5850,9 +5850,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"drachtio-sip": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-sip/-/drachtio-sip-0.6.0.tgz",
|
||||
"integrity": "sha512-C8Y33rVpP0KwmZmBMxBjhbj58kktVFlzc+Od2g6TgOaqeEyF0JhwrHnech+iEtr2A2eKBlA85C9cCRh1+QpoRA==",
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-sip/-/drachtio-sip-0.6.2.tgz",
|
||||
"integrity": "sha512-BkiRZq3Yq2WVSGY3M7Hv4yX4dIW/o0/4xNMcm26IxT71YIRy07UtbQUHaMI3P2HfPu5zK6RoQW2MHrxPXtz6ZQ==",
|
||||
"requires": {
|
||||
"debug": "^4.3.1",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
@@ -5860,23 +5860,23 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-plugin-promise": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz",
|
||||
"integrity": "sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.1.tgz",
|
||||
"integrity": "sha512-XgdcdyNzHfmlQyweOPTxmc7pIsS6dE4MvwhXWMQ2Dxs1XAL2GJDilUsjWen6TWik0aSI+zD/PqocZBblcm9rdA==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"drachtio-srf": {
|
||||
"version": "4.4.55",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.4.55.tgz",
|
||||
"integrity": "sha512-wADXzcEdxD748iSK2KepD9LEiA+XW0nE2zNV89azKk0AafZGD0+DLMf1m8IOBnFE30H91pJI74Z8fO652+QB0A==",
|
||||
"version": "4.4.59",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.4.59.tgz",
|
||||
"integrity": "sha512-hrW9bZ8TZR9JQ3pqI+nyrI1eAzEOwHuvm1lNL1fbmZmRddKJzYdylkgVoyURs/OlT/nANy/M43GrQjcGP4psPw==",
|
||||
"requires": {
|
||||
"async": "^1.4.2",
|
||||
"debug": "^3.2.7",
|
||||
"delegates": "^0.1.0",
|
||||
"deprecate": "^1.1.1",
|
||||
"drachtio-sip": "^0.6.0",
|
||||
"drachtio-sip": "^0.6.2",
|
||||
"node-noop": "0.0.1",
|
||||
"only": "0.0.2",
|
||||
"sdp-transform": "^2.14.1",
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@
|
||||
"cidr-matcher": "^2.1.1",
|
||||
"debug": "^4.3.1",
|
||||
"drachtio-fn-b2b-sugar": "0.0.12",
|
||||
"drachtio-srf": "^4.4.55",
|
||||
"drachtio-srf": "^4.4.59",
|
||||
"pino": "^6.8.0",
|
||||
"rtpengine-client": "^0.2.0"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user