mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2026-07-04 19:32:01 +00:00
added support for sip:request verb, used to send SIP INFO/NOTIFY etc during call (#116)
This commit is contained in:
@@ -17,6 +17,9 @@ function makeTask(logger, obj, parent) {
|
|||||||
case TaskName.SipDecline:
|
case TaskName.SipDecline:
|
||||||
const TaskSipDecline = require('./sip_decline');
|
const TaskSipDecline = require('./sip_decline');
|
||||||
return new TaskSipDecline(logger, data, parent);
|
return new TaskSipDecline(logger, data, parent);
|
||||||
|
case TaskName.SipRequest:
|
||||||
|
const TaskSipRequest = require('./sip_request');
|
||||||
|
return new TaskSipRequest(logger, data, parent);
|
||||||
case TaskName.SipRefer:
|
case TaskName.SipRefer:
|
||||||
const TaskSipRefer = require('./sip_refer');
|
const TaskSipRefer = require('./sip_refer');
|
||||||
return new TaskSipRefer(logger, data, parent);
|
return new TaskSipRefer(logger, data, parent);
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
const Task = require('./task');
|
||||||
|
const {TaskName, TaskPreconditions} = require('../utils/constants');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a SIP request (e.g. INFO, NOTIFY, etc) on an existing call leg
|
||||||
|
*/
|
||||||
|
class TaskSipRequest extends Task {
|
||||||
|
constructor(logger, opts) {
|
||||||
|
super(logger, opts);
|
||||||
|
this.preconditions = TaskPreconditions.StableCall;
|
||||||
|
|
||||||
|
this.method = this.data.method.toUpperCase();
|
||||||
|
this.headers = this.data.headers || {};
|
||||||
|
this.body = this.data.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() { return TaskName.SipRequest; }
|
||||||
|
|
||||||
|
async exec(cs, dlg) {
|
||||||
|
super.exec(cs);
|
||||||
|
try {
|
||||||
|
this.logger.info({dlg}, `TaskSipRequest: sending a SIP ${this.method}`);
|
||||||
|
const res = await dlg.request({
|
||||||
|
method: this.method,
|
||||||
|
headers: this.headers,
|
||||||
|
body: this.body
|
||||||
|
});
|
||||||
|
const result = {result: 'success', sipStatus: res.status};
|
||||||
|
this.span.setAttributes({
|
||||||
|
...this.headers,
|
||||||
|
...(this.body && {body: this.body}),
|
||||||
|
'response.status_code': res.status
|
||||||
|
});
|
||||||
|
this.logger.debug({result}, `TaskSipRequest: received response to ${this.method}`);
|
||||||
|
await this.performAction(result);
|
||||||
|
} catch (err) {
|
||||||
|
this.logger.error({err}, 'TaskSipRequest: error');
|
||||||
|
this.span.setAttributes({
|
||||||
|
...this.headers,
|
||||||
|
...(this.body && {body: this.body}),
|
||||||
|
'response.error': err.message
|
||||||
|
});
|
||||||
|
await this.performAction({result: 'failed', err: err.message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TaskSipRequest;
|
||||||
@@ -9,6 +9,17 @@
|
|||||||
"status"
|
"status"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"sip:request": {
|
||||||
|
"properties": {
|
||||||
|
"method": "string",
|
||||||
|
"body": "string",
|
||||||
|
"headers": "object",
|
||||||
|
"actionHook": "object|string"
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"method"
|
||||||
|
]
|
||||||
|
},
|
||||||
"sip:refer": {
|
"sip:refer": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"referTo": "string",
|
"referTo": "string",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"Redirect": "redirect",
|
"Redirect": "redirect",
|
||||||
"RestDial": "rest:dial",
|
"RestDial": "rest:dial",
|
||||||
"SipDecline": "sip:decline",
|
"SipDecline": "sip:decline",
|
||||||
|
"SipRequest": "sip:request",
|
||||||
"SipRefer": "sip:refer",
|
"SipRefer": "sip:refer",
|
||||||
"SipNotify": "sip:notify",
|
"SipNotify": "sip:notify",
|
||||||
"SipRedirect": "sip:redirect",
|
"SipRedirect": "sip:redirect",
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ INSERT INTO `applications` VALUES ('24d0f6af-e976-44dd-a2e8-41c7b55abe33','say a
|
|||||||
INSERT INTO `applications` VALUES ('17461c69-56b5-4dab-ad83-1c43a0f93a3d','gather',NULL,'bb845d4b-83a9-4cde-a6e9-50f3743bab3f','10692465-a511-4277-9807-b7157e4f81e1','293904c1-351b-4bca-8d58-1a29b853c7db',NULL,'google','en-US','en-US-Standard-C','google','en-US');
|
INSERT INTO `applications` VALUES ('17461c69-56b5-4dab-ad83-1c43a0f93a3d','gather',NULL,'bb845d4b-83a9-4cde-a6e9-50f3743bab3f','10692465-a511-4277-9807-b7157e4f81e1','293904c1-351b-4bca-8d58-1a29b853c7db',NULL,'google','en-US','en-US-Standard-C','google','en-US');
|
||||||
INSERT INTO `applications` VALUES ('baf9213b-5556-4c20-870c-586392ed246f','transcribe',NULL,'bb845d4b-83a9-4cde-a6e9-50f3743bab3f','ecb67a8f-f7ce-4919-abf0-bbc69c1001e5','293904c1-351b-4bca-8d58-1a29b853c7db',NULL,'google','en-US','en-US-Standard-C','google','en-US');
|
INSERT INTO `applications` VALUES ('baf9213b-5556-4c20-870c-586392ed246f','transcribe',NULL,'bb845d4b-83a9-4cde-a6e9-50f3743bab3f','ecb67a8f-f7ce-4919-abf0-bbc69c1001e5','293904c1-351b-4bca-8d58-1a29b853c7db',NULL,'google','en-US','en-US-Standard-C','google','en-US');
|
||||||
INSERT INTO `applications` VALUES ('ae026ab5-3029-47b4-9d7c-236e3a4b4ebe','transcribe account 2',NULL,'622f62e4-303a-49f2-bbe0-eb1e1714e37a','ecb67a8f-f7ce-4919-abf0-bbc69c1001e5','293904c1-351b-4bca-8d58-1a29b853c7db',NULL,'google','en-US','en-US-Standard-C','google','en-US');
|
INSERT INTO `applications` VALUES ('ae026ab5-3029-47b4-9d7c-236e3a4b4ebe','transcribe account 2',NULL,'622f62e4-303a-49f2-bbe0-eb1e1714e37a','ecb67a8f-f7ce-4919-abf0-bbc69c1001e5','293904c1-351b-4bca-8d58-1a29b853c7db',NULL,'google','en-US','en-US-Standard-C','google','en-US');
|
||||||
|
INSERT INTO `applications` VALUES ('195d9507-6a42-46a8-825f-f009e729d023','sip info',NULL,'bb845d4b-83a9-4cde-a6e9-50f3743bab3f','c9113e7a-741f-48b9-96c1-f2f78176eeb3','293904c1-351b-4bca-8d58-1a29b853c7db',NULL,'google','en-US','en-US-Standard-C','google','en-US');
|
||||||
/*!40000 ALTER TABLE `applications` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `applications` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
@@ -449,6 +450,7 @@ INSERT INTO `phone_numbers` VALUES ('e686a320-0725-418f-be65-532159bdc3ed','1617
|
|||||||
INSERT INTO `phone_numbers` VALUES ('05eeed62-b29b-4679-bf38-d7a4e318be44','16174000003','5145b436-2f38-4029-8d4c-fd8c67831c7a','bb845d4b-83a9-4cde-a6e9-50f3743bab3f','17461c69-56b5-4dab-ad83-1c43a0f93a3d', NULL);
|
INSERT INTO `phone_numbers` VALUES ('05eeed62-b29b-4679-bf38-d7a4e318be44','16174000003','5145b436-2f38-4029-8d4c-fd8c67831c7a','bb845d4b-83a9-4cde-a6e9-50f3743bab3f','17461c69-56b5-4dab-ad83-1c43a0f93a3d', NULL);
|
||||||
INSERT INTO `phone_numbers` VALUES ('f3c53863-b629-4cf6-9dcb-c7fb7072314b','16174000004','5145b436-2f38-4029-8d4c-fd8c67831c7a','bb845d4b-83a9-4cde-a6e9-50f3743bab3f','baf9213b-5556-4c20-870c-586392ed246f', NULL);
|
INSERT INTO `phone_numbers` VALUES ('f3c53863-b629-4cf6-9dcb-c7fb7072314b','16174000004','5145b436-2f38-4029-8d4c-fd8c67831c7a','bb845d4b-83a9-4cde-a6e9-50f3743bab3f','baf9213b-5556-4c20-870c-586392ed246f', NULL);
|
||||||
INSERT INTO `phone_numbers` VALUES ('f6416c17-829a-4f11-9c32-f0d00e4a9ae9','16174000005','5145b436-2f38-4029-8d4c-fd8c67831c7a','622f62e4-303a-49f2-bbe0-eb1e1714e37a','ae026ab5-3029-47b4-9d7c-236e3a4b4ebe', NULL);
|
INSERT INTO `phone_numbers` VALUES ('f6416c17-829a-4f11-9c32-f0d00e4a9ae9','16174000005','5145b436-2f38-4029-8d4c-fd8c67831c7a','622f62e4-303a-49f2-bbe0-eb1e1714e37a','ae026ab5-3029-47b4-9d7c-236e3a4b4ebe', NULL);
|
||||||
|
INSERT INTO `phone_numbers` VALUES ('964d0581-9627-44cb-be20-8118050406b2','16174000006','5145b436-2f38-4029-8d4c-fd8c67831c7a','bb845d4b-83a9-4cde-a6e9-50f3743bab3f','195d9507-6a42-46a8-825f-f009e729d023', NULL);
|
||||||
/*!40000 ALTER TABLE `phone_numbers` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `phone_numbers` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
@@ -736,6 +738,7 @@ INSERT INTO `webhooks` VALUES ('c71e79db-24f2-4866-a3ee-febb0f97b341','http://12
|
|||||||
INSERT INTO `webhooks` VALUES ('54ab0976-a6c0-45d8-89a4-d90d45bf9d96','http://127.0.0.1:3101/','POST',NULL,NULL);
|
INSERT INTO `webhooks` VALUES ('54ab0976-a6c0-45d8-89a4-d90d45bf9d96','http://127.0.0.1:3101/','POST',NULL,NULL);
|
||||||
INSERT INTO `webhooks` VALUES ('10692465-a511-4277-9807-b7157e4f81e1','http://127.0.0.1:3102/','POST',NULL,NULL);
|
INSERT INTO `webhooks` VALUES ('10692465-a511-4277-9807-b7157e4f81e1','http://127.0.0.1:3102/','POST',NULL,NULL);
|
||||||
INSERT INTO `webhooks` VALUES ('ecb67a8f-f7ce-4919-abf0-bbc69c1001e5','http://127.0.0.1:3103/','POST',NULL,NULL);
|
INSERT INTO `webhooks` VALUES ('ecb67a8f-f7ce-4919-abf0-bbc69c1001e5','http://127.0.0.1:3103/','POST',NULL,NULL);
|
||||||
|
INSERT INTO `webhooks` VALUES ('c9113e7a-741f-48b9-96c1-f2f78176eeb3','http://127.0.0.1:3104/','POST',NULL,NULL);
|
||||||
/*!40000 ALTER TABLE `webhooks` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `webhooks` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||||
|
|||||||
@@ -123,6 +123,18 @@ services:
|
|||||||
fs:
|
fs:
|
||||||
ipv4_address: 172.38.0.63
|
ipv4_address: 172.38.0.63
|
||||||
|
|
||||||
|
webhook-sip-info:
|
||||||
|
image: jambonz/webhook-test-scaffold:latest
|
||||||
|
environment:
|
||||||
|
APP_PATH: /tmp/info.json
|
||||||
|
ports:
|
||||||
|
- "3104:3000/tcp"
|
||||||
|
volumes:
|
||||||
|
- ./test-apps:/tmp
|
||||||
|
networks:
|
||||||
|
fs:
|
||||||
|
ipv4_address: 172.38.0.64
|
||||||
|
|
||||||
influxdb:
|
influxdb:
|
||||||
image: influxdb:1.8
|
image: influxdb:1.8
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ require('./account-validation-tests');
|
|||||||
require('./webhooks-tests');
|
require('./webhooks-tests');
|
||||||
require('./say-tests');
|
require('./say-tests');
|
||||||
require('./gather-tests');
|
require('./gather-tests');
|
||||||
|
require('./sip-request-tests');
|
||||||
require('./remove-test-db');
|
require('./remove-test-db');
|
||||||
require('./docker_stop');
|
require('./docker_stop');
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||||
|
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||||
|
|
||||||
|
|
||||||
|
<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[
|
||||||
|
|
||||||
|
INVITE sip:16174000006@[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: <sip:16174000006@[remote_ip]:[remote_port]>
|
||||||
|
Call-ID: [call_id]
|
||||||
|
CSeq: 1 INVITE
|
||||||
|
Contact: sip:sipp@[local_ip]:[local_port]
|
||||||
|
Max-Forwards: 70
|
||||||
|
X-Account-Sid: bb845d4b-83a9-4cde-a6e9-50f3743bab3f
|
||||||
|
Subject: uac-gather-account-creds-success
|
||||||
|
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 response="100"
|
||||||
|
optional="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<recv response="180" optional="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<recv response="183" optional="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<!-- 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 response="200" rtd="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<!-- Packet lost can be simulated in any send/recv message by -->
|
||||||
|
<!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
|
||||||
|
<send>
|
||||||
|
<![CDATA[
|
||||||
|
|
||||||
|
ACK sip:16174000006@[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: 16174000006 <sip:16174000006@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||||
|
Call-ID: [call_id]
|
||||||
|
CSeq: 1 ACK
|
||||||
|
Contact: sip:sipp@[local_ip]:[local_port]
|
||||||
|
Max-Forwards: 70
|
||||||
|
Subject: uac-gather-account-creds-success
|
||||||
|
Content-Length: 0
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</send>
|
||||||
|
|
||||||
|
<recv request="INFO">
|
||||||
|
</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>
|
||||||
|
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
</scenario>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
const test = require('tape');
|
||||||
|
const { sippUac } = require('./sipp')('test_fs');
|
||||||
|
const bent = require('bent');
|
||||||
|
const getJSON = bent('json')
|
||||||
|
const clearModule = require('clear-module');
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
function connect(connectable) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connectable.on('connect', () => {
|
||||||
|
return resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
test('sending SIP in-dialog requests tests', async(t) => {
|
||||||
|
clearModule.all();
|
||||||
|
const {srf, disconnect} = require('../app');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await connect(srf);
|
||||||
|
await sippUac('uac-send-info-during-dialog.xml', '172.38.0.10');
|
||||||
|
const obj = await getJSON('http://127.0.0.1:3104/actionHook');
|
||||||
|
t.ok(obj.result === 'success' && obj.sip_status === 200, 'successfully sent SIP INFO');
|
||||||
|
|
||||||
|
disconnect();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`error received: ${err}`);
|
||||||
|
disconnect();
|
||||||
|
t.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"verb": "say",
|
||||||
|
"text": "hello"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"verb": "sip:request",
|
||||||
|
"method": "info",
|
||||||
|
"headers": {
|
||||||
|
"Content-Type": "application/text"
|
||||||
|
},
|
||||||
|
"body": "here I am ",
|
||||||
|
"actionHook": "/actionHook"
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user