mirror of
https://github.com/jambonz/sbc-inbound.git
synced 2026-10-04 02:04:22 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c78ec892b9 | ||
|
|
6d237d43b3 | ||
|
|
44d298a4f3 | ||
|
|
030059a596 | ||
|
|
78b60525e2 |
@@ -1,7 +1,7 @@
|
||||
const Emitter = require('events');
|
||||
const bent = require('bent');
|
||||
const assert = require('assert');
|
||||
const PORT = process.env.AWS_SNS_PORT || 3001;
|
||||
const PORT = process.env.AWS_SNS_PORT || 3010;
|
||||
const {LifeCycleEvents} = require('./constants');
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
@@ -21,6 +21,26 @@ class SnsNotifier extends Emitter {
|
||||
|
||||
this.logger = logger;
|
||||
}
|
||||
_doListen(logger, app, port, resolve) {
|
||||
return app.listen(port, () => {
|
||||
this.snsEndpoint = `http://${this.publicIp}:${port}`;
|
||||
logger.info(`SNS lifecycle server listening on http://localhost:${port}`);
|
||||
resolve(app);
|
||||
});
|
||||
}
|
||||
|
||||
_handleErrors(logger, app, resolve, reject, e) {
|
||||
if (e.code === 'EADDRINUSE' &&
|
||||
process.env.AWS_SNS_PORT_MAX &&
|
||||
e.port < process.env.AWS_SNS_PORT_MAX) {
|
||||
|
||||
logger.info(`SNS lifecycle server failed to bind port on ${e.port}, will try next port`);
|
||||
const server = this._doListen(logger, app, ++e.port, resolve);
|
||||
server.on('error', this._handleErrors.bind(this, logger, app, resolve, reject));
|
||||
return;
|
||||
}
|
||||
reject(e);
|
||||
}
|
||||
|
||||
async _handlePost(req, res) {
|
||||
try {
|
||||
@@ -45,6 +65,7 @@ class SnsNotifier extends Emitter {
|
||||
}, 'response from SNS SubscribeURL');
|
||||
const data = await this.describeInstance();
|
||||
this.lifecycleState = data.AutoScalingInstances[0].LifecycleState;
|
||||
this.emit('SubscriptionConfirmation', {publicIp: this.publicIp});
|
||||
break;
|
||||
|
||||
case 'Notification':
|
||||
@@ -80,14 +101,12 @@ class SnsNotifier extends Emitter {
|
||||
|
||||
async init() {
|
||||
try {
|
||||
this.logger.info('SnsNotifier: retrieving instance data');
|
||||
this.logger.debug('SnsNotifier: retrieving instance data');
|
||||
this.instanceId = await getString('http://169.254.169.254/latest/meta-data/instance-id');
|
||||
this.publicIp = await getString('http://169.254.169.254/latest/meta-data/public-ipv4');
|
||||
this.snsEndpoint = `http://${this.publicIp}:${PORT}`;
|
||||
this.logger.info({
|
||||
instanceId: this.instanceId,
|
||||
publicIp: this.publicIp,
|
||||
snsEndpoint: this.snsEndpoint
|
||||
publicIp: this.publicIp
|
||||
}, 'retrieved AWS instance data');
|
||||
|
||||
// start listening
|
||||
@@ -99,7 +118,10 @@ class SnsNotifier extends Emitter {
|
||||
this.logger.error(err, 'burped error');
|
||||
res.status(err.status || 500).json({msg: err.message});
|
||||
});
|
||||
app.listen(PORT);
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = this._doListen(this.logger, app, PORT, resolve);
|
||||
server.on('error', this._handleErrors.bind(this, this.logger, app, resolve, reject));
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
this.logger.error({err}, 'Error retrieving AWS instance metadata');
|
||||
|
||||
+2
-2
@@ -804,7 +804,7 @@ Duration=${payload.duration} `
|
||||
this.uac = uac;
|
||||
uac.other = this.uas;
|
||||
this.uas.other = uac;
|
||||
uac.on('modify', this._onFeatureServerReinvite.bind(this, uac));
|
||||
uac.on('modify', this._onReinvite.bind(this, uac));
|
||||
uac.on('refer', this._onFeatureServerTransfer.bind(this, uac));
|
||||
uac.on('destroy', () => {
|
||||
this.logger.info('call ended with normal termination');
|
||||
@@ -822,7 +822,7 @@ Duration=${payload.duration} `
|
||||
const response = await this.answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onFeatureServerReinvite: rtpengine failed: ${JSON.stringify(response)}`);
|
||||
throw new Error(`_onFeatureServerTransfer: rtpengine failed: ${JSON.stringify(response)}`);
|
||||
}
|
||||
this.logger.info('successfully moved call to new feature server');
|
||||
} catch (err) {
|
||||
|
||||
@@ -57,6 +57,16 @@ WHERE sg.voip_carrier_sid = ?
|
||||
AND sg.voip_carrier_sid = vc.voip_carrier_sid
|
||||
AND outbound = 1`;
|
||||
|
||||
const sqlSelectCarrierRequiringRegistration = `
|
||||
SELECT sg.sip_gateway_sid, sg.voip_carrier_sid, vc.name, vc.service_provider_sid, vc.account_sid,
|
||||
vc.application_sid, sg.inbound, sg.outbound, sg.is_active, sg.ipv4, sg.netmask
|
||||
FROM sip_gateways sg, voip_carriers vc
|
||||
WHERE sg.voip_carrier_sid = vc.voip_carrier_sid
|
||||
AND vc.requires_register = 1
|
||||
AND vc.is_active = 1
|
||||
AND vc.register_sip_realm = ?
|
||||
AND vc.register_username = ?`;
|
||||
|
||||
const gatewayMatchesSourceAddress = (source_address, gw) => {
|
||||
if (32 === gw.netmask && gw.ipv4 === source_address) return true;
|
||||
if (gw.netmask < 32) {
|
||||
@@ -179,6 +189,15 @@ module.exports = (srf, logger) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The host part of the SIP URI is not a dot-decimal IP address,
|
||||
* so this can be one of two things:
|
||||
* (1) a sip realm value associate with an account, or
|
||||
* (2) a carrier name for a carrier that we send outbound registrations to
|
||||
*
|
||||
* Let's look for case #1 first...
|
||||
*/
|
||||
|
||||
/* get all the carriers and gateways for the account owning this sip realm */
|
||||
const [gwAcc] = await pp.query(sqlSelectAllCarriersForAccountByRealm, uri.host);
|
||||
const [gwSP] = gwAcc.length ? [[]] : await pp.query(sqlSelectAllCarriersForSPByRealm, uri.host);
|
||||
@@ -196,6 +215,41 @@ module.exports = (srf, logger) => {
|
||||
account: a[0]
|
||||
};
|
||||
}
|
||||
|
||||
/* no match, so let's look for case #2 */
|
||||
try {
|
||||
logger.info({
|
||||
host: uri.host,
|
||||
user: uri.user
|
||||
}, 'sip realm is not associated with an account, checking carriers');
|
||||
const [gw] = await pp.query(sqlSelectCarrierRequiringRegistration, [uri.host, uri.user]);
|
||||
const matches = gw.filter(gatewayMatchesSourceAddress.bind(null, req.source_address));
|
||||
if (1 === matches.length) {
|
||||
// bingo
|
||||
//TODO: this assumes the carrier is associate to an account, not an SP
|
||||
//if the carrier is associated with an SP (which would mean we
|
||||
//must see a dialed number in the To header, not the register username),
|
||||
//then we need to look up the account based on the dialed number in the To header
|
||||
const [a] = await pp.query(sqlAccountBySid, matches[0].account_sid);
|
||||
if (0 === a.length) return failure;
|
||||
logger.debug({matches}, `found registration carrier using ${uri.host} and ${uri.user}`);
|
||||
return {
|
||||
fromCarrier: true,
|
||||
gateway: matches[0],
|
||||
service_provider_sid: a[0].service_provider_sid,
|
||||
account_sid: a[0].account_sid,
|
||||
application_sid: matches[0].application_sid,
|
||||
account: a[0]
|
||||
};
|
||||
|
||||
}
|
||||
else if (matches.length > 1) {
|
||||
logger.warn({matches, source_address: req.source_address}, 'multiple gateways match source address');
|
||||
}
|
||||
} catch (err) {
|
||||
logger.info({err, host: uri.host, user: uri.user}, 'Error looking up carrier by host and user');
|
||||
}
|
||||
|
||||
return failure;
|
||||
};
|
||||
|
||||
|
||||
+23
-5
@@ -71,6 +71,26 @@ const systemHealth = async(redisClient, ping, getCount) => {
|
||||
return getCount();
|
||||
};
|
||||
|
||||
const doListen = (logger, app, port, resolve) => {
|
||||
return app.listen(port, () => {
|
||||
logger.info(`Health check server listening on http://localhost:${port}`);
|
||||
resolve(app);
|
||||
});
|
||||
};
|
||||
const handleErrors = (logger, app, resolve, reject, e) => {
|
||||
if (e.code === 'EADDRINUSE' &&
|
||||
process.env.HTTP_PORT_MAX &&
|
||||
e.port < process.env.HTTP_PORT_MAX) {
|
||||
|
||||
logger.info(`Health check server failed to bind port on ${e.port}, will try next port`);
|
||||
const server = doListen(logger, app, ++e.port, resolve);
|
||||
server.on('error', handleErrors.bind(null, logger, app, resolve, reject));
|
||||
return;
|
||||
}
|
||||
reject(e);
|
||||
};
|
||||
|
||||
|
||||
const createHealthCheckApp = (port, logger) => {
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
@@ -78,11 +98,9 @@ const createHealthCheckApp = (port, logger) => {
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.json());
|
||||
|
||||
return new Promise((resolve) => {
|
||||
app.listen(port, () => {
|
||||
logger.info(`Health check server started at http://localhost:${port}`);
|
||||
resolve(app);
|
||||
});
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = doListen(logger, app, port, resolve);
|
||||
server.on('error', handleErrors.bind(null, logger, app, resolve, reject));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Generated
+22
-7
@@ -9,7 +9,7 @@
|
||||
"version": "v0.7.7",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.6.19",
|
||||
"@jambonz/db-helpers": "^0.7.0",
|
||||
"@jambonz/http-authenticator": "^0.2.2",
|
||||
"@jambonz/http-health-check": "^0.0.1",
|
||||
"@jambonz/realtimedb-helpers": "^0.4.35",
|
||||
@@ -572,13 +572,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/db-helpers": {
|
||||
"version": "0.6.19",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.6.19.tgz",
|
||||
"integrity": "sha512-mR9PqPY4aEoeTtUuZI1+4r+k1BFKoe0Dl9pyeAEvm7KSlRMHCVWbOzVE8WfoifC9dZ9541iW5pseqqip3QMkyw==",
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.7.0.tgz",
|
||||
"integrity": "sha512-Fj0q8qEwW2xKCtOyDkzKLl6kvBASFTeLljc+LW1hoF47pe+IFc3ZXPL3ntqwX39YgFCMayeUrJMdio+1GYsECA==",
|
||||
"dependencies": {
|
||||
"cidr-matcher": "^2.1.1",
|
||||
"debug": "^4.3.3",
|
||||
"mysql2": "^2.3.3",
|
||||
"node-object-hash": "^2.3.10",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
@@ -3914,6 +3915,14 @@
|
||||
"resolved": "https://registry.npmjs.org/node-noop/-/node-noop-0.0.1.tgz",
|
||||
"integrity": "sha512-kAUvIRxZyDYFTLqGj+7zqXduG89vtqGmNMt9qDMvYH3H8uNTCOTz5ZN1q2Yg8++fWbzv+ERtYVqaOH42Ag5OpA=="
|
||||
},
|
||||
"node_modules/node-object-hash": {
|
||||
"version": "2.3.10",
|
||||
"resolved": "https://registry.npmjs.org/node-object-hash/-/node-object-hash-2.3.10.tgz",
|
||||
"integrity": "sha512-jY5dPJzw6NHd/KPSfPKJ+IHoFS81/tJ43r34ZeNMXGzCOM8jwQDCD12HYayKIB6MuznrnqIYy2e891NA2g0ibA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-preload": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
|
||||
@@ -6194,13 +6203,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"@jambonz/db-helpers": {
|
||||
"version": "0.6.19",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.6.19.tgz",
|
||||
"integrity": "sha512-mR9PqPY4aEoeTtUuZI1+4r+k1BFKoe0Dl9pyeAEvm7KSlRMHCVWbOzVE8WfoifC9dZ9541iW5pseqqip3QMkyw==",
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.7.0.tgz",
|
||||
"integrity": "sha512-Fj0q8qEwW2xKCtOyDkzKLl6kvBASFTeLljc+LW1hoF47pe+IFc3ZXPL3ntqwX39YgFCMayeUrJMdio+1GYsECA==",
|
||||
"requires": {
|
||||
"cidr-matcher": "^2.1.1",
|
||||
"debug": "^4.3.3",
|
||||
"mysql2": "^2.3.3",
|
||||
"node-object-hash": "^2.3.10",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
@@ -8767,6 +8777,11 @@
|
||||
"resolved": "https://registry.npmjs.org/node-noop/-/node-noop-0.0.1.tgz",
|
||||
"integrity": "sha512-kAUvIRxZyDYFTLqGj+7zqXduG89vtqGmNMt9qDMvYH3H8uNTCOTz5ZN1q2Yg8++fWbzv+ERtYVqaOH42Ag5OpA=="
|
||||
},
|
||||
"node-object-hash": {
|
||||
"version": "2.3.10",
|
||||
"resolved": "https://registry.npmjs.org/node-object-hash/-/node-object-hash-2.3.10.tgz",
|
||||
"integrity": "sha512-jY5dPJzw6NHd/KPSfPKJ+IHoFS81/tJ43r34ZeNMXGzCOM8jwQDCD12HYayKIB6MuznrnqIYy2e891NA2g0ibA=="
|
||||
},
|
||||
"node-preload": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
"jslint": "eslint app.js lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.6.19",
|
||||
"@jambonz/db-helpers": "^0.7.0",
|
||||
"@jambonz/realtimedb-helpers": "^0.4.35",
|
||||
"@jambonz/http-authenticator": "^0.2.2",
|
||||
"@jambonz/http-health-check": "^0.0.1",
|
||||
|
||||
Reference in New Issue
Block a user