drachtio / drachtio-srf Goto Github PK
View Code? Open in Web Editor NEWdrachtio signaling resource framework
Home Page: https://drachtio.org
License: MIT License
drachtio signaling resource framework
Home Page: https://drachtio.org
License: MIT License
When a 401 auth challenge is received for a request (e.g. REGISTER) sent using TCP or TLS transports, the response reply is always proxied to sip:<ip_address>:<port>
on the default UDP transport which breaks the exchange.
This is caused by the code around line 107 of digest-client.js which is trying to avoid new DNS lookups but in doing loses critical elements of the original uri.
Have a proto-fix, will test and submit a PR shortly.
Hi,
I need to receive cdr:start and cdr:stop events but even though cdr:attempt and cdr:stop events received, start event does not receive, in my config file cdr config is 'true', is there anything more i need to do? I also added drachtio.log file.
Thanks
drachtio.zip
Please consider this.
Caller should send UPDATE with new SDP before receiving 200 OK from callee.
But in current SRF, Dialog request method for sending UPDATE will be available from receiving 200 OK. Any suggestion?
Or, Can I send UPDATE via out-of-dialog method, request with same Call-ID?
Thank you.
I cannot get drachtio to resend another INVITE after receiving a 407 Proxy Authentication challenge.
First I tried with drachtio-srf, but it only sends an ACK and nothing else happens:
srf.createUacDialog(`sip:${opts.callednumber}@${opts.domain}`, {
localSdp: sdp,
callerNumber: opts.user,
calledNumber: opts.calledNumber,
headers: {
'From': `sip:${opts.user}@${opts.domain}`,
'User-Agent': 'test UA',
'Contact': `sip:${opts.user}@${opts.domain}:${opts.hostport}`
},
auth: {
username: opts.user,
password: opts.password
}
}, function(err, dialog) {
if( err ) { return err }
debug('created uac dialog: ', dialog);
});
When I tried using drachtio, the same SIP signaling occurred, but I did get an error:
Here is the code:
srf.request({
uri: `sip:${opts.callednumber}@${opts.domain}`,
method: 'INVITE',
headers: {
'From': `sip:${opts.user}@${opts.domain}`,
'User-Agent': 'test UA',
'Contact': `sip:${opts.user}@${opts.domain}:${opts.hostport}`,
},
auth: {
username: opts.user,
password: opts.password
}
}, function (err, req ){
if( err ) console.error( err );
req.on('response', function(response) {
console.log('we got a response');
});
});
I got the following error:
drachtioDialer/node_modules/drachtio/lib/client/digest-client.js:139
var challenge = digest.substr(digest.indexOf(prefix) + prefix.length);
^
TypeError: Cannot read property 'substr' of undefined
at parseChallenge (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/digest-client.js:139:25)
at /Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/digest-client.js:42:21
at fn (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/digest-client.js:30:50)
at DigestClient.authenticate (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/digest-client.js:37:3)
at handle (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/agent.js:186:14)
at Socket.onData (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/agent.js:345:4)
at emitOne (events.js:90:13)
at Socket.emit (events.js:182:7)
at readableAddChunk (_stream_readable.js:153:18)
at Socket.Readable.push (_stream_readable.js:111:10)
So, in digest-client.js, I replaced:
var challenge = parseChallenge(self.res.get('www-authenticate'));
with
// adding this to get proxy-authenticate challenges as well
if (self.res.get('www-authenticate') === undefined) {
var challenge = parseChallenge(self.res.get('proxy-authenticate'));
} else {
var challenge = parseChallenge(self.res.get('www-authenticate'));
}
Then I got the following error:
drachtioDialer/node_modules/drachtio/lib/client/agent.js:189
req.on('response', l) ;
^
TypeError: Cannot read property 'on' of undefined
at /Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/agent.js:190:12
at Array.forEach (native)
at Object.callback (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/agent.js:189:38)
at agent.pendingRequests.(anonymous function) (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/agent.js:436:11)
at handle (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/agent.js:219:4)
at Socket.onData (/Users/byoungdale/Documents/drachtio/drachtioDialer/node_modules/drachtio/lib/client/agent.js:345:4)
at emitOne (events.js:90:13)
at Socket.emit (events.js:182:7)
at readableAddChunk (_stream_readable.js:153:18)
at Socket.Readable.push (_stream_readable.js:111:10)
When I did a debug on onData
function, I get:
onData: msg: 105#50a4acdd-caf5-4b44-9fb1-29f6f7fc93c8|response|3bd34460-04e6-11e7-9ef2-733c78e8dad2|NOK|Error creating leg
From the drachtio-server:
SIP/2.0 407 Proxy Authentication Required
Via: SIP/2.0/UDP 10.0.1.183;received=192.168.64.22;branch=z9hG4bKrrKXUgDHHXQDj
To: <sip:[email protected]>;tag=sansay232705rdb53
From: <sip:[email protected]>;tag=5j2D1meNKt4Nr
Call-ID: 133ceeb9-7f89-1235-71b3-0800271b9bde
CSeq: 104202563 INVITE
Proxy-Authenticate: Digest realm="example.com", nonce="f6ff5487-dda0-4d25-a793-188e91034f2f", algorithm=MD5, qo
p="auth"
User-Agent: SIP Server
Accept: application/sdp
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Allow-Events: talk, hold, conference, presence, as-feature-event, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer
Content-Length: 0
00014a09|2017-Mar-09 16:34:15.208809| tport.c:3023 tport_deliver() tport_deliver(0xfb6aa0): msg 0xfe3960 (801 bytes) from udp/192.168.1.9:5060 next=(nil)
00014a0a|2017-Mar-09 16:34:15.208833| nta.c:3299 agent_recv_response() nta: received 407 Proxy Authentication Required for INVITE (104202563)
00014a0b|2017-Mar-09 16:34:15.208856| nta.c:3366 agent_recv_response() nta: 407 Proxy Authentication Required is going to a transaction
00014a0c|2017-Mar-09 16:34:15.208876| tport.c:4222 tport_release() tport_release(0xfb6aa0): 0xfc7e90 by 0xfdfcb0 with 0xfe3960
00014a0d|2017-Mar-09 16:34:15.208933| tport.c:3257 tport_tsend() tport_tsend(0xfb6aa0) tpn = UDP/192.168.1.9:5060
00014a0e|2017-Mar-09 16:34:15.208966| tport.c:4046 tport_resolve() tport_resolve addrinfo = 192.168.1.9:5060
00014a0f|2017-Mar-09 16:34:15.208988| tport.c:4680 tport_by_addrinfo() tport_by_addrinfo(0xfb6aa0): not found by name UDP/192.168.1.9:5060
00014a10|2017-Mar-09 16:34:15.209165| tport.c:3492 tport_send_msg() tport_vsend returned 325
00014a11|2017-Mar-09 16:34:15.209236| send 325 bytes to udp/[192.168.1.9]:5060 at 16:34:15.209034:
ACK sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 10.0.1.183;branch=z9hG4bKrrKXUgDHHXQDj
Max-Forwards: 70
From: <sip:[email protected]>;tag=5j2D1meNKt4Nr
To: <sip:[email protected]>;tag=sansay232705rdb53
Call-ID: 133ceeb9-7f89-1235-71b3-0800271b9bde
CSeq: 104202563 ACK
Content-Length: 0
00014a12|2017-Mar-09 16:34:15.209268| nta.c:8304 outgoing_send() nta: sent ACK (104202563) to UDP/192.168.1.9:5060
00014a13|2017-Mar-09 16:34:15.209290| nta.c:8722 outgoing_free() nta: outgoing_free(0xfe3e80)
00014a14|2017-Mar-09 16:34:15.209346| ClientController::removeDialog - dialog not found: 1dc5801e-595a-469a-9858-0a586922de71
00014a15|2017-Mar-09 16:34:15.209375| nta.c:4470 nta_leg_destroy() nta_leg_destroy(0xfd5ab0)
00014a16|2017-Mar-09 16:34:15.216729| nta.c:4423 nta_leg_tcreate() nta_leg_tcreate(): Missing local dialog address
00014a17|2017-Mar-09 16:34:15.216794| SipDialogController::doSendRequestOutsideDialog - Error creating leg
Hi,
I'm facing quite a lot of error invalid message from server, did not start with length#:
.
I'm using drachtio 4.1.6 package and spotted an issue with a regex in the _onData
handler of wire-protocol
_onData(socket, msg) {
this._logger('<===' + CRLF + msg + CRLF) ;
if (!this.mapIncomingMsg.has(socket)) {
this.mapIncomingMsg.set(socket, {
incomingMsg: '',
length: -1
});
}
const obj = this.mapIncomingMsg.get(socket) ;
try {
while ([...msg].length > 0) {
let pos ;
if (0 === obj.incomingMsg.length) {
//waiting for a new message
pos = msg.indexOf('#') ;
if (-1 === pos) {
if (msg.match(/^\\d+$/)) {
//it can happen that a message is broken between the length digits and '#'
obj.incomingMsg = msg ;
obj.incomingMsgLength = -1 ; //unknown
return ;
}
else {
throw new Error('invalid message from server, did not start with length#: ' + msg) ;
}
}
msg = this.parseMessageHeader(msg, pos, obj);
}
The msg.match(/^\\d+$/)
is probably wrong and should be msg.match(/^\d+$/)
Cheers
I've got an interesting race condition, I think.
My scenario is that Asterisk server does an immediate reinvite whenever it receives an inbound call. I'm not sure exactly why it does so - maybe it's SDES encryption related or something, or maybe it's to do an RPID header update.
The problem is with the modify event. The reinvite is more often processed before the createB2BUA promise is returned, meaning that the 'modify' event handler is not yet attached, denying my the opportunity to handle the SDP of this reinvite accordingly.
Some times the promise will have returned first, which seems to be the case when I execute the code on an AWS server. When running it locally on my own machine it's a bit random if the promise is returned before the reinvite or not.
Let me know if you want a log dump, I've already created one ;)
¿It´s posible to make and outbound call and on answer redirect to a registered user? The idea it´s implement a SIP CTI wrapper over drachtio based on nodejs.
HI Dave,
With web clients using JSSIP we have a problem that the web page is closed leaving an active registration behind. The registration contact isn't valid since the associated websocket is now closed. So attempts to call it are a waste of time and get 503 DNS Error.
It would be helpful to get an even in your SRF client so that we could clean up the registration. Or something like that.
Thanks,
Steve
Hi Dave,
I have a scenario where I need to programatically generate a new call. I'll likely wrap this in sinatra or similar.
I've built a quick PoC like this:
function makeGreetingCall(srf, mediaserver) {
// Create a media endpoint
let ep;
mediaserver.createEndpoint()
.then((endpoint) => {
ep = endpoint;
return srf.createUAC('sip:[email protected]', {
localSdp: endpoint.local.sdp,
headers: {
'X-Call-Type': 'Test'
}
});
})
.then((dialog) => {
...
And called it directly from the console. However I get thrown:
(node:26498) UnhandledPromiseRejectionWarning: can not send request to myself
I'm assuming this is something built into drachtio server to ensure we don't get caught in a loop scenario. What would you recommend is the best way to "cold initiate" a call like this?
Thanks!
Hey there!
So, I'm relying on the IP of the drachtio instance that connects to my SRF instances (outbound), and while the documentation doesn't have any information on it, there is the socket-object on the request object which seems to basically just be the node socket associated with the request.
Is there a more correct way to obtain the drachtio servers ip, or is it perfectly fine to use that - my main concern would obviously be that this variable were to disappear in the future. Maybe a getSocket() method to provide a proper interface for obtaining the socket?
Here's what I'm currently doing:
srf.use((req, res, next) => {
var drachtioServerIp = req.socket.remoteAddress;
req.drachtioServerIp = drachtioServerIp;
next();
});
We are now able to connect to our provider from out local network. Works perfect (using the rport parameter in the via-headers).
But RTP does not work.
With a standard SIP Phone everything works (using Symmetric RTP)
Here is a sample Invite from PhonerLite (RTP works)
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 172.22.17.9:5060;branch=z9hG4bK805b23d3bcefe811bfcc44f3ad1623db;rport
From: "PhonerLite" <sip:[email protected]>;tag=2957686305
To: <sip:[email protected]>
Call-ID: [email protected]
CSeq: 6 INVITE
Contact: <sip:[email protected]:5060;gr=800739A8-BCEF-E811-BFC3-44F3AD1623DB>
Proxy-Authorization: Digest username="fo281943tr34752_17", realm="sip.solucon.com", nonce="2826a87e-f14f-11e8-8a1f-ad845d2751ad", uri="sip:[email protected]", response="7edafad7e6ef26329868829e9d3010cf", algorithm=MD5, cnonce="805b23d3bcefe811bfcb44f3ad1623db", qop=auth, nc=00000001
Content-Type: application/sdp
Allow: INVITE, ACK, BYE, CANCEL, INFO, MESSAGE, NOTIFY, OPTIONS, REFER, UPDATE, PRACK
Max-Forwards: 70
User-Agent: SIPPER for PhonerLite
Session-Expires: 1800
Supported: 100rel, replaces, from-change, gruu, timer
P-Preferred-Identity: <sip:[email protected]>
Content-Length: 544
v=0
o=- 966294547 1 IN IP4 172.22.17.9
s=SIPPER for PhonerLite
c=IN IP4 172.22.17.9
t=0 0
m=audio 5062 RTP/AVP 107 8 0 2 3 97 110 111 9 18 11 118 101
a=rtpmap:107 opus/48000/2
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:2 G726-32/8000
a=rtpmap:3 GSM/8000
a=rtpmap:97 iLBC/8000
a=rtpmap:110 speex/8000
a=rtpmap:111 speex/16000
a=rtpmap:9 G722/8000
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=yes
a=rtpmap:11 L16/44100
a=rtpmap:118 L16/16000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ssrc:4071078720
a=sendrecv
and a drachtIO Version with no RTP Working.
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 172.22.17.11;rport;branch=z9hG4bKXjvBrB86Dtt5Q
Max-Forwards: 70
From: <sip:172.22.17.11:5060>;tag=4jSmN2Q8Kt9mF
To: <sip:[email protected]>
Call-ID: 82cbf7f7-6bf2-1237-61bd-3ac0b2717a22
CSeq: 131273192 INVITE
Contact: <sip:172.22.17.11:5060>
Proxy-Authorization: Digest username="fo281943tr34752_04", realm="sip.solucon.com", nonce="ab8dc968-f14f-11e8-8239-835e74e5dce3", uri="sip:[email protected]", response="570830f61c97f1d27581db48ca217f0f", qop="auth", nc=00000001, cnonce="0f6dd5d5"
Content-Type: application/sdp
Content-Length: 549
v=0
o=FreeSWITCH 1543197738 1543197739 IN IP4 172.22.17.11
s=FreeSWITCH
c=IN IP4 172.22.17.11
t=0 0
m=audio 20766 RTP/AVP 0 102 103 8 101 104 106
a=rtpmap:0 PCMU/8000
a=rtpmap:102 opus/48000/2
a=fmtp:102 useinbandfec=0; cbr=1; maxaveragebitrate=30000; maxplaybackrate=48000; ptime=20; minptime=10; maxptime=40
a=rtpmap:103 SPEEX/32000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:104 telephone-event/48000
a=fmtp:104 0-16
a=rtpmap:106 telephone-event/32000
a=fmtp:106 0-16
a=ptime:20
a=sendrecv
Do you have any idea
how to get RDP Working? It seems Phonerlite provides a SSRC ..?
As far as i understood Symmetric RTP the client (drachtio) needs to start RTP
(to punch a hole in the firewall, so the carrier can send RTP to the same src-port)
When implementing b2bua for Invite, an Invite comes from user A containing a Contact header with various params such as sip.instance and other feature tags. However, the b2bua send the Invite out to user B with only the sip uri, with no other params. I tried to add 'Contact' to the proxyRequestHeaders array, but it just puts in a second Contact in the SIP header. The client chokes on this, maybe it should be more flexible. But is there a way to conserve the original Contact header?
Hi, I am new to drachtio, I installed drachtio-server and using drachtio-srf. I couldn't figure out how can I establish a call between 2 agents. I can register agents with softphone. Now I have to send invite message with sdp from one to other and response from other agent. When using softphone, I receive 100 Trying message server, I have to redirect the call but I couldnt find any samples.
Hi,
We are making big steps forward using DrachtIO (great work!), and creating a TypeScript D.TS File for your libary.
During our Test's we have seen some behaviour with our SIP Carrier (which is not a Bug with DrachtIO, but more a general question of SIP):
There is a Provisional Response 181 (Call Is Being Forwarded) defined on the SIP Protocol, but we havent seen this code in any of our calls (forwarded to mailbox, forwarded to other phone, etc.)
Is this Response not used, or does our carrier suppress this information?
If we dial a wrong number, the callflow looks like this
-> INVITE
<- TRYING
<- OK
<- AUDIO RTP Stream (20seconds, - Wrong number)
<- 404 Not Found
Is there a way to get the Information "404 - Number not found" without listening to the AudioStream for 20 Sec. before the final result arrives?
thx for your help and inspiration
Andreas
Hi there,
I'm starting a new UAC using the createUAC function, is there a way to set the call ID, the from and to tags.
also where can I find a list of the parameters that can be passed to that function.
I'm still fairly new to this, i apologize if the answer is on the site, I just wasn't able to find it, any help would be greatly appreciated.
Hi Dave,
This may be a dumb question as I'm not a node/modern JS guy, but how do you stop execution of a call on an error condition within chained promises?
https://gist.github.com/WhiteyDude/8dfe7c612cafa7dbf6f3970d5f8d946e
In the commented spot where I wish to stop execution, I've tried using a next()
I've seen in examples, and I've tried returning a res.send()
. However execution continues and the console.log
is triggered. This works perfectly if I return it from within the main invite handler:
https://gist.github.com/WhiteyDude/98f21cc61e306ae340dcce7e691f67b1
I figure because it's within a promise (which I'm also new to), it doesn't return before execution continues. Is there a function I can call to do this, or a clean way to make this blocking?
Thanks!
Hi Dave, hope you are doing well.
I realized that Srf.parseUri() does not handle names instead of IPs.
const parseUri = Srf.parseUri;
const uriWithIp = 'sip:[email protected]:5060';
parseUri(uriWithIp); // this works fine
const uriWithName = 'sip:user@host:5060';
parseUri(uriWithName); // this FAILS
By looking the code, it appears that it intended to handle it (names instead of IPs), but in practice it does not work. Note that the other (commented out) code works well for names.
Thanks!
I'm trying to write an INVITE
handler that needs to wait on a subsequent UPDATE
before returning 200. The skeleton I have is:
const handler = async (request, response) => {
console.log(`Inside ${request.method} handler for ${request.get("call-id")}`);
let handled_update = false;
console.log('Registering UPDATE handler for INVITE');
request.on('update', (update_request, update_response) => {
console.log('Inside UPDATE callback');
response.send(200);
handled_update = true;
update_response.send(200);
});
console.log('Spinning!');
while (!handled_update) {
response.send(100);
console.log('Waiting for UPDATE');
await sleep(1500);
}
console.log('updated!');
}
srf.invite(handler);
However when I run SIPp at this the UPDATE sent never gets a response. It appears that the .on()
callback never gets called. Is this the proper way to handle this?
Hi Dave,
I can't seem to connect 2 ws/wss endpoints together. I keep getting 503 error. Both my UA were able to register fine. Can send invite fine but the createB2BUA errors out. My feeling is I'm not correctly giving it the correct uri parameter. I can get this to work with a non ws.
I have tried using these for the uri
sip:user@serverip;transport=ws
sip:user@serverip;transport=wss
sip:[email protected];transport=ws
sip:[email protected];transport=wss
sip:<receiver>:<rport>; transport=ws
sip:<receiver>:<rport>; transport=wss
Thanks in advance
Hi,
Case sensitivity is generally benign in SIP, but I would like consistent case in my headers for testing. It seems like all headers that are 'normal' or generated automatically are formatted like 'Contact', 'To', 'Content-Length' with upper case first letters. When I add custom headers, they are always set to lower case. Is there a way to have the header on-the-wire match the case that is provided in the header API? For example:
srf.register(req, res) => {
res.send(200, {
headers: {
expires: 3600,
'SIP-ETag': 'something'
}
});
});
In this case, expires goes out on the wire as 'Expires' but the SIP-ETag is 'sip-etag'.
Thanks,
James
I would like to use drachtio-srf as an inbound sip/rtp server. Is there any sample configuration to drachtio register sip trunk with preferably rtpengine? If not is there any sample configration for fsmrf?
Thanks
I'm trying to send a register using an outbound proxy.
The first register is sent successfully and it is responded with a challenge (401).
The issue is with the second register. Drachtio seems to successfully create the request, but it fails to send it to the outbound proxy, it does not find the transport protocol.
I changed the outbound proxy uri on the configuration to include the transport protocol, but it didn't work.
I increased the log level and noticed the difference on the log. The issue occurs around method SipTransport::findAppropriateTransport.
Only on the first request that the entire outbound-proxy parameter is passed to the mentioned method. In the second one, the transport is not on the uri.
Here are the parts of the logs comparing the first and the second request.
First request (SUCCESS):
SipDialogController::doSendRequestOutsideDialog sending request to route url: sip:21.21.100.190:5060;transport=tcp
SipTransport::findAppropriateTransport: searching for a transport to reach tcp/sip:21.21.100.190:5060;transport=tcp
SipTransport::findAppropriateTransport - after filtering for transport we have 1 candidates
SipTransport::findAppropriateTransport - after filtering for protocol we have 1 candidates
SipTransport::findAppropriateTransport: - returning the best match 0x564836faaa60: tcp/21.21.100.190:50060
Second request (FAIL):
SipDialogController::doSendRequestOutsideDialog sending request to route url: sip:21.21.100.190:5060
SipTransport::findAppropriateTransport: searching for a transport to reach udp/sip:21.21.100.190:5060
SipTransport::findAppropriateTransport - after filtering for transport we have 1 candidates
SipTransport::findAppropriateTransport - after filtering for protocol we have 0 candidates
SipTransport::findAppropriateTransport: - no transports found
I'm attaching the Configuration file and the Log file.
Is there any missing configuration?
Let me know if you need anything else.
Thanks in advance!
Hi there,
I just came across your software and it's really something I would like to use in our testing environment.
I'm just trying something simple and it's not working, I'm new to node.js and I have not done JS in a while, so please I apologize if this is not the right forum to ask this.
I'm just running your example to send an option request out, and I get an error when I run the script. can you just tell me if it's a problem with the example code ..
const Srf = require('drachtio-srf');
const srf = new Srf();
const assert = require('assert');
srf.connect({
host: '172.17.0.2',
port: 9022,
secret: 'cymru'
});
srf
.on('connect', (err, hostport) => {
console.log(connected to a drachtio server listening on: ${hostport}
);
})
.on('error', (err) => {
console.log(Error connecting to drachtio server: ${err}
);
process.exit(1);
});
srf.request('sip:[email protected]', {
method: 'OPTIONS'
}, (err, req) => {
// req is the SIP request that went out over the wire
req.on('response', (res) => {
console.log(received ${res.status} response to our OPTIONS request
);
});
});
output
[root@SIPp1 geo-test]# node app.js
assert.js:339
throw err;
^
AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:
assert(typeSocket(socket))
at sockPort (/root/dev/geo-test/node_modules/drachtio-srf/lib/drachtio-agent.js:25:3)
at DrachtioAgent._getDefaultSocket (/root/dev/geo-test/node_modules/drachtio-srf/lib/drachtio-agent.js:505:56)
at DrachtioAgent._normalizeParams (/root/dev/geo-test/node_modules/drachtio-srf/lib/drachtio-agent.js:254:21)
at DrachtioAgent.request (/root/dev/geo-test/node_modules/drachtio-srf/lib/drachtio-agent.js:328:25)
at Function.proto.(anonymous function) [as request] (/root/dev/geo-test/node_modules/delegates/index.js:40:31)
at __x (/root/dev/geo-test/node_modules/drachtio-srf/lib/srf.js:923:19)
at Srf.request (/root/dev/geo-test/node_modules/drachtio-srf/lib/srf.js:927:7)
at Object.<anonymous> (/root/dev/geo-test/app.js:22:5)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
[root@SIPp1 geo-test]# s
There is an inconsistency as well as a documentation bug here.
Srf#request
resolves to the request sent. The application then listens for responses by attaching a listener to that request for the 'response' event.
Dialog#request
unintentionally works differently. It causes the request to be sent, waits for the response, and resolves with the response object.
Changing this is simple, but could affect applications in the field, so it should be done as part of a major release. Until this issue is updated / closed with a resolution, the behavior should be expected to be as above
Hi,
There was a commit on Sep 30, 2017 to support proxy for outbound requests. Does this work?
Should the srf code be like this?
srf.request(uri, {method: 'NOTIFY', proxy: '192.168.1.21:5060'},...
I am testing this but it doesn't seem to have an effect. I would like to send the request to an alternative location which is a SIP proxy.
Thanks,
James
Can I use [use] term of srf for catching ACK caused by INVITE? In such a 3rd party call control, I have to get SDP in received ACK method caused by reINVITE in dialog. Any suggestions?
Getting error when trying to register a client. I'm using linphone client (http://www.linphone.org/).
It's setup to use outbound connections. Is something wrong with the register request?
Here is the log from the app retrieving the request from server.
wire-protocol.js:258 invalid client message, closing socket: Error: invalid message from server, did not start with length#: POST /?method=REGISTER&domain=sip-local.vitalchat.com&protocol=udp&source_address=192.168.99.1&fromUser=ghafran&toUser=ghafran&uriUser=&contentType=&uri=sip%3asip-local.vitalchat.com HTTP/1.1
User-Agent: Drachtio/v0.7.3-12-gfad3d4c
Host: mcu:3001
Accept: application/json
Content-Type: text/plain; charset=UTF-8
Content-Length: 583
REGISTER sip:sip-local.vitalchat.com SIP/2.0
Via: SIP/2.0/UDP 192.168.99.1:5060;branch=z9hG4bK.SDW4GWWfN;rport=5060
From: <sip:[email protected]>;tag=qLDVDBlgV
To: sip:[email protected]
CSeq: 46 REGISTER
Call-ID: omi-4Q1ZNj
Max-Forwards: 70
Supported: replaces, outbound
Accept: application/sdp
Accept: text/plain
Accept: application/vnd.gsma.rcs-ft-http+xml
Contact: <sip:[email protected];transport=udp>;+sip.instance="<urn:uuid:50362994-9ecb-4718-aff3-20392eb365cc>"
Expires: 600
User-Agent: Linphone Desktop/4.1.1 (belle-sip/1.6.3)
My code below:
const Srf = require('drachtio-srf'),
registrationParser = require('drachtio-mw-registration-parser');
var _srf;
module.exports = class sip {
static start() {
_srf = new Srf();
// Using outbound connection
_srf.listen({
port: global.app.web.sip_port,
secret: global.app.web.sip_secret
});
// Log all incoming requests
_srf.use((req, res, next) => {
console.log(`incoming ${req.method} from ${req.source_address}}`);
});
// Setup registration
_srf.use('register', registrationParser);
_srf.register(sip.onRegister);
// Log connection events
_srf.on('connect', (err, hostport) => {
console.log(`connected to a sip server listening on: ${hostport}`);
});
// Setup invites
_srf.invite(sip.onInvite);
}
static onInvite(req, res) {
res.send(486, 'So sorry, busy right now', {
headers: {
'X-Custom-Header': 'because why not?'
}
});
}
static onRegister(req, res) {
console.log(req.authorization);
console.log(`registration info: ${req.registration}`);
}
};
Hello Dave! I hope you are doing well.
I have a situation that I need to implement with Drachtio. After starting a standard dialog using createUAC(), I need later to send a reINVITE without SDP, then 200OK and ACK will finally carry the offer/answer.
I know that reINVITE would be processed this way and the SDP in the 200OK would be obtained from the res object:
callerDialog.modify(callerSDP, (err, res) => {...}
For my scenario I can send an empty string in the place of callerSDP above and can handle the new calling SDP (i.e. the offer) in the res object, but how can I send later the new caller SDP (i.e. the answer) in the ACK?
I know that for the initial INVITE we can use the noAck: true in the options for createUAC() and later use the obj.ack(localSDP), but this is a different scenario, right?
Can you please advise on this? Thank you so much!
Hi,
I am trying to create some internal testing tools using Drachtio. I am using drachtio-srf to act as a registrar and create a proxy for invite/sessions. I would also like to handle publish methods directly. When I call srf.publish(), Node complains that it doesn't exist. The method support comes from sip-methods so I added PUBLISH to the exported array. However, even now the method doesn't fire. Can you point me to a solution? Does the drachtio-server pass it through? I am using server version 0.5.0-122-g3a17efc.
Thank you!
Hi,
drachtio-srf doesn't answer to sip options from my UAC. I have a very simple app from api doc.
const Srf = require('drachtio-srf');
const srf = new Srf();
srf.connect({
host: '127.0.0.1',
port: 9022,
secret: 'cymru'
});
srf.on('connect', (err, hostport) => {
console.log(`connected to a drachtio server listening on: ${hostport}`);
});
//srf.use((req, res, next) => console.log(`incoming ${req.method} from ${req.source_address}`));
srf.options((req, res) => {
res.send(200, {
headers: {
'Subject': 'All\'s well here'
}
});
});
When OPTIONS message arrives to drachtio, there is never answer and UAC retransmit it.
When I delete srf.options part on app.js, drachtio answer 500 (it's normal, because there is no configuration to answer to options).
When I try with invite answer, It works like a charm. It's not a network issue.
srf.invite((req, res) => {
console.log(`send 486`);
res.send(486, 'So sorry, busy right now', {
headers: {
'X-Custom-Header': 'because why not?'
}
});
});
Versions:
drachtio server: v0.8.2
drachtio-srf: [email protected]
Can you help me please with this issue ?
Thanks in advance
Hi Dave
I'm having an issue getting the basic createB2BUA example working.
Running it as shown in the documentation causes a validation error, which on inspection is because the signature has changed to have the URI in index 2 rather than index 0?
After moving it, I now see log message 'Error creating UAS dialog: SipError: Sip non-success response: 503'.
No INVITE is sent to my UAS, and a 503 Service Unavailable is returned to my UAC.
The version in my package.json shows "drachtio-srf": "^4.4.8"
Thanks for any advice.
Phil
Is it possible to bind the server to a specific interface? Right now the Server chooses the wrong interface for outgoing UDP (in a specific scenario with our internal phones).
Hi,
Can the UAC object do a transfer?
i'm looking for documentation listing the opts for the destroy and request method of the dialog, would you be able to point me in the right direction?
thx
methods
destroy(opts, callback): terminates a dialog, by sending a BYE (in the case of an INVITE dialog), or a NOTIFY with Subscription-State: terminated (in the case of a SUBSCRIBE dialog).
modify(sdp, callback): modifies a SIP INVITE dialog by putting it on or off hold or re-INVITing to a new session description protocol.
request(opts, callback): sends a SIP request within a dialog.
I've tried to implement following connection flow with UAS dialog:
https://tools.ietf.org/html/draft-ietf-mmusic-trickle-ice-sip-15#page-14
After creating UAS dialog, the first response after receiving the INVITE will be 200 ACK. In the example above, the first response should be 183 Session Progress. Would be great if the dialog supports this kind of connection flow. Or is there a better way to implement this (without using UAS dialog)?
Issue is that in some attempts if the A leg sends a CANCEL into drachtio that CANCEL is not forwarded to the B leg.
Redacted log being sent over email...
Hi, I am trying to get npm to update with the latest version of drachtio and drachtio-srf so that it references the sip-methods 0.3.0 version. But even when we update the develop branches here, it doesn't update. Also, the latest develop version here is 4.2.1, but npm has it as 4.2.4. Can you possibly sync-up the versions? I would like to deploy some tests automatically, but can't without publish support. Thanks!
Our Provider uses DNS to spread request over different machines
Take a look at ``nslookup sip.solucon.com"
Name: sip.solucon.com
Addresses: 92.197.181.225
92.197.178.224
92.197.178.226
92.197.181.224
92.197.178.225
92.197.180.225
92.197.180.227
92.197.180.229
92.197.181.229
92.197.181.228
92.197.178.229
92.197.180.224
92.197.181.227
92.197.180.226
92.197.181.226
92.197.178.228
92.197.178.227
92.197.180.228
Every DNS Call gets a new TOP-HIT.
This ends in a Problem:
IF you Start an INVITE Dialog and gets an Authentication Required the new Dialog with prepard Authentication Headers goes to another Server, which does not know anthing about the nounce etc.
IF you fix the Sip Adress from "sip.solucon.com" to 92.197.181.228 everything is fine.
So DNS should only be resolved per CALLID, not per Request or dialog
Hey Dave, I hope all is well!
In https://github.com/davehorton/drachtio-srf/blob/master/lib/dialog.js L360-366 there are a bunch of tests being made which I'm trying to understand.
Drachtio doesn't fire 'modify' on the dialog when I unhold a call, because line 364 resolves to true (see if statement on line 379) - and instead it just does whatever the the default action is... which seems to be just return the currently last known SDP?
Disclaimer: I'm not very well versed in SIP and maybe I'm asking an obvious question. In that case, I'm sorry.
I'm trying to make a simple proxy that forwards all invites to a SIP server using a paid account. However, the proxy should only allow whitelisted numbers. Relevant snippet of my code:
srf.on("connect", () => console.log("Connected!"));
srf.register((req, res) => {
console.log("Incoming registration");
srf.proxyRequest(req, `sip:${remoteHost}`)
});
srf.invite((req, res) => {
console.log(`Calling ${req.calledNumber}`);
if (config.whitelist.includes(req.calledNumber)) {
srf.proxyRequest(req, `sip:${remoteHost}`)
} else {
res.send(486, "Busy");
}
});
The Drachtio server is running on port 5060.
When I run this, my phone (Cisco SPA-301) tries to register through my proxy (i see incoming request in Wireshark), but a response never arrives. Also, nothing gets printed from my node.js code besides "Connected!", so I suppose the request doesn't even arrive to the proxy. What might be the reason for this?
I am trying to figure the best way to find the Call-ID in the srf._dialogs
map when I get an INVITE or REFER with a Replaces header. In an attended transfer scenario, the endpoint sets up a dialog with the transferTarget and then sends a REFER to the transferee with a Replaces
header containing the Call-ID of the dialog with the transferTarget.
In this scenario, drachtio is acting as a B2BUA between all the endpoints (and media is just peer to peer for now), so I actually need to find the dialog of the other side of the call (UAS dialog if received on the UAC side, and vice versa).
I have a gist of a latter diagram and sip trace of a successful attended transfer through drachtio here.
I am wondering if there is a better way to find the dialog associated with the Call-ID in the replaces header than what I am doing below by looping through the map of dialogs:
// referParams has all the parsed elements of a refer header
findReplacesDialog(srf._dialogs, referParams.replacesCallId);
const findReplacesDialog = (dialogMap, replacesCallId) => {
var replacesDialog;
const dialogCallIds = Array.from(dialogMap.keys());
debug('Dialog Keys');
debug(dialogCallIds);
dialogCallIds.every((dialog, i) => {
const currentDialog = dialogMap.get(dialog);
const previousDialog = dialogMap.get(dialogCallIds[i-1]);
const nextDialog = dialogMap.get(dialogCallIds[i+1]);
debug('replacesCallId');
debug(replacesCallId);
debug('currentDialog.sip.callId');
debug(currentDialog.sip.callId);
if (nextDialog) { debug('nextDialog.sip.callId'); debug(nextDialog.sip.callId); }
if (previousDialog) { debug('previousDialog.sip.callId'); debug(previousDialog.sip.callId) }
if (currentDialog.sip.callId == replacesCallId) {
debug(`FOUND A MATCH!!!! ${dialog}`);
// drachtio adds ';uas' when it's the UAS of the dialog
if (dialog == `${replacesCallId};uas`) {
debug('UAS dialog: setting repalcesDialog equal to previousDialog');
replacesDialog = previousDialog;
return false;
} else {
debug('UAC dialog: setting repalcesDialog equal to nextDialog');
replacesDialog = nextDialog;
return false;
}
}
return true;
});
return replacesDialog;
};
Hey there!
I'm trying to track down an issue I'm having when running my SRF instances on Amazon through a Network Load Balancer using Outbound Connections.
I'm by no means certain it's caused by the NLB, but the error I'm getting is: "Provided socket has been destroyed".
It only seems to happen when I'm using the Simring, so I'm looking for some insight into the internal workings of the SRF framework.
The error is caused in drachtio-agent.js on this line:
assert.ok(params.socket.destroyed !== true, 'provided socket has been destroyed');
Here is an excerpt of my code.
const register = await registrar.getNextRegistration(user, 10000); //Wait for up to 10 seconds for a new registration to happen.
if (!register) {
info(`No registration happened within timeout for ${user}`);
res.send(404, () => endSrf()); //===== THIS WORKS! ======
return;
}
const simring = new Simring(req, res, [register.contact], {
proxyResponseHeaders: [],
headers: {
"from": req.headers.from
},
localSdpB: sdp,
localSdpA: getSdpA.bind(null, {
'call-id': req.get('Call-Id'),
"via-branch": via.params.branch,
'from-tag': from.params.tag
}, rtpEngineHost)
});
try {
const {uas, uac} = await simring.start(); //===== THIS IMMEDIATELY FAILS ======
}
catch(err) {
error("Error during simring: " + err, err);
endSrf();
}
Essentially I'm wondering what causes that error. It doesn't appear that the Outbound Connection has been torn down, as the res.send(404, () => endSrf());
works every time. It's only Simring.start() that throws this error.
Hi Dave
Making good progress but hit a problem.
I have a sipp UAC script emulating our application server executing a MSML call flow to collect a PIN and join a conference.
This all works fine.
However, the same call flow fails for calls from the actual application server.
It appears the INFO event handler in our javascript is not being called in this call, and the srf is responding automatically to the INFO.
https://gist.github.com/phildunks/8eba657aec5ff8dea97b3459980e1bdc
This gist contains the full srf log for both calls. I have commented inline to explain the call flow.
Thanks very much for your help.
Phil
Hey Dave! I hope you are fine!
I am trying to add a parameter (epid) to the From header when generating a REGISTER request. Somehow I cannot do it... I get a response "Error creating leg"
srf.request(`sip:${phoneNumber}@localhost;transport=tcp`, {
method: 'REGISTER',
headers: {
'contact': `<sip:${phoneNumber}@localhost>;transport=tcp`,
'from': `<sip:${phoneNumber}@localhost>;tag=${fromTag};epid=${epid}`,
'expires': expires
}
}
Do you know how I can do it? I searched but didn't find any documentation about it. Thanks!
Hi! I have a Drachtio B2BUA, and I'm trying to implement a caller-ID masking service, where the B2BUA alters the caller’s address in the From header to a different name & URI.
I'm currently trying to implement this by using passing in a new From
value to the opts.headers
field in createB2BUA
, but it seems like the B-leg is ignoring the new From header and using the same From header as the A-leg.
Is this functionality possible using Drachtio? Is using opts.headers
the correct approach? Happy to upload the reproducing code if you think it's a problem with my implementation.
Thanks so much!
Hi Dave,
Testing out cbRequest on a createUAC
call doesn't appear to yield any result, just a null value:
srf.createUAC(`sip:${outbound_endpoints[key]}@dummy.host`,
{
localSdp: b_endpoint.local.sdp,
headers: b_outbound_headers
},
{
cbRequest: (req) => console.log(`Received request - ${req}`),
cbProvisional: (res) => console.log(`got provisional response: ${res.status}`)
}
)
With this in place, my console outputs:
0|app | Received request - null
0|app | got provisional response: 187
Some digging into the code (http://davehorton.github.io/drachtio-srf/api/srf.js.html#line250) shows me the function returns null,obj instead of just the obj. Given cbProvisional only returns the obj, I'm unsure if this is a documentation mistake or not.
The following docs mislead this:
https://drachtio.org/docs ("Canceling an INVITE we sent")
http://davehorton.github.io/drachtio-srf/api/Srf.html#~uacProgressCallbacks
Cheers!
I am working on a 'REFER' handler and was going to see about making it middleware, but there is no middleware handling for dialog events. So, the middleware could only be used on out of dialog REFER messages. Would adding something like the srf.use
method to the dialog class be worthwhile? Or, since it's easy, just stick to using the REFER handler in the dialog.on
callback?
I am picturing something like this:
const referHandler = require('refer-handler-middleware');
srf.createB2BUA(req, res, transferor, {localSdpB: req.body})
.then(({uac, uas}) => {
console.log('call connected');
uas.use('refer', referHandler);
})
.catch((error) => {
console.error(`Error: ${error}`);
});
I'm trying to use drachtio-srf to register to a SIP server and be able to handle invites, however I'm having trouble registering, I'm receiving a 401 Unauthorized. I'm sending the following request upon successfully connecting to the drachtio-server
`
srf.on("connect", (err, hostport) => {
if (err) return console.log("error connecting: ${err}");
srf.request({
uri : "sip:<sip host>:5060",
method: "REGISTER",
headers: {
"From": "sip:<sip username>@<sip host>",
"To": "sip:<sip username@<sip host>",
"User-Agent" : "drachtio-srf",
},
auth: {
username: "<sip username>,
password: "<sip password>"
}
}, function(err, req){
if( err ) { throw err ; }
req.on("response", function(res) {
if( res.status < 200 ) {
console.log("Response " + res.status)
return; }
if( 200 !== res.msg.status) {
console.log("Error registering: " + res.msg.status);
}else {
console.log("registered successfully");
}
});
});
})`
I have access to the SIP traces of the server I'm trying to connect to, and I get the following error message: The SIP subscriber failed to register. Error: No authentication message received. I read that by providing the "auth" in drachtio-srf it takes care of answering the challenge, but I don't know if that is happening. I'm using drachtio-srf 4.3.0
Hi Dave!
Great to meet you at Commcon!
I've been mulling over the idea of storing dialogs outside of the specific instance, which could potentially have many benefits - recovery of dialogs after an unexpected exit, sharing of dialogs between multiple load balanced instances, etc.
Reading through how dialogs are stored, it seems to be they sit under the main Srf object as a Map. It seems to me like hooking into the dialog creation and removal (http://davehorton.github.io/drachtio-srf/api/srf.js.html#line967) shouldn't be too hard. However when I dump out a dialog, I can see it's a complex object. It seems to contain srf, agent, req, res etc, all of which have their own functions and child objects.
I'm wondering how necessary these are from a storage perspective? I can envision most values being held in a simple redis hash, things like type, onHold, connected, dialog ID, etc. I'm also not sure how you'd handle events, as they're hooked into the individual dialog and are functions?
Maybe redis isn't the right storage mechanism, as a dialog within drachtio is less of a hash of values and more of a living object?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.