mirror of
https://github.com/jambonz/sbc-outbound.git
synced 2026-10-04 02:04:19 +00:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3512fb468d | ||
|
|
4a0ed4cdca | ||
|
|
69928ce8bc | ||
|
|
a6c9699f37 | ||
|
|
ce6ca6c21a | ||
|
|
f661883095 | ||
|
|
bd0c8d2783 | ||
|
|
a2c8abb632 | ||
|
|
b0d3e6bbac | ||
|
|
782102b6c1 | ||
|
|
25c1f11935 | ||
|
|
9826174ecf | ||
|
|
6bb0b21100 | ||
|
|
08f5f1f58e | ||
|
|
5d1909e50c | ||
|
|
4f947ad3f2 | ||
|
|
dccd57935e | ||
|
|
c66ba70500 | ||
|
|
e213409dec | ||
|
|
96906bd0ad | ||
|
|
cff42ef539 | ||
|
|
2d49b6ed8e | ||
|
|
160f888643 | ||
|
|
521e540901 | ||
|
|
d6bd607aee | ||
|
|
e4313fd5d3 |
@@ -14,19 +14,19 @@ const opts = Object.assign({
|
||||
timestamp: () => {return `, "time": "${new Date().toISOString()}"`;}
|
||||
}, {level: process.env.JAMBONES_LOGLEVEL || 'info'});
|
||||
const logger = require('pino')(opts);
|
||||
const StatsCollector = require('jambonz-stats-collector');
|
||||
const StatsCollector = require('@jambonz/stats-collector');
|
||||
const stats = srf.locals.stats = new StatsCollector(logger);
|
||||
const {route, setLogger} = require('./lib/middleware');
|
||||
const CallSession = require('./lib/call-session');
|
||||
const {performLcr} = require('jambonz-db-helpers')({
|
||||
const {performLcr, lookupAllTeamsFQDNs, lookupAccountBySipRealm} = require('@jambonz/db-helpers')({
|
||||
host: process.env.JAMBONES_MYSQL_HOST,
|
||||
user: process.env.JAMBONES_MYSQL_USER,
|
||||
password: process.env.JAMBONES_MYSQL_PASSWORD,
|
||||
database: process.env.JAMBONES_MYSQL_DATABASE,
|
||||
connectionLimit: process.env.JAMBONES_MYSQL_CONNECTION_LIMIT || 10
|
||||
}, logger);
|
||||
srf.locals.dbHelpers = {performLcr};
|
||||
const {getRtpEngine} = require('jambonz-rtpengine-utils')(process.env.JAMBONES_RTPENGINES.split(','), logger, {
|
||||
srf.locals.dbHelpers = {performLcr, lookupAllTeamsFQDNs, lookupAccountBySipRealm};
|
||||
const {getRtpEngine} = require('@jambonz/rtpengine-utils')(process.env.JAMBONES_RTPENGINES.split(','), logger, {
|
||||
emitter: srf.locals.stats
|
||||
});
|
||||
srf.locals.getRtpEngine = getRtpEngine;
|
||||
@@ -61,4 +61,7 @@ setInterval(() => {
|
||||
stats.gauge('sbc.sip.calls.count', activeCallIds.size, ['direction:outbound']);
|
||||
}, 5000);
|
||||
|
||||
const {pingMsTeamsGateways} = require('./lib/utils');
|
||||
pingMsTeamsGateways(logger, srf);
|
||||
|
||||
module.exports = {srf};
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
{
|
||||
"transport-protocol": "UDP/TLS/RTP/SAVPF",
|
||||
"ICE": "force",
|
||||
"SDES": "off",
|
||||
"flags": ["generate mid", "SDES-no"],
|
||||
"rtcp-mux": ["require"]
|
||||
"default": {
|
||||
"transport-protocol": "UDP/TLS/RTP/SAVPF",
|
||||
"ICE": "force",
|
||||
"SDES": "off",
|
||||
"flags": ["generate mid", "SDES-no", "media handover"],
|
||||
"rtcp-mux": ["require"]
|
||||
},
|
||||
"teams": {
|
||||
"transport-protocol": "RTP/SAVP",
|
||||
"ICE": "force",
|
||||
"flags": ["generate mid", "media handover",
|
||||
"SDES-no-AES_CM_128_HMAC_SHA1_32",
|
||||
"SDES-no-F8_128_HMAC_SHA1_80",
|
||||
"SDES-no-F8_128_HMAC_SHA1_32",
|
||||
"SDES-no-NULL_HMAC_SHA1_80",
|
||||
"SDES-no-NULL_HMAC_SHA1_32",
|
||||
"SDES-no-AES_192_CM_HMAC_SHA1_80",
|
||||
"SDES-no-AES_192_CM_HMAC_SHA1_32",
|
||||
"SDES-no-AES_256_CM_HMAC_SHA1_80",
|
||||
"SDES-no-AES_256_CM_HMAC_SHA1_32"
|
||||
],
|
||||
"rtcp-mux": ["require"]
|
||||
}
|
||||
}
|
||||
+158
-20
@@ -2,8 +2,28 @@ const Emitter = require('events');
|
||||
const {makeRtpEngineOpts} = require('./utils');
|
||||
const {forwardInDialogRequests} = require('drachtio-fn-b2b-sugar');
|
||||
const {SipError} = require('drachtio-srf');
|
||||
const {parseUri, stringifyUri} = require('drachtio-srf');
|
||||
const debug = require('debug')('jambonz:sbc-outbound');
|
||||
|
||||
/**
|
||||
* this is to make sure the outgoing From has the number in the incoming From
|
||||
* and not the incoming PAI
|
||||
*/
|
||||
const createBLegFromHeader = (req, teams) => {
|
||||
const from = req.getParsedHeader('From');
|
||||
const host = teams ? req.get('X-MS-Teams-Tenant-FQDN') : 'localhost';
|
||||
const uri = parseUri(from.uri);
|
||||
if (uri && uri.user) return `sip:${uri.user}@${host}`;
|
||||
return `sip:anonymous@${host}`;
|
||||
};
|
||||
const createBLegToHeader = (req, teams) => {
|
||||
const to = req.getParsedHeader('To');
|
||||
const host = teams ? req.get('X-MS-Teams-Tenant-FQDN') : 'localhost';
|
||||
const uri = parseUri(to.uri);
|
||||
if (uri && uri.user) return `sip:${uri.user}@${host}`;
|
||||
return `sip:anonymous@${host}`;
|
||||
};
|
||||
|
||||
class CallSession extends Emitter {
|
||||
constructor(logger, req, res) {
|
||||
super();
|
||||
@@ -12,12 +32,13 @@ class CallSession extends Emitter {
|
||||
this.srf = req.srf;
|
||||
this.performLcr = this.srf.locals.dbHelpers.performLcr;
|
||||
this.logger = logger.child({callId: req.get('Call-ID')});
|
||||
this.useWss = req.locals.registration && req.locals.registration.protocol === 'wss';
|
||||
this.useWss = req.locals.registration && req.locals.registration.protocol === 'wss';
|
||||
this.stats = this.srf.locals.stats;
|
||||
this.activeCallIds = this.srf.locals.activeCallIds;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
const teams = this.teams = this.req.locals.target === 'teams';
|
||||
const engine = this.srf.locals.getRtpEngine();
|
||||
if (!engine) {
|
||||
this.logger.info('No available rtpengines, rejecting call!');
|
||||
@@ -31,25 +52,59 @@ class CallSession extends Emitter {
|
||||
this.answer = answer;
|
||||
this.del = del;
|
||||
|
||||
this.rtpEngineOpts = makeRtpEngineOpts(this.req, false, this.useWss);
|
||||
this.rtpEngineOpts = makeRtpEngineOpts(this.req, false, this.useWss || teams, teams);
|
||||
this.rtpEngineResource = {destroy: this.del.bind(null, this.rtpEngineOpts.common)};
|
||||
let proxy, uris;
|
||||
|
||||
try {
|
||||
// determine where to send the call
|
||||
debug(`connecting call: ${JSON.stringify(this.req.locals)}`);
|
||||
const headers = {
|
||||
'From': createBLegFromHeader(this.req, teams),
|
||||
'To': createBLegToHeader(this.req, teams),
|
||||
Allow: 'INVITE, ACK, OPTIONS, CANCEL, BYE, NOTIFY, UPDATE, PRACK'
|
||||
};
|
||||
|
||||
if (this.req.locals.registration) {
|
||||
debug(`sending call to user ${JSON.stringify(this.req.locals.registration)}`);
|
||||
proxy = this.req.locals.registration.contact;
|
||||
uris = [this.req.uri];
|
||||
debug(`sending call to registered user ${JSON.stringify(this.req.locals.registration)}`);
|
||||
const contact = this.req.locals.registration.contact;
|
||||
let destUri = this.req.uri;
|
||||
if (this.req.has('X-Override-To')) {
|
||||
const dest = this.req.get('X-Override-To');
|
||||
const uri = parseUri(contact);
|
||||
uri.user = dest;
|
||||
destUri = stringifyUri(uri);
|
||||
this.logger.info(`overriding destination user with ${dest}, so final uri is ${destUri}`);
|
||||
}
|
||||
if (contact.includes('transport=ws')) {
|
||||
uris = [contact];
|
||||
}
|
||||
else {
|
||||
proxy = this.req.locals.registration.proxy;
|
||||
uris = [this.req.locals.registration.contact];
|
||||
}
|
||||
}
|
||||
else if (this.req.locals.target === 'forward') {
|
||||
uris = [this.req.uri];
|
||||
}
|
||||
else if (teams) {
|
||||
const vmailParam = 'opaque=app:voicemail';
|
||||
proxy = `sip:${this.req.calledNumber}@sip.pstnhub.microsoft.com:5061;transport=tls`;
|
||||
if (this.req.uri.includes(vmailParam)) {
|
||||
uris = [`sip:${this.req.calledNumber}@sip.pstnhub.microsoft.com;${vmailParam}`];
|
||||
}
|
||||
else uris = [`sip:${this.req.calledNumber}@sip.pstnhub.microsoft.com`];
|
||||
Object.assign(headers, {
|
||||
Contact: `sip:${this.req.calledNumber}@${this.req.get('X-MS-Teams-Tenant-FQDN')}:5061;transport=tls`
|
||||
});
|
||||
}
|
||||
else {
|
||||
debug('calling lcr');
|
||||
try {
|
||||
// strip leading plus sign
|
||||
/**
|
||||
* 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;
|
||||
@@ -67,8 +122,9 @@ class CallSession extends Emitter {
|
||||
|
||||
// rtpengine 'offer'
|
||||
debug('sending offer command to rtpengine');
|
||||
const response = await this.offer(this.rtpEngineOpts.offer);
|
||||
const response = await this.offer(this.rtpEngineOpts.offer, {sdp: this.req.body});
|
||||
debug(`response from rtpengine to offer ${JSON.stringify(response)}`);
|
||||
this.logger.debug({offer: this.rtpEngineOpts.offer, response}, 'initial offer to rtpengine');
|
||||
if ('ok' !== response.result) {
|
||||
this.logger.error(`rtpengine offer failed with ${JSON.stringify(response)}`);
|
||||
throw new Error('rtpengine failed: answer');
|
||||
@@ -78,19 +134,23 @@ class CallSession extends Emitter {
|
||||
let earlyMedia = false;
|
||||
while (uris.length) {
|
||||
const uri = uris.shift();
|
||||
const passFailure = 0 === uris.length; // only a single target
|
||||
debug(`sending INVITE to ${uri} via ${proxy})`);
|
||||
this.logger.info(`sending INVITE to ${uri}`);
|
||||
try {
|
||||
const {uas, uac} = await this.srf.createB2BUA(this.req, this.res, uri, {
|
||||
proxy,
|
||||
passFailure: false,
|
||||
proxyRequestHeaders: ['all'],
|
||||
proxyResponseHeaders: ['all'],
|
||||
passFailure,
|
||||
proxyRequestHeaders: ['all', '-X-MS-Teams-FQDN', '-X-MS-Teams-Tenant-FQDN', '-Allow', '-X-Override-To',
|
||||
'-Session-Expires', 'Min-SE'],
|
||||
proxyResponseHeaders: ['all', '-Allow'],
|
||||
headers,
|
||||
localSdpB: response.sdp,
|
||||
localSdpA: async(sdp, res) => {
|
||||
const opts = Object.assign({sdp, 'to-tag': res.getParsedHeader('To').params.tag},
|
||||
this.rtpEngineOpts.answer);
|
||||
this.toTag = res.getParsedHeader('To').params.tag;
|
||||
const opts = Object.assign(this.rtpEngineOpts.answer, {sdp, 'to-tag': this.toTag});
|
||||
const response = await this.answer(opts);
|
||||
this.logger.debug({answer: opts, response}, 'rtpengine answer');
|
||||
if ('ok' !== response.result) {
|
||||
this.logger.error(`rtpengine answer failed with ${JSON.stringify(response)}`);
|
||||
throw new Error('rtpengine failed: answer');
|
||||
@@ -121,7 +181,7 @@ class CallSession extends Emitter {
|
||||
if (err instanceof SipError) this.logger.info(`final call failure ${err.status}`);
|
||||
else this.logger.error(err, 'unexpected call failure');
|
||||
debug(`got final outdial error: ${err}`);
|
||||
this.res.send(err.status || 500);
|
||||
if (!passFailure) this.res.send(err.status || 500);
|
||||
this.emit('failed');
|
||||
this.rtpEngineResource.destroy();
|
||||
const tags = ['accepted:no', `sipStatus:${err.status || 500}`];
|
||||
@@ -153,26 +213,29 @@ class CallSession extends Emitter {
|
||||
this.logger.info('call ended');
|
||||
this.rtpEngineResource.destroy();
|
||||
this.activeCallIds.delete(this.req.get('Call-ID'));
|
||||
dlg.other.destroy();
|
||||
});
|
||||
|
||||
//re-invite
|
||||
dlg.on('modify', this._onReinvite.bind(this, dlg));
|
||||
});
|
||||
|
||||
uas.on('modify', this._onReinvite.bind(this, uas));
|
||||
|
||||
uac.on('modify', this._onNetworkReinvite.bind(this, uac));
|
||||
uas.on('refer', this._onFeatureServerTransfer.bind(this, uas));
|
||||
|
||||
|
||||
// default forwarding of other request types
|
||||
forwardInDialogRequests(uas);
|
||||
forwardInDialogRequests(uac, ['info', 'notify', 'options', 'message']);
|
||||
}
|
||||
|
||||
async _onReinvite(dlg, req, res) {
|
||||
try {
|
||||
let response = await this.offer(Object.assign({sdp: req.body}, this.rtpEngineOpts.offer));
|
||||
let response = await this.offer(Object.assign(this.rtpEngineOpts.offer, {sdp: req.body}));
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onReinvite: rtpengine failed: offer: ${JSON.stringify(response)}`);
|
||||
}
|
||||
const sdp = await dlg.other.modify(response.sdp);
|
||||
const opts = Object.assign({sdp, 'to-tag': res.getParsedHeader('To').params.tag},
|
||||
this.rtpEngineOpts.answer);
|
||||
const opts = Object.assign(this.rtpEngineOpts.answer, {sdp, 'to-tag': res.getParsedHeader('To').params.tag});
|
||||
response = await this.answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
@@ -184,6 +247,81 @@ class CallSession extends Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
async _onNetworkReinvite(dlg, req, res) {
|
||||
try {
|
||||
const newAnswerOpts = Object.assign({}, this.rtpEngineOpts.answer, {sdp: req.body});
|
||||
let response = await this.answer(newAnswerOpts);
|
||||
this.logger.debug({answer: newAnswerOpts, response}, '_onNetworkReinvite: answer to rtpengine');
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onReinvite: rtpengine failed: offer: ${JSON.stringify(response)}`);
|
||||
}
|
||||
|
||||
// reinvite feature server
|
||||
const sdp = await dlg.other.modify(response.sdp);
|
||||
|
||||
const newOfferOpts = Object.assign({}, this.rtpEngineOpts.offer, {sdp, 'to-tag': this.toTag});
|
||||
response = await this.offer(newOfferOpts);
|
||||
this.logger.debug({answer: newOfferOpts, response}, '_onNetworkReinvite: offer to rtpengine');
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onReinvite: rtpengine failed: ${JSON.stringify(response)}`);
|
||||
}
|
||||
res.send(200, {body: response.sdp});
|
||||
} catch (err) {
|
||||
this.logger.error(err, 'Error handling reinvite');
|
||||
}
|
||||
}
|
||||
|
||||
async _onFeatureServerTransfer(dlg, req, res) {
|
||||
try {
|
||||
const referTo = req.getParsedHeader('Refer-To');
|
||||
const uri = parseUri(referTo.uri);
|
||||
this.logger.info({uri, referTo}, '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);
|
||||
}
|
||||
res.send(202);
|
||||
|
||||
// invite to new fs
|
||||
const headers = {};
|
||||
if (req.has('X-Retain-Call-Sid')) {
|
||||
Object.assign(headers, {'X-Retain-Call-Sid': req.get('X-Retain-Call-Sid')});
|
||||
}
|
||||
const dlg = await this.srf.createUAC(referTo.uri, {localSdp: dlg.local.sdp, headers});
|
||||
this.uas.destroy();
|
||||
|
||||
this.uas = dlg;
|
||||
this.uas.other = this.uac;
|
||||
this.uac.other = this.uas;
|
||||
this.uas.on('modify', this._onReinvite.bind(this, this.uas));
|
||||
this.uas.on('refer', this._onFeatureServerTransfer.bind(this, this.uas));
|
||||
this.uas.on('destroy', () => {
|
||||
this.logger.info('call ended with normal termination');
|
||||
this.rtpEngineResource.destroy();
|
||||
this.activeCallIds.delete(this.req.get('Call-ID'));
|
||||
this.uas.other.destroy();
|
||||
});
|
||||
|
||||
// modify rtpengine to stream to new feature server
|
||||
let response = await this.offer(Object.assign(this.rtpEngineOpts.offer, {sdp: this.uas.remote.sdp}));
|
||||
if ('ok' !== response.result) {
|
||||
throw new Error(`_onReinvite: rtpengine failed: offer: ${JSON.stringify(response)}`);
|
||||
}
|
||||
const sdp = await this.uas.other.modify(response.sdp);
|
||||
const opts = Object.assign({sdp, 'to-tag': res.getParsedHeader('To').params.tag},
|
||||
this.rtpEngineOpts.answer);
|
||||
response = await this.answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
throw new Error(`_onReinvite: rtpengine failed: ${JSON.stringify(response)}`);
|
||||
}
|
||||
this.logger.info('successfully moved call to new feature server');
|
||||
} catch (err) {
|
||||
this.logger.error(err, 'Error handling refer from feature server');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CallSession;
|
||||
|
||||
+18
-4
@@ -22,6 +22,7 @@ function route(opts) {
|
||||
const registrar = new Registrar(opts);
|
||||
return async(req, res, next) => {
|
||||
const logger = req.locals.logger;
|
||||
const {lookupAccountBySipRealm} = req.srf.locals.dbHelpers;
|
||||
logger.info(`received outbound INVITE to ${req.uri} from server at ${req.server.hostport}`);
|
||||
const uri = parseUri(req.uri);
|
||||
if (!uri.user || !uri.host) {
|
||||
@@ -43,7 +44,12 @@ function route(opts) {
|
||||
let reg;
|
||||
const dotDecimalHost = /^[0-9\.]+$/.test(uri.host);
|
||||
|
||||
if (!dotDecimalHost) {
|
||||
if (req.has('X-MS-Teams-FQDN') && req.has('X-MS-Teams-Tenant-FQDN')) {
|
||||
logger.debug('This is a call to ms teams');
|
||||
req.locals.target = 'teams';
|
||||
return next();
|
||||
}
|
||||
else if (!dotDecimalHost) {
|
||||
// uri host is not a dot-decimal address, so try to look up user
|
||||
debug(`searching for registered user ${aor}`);
|
||||
reg = await registrar.query(aor);
|
||||
@@ -63,10 +69,18 @@ function route(opts) {
|
||||
req.locals.target = 'user';
|
||||
return next();
|
||||
}
|
||||
else {
|
||||
// if the sip domain is one of ours return 404
|
||||
const account = await lookupAccountBySipRealm(uri.host);
|
||||
if (account) {
|
||||
logger.info(`returning 404 to unregistered user in valid domain: ${req.uri}`);
|
||||
res.send(404);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!isLocalUri(uri.host, req) /*|| !dotDecimalHost */) {
|
||||
// TODO: need to try to forward calls to a DNS host name
|
||||
// so long as that domain name is not associated with an account or SP in our DB
|
||||
if (!dotDecimalHost || !isLocalUri(uri.host, req)) {
|
||||
// call that needs to be forwarded to a sip endpoint
|
||||
logger.info(`forwarding call to sip endpoint ${req.uri}`);
|
||||
req.locals.target = 'forward';
|
||||
return next();
|
||||
|
||||
+45
-5
@@ -2,14 +2,21 @@ const rtpCharacteristics = require('../data/rtp-transcoding');
|
||||
const srtpCharacteristics = require('../data/srtp-transcoding');
|
||||
const debug = require('debug')('jambonz:sbc-outbound');
|
||||
|
||||
function makeRtpEngineOpts(req, srcIsUsingSrtp, dstIsUsingSrtp) {
|
||||
function makeRtpEngineOpts(req, srcIsUsingSrtp, dstIsUsingSrtp, teams = false) {
|
||||
const from = req.getParsedHeader('from');
|
||||
const srtpOpts = teams ? srtpCharacteristics['teams'] : srtpCharacteristics['default'];
|
||||
const common = {'call-id': req.get('Call-ID'), 'from-tag': from.params.tag};
|
||||
return {
|
||||
common,
|
||||
offer: Object.assign({'sdp': req.body, 'replace': ['origin', 'session-connection']}, common,
|
||||
dstIsUsingSrtp ? srtpCharacteristics : rtpCharacteristics),
|
||||
answer: Object.assign({}, common, srcIsUsingSrtp ? srtpCharacteristics : rtpCharacteristics)
|
||||
offer: Object.assign(
|
||||
{'sdp': req.body, 'replace': ['origin', 'session-connection']},
|
||||
{'direction': [ 'private', 'public']},
|
||||
common,
|
||||
dstIsUsingSrtp ? srtpOpts : rtpCharacteristics),
|
||||
answer: Object.assign(
|
||||
{'replace': ['origin', 'session-connection']},
|
||||
common,
|
||||
srcIsUsingSrtp ? srtpOpts : rtpCharacteristics)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +34,40 @@ function selectHostPort(hostport, protocol) {
|
||||
return sel[0];
|
||||
}
|
||||
|
||||
function pingMs(logger, srf, gateway, fqdns) {
|
||||
const uri = `sip:${gateway}`;
|
||||
const proxy = `sip:${gateway}:5061;transport=tls`;
|
||||
fqdns.forEach((fqdn) => {
|
||||
const contact = `<sip:${fqdn}:5061;transport=tls>`;
|
||||
srf.request(uri, {
|
||||
method: 'OPTIONS',
|
||||
proxy,
|
||||
headers: {
|
||||
'Contact': contact,
|
||||
'From': contact,
|
||||
}
|
||||
}).catch((err) => logger.error(err, `Error pinging MS Teams at ${gateway}`));
|
||||
});
|
||||
}
|
||||
function pingMsTeamsGateways(logger, srf) {
|
||||
const {lookupAllTeamsFQDNs} = srf.locals.dbHelpers;
|
||||
lookupAllTeamsFQDNs()
|
||||
.then((fqdns) => {
|
||||
if (fqdns.length > 0) {
|
||||
['sip.pstnhub.microsoft.com', 'sip2.pstnhub.microsoft.com', 'sip3.pstnhub.microsoft.com']
|
||||
.forEach((gw) => {
|
||||
setInterval(pingMs.bind(this, logger, srf, gw, fqdns), 60000);
|
||||
});
|
||||
}
|
||||
return;
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(err, 'Error looking up all ms teams fqdns');
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
makeRtpEngineOpts,
|
||||
selectHostPort
|
||||
selectHostPort,
|
||||
pingMsTeamsGateways
|
||||
};
|
||||
|
||||
Generated
+1263
-3233
File diff suppressed because it is too large
Load Diff
+11
-12
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sbc-outbound",
|
||||
"version": "0.3.2",
|
||||
"version": "0.4.3",
|
||||
"main": "app.js",
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
@@ -27,22 +27,21 @@
|
||||
"jslint": "eslint app.js lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"@jambonz/db-helpers": "^0.4.2",
|
||||
"@jambonz/rtpengine-utils": "^0.1.7",
|
||||
"@jambonz/stats-collector": "0.1.4",
|
||||
"debug": "^4.3.1",
|
||||
"drachtio-fn-b2b-sugar": "^0.0.12",
|
||||
"drachtio-srf": "^4.4.28",
|
||||
"jambonz-rtpengine-utils": "0.1.1",
|
||||
"jambonz-db-helpers": "^0.3.2",
|
||||
"jambonz-mw-registrar": "^0.1.2",
|
||||
"jambonz-stats-collector": "0.0.3",
|
||||
"pino": "^5.14.0",
|
||||
"rtpengine-client": "^0.0.8"
|
||||
"drachtio-srf": "^4.4.44",
|
||||
"jambonz-mw-registrar": "^0.1.3",
|
||||
"pino": "^6.8.0",
|
||||
"rtpengine-client": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"blue-tape": "^1.0.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"nyc": "^14.1.1",
|
||||
"tap": "^14.10.2",
|
||||
"nyc": "^15.1.0",
|
||||
"tap-dot": "^2.0.0",
|
||||
"tap-spec": "^5.0.0"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const test = require('tape').test ;
|
||||
const test = require('blue-tape');
|
||||
//const test = require('tape').test ;
|
||||
const exec = require('child_process').exec ;
|
||||
const pwd = process.env.TRAVIS ? '' : '-p$MYSQL_ROOT_PASSWORD';
|
||||
|
||||
|
||||
+194
-139
@@ -1,204 +1,259 @@
|
||||
/* SQLEditor (MySQL (2))*/
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
DROP TABLE IF EXISTS `call_routes`;
|
||||
DROP TABLE IF EXISTS call_routes;
|
||||
|
||||
DROP TABLE IF EXISTS `lcr_carrier_set_entry`;
|
||||
DROP TABLE IF EXISTS lcr_carrier_set_entry;
|
||||
|
||||
DROP TABLE IF EXISTS `lcr_routes`;
|
||||
DROP TABLE IF EXISTS lcr_routes;
|
||||
|
||||
DROP TABLE IF EXISTS `api_keys`;
|
||||
DROP TABLE IF EXISTS api_keys;
|
||||
|
||||
DROP TABLE IF EXISTS `phone_numbers`;
|
||||
DROP TABLE IF EXISTS ms_teams_tenants;
|
||||
|
||||
DROP TABLE IF EXISTS `sip_gateways`;
|
||||
DROP TABLE IF EXISTS sbc_addresses;
|
||||
|
||||
DROP TABLE IF EXISTS `voip_carriers`;
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
DROP TABLE IF EXISTS `accounts`;
|
||||
DROP TABLE IF EXISTS phone_numbers;
|
||||
|
||||
DROP TABLE IF EXISTS `applications`;
|
||||
DROP TABLE IF EXISTS sip_gateways;
|
||||
|
||||
DROP TABLE IF EXISTS `service_providers`;
|
||||
DROP TABLE IF EXISTS voip_carriers;
|
||||
|
||||
DROP TABLE IF EXISTS `webhooks`;
|
||||
DROP TABLE IF EXISTS accounts;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
DROP TABLE IF EXISTS applications;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `call_routes`
|
||||
DROP TABLE IF EXISTS service_providers;
|
||||
|
||||
DROP TABLE IF EXISTS webhooks;
|
||||
|
||||
CREATE TABLE call_routes
|
||||
(
|
||||
`call_route_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`priority` INTEGER NOT NULL,
|
||||
`account_sid` CHAR(36) NOT NULL,
|
||||
`regex` VARCHAR(255) NOT NULL,
|
||||
`application_sid` CHAR(36) NOT NULL,
|
||||
PRIMARY KEY (`call_route_sid`)
|
||||
call_route_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
priority INTEGER NOT NULL,
|
||||
account_sid CHAR(36) NOT NULL,
|
||||
regex VARCHAR(255) NOT NULL,
|
||||
application_sid CHAR(36) NOT NULL,
|
||||
PRIMARY KEY (call_route_sid)
|
||||
) ENGINE=InnoDB COMMENT='a regex-based pattern match for call routing';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lcr_routes`
|
||||
CREATE TABLE lcr_routes
|
||||
(
|
||||
`lcr_route_sid` CHAR(36),
|
||||
`regex` VARCHAR(32) NOT NULL COMMENT 'regex-based pattern match against dialed number, used for LCR routing of PSTN calls',
|
||||
`description` VARCHAR(1024),
|
||||
`priority` INTEGER NOT NULL UNIQUE COMMENT 'lower priority routes are attempted first',
|
||||
PRIMARY KEY (`lcr_route_sid`)
|
||||
lcr_route_sid CHAR(36),
|
||||
regex VARCHAR(32) NOT NULL COMMENT 'regex-based pattern match against dialed number, used for LCR routing of PSTN calls',
|
||||
description VARCHAR(1024),
|
||||
priority INTEGER NOT NULL UNIQUE COMMENT 'lower priority routes are attempted first',
|
||||
PRIMARY KEY (lcr_route_sid)
|
||||
) COMMENT='Least cost routing table';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `api_keys`
|
||||
CREATE TABLE api_keys
|
||||
(
|
||||
`api_key_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`token` CHAR(36) NOT NULL UNIQUE ,
|
||||
`account_sid` CHAR(36),
|
||||
`service_provider_sid` CHAR(36),
|
||||
PRIMARY KEY (`api_key_sid`)
|
||||
api_key_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
token CHAR(36) NOT NULL UNIQUE ,
|
||||
account_sid CHAR(36),
|
||||
service_provider_sid CHAR(36),
|
||||
expires_at TIMESTAMP NULL,
|
||||
last_used TIMESTAMP NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (api_key_sid)
|
||||
) ENGINE=InnoDB COMMENT='An authorization token that is used to access the REST api';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `voip_carriers`
|
||||
CREATE TABLE ms_teams_tenants
|
||||
(
|
||||
`voip_carrier_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(64) NOT NULL UNIQUE ,
|
||||
`description` VARCHAR(255),
|
||||
`account_sid` CHAR(36) COMMENT 'if provided, indicates this entity represents a customer PBX that is associated with a specific account',
|
||||
`application_sid` CHAR(36) COMMENT 'If provided, all incoming calls from this source will be routed to the associated application',
|
||||
PRIMARY KEY (`voip_carrier_sid`)
|
||||
ms_teams_tenant_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
service_provider_sid CHAR(36) NOT NULL,
|
||||
account_sid CHAR(36) NOT NULL,
|
||||
application_sid CHAR(36),
|
||||
tenant_fqdn VARCHAR(255) NOT NULL UNIQUE ,
|
||||
PRIMARY KEY (ms_teams_tenant_sid)
|
||||
) COMMENT='A Microsoft Teams customer tenant';
|
||||
|
||||
CREATE TABLE sbc_addresses
|
||||
(
|
||||
sbc_address_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
ipv4 VARCHAR(255) NOT NULL,
|
||||
port INTEGER NOT NULL DEFAULT 5060,
|
||||
service_provider_sid CHAR(36),
|
||||
PRIMARY KEY (sbc_address_sid)
|
||||
);
|
||||
|
||||
CREATE TABLE users
|
||||
(
|
||||
user_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
name CHAR(36) NOT NULL UNIQUE ,
|
||||
hashed_password VARCHAR(1024) NOT NULL,
|
||||
salt CHAR(16) NOT NULL,
|
||||
force_change BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
PRIMARY KEY (user_sid)
|
||||
);
|
||||
|
||||
CREATE TABLE voip_carriers
|
||||
(
|
||||
voip_carrier_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
name VARCHAR(64) NOT NULL UNIQUE ,
|
||||
description VARCHAR(255),
|
||||
account_sid CHAR(36) COMMENT 'if provided, indicates this entity represents a customer PBX that is associated with a specific account',
|
||||
application_sid CHAR(36) COMMENT 'If provided, all incoming calls from this source will be routed to the associated application',
|
||||
e164_leading_plus BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (voip_carrier_sid)
|
||||
) ENGINE=InnoDB COMMENT='A Carrier or customer PBX that can send or receive calls';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `phone_numbers`
|
||||
CREATE TABLE phone_numbers
|
||||
(
|
||||
`phone_number_sid` CHAR(36) UNIQUE ,
|
||||
`number` VARCHAR(32) NOT NULL UNIQUE ,
|
||||
`voip_carrier_sid` CHAR(36) NOT NULL,
|
||||
`account_sid` CHAR(36),
|
||||
`application_sid` CHAR(36),
|
||||
PRIMARY KEY (`phone_number_sid`)
|
||||
phone_number_sid CHAR(36) UNIQUE ,
|
||||
number VARCHAR(32) NOT NULL UNIQUE ,
|
||||
voip_carrier_sid CHAR(36) NOT NULL,
|
||||
account_sid CHAR(36),
|
||||
application_sid CHAR(36),
|
||||
PRIMARY KEY (phone_number_sid)
|
||||
) ENGINE=InnoDB COMMENT='A phone number that has been assigned to an account';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `webhooks`
|
||||
CREATE TABLE webhooks
|
||||
(
|
||||
`webhook_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`url` VARCHAR(1024) NOT NULL,
|
||||
`method` ENUM("GET","POST") NOT NULL DEFAULT 'POST',
|
||||
`username` VARCHAR(255),
|
||||
`password` VARCHAR(255),
|
||||
PRIMARY KEY (`webhook_sid`)
|
||||
webhook_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
url VARCHAR(1024) NOT NULL,
|
||||
method ENUM("GET","POST") NOT NULL DEFAULT 'POST',
|
||||
username VARCHAR(255),
|
||||
password VARCHAR(255),
|
||||
PRIMARY KEY (webhook_sid)
|
||||
) COMMENT='An HTTP callback';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lcr_carrier_set_entry`
|
||||
CREATE TABLE sip_gateways
|
||||
(
|
||||
`lcr_carrier_set_entry_sid` CHAR(36),
|
||||
`workload` INTEGER NOT NULL DEFAULT 1 COMMENT 'represents a proportion of traffic to send through the associated carrier; can be used for load balancing traffic across carriers with a common priority for a destination',
|
||||
`lcr_route_sid` CHAR(36) NOT NULL,
|
||||
`voip_carrier_sid` CHAR(36) NOT NULL,
|
||||
`priority` INTEGER NOT NULL DEFAULT 0 COMMENT 'lower priority carriers are attempted first',
|
||||
PRIMARY KEY (`lcr_carrier_set_entry_sid`)
|
||||
) COMMENT='An entry in the LCR routing list';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sip_gateways`
|
||||
(
|
||||
`sip_gateway_sid` CHAR(36),
|
||||
`ipv4` VARCHAR(32) NOT NULL COMMENT 'ip address or DNS name of the gateway. For gateways providing inbound calling service, ip address is required.',
|
||||
`port` INTEGER NOT NULL DEFAULT 5060 COMMENT 'sip signaling port',
|
||||
`inbound` BOOLEAN NOT NULL COMMENT 'if true, whitelist this IP to allow inbound calls from the gateway',
|
||||
`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,
|
||||
PRIMARY KEY (`sip_gateway_sid`)
|
||||
sip_gateway_sid CHAR(36),
|
||||
ipv4 VARCHAR(128) NOT NULL COMMENT 'ip address or DNS name of the gateway. For gateways providing inbound calling service, ip address is required.',
|
||||
port INTEGER NOT NULL DEFAULT 5060 COMMENT 'sip signaling port',
|
||||
inbound BOOLEAN NOT NULL COMMENT 'if true, whitelist this IP to allow inbound calls from the gateway',
|
||||
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,
|
||||
PRIMARY KEY (sip_gateway_sid)
|
||||
) COMMENT='A whitelisted sip gateway used for origination/termination';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `applications`
|
||||
CREATE TABLE lcr_carrier_set_entry
|
||||
(
|
||||
`application_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(64) NOT NULL,
|
||||
`account_sid` CHAR(36) NOT NULL COMMENT 'account that this application belongs to',
|
||||
`call_hook_sid` CHAR(36) COMMENT 'webhook to call for inbound calls to phone numbers owned by this account',
|
||||
`call_status_hook_sid` CHAR(36) COMMENT 'webhook to call for call status events',
|
||||
`speech_synthesis_vendor` VARCHAR(64) NOT NULL DEFAULT 'google',
|
||||
`speech_synthesis_voice` VARCHAR(64) NOT NULL DEFAULT 'en-US-Wavenet-C',
|
||||
`speech_recognizer_vendor` VARCHAR(64) NOT NULL DEFAULT 'google',
|
||||
`speech_recognizer_language` VARCHAR(64) NOT NULL DEFAULT 'en-US',
|
||||
PRIMARY KEY (`application_sid`)
|
||||
lcr_carrier_set_entry_sid CHAR(36),
|
||||
workload INTEGER NOT NULL DEFAULT 1 COMMENT 'represents a proportion of traffic to send through the associated carrier; can be used for load balancing traffic across carriers with a common priority for a destination',
|
||||
lcr_route_sid CHAR(36) NOT NULL,
|
||||
voip_carrier_sid CHAR(36) NOT NULL,
|
||||
priority INTEGER NOT NULL DEFAULT 0 COMMENT 'lower priority carriers are attempted first',
|
||||
PRIMARY KEY (lcr_carrier_set_entry_sid)
|
||||
) COMMENT='An entry in the LCR routing list';
|
||||
|
||||
CREATE TABLE applications
|
||||
(
|
||||
application_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
account_sid CHAR(36) NOT NULL COMMENT 'account that this application belongs to',
|
||||
call_hook_sid CHAR(36) COMMENT 'webhook to call for inbound calls to phone numbers owned by this account',
|
||||
call_status_hook_sid CHAR(36) COMMENT 'webhook to call for call status events',
|
||||
speech_synthesis_vendor VARCHAR(64) NOT NULL DEFAULT 'google',
|
||||
speech_synthesis_language VARCHAR(12) NOT NULL DEFAULT 'en-US',
|
||||
speech_synthesis_voice VARCHAR(64),
|
||||
speech_recognizer_vendor VARCHAR(64) NOT NULL DEFAULT 'google',
|
||||
speech_recognizer_language VARCHAR(64) NOT NULL DEFAULT 'en-US',
|
||||
PRIMARY KEY (application_sid)
|
||||
) ENGINE=InnoDB COMMENT='A defined set of behaviors to be applied to phone calls ';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `service_providers`
|
||||
CREATE TABLE service_providers
|
||||
(
|
||||
`service_provider_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(64) NOT NULL UNIQUE ,
|
||||
`description` VARCHAR(255),
|
||||
`root_domain` VARCHAR(128) UNIQUE ,
|
||||
`registration_hook_sid` CHAR(36),
|
||||
PRIMARY KEY (`service_provider_sid`)
|
||||
service_provider_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
name VARCHAR(64) NOT NULL UNIQUE ,
|
||||
description VARCHAR(255),
|
||||
root_domain VARCHAR(128) UNIQUE ,
|
||||
registration_hook_sid CHAR(36),
|
||||
ms_teams_fqdn VARCHAR(255),
|
||||
PRIMARY KEY (service_provider_sid)
|
||||
) ENGINE=InnoDB COMMENT='A partition of the platform used by one service provider';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `accounts`
|
||||
CREATE TABLE accounts
|
||||
(
|
||||
`account_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(64) NOT NULL,
|
||||
`sip_realm` VARCHAR(132) UNIQUE COMMENT 'sip domain that will be used for devices registering under this account',
|
||||
`service_provider_sid` CHAR(36) NOT NULL COMMENT 'service provider that owns the customer relationship with this account',
|
||||
`registration_hook_sid` CHAR(36) COMMENT 'webhook to call when devices underr this account attempt to register',
|
||||
`device_calling_application_sid` CHAR(36) COMMENT 'application to use for outbound calling from an account',
|
||||
`is_active` BOOLEAN NOT NULL DEFAULT true,
|
||||
PRIMARY KEY (`account_sid`)
|
||||
account_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
sip_realm VARCHAR(132) UNIQUE COMMENT 'sip domain that will be used for devices registering under this account',
|
||||
service_provider_sid CHAR(36) NOT NULL COMMENT 'service provider that owns the customer relationship with this account',
|
||||
registration_hook_sid CHAR(36) COMMENT 'webhook to call when devices underr this account attempt to register',
|
||||
device_calling_application_sid CHAR(36) COMMENT 'application to use for outbound calling from an account',
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
PRIMARY KEY (account_sid)
|
||||
) ENGINE=InnoDB COMMENT='An enterprise that uses the platform for comm services';
|
||||
|
||||
CREATE INDEX `call_routes_call_route_sid_idx` ON `call_routes` (`call_route_sid`);
|
||||
ALTER TABLE `call_routes` ADD FOREIGN KEY account_sid_idxfk (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
CREATE INDEX call_route_sid_idx ON call_routes (call_route_sid);
|
||||
ALTER TABLE call_routes ADD FOREIGN KEY account_sid_idxfk (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
ALTER TABLE `call_routes` ADD FOREIGN KEY application_sid_idxfk (`application_sid`) REFERENCES `applications` (`application_sid`);
|
||||
ALTER TABLE call_routes ADD FOREIGN KEY application_sid_idxfk (application_sid) REFERENCES applications (application_sid);
|
||||
|
||||
CREATE INDEX `api_keys_api_key_sid_idx` ON `api_keys` (`api_key_sid`);
|
||||
CREATE INDEX `api_keys_account_sid_idx` ON `api_keys` (`account_sid`);
|
||||
ALTER TABLE `api_keys` ADD FOREIGN KEY account_sid_idxfk_1 (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
CREATE INDEX api_key_sid_idx ON api_keys (api_key_sid);
|
||||
CREATE INDEX account_sid_idx ON api_keys (account_sid);
|
||||
ALTER TABLE api_keys ADD FOREIGN KEY account_sid_idxfk_1 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
CREATE INDEX `api_keys_service_provider_sid_idx` ON `api_keys` (`service_provider_sid`);
|
||||
ALTER TABLE `api_keys` ADD FOREIGN KEY service_provider_sid_idxfk (`service_provider_sid`) REFERENCES `service_providers` (`service_provider_sid`);
|
||||
CREATE INDEX service_provider_sid_idx ON api_keys (service_provider_sid);
|
||||
ALTER TABLE api_keys ADD FOREIGN KEY service_provider_sid_idxfk (service_provider_sid) REFERENCES service_providers (service_provider_sid);
|
||||
|
||||
CREATE INDEX `voip_carriers_voip_carrier_sid_idx` ON `voip_carriers` (`voip_carrier_sid`);
|
||||
CREATE INDEX `voip_carriers_name_idx` ON `voip_carriers` (`name`);
|
||||
ALTER TABLE `voip_carriers` ADD FOREIGN KEY account_sid_idxfk_2 (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
CREATE INDEX ms_teams_tenant_sid_idx ON ms_teams_tenants (ms_teams_tenant_sid);
|
||||
ALTER TABLE ms_teams_tenants ADD FOREIGN KEY service_provider_sid_idxfk_1 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
|
||||
|
||||
ALTER TABLE `voip_carriers` ADD FOREIGN KEY application_sid_idxfk_1 (`application_sid`) REFERENCES `applications` (`application_sid`);
|
||||
ALTER TABLE ms_teams_tenants ADD FOREIGN KEY account_sid_idxfk_2 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
CREATE INDEX `phone_numbers_phone_number_sid_idx` ON `phone_numbers` (`phone_number_sid`);
|
||||
CREATE INDEX `phone_numbers_voip_carrier_sid_idx` ON `phone_numbers` (`voip_carrier_sid`);
|
||||
ALTER TABLE `phone_numbers` ADD FOREIGN KEY voip_carrier_sid_idxfk (`voip_carrier_sid`) REFERENCES `voip_carriers` (`voip_carrier_sid`);
|
||||
ALTER TABLE ms_teams_tenants ADD FOREIGN KEY application_sid_idxfk_1 (application_sid) REFERENCES applications (application_sid);
|
||||
|
||||
ALTER TABLE `phone_numbers` ADD FOREIGN KEY account_sid_idxfk_3 (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
CREATE INDEX tenant_fqdn_idx ON ms_teams_tenants (tenant_fqdn);
|
||||
CREATE INDEX sbc_addresses_idx_host_port ON sbc_addresses (ipv4,port);
|
||||
|
||||
ALTER TABLE `phone_numbers` ADD FOREIGN KEY application_sid_idxfk_2 (`application_sid`) REFERENCES `applications` (`application_sid`);
|
||||
CREATE INDEX sbc_address_sid_idx ON sbc_addresses (sbc_address_sid);
|
||||
CREATE INDEX service_provider_sid_idx ON sbc_addresses (service_provider_sid);
|
||||
ALTER TABLE sbc_addresses ADD FOREIGN KEY service_provider_sid_idxfk_2 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
|
||||
|
||||
CREATE INDEX `webhooks_webhook_sid_idx` ON `webhooks` (`webhook_sid`);
|
||||
ALTER TABLE `lcr_carrier_set_entry` ADD FOREIGN KEY lcr_route_sid_idxfk (`lcr_route_sid`) REFERENCES `lcr_routes` (`lcr_route_sid`);
|
||||
CREATE INDEX user_sid_idx ON users (user_sid);
|
||||
CREATE INDEX name_idx ON users (name);
|
||||
CREATE INDEX voip_carrier_sid_idx ON voip_carriers (voip_carrier_sid);
|
||||
CREATE INDEX name_idx ON voip_carriers (name);
|
||||
ALTER TABLE voip_carriers ADD FOREIGN KEY account_sid_idxfk_3 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
ALTER TABLE `lcr_carrier_set_entry` ADD FOREIGN KEY voip_carrier_sid_idxfk_1 (`voip_carrier_sid`) REFERENCES `voip_carriers` (`voip_carrier_sid`);
|
||||
ALTER TABLE voip_carriers ADD FOREIGN KEY application_sid_idxfk_2 (application_sid) REFERENCES applications (application_sid);
|
||||
|
||||
CREATE UNIQUE INDEX `sip_gateways_sip_gateway_idx_hostport` ON `sip_gateways` (`ipv4`,`port`);
|
||||
CREATE INDEX phone_number_sid_idx ON phone_numbers (phone_number_sid);
|
||||
CREATE INDEX voip_carrier_sid_idx ON phone_numbers (voip_carrier_sid);
|
||||
ALTER TABLE phone_numbers ADD FOREIGN KEY voip_carrier_sid_idxfk (voip_carrier_sid) REFERENCES voip_carriers (voip_carrier_sid);
|
||||
|
||||
ALTER TABLE `sip_gateways` ADD FOREIGN KEY voip_carrier_sid_idxfk_2 (`voip_carrier_sid`) REFERENCES `voip_carriers` (`voip_carrier_sid`);
|
||||
ALTER TABLE phone_numbers ADD FOREIGN KEY account_sid_idxfk_4 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
CREATE UNIQUE INDEX `applications_idx_name` ON `applications` (`account_sid`,`name`);
|
||||
ALTER TABLE phone_numbers ADD FOREIGN KEY application_sid_idxfk_3 (application_sid) REFERENCES applications (application_sid);
|
||||
|
||||
CREATE INDEX `applications_application_sid_idx` ON `applications` (`application_sid`);
|
||||
CREATE INDEX `applications_name_idx` ON `applications` (`name`);
|
||||
CREATE INDEX `applications_account_sid_idx` ON `applications` (`account_sid`);
|
||||
ALTER TABLE `applications` ADD FOREIGN KEY account_sid_idxfk_4 (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
CREATE INDEX webhook_sid_idx ON webhooks (webhook_sid);
|
||||
CREATE UNIQUE INDEX sip_gateway_idx_hostport ON sip_gateways (ipv4,port);
|
||||
|
||||
ALTER TABLE `applications` ADD FOREIGN KEY call_hook_sid_idxfk (`call_hook_sid`) REFERENCES `webhooks` (`webhook_sid`);
|
||||
ALTER TABLE sip_gateways ADD FOREIGN KEY voip_carrier_sid_idxfk_1 (voip_carrier_sid) REFERENCES voip_carriers (voip_carrier_sid);
|
||||
|
||||
ALTER TABLE `applications` ADD FOREIGN KEY call_status_hook_sid_idxfk (`call_status_hook_sid`) REFERENCES `webhooks` (`webhook_sid`);
|
||||
ALTER TABLE lcr_carrier_set_entry ADD FOREIGN KEY lcr_route_sid_idxfk (lcr_route_sid) REFERENCES lcr_routes (lcr_route_sid);
|
||||
|
||||
CREATE INDEX `service_providers_service_provider_sid_idx` ON `service_providers` (`service_provider_sid`);
|
||||
CREATE INDEX `service_providers_name_idx` ON `service_providers` (`name`);
|
||||
CREATE INDEX `service_providers_root_domain_idx` ON `service_providers` (`root_domain`);
|
||||
ALTER TABLE `service_providers` ADD FOREIGN KEY registration_hook_sid_idxfk (`registration_hook_sid`) REFERENCES `webhooks` (`webhook_sid`);
|
||||
ALTER TABLE lcr_carrier_set_entry ADD FOREIGN KEY voip_carrier_sid_idxfk_2 (voip_carrier_sid) REFERENCES voip_carriers (voip_carrier_sid);
|
||||
|
||||
CREATE INDEX `accounts_account_sid_idx` ON `accounts` (`account_sid`);
|
||||
CREATE INDEX `accounts_name_idx` ON `accounts` (`name`);
|
||||
CREATE INDEX `accounts_sip_realm_idx` ON `accounts` (`sip_realm`);
|
||||
CREATE INDEX `accounts_service_provider_sid_idx` ON `accounts` (`service_provider_sid`);
|
||||
ALTER TABLE `accounts` ADD FOREIGN KEY service_provider_sid_idxfk_1 (`service_provider_sid`) REFERENCES `service_providers` (`service_provider_sid`);
|
||||
CREATE UNIQUE INDEX applications_idx_name ON applications (account_sid,name);
|
||||
|
||||
ALTER TABLE `accounts` ADD FOREIGN KEY registration_hook_sid_idxfk_1 (`registration_hook_sid`) REFERENCES `webhooks` (`webhook_sid`);
|
||||
CREATE INDEX application_sid_idx ON applications (application_sid);
|
||||
CREATE INDEX account_sid_idx ON applications (account_sid);
|
||||
ALTER TABLE applications ADD FOREIGN KEY account_sid_idxfk_5 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
ALTER TABLE `accounts` ADD FOREIGN KEY device_calling_application_sid_idxfk (`device_calling_application_sid`) REFERENCES `applications` (`application_sid`);
|
||||
ALTER TABLE applications ADD FOREIGN KEY call_hook_sid_idxfk (call_hook_sid) REFERENCES webhooks (webhook_sid);
|
||||
|
||||
ALTER TABLE applications ADD FOREIGN KEY call_status_hook_sid_idxfk (call_status_hook_sid) REFERENCES webhooks (webhook_sid);
|
||||
|
||||
CREATE INDEX service_provider_sid_idx ON service_providers (service_provider_sid);
|
||||
CREATE INDEX name_idx ON service_providers (name);
|
||||
CREATE INDEX root_domain_idx ON service_providers (root_domain);
|
||||
ALTER TABLE service_providers ADD FOREIGN KEY registration_hook_sid_idxfk (registration_hook_sid) REFERENCES webhooks (webhook_sid);
|
||||
|
||||
CREATE INDEX account_sid_idx ON accounts (account_sid);
|
||||
CREATE INDEX sip_realm_idx ON accounts (sip_realm);
|
||||
CREATE INDEX service_provider_sid_idx ON accounts (service_provider_sid);
|
||||
ALTER TABLE accounts ADD FOREIGN KEY service_provider_sid_idxfk_3 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
|
||||
|
||||
ALTER TABLE accounts ADD FOREIGN KEY registration_hook_sid_idxfk_1 (registration_hook_sid) REFERENCES webhooks (webhook_sid);
|
||||
|
||||
ALTER TABLE accounts ADD FOREIGN KEY device_calling_application_sid_idxfk (device_calling_application_sid) REFERENCES applications (application_sid);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
|
||||
@@ -27,6 +27,7 @@ services:
|
||||
|
||||
rtpengine:
|
||||
image: drachtio/rtpengine:latest
|
||||
command: rtpengine --interface private/172.39.0.12 --interface public/172.39.0.12!172.39.0.12
|
||||
ports:
|
||||
- "12222:22222/udp"
|
||||
networks:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
const test = require('tape').test ;
|
||||
const test = require('blue-tape');
|
||||
//const test = require('tape').test ;
|
||||
const exec = require('child_process').exec ;
|
||||
const async = require('async');
|
||||
|
||||
test('starting docker network..', (t) => {
|
||||
exec(`docker-compose -f ${__dirname}/docker-compose-testbed.yaml up -d`, (err, stdout, stderr) => {
|
||||
t.pass('docker started');
|
||||
t.end(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
const test = require('tape').test ;
|
||||
const test = require('blue-tape');
|
||||
//const test = require('tape').test ;
|
||||
const exec = require('child_process').exec ;
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const test = require('tape').test ;
|
||||
const test = require('blue-tape') ;
|
||||
const exec = require('child_process').exec ;
|
||||
const pwd = process.env.TRAVIS ? '' : '-p$MYSQL_ROOT_PASSWORD';
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
<send retrans="500" start_txn="invite">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:16173333456@jambonz.org SIP/2.0
|
||||
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@jambonz.org>
|
||||
To: <sip:16173333456@127.0.0.1>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:16173333456@jambonz.org SIP/2.0
|
||||
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@jambonz.org>
|
||||
To: <sip:16173333456@127.0.0.1>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
@@ -43,10 +43,10 @@
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:sip:+16173333456@jambonz.org SIP/2.0
|
||||
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@jambonz.org>[peer_tag_param]
|
||||
To: <sip:sip:+16173333456@127.0.0.1>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 ACK
|
||||
Subject: uac-pcap-carrier-success
|
||||
@@ -122,10 +122,10 @@
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
BYE sip:sip:+16173333456@jambonz.org SIP/2.0
|
||||
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@jambonz.org>[peer_tag_param]
|
||||
To: <sip:sip:+16173333456@127.0.0.1>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 3 BYE
|
||||
Max-Forwards: 70
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:16173333456@jambonz.org SIP/2.0
|
||||
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@jambonz.org>
|
||||
To: <sip:16173333456@127.0.0.1>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
@@ -43,10 +43,10 @@
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:sip:+16173333456@jambonz.org SIP/2.0
|
||||
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@jambonz.org>[peer_tag_param]
|
||||
To: <sip:sip:+16173333456@127.0.0.1>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 ACK
|
||||
Subject: uac-pcap-carrier-success
|
||||
@@ -69,10 +69,10 @@
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
BYE sip:sip:+16173333456@jambonz.org SIP/2.0
|
||||
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@jambonz.org>[peer_tag_param]
|
||||
To: <sip:sip:+16173333456@127.0.0.1>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 2 BYE
|
||||
Max-Forwards: 70
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:jane@jambonz.org SIP/2.0
|
||||
INVITE sip:jane@sip.example.com 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:jane@jambonz.org>
|
||||
To: <sip:jane@sip.example.com>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
@@ -62,10 +62,10 @@
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:sip:jane@jambonz.org SIP/2.0
|
||||
ACK sip:sip:jane@sip.example.com SIP/2.0
|
||||
[last_Via]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: <sip:sip:jane@jambonz.org>[peer_tag_param]
|
||||
To: <sip:sip:jane@sip.example.com>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 ACK
|
||||
Subject: uac-pcap-device-success
|
||||
|
||||
@@ -21,20 +21,6 @@ test('sbc-outbound tests', async(t) => {
|
||||
|
||||
try {
|
||||
await connect(srf);
|
||||
|
||||
// for now, the docker image for sbc-registrar needs a mysql database..
|
||||
// TODO: figure out how to add that into the docker network and build the schema there
|
||||
/* send a registration from 172.39.0.31 */
|
||||
//await sippUac('uac-register-auth-success.xml', {ip: '172.39.0.31', data_file: 'good_user.csv'});
|
||||
//t.pass('sip user/device registered over udp');
|
||||
|
||||
/* now start a sipp service waiting on 172.39.0.31 for an INVITE */
|
||||
//const p = sippUac('uas.xml', {ip: '172.39.0.31'});
|
||||
|
||||
/* now send an outbound call from the appserver targeted to the user that registered from 172.39.0.31 */
|
||||
//await sippUac('uac-pcap-device-success.xml');
|
||||
//await p;
|
||||
//t.pass('successfully completed outbound call to the registered user/devices');
|
||||
|
||||
/* call to unregistered user */
|
||||
await sippUac('uac-pcap-device-404.xml');
|
||||
|
||||
Reference in New Issue
Block a user