Compare commits

..
12 Commits
Author SHA1 Message Date
Dave Horton d5a1337811 bugfix: connection to drachtio was not closed on non-success response to invite (#27) 2022-03-18 14:04:52 -04:00
Snyk bot a6571134cd fix: Dockerfile to reduce vulnerabilities (#26)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-DEBIAN11-GNUTLS28-2419151
- https://snyk.io/vuln/SNYK-DEBIAN11-OPENSSL-2388380
- https://snyk.io/vuln/SNYK-DEBIAN11-OPENSSL-2426309
- https://snyk.io/vuln/SNYK-DEBIAN11-UTILLINUX-2401081
- https://snyk.io/vuln/SNYK-DEBIAN11-UTILLINUX-2401081
2022-03-18 07:54:19 -04:00
Dave Horton e0e5c75496 bump version 2022-03-08 20:15:17 -05:00
Dave Horton c08e35c261 Feature/incoming refer (#25)
* handle incoming REFER and send on to the FS

* clarity
2022-03-05 15:22:11 -05:00
Dave Horton 883c63723c update to dbhelpers with support for searching root domains to identify account 2022-02-17 20:59:17 -05:00
Dave Horton 13f78bf8d9 added pre-commit hook for linting 2022-02-14 13:18:04 -05:00
Dave Horton 55056c1771 bump version 2022-02-09 15:43:40 -05:00
Dave Horton 87ec5f8e09 update to latest @jambonz/realtimedb-helpers with support for redis username / password auth 2022-02-09 15:13:54 -05:00
Dave Horton 317280befc update deps 2022-02-09 08:22:14 -05:00
Dave Horton 7b97a0a137 0.7.2 version 2022-01-28 09:12:35 -05:00
Dave Horton 75d8381ebb Feature/rtpengine locate by dns (#22)
* initial changes to use udp and dns in K8s for rtpengine ng

* github actions

* logging

* remove port from service name before dns lookup

* query rtpengine dns immediately on startup

* bugfix prev checkin

* use dns.lookup instead of resolve4 (k8s does not appear to consult search patterns in resolve.conf with the latter)

* return all rtpengine endpoints in dns lookup

* bugfix: polling rtpengine endpoints

* fix prev commit

* catch error on rtpengine failure

* update deps

* require node 14 in gh action build

* specify node version in gh actions
2022-01-23 18:03:11 -05:00
Dave Horton 7750fdc3f2 healthcheck only in k8s 2022-01-22 21:44:14 -05:00
9 changed files with 2297 additions and 426 deletions
@@ -11,8 +11,8 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- run: npm install
node-version: 14.x
- run: npm ci
- run: npm run jslint
- run: npm test
+1 -1
View File
@@ -1,7 +1,7 @@
# Logs
logs
*.log
.vscode/
# Runtime data
pids
*.pid
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run jslint
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:17-slim
FROM node:17.7.1-slim
WORKDIR /opt/app/
COPY package.json ./
RUN npm install
+44 -25
View File
@@ -26,6 +26,7 @@ const {
});
const StatsCollector = require('@jambonz/stats-collector');
const stats = new StatsCollector(logger);
const {equalsIgnoreOrder} = require('./lib/utils');
const {LifeCycleEvents} = require('./lib/constants');
const setNameRtp = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-rtp`;
const rtpServers = [];
@@ -56,7 +57,7 @@ const {createSet, retrieveSet, addToSet, removeFromSet, incrKey, decrKey} = requ
const {getRtpEngine, setRtpEngines} = require('@jambonz/rtpengine-utils')([], logger, {
emitter: stats,
dtmfListenPort: process.env.DTMF_LISTEN_PORT || 22224,
protocol: process.env.RTPENGINE_NG_PROTOCOL || (process.env.K8S ? 'ws' : 'udp')
protocol: 'udp'
});
srf.locals = {...srf.locals,
stats,
@@ -170,40 +171,58 @@ srf.use((req, res, next, err) => {
res.send(500);
});
const PORT = process.env.HTTP_PORT || 3000;
const getCount = () => activeCallIds.size;
const healthCheck = require('@jambonz/http-health-check');
healthCheck({port: PORT, logger, path: '/', fn: getCount});
if (process.env.K8S) {
const PORT = process.env.HTTP_PORT || 3000;
const getCount = () => activeCallIds.size;
const healthCheck = require('@jambonz/http-health-check');
healthCheck({port: PORT, logger, path: '/', fn: getCount});
}
if ('test' !== process.env.NODE_ENV) {
/* update call stats periodically */
setInterval(() => {
stats.gauge('sbc.sip.calls.count', activeCallIds.size, ['direction:inbound']);
}, 20000);
}
/* update call stats periodically */
setInterval(() => {
stats.gauge('sbc.sip.calls.count', activeCallIds.size, ['direction:inbound']);
}, 20000);
const arrayCompare = (a, b) => {
if (a.length !== b.length) return false;
const uniqueValues = new Set([...a, ...b]);
for (const v of uniqueValues) {
const aCount = a.filter((e) => e === v).length;
const bCount = b.filter((e) => e === v).length;
if (aCount !== bCount) return false;
}
return true;
const lookupRtpServiceEndpoints = (lookup, serviceName) => {
logger.debug(`dns lookup for ${serviceName}..`);
lookup(serviceName, {family: 4, all: true}, (err, addresses) => {
if (err) {
logger.error({err}, `Error looking up ${serviceName}`);
return;
}
logger.debug({addresses, rtpServers}, `dns lookup for ${serviceName} returned`);
const addrs = addresses.map((a) => a.address);
if (!equalsIgnoreOrder(addrs, rtpServers)) {
rtpServers.length = 0;
Array.prototype.push.apply(rtpServers, addrs);
logger.info({rtpServers}, 'rtpserver endpoints have been updated');
setRtpEngines(rtpServers.map((a) => `${a}:${process.env.RTPENGINE_PORT || 22222}`));
}
});
};
const serviceName = process.env.JAMBONES_RTPENGINES || process.env.K8S_RTPENGINE_SERVICE_NAME;
if (serviceName) {
logger.info(`rtpengine(s) will be found at: ${serviceName}`);
setRtpEngines([serviceName]);
if (process.env.K8S_RTPENGINE_SERVICE_NAME) {
/* poll dns for endpoints every so often */
const arr = /^(.*):(\d+)$/.exec(process.env.K8S_RTPENGINE_SERVICE_NAME);
const svc = arr[1];
logger.info(`rtpengine(s) will be found at dns name: ${svc}`);
const {lookup} = require('dns');
lookupRtpServiceEndpoints(lookup, svc);
setInterval(lookupRtpServiceEndpoints.bind(null, lookup, svc), process.env.RTPENGINE_DNS_POLL_INTERVAL || 10000);
}
else if (process.env.JAMBONES_RTPENGINES) {
/* static list of rtpengines */
setRtpEngines([process.env.JAMBONES_RTPENGINES]);
}
else {
/* update rtpengines periodically */
/* poll redis periodically for rtpengines that have registered via OPTIONS ping */
const getActiveRtpServers = async() => {
try {
const set = await retrieveSet(setNameRtp);
const newArray = Array.from(set);
logger.debug({newArray, rtpServers}, 'getActiveRtpServers');
if (!arrayCompare(newArray, rtpServers)) {
if (!equalsIgnoreOrder(newArray, rtpServers)) {
logger.info({newArray}, 'resetting active rtpengines');
setRtpEngines(newArray.map((a) => `${a}:${process.env.RTPENGINE_PORT || 22222}`));
rtpServers.length = 0;
+16 -4
View File
@@ -197,14 +197,14 @@ class CallSession extends Emitter {
this._setHandlers({uas, uac});
return;
} catch (err) {
this.rtpEngineResource.destroy();
this.rtpEngineResource.destroy().catch((err) => this.logger.info({err}, 'Error destroying rtpe after failure'));
this.activeCallIds.delete(this.req.get('Call-ID'));
this.stats.gauge('sbc.sip.calls.count', this.activeCallIds.size);
if (err instanceof SipError) {
const tags = ['accepted:no', `sipStatus:${err.status}`, `originator:${this.req.locals.originator}`];
this.stats.increment('sbc.terminations', tags);
this.logger.info(`call failed to connect to feature server with ${err.status}`);
return this.emit('failed');
this.emit('failed');
}
else if (err.message !== 'call canceled') {
this.logger.error(err, 'unexpected error routing inbound call');
@@ -618,8 +618,20 @@ Duration=${payload.duration} `
}
}
else {
// TODO: forward on to feature server
res.send(501);
/* REFER coming in from a sip device, forward to feature server */
try {
const response = await dlg.other.request({
method: 'REFER',
headers: {
'Refer-To': req.get('Refer-To'),
'Referred-By': req.get('Referred-By'),
'User-Agent': req.get('User-Agent')
}
});
res.send(response.status, response.reason);
} catch (err) {
this.logger.error({err}, 'CallSession:_onRefer: error handling incoming REFER');
}
}
}
+13 -1
View File
@@ -45,11 +45,23 @@ const normalizeDID = (tel) => {
return arr ? arr[1] : tel;
};
const equalsIgnoreOrder = (a, b) => {
if (a.length !== b.length) return false;
const uniqueValues = new Set([...a, ...b]);
for (const v of uniqueValues) {
const aCount = a.filter((e) => e === v).length;
const bCount = b.filter((e) => e === v).length;
if (aCount !== bCount) return false;
}
return true;
};
module.exports = {
isWSS,
SdpWantsSrtp,
getAppserver,
makeRtpEngineOpts,
makeCallCountKey,
normalizeDID
normalizeDID,
equalsIgnoreOrder
};
+2208 -385
View File
File diff suppressed because it is too large Load Diff
+8 -7
View File
@@ -1,9 +1,9 @@
{
"name": "sbc-inbound",
"version": "v0.7.1",
"version": "v0.7.4",
"main": "app.js",
"engines": {
"node": ">= 10.16.0"
"node": ">= 12.0.0"
},
"keywords": [
"sip",
@@ -25,11 +25,11 @@
"jslint": "eslint app.js lib"
},
"dependencies": {
"@jambonz/db-helpers": "^0.6.16",
"@jambonz/db-helpers": "^0.6.17",
"@jambonz/http-authenticator": "^0.2.0",
"@jambonz/http-health-check": "^0.0.1",
"@jambonz/realtimedb-helpers": "^0.4.9",
"@jambonz/rtpengine-utils": "^0.2.2",
"@jambonz/realtimedb-helpers": "^0.4.24",
"@jambonz/rtpengine-utils": "^0.3.1",
"@jambonz/stats-collector": "^0.1.6",
"@jambonz/time-series": "^0.1.6",
"aws-sdk": "^2.1036.0",
@@ -39,6 +39,7 @@
"drachtio-fn-b2b-sugar": "0.0.12",
"drachtio-srf": "^4.4.59",
"express": "^4.17.1",
"husky": "^7.0.4",
"pino": "^7.4.1",
"rtpengine-client": "^0.2.0",
"verify-aws-sns-signature": "^0.0.6",
@@ -46,8 +47,8 @@
},
"devDependencies": {
"clear-module": "^4.1.1",
"eslint": "^7.15.0",
"eslint-plugin-promise": "^4.2.1",
"eslint": "^7.32.0",
"eslint-plugin-promise": "^4.3.1",
"nyc": "^15.1.0",
"tape": "^4.13.3"
}