Compare commits

...
Author SHA1 Message Date
rhonda hollis a5ea0740a9 refactor
- remove Redis
- handle proxing of non-success response
2026-05-15 17:28:17 -07:00
rhonda hollis 79b2a99fe8 ensure application_sid & traceId are on CDR 2026-05-14 09:14:43 -07:00
Dave Horton cd48675499 curtail massive log msg (#242) 2026-04-23 07:35:27 -04:00
Hoan Luu Huu cecdbdccef update drachtio srf 5.0.21 (#241) 2026-04-13 21:24:28 -04:00
5 changed files with 58 additions and 13 deletions
+33
View File
@@ -19,6 +19,9 @@ const debug = require('debug')('jambonz:sbc-inbound');
const MS_TEAMS_USER_AGENT = 'Microsoft.PSTNHub.SIPProxy';
const MS_TEAMS_SIP_ENDPOINT = 'sip.pstnhub.microsoft.com';
const IMMUTABLE_HEADERS = ['via', 'from', 'to', 'call-id', 'cseq', 'max-forwards', 'content-length'];
const NONCOPYABLE_RESPONSE_HEADERS = [
'via', 'from', 'to', 'call-id', 'cseq', 'contact', 'content-length', 'content-type'
];
/**
* this is to make sure the outgoing From has the number in the incoming From
@@ -281,6 +284,7 @@ class CallSession extends Emitter {
proxy,
headers,
responseHeaders,
passFailure: false,
proxyRequestHeaders: [
'all',
'-Authorization',
@@ -354,6 +358,19 @@ class CallSession extends Emitter {
const tags = ['accepted:no', `sipStatus:${err.status}`, `originator:${this.req.locals.originator}`];
this.stats.increment('sbc.terminations', tags);
this.logger.info(`call failed to connect to feature server with ${err.status}`);
/* capture trace_id and application_sid from the feature server's error response for the CDR. */
if (this.req.locals.cdr && err.res) {
const trace_id = err.res.get('X-Trace-ID');
if (trace_id) {
this.req.locals.cdr.trace_id = trace_id;
}
const application_sid = err.res.get('X-Application-Sid');
if (application_sid) {
this.req.locals.cdr.application_sid = application_sid;
}
}
this.emit('failed');
}
else if (err.message !== 'call canceled') {
@@ -368,6 +385,22 @@ class CallSession extends Emitter {
.catch((err) => this.logger.error(err, 'Error decrementing call counts'));
}
/* manually proxy the failure response to UAS so that the trace_id/application_sid capture above runs before
res.end fires (which is what triggers the failure-CDR writer). */
if (err.message !== 'call canceled' && !this.res.finalResponseSent) {
if (err instanceof SipError && err.res) {
const headers = {};
Object.keys(err.res.headers || {}).forEach((h) => {
if (!NONCOPYABLE_RESPONSE_HEADERS.includes(h)) headers[h] = err.res.headers[h];
});
this.res.send(err.status, err.reason, {headers});
}
else {
this.res.send(err.status || 500, err.reason);
}
}
this.srf.endSession(this.req);
}
}
+14 -4
View File
@@ -394,8 +394,13 @@ module.exports = (srf, logger) => {
}
}
if (r.length > 1) {
logger.info({r},
'multiple carriers with the same gateway have the same number provisioned for the same account'
const all = r.map(({account_sid, voip_carrier_sid}) => ({account_sid, voip_carrier_sid}));
logger.info({
number: r[0].number,
total: all.length,
matches: all.slice(0, 5)
},
'multiple carriers with the same gateway have the same number provisioned for the same account'
+ ' -- cannot determine which one to use');
return {
fromCarrier: true,
@@ -601,8 +606,13 @@ module.exports = (srf, logger) => {
}
}
else if (r.length > 1) {
logger.info({r},
'multiple accounts have added this carrier with default routing -- cannot determine which to use');
const all = r.map(({account_sid, voip_carrier_sid}) => ({account_sid, voip_carrier_sid}));
logger.info({
number: r[0].number,
total: all.length,
matches: all.slice(0, 5)
},
'multiple accounts have added this carrier with default routing -- cannot determine which to use');
return {
fromCarrier: true,
error: 'Multiple accounts are attempting to route the same phone number from the same carrier'
+6 -4
View File
@@ -59,13 +59,15 @@ module.exports = function(srf, logger) {
/* write cdr for non-success response here */
res.once('end', ({status}) => {
if (req.locals.cdr && req.locals.cdr.account_sid && status > 200 && 401 !== status) {
const trunk = ['trunk', 'teams'].includes(req.locals.originator) ? req.locals.carrier : req.locals.originator;
if (req.locals.cdr && req.locals.cdr.account_sid && status > 200 && 401 !== status) {
const trunk = ['trunk', 'teams'].includes(req.locals.originator) ?
req.locals.carrier : req.locals.originator;
writeCdrs({...req.locals.cdr,
terminated_at: Date.now(),
termination_reason: status === 487 === status ? 'caller abandoned' : 'failed',
termination_reason: status === 487 ? 'caller abandoned' : 'failed',
sip_status: status,
trunk
trunk,
...(req.locals.application_sid && {application_sid: req.locals.application_sid})
}).catch((err) => logger.error({err}, 'Error writing cdr for call failure'));
}
});
+4 -4
View File
@@ -24,7 +24,7 @@
"cidr-matcher": "^2.1.1",
"debug": "^4.4.3",
"drachtio-fn-b2b-sugar": "0.2.1",
"drachtio-srf": "^5.0.20",
"drachtio-srf": "^5.0.21",
"express": "^4.21.2",
"pino": "^10.1.0",
"verify-aws-sns-signature": "^0.1.0",
@@ -3088,9 +3088,9 @@
"integrity": "sha512-bMtje8GWVTze+UG6WSGnlUfBaYCuFiApNXl/XxWc+X9uATZiZkV2jIqhf+Y4SY3nS8dZclJIVKd9qwoCa+i+Vw=="
},
"node_modules/drachtio-srf": {
"version": "5.0.20",
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-5.0.20.tgz",
"integrity": "sha512-gqWTfqFZhC93TVBaFtRseemmfHPASotMfHhCy/3wQUHZShUl+Zr7Vbq+pLD1kyTNr4/pzpMwEMLd0/6oq/fCtg==",
"version": "5.0.21",
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-5.0.21.tgz",
"integrity": "sha512-9hkQ7LURI1ceTMs49Nh2aosAd2v0565eD8Ccho5sSzXEHuq0DE3epjStlThq6LvIGVVAOXuSQGXFmlMWK92R3w==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.3",
+1 -1
View File
@@ -41,7 +41,7 @@
"cidr-matcher": "^2.1.1",
"debug": "^4.4.3",
"drachtio-fn-b2b-sugar": "0.2.1",
"drachtio-srf": "^5.0.20",
"drachtio-srf": "^5.0.21",
"express": "^4.21.2",
"pino": "^10.1.0",
"verify-aws-sns-signature": "^0.1.0",