Skip to content

Commit

Permalink
Feature/sip refer (#18)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
davehorton authored Nov 20, 2021
1 parent 8584020 commit f16598e
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 31 deletions.
13 changes: 12 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
39 changes: 35 additions & 4 deletions lib/call-session.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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);

Expand Down
23 changes: 22 additions & 1 deletion lib/db-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);

Expand Down Expand Up @@ -125,6 +145,7 @@ module.exports = (srf, logger) => {

return {
wasOriginatedFromCarrier,
getApplicationForDidAndCarrier
getApplicationForDidAndCarrier,
getOutboundGatewayForRefer
};
};
5 changes: 2 additions & 3 deletions lib/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 || {};
Expand Down Expand Up @@ -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:
Expand All @@ -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,
Expand Down
42 changes: 21 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down

0 comments on commit f16598e

Please sign in to comment.