mirror of
https://github.com/jambonz/sbc-sip-sidecar.git
synced 2025-12-19 04:27:46 +00:00
feat: merge sip-registra and sip-options-handler
This commit is contained in:
23
Dockerfile
Normal file
23
Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
||||
FROM --platform=linux/amd64 node:18.6.0-alpine as base
|
||||
|
||||
RUN apk --update --no-cache add --virtual .builds-deps build-base python3
|
||||
|
||||
WORKDIR /opt/app/
|
||||
|
||||
FROM base as build
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
|
||||
FROM base
|
||||
|
||||
COPY --from=build /opt/app /opt/app/
|
||||
|
||||
ARG NODE_ENV
|
||||
|
||||
ENV NODE_ENV $NODE_ENV
|
||||
|
||||
CMD [ "node", "app.js" ]
|
||||
104
README.md
Normal file
104
README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# sbc-sip-sidecar 
|
||||
|
||||
This application provides a part of the SBC (Session Border Controller) functionality of jambonz. It handles incoming/outgoing REGISTER requests from/to clients/servers (including both sip softphones and WebRTC client applications), incoming OPTIONS. Register Authentication is delegated to customer-side logic via a web callback configured for the account in the jambonz database. Information about active registrations is stored in a redis database.
|
||||
|
||||
## registrar database
|
||||
|
||||
A redis database is used to hold active registrations. When a register request arrives and is authenticated, the following values are parsed from the request:
|
||||
- the address of record, or "aor" (e.g, daveh@drachtio.org),
|
||||
- the sip uri, or "contact" that this user is advertising (e.g. sip:daveh@3.44.3.12:5060)
|
||||
- the source address and port that sent the REGISTER request to the server
|
||||
- the transport protocol that should be used to contact the user (e.g. udp, tcp, wss etc)
|
||||
- the sip address of the drachtio server that received the REGISTER request, and
|
||||
- the expiration of the registration, in seconds.
|
||||
- the application callback that should be invoked when a call is placed from this registered device
|
||||
- the application status callback that should invoked for call events on calls placed from this registered device
|
||||
|
||||
A hash value is created from these values and stored with an expiry value equal to the number of seconds granted to the registration (note that when a sip client is detected as being behind a firewall, the application will reduce the granted expires value to 30 seconds, in order to force the client to re-register frequently, however the expiry in redis is set to the longer, originally requested expires value).
|
||||
|
||||
The hash value is inserted with a key being the aor:
|
||||
```
|
||||
aor => {contact, source, protocol, sbcAddress, call_hook, call_status_hook}, expiry = registration expires value
|
||||
```
|
||||
|
||||
## configuration
|
||||
|
||||
Configuration is provided via the [npmjs config](https://www.npmjs.com/package/config) package. The following elements make up the configuration for the application:
|
||||
##### drachtio server location
|
||||
```
|
||||
{
|
||||
"drachtio": {
|
||||
"port": 3001,
|
||||
"secret": "cymru"
|
||||
},
|
||||
```
|
||||
the `drachtio` object specifies the port to listen on for tcp connections from drachtio servers as well as the shared secret that is used to authenticate to the server.
|
||||
|
||||
> Note: [outbound connections](https://drachtio.org/docs#outbound-connections) are used for all drachtio applications in jambonz, to allow for easier centralization and clustering of application logic.
|
||||
|
||||
##### redis server location
|
||||
```
|
||||
"redis": {
|
||||
"port": 6379,
|
||||
"host": "127.0.0.1"
|
||||
},
|
||||
```
|
||||
the `redis` object specifies the location of the redis database. Any of the options [defined here](https://www.npmjs.com/package/redis#rediscreateclient) may be supplied, but host and port are minimally required.
|
||||
|
||||
Note that in a fully-scaled out environment with multiple SBCs there will be one centralized redis database (or cluster) that stores registrations for all SBCs.
|
||||
|
||||
##### application log level
|
||||
```
|
||||
"logging": {
|
||||
"level": "info"
|
||||
}
|
||||
```
|
||||
|
||||
## http callback
|
||||
Authenticating users is the responsibility of the client by exposing an http callback. A POST request will be sent to the configured callback (i.e. the value in the `accounts.registration_hook` column in the associated sip realm value in the REGISTER request). The body of the POST will be a json payload including the following information:
|
||||
```
|
||||
{
|
||||
"method": "REGISTER",
|
||||
"expires": 3600,
|
||||
"scheme": "digest",
|
||||
"username": "john",
|
||||
"realm": "jambonz.org",
|
||||
"nonce": "157590482938000",
|
||||
"uri": "sip:172.37.0.10:5060",
|
||||
"response": "be641cf7951ff23ab04c57907d59f37d",
|
||||
"qop": "auth",
|
||||
"nc": "00000001",
|
||||
"cnonce": "6b8b4567",
|
||||
"algorithm": "MD5"
|
||||
}
|
||||
```
|
||||
It is the responsibility of the customer-side logic to retrieve the associated password for the given username and to then authenticate the request by calculating a response hash value (per the algorithm described in [RFC 2617](https://tools.ietf.org/html/rfc2617#section-3.2.2)) and comparing it to the response property in the http body.
|
||||
|
||||
For example code showing how to calculate the response hash given the above inputs, [see here](https://github.com/jambonz/customer-auth-server/blob/master/lib/utils.js).
|
||||
|
||||
For a simple, full-fledged example server doing the same, [see here](https://github.com/jambonz/customer-auth-server).
|
||||
|
||||
The customer server SHOULD return a 200 OK response to the http request in all cases with a json body indicating whether the request was successfully authenticated.
|
||||
|
||||
The body MUST include a `status` field with a value of either `ok` or `fail`, indicating whether the request was authenticated or not.
|
||||
```
|
||||
{"status": "ok"}
|
||||
```
|
||||
|
||||
Additionally, in the case of failure, the body MAY include a `msg` field with a human-readable description of why the authentication failed.
|
||||
```
|
||||
{"status": "fail", "msg": "invalid username"}
|
||||
```
|
||||
|
||||
In the case of success, the body MAY include an `expires` value which specifies the duration of time, in seconds, to grant for this registration. If not provided, the expires value in the REGISTER request is used; if provided, however, the value provided must be less than or equal to the duration requested.
|
||||
```
|
||||
{"status": "ok", "expires": 300}
|
||||
```
|
||||
|
||||
Additionally in the case of success, the body SHOULD include `call_hook` and `call_status_hook` properties that reference the application URLs to use when calls are placed from this device. If these values are not provided, outbound calling from the device will not be allowed.
|
||||
|
||||
## Running the test suite
|
||||
To run the included test suite, you will need to have a mysql server installed on your laptop/server. You will need to set the MYSQL_ROOT_PASSWORD env variable to the mysql root password before running the tests. The test suite creates a database named 'jambones_test' in your mysql server to run the tests against, and removes it when done.
|
||||
```
|
||||
MYSQL_ROOT_PASSWORD=foobar npm test
|
||||
```
|
||||
131
app.js
131
app.js
@@ -1,12 +1,13 @@
|
||||
const assert = require('assert');
|
||||
assert.ok(process.env.JAMBONES_MYSQL_HOST &&
|
||||
process.env.JAMBONES_MYSQL_USER &&
|
||||
process.env.JAMBONES_MYSQL_PASSWORD &&
|
||||
process.env.JAMBONES_MYSQL_DATABASE, 'missing JAMBONES_MYSQL_XXX env vars');
|
||||
process.env.JAMBONES_MYSQL_USER &&
|
||||
process.env.JAMBONES_MYSQL_PASSWORD &&
|
||||
process.env.JAMBONES_MYSQL_DATABASE, 'missing JAMBONES_MYSQL_XXX env vars');
|
||||
assert.ok(process.env.JAMBONES_REDIS_HOST, 'missing JAMBONES_REDIS_HOST env var');
|
||||
assert.ok(process.env.DRACHTIO_HOST, 'missing DRACHTIO_HOST env var');
|
||||
assert.ok(process.env.DRACHTIO_PORT, 'missing DRACHTIO_PORT env var');
|
||||
assert.ok(process.env.DRACHTIO_SECRET, 'missing DRACHTIO_SECRET env var');
|
||||
|
||||
const opts = Object.assign({
|
||||
timestamp: () => { return `, "time": "${new Date().toISOString()}"`; }
|
||||
}, { level: process.env.JAMBONES_LOGLEVEL || 'info' });
|
||||
@@ -14,10 +15,21 @@ const logger = require('pino')(opts);
|
||||
const Srf = require('drachtio-srf');
|
||||
const srf = new Srf();
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-sip`;
|
||||
|
||||
const StatsCollector = require('@jambonz/stats-collector');
|
||||
const stats = new StatsCollector(logger);
|
||||
const { initLocals, rejectIpv4, checkCache, checkAccountLimits } = require('./lib/middleware');
|
||||
const responseTime = require('drachtio-mw-response-time');
|
||||
const regParser = require('drachtio-mw-registration-parser');
|
||||
const Registrar = require('@jambonz/mw-registrar');
|
||||
const Emitter = require('events');
|
||||
const debug = require('debug')('jambonz:sbc-registrar');
|
||||
const {
|
||||
lookupAuthHook,
|
||||
lookupAllVoipCarriers,
|
||||
lookupSipGatewaysByCarrier,
|
||||
lookupAccountBySipRealm,
|
||||
lookupAccountCapacitiesBySid,
|
||||
addSbcAddress
|
||||
} = require('@jambonz/db-helpers')({
|
||||
host: process.env.JAMBONES_MYSQL_HOST,
|
||||
user: process.env.JAMBONES_MYSQL_USER,
|
||||
@@ -25,22 +37,45 @@ const {
|
||||
database: process.env.JAMBONES_MYSQL_DATABASE,
|
||||
connectionLimit: process.env.JAMBONES_MYSQL_CONNECTION_LIMIT || 10
|
||||
}, logger);
|
||||
const {
|
||||
writeAlerts,
|
||||
AlertType
|
||||
} = require('@jambonz/time-series')(logger, {
|
||||
host: process.env.JAMBONES_TIME_SERIES_HOST,
|
||||
commitSize: 50,
|
||||
commitInterval: 'test' === process.env.NODE_ENV ? 7 : 20
|
||||
});
|
||||
|
||||
const {
|
||||
retrieveSet } = require('@jambonz/realtimedb-helpers')({
|
||||
addToSet,
|
||||
removeFromSet,
|
||||
isMemberOfSet,
|
||||
retrieveSet
|
||||
} = require('@jambonz/realtimedb-helpers')({
|
||||
host: process.env.JAMBONES_REDIS_HOST || 'localhost',
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
}, logger);
|
||||
|
||||
srf.locals = {
|
||||
...srf.locals,
|
||||
stats,
|
||||
addToSet, removeFromSet, isMemberOfSet, retrieveSet,
|
||||
registrar: new Registrar(logger, {
|
||||
host: process.env.JAMBONES_REDIS_HOST,
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
}),
|
||||
dbHelpers: {
|
||||
lookupAuthHook,
|
||||
lookupAllVoipCarriers,
|
||||
lookupSipGatewaysByCarrier,
|
||||
lookupAccountBySipRealm,
|
||||
lookupAccountCapacitiesBySid
|
||||
},
|
||||
realtimeDbHelpers: {
|
||||
retrieveSet
|
||||
}
|
||||
},
|
||||
writeAlerts,
|
||||
AlertType
|
||||
};
|
||||
|
||||
srf.connect({ host: process.env.DRACHTIO_HOST, port: process.env.DRACHTIO_PORT, secret: process.env.DRACHTIO_SECRET });
|
||||
@@ -48,6 +83,17 @@ srf.on('connect', (err, hp) => {
|
||||
const ativateRegBot = async(err, hp) => {
|
||||
if (err) return logger.error({ err }, 'Error connecting to drachtio server');
|
||||
logger.info(`connected to drachtio listening on ${hp}`);
|
||||
|
||||
// Add SBC Public IP to Database
|
||||
const hostports = hp.split(',');
|
||||
for (const hp of hostports) {
|
||||
const arr = /^(.*)\/(.*):(\d+)$/.exec(hp);
|
||||
if (arr && 'udp' === arr[1]) {
|
||||
logger.info(`adding sbc public address to database: ${arr[2]}`);
|
||||
addSbcAddress(arr[2]);
|
||||
}
|
||||
}
|
||||
|
||||
// Only run when I'm the first member in the set Of Actip Sip SBC
|
||||
const set = await retrieveSet(setName);
|
||||
const newArray = Array.from(set);
|
||||
@@ -80,4 +126,77 @@ if (process.env.NODE_ENV === 'test') {
|
||||
});
|
||||
}
|
||||
|
||||
const rttMetric = (req, res, time) => {
|
||||
if (res.cached) {
|
||||
stats.histogram('sbc.registration.cached.response_time', time.toFixed(0), [`status:${res.statusCode}`]);
|
||||
}
|
||||
else {
|
||||
stats.histogram('sbc.registration.total.response_time', time.toFixed(0), [`status:${res.statusCode}`]);
|
||||
}
|
||||
};
|
||||
|
||||
class RegOutcomeReporter extends Emitter {
|
||||
constructor() {
|
||||
super();
|
||||
this
|
||||
.on('regHookOutcome', ({ rtt, status }) => {
|
||||
stats.histogram('app.hook.response_time', rtt, ['hook_type:auth', `status:${status}`]);
|
||||
if (![200, 403].includes(status)) {
|
||||
stats.increment('app.hook.error.count', ['hook_type:auth', `status:${status}`]);
|
||||
}
|
||||
})
|
||||
.on('error', async(err, req) => {
|
||||
logger.error({ err }, 'http webhook failed');
|
||||
const { account_sid } = req.locals;
|
||||
if (account_sid) {
|
||||
let opts = { account_sid };
|
||||
if (err.code === 'ECONNREFUSED') {
|
||||
opts = { ...opts, alert_type: AlertType.WEBHOOK_CONNECTION_FAILURE, url: err.hook };
|
||||
}
|
||||
else if (err.code === 'ENOTFOUND') {
|
||||
opts = { ...opts, alert_type: AlertType.WEBHOOK_CONNECTION_FAILURE, url: err.hook };
|
||||
}
|
||||
else if (err.name === 'StatusError') {
|
||||
opts = { ...opts, alert_type: AlertType.WEBHOOK_STATUS_FAILURE, url: err.hook, status: err.statusCode };
|
||||
}
|
||||
|
||||
if (opts.alert_type) {
|
||||
try {
|
||||
await writeAlerts(opts);
|
||||
} catch (err) {
|
||||
logger.error({ err, opts }, 'Error writing alert');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const authenticator = require('@jambonz/http-authenticator')(lookupAuthHook, logger, {
|
||||
emitter: new RegOutcomeReporter()
|
||||
});
|
||||
|
||||
// middleware
|
||||
srf.use('register', [
|
||||
initLocals,
|
||||
responseTime(rttMetric),
|
||||
rejectIpv4(logger),
|
||||
regParser,
|
||||
checkCache(logger),
|
||||
checkAccountLimits(logger),
|
||||
authenticator]);
|
||||
|
||||
srf.use('options', [
|
||||
initLocals
|
||||
]);
|
||||
|
||||
srf.register(require('./lib/register')({logger}));
|
||||
srf.options(require('./lib/options')({srf, logger}));
|
||||
|
||||
setInterval(async() => {
|
||||
const count = await srf.locals.registrar.getCountOfUsers();
|
||||
debug(`count of registered users: ${count}`);
|
||||
stats.gauge('sbc.users.count', parseInt(count));
|
||||
}, 30000);
|
||||
|
||||
module.exports = { srf, logger };
|
||||
|
||||
122
lib/middleware.js
Normal file
122
lib/middleware.js
Normal file
@@ -0,0 +1,122 @@
|
||||
const parseUri = require('drachtio-srf').parseUri;
|
||||
const debug = require('debug')('jambonz:sbc-registrar');
|
||||
const {NAT_EXPIRES} = require('./utils');
|
||||
|
||||
const initLocals = (req, res, next) => {
|
||||
req.locals = req.locals || {};
|
||||
next();
|
||||
};
|
||||
|
||||
const rejectIpv4 = (logger) => {
|
||||
return (req, res, next) => {
|
||||
const uri = parseUri(req.uri);
|
||||
if (/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(uri.host)) {
|
||||
debug(`rejecting REGISTER from ${req.uri} as it has an ipv4 address and sip realm is required`);
|
||||
res.send(403);
|
||||
return req.srf.endSession(req);
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
const checkCache = (logger) => {
|
||||
return async(req, res, next) => {
|
||||
const registration = req.registration;
|
||||
const uri = parseUri(registration.aor);
|
||||
const aor = `${uri.user}@${uri.host}`;
|
||||
req.locals.realm = uri.host;
|
||||
|
||||
if (registration.type === 'unregister') return next();
|
||||
|
||||
const registrar = req.srf.locals.registrar;
|
||||
const result = await registrar.query(aor);
|
||||
if (result) {
|
||||
// if known valid registration coming from same address, no need to hit the reg callback hook
|
||||
if (result.proxy === `sip:${req.source_address}:${req.source_port}`) {
|
||||
debug(`responding to cached register for ${aor}`);
|
||||
res.cached = true;
|
||||
res.send(200, {
|
||||
headers: {
|
||||
'Contact': req.get('Contact').replace(/expires=\d+/, `expires=${NAT_EXPIRES}`),
|
||||
'Expires': NAT_EXPIRES
|
||||
}
|
||||
});
|
||||
return req.srf.endSession(req);
|
||||
}
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
const checkAccountLimits = (logger) => {
|
||||
return async(req, res, next) => {
|
||||
|
||||
const {lookupAccountBySipRealm, lookupAccountCapacitiesBySid} = req.srf.locals.dbHelpers;
|
||||
const {realm} = req.locals;
|
||||
const {registrar, writeAlerts, AlertType} = req.srf.locals;
|
||||
try {
|
||||
const account = await lookupAccountBySipRealm(realm);
|
||||
if (account) {
|
||||
req.locals = {
|
||||
...req.locals,
|
||||
account_sid: account.account_sid,
|
||||
webhook_secret: account.webhook_secret
|
||||
};
|
||||
debug(account, `checkAccountLimits: retrieved account for realm: ${realm}`);
|
||||
}
|
||||
else if (process.env.JAMBONES_HOSTING) {
|
||||
debug(`checkAccountLimits: unknown sip realm ${realm}`);
|
||||
logger.info(`checkAccountLimits: rejecting register for unknown sip realm: ${realm}`);
|
||||
return res.send(403);
|
||||
}
|
||||
|
||||
if ('unregister' === req.registration.type || !process.env.JAMBONES_HOSTING) return next();
|
||||
|
||||
/* only check limits on the jambonz hosted platform */
|
||||
const {account_sid} = account;
|
||||
const capacities = await lookupAccountCapacitiesBySid(account_sid);
|
||||
debug(JSON.stringify(capacities));
|
||||
const limit_calls = capacities.find((c) => c.category == 'voice_call_session');
|
||||
let limit_registrations = limit_calls.quantity * account.device_to_call_ratio;
|
||||
const extra = capacities.find((c) => c.category == 'device');
|
||||
if (extra && extra.quantity) limit_registrations += extra.quantity;
|
||||
debug(`call capacity: ${limit_calls.quantity}, device capacity: ${limit_registrations}`);
|
||||
|
||||
if (0 === limit_registrations) {
|
||||
debug('checkAccountLimits: device calling not allowed for this account');
|
||||
logger.info({account_sid}, 'checkAccountLimits: device calling not allowed for this account');
|
||||
writeAlerts({
|
||||
alert_type: AlertType.DEVICE_LIMIT,
|
||||
account_sid,
|
||||
count: 0
|
||||
}).catch((err) => logger.info({err}, 'checkAccountLimits: error writing alert'));
|
||||
|
||||
return res.send(503, 'Max Devices Registered');
|
||||
}
|
||||
|
||||
const deviceCount = await registrar.getCountOfUsers(realm);
|
||||
if (deviceCount >= limit_registrations) {
|
||||
debug(account_sid, `checkAccountLimits: limit ${limit_registrations} count ${deviceCount}`);
|
||||
logger.info({account_sid}, 'checkAccountLimits: registration rejected due to limits');
|
||||
writeAlerts({
|
||||
alert_type: AlertType.DEVICE_LIMIT,
|
||||
account_sid,
|
||||
count: limit_registrations
|
||||
}).catch((err) => logger.info({err}, 'checkAccountLimits: error writing alert'));
|
||||
return res.send(503, 'Max Devices Registered');
|
||||
}
|
||||
debug(`checkAccountLimits - passed: devices registered ${deviceCount}, limit is ${limit_registrations}`);
|
||||
next();
|
||||
} catch (err) {
|
||||
logger.error({err, realm}, 'checkAccountLimits: error checking account limits');
|
||||
res.send(500);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
initLocals,
|
||||
rejectIpv4,
|
||||
checkCache,
|
||||
checkAccountLimits
|
||||
};
|
||||
118
lib/options.js
Normal file
118
lib/options.js
Normal file
@@ -0,0 +1,118 @@
|
||||
const debug = require('debug')('jambonz:sbc-options-handler');
|
||||
const fsServers = new Map();
|
||||
const rtpServers = new Map();
|
||||
|
||||
module.exports = ({srf, logger}) => {
|
||||
const {stats, addToSet, removeFromSet, isMemberOfSet, retrieveSet} = srf.locals;
|
||||
|
||||
const setNameFs = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
|
||||
const setNameRtp = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-rtp`;
|
||||
|
||||
/* check for expired servers every so often */
|
||||
setInterval(async() => {
|
||||
const now = Date.now();
|
||||
const expires = process.env.EXPIRES_INTERVAL || 60000;
|
||||
for (const [key, value] of fsServers) {
|
||||
const duration = now - value;
|
||||
if (duration > expires) {
|
||||
fsServers.delete(key);
|
||||
await removeFromSet(setNameFs, key);
|
||||
const members = await retrieveSet(setNameFs);
|
||||
const countOfMembers = members.length;
|
||||
logger.info({members}, `expired member ${key} from ${setNameFs} we now have ${countOfMembers}`);
|
||||
}
|
||||
}
|
||||
for (const [key, value] of rtpServers) {
|
||||
const duration = now - value;
|
||||
if (duration > expires) {
|
||||
rtpServers.delete(key);
|
||||
await removeFromSet(setNameRtp, key);
|
||||
const members = await retrieveSet(setNameRtp);
|
||||
const countOfMembers = members.length;
|
||||
logger.info({members}, `expired member ${key} from ${setNameRtp} we now have ${countOfMembers}`);
|
||||
}
|
||||
}
|
||||
}, process.env.CHECK_EXPIRES_INTERVAL || 20000);
|
||||
|
||||
/* retrieve the initial list of servers, if any, so we can watch them as well */
|
||||
const _init = async() => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
const runningFs = await retrieveSet(setNameFs);
|
||||
const runningRtp = await retrieveSet(setNameRtp);
|
||||
|
||||
if (runningFs.length) {
|
||||
logger.info({runningFs}, 'start watching these FS servers');
|
||||
for (const ip of runningFs) fsServers.set(ip, now);
|
||||
}
|
||||
|
||||
if (runningRtp.length) {
|
||||
logger.info({runningRtp}, 'start watching these RTP servers');
|
||||
for (const ip of runningRtp) rtpServers.set(ip, now);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error({err}, 'error initializing from redis');
|
||||
}
|
||||
};
|
||||
_init();
|
||||
|
||||
return async(req, res) => {
|
||||
|
||||
/* OPTIONS ping from internal FS or RTP server? */
|
||||
const internal = req.has('X-FS-Status') || req.has('X-RTP-Status');
|
||||
if (!internal) {
|
||||
debug('got external OPTIONS ping');
|
||||
res.send(200);
|
||||
return req.srf.endSession(req);
|
||||
}
|
||||
|
||||
try {
|
||||
let map, status, countOfMembers;
|
||||
const h = ['X-FS-Status', 'X-RTP-Status'].find((h) => req.has(h));
|
||||
if (h) {
|
||||
const isRtpServer = req.has('X-RTP-Status');
|
||||
const key = isRtpServer ? req.source_address : `${req.source_address}:${req.source_port}`;
|
||||
const prefix = isRtpServer ? 'X-RTP' : 'X-FS';
|
||||
map = isRtpServer ? rtpServers : fsServers;
|
||||
const setName = isRtpServer ? setNameRtp : setNameFs;
|
||||
const gaugeName = isRtpServer ? 'rtpservers' : 'featureservers';
|
||||
|
||||
status = req.get(`${prefix}-Status`);
|
||||
|
||||
if (status === 'open') {
|
||||
map.set(key, Date.now());
|
||||
const exists = await isMemberOfSet(setName, key);
|
||||
if (!exists) {
|
||||
await addToSet(setName, key);
|
||||
const members = await retrieveSet(setName);
|
||||
countOfMembers = members.length;
|
||||
logger.info({members}, `added new member ${key} to ${setName} we now have ${countOfMembers}`);
|
||||
debug({members}, `added new member ${key} to ${setName}`);
|
||||
}
|
||||
else {
|
||||
const members = await retrieveSet(setName);
|
||||
countOfMembers = members.length;
|
||||
debug(`checkin from existing member ${key} to ${setName}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
map.delete(key);
|
||||
await removeFromSet(setName, key);
|
||||
const members = await retrieveSet(setName);
|
||||
countOfMembers = members.length;
|
||||
logger.info({members}, `removed member ${key} from ${setName} we now have ${countOfMembers}`);
|
||||
debug({members}, `removed member ${key} from ${setName}`);
|
||||
}
|
||||
stats.gauge(gaugeName, map.size);
|
||||
}
|
||||
res.send(200, {headers: {
|
||||
'X-Members': countOfMembers
|
||||
}});
|
||||
} catch (err) {
|
||||
res.send(503);
|
||||
debug(err);
|
||||
logger.error({err}, 'Error handling OPTIONS');
|
||||
}
|
||||
return req.srf.endSession(req);
|
||||
};
|
||||
};
|
||||
72
lib/register.js
Normal file
72
lib/register.js
Normal file
@@ -0,0 +1,72 @@
|
||||
const {isUacBehindNat, getSipProtocol, NAT_EXPIRES} = require('./utils');
|
||||
const parseUri = require('drachtio-srf').parseUri;
|
||||
const debug = require('debug')('jambonz:sbc-registrar');
|
||||
|
||||
module.exports = handler;
|
||||
|
||||
function handler({logger}) {
|
||||
return async(req, res) => {
|
||||
debug(`received ${req.method} from ${req.protocol}/${req.source_address}:${req.source_port}`);
|
||||
|
||||
if ('register' === req.registration.type && '0' !== req.registration.expires) await register(logger, req, res);
|
||||
else await unregister(logger, req, res);
|
||||
|
||||
req.srf.endSession(req);
|
||||
};
|
||||
}
|
||||
|
||||
async function register(logger, req, res) {
|
||||
try {
|
||||
const registrar = req.srf.locals.registrar;
|
||||
const registration = req.registration;
|
||||
const uri = parseUri(registration.aor);
|
||||
const aor = `${uri.user}@${uri.host}`;
|
||||
let expires = req.authorization.grant.expires || registration.expires;
|
||||
const grantedExpires = expires;
|
||||
let contactHdr = req.get('Contact');
|
||||
|
||||
// reduce the registration interval if the device is behind a nat
|
||||
if (isUacBehindNat(req)) {
|
||||
expires = NAT_EXPIRES;
|
||||
contactHdr = contactHdr.replace(/expires=\d+/, `expires=${expires}`);
|
||||
}
|
||||
const opts = {
|
||||
contact: req.getParsedHeader('Contact')[0].uri,
|
||||
sbcAddress: req.server.hostport,
|
||||
protocol: getSipProtocol(req),
|
||||
proxy: `sip:${req.source_address}:${req.source_port}`,
|
||||
callHook: req.authorization.grant.call_hook,
|
||||
callStatusHook: req.authorization.grant.call_status_hook
|
||||
};
|
||||
logger.debug(`adding aor to redis ${aor}`);
|
||||
const result = await registrar.add(aor, opts, grantedExpires);
|
||||
debug(`result ${result} from adding ${JSON.stringify(opts)}`);
|
||||
logger.debug(`successfully added ${aor} to redis, sending 200 OK`);
|
||||
|
||||
res.send(200, {
|
||||
headers: {
|
||||
'Contact': contactHdr,
|
||||
'Expires': expires
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error({err}, 'Error trying to process REGISTER');
|
||||
if (!res.finalResponseSent) res.send(500);
|
||||
}
|
||||
}
|
||||
|
||||
async function unregister(logger, req, res) {
|
||||
const registrar = req.srf.locals.registrar;
|
||||
const uri = parseUri(req.registration.aor);
|
||||
const aor = `${uri.user}@${uri.host}`;
|
||||
const result = await registrar.remove(aor);
|
||||
|
||||
logger.debug({result}, `successfully unregistered ${req.registration.aor}`);
|
||||
|
||||
res.send(200, {
|
||||
headers: {
|
||||
'Contact': req.get('Contact'),
|
||||
'Expires': 0
|
||||
}
|
||||
});
|
||||
}
|
||||
21
lib/utils.js
Normal file
21
lib/utils.js
Normal file
@@ -0,0 +1,21 @@
|
||||
function isUacBehindNat(req) {
|
||||
|
||||
// no need for nat handling if wss or tcp being used
|
||||
if (req.protocol !== 'udp') return false;
|
||||
|
||||
// let's keep it simple -- if udp, let's crank down the register interval
|
||||
return true;
|
||||
}
|
||||
|
||||
function getSipProtocol(req) {
|
||||
if (req.getParsedHeader('Via')[0].protocol.toLowerCase().startsWith('wss')) return 'wss';
|
||||
if (req.getParsedHeader('Via')[0].protocol.toLowerCase().startsWith('ws')) return 'ws';
|
||||
if (req.getParsedHeader('Via')[0].protocol.toLowerCase().startsWith('tcp')) return 'tcp';
|
||||
if (req.getParsedHeader('Via')[0].protocol.toLowerCase().startsWith('udp')) return 'udp';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isUacBehindNat,
|
||||
getSipProtocol,
|
||||
NAT_EXPIRES: 30
|
||||
};
|
||||
211
package-lock.json
generated
211
package-lock.json
generated
@@ -10,8 +10,14 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.6.18",
|
||||
"@jambonz/http-authenticator": "^0.2.1",
|
||||
"@jambonz/mw-registrar": "^0.2.2",
|
||||
"@jambonz/realtimedb-helpers": "^0.4.29",
|
||||
"@jambonz/stats-collector": "^0.1.6",
|
||||
"@jambonz/time-series": "^0.1.12",
|
||||
"debug": "^4.3.4",
|
||||
"drachtio-mw-registration-parser": "^0.1.0",
|
||||
"drachtio-mw-response-time": "^1.0.2",
|
||||
"drachtio-srf": "^4.5.17",
|
||||
"pino": "^6.14.0"
|
||||
},
|
||||
@@ -266,6 +272,28 @@
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/http-authenticator": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/http-authenticator/-/http-authenticator-0.2.2.tgz",
|
||||
"integrity": "sha512-yl6CajF8c8BOTrXEB/AbTXgqrT6XeymwVZbJWeJG8HZA21UXkKCcM26b8f0P9qqokSvFj0ObjCk22Ks2ytSLNg==",
|
||||
"dependencies": {
|
||||
"bent": "^7.3.12",
|
||||
"debug": "^4.3.1",
|
||||
"drachtio-srf": "^4.4.63",
|
||||
"nonce": "^1.0.4",
|
||||
"qs": "^6.9.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/mw-registrar": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/mw-registrar/-/mw-registrar-0.2.2.tgz",
|
||||
"integrity": "sha512-CG0MUVRZZ+tBgB5kvjn5IS1R/OdNV5PpAsxCKE0ehe6XVJ1ap4ch9hSZmEh2q7qPnWu8sR451peF33dnoSeaPA==",
|
||||
"dependencies": {
|
||||
"@jambonz/promisify-redis": "^0.0.6",
|
||||
"debug": "^4.3.1",
|
||||
"redis": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/promisify-redis": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/promisify-redis/-/promisify-redis-0.0.6.tgz",
|
||||
@@ -291,6 +319,15 @@
|
||||
"redis": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/stats-collector": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/stats-collector/-/stats-collector-0.1.6.tgz",
|
||||
"integrity": "sha512-Qk+kpeb2wravpj3OYPC4N3ML1qoAzARNLfKGZtJ05PTAtfWoZMPnyfPAM9EJHIiVfs2Lec3CXDjEpHna0mc9EA==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.2",
|
||||
"hot-shots": "^8.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/time-series": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.12.tgz",
|
||||
@@ -640,6 +677,15 @@
|
||||
"url": "https://bevry.me/fund"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
@@ -887,6 +933,19 @@
|
||||
"ignored": "bin/ignored"
|
||||
}
|
||||
},
|
||||
"node_modules/drachtio-mw-registration-parser": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-mw-registration-parser/-/drachtio-mw-registration-parser-0.1.0.tgz",
|
||||
"integrity": "sha512-SNXEbFjOSuvDCArff/fH4xl1424sQTjPVzNE1Lq5LcyV9sVmW9+/CBBwwkFf1QgEtVUvgTa4w/Jx26Amb3hxaA==",
|
||||
"engines": {
|
||||
"node": ">= 6.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/drachtio-mw-response-time": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-mw-response-time/-/drachtio-mw-response-time-1.0.2.tgz",
|
||||
"integrity": "sha512-d+DtKuqhpkSBBkRfwcgS3x26T3lrdgo86yVWZ4wy+K8RtS1faT3hgLBq9EPEYSDkcw76r4klvdDWPhTrPqGAQw=="
|
||||
},
|
||||
"node_modules/drachtio-srf": {
|
||||
"version": "4.5.17",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.5.17.tgz",
|
||||
@@ -1350,6 +1409,12 @@
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/flat-cache": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
|
||||
@@ -1689,6 +1754,17 @@
|
||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz",
|
||||
"integrity": "sha512-Rf4YVNYpKjZ6ASAmibcwTNciQ5Co5Ztq6iZPEykHpkoflnD/K5ryE/rHehFsTm4NJj8nKDhbi3eKBWGogmNnkg=="
|
||||
},
|
||||
"node_modules/hot-shots": {
|
||||
"version": "8.5.2",
|
||||
"resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-8.5.2.tgz",
|
||||
"integrity": "sha512-1CKCtbYU28KtRriRW+mdOZzKce0WPqU0FOYE4bYs3gD1bFpOrYzQDXfQ09Qz9dJPEltasDOGhFKiYaiuW/j9Dg==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"unix-dgram": "2.0.x"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
@@ -2338,6 +2414,12 @@
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
|
||||
},
|
||||
"node_modules/nan": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
|
||||
"integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -2376,6 +2458,14 @@
|
||||
"resolved": "https://registry.npmjs.org/node-noop/-/node-noop-0.0.1.tgz",
|
||||
"integrity": "sha512-kAUvIRxZyDYFTLqGj+7zqXduG89vtqGmNMt9qDMvYH3H8uNTCOTz5ZN1q2Yg8++fWbzv+ERtYVqaOH42Ag5OpA=="
|
||||
},
|
||||
"node_modules/nonce": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/nonce/-/nonce-1.0.4.tgz",
|
||||
"integrity": "sha512-FVPu+tMZPP91HDwiq1DNhn9WIhg4/uo6mXR0xXAn0IMOxDmjJOkgbH0tm7qtowvAFZofWZRX+9KWZpNURrgtSA==",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/object-hash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||
@@ -2590,6 +2680,20 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/querystring": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||
@@ -3185,6 +3289,20 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/unix-dgram": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/unix-dgram/-/unix-dgram-2.0.4.tgz",
|
||||
"integrity": "sha512-7tpK6x7ls7J7pDrrAU63h93R0dVhRbPwiRRCawR10cl+2e1VOvF3bHlVJc6WI1dl/8qk5He673QU+Ogv7bPNaw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"bindings": "^1.3.0",
|
||||
"nan": "^2.13.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.48"
|
||||
}
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@@ -3634,6 +3752,28 @@
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@jambonz/http-authenticator": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/http-authenticator/-/http-authenticator-0.2.2.tgz",
|
||||
"integrity": "sha512-yl6CajF8c8BOTrXEB/AbTXgqrT6XeymwVZbJWeJG8HZA21UXkKCcM26b8f0P9qqokSvFj0ObjCk22Ks2ytSLNg==",
|
||||
"requires": {
|
||||
"bent": "^7.3.12",
|
||||
"debug": "^4.3.1",
|
||||
"drachtio-srf": "^4.4.63",
|
||||
"nonce": "^1.0.4",
|
||||
"qs": "^6.9.4"
|
||||
}
|
||||
},
|
||||
"@jambonz/mw-registrar": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/mw-registrar/-/mw-registrar-0.2.2.tgz",
|
||||
"integrity": "sha512-CG0MUVRZZ+tBgB5kvjn5IS1R/OdNV5PpAsxCKE0ehe6XVJ1ap4ch9hSZmEh2q7qPnWu8sR451peF33dnoSeaPA==",
|
||||
"requires": {
|
||||
"@jambonz/promisify-redis": "^0.0.6",
|
||||
"debug": "^4.3.1",
|
||||
"redis": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"@jambonz/promisify-redis": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/promisify-redis/-/promisify-redis-0.0.6.tgz",
|
||||
@@ -3656,6 +3796,15 @@
|
||||
"redis": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"@jambonz/stats-collector": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/stats-collector/-/stats-collector-0.1.6.tgz",
|
||||
"integrity": "sha512-Qk+kpeb2wravpj3OYPC4N3ML1qoAzARNLfKGZtJ05PTAtfWoZMPnyfPAM9EJHIiVfs2Lec3CXDjEpHna0mc9EA==",
|
||||
"requires": {
|
||||
"debug": "^4.3.2",
|
||||
"hot-shots": "^8.5.0"
|
||||
}
|
||||
},
|
||||
"@jambonz/time-series": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.12.tgz",
|
||||
@@ -3924,6 +4073,15 @@
|
||||
"resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz",
|
||||
"integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg=="
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
@@ -4121,6 +4279,16 @@
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"drachtio-mw-registration-parser": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-mw-registration-parser/-/drachtio-mw-registration-parser-0.1.0.tgz",
|
||||
"integrity": "sha512-SNXEbFjOSuvDCArff/fH4xl1424sQTjPVzNE1Lq5LcyV9sVmW9+/CBBwwkFf1QgEtVUvgTa4w/Jx26Amb3hxaA=="
|
||||
},
|
||||
"drachtio-mw-response-time": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-mw-response-time/-/drachtio-mw-response-time-1.0.2.tgz",
|
||||
"integrity": "sha512-d+DtKuqhpkSBBkRfwcgS3x26T3lrdgo86yVWZ4wy+K8RtS1faT3hgLBq9EPEYSDkcw76r4klvdDWPhTrPqGAQw=="
|
||||
},
|
||||
"drachtio-srf": {
|
||||
"version": "4.5.17",
|
||||
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.5.17.tgz",
|
||||
@@ -4481,6 +4649,12 @@
|
||||
"flat-cache": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"optional": true
|
||||
},
|
||||
"flat-cache": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
|
||||
@@ -4735,6 +4909,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"hot-shots": {
|
||||
"version": "8.5.2",
|
||||
"resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-8.5.2.tgz",
|
||||
"integrity": "sha512-1CKCtbYU28KtRriRW+mdOZzKce0WPqU0FOYE4bYs3gD1bFpOrYzQDXfQ09Qz9dJPEltasDOGhFKiYaiuW/j9Dg==",
|
||||
"requires": {
|
||||
"unix-dgram": "2.0.x"
|
||||
}
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
@@ -5232,6 +5414,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
|
||||
"integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
|
||||
"optional": true
|
||||
},
|
||||
"natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -5256,6 +5444,11 @@
|
||||
"resolved": "https://registry.npmjs.org/node-noop/-/node-noop-0.0.1.tgz",
|
||||
"integrity": "sha512-kAUvIRxZyDYFTLqGj+7zqXduG89vtqGmNMt9qDMvYH3H8uNTCOTz5ZN1q2Yg8++fWbzv+ERtYVqaOH42Ag5OpA=="
|
||||
},
|
||||
"nonce": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/nonce/-/nonce-1.0.4.tgz",
|
||||
"integrity": "sha512-FVPu+tMZPP91HDwiq1DNhn9WIhg4/uo6mXR0xXAn0IMOxDmjJOkgbH0tm7qtowvAFZofWZRX+9KWZpNURrgtSA=="
|
||||
},
|
||||
"object-hash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||
@@ -5420,6 +5613,14 @@
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"requires": {
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||
@@ -5852,6 +6053,16 @@
|
||||
"which-boxed-primitive": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"unix-dgram": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/unix-dgram/-/unix-dgram-2.0.4.tgz",
|
||||
"integrity": "sha512-7tpK6x7ls7J7pDrrAU63h93R0dVhRbPwiRRCawR10cl+2e1VOvF3bHlVJc6WI1dl/8qk5He673QU+Ogv7bPNaw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"bindings": "^1.3.0",
|
||||
"nan": "^2.13.2"
|
||||
}
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
|
||||
@@ -28,8 +28,14 @@
|
||||
"homepage": "https://github.com/xquanluu/sbc-outbound-handler#readme",
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.6.18",
|
||||
"@jambonz/realtimedb-helpers": "^0.4.29",
|
||||
"@jambonz/http-authenticator": "^0.2.1",
|
||||
"@jambonz/mw-registrar": "^0.2.2",
|
||||
"@jambonz/stats-collector": "^0.1.6",
|
||||
"@jambonz/time-series": "^0.1.12",
|
||||
"debug": "^4.3.4",
|
||||
"drachtio-mw-registration-parser": "^0.1.0",
|
||||
"drachtio-mw-response-time": "^1.0.2",
|
||||
"@jambonz/realtimedb-helpers": "^0.4.29",
|
||||
"drachtio-srf": "^4.5.17",
|
||||
"pino": "^6.14.0"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '3'
|
||||
|
||||
networks:
|
||||
sbc-registrar:
|
||||
sbc-sip-sidecar:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
sbc-registrar:
|
||||
sbc-sip-sidecar:
|
||||
ipv4_address: 172.39.0.2
|
||||
sbc:
|
||||
image: drachtio/drachtio-server:latest
|
||||
@@ -28,17 +28,28 @@ services:
|
||||
ports:
|
||||
- "9022:9022/tcp"
|
||||
networks:
|
||||
sbc-registrar:
|
||||
sbc-sip-sidecar:
|
||||
ipv4_address: 172.39.0.10
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
auth-server:
|
||||
image: jambonz/customer-auth-server:latest
|
||||
command: npm start
|
||||
ports:
|
||||
- "4000:4000/tcp"
|
||||
env_file: docker.env
|
||||
networks:
|
||||
sbc-sip-sidecar:
|
||||
ipv4_address: 172.39.0.12
|
||||
|
||||
redis:
|
||||
image: redis:5-alpine
|
||||
ports:
|
||||
- "16379:6379/tcp"
|
||||
networks:
|
||||
sbc-registrar:
|
||||
sbc-sip-sidecar:
|
||||
ipv4_address: 172.39.0.13
|
||||
|
||||
sipp-uas-auth-register:
|
||||
@@ -49,7 +60,7 @@ services:
|
||||
- ./scenarios:/tmp
|
||||
tty: true
|
||||
networks:
|
||||
sbc-registrar:
|
||||
sbc-sip-sidecar:
|
||||
ipv4_address: 172.39.0.14
|
||||
|
||||
sipp-uas-auth-register-fail:
|
||||
@@ -60,5 +71,14 @@ services:
|
||||
- ./scenarios:/tmp
|
||||
tty: true
|
||||
networks:
|
||||
sbc-registrar:
|
||||
sbc-sip-sidecar:
|
||||
ipv4_address: 172.39.0.15
|
||||
uas:
|
||||
image: drachtio/sipp:latest
|
||||
command: sipp -sf /tmp/uas.xml
|
||||
volumes:
|
||||
- ./scenarios:/tmp
|
||||
tty: true
|
||||
networks:
|
||||
sbc-sip-sidecar:
|
||||
ipv4_address: 172.39.0.60
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
require('./docker_start');
|
||||
require('./create-test-db');
|
||||
require('./regbot-tests');
|
||||
require('./sip-register-tests');
|
||||
require('./sip-options-tests');
|
||||
require('./docker_stop');
|
||||
|
||||
3
test/scenarios/bad_password.csv
Normal file
3
test/scenarios/bad_password.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
SEQUENTIAL
|
||||
# user, domain, authentication
|
||||
jane;jambonz.org;[authentication username=jane password=8765]
|
||||
|
3
test/scenarios/bad_realm.csv
Normal file
3
test/scenarios/bad_realm.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
SEQUENTIAL
|
||||
# user, domain, authentication
|
||||
john;fail.com;[authentication username=john password=1234]
|
||||
|
3
test/scenarios/good_user.csv
Normal file
3
test/scenarios/good_user.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
SEQUENTIAL
|
||||
# user, domain, authentication
|
||||
john;jambonz.org;[authentication username=john password=1234]
|
||||
|
3
test/scenarios/good_user2.csv
Normal file
3
test/scenarios/good_user2.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
SEQUENTIAL
|
||||
# user, domain, authentication
|
||||
jane;jambonz.org;[authentication username=jane password=5678]
|
||||
|
50
test/scenarios/uac-add-fs-1.xml
Normal file
50
test/scenarios/uac-add-fs-1.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
X-FS-Status: open
|
||||
X-FS-Calls: 0
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="1" search_in="hdr" header="X-Members:" check_it="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
50
test/scenarios/uac-add-fs-2.xml
Normal file
50
test/scenarios/uac-add-fs-2.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
X-FS-Status: open
|
||||
X-FS-Calls: 0
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="2" search_in="hdr" header="X-Members:" check_it="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
50
test/scenarios/uac-add-rtp-1.xml
Normal file
50
test/scenarios/uac-add-rtp-1.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
X-RTP-Status: open
|
||||
X-RTP-Calls: 0
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="1" search_in="hdr" header="X-Members:" check_it="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
50
test/scenarios/uac-add-rtp-2.xml
Normal file
50
test/scenarios/uac-add-rtp-2.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
X-RTP-Status: open
|
||||
X-RTP-Calls: 0
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="2" search_in="hdr" header="X-Members:" check_it="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
48
test/scenarios/uac-external-options-ping.xml
Normal file
48
test/scenarios/uac-external-options-ping.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="\d+" search_in="hdr" header="X-Members:" check_it_inverse="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
73
test/scenarios/uac-register-auth-failure-expect-403.xml
Normal file
73
test/scenarios/uac-register-auth-failure-expect-403.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
CSeq: 7 REGISTER
|
||||
Subject: uac-register-auth-failure-expect-403
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 3600
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="401" auth="true" rtd="true">
|
||||
</recv>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
CSeq: 8 REGISTER
|
||||
Subject: uac-register-auth-failure-expect-403
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 3600
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
[field2]
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="403">
|
||||
</recv>
|
||||
|
||||
<ResponseTimeRepartition value="10, 20"/>
|
||||
<CallLengthRepartition value="10"/>
|
||||
</scenario>
|
||||
|
||||
29
test/scenarios/uac-register-auth-failure-expect-503.xml
Normal file
29
test/scenarios/uac-register-auth-failure-expect-503.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
CSeq: 7 REGISTER
|
||||
Subject: uac-register-auth-failure-expect-403
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 3600
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="503" auth="true" rtd="true">
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
|
||||
55
test/scenarios/uac-register-auth-success.xml
Normal file
55
test/scenarios/uac-register-auth-success.xml
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
Subject: uac-register-auth-success
|
||||
CSeq: 7 REGISTER
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 3600
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="401" auth="true" rtd="true">
|
||||
</recv>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
CSeq: 8 REGISTER
|
||||
Subject: uac-register-auth-success
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 3600
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
[field2]
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="200">
|
||||
</recv>
|
||||
|
||||
<ResponseTimeRepartition value="10, 20"/>
|
||||
<CallLengthRepartition value="10"/>
|
||||
</scenario>
|
||||
|
||||
73
test/scenarios/uac-register-auth-success2.xml
Normal file
73
test/scenarios/uac-register-auth-success2.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg2///[call_id]
|
||||
Subject: uac-register-auth-success
|
||||
CSeq: 7 REGISTER
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 5
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="401" auth="true" rtd="true">
|
||||
</recv>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg2///[call_id]
|
||||
CSeq: 8 REGISTER
|
||||
Subject: uac-register-auth-success
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 5
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
[field2]
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="200">
|
||||
</recv>
|
||||
|
||||
<ResponseTimeRepartition value="10, 20"/>
|
||||
<CallLengthRepartition value="10"/>
|
||||
</scenario>
|
||||
|
||||
28
test/scenarios/uac-register-unknown-realm.xml
Normal file
28
test/scenarios/uac-register-unknown-realm.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
CSeq: 7 REGISTER
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 3600
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="403">
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
|
||||
28
test/scenarios/uac-reject-ipv4-realm.xml
Normal file
28
test/scenarios/uac-reject-ipv4-realm.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:192.169.1.1 SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
CSeq: 7 REGISTER
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 3600
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="403">
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
|
||||
50
test/scenarios/uac-remove-fs-1.xml
Normal file
50
test/scenarios/uac-remove-fs-1.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
X-FS-Status: closed
|
||||
X-FS-Calls: 0
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="1" search_in="hdr" header="X-Members:" check_it="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
50
test/scenarios/uac-remove-fs-2.xml
Normal file
50
test/scenarios/uac-remove-fs-2.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
X-FS-Status: closed
|
||||
X-FS-Calls: 0
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="0" search_in="hdr" header="X-Members:" check_it="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
50
test/scenarios/uac-remove-rtp-1.xml
Normal file
50
test/scenarios/uac-remove-rtp-1.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
X-RTP-Status: closed
|
||||
X-RTP-Calls: 0
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="1" search_in="hdr" header="X-Members:" check_it="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
50
test/scenarios/uac-remove-rtp-2.xml
Normal file
50
test/scenarios/uac-remove-rtp-2.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 OPTIONS
|
||||
Max-Forwards: 70
|
||||
Subject: Performance Test
|
||||
X-RTP-Status: closed
|
||||
X-RTP-Calls: 0
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" rtd="true">
|
||||
<action>
|
||||
<ereg regexp="0" search_in="hdr" header="X-Members:" check_it="true" assign_to="1"/>
|
||||
<log message="[$1]"/>
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
</scenario>
|
||||
71
test/scenarios/uac-unregister-auth-success.xml
Normal file
71
test/scenarios/uac-unregister-auth-success.xml
Normal file
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uac' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic Sipstone UAC">
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
CSeq: 7 REGISTER
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 0
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="401" auth="true" rtd="true">
|
||||
</recv>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
REGISTER sip:[field1] SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
Max-Forwards: 70
|
||||
From: "sipp" <sip:[field0]@[field1]>;tag=[call_number]
|
||||
To: "sipp" <sip:[field0]@[field1]>
|
||||
Call-ID: reg///[call_id]
|
||||
CSeq: 8 REGISTER
|
||||
Contact: <sip:sipp@[local_ip]:[local_port]>
|
||||
Expires: 0
|
||||
Content-Length: 0
|
||||
User-Agent: SIPp
|
||||
[field2]
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="200">
|
||||
</recv>
|
||||
|
||||
<ResponseTimeRepartition value="10, 20"/>
|
||||
<CallLengthRepartition value="10"/>
|
||||
</scenario>
|
||||
|
||||
101
test/scenarios/uas-auth-register copy.xml
Normal file
101
test/scenarios/uas-auth-register copy.xml
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uas' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic UAS responder">
|
||||
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
|
||||
<!-- are saved and used for following messages sent. Useful to test -->
|
||||
<!-- against stateful SIP proxies/B2BUAs. -->
|
||||
<recv request="REGISTER" crlf="true">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 401 Unauthorized
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
WWW-Authenticate: Digest realm="sip.jambonz.org", nonce="4cdbb733645816512687270b83d2ae5d11e4d9d8"
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv request="REGISTER" crlf="true">
|
||||
<action>
|
||||
<verifyauth assign_to="authvalid" username="foo" password="bar" />
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
<nop hide="true" test="authvalid" next="goodauth" />
|
||||
|
||||
<send next="endit">
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 403 Forbidden
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>;expires=60
|
||||
Content-Type: application/sdp
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<label id="goodauth"/>
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 200 OK
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>;expires=60
|
||||
Content-Type: application/sdp
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<label id="badauth"/>
|
||||
|
||||
<label id="endit"/>
|
||||
|
||||
<!-- Keep the call open for a while in case the 200 is lost to be -->
|
||||
<!-- able to retransmit it if we receive the BYE again. -->
|
||||
<timewait milliseconds="4000"/>
|
||||
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
|
||||
</scenario>
|
||||
|
||||
101
test/scenarios/uas-auth-register2.xml
Normal file
101
test/scenarios/uas-auth-register2.xml
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uas' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic UAS responder">
|
||||
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
|
||||
<!-- are saved and used for following messages sent. Useful to test -->
|
||||
<!-- against stateful SIP proxies/B2BUAs. -->
|
||||
<recv request="REGISTER" crlf="true">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 401 Unauthorized
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
WWW-Authenticate: Digest realm="sip.jambonz.org", nonce="4cdbb733645816512687270b83d2ae5d11e4d9d8"
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv request="REGISTER" crlf="true">
|
||||
<action>
|
||||
<verifyauth assign_to="authvalid" username="foo" password="baz" />
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
<nop hide="true" test="authvalid" next="goodauth" />
|
||||
|
||||
<send next="endit">
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 403 Forbidden
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>;expires=60
|
||||
Content-Type: application/sdp
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<label id="goodauth"/>
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 200 OK
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>;expires=60
|
||||
Content-Type: application/sdp
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<label id="badauth"/>
|
||||
|
||||
<label id="endit"/>
|
||||
|
||||
<!-- Keep the call open for a while in case the 200 is lost to be -->
|
||||
<!-- able to retransmit it if we receive the BYE again. -->
|
||||
<timewait milliseconds="4000"/>
|
||||
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
|
||||
</scenario>
|
||||
|
||||
120
test/scenarios/uas.xml
Normal file
120
test/scenarios/uas.xml
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp default 'uas' scenario. -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="Basic UAS responder">
|
||||
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
|
||||
<!-- are saved and used for following messages sent. Useful to test -->
|
||||
<!-- against stateful SIP proxies/B2BUAs. -->
|
||||
<recv request="INVITE" crlf="true">
|
||||
<action>
|
||||
<ereg regexp=".*" search_in="hdr" header="Subject:" assign_to="1" />
|
||||
</action>
|
||||
</recv>
|
||||
|
||||
<!-- The '[last_*]' keyword is replaced automatically by the -->
|
||||
<!-- specified header if it was present in the last message received -->
|
||||
<!-- (except if it was a retransmission). If the header was not -->
|
||||
<!-- present or if no message has been received, the '[last_*]' -->
|
||||
<!-- keyword is discarded, and all bytes until the end of the line -->
|
||||
<!-- are also discarded. -->
|
||||
<!-- -->
|
||||
<!-- If the specified header was present several times in the -->
|
||||
<!-- message, all occurrences are concatenated (CRLF separated) -->
|
||||
<!-- to be used in place of the '[last_*]' keyword. -->
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 180 Ringing
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
[last_Record-Route:]
|
||||
Subject:[$1]
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 200 OK
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
[last_Record-Route:]
|
||||
Subject:[$1]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[media_ip_type] [media_ip]
|
||||
t=0 0
|
||||
m=audio [media_port] RTP/AVP 0
|
||||
a=rtpmap:0 PCMU/8000
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv request="ACK"
|
||||
rtd="true"
|
||||
crlf="true">
|
||||
</recv>
|
||||
|
||||
<recv request="BYE">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 200 OK
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<!-- Keep the call open for a while in case the 200 is lost to be -->
|
||||
<!-- able to retransmit it if we receive the BYE again. -->
|
||||
<timewait milliseconds="4000"/>
|
||||
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
|
||||
</scenario>
|
||||
|
||||
94
test/sipp.js
Normal file
94
test/sipp.js
Normal file
@@ -0,0 +1,94 @@
|
||||
const { spawn } = require('child_process');
|
||||
const debug = require('debug')('jambonz:ci');
|
||||
let network;
|
||||
const obj = {};
|
||||
let output = '';
|
||||
let idx = 1;
|
||||
|
||||
function clearOutput() {
|
||||
output = '';
|
||||
}
|
||||
|
||||
function addOutput(str) {
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (str.charCodeAt(i) < 128) output += str.charAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = (networkName) => {
|
||||
network = networkName ;
|
||||
return obj;
|
||||
};
|
||||
|
||||
obj.output = () => {
|
||||
return output;
|
||||
};
|
||||
|
||||
obj.sippUac = (file, regObj, bindAddress, injectionFile) => {
|
||||
const cmd = 'docker';
|
||||
let args = null;
|
||||
if(regObj) {
|
||||
args = [
|
||||
'run', '--rm', '--net', `${network}`,
|
||||
'-v', `${__dirname}/scenarios:/tmp/scenarios`,
|
||||
'drachtio/sipp', 'sipp', `${regObj.remote_host}`, // remote host is require on auth
|
||||
'-inf', `/tmp/scenarios/${regObj.data_file}`,
|
||||
'-sf', `/tmp/scenarios/${file}`,
|
||||
'-m', '1',
|
||||
'-sleep', '250ms',
|
||||
'-nostdin',
|
||||
'-cid_str', `%u-%p@%s-${idx++}`,
|
||||
'sbc', '-trace_msg'
|
||||
];
|
||||
} else if (injectionFile) {
|
||||
args = [
|
||||
'run', '-t', '--rm', '--net', `${network}`,
|
||||
'-v', `${__dirname}/scenarios:/tmp/scenarios`,
|
||||
'drachtio/sipp', 'sipp', '-sf', `/tmp/scenarios/${file}`,
|
||||
'-inf', `/tmp/scenarios/${injectionFile}`,
|
||||
'-m', '1',
|
||||
'-sleep', '250ms',
|
||||
'-nostdin',
|
||||
'-cid_str', `%u-%p@%s-${idx++}`,
|
||||
'172.39.0.10'];
|
||||
}
|
||||
else {
|
||||
args = [
|
||||
'run', '-t', '--rm', '--net', `${network}`,
|
||||
'-v', `${__dirname}/scenarios:/tmp/scenarios`,
|
||||
'drachtio/sipp', 'sipp', '-sf', `/tmp/scenarios/${file}`,
|
||||
'-m', '1',
|
||||
'-sleep', '250ms',
|
||||
'-nostdin',
|
||||
'-cid_str', `%u-%p@%s-${idx++}`,
|
||||
'172.39.0.10'];
|
||||
}
|
||||
|
||||
if (bindAddress) args.splice(5, 0, '--ip', bindAddress);
|
||||
|
||||
clearOutput();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const child_process = spawn(cmd, args, {stdio: ['inherit', 'pipe', 'pipe']});
|
||||
|
||||
child_process.on('exit', (code, signal) => {
|
||||
if (code === 0) {
|
||||
return resolve();
|
||||
}
|
||||
console.log(`sipp exited with non-zero code ${code} signal ${signal}`);
|
||||
reject(code);
|
||||
});
|
||||
child_process.on('error', (error) => {
|
||||
console.log(`error spawing child process for docker: ${args}`);
|
||||
});
|
||||
|
||||
child_process.stdout.on('data', (data) => {
|
||||
debug(`stdout: ${data}`);
|
||||
addOutput(data.toString());
|
||||
});
|
||||
child_process.stderr.on('data', (data) => {
|
||||
debug(`stderr: ${data}`);
|
||||
addOutput(data.toString());
|
||||
});
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user