mirror of
https://github.com/jambonz/sbc-inbound.git
synced 2026-10-04 02:04:22 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3963bf057 | ||
|
|
238f3fe05a | ||
|
|
51e926629c | ||
|
|
3df94ced57 | ||
|
|
62063a7250 | ||
|
|
3d58fdd242 | ||
|
|
12ba6b3968 | ||
|
|
ae8469cfee | ||
|
|
bf7c09fc83 | ||
|
|
4476c233ff | ||
|
|
45883238e1 | ||
|
|
471f3dc0bb | ||
|
|
5ba9058216 | ||
|
|
6f82454be2 | ||
|
|
5f60580040 | ||
|
|
d0b0feafdc | ||
|
|
b3e38ab761 | ||
|
|
ee16cdd859 | ||
|
|
28cfe27b58 | ||
|
|
e1ea9dbdf2 | ||
|
|
3fdbeb64f8 | ||
|
|
2204140291 | ||
|
|
f01d2140db | ||
|
|
ae9b4acf19 | ||
|
|
09a1386283 |
+1
-1
@@ -8,7 +8,7 @@
|
||||
"jsx": false,
|
||||
"modules": false
|
||||
},
|
||||
"ecmaVersion": 2017
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"plugins": ["promise"],
|
||||
"rules": {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
- run: npm install
|
||||
- run: npm run jslint
|
||||
- run: npm test
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
sudo: required
|
||||
language: node_js
|
||||
node_js:
|
||||
- "lts/*"
|
||||
services:
|
||||
- docker
|
||||
- mysql
|
||||
script:
|
||||
- npm test
|
||||
+10
-7
@@ -1,13 +1,16 @@
|
||||
FROM node:lts-alpine
|
||||
FROM node:alpine as builder
|
||||
RUN apk update && apk add --no-cache python make g++
|
||||
WORKDIR /opt/app/
|
||||
COPY package.json ./
|
||||
RUN npm install
|
||||
RUN npm prune
|
||||
|
||||
RUN mkdir -p /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
FROM node:alpine as app
|
||||
WORKDIR /opt/app
|
||||
COPY . /opt/app
|
||||
COPY --from=builder /opt/app/node_modules ./node_modules
|
||||
|
||||
ARG NODE_ENV
|
||||
ENV NODE_ENV $NODE_ENV
|
||||
|
||||
COPY package.json /usr/src/app/
|
||||
RUN npm install
|
||||
COPY . /usr/src/app
|
||||
|
||||
CMD [ "npm", "start" ]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# sbc-inbound [](http://travis-ci.org/jambonz/sbc-inbound)
|
||||
# sbc-inbound 
|
||||
|
||||
This application provides a part of the SBC (Session Border Controller) functionality of jambonz. It handles incoming INVITE requests from carrier sip trunks or from sip devices and webrtc applications. SIP INVITEs from known carriers are allowed in, while INVITEs from sip devices are challenged to authenticate. SIP traffic that is allowed in is sent on to a jambonz application server in a private subnet.
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ 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);
|
||||
srf.locals.getFeatureServer = require('./lib/fs-tracking')(srf, logger);
|
||||
const {getRtpEngine} = require('jambonz-rtpengine-utils')(process.env.JAMBONES_RTPENGINES.split(','), logger, {
|
||||
const {getRtpEngine} = require('@jambonz/rtpengine-utils')(process.env.JAMBONES_RTPENGINES.split(','), logger, {
|
||||
emitter: srf.locals.stats
|
||||
});
|
||||
srf.locals.getRtpEngine = getRtpEngine;
|
||||
|
||||
+42
-26
@@ -79,10 +79,17 @@ class CallSession extends Emitter {
|
||||
this.logger.info(`uri will be: ${uri}, proxy ${proxy}`);
|
||||
|
||||
try {
|
||||
const response = await this.offer(this.rtpEngineOpts.offer);
|
||||
debug(`response from rtpengine to offer ${JSON.stringify(response)}`);
|
||||
const opts = {
|
||||
...this.rtpEngineOpts.common,
|
||||
...this.rtpEngineOpts.uac.mediaOpts,
|
||||
'from-tag': this.rtpEngineOpts.uas.tag,
|
||||
direction: ['public', 'private'],
|
||||
sdp: this.req.body
|
||||
};
|
||||
const response = await this.offer(opts);
|
||||
this.logger.debug({opts, response}, 'response from rtpengine to offer');
|
||||
if ('ok' !== response.result) {
|
||||
this.logger.error(`rtpengine offer failed with ${JSON.stringify(response)}`);
|
||||
this.logger.error({}, `rtpengine offer failed with ${JSON.stringify(response)}`);
|
||||
throw new Error('rtpengine failed: answer');
|
||||
}
|
||||
|
||||
@@ -124,12 +131,18 @@ class CallSession extends Emitter {
|
||||
proxy,
|
||||
headers,
|
||||
responseHeaders,
|
||||
proxyRequestHeaders: ['all', '-Authorization', '-Max-Forwards', '-Record-Route'],
|
||||
proxyRequestHeaders: ['all', '-Authorization', '-Max-Forwards', '-Record-Route', '-Session-Expires', 'Min-SE'],
|
||||
proxyResponseHeaders: ['all'],
|
||||
localSdpB: response.sdp,
|
||||
localSdpA: async(sdp, res) => {
|
||||
this.toTag = res.getParsedHeader('To').params.tag;
|
||||
const opts = Object.assign({sdp, 'to-tag': this.toTag}, this.rtpEngineOpts.answer);
|
||||
this.rtpEngineOpts.uac.tag = res.getParsedHeader('To').params.tag;
|
||||
const opts = {
|
||||
...this.rtpEngineOpts.common,
|
||||
...this.rtpEngineOpts.uas.mediaOpts,
|
||||
'from-tag': this.rtpEngineOpts.uas.tag,
|
||||
'to-tag': this.rtpEngineOpts.uac.tag,
|
||||
sdp
|
||||
};
|
||||
const response = await this.answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
this.logger.error(`rtpengine answer failed with ${JSON.stringify(response)}`);
|
||||
@@ -141,7 +154,6 @@ class CallSession extends Emitter {
|
||||
|
||||
// successfully connected
|
||||
this.logger.info('call connected successfully to feature server');
|
||||
this.toTag = uas.sip.localTag;
|
||||
this._setHandlers({uas, uac});
|
||||
return;
|
||||
} catch (err) {
|
||||
@@ -190,8 +202,8 @@ class CallSession extends Emitter {
|
||||
});
|
||||
});
|
||||
uas.on('modify', this._onReinvite.bind(this, uas));
|
||||
uac.on('modify', this._onReinvite.bind(this, uac));
|
||||
|
||||
uac.on('modify', this._onFeatureServerReinvite.bind(this, uac));
|
||||
uac.on('refer', this._onFeatureServerTransfer.bind(this, uac));
|
||||
uas.on('refer', this._onRefer.bind(this, uas));
|
||||
|
||||
@@ -215,6 +227,7 @@ class CallSession extends Emitter {
|
||||
this.logger.info({opts, response}, 'sent offer for reinvite to rtpengine');
|
||||
const sdp = await this.uac.modify(response.sdp);
|
||||
opts = Object.assign(this.rtpEngineOpts.answer, {sdp, 'to-tag': this.toTag});
|
||||
Object.assign(this.rtpEngineOpts.offer, {'to-tag': this.toTag});
|
||||
response = await this.answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
@@ -252,41 +265,44 @@ class CallSession extends Emitter {
|
||||
|
||||
async _onReinvite(dlg, req, res) {
|
||||
try {
|
||||
let opts = Object.assign(this.rtpEngineOpts.offer, {sdp: req.body});
|
||||
const fromTag = dlg.type === 'uas' ? this.rtpEngineOpts.uas.tag : this.rtpEngineOpts.uac.tag;
|
||||
const toTag = dlg.type === 'uas' ? this.rtpEngineOpts.uac.tag : this.rtpEngineOpts.uas.tag;
|
||||
const offerMedia = dlg.type === 'uas' ? this.rtpEngineOpts.uac.mediaOpts : this.rtpEngineOpts.uas.mediaOpts;
|
||||
const answerMedia = dlg.type === 'uas' ? this.rtpEngineOpts.uas.mediaOpts : this.rtpEngineOpts.uac.mediaOpts;
|
||||
const direction = dlg.type === 'uas' ? ['private', 'public'] : ['public', 'private'];
|
||||
let opts = {
|
||||
...this.rtpEngineOpts.common,
|
||||
...offerMedia,
|
||||
'from-tag': fromTag,
|
||||
'to-tag': toTag,
|
||||
direction,
|
||||
sdp: req.body,
|
||||
};
|
||||
|
||||
let response = await this.offer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onReinvite: rtpengine failed: offer: ${JSON.stringify(response)}`);
|
||||
}
|
||||
this.logger.info({opts, response}, 'sent offer for reinvite to rtpengine');
|
||||
const sdp = await dlg.other.modify(response.sdp);
|
||||
opts = Object.assign({sdp, 'to-tag': this.toTag}, this.rtpEngineOpts.answer);
|
||||
opts = {
|
||||
...this.rtpEngineOpts.common,
|
||||
...answerMedia,
|
||||
'from-tag': fromTag,
|
||||
'to-tag': toTag,
|
||||
sdp
|
||||
};
|
||||
response = await this.answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onReinvite: rtpengine failed: ${JSON.stringify(response)}`);
|
||||
}
|
||||
this.logger.info({opts, response}, 'sent answer for reinvite to rtpengine');
|
||||
res.send(200, {body: response.sdp});
|
||||
} catch (err) {
|
||||
this.logger.error(err, 'Error handling reinvite');
|
||||
}
|
||||
}
|
||||
|
||||
async _onFeatureServerReinvite(dlg, req, res) {
|
||||
try {
|
||||
const opts = Object.assign({sdp: req.body, 'to-tag': this.toTag}, this.rtpEngineOpts.answer);
|
||||
const response = await this.answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onFeatureServerReinvite: rtpengine failed: ${JSON.stringify(response)}`);
|
||||
}
|
||||
res.send(200, {body: dlg.local.sdp});
|
||||
} catch (err) {
|
||||
this.logger.error(err, 'Error handling reinvite from feature server');
|
||||
}
|
||||
}
|
||||
|
||||
async _onFeatureServerTransfer(dlg, req, res) {
|
||||
try {
|
||||
const referTo = req.getParsedHeader('Refer-To');
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ module.exports = (srf, logger) => {
|
||||
const stats = srf.locals.stats;
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
|
||||
|
||||
const {createSet} = require('jambonz-realtimedb-helpers')({
|
||||
const {createSet} = require('@jambonz/realtimedb-helpers')({
|
||||
host: process.env.JAMBONES_REDIS_HOST || 'localhost',
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
}, logger);
|
||||
|
||||
+4
-2
@@ -1,7 +1,9 @@
|
||||
const debug = require('debug')('jambonz:sbc-inbound');
|
||||
const Emitter = require('events');
|
||||
const parseUri = require('drachtio-srf').parseUri;
|
||||
const msProxyIps = process.env.MS_TEAMS_SIP_PROXY_IPS ? process.env.MS_TEAMS_SIP_PROXY_IPS.split(',').map((i) => i.trim()) : [];
|
||||
const msProxyIps = process.env.MS_TEAMS_SIP_PROXY_IPS ?
|
||||
process.env.MS_TEAMS_SIP_PROXY_IPS.split(',').map((i) => i.trim()) :
|
||||
[];
|
||||
|
||||
class AuthOutcomeReporter extends Emitter {
|
||||
constructor(stats) {
|
||||
@@ -15,7 +17,7 @@ class AuthOutcomeReporter extends Emitter {
|
||||
module.exports = function(srf, logger) {
|
||||
const {lookupSipGatewayBySignalingAddress, lookupAuthHook} = srf.locals.dbHelpers;
|
||||
const {stats} = srf.locals;
|
||||
const authenticator = require('jambonz-http-authenticator')(lookupAuthHook, logger, {
|
||||
const authenticator = require('@jambonz/http-authenticator')(lookupAuthHook, logger, {
|
||||
blacklistUnknownRealms: true,
|
||||
emitter: new AuthOutcomeReporter(stats)
|
||||
});
|
||||
|
||||
+15
-10
@@ -12,19 +12,24 @@ function getAppserver(srf) {
|
||||
}
|
||||
|
||||
function makeRtpEngineOpts(req, srcIsUsingSrtp, dstIsUsingSrtp, teams = false) {
|
||||
const srtpOpts = teams ? srtpCharacteristics['teams'] : srtpCharacteristics['default'];
|
||||
const from = req.getParsedHeader('from');
|
||||
const common = {'call-id': req.get('Call-ID'), 'from-tag': from.params.tag};
|
||||
const srtpOpts = teams ? srtpCharacteristics['teams'] : srtpCharacteristics['default'];
|
||||
const dstOpts = dstIsUsingSrtp ? srtpOpts : rtpCharacteristics;
|
||||
const srctOpts = srcIsUsingSrtp ? srtpOpts : rtpCharacteristics;
|
||||
const common = {
|
||||
'call-id': req.get('Call-ID'),
|
||||
'replace': ['origin', 'session-connection']
|
||||
};
|
||||
return {
|
||||
common,
|
||||
offer: Object.assign(
|
||||
{'sdp': req.body, 'replace': ['origin', 'session-connection']},
|
||||
common,
|
||||
dstIsUsingSrtp ? srtpOpts : rtpCharacteristics),
|
||||
answer: Object.assign(
|
||||
{'replace': ['origin', 'session-connection']},
|
||||
common,
|
||||
srcIsUsingSrtp ? srtpOpts : rtpCharacteristics)
|
||||
uas: {
|
||||
tag: from.params.tag,
|
||||
mediaOpts: srctOpts
|
||||
},
|
||||
uac: {
|
||||
tag: null,
|
||||
mediaOpts: dstOpts
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Generated
+5594
-1336
File diff suppressed because it is too large
Load Diff
+13
-13
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sbc-inbound",
|
||||
"version": "0.3.2",
|
||||
"version": "0.3.6",
|
||||
"main": "app.js",
|
||||
"engines": {
|
||||
"node": ">= 10.16.0"
|
||||
@@ -20,28 +20,28 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node app",
|
||||
"test": "NODE_ENV=test JAMBONES_MYSQL_HOST=localhost JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=localhost JAMBONES_REDIS_PORT=16379 JAMBONES_LOGLEVEL=error DRACHTIO_SECRET=cymru DRACHTIO_HOST=127.0.0.1 DRACHTIO_PORT=9060 JAMBONES_RTPENGINES=127.0.0.1:12222 JAMBONES_FEATURE_SERVERS=172.38.0.11 node test/ | ./node_modules/.bin/tap-spec",
|
||||
"test": "NODE_ENV=test JAMBONES_MYSQL_HOST=127.0.0.1 JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=localhost JAMBONES_REDIS_PORT=16379 JAMBONES_LOGLEVEL=error DRACHTIO_SECRET=cymru DRACHTIO_HOST=127.0.0.1 DRACHTIO_PORT=9060 JAMBONES_RTPENGINES=127.0.0.1:12222 JAMBONES_FEATURE_SERVERS=172.38.0.11 node test/ | ./node_modules/.bin/tap-spec",
|
||||
"coverage": "./node_modules/.bin/nyc --reporter html --report-dir ./coverage npm run test",
|
||||
"jslint": "eslint app.js lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"@jambonz/db-helpers": "^0.5.12",
|
||||
"@jambonz/http-authenticator": "^0.1.6",
|
||||
"@jambonz/realtimedb-helpers": "^0.2.20",
|
||||
"@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.33",
|
||||
"@jambonz/db-helpers": "^0.3.6",
|
||||
"jambonz-http-authenticator": "0.1.5",
|
||||
"jambonz-realtimedb-helpers": "^0.2.4",
|
||||
"jambonz-rtpengine-utils": "0.1.1",
|
||||
"jambonz-stats-collector": "0.0.3",
|
||||
"pino": "^5.14.0",
|
||||
"rtpengine-client": "^0.0.8"
|
||||
"drachtio-srf": "^4.4.44",
|
||||
"pino": "^6.8.0",
|
||||
"rtpengine-client": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"blue-tape": "^1.0.0",
|
||||
"clear-module": "^4.1.1",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"nyc": "^15.0.1",
|
||||
"nyc": "^15.1.0",
|
||||
"tap-spec": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
const test = require('tape').test ;
|
||||
const exec = require('child_process').exec ;
|
||||
const pwd = process.env.TRAVIS ? '' : '-p$MYSQL_ROOT_PASSWORD';
|
||||
|
||||
test('creating jambones_test database', (t) => {
|
||||
exec(`mysql -h localhost -u root ${pwd} < ${__dirname}/db/create_test_db.sql`, (err, stdout, stderr) => {
|
||||
exec(`mysql -h 127.0.0.1 -u root --protocol=tcp < ${__dirname}/db/create_test_db.sql`, (err, stdout, stderr) => {
|
||||
if (err) return t.end(err);
|
||||
t.pass('database successfully created');
|
||||
t.end();
|
||||
@@ -11,7 +10,7 @@ test('creating jambones_test database', (t) => {
|
||||
});
|
||||
|
||||
test('creating schema', (t) => {
|
||||
exec(`mysql -h localhost -u root ${pwd} -D jambones_test < ${__dirname}/db/jambones-sql.sql`, (err, stdout, stderr) => {
|
||||
exec(`mysql -h 127.0.0.1 -u root --protocol=tcp -D jambones_test < ${__dirname}/db/jambones-sql.sql`, (err, stdout, stderr) => {
|
||||
if (err) return t.end(err);
|
||||
t.pass('schema successfully created');
|
||||
t.end();
|
||||
@@ -19,7 +18,7 @@ test('creating schema', (t) => {
|
||||
});
|
||||
|
||||
test('populating test case data', (t) => {
|
||||
exec(`mysql -h localhost -u root ${pwd} -D jambones_test < ${__dirname}/db/populate-test-data.sql`, (err, stdout, stderr) => {
|
||||
exec(`mysql -h 127.0.0.1 -u root --protocol=tcp -D jambones_test < ${__dirname}/db/populate-test-data.sql`, (err, stdout, stderr) => {
|
||||
if (err) return t.end(err);
|
||||
t.pass('test data set created');
|
||||
t.end();
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
create database jambones_test;
|
||||
create user jambones_test@localhost IDENTIFIED WITH mysql_native_password by 'jambones_test';
|
||||
grant all on jambones_test.* to jambones_test@localhost;
|
||||
create user jambones_test@'%' IDENTIFIED WITH mysql_native_password by 'jambones_test';
|
||||
grant all on jambones_test.* to jambones_test@'%';
|
||||
|
||||
+39
-29
@@ -1,6 +1,6 @@
|
||||
/* SQLEditor (MySQL (2))*/
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
DROP TABLE IF EXISTS call_routes;
|
||||
|
||||
@@ -8,10 +8,10 @@ DROP TABLE IF EXISTS lcr_carrier_set_entry;
|
||||
|
||||
DROP TABLE IF EXISTS lcr_routes;
|
||||
|
||||
DROP TABLE IF EXISTS ms_teams_tenants;
|
||||
|
||||
DROP TABLE IF EXISTS api_keys;
|
||||
|
||||
DROP TABLE IF EXISTS ms_teams_tenants;
|
||||
|
||||
DROP TABLE IF EXISTS sbc_addresses;
|
||||
|
||||
DROP TABLE IF EXISTS users;
|
||||
@@ -22,16 +22,14 @@ DROP TABLE IF EXISTS sip_gateways;
|
||||
|
||||
DROP TABLE IF EXISTS voip_carriers;
|
||||
|
||||
DROP TABLE IF EXISTS applications;
|
||||
|
||||
DROP TABLE IF EXISTS accounts;
|
||||
|
||||
DROP TABLE IF EXISTS applications;
|
||||
|
||||
DROP TABLE IF EXISTS service_providers;
|
||||
|
||||
DROP TABLE IF EXISTS webhooks;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
CREATE TABLE call_routes
|
||||
(
|
||||
call_route_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
@@ -51,26 +49,28 @@ priority INTEGER NOT NULL UNIQUE COMMENT 'lower priority routes are attempted f
|
||||
PRIMARY KEY (lcr_route_sid)
|
||||
) COMMENT='Least cost routing table';
|
||||
|
||||
CREATE TABLE ms_teams_tenants
|
||||
(
|
||||
ms_teams_tenant_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
service_provider_sid CHAR(36) NOT NULL,
|
||||
account_sid CHAR(36),
|
||||
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 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),
|
||||
expires_at TIMESTAMP,
|
||||
expires_at TIMESTAMP NULL DEFAULT NULL,
|
||||
last_used TIMESTAMP NULL DEFAULT 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 ms_teams_tenants
|
||||
(
|
||||
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 ,
|
||||
@@ -97,6 +97,11 @@ 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,
|
||||
requires_register BOOLEAN NOT NULL DEFAULT false,
|
||||
register_username VARCHAR(64),
|
||||
register_sip_realm VARCHAR(64),
|
||||
register_password VARCHAR(64),
|
||||
PRIMARY KEY (voip_carrier_sid)
|
||||
) ENGINE=InnoDB COMMENT='A Carrier or customer PBX that can send or receive calls';
|
||||
|
||||
@@ -147,8 +152,9 @@ 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_hook_sid CHAR(36) COMMENT 'webhook to call for inbound calls ',
|
||||
call_status_hook_sid CHAR(36) COMMENT 'webhook to call for call status events',
|
||||
messaging_hook_sid CHAR(36) COMMENT 'webhook to call for inbound SMS/MMS ',
|
||||
speech_synthesis_vendor VARCHAR(64) NOT NULL DEFAULT 'google',
|
||||
speech_synthesis_language VARCHAR(12) NOT NULL DEFAULT 'en-US',
|
||||
speech_synthesis_voice VARCHAR(64),
|
||||
@@ -185,21 +191,21 @@ ALTER TABLE call_routes ADD FOREIGN KEY account_sid_idxfk (account_sid) REFERENC
|
||||
|
||||
ALTER TABLE call_routes ADD FOREIGN KEY application_sid_idxfk (application_sid) REFERENCES applications (application_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 (service_provider_sid) REFERENCES service_providers (service_provider_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);
|
||||
|
||||
ALTER TABLE ms_teams_tenants ADD FOREIGN KEY account_sid_idxfk_1 (account_sid) REFERENCES accounts (account_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 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 ms_teams_tenants ADD FOREIGN KEY account_sid_idxfk_2 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
ALTER TABLE ms_teams_tenants ADD FOREIGN KEY application_sid_idxfk_1 (application_sid) REFERENCES applications (application_sid);
|
||||
|
||||
CREATE INDEX tenant_fqdn_idx ON ms_teams_tenants (tenant_fqdn);
|
||||
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_2 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
CREATE INDEX service_provider_sid_idx ON api_keys (service_provider_sid);
|
||||
ALTER TABLE api_keys ADD FOREIGN KEY service_provider_sid_idxfk_1 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
|
||||
|
||||
CREATE INDEX sbc_addresses_idx_host_port ON sbc_addresses (ipv4,port);
|
||||
|
||||
CREATE INDEX sbc_address_sid_idx ON sbc_addresses (sbc_address_sid);
|
||||
@@ -241,6 +247,8 @@ ALTER TABLE applications ADD FOREIGN KEY call_hook_sid_idxfk (call_hook_sid) REF
|
||||
|
||||
ALTER TABLE applications ADD FOREIGN KEY call_status_hook_sid_idxfk (call_status_hook_sid) REFERENCES webhooks (webhook_sid);
|
||||
|
||||
ALTER TABLE applications ADD FOREIGN KEY messaging_hook_sid_idxfk (messaging_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);
|
||||
@@ -254,3 +262,5 @@ ALTER TABLE accounts ADD FOREIGN KEY service_provider_sid_idxfk_3 (service_provi
|
||||
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;
|
||||
|
||||
@@ -7,7 +7,7 @@ values ('ed649e33-e771-403a-8c99-1780eabbc803', '3f35518f-5a0d-4c2e-90a5-2407bb3
|
||||
|
||||
insert into voip_carriers (voip_carrier_sid, name) values ('287c1452-620d-4195-9f19-c9814ef90d78', 'westco');
|
||||
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.38.0.20', true, true);
|
||||
values ('124a5339-c62c-4075-9e19-f4de70a96597', '287c1452-620d-4195-9f19-c9814ef90d78', '172.38.0.20/32', true, true);
|
||||
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, port, inbound, outbound)
|
||||
values ('efbc4830-57cd-4c78-a56f-d64fdf210fe8', '287c1452-620d-4195-9f19-c9814ef90d78', '3.3.3.3', 5062, false, true);
|
||||
|
||||
|
||||
@@ -7,7 +7,20 @@ networks:
|
||||
config:
|
||||
- subnet: 172.38.0.0/16
|
||||
|
||||
services:
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
ports:
|
||||
- "3306:3306"
|
||||
environment:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "--protocol", "tcp"]
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
sbc-inbound:
|
||||
ipv4_address: 172.38.0.2
|
||||
sbc:
|
||||
image: drachtio/drachtio-server:latest
|
||||
command: drachtio --contact "sip:*;transport=udp" --loglevel debug --sofia-loglevel 9
|
||||
@@ -16,6 +29,9 @@ services:
|
||||
networks:
|
||||
sbc-inbound:
|
||||
ipv4_address: 172.38.0.10
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
appserver:
|
||||
image: drachtio/sipp:latest
|
||||
@@ -47,6 +63,7 @@ services:
|
||||
|
||||
rtpengine:
|
||||
image: drachtio/rtpengine:latest
|
||||
command: rtpengine --interface private/172.38.0.14 --interface public/172.38.0.14!172.38.0.14
|
||||
ports:
|
||||
- "12222:22222/udp"
|
||||
networks:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
require('./docker_start');
|
||||
require('./create-test-db');
|
||||
require('./sip-tests');
|
||||
require('./remove-test-db');
|
||||
require('./docker_stop');
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
const test = require('tape').test ;
|
||||
const exec = require('child_process').exec ;
|
||||
const pwd = process.env.TRAVIS ? '' : '-p$MYSQL_ROOT_PASSWORD';
|
||||
|
||||
test('dropping jambones_test database', (t) => {
|
||||
exec(`mysql -h localhost -u root ${pwd} < ${__dirname}/db/remove_test_db.sql`, (err, stdout, stderr) => {
|
||||
if (err) return t.end(err);
|
||||
t.pass('database successfully dropped');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
const { spawn } = require('child_process');
|
||||
const debug = require('debug')('test:sipp');
|
||||
const debug = require('debug')('jambonz:ci');
|
||||
let network;
|
||||
const obj = {};
|
||||
let output = '';
|
||||
@@ -27,7 +27,7 @@ obj.output = () => {
|
||||
obj.sippUac = (file, bindAddress) => {
|
||||
const cmd = 'docker';
|
||||
const args = [
|
||||
'run', '-ti', '--rm', '--net', `${network}`,
|
||||
'run', '--rm', '--net', `${network}`,
|
||||
'-v', `${__dirname}/scenarios:/tmp/scenarios`,
|
||||
'drachtio/sipp', 'sipp', '-sf', `/tmp/scenarios/${file}`,
|
||||
'-m', '1',
|
||||
@@ -37,7 +37,7 @@ obj.sippUac = (file, bindAddress) => {
|
||||
'sbc'
|
||||
];
|
||||
|
||||
if (bindAddress) args.splice(5, 0, '--ip', bindAddress);
|
||||
if (bindAddress) args.splice(4, 0, '--ip', bindAddress);
|
||||
|
||||
//console.log(args.join(' '));
|
||||
clearOutput();
|
||||
@@ -57,11 +57,11 @@ obj.sippUac = (file, bindAddress) => {
|
||||
});
|
||||
|
||||
child_process.stdout.on('data', (data) => {
|
||||
//debug(`stdout: ${data}`);
|
||||
debug(`stderr: ${data}`);
|
||||
addOutput(data.toString());
|
||||
});
|
||||
child_process.stdout.on('data', (data) => {
|
||||
//debug(`stdout: ${data}`);
|
||||
child_process.stderr.on('data', (data) => {
|
||||
debug(`stderr: ${data}`);
|
||||
addOutput(data.toString());
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user