Compare commits

..
7 Commits
Author SHA1 Message Date
Quan HL 14552c0ef0 feat: outbound protocol 2023-05-10 09:41:52 +07:00
Quan HL d5895c24fe fix typo 2023-05-08 20:01:53 +07:00
Quan HL a1fdf56e73 fix typo 2023-05-08 20:00:22 +07:00
Quan HL 93d6a30160 fix typo 2023-05-08 19:59:41 +07:00
Quan HL 20ac00973a fix: add lookupCarrierByAccountLcr to locals 2023-05-05 09:25:53 +07:00
Quan HL 22312c50a4 fix: await for async 2023-04-25 18:27:57 +07:00
Quan HL 4020f84847 feat: lcr added 2023-04-25 15:57:45 +07:00
12 changed files with 242 additions and 407 deletions
+1 -3
View File
@@ -2,8 +2,6 @@ name: Docker
on:
push:
branches:
- main
tags:
- '*'
@@ -20,7 +18,7 @@ jobs:
- name: prepare tag
id: prepare_tag
run: |
IMAGE_ID=jambonz/sbc-outbound
IMAGE_ID=$GITHUB_REPOSITORY
# Strip git ref prefix from version
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
+9 -32
View File
@@ -3,38 +3,12 @@ assert.ok(process.env.JAMBONES_MYSQL_HOST &&
process.env.JAMBONES_MYSQL_USER &&
process.env.JAMBONES_MYSQL_PASSWORD &&
process.env.JAMBONES_MYSQL_DATABASE, 'missing JAMBONES_MYSQL_XXX env vars');
if (process.env.JAMBONES_REDIS_SENTINELS) {
assert.ok(process.env.JAMBONES_REDIS_SENTINEL_MASTER_NAME,
'missing JAMBONES_REDIS_SENTINEL_MASTER_NAME env var, JAMBONES_REDIS_SENTINEL_PASSWORD env var is optional');
} else {
assert.ok(process.env.JAMBONES_REDIS_HOST, 'missing JAMBONES_REDIS_HOST env var');
}
assert.ok(process.env.JAMBONES_REDIS_HOST, 'missing JAMBONES_REDIS_HOST env var');
assert.ok(process.env.DRACHTIO_PORT || process.env.DRACHTIO_HOST, 'missing DRACHTIO_PORT env var');
assert.ok(process.env.DRACHTIO_SECRET, 'missing DRACHTIO_SECRET env var');
assert.ok(process.env.JAMBONES_NETWORK_CIDR || process.env.K8S, 'missing JAMBONES_NETWORK_CIDR env var');
assert.ok(process.env.JAMBONES_TIME_SERIES_HOST, 'missing JAMBONES_TIME_SERIES_HOST env var');
const JAMBONES_REDIS_SENTINELS = process.env.JAMBONES_REDIS_SENTINELS ? {
sentinels: process.env.JAMBONES_REDIS_SENTINELS.split(',').map((sentinel) => {
let host, port = 26379;
if (sentinel.includes(':')) {
const arr = sentinel.split(':');
host = arr[0];
port = parseInt(arr[1], 10);
} else {
host = sentinel;
}
return {host, port};
}),
name: process.env.JAMBONES_REDIS_SENTINEL_MASTER_NAME,
...(process.env.JAMBONES_REDIS_SENTINEL_PASSWORD && {
password: process.env.JAMBONES_REDIS_SENTINEL_PASSWORD
}),
...(process.env.JAMBONES_REDIS_SENTINEL_USERNAME && {
username: process.env.JAMBONES_REDIS_SENTINEL_USERNAME
})
} : null;
const Srf = require('drachtio-srf');
const srf = new Srf('sbc-outbound');
const CIDRMatcher = require('cidr-matcher');
@@ -63,7 +37,7 @@ const setNameRtp = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-rtp
const rtpServers = [];
const {
ping,
lookupOutboundCarrierForAccount,
performLcr,
lookupAllTeamsFQDNs,
lookupAccountBySipRealm,
lookupAccountBySid,
@@ -87,8 +61,8 @@ const {
incrKey,
decrKey,
retrieveSet,
isMemberOfSet,
} = require('@jambonz/realtimedb-helpers')(JAMBONES_REDIS_SENTINELS || {
isMemberOfSet
} = require('@jambonz/realtimedb-helpers')({
host: process.env.JAMBONES_REDIS_HOST,
port: process.env.JAMBONES_REDIS_PORT || 6379
}, logger);
@@ -110,7 +84,7 @@ srf.locals = {...srf.locals,
idleEmitter,
dbHelpers: {
ping,
lookupOutboundCarrierForAccount,
performLcr,
lookupAllTeamsFQDNs,
lookupAccountBySipRealm,
lookupAccountBySid,
@@ -128,7 +102,10 @@ srf.locals = {...srf.locals,
isMemberOfSet
}
};
const {initLocals, checkLimits, route} = require('./lib/middleware')(srf, logger, redisClient);
const {initLocals, checkLimits, route} = require('./lib/middleware')(srf, logger, {
host: process.env.JAMBONES_REDIS_HOST,
port: process.env.JAMBONES_REDIS_PORT || 6379
});
const ngProtocol = process.env.JAMBONES_NG_PROTOCOL || 'udp';
const ngPort = process.env.RTPENGINE_PORT || ('udp' === ngProtocol ? 22222 : 8080);
const {getRtpEngine, setRtpEngines} = require('@jambonz/rtpengine-utils')([], logger, {
+78 -119
View File
@@ -33,21 +33,19 @@ const createBLegToHeader = (req, teams) => {
return `sip:anonymous@${host}`;
};
const initCdr = (req, invite) => {
const {srf} = req;
const {trace_id} = req.locals;
const uri = parseUri(invite.uri);
const initCdr = (srf, req) => {
const uri = parseUri(req.uri);
const regex = /^\+(\d+)$/;
let arr = regex.exec(invite.calledNumber);
const to = arr ? arr[1] : invite.calledNumber;
arr = regex.exec(invite.callingNumber);
const from = arr ? arr[1] : invite.callingNumber;
let arr = regex.exec(req.calledNumber);
const to = arr ? arr[1] : req.calledNumber;
arr = regex.exec(req.callingNumber);
const from = arr ? arr[1] : req.callingNumber;
const applicationSid = req.get('X-Application-Sid');
return {
account_sid: req.get('X-Account-Sid'),
call_sid: req.get('X-Call-Sid'),
sip_callid: invite.get('Call-ID'),
sip_callid: req.get('Call-ID'),
...(applicationSid && {application_sid: applicationSid}),
from,
to,
@@ -57,7 +55,7 @@ const initCdr = (req, invite) => {
direction: 'outbound',
host: srf.locals.sipAddress,
remote_host: uri.host,
trace_id: trace_id || '00000000000000000000000000000000'
trace_id: req.get('X-Trace-ID') || '00000000000000000000000000000000'
};
};
@@ -85,13 +83,12 @@ class CallSession extends Emitter {
this.decrKey = req.srf.locals.realtimeDbHelpers.decrKey;
const {
lookupOutboundCarrierForAccount,
const {performLcr,
lookupCarrierBySid,
lookupSipGatewaysByCarrier,
lookupCarrierByAccountLcr
} = this.srf.locals.dbHelpers;
this.lookupOutboundCarrierForAccount = lookupOutboundCarrierForAccount;
this.performLcr = performLcr;
this.lookupCarrierBySid = lookupCarrierBySid;
this.lookupSipGatewaysByCarrier = lookupSipGatewaysByCarrier;
this.lookupCarrierByAccountLcr = lookupCarrierByAccountLcr;
@@ -171,7 +168,6 @@ class CallSession extends Emitter {
this.subscribeRequest = subscribeRequest;
this.subscribeAnswer = subscribeAnswer;
this.unsubscribe = unsubscribe;
this.srsClients = [];
this.rtpEngineOpts = makeRtpEngineOpts(this.req, false, this.useWss || teams, teams);
this.rtpEngineResource = {destroy: this.del.bind(null, this.rtpEngineOpts.common)};
@@ -226,77 +222,60 @@ class CallSession extends Emitter {
let voip_carrier_sid = this.req.get('X-Requested-Carrier-Sid');
const account_sid = this.req.get('X-Account-Sid');
if (!voip_carrier_sid && account_sid) {
/* search for an LCR table for this account or service provider */
debug('calling lcr');
voip_carrier_sid = await this.lookupCarrierByAccountLcr(account_sid, this.req.calledNumber);
}
if (!voip_carrier_sid) {
/* no LCR for this account/SP - try with inbound carrier */
const inbound_carrier_sid = this.req.get('X-Voip-Carrier-Sid');
if (inbound_carrier_sid) {
const gateways = await this.lookupSipGatewaysByCarrier(inbound_carrier_sid);
const gws = (gateways || [])
.filter((gw) => gw.outbound);
if (gws.length) {
voip_carrier_sid = inbound_carrier_sid;
}
if (voip_carrier_sid) {
const vc = await this.lookupCarrierBySid(voip_carrier_sid);
const gateways = await this.lookupSipGatewaysByCarrier(voip_carrier_sid);
const gws = (gateways || [])
.filter((gw) => gw.outbound);
if (gws.length) {
uris = [];
gws.forEach((o) => {
const prefix = vc.tech_prefix;
const hostport = !o.port || 5060 === o.port ? o.ipv4 : `${o.ipv4}:${o.port}`;
const prependPlus = vc.e164_leading_plus && !this.req.calledNumber.startsWith('0');
const transport = o.protocol || 'udp';
const u = `sip:${prefix ? prefix : ''}${prependPlus ? '+' : ''}${this.req.calledNumber}@${hostport};transport=${transport}`;
const obj = {
name: vc.name,
diversion: vc.diversion,
hostport
};
if (vc.register_username && vc.register_password) {
obj.auth = {
username: vc.register_username,
password: vc.register_password
};
}
mapGateways.set(u, obj);
uris.push(u);
});
this.logger.debug({uris, voip_carrier_sid}, 'selected outbound gateways for requested carrier');
}
else {
this.logger.info({voip_carrier_sid}, 'no outbound gateways found for requested carrier');
}
}
if (!voip_carrier_sid) {
/* no LCR/ inbound carrier for this account/SP - at this point its a random shuffle of outbound carriers */
voip_carrier_sid = await this.lookupOutboundCarrierForAccount(this.account_sid);
}
if (!voip_carrier_sid) {
/* no outbound carriers exist for this account/SP */
this.logger.info(`no outbound carriers found for account_sid ${account_sid}`);
this.res.send(603);
return this.srf.endSession(this.req);
}
const vc = await this.lookupCarrierBySid(voip_carrier_sid);
const gateways = await this.lookupSipGatewaysByCarrier(voip_carrier_sid);
const gws = (gateways || [])
.filter((gw) => gw.outbound);
if (gws.length) {
uris = [];
gws.forEach((o) => {
const calledNumber = this.req.calledNumber.startsWith('+') ?
this.req.calledNumber.slice(1) :
this.req.calledNumber;
const prefix = vc.tech_prefix || '';
const protocol = o.protocol?.startsWith('tls') ? 'tls' : (o.protocol || 'udp');
const hostport = !o.port || 5060 === o.port ? o.ipv4 : `${o.ipv4}:${o.port}`;
const prependPlus = vc.e164_leading_plus && !this.req.calledNumber.startsWith('0') ? '+' : '';
const transport = `transport=${protocol}`;
const scheme = protocol === 'tls' ? 'sips' : 'sip';
const u = `${scheme}:${prefix}${prependPlus}${calledNumber}@${hostport};${transport}`;
const obj = {
name: vc.name,
diversion: vc.diversion,
hostport,
protocol: o.protocol
};
if (vc.register_username && vc.register_password) {
obj.auth = {
username: vc.register_username,
password: vc.register_password
};
}
mapGateways.set(u, obj);
uris.push(u);
if (o.protocol === 'tls/srtp') {
/** TODO: this is a bit of a hack in the sense that we are not
* supporting a scenario where you have a carrier with several outbound
* gateways, some requiring encrypted media and some not. This should be rectified
* but it will require more significant changes and right now it seems
* like a rare use case -- encryption is usually an all or nothing requirement.
*/
this.logger.info({u}, 'using SRTP for outbound call');
this.rtpEngineOpts = makeRtpEngineOpts(this.req, false, true, true);
}
});
this.logger.debug({uris, voip_carrier_sid}, 'selected outbound gateways for requested carrier');
}
else {
this.logger.info({voip_carrier_sid}, 'no outbound gateways found for requested carrier');
if (mapGateways.size === 0) {
/**
* We normalize the called number by removing a leading + before sending it to LCR..
* but LCR will return us an array of sip uris, with leading + for carriers that require it
*/
const routableNumber = this.req.calledNumber.startsWith('+') ?
this.req.calledNumber.slice(1) :
this.req.calledNumber;
const gateways = await this.performLcr(routableNumber, this.account_sid);
if (!gateways || gateways.length === 0) throw new Error('no routes found');
debug(`got gateways: ${JSON.stringify(gateways)}`);
gateways.forEach((gw) => mapGateways.set(gw.uri, {
name: gw.name,
auth: gw.auth,
diversion: gw.diversion,
hostport: gw.hostport
}));
uris = gateways.map((gw) => gw.uri);
}
} catch (err) {
debug(err);
@@ -383,7 +362,6 @@ class CallSession extends Emitter {
'-X-Preferred-From-User',
'X-Preferred-From-Host',
'-X-Jambonz-FS-UUID',
'-X-Voip-Carrier-Sid',
],
proxyResponseHeaders: [
'all',
@@ -427,7 +405,7 @@ class CallSession extends Emitter {
}
else {
this.req.locals.cdr = {
...initCdr(this.req, inv),
...initCdr(this.req.srf, inv),
service_provider_sid: this.req.locals.service_provider_sid,
account_sid: this.req.locals.account_sid,
...(this.req.locals.application_sid && {application_sid: this.req.locals.application_sid}),
@@ -543,18 +521,12 @@ class CallSession extends Emitter {
/* write cdr for connected call */
if (this.req.locals.cdr) {
const now = Date.now();
const day = new Date();
const recordAllCalls = this.req.locals.record_all_calls;
let recording_url = `/Accounts/${this.account_sid}/RecentCalls/${this.req.locals.cdr.call_sid}/record`;
recording_url += `/${day.getFullYear()}/${(day.getMonth() + 1).toString().padStart(2, '0')}`;
recording_url += `/${day.getDate().toString().padStart(2, '0')}/${recordAllCalls}`;
this.writeCdrs({...this.req.locals.cdr,
terminated_at: now,
termination_reason: dlg.type === 'uas' ? 'caller hungup' : 'called party hungup',
sip_status: 200,
answered: true,
duration: Math.floor((now - callStart) / 1000),
...(recordAllCalls && {recording_url})
duration: Math.floor((now - callStart) / 1000)
}).catch((err) => this.logger.error({err}, 'Error writing cdr for completed call'));
}
/* de-link the 2 Dialogs for GC */
@@ -563,7 +535,10 @@ class CallSession extends Emitter {
dlg.other = null;
other.other = null;
this._stopRecording();
if (this.srsClient) {
this.srsClient.stop();
this.srsClient = null;
}
this.logger.info(`call ended with normal termination, there are ${this.activeCallIds.size} active`);
if (this.activeCallIds.size === 0) this.idleEmitter.emit('idle');
@@ -588,13 +563,6 @@ class CallSession extends Emitter {
forwardInDialogRequests(uac, ['notify', 'options', 'message']);
}
_stopRecording() {
if (this.srsClients.length) {
this.srsClients.forEach((c) => c.stop());
this.srsClients = [];
}
}
async _onRefer(dlg, req, res) {
/* REFER coming in from a sip device, forward to feature server */
try {
@@ -740,7 +708,7 @@ Duration=${payload.duration} `
const callSid = req.get('X-Call-Sid');
const accountSid = req.get('X-Account-Sid');
const applicationSid = req.get('X-Application-Sid');
if (this.srsClients.length) {
if (this.srsClient) {
res.send(400);
this.logger.info('discarding duplicate startCallRecording request for a call');
return;
@@ -750,14 +718,13 @@ Duration=${payload.duration} `
res.send(400);
return;
}
const arr = srsUrl.split(',');
this.srsClients = arr.map((url) => new SrsClient(this.logger, {
this.srsClient = new SrsClient(this.logger, {
srf: dlg.srf,
direction: 'outbound',
originalInvite: this.req,
callingNumber: this.req.callingNumber,
calledNumber: this.req.calledNumber,
srsUrl: url,
srsUrl,
srsRecordingId,
callSid,
accountSid,
@@ -772,49 +739,41 @@ Duration=${payload.duration} `
blockMedia: this.blockMedia,
unblockMedia: this.unblockMedia,
unsubscribe: this.unsubscribe
}));
});
try {
succeeded = (await Promise.all(
this.srsClients.map((c) => c.start())
)).every((r) => r);
succeeded = await this.srsClient.start();
} catch (err) {
this.logger.error({err}, 'Error starting SipRec call recording');
}
}
else if (reason === 'stopCallRecording') {
if (!this.srsClients.length) {
if (!this.srsClient) {
res.send(400);
this.logger.info('discarding stopCallRecording request because we are not recording');
return;
}
try {
succeeded = (await Promise.all(
this.srsClients.map((c) => c.stop())
)).every((r) => r);
succeeded = await this.srsClient.stop();
} catch (err) {
this.logger.error({err}, 'Error stopping SipRec call recording');
}
this.srsClients = [];
this.srsClient = null;
}
else if (reason === 'pauseCallRecording') {
if (!this.srsClients.length || this.srsClients.every((c) => c.paused)) {
if (!this.srsClient || this.srsClient.paused) {
this.logger.info('discarding invalid pauseCallRecording request');
res.send(400);
return;
}
succeeded = (await Promise.all(
this.srsClients.map((c) => c.pause())
)).every((r) => r);
succeeded = await this.srsClient.pause();
}
else if (reason === 'resumeCallRecording') {
if (!this.srsClients.length || !this.srsClients.every((c) => c.paused)) {
if (!this.srsClient || !this.srsClient.paused) {
res.send(400);
this.logger.info('discarding invalid resumeCallRecording request');
return;
}
succeeded = (await Promise.all(
this.srsClients.map((c) => c.resume())
)).every((r) => r);
succeeded = await this.srsClient.resume();
}
res.send(succeeded ? 200 : 503);
}
+2 -3
View File
@@ -4,10 +4,10 @@ const Registrar = require('@jambonz/mw-registrar');
const {selectHostPort, nudgeCallCounts} = require('./utils');
const FS_UUID_SET_NAME = 'fsUUIDs';
module.exports = (srf, logger, redisClient) => {
module.exports = (srf, logger, opts) => {
const {incrKey, decrKey, isMemberOfSet} = srf.locals.realtimeDbHelpers;
const {stats} = srf.locals;
const registrar = new Registrar(logger, redisClient);
const registrar = new Registrar(opts);
const {
lookupAccountCapacitiesBySid,
lookupAccountBySid,
@@ -19,7 +19,6 @@ module.exports = (srf, logger, redisClient) => {
const callId = req.get('Call-ID');
req.locals.account_sid = req.get('X-Account-Sid');
req.locals.application_sid = req.get('X-Application-Sid');
req.locals.record_all_calls = req.get('X-Record-All-Calls');
const traceId = req.locals.trace_id = req.get('X-Trace-ID');
req.locals.logger = logger.child({
callId,
+113 -126
View File
@@ -1,20 +1,20 @@
{
"name": "sbc-outbound",
"version": "0.8.4",
"version": "v0.8.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "sbc-outbound",
"version": "0.8.4",
"version": "v0.8.2",
"license": "MIT",
"dependencies": {
"@jambonz/db-helpers": "^0.9.0",
"@jambonz/db-helpers": "^0.7.8",
"@jambonz/http-health-check": "^0.0.1",
"@jambonz/mw-registrar": "0.2.4",
"@jambonz/realtimedb-helpers": "^0.8.6",
"@jambonz/mw-registrar": "0.2.2",
"@jambonz/realtimedb-helpers": "^0.7.0",
"@jambonz/rtpengine-utils": "^0.4.3",
"@jambonz/siprec-client-utils": "^0.2.5",
"@jambonz/siprec-client-utils": "^0.2.4",
"@jambonz/stats-collector": "^0.1.8",
"@jambonz/time-series": "^0.2.5",
"cidr-matcher": "^2.1.1",
@@ -538,11 +538,6 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
"node_modules/@ioredis/commands": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
},
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -578,9 +573,9 @@
}
},
"node_modules/@jambonz/db-helpers": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.9.0.tgz",
"integrity": "sha512-4fvwONj4jQNIHyG76WGdE7AuMt9vDl4sfHmHrY3PSgOh+kf2BCtBEYqoxyJ96/NH9OeUYkuXoM6fjSvpS7GYVw==",
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.7.9.tgz",
"integrity": "sha512-JajIJSPXW0OTjVprDwTH8/yU/qhHY1XkXe6f5PRh0kvRt42AmYggcGKqgivUkY1seR/GVCnQccDcIA2ZEdvDUg==",
"dependencies": {
"cidr-matcher": "^2.1.1",
"debug": "^4.3.4",
@@ -601,20 +596,34 @@
}
},
"node_modules/@jambonz/mw-registrar": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@jambonz/mw-registrar/-/mw-registrar-0.2.4.tgz",
"integrity": "sha512-GHRlvHsDvwfQfqOUKh4Emt+CvoiODQ+Tny5zg8ZT5q5yz77qy3XIfOF072xO9gDSPrXjn0rH13W3iIKtNzcOIA==",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@jambonz/mw-registrar/-/mw-registrar-0.2.2.tgz",
"integrity": "sha512-CG0MUVRZZ+tBgB5kvjn5IS1R/OdNV5PpAsxCKE0ehe6XVJ1ap4ch9hSZmEh2q7qPnWu8sR451peF33dnoSeaPA==",
"dependencies": {
"debug": "^4.3.1"
"@jambonz/promisify-redis": "^0.0.6",
"debug": "^4.3.1",
"redis": "^3.1.1"
}
},
"node_modules/@jambonz/promisify-redis": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@jambonz/promisify-redis/-/promisify-redis-0.0.6.tgz",
"integrity": "sha512-9KmWV+ODDOPwdqijhgXOXkloGNm7nmCf3ch4D1vN46lh9FQLmnlQmEmBHIFaKB3vAgIgcMzNzcNmY23JGCGguA==",
"dependencies": {
"redis-commands": "^1.6.0"
},
"peerDependencies": {
"redis": "^3.0.0"
}
},
"node_modules/@jambonz/realtimedb-helpers": {
"version": "0.8.6",
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.8.6.tgz",
"integrity": "sha512-ODKVVat2VAQheY13DjiAxiBBOmffMoeu3xviTjsTODr3ySZkqQZvSWU7N80pAIZvoiWG1UUEy9yI8D8mE4Jgiw==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.7.0.tgz",
"integrity": "sha512-hu+CcV0jzQU6J4vW8bBEz52NqEroLHOB0wjVb/VmSL4N0+MAJ1wbPUNk8go5aMk809Vr/Od2z9nHInGnTiBHzA==",
"dependencies": {
"@jambonz/promisify-redis": "^0.0.6",
"debug": "^4.3.4",
"ioredis": "^5.3.2"
"redis": "^3.1.2"
}
},
"node_modules/@jambonz/rtpengine-utils": {
@@ -628,9 +637,9 @@
}
},
"node_modules/@jambonz/siprec-client-utils": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.5.tgz",
"integrity": "sha512-Ib3M2ecFNxi80gZRG3hcCvxXLLImti1/0bVjAtglGjo1+qn3MyirIVYDchqdabzOC2nWl5aKBEcpG30c2saIDg==",
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.4.tgz",
"integrity": "sha512-ptwY1crXmYYT0WtkMzxtVyEuH8WD0F4Za3K7YQei3bVMdHS+w2CwndfRWGlectkFTuG/eYhTCPrNzD7oIcRyjg==",
"dependencies": {
"sdp-transform": "^2.14.1",
"uuid": "^8.3.2"
@@ -1107,14 +1116,6 @@
"node": ">=6"
}
},
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2476,29 +2477,6 @@
"node": ">= 0.4"
}
},
"node_modules/ioredis": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
"dependencies": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
},
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ioredis"
}
},
"node_modules/ip6addr": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/ip6addr/-/ip6addr-0.2.5.tgz",
@@ -3039,22 +3017,12 @@
"node": ">=8"
}
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
},
"node_modules/lodash.flattendeep": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
"integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
"dev": true
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -3788,6 +3756,29 @@
"node": ">= 12.13.0"
}
},
"node_modules/redis": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz",
"integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==",
"dependencies": {
"denque": "^1.5.0",
"redis-commands": "^1.7.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-redis"
}
},
"node_modules/redis-commands": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
"integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
},
"node_modules/redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
@@ -3807,6 +3798,14 @@
"node": ">=4"
}
},
"node_modules/redis/node_modules/denque": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==",
"engines": {
"node": ">=0.10"
}
},
"node_modules/regexp.prototype.flags": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
@@ -4227,11 +4226,6 @@
"node": ">= 0.6"
}
},
"node_modules/standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -5213,11 +5207,6 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
"@ioredis/commands": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
},
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -5246,9 +5235,9 @@
"dev": true
},
"@jambonz/db-helpers": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.9.0.tgz",
"integrity": "sha512-4fvwONj4jQNIHyG76WGdE7AuMt9vDl4sfHmHrY3PSgOh+kf2BCtBEYqoxyJ96/NH9OeUYkuXoM6fjSvpS7GYVw==",
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.7.9.tgz",
"integrity": "sha512-JajIJSPXW0OTjVprDwTH8/yU/qhHY1XkXe6f5PRh0kvRt42AmYggcGKqgivUkY1seR/GVCnQccDcIA2ZEdvDUg==",
"requires": {
"cidr-matcher": "^2.1.1",
"debug": "^4.3.4",
@@ -5266,20 +5255,31 @@
}
},
"@jambonz/mw-registrar": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@jambonz/mw-registrar/-/mw-registrar-0.2.4.tgz",
"integrity": "sha512-GHRlvHsDvwfQfqOUKh4Emt+CvoiODQ+Tny5zg8ZT5q5yz77qy3XIfOF072xO9gDSPrXjn0rH13W3iIKtNzcOIA==",
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@jambonz/mw-registrar/-/mw-registrar-0.2.2.tgz",
"integrity": "sha512-CG0MUVRZZ+tBgB5kvjn5IS1R/OdNV5PpAsxCKE0ehe6XVJ1ap4ch9hSZmEh2q7qPnWu8sR451peF33dnoSeaPA==",
"requires": {
"debug": "^4.3.1"
"@jambonz/promisify-redis": "^0.0.6",
"debug": "^4.3.1",
"redis": "^3.1.1"
}
},
"@jambonz/promisify-redis": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@jambonz/promisify-redis/-/promisify-redis-0.0.6.tgz",
"integrity": "sha512-9KmWV+ODDOPwdqijhgXOXkloGNm7nmCf3ch4D1vN46lh9FQLmnlQmEmBHIFaKB3vAgIgcMzNzcNmY23JGCGguA==",
"requires": {
"redis-commands": "^1.6.0"
}
},
"@jambonz/realtimedb-helpers": {
"version": "0.8.6",
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.8.6.tgz",
"integrity": "sha512-ODKVVat2VAQheY13DjiAxiBBOmffMoeu3xviTjsTODr3ySZkqQZvSWU7N80pAIZvoiWG1UUEy9yI8D8mE4Jgiw==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.7.0.tgz",
"integrity": "sha512-hu+CcV0jzQU6J4vW8bBEz52NqEroLHOB0wjVb/VmSL4N0+MAJ1wbPUNk8go5aMk809Vr/Od2z9nHInGnTiBHzA==",
"requires": {
"@jambonz/promisify-redis": "^0.0.6",
"debug": "^4.3.4",
"ioredis": "^5.3.2"
"redis": "^3.1.2"
}
},
"@jambonz/rtpengine-utils": {
@@ -5293,9 +5293,9 @@
}
},
"@jambonz/siprec-client-utils": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.5.tgz",
"integrity": "sha512-Ib3M2ecFNxi80gZRG3hcCvxXLLImti1/0bVjAtglGjo1+qn3MyirIVYDchqdabzOC2nWl5aKBEcpG30c2saIDg==",
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.4.tgz",
"integrity": "sha512-ptwY1crXmYYT0WtkMzxtVyEuH8WD0F4Za3K7YQei3bVMdHS+w2CwndfRWGlectkFTuG/eYhTCPrNzD7oIcRyjg==",
"requires": {
"sdp-transform": "^2.14.1",
"uuid": "^8.3.2"
@@ -5657,11 +5657,6 @@
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
"dev": true
},
"cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -6712,22 +6707,6 @@
"side-channel": "^1.0.4"
}
},
"ioredis": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
"requires": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
}
},
"ip6addr": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/ip6addr/-/ip6addr-0.2.5.tgz",
@@ -7114,22 +7093,12 @@
"p-locate": "^4.1.0"
}
},
"lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
},
"lodash.flattendeep": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
"integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
"dev": true
},
"lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
},
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -7700,6 +7669,29 @@
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz",
"integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg=="
},
"redis": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz",
"integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==",
"requires": {
"denque": "^1.5.0",
"redis-commands": "^1.7.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0"
},
"dependencies": {
"denque": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="
}
}
},
"redis-commands": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
"integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
},
"redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
@@ -8024,11 +8016,6 @@
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="
},
"standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
},
"statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "sbc-outbound",
"version": "0.8.4",
"version": "v0.8.2",
"main": "app.js",
"engines": {
"node": ">= 12.0.0"
@@ -27,12 +27,12 @@
"jslint": "eslint app.js lib"
},
"dependencies": {
"@jambonz/db-helpers": "^0.9.0",
"@jambonz/realtimedb-helpers": "^0.8.6",
"@jambonz/db-helpers": "^0.7.8",
"@jambonz/realtimedb-helpers": "^0.7.0",
"@jambonz/http-health-check": "^0.0.1",
"@jambonz/mw-registrar": "0.2.4",
"@jambonz/mw-registrar": "0.2.2",
"@jambonz/rtpengine-utils": "^0.4.3",
"@jambonz/siprec-client-utils": "^0.2.5",
"@jambonz/siprec-client-utils": "^0.2.4",
"@jambonz/stats-collector": "^0.1.8",
"@jambonz/time-series": "^0.2.5",
"cidr-matcher": "^2.1.1",
+2 -2
View File
@@ -429,7 +429,7 @@ inbound BOOLEAN NOT NULL COMMENT 'if true, whitelist this IP to allow inbound ca
outbound BOOLEAN NOT NULL COMMENT 'if true, include in least-cost routing when placing calls to the PSTN',
voip_carrier_sid CHAR(36) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT 1,
protocol ENUM('udp','tcp','tls', 'tls/srtp') DEFAULT 'udp' COMMENT 'Outbound call protocol',
protocol ENUM('udp','tcp','tls') DEFAULT 'udp' COMMENT 'Outbound call protocol',
PRIMARY KEY (sip_gateway_sid)
) COMMENT='A whitelisted sip gateway used for origination/termination';
@@ -683,4 +683,4 @@ ALTER TABLE accounts ADD FOREIGN KEY device_calling_application_sid_idxfk (devic
ALTER TABLE accounts ADD FOREIGN KEY siprec_hook_sid_idxfk (siprec_hook_sid) REFERENCES applications (application_sid);
SET FOREIGN_KEY_CHECKS=1;
SET FOREIGN_KEY_CHECKS=1;
+5 -16
View File
@@ -27,23 +27,12 @@ insert into voip_carriers (voip_carrier_sid, name, service_provider_sid) values
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound)
values ('e71519ff-4494-4c98-a06a-324e2712d94b', '1d8ef351-062a-4487-94f8-7698d5a40d24', '172.39.0.21', true, true);
-- lcr route: default eastco, but 1617 matches westco (503)
insert into lcr(lcr_sid, account_sid)
values('c0b0b6a0-0b0a-4b0b-8b0b-0b0b0b0b0b0b', 'ed649e33-e771-403a-8c99-1780eabbc803');
insert into lcr_routes(lcr_route_sid, lcr_sid, regex, priority)
values ('9eba4204-b036-4388-8f47-724c4cfb3d4e', 'c0b0b6a0-0b0a-4b0b-8b0b-0b0b0b0b0b0b', '.*', 999);
-- lcr route: first try eastco (503) then westco (200)
insert into lcr(lcr_sid, name, is_active, service_provider_sid) values ('0eba4204-b036-4388-8f47-724c4cfb3d4f', 'default LCR', 1, '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0');
insert into lcr_routes(lcr_route_sid, lcr_sid, regex, priority) values ('0eba4204-b036-4388-8f47-724c4cfb3d4e', '0eba4204-b036-4388-8f47-724c4cfb3d4f', '.*', 1);
insert into lcr_carrier_set_entry(lcr_carrier_set_entry_sid, lcr_route_sid, voip_carrier_sid, priority)
values ('13e344a0-8a4c-4f95-8a19-ccbfc7ab053e', '9eba4204-b036-4388-8f47-724c4cfb3d4e', '1d8ef351-062a-4487-94f8-7698d5a40d24', 1);
-- attach default route to lcr
update lcr set default_carrier_set_entry_sid = '13e344a0-8a4c-4f95-8a19-ccbfc7ab053e';
-- add a route based on digit match
insert into lcr_routes(lcr_route_sid, lcr_sid, regex, priority)
values ('3eba4204-b036-4388-8f47-724c4cfb3d4e', 'c0b0b6a0-0b0a-4b0b-8b0b-0b0b0b0b0b0b', '1617', 1);
values ('b677a7b5-bec6-4045-ae4a-a67a5ccb3448', '0eba4204-b036-4388-8f47-724c4cfb3d4e', '1d8ef351-062a-4487-94f8-7698d5a40d24', 2);
insert into lcr_carrier_set_entry(lcr_carrier_set_entry_sid, lcr_route_sid, voip_carrier_sid, priority)
values ('b677a7b5-bec6-4045-ae4a-a67a5ccb3448', '3eba4204-b036-4388-8f47-724c4cfb3d4e', '287c1452-620d-4195-9f19-c9814ef90d78', 1);
values ('13e344a0-8a4c-4f95-8a19-ccbfc7ab053e', '0eba4204-b036-4388-8f47-724c4cfb3d4e', '287c1452-620d-4195-9f19-c9814ef90d78', 1);
+22
View File
@@ -17,7 +17,29 @@ values ('f4e1848d-3ff8-40eb-b9c1-30e1ef053f94','ed649e33-e771-403a-8c99-1780eabb
insert into account_products(account_product_sid, account_subscription_sid, product_sid,quantity)
values ('f23ff996-6534-4aba-8666-4b347391eca2', 'f4e1848d-3ff8-40eb-b9c1-30e1ef053f94', 'c4403cdb-8e75-4b27-9726-7d8315e3216d', 10);
-- "good" carrier - "westco" at 172.39.0.20
insert into voip_carriers (voip_carrier_sid, name, service_provider_sid) values ('287c1452-620d-4195-9f19-c9814ef90d78', 'westco', '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0');
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound)
values ('124a5339-c62c-4075-9e19-f4de70a96597', '287c1452-620d-4195-9f19-c9814ef90d78', '172.39.0.20', true, true);
-- "bad" carrier - "eastco" at 172.39.0.21 (returns 503)
insert into voip_carriers (voip_carrier_sid, name, service_provider_sid) values ('1d8ef351-062a-4487-94f8-7698d5a40d24', 'eastco', '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0');
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound)
values ('e71519ff-4494-4c98-a06a-324e2712d94b', '1d8ef351-062a-4487-94f8-7698d5a40d24', '172.39.0.21', true, true);
-- "bad" carrier - "northco" at 172.39.0.22 (returns 100 Trying and never answers)
insert into voip_carriers (voip_carrier_sid, name, service_provider_sid) values ('7b4b9c56-4d81-4f31-9d70-62cd7d82193b', 'northco', '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0');
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound)
values ('fcbb2109-582c-4d55-b38a-b6bc7cc4be73', '7b4b9c56-4d81-4f31-9d70-62cd7d82193b', '172.39.0.22', true, true);
-- lcr route: first try eastco (503) then northco (cancel), then westco (200)
insert into lcr(lcr_sid, name, is_active, service_provider_sid) values ('0eba4204-b036-4388-8f47-724c4cfb3d4f', 'default LCR', 1, '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0');
insert into lcr_routes(lcr_route_sid, lcr_sid, regex, priority) values ('0eba4204-b036-4388-8f47-724c4cfb3d4e', '0eba4204-b036-4388-8f47-724c4cfb3d4f', '.*', 1);
insert into lcr_carrier_set_entry(lcr_carrier_set_entry_sid, lcr_route_sid, voip_carrier_sid, priority)
values ('b677a7b5-bec6-4045-ae4a-a67a5ccb3448', '0eba4204-b036-4388-8f47-724c4cfb3d4e', '1d8ef351-062a-4487-94f8-7698d5a40d24', 3);
insert into lcr_carrier_set_entry(lcr_carrier_set_entry_sid, lcr_route_sid, voip_carrier_sid, priority)
values ('b417ce66-a805-46b3-b296-697a6c2ca249', '0eba4204-b036-4388-8f47-724c4cfb3d4e', '7b4b9c56-4d81-4f31-9d70-62cd7d82193b', 1);
insert into lcr_carrier_set_entry(lcr_carrier_set_entry_sid, lcr_route_sid, voip_carrier_sid, priority)
values ('13e344a0-8a4c-4f95-8a19-ccbfc7ab053e', '0eba4204-b036-4388-8f47-724c4cfb3d4e', '287c1452-620d-4195-9f19-c9814ef90d78', 2);
+2 -2
View File
@@ -33,7 +33,7 @@
CSeq: 1 INVITE
Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70
Subject: uac-cancel
Subject: uac-pcap-carrier-success
X-Account-Sid: ed649e33-e771-403a-8c99-1780eabbc803
X-Call-Sid: fff49e33-e771-403a-8c99-1780eabbc803
X-Jambonz-Routing: phone
@@ -60,7 +60,7 @@
<recv response="100" response_txn="invite"/>
<pause milliseconds="1000"/>
<pause milliseconds="3000"/>
<send>
<![CDATA[
@@ -1,92 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<scenario name="UAC with media">
<send retrans="500">
<![CDATA[
INVITE sip:16173333456@127.0.0.1 SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
To: <sip:16173333456@127.0.0.1>
Call-ID: [call_id]
CSeq: 1 INVITE
Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70
X-Account-Sid: ed649e33-e771-403a-8c99-1780eabbc803
X-Call-Sid: fff49e33-e771-403a-8c99-1780eabbc803
X-Jambonz-Routing: phone
X-Voip-Carrier-Sid: 287c1452-620d-4195-9f19-c9814ef90d78
Subject: uac-pcap-carrier-success
Content-Type: application/sdp
Content-Length: [len]
v=0
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
s=-
c=IN IP[local_ip_type] [local_ip]
t=0 0
m=audio [auto_media_port] RTP/AVP 8 101
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-11,16
]]>
</send>
<recv response="100" optional="true">
</recv>
<recv response="180" optional="true">
</recv>
<recv response="200" rtd="true" crlf="true">
</recv>
<send>
<![CDATA[
ACK sip:sip:+16173333456@127.0.0.1 SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
To: <sip:sip:+16173333456@127.0.0.1>[peer_tag_param]
Call-ID: [call_id]
CSeq: 1 ACK
Subject: uac-pcap-carrier-success
Content-Length: 0
]]>
</send>
<!-- Play a pre-recorded PCAP file (RTP stream) -->
<nop>
<action>
<exec play_pcap_audio="pcap/g711a.pcap"/>
</action>
</nop>
<!-- Pause briefly -->
<pause milliseconds="2000"/>
<!-- The 'crlf' option inserts a blank line in the statistics report. -->
<send retrans="500">
<![CDATA[
BYE sip:sip:+16173333456@127.0.0.1 SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
To: <sip:sip:+16173333456@127.0.0.1>[peer_tag_param]
Call-ID: [call_id]
CSeq: 2 BYE
Max-Forwards: 70
Subject: uac-pcap-carrier-success
Content-Length: 0
]]>
</send>
<recv response="200" crlf="true">
</recv>
</scenario>
+3 -7
View File
@@ -44,10 +44,6 @@ test('sbc-outbound tests', async(t) => {
await sippUac('uac-pcap-carrier-success.xml');
t.pass('successfully completed outbound call to sip trunk');
/* call to PSTN with no lcr configured */
await sippUac('uac-pcap-inbound-carrier-success.xml');
t.pass('successfully completed outbound call to sip trunk');
/* call to PSTN with request uri we see in kubernetes */
await sippUac('uac-pcap-carrier-success-k8s.xml');
t.pass('successfully completed outbound call to sip trunk (k8S req uri)');
@@ -58,7 +54,7 @@ test('sbc-outbound tests', async(t) => {
/* call to PSTN with lcr configured */
await sippUac('uac-pcap-carrier-success.xml');
t.pass('successfully completed outbound call using LCR');
t.pass('successfully completed outbound lcr carrier with crankback after failure');
// re-rack test data
execSync(`mysql -h 127.0.0.1 -u root --protocol=tcp -D jambones_test < ${__dirname}/db/jambones-sql.sql`);
@@ -91,8 +87,8 @@ test('sbc-outbound tests', async(t) => {
await waitFor(25);
const res = await queryCdrs({account_sid: 'ed649e33-e771-403a-8c99-1780eabbc803'});
console.log(`${res.total} cdrs: ${JSON.stringify(res)}`);
t.ok(res.total === 7, 'wrote 7 cdrs');
console.log(`cdrs: ${JSON.stringify(res)}`);
t.ok(res.total === 6, 'wrote 6 cdrs');
srf.disconnect();
} catch (err) {