drachtio-srf 4.4.64 → 4.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +1 -1
- package/lib/dialog.js +103 -89
- package/lib/srf.js +113 -499
- package/package.json +11 -13
package/.eslintrc.json
CHANGED
package/lib/dialog.js
CHANGED
|
@@ -198,21 +198,24 @@ class Dialog extends Emitter {
|
|
|
198
198
|
|
|
199
199
|
const __x = (callback) => {
|
|
200
200
|
if (this.dialogType === 'INVITE') {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
201
|
+
try {
|
|
202
|
+
this.agent.request({
|
|
203
|
+
method: 'BYE',
|
|
204
|
+
headers: opts.headers || {},
|
|
205
|
+
stackDialogId: this.id,
|
|
206
|
+
auth: opts.auth || this.auth,
|
|
207
|
+
_socket: this.socket
|
|
208
|
+
}, (err, bye) => {
|
|
209
|
+
if (err || !bye) {
|
|
210
|
+
return removeDialog(err, bye, callback);
|
|
211
|
+
}
|
|
212
|
+
bye.on('response', () => {
|
|
213
|
+
removeDialog(err, bye, callback);
|
|
214
|
+
});
|
|
214
215
|
});
|
|
215
|
-
})
|
|
216
|
+
} catch (err) {
|
|
217
|
+
removeDialog(err, null, callback);
|
|
218
|
+
}
|
|
216
219
|
if (this._emitter) {
|
|
217
220
|
Object.assign(this._state, {state: 'terminated'});
|
|
218
221
|
this._emitter.emit('stateChange', this._state);
|
|
@@ -223,14 +226,18 @@ class Dialog extends Emitter {
|
|
|
223
226
|
opts.headers = opts.headers || {} ;
|
|
224
227
|
opts.headers['subscription-state'] = 'terminated';
|
|
225
228
|
opts.headers['event'] = this.subscribeEvent ;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
try {
|
|
230
|
+
this.agent.request({
|
|
231
|
+
method: 'NOTIFY',
|
|
232
|
+
headers: opts.headers || {},
|
|
233
|
+
stackDialogId: this.id,
|
|
234
|
+
_socket: this.socket
|
|
235
|
+
}, (err, notify) => {
|
|
236
|
+
removeDialog(err, notify, callback);
|
|
237
|
+
}) ;
|
|
238
|
+
} catch (err) {
|
|
239
|
+
removeDialog(err, null, callback);
|
|
240
|
+
}
|
|
234
241
|
}
|
|
235
242
|
};
|
|
236
243
|
|
|
@@ -318,43 +325,47 @@ class Dialog extends Emitter {
|
|
|
318
325
|
if (opts.headers && !opts.headers['Contact']) {
|
|
319
326
|
opts.headers['Contact'] = this.local.contact;
|
|
320
327
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
return callback(null, res.body);
|
|
344
|
-
}
|
|
345
|
-
else {
|
|
346
|
-
debug(`opts: ${JSON.stringify(opts)}`);
|
|
347
|
-
debug('SipDialog#modify: go 200 OK to 3pcc INVITE with no sdp; ack is application responsibility');
|
|
348
|
-
return callback(null, res.body, (sdp) => {
|
|
349
|
-
ack({body: sdp});
|
|
328
|
+
try {
|
|
329
|
+
this.agent.request({
|
|
330
|
+
method: 'INVITE',
|
|
331
|
+
stackDialogId: this.id,
|
|
332
|
+
body: this.local.sdp,
|
|
333
|
+
_socket: this.socket,
|
|
334
|
+
headers:
|
|
335
|
+
opts.headers ? opts.headers : {'Contact': this.local.contact}
|
|
336
|
+
}, (err, req) => {
|
|
337
|
+
if (err) {
|
|
338
|
+
this._reinvitesInProgress.count--;
|
|
339
|
+
const admitOne = this._reinvitesInProgress.admitOne.shift();
|
|
340
|
+
if (admitOne) setImmediate(admitOne);
|
|
341
|
+
return callback(err);
|
|
342
|
+
}
|
|
343
|
+
req.on('response', (res, ack) => {
|
|
344
|
+
debug(`Dialog#modifySession: received response to reINVITE with status ${res.status}`) ;
|
|
345
|
+
if (res.status >= 200) {
|
|
346
|
+
if (200 === res.status) {
|
|
347
|
+
this.remote.sdp = res.body ;
|
|
348
|
+
if (this.local.sdp || opts.noAck !== true) {
|
|
349
|
+
ack() ;
|
|
350
350
|
onReInviteComplete(this);
|
|
351
|
-
|
|
351
|
+
return callback(null, res.body);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
debug(`opts: ${JSON.stringify(opts)}`);
|
|
355
|
+
debug('SipDialog#modify: go 200 OK to 3pcc INVITE with no sdp; ack is application responsibility');
|
|
356
|
+
return callback(null, res.body, (sdp) => {
|
|
357
|
+
ack({body: sdp});
|
|
358
|
+
onReInviteComplete(this);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
352
361
|
}
|
|
362
|
+
callback(new SipError(res.status, res.reason)) ;
|
|
353
363
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
364
|
+
}) ;
|
|
365
|
+
});
|
|
366
|
+
} catch (err) {
|
|
367
|
+
callback(err);
|
|
368
|
+
}
|
|
358
369
|
});
|
|
359
370
|
};
|
|
360
371
|
|
|
@@ -398,45 +409,48 @@ class Dialog extends Emitter {
|
|
|
398
409
|
const __x = (callback) => {
|
|
399
410
|
const method = opts.method.toUpperCase() ;
|
|
400
411
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
req.on('response', (res, ack) => {
|
|
414
|
-
if ('BYE' === method) {
|
|
415
|
-
this.srf.removeDialog(this) ;
|
|
412
|
+
try {
|
|
413
|
+
this.agent.request({
|
|
414
|
+
method: method,
|
|
415
|
+
stackDialogId: this.id,
|
|
416
|
+
headers: opts.headers || {},
|
|
417
|
+
auth: opts.auth || this.auth,
|
|
418
|
+
_socket: this.socket,
|
|
419
|
+
body: opts.body
|
|
420
|
+
}, (err, req) => {
|
|
421
|
+
if (err) {
|
|
422
|
+
return callback(err) ;
|
|
416
423
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
424
|
+
|
|
425
|
+
req.on('response', (res, ack) => {
|
|
426
|
+
if ('BYE' === method) {
|
|
427
|
+
this.srf.removeDialog(this) ;
|
|
428
|
+
}
|
|
429
|
+
if ('INVITE' === method && res.status >= 200) {
|
|
430
|
+
if (res.status > 200 || opts.body || opts.noAck !== true) ack() ;
|
|
431
|
+
else {
|
|
432
|
+
return callback(null, res, ack) ;
|
|
433
|
+
}
|
|
422
434
|
}
|
|
423
|
-
}
|
|
424
435
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
436
|
+
if (this.dialogType === 'SUBSCRIBE' && 'NOTIFY' === method &&
|
|
437
|
+
/terminated/.test(req.get('Subscription-State'))) {
|
|
438
|
+
debug('received response to a NOTIFY we sent terminating final subscription; dialog is ended') ;
|
|
428
439
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
440
|
+
const from = req.getParsedHeader('From');
|
|
441
|
+
if (this.removeSubscription(from.uri, req.get('Event')) === 0) {
|
|
442
|
+
this.connected = false ;
|
|
443
|
+
this.srf.removeDialog(this) ;
|
|
444
|
+
this.emit('destroy', req) ;
|
|
445
|
+
this.removeAllListeners();
|
|
446
|
+
}
|
|
435
447
|
}
|
|
436
|
-
|
|
437
|
-
|
|
448
|
+
callback(null, res) ;
|
|
449
|
+
}) ;
|
|
438
450
|
}) ;
|
|
439
|
-
})
|
|
451
|
+
} catch (err) {
|
|
452
|
+
callback(err);
|
|
453
|
+
}
|
|
440
454
|
} ;
|
|
441
455
|
|
|
442
456
|
if (callback) {
|
package/lib/srf.js
CHANGED
|
@@ -6,8 +6,6 @@ const delegate = require('delegates') ;
|
|
|
6
6
|
const parser = require('./sip-parser/parser');
|
|
7
7
|
const methods = require('sip-methods') ;
|
|
8
8
|
const SipError = require('./sip_error') ;
|
|
9
|
-
const async = require('async') ;
|
|
10
|
-
const deprecate = require('deprecate');
|
|
11
9
|
const debug = require('debug')('drachtio:srf') ;
|
|
12
10
|
const Socket = require('net').Socket;
|
|
13
11
|
const noop = () => {};
|
|
@@ -27,6 +25,8 @@ DialogState.Cancelled = 'cancelled';
|
|
|
27
25
|
DialogDirection.Initiator = 'initiator';
|
|
28
26
|
DialogDirection.Recipient = 'recipient';
|
|
29
27
|
|
|
28
|
+
const sleepFor = async(ms) => await new Promise((resolve) => setTimeout(resolve, ms));
|
|
29
|
+
|
|
30
30
|
const noncopyableHdrs = ['via', 'from', 'to', 'call-id', 'cseq', 'contact', 'content-length', 'content-type'];
|
|
31
31
|
function copyAllHeaders(msg, obj) {
|
|
32
32
|
if (msg) Object.keys(msg.headers).forEach((h) => {
|
|
@@ -67,11 +67,6 @@ class Srf extends Emitter {
|
|
|
67
67
|
// then ..
|
|
68
68
|
// srf.connect(), or srf.listen()
|
|
69
69
|
//
|
|
70
|
-
// the old ways:
|
|
71
|
-
// new Srf(connectArgs)
|
|
72
|
-
// or
|
|
73
|
-
// new Srf(app)
|
|
74
|
-
// are deprecated
|
|
75
70
|
|
|
76
71
|
this._dialogs = new Map() ;
|
|
77
72
|
this._tags = [];
|
|
@@ -209,10 +204,10 @@ class Srf extends Emitter {
|
|
|
209
204
|
createUAS(req, res, opts = {}, callback) {
|
|
210
205
|
opts.headers = opts.headers || {} ;
|
|
211
206
|
const body = opts.body || opts.localSdp;
|
|
212
|
-
const generateSdp = typeof body === 'function' ?
|
|
213
|
-
|
|
207
|
+
const generateSdp = typeof body === 'function' ? body : () => opts.localSdp;
|
|
208
|
+
assert(typeof generateSdp === 'function');
|
|
214
209
|
|
|
215
|
-
const __fail = (
|
|
210
|
+
const __fail = (err, callback) => {
|
|
216
211
|
debug(`createUAS failed with ${err}`);
|
|
217
212
|
callback(err);
|
|
218
213
|
};
|
|
@@ -236,7 +231,7 @@ class Srf extends Emitter {
|
|
|
236
231
|
}
|
|
237
232
|
}
|
|
238
233
|
|
|
239
|
-
const __send = (
|
|
234
|
+
const __send = (content, callback) => {
|
|
240
235
|
let called = false;
|
|
241
236
|
debug('createUAS sending');
|
|
242
237
|
|
|
@@ -297,18 +292,17 @@ class Srf extends Emitter {
|
|
|
297
292
|
// should we emit some sort of event?
|
|
298
293
|
}) ;
|
|
299
294
|
}
|
|
300
|
-
else {
|
|
301
|
-
callback(null, dialog) ;
|
|
302
|
-
}
|
|
303
295
|
});
|
|
304
296
|
};
|
|
305
297
|
|
|
306
|
-
const __x = (callback) => {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
298
|
+
const __x = async(callback) => {
|
|
299
|
+
try {
|
|
300
|
+
const sdp = await generateSdp();
|
|
301
|
+
debug({sdp}, `createUAS - generateSdp returned ${sdp}`);
|
|
302
|
+
__send(sdp, callback);
|
|
303
|
+
} catch (err) {
|
|
304
|
+
__fail(err, callback);
|
|
305
|
+
}
|
|
312
306
|
};
|
|
313
307
|
|
|
314
308
|
if (callback) {
|
|
@@ -450,7 +444,7 @@ class Srf extends Emitter {
|
|
|
450
444
|
from = `"${opts.callingName}" <${usingTls ? 'sips' : 'sip'}:${opts.callingNumber}@localhost>`;
|
|
451
445
|
} else {
|
|
452
446
|
from = `${usingTls ? 'sips' : 'sip'}:${opts.callingNumber}@localhost`;
|
|
453
|
-
}
|
|
447
|
+
}
|
|
454
448
|
}
|
|
455
449
|
|
|
456
450
|
if (from) {
|
|
@@ -833,37 +827,42 @@ class Srf extends Emitter {
|
|
|
833
827
|
let remoteSdpB, translatedRemoteSdpB ;
|
|
834
828
|
|
|
835
829
|
/* returns a Promise that resolves with the sdp to use responding to the A leg */
|
|
836
|
-
|
|
830
|
+
const generateSdpA = async(res) => {
|
|
837
831
|
debug('createB2BUA: generateSdpA');
|
|
838
832
|
|
|
839
833
|
const sdpB = res.body ;
|
|
840
834
|
if (res.getParsedHeader('CSeq').method === 'SUBSCRIBE' || !sdpB) {
|
|
841
|
-
return
|
|
835
|
+
return sdpB ;
|
|
842
836
|
}
|
|
843
837
|
|
|
844
838
|
if (remoteSdpB && remoteSdpB === sdpB) {
|
|
845
839
|
// called again with same remote SDP, return previous result
|
|
846
|
-
|
|
840
|
+
if (translatedRemoteSdpB) return translatedRemoteSdpB;
|
|
841
|
+
|
|
842
|
+
/* race condition: we are still producing the translatedSdp from 183 */
|
|
843
|
+
await sleepFor(100);
|
|
844
|
+
if (translatedRemoteSdpB) return translatedRemoteSdpB;
|
|
845
|
+
await sleepFor(500);
|
|
846
|
+
if (translatedRemoteSdpB) return translatedRemoteSdpB;
|
|
847
|
+
await sleepFor(1000);
|
|
848
|
+
return translatedRemoteSdpB;
|
|
847
849
|
}
|
|
848
850
|
|
|
849
851
|
remoteSdpB = sdpB ;
|
|
850
852
|
if (!opts.localSdpA) {
|
|
851
853
|
// passthru B leg SDP
|
|
852
|
-
return
|
|
854
|
+
return translatedRemoteSdpB = sdpB;
|
|
853
855
|
}
|
|
854
856
|
else if ('function' === typeof opts.localSdpA) {
|
|
855
857
|
// call function that returns either the sdp, or a Promise that resolves to the sdp
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
return p
|
|
859
|
-
.then((sdpA) => translatedRemoteSdpB = sdpA)
|
|
860
|
-
.catch((err) => Promise.reject(err));
|
|
858
|
+
const sdpA = await opts.localSdpA(sdpB, res);
|
|
859
|
+
return translatedRemoteSdpB = sdpA;
|
|
861
860
|
}
|
|
862
861
|
else {
|
|
863
862
|
// insert provided SDP
|
|
864
|
-
return
|
|
863
|
+
return translatedRemoteSdpB = opts.localSdpA ;
|
|
865
864
|
}
|
|
866
|
-
}
|
|
865
|
+
};
|
|
867
866
|
|
|
868
867
|
/* uac request sent, set handler to propagate CANCEL from A leg if we get it */
|
|
869
868
|
function handleUACSent(err, uacReq) {
|
|
@@ -883,7 +882,11 @@ class Srf extends Emitter {
|
|
|
883
882
|
|
|
884
883
|
/* get headers from response on uac (B) leg and ready them for inclusion on our response on uas (A) leg */
|
|
885
884
|
function copyUACHeadersToUAS(uacRes) {
|
|
886
|
-
const headers = {}
|
|
885
|
+
const headers = {};
|
|
886
|
+
if (!uacRes) {
|
|
887
|
+
return headers;
|
|
888
|
+
}
|
|
889
|
+
|
|
887
890
|
if (proxyResponseHeaders[0] === 'all') {
|
|
888
891
|
copyAllHeaders(uacRes, headers);
|
|
889
892
|
possiblyRemoveHeaders(proxyResponseHeaders.slice(1), headers);
|
|
@@ -910,22 +913,21 @@ class Srf extends Emitter {
|
|
|
910
913
|
}
|
|
911
914
|
|
|
912
915
|
/* propagate any provisional responses from uac (B) leg to uas (A) leg */
|
|
913
|
-
|
|
916
|
+
const handleUACProvisionalResponse = async(provisionalRes, uacReq) => {
|
|
914
917
|
if (provisionalRes.status > 101) {
|
|
915
918
|
debug(`Srf#createB2BUA: received a provisional response ${provisionalRes.status}`) ;
|
|
916
919
|
if (propagateProvisional) {
|
|
917
920
|
const opts = { headers: copyUACHeadersToUAS(provisionalRes) } ;
|
|
918
921
|
if (provisionalRes.body) {
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
});
|
|
922
|
+
try {
|
|
923
|
+
const sdpA = await generateSdpA(provisionalRes);
|
|
924
|
+
opts.body = sdpA ;
|
|
925
|
+
return res.send(provisionalRes.status, provisionalRes.reason, opts);
|
|
926
|
+
} catch (err) {
|
|
927
|
+
debug(`Srf#createB2BUA: failed in call to produceSdpForALeg: ${err.message}`);
|
|
928
|
+
res.send(500) ;
|
|
929
|
+
uacReq.cancel() ;
|
|
930
|
+
}
|
|
929
931
|
}
|
|
930
932
|
else {
|
|
931
933
|
res.send(provisionalRes.status, provisionalRes.reason, opts) ;
|
|
@@ -936,9 +938,9 @@ class Srf extends Emitter {
|
|
|
936
938
|
}
|
|
937
939
|
}
|
|
938
940
|
cbProvisional(provisionalRes);
|
|
939
|
-
}
|
|
941
|
+
};
|
|
940
942
|
|
|
941
|
-
const __x = (callback) => {
|
|
943
|
+
const __x = async(callback) => {
|
|
942
944
|
debug(`createB2BUA: creating UAC, opts: ${JSON.stringify(opts)}`);
|
|
943
945
|
|
|
944
946
|
opts._socket = req.socket ;
|
|
@@ -960,73 +962,75 @@ class Srf extends Emitter {
|
|
|
960
962
|
}
|
|
961
963
|
}
|
|
962
964
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
965
|
+
/* ok, first create the UAC */
|
|
966
|
+
let uac;
|
|
967
|
+
try {
|
|
968
|
+
uac = await this.createUAC(opts, {cbRequest: handleUACSent, cbProvisional: handleUACProvisionalResponse});
|
|
969
|
+
|
|
970
|
+
} catch (err) {
|
|
971
|
+
debug(`createB2BUA: received non-success ${err.status || err} on uac leg`);
|
|
972
|
+
const opts = {headers: copyUACHeadersToUAS(err.res)} ;
|
|
973
|
+
if (propagateFailure && !res.finalResponseSent) {
|
|
974
|
+
// failed B: propagate failure to A
|
|
975
|
+
res.send(err.status || 500, opts);
|
|
976
|
+
}
|
|
977
|
+
return callback(err);
|
|
978
|
+
}
|
|
976
979
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
980
|
+
let finalResponse, ackFunction;
|
|
981
|
+
if (is3pcc) {
|
|
982
|
+
/* this is a 3pcc invite, will sdp in ACK from A leg */
|
|
983
|
+
const {ack, res} = uac;
|
|
984
|
+
finalResponse = res;
|
|
985
|
+
ackFunction = ack;
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
finalResponse = uac.res;
|
|
989
|
+
/* success establishing uac (B) leg, now establish uas (A) leg */
|
|
990
|
+
debug('createB2BUA: successfully created UAC..queueing requests..');
|
|
981
991
|
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
})
|
|
987
|
-
.then((uas) => {
|
|
988
|
-
if (is3pcc) {
|
|
989
|
-
debug('createB2BUA: successfully created UAS..but this is 3pcc, so a bit more work to do');
|
|
990
|
-
uas.once('ack', (ackRequest) => {
|
|
991
|
-
debug(`createB2BUA: got ACK from UAS, pass on sdp: ${ackRequest.body}`);
|
|
992
|
-
const p = typeof opts.localSdpB === 'function' ?
|
|
993
|
-
opts.localSdpB(ackRequest.body) : Promise.resolve(ackRequest.body);
|
|
994
|
-
p
|
|
995
|
-
.then((sdp) => ackFunction(sdp))
|
|
996
|
-
.then((uac) => {
|
|
997
|
-
uac.other = uas;
|
|
998
|
-
uas.other = uac;
|
|
999
|
-
debug('createB2BUA: successfully created bot dialogs in 3pcc!');
|
|
1000
|
-
callback(null, {uac, uas}); // successfully connected! resolve promise with both dialogs
|
|
1001
|
-
});
|
|
1002
|
-
});
|
|
1003
|
-
return
|
|
1004
|
-
}
|
|
992
|
+
/* need to hold any reINVITEs etc on the B leg until we establish A */
|
|
993
|
+
uac.queueRequests = true;
|
|
994
|
+
cbFinalizedUac(uac);
|
|
995
|
+
}
|
|
1005
996
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
return callback(null, {uac, uas}); // successfully connected! resolve promise with both dialogs
|
|
1014
|
-
})
|
|
1015
|
-
.catch((err) => {
|
|
1016
|
-
debug('createB2BUA: failed creating UAS..done!');
|
|
1017
|
-
uac.destroy() ; // failed A leg after success on B: tear down B
|
|
1018
|
-
callback(err) ;
|
|
1019
|
-
});
|
|
1020
|
-
})
|
|
1021
|
-
.catch((err) => {
|
|
1022
|
-
debug(`createB2BUA: received non-success ${err.status || err} on uac leg`);
|
|
1023
|
-
const opts = {headers: copyUACHeadersToUAS(err.res)} ;
|
|
1024
|
-
if (propagateFailure && !res.finalResponseSent) {
|
|
1025
|
-
// failed B: propagate failure to A
|
|
1026
|
-
res.send(err.status || 500, opts);
|
|
1027
|
-
}
|
|
1028
|
-
callback(err);
|
|
997
|
+
/* now finalize the UAS */
|
|
998
|
+
let uas;
|
|
999
|
+
try {
|
|
1000
|
+
uas = await this.createUAS(req, res, {
|
|
1001
|
+
headers: copyUACHeadersToUAS(finalResponse),
|
|
1002
|
+
localSdp: generateSdpA.bind(null, finalResponse),
|
|
1003
|
+
dialogStateEmitter: opts.dialogStateEmitter
|
|
1029
1004
|
});
|
|
1005
|
+
|
|
1006
|
+
if (is3pcc) {
|
|
1007
|
+
debug('createB2BUA: successfully created UAS..but this is 3pcc, so a bit more work to do');
|
|
1008
|
+
uas.once('ack', async(ackRequest) => {
|
|
1009
|
+
debug(`createB2BUA: got ACK from UAS, pass on sdp: ${ackRequest.body}`);
|
|
1010
|
+
const sdp = await (typeof opts.localSdpB === 'function' ?
|
|
1011
|
+
opts.localSdpB(ackRequest.body) : Promise.resolve(ackRequest.body));
|
|
1012
|
+
uac = await ackFunction(sdp);
|
|
1013
|
+
uac.other = uas;
|
|
1014
|
+
uas.other = uac;
|
|
1015
|
+
debug('createB2BUA: successfully created bot dialogs in 3pcc!');
|
|
1016
|
+
return callback(null, {uac, uas}); // successfully connected! resolve promise with both dialogs
|
|
1017
|
+
});
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
debug('createB2BUA: successfully created UAS..done!');
|
|
1022
|
+
uas.once('ack', () => {
|
|
1023
|
+
debug('createB2BUA: got ACK from UAS, process any queued UAC requests');
|
|
1024
|
+
uac.queueRequests = false;
|
|
1025
|
+
});
|
|
1026
|
+
uac.other = uas;
|
|
1027
|
+
uas.other = uac;
|
|
1028
|
+
return callback(null, {uac, uas}); // successfully connected! resolve promise with both dialogs
|
|
1029
|
+
} catch (err) {
|
|
1030
|
+
debug({err}, 'createB2BUA: failed creating UAS..done!');
|
|
1031
|
+
uac.destroy() ; // failed A leg after success on B: tear down B
|
|
1032
|
+
return callback(err) ;
|
|
1033
|
+
}
|
|
1030
1034
|
};
|
|
1031
1035
|
|
|
1032
1036
|
if (callback) {
|
|
@@ -1185,396 +1189,6 @@ class Srf extends Emitter {
|
|
|
1185
1189
|
return this._dialogs.get(stackDialogId);
|
|
1186
1190
|
}
|
|
1187
1191
|
|
|
1188
|
-
/* deprecated */
|
|
1189
|
-
createUasDialog(req, res, opts, cb) {
|
|
1190
|
-
deprecate('please consider migrating to createUAS, the promises-based version');
|
|
1191
|
-
|
|
1192
|
-
assert.ok(!!req.msg, 'argument \'req\' must be a drachtio Request') ;
|
|
1193
|
-
assert.equal(typeof res.agent, 'object', 'argument \'res\' must be a drachtio Response') ;
|
|
1194
|
-
assert.equal(typeof opts, 'object', 'argument \'opts\' must be provided with connection options') ;
|
|
1195
|
-
if (req.method === 'INVITE') {
|
|
1196
|
-
assert.equal(typeof opts.localSdp, 'string', 'argument \'opts.localSdp\' was not provided') ;
|
|
1197
|
-
}
|
|
1198
|
-
assert.equal(typeof cb, 'function', 'a callback function is required');
|
|
1199
|
-
|
|
1200
|
-
opts.headers = opts.headers || {} ;
|
|
1201
|
-
|
|
1202
|
-
res.send(req.method === 'INVITE' ? 200 : 202, {
|
|
1203
|
-
headers: opts.headers,
|
|
1204
|
-
body: opts.localSdp
|
|
1205
|
-
}, (err, response) => {
|
|
1206
|
-
if (err) { return cb(err) ; }
|
|
1207
|
-
|
|
1208
|
-
const dialog = new Dialog(this, 'uas', {req: req, res: res, sent: response}) ;
|
|
1209
|
-
this.addDialog(dialog);
|
|
1210
|
-
|
|
1211
|
-
if (req.method === 'INVITE') {
|
|
1212
|
-
dialog.once('ack', () => {
|
|
1213
|
-
cb(null, dialog) ;
|
|
1214
|
-
}) ;
|
|
1215
|
-
}
|
|
1216
|
-
else {
|
|
1217
|
-
cb(null, dialog) ;
|
|
1218
|
-
}
|
|
1219
|
-
});
|
|
1220
|
-
|
|
1221
|
-
req.on('cancel', () => {
|
|
1222
|
-
debug('Srf#createUasDialog: received CANCEL from uac') ;
|
|
1223
|
-
cb(new SipError(487, 'Request Terminated')) ;
|
|
1224
|
-
}) ;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
createUacDialog(uri, opts, cb, cbProvisional) {
|
|
1228
|
-
deprecate('please consider migrating to createUAC, the promises-based version');
|
|
1229
|
-
|
|
1230
|
-
return new Promise((resolve, reject) => {
|
|
1231
|
-
const method = opts.method || 'INVITE' ;
|
|
1232
|
-
|
|
1233
|
-
if (typeof uri === 'string') { opts.uri = uri ;}
|
|
1234
|
-
else if (typeof uri === 'object') {
|
|
1235
|
-
cbProvisional = cb ;
|
|
1236
|
-
cb = opts ;
|
|
1237
|
-
opts = uri ;
|
|
1238
|
-
}
|
|
1239
|
-
opts.headers = opts.headers || {} ;
|
|
1240
|
-
|
|
1241
|
-
assert.ok(method === 'INVITE' || method === 'SUBSCRIBE', 'method must be either INVITE or SUBSCRIBE') ;
|
|
1242
|
-
assert.ok(!!opts.uri, 'uri must be specified') ;
|
|
1243
|
-
assert.equal(typeof cb, 'function', 'a callback function is required') ;
|
|
1244
|
-
|
|
1245
|
-
const parsed = parser.parseUri(opts.uri) ;
|
|
1246
|
-
if (!parsed) {
|
|
1247
|
-
if (-1 === opts.uri.indexOf('@') && 0 !== opts.uri.indexOf('sip:')) {
|
|
1248
|
-
const address = opts.uri ;
|
|
1249
|
-
opts.uri = 'sip:' + (opts.calledNumber ? opts.calledNumber + '@' : '') + address ;
|
|
1250
|
-
}
|
|
1251
|
-
else if (0 !== opts.uri.indexOf('sip:')) {
|
|
1252
|
-
opts.uri = 'sip:' + opts.uri ;
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
if (opts.callingNumber) {
|
|
1257
|
-
opts.headers.from = 'sip:' + opts.callingNumber + '@localhost' ;
|
|
1258
|
-
opts.headers.contact = 'sip:' + opts.callingNumber + '@localhost' ;
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
const is3pcc = !opts.localSdp && 'INVITE' === method ;
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
this._app.request({
|
|
1265
|
-
uri: opts.uri,
|
|
1266
|
-
method: method,
|
|
1267
|
-
headers: opts.headers,
|
|
1268
|
-
body: opts.localSdp,
|
|
1269
|
-
auth: opts.auth
|
|
1270
|
-
},
|
|
1271
|
-
(err, req) => {
|
|
1272
|
-
if (err) {
|
|
1273
|
-
reject(err) ;
|
|
1274
|
-
return cb(err) ;
|
|
1275
|
-
}
|
|
1276
|
-
resolve(req) ;
|
|
1277
|
-
req.on('response', (res, ack) => {
|
|
1278
|
-
if (res.status < 200) {
|
|
1279
|
-
if (res.has('RSeq')) {
|
|
1280
|
-
ack() ; // send PRACK
|
|
1281
|
-
}
|
|
1282
|
-
if (cbProvisional) {
|
|
1283
|
-
cbProvisional(res) ;
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
else {
|
|
1287
|
-
if (is3pcc && 200 === res.status && !!res.body) {
|
|
1288
|
-
|
|
1289
|
-
if (opts.noAck === true) {
|
|
1290
|
-
// caller is responsible for sending ACK
|
|
1291
|
-
return cb(null, res.body, function(localSdp, callback) {
|
|
1292
|
-
ack({body: localSdp}) ;
|
|
1293
|
-
|
|
1294
|
-
const dialog = new Dialog(this, 'uac', {req: req, res: res}) ;
|
|
1295
|
-
dialog.local.sdp = localSdp ;
|
|
1296
|
-
this.addDialog(dialog) ;
|
|
1297
|
-
callback(null, dialog) ;
|
|
1298
|
-
}.bind(this));
|
|
1299
|
-
}
|
|
1300
|
-
let bhSdp = res.body.replace(/c=IN\s+IP4\s+(\d+\.\d+\.\d+\.\d+)/, function(/* match, p1 */) {
|
|
1301
|
-
return 'c=IN IP4 0.0.0.0' ;
|
|
1302
|
-
}) ;
|
|
1303
|
-
bhSdp = bhSdp.replace(/(o=[a-zA-Z0-9]+\s+\d+\s+\d+\s+IN\s+IP4\s+)(\d+\.\d+\.\d+\.\d+)/,
|
|
1304
|
-
(match, p1) => { return p1 + '0.0.0.0' ;}
|
|
1305
|
-
) ;
|
|
1306
|
-
ack({
|
|
1307
|
-
body: bhSdp
|
|
1308
|
-
}) ;
|
|
1309
|
-
}
|
|
1310
|
-
else if (method === 'INVITE') {
|
|
1311
|
-
ack() ;
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
if ((200 === res.status && method === 'INVITE') ||
|
|
1315
|
-
((202 === res.status || 200 === res.status) && method === 'SUBSCRIBE')) {
|
|
1316
|
-
|
|
1317
|
-
const dialog = new Dialog(this, 'uac', {req: req, res: res}) ;
|
|
1318
|
-
this.addDialog(dialog) ;
|
|
1319
|
-
return cb(null, dialog) ;
|
|
1320
|
-
}
|
|
1321
|
-
const error = new SipError(res.status, res.reason) ;
|
|
1322
|
-
error.res = res ;
|
|
1323
|
-
cb(error) ;
|
|
1324
|
-
}
|
|
1325
|
-
}) ;
|
|
1326
|
-
}) ;
|
|
1327
|
-
});
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
createBackToBackDialogs(req, res, uri, opts, cb) {
|
|
1331
|
-
deprecate('please consider migrating to createB2BUA, the promises-based version');
|
|
1332
|
-
|
|
1333
|
-
assert.ok(typeof uri === 'string' || Array.isArray(uri), 'argument \'uri\' must be either a string or an array') ;
|
|
1334
|
-
|
|
1335
|
-
if (typeof opts === 'function') {
|
|
1336
|
-
cb = opts ;
|
|
1337
|
-
opts = {} ;
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
assert.ok(!opts.onProvisional ||
|
|
1341
|
-
typeof opts.onProvisional === 'function', 'argument \'opts.onProvisional\' must be a function') ;
|
|
1342
|
-
|
|
1343
|
-
let remoteSdpB, translatedRemoteSdpB ;
|
|
1344
|
-
|
|
1345
|
-
function produceSdpForALeg(sdpB, res, callback) {
|
|
1346
|
-
const method = res.getParsedHeader('CSeq').method ;
|
|
1347
|
-
|
|
1348
|
-
if (method === 'SUBSCRIBE' || !sdpB) {
|
|
1349
|
-
// no-op
|
|
1350
|
-
return callback(null, sdpB) ;
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
if (remoteSdpB && remoteSdpB === sdpB) {
|
|
1354
|
-
// called again with same remote SDP, return previous result
|
|
1355
|
-
return callback(null, translatedRemoteSdpB) ;
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
remoteSdpB = sdpB ;
|
|
1359
|
-
if (!opts.localSdpA) {
|
|
1360
|
-
// no-op: caller does not want to do any substitution
|
|
1361
|
-
callback(null, translatedRemoteSdpB = sdpB) ;
|
|
1362
|
-
}
|
|
1363
|
-
else if ('function' === typeof opts.localSdpA) {
|
|
1364
|
-
// invoke provided callback to generate SDP
|
|
1365
|
-
opts.localSdpA(sdpB, res, (err, sdp) => {
|
|
1366
|
-
callback(err, translatedRemoteSdpB = sdp);
|
|
1367
|
-
}) ;
|
|
1368
|
-
}
|
|
1369
|
-
else {
|
|
1370
|
-
// insert provided SDP
|
|
1371
|
-
callback(null, translatedRemoteSdpB = opts.localSdpA) ;
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
opts.method = req.method ;
|
|
1376
|
-
const onProvisional = opts.onProvisional ;
|
|
1377
|
-
|
|
1378
|
-
const proxyRequestHeaders = opts.proxyRequestHeaders || [] ;
|
|
1379
|
-
const proxyResponseHeaders = opts.proxyResponseHeaders || [] ;
|
|
1380
|
-
|
|
1381
|
-
// default From, To, and user part of uri if not provided
|
|
1382
|
-
opts.headers = opts.headers || {} ;
|
|
1383
|
-
|
|
1384
|
-
// pass specified headers on to the B leg
|
|
1385
|
-
proxyRequestHeaders.forEach((hdr) => {
|
|
1386
|
-
if (req.has(hdr)) {
|
|
1387
|
-
opts.headers[hdr] = req.get(hdr) ;
|
|
1388
|
-
}
|
|
1389
|
-
}) ;
|
|
1390
|
-
/*
|
|
1391
|
-
opts.headers.forEach(opts.headers, (value, hdr) => {
|
|
1392
|
-
opts.headers[hdr] = value ;
|
|
1393
|
-
}) ;
|
|
1394
|
-
*/
|
|
1395
|
-
if (!opts.headers.from && !opts.callingNumber) { opts.callingNumber = req.callingNumber; }
|
|
1396
|
-
if (!opts.headers.to && !opts.calledNumber) { opts.calledNumber = req.calledNumber; }
|
|
1397
|
-
|
|
1398
|
-
opts.localSdp = opts.localSdpB || req.body ;
|
|
1399
|
-
|
|
1400
|
-
uri = 'string' === typeof uri ? [uri] : uri ;
|
|
1401
|
-
|
|
1402
|
-
let finalUacFail ;
|
|
1403
|
-
let finalUacSuccess ;
|
|
1404
|
-
let receivedProvisional = false ;
|
|
1405
|
-
let canceled = false ;
|
|
1406
|
-
let uacBye, reqImmediateNotify, resImmediateNotify ;
|
|
1407
|
-
let uacPromise ;
|
|
1408
|
-
|
|
1409
|
-
// DH: NOTE (possible TODO): callback signature changes in async 2.x for detectXXX
|
|
1410
|
-
async.detectSeries(
|
|
1411
|
-
|
|
1412
|
-
// list of remote URIs to iterate
|
|
1413
|
-
uri,
|
|
1414
|
-
|
|
1415
|
-
// truth test
|
|
1416
|
-
(uri, callback) => {
|
|
1417
|
-
|
|
1418
|
-
if (receivedProvisional || canceled) {
|
|
1419
|
-
// stop cranking back once we receive a provisional > 100 from somebody or the caller canceled
|
|
1420
|
-
return callback(false);
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
// launch the next INVITE or SUBSCRIBE
|
|
1424
|
-
debug('sending %s to %s', opts.method, uri) ;
|
|
1425
|
-
uacPromise = this.createUacDialog(uri, opts,
|
|
1426
|
-
(err, uacDialog) => {
|
|
1427
|
-
if (err) {
|
|
1428
|
-
//non-success: crank back to the next uri if we have one
|
|
1429
|
-
finalUacFail = err ;
|
|
1430
|
-
debug('got failure %d', err.status) ;
|
|
1431
|
-
return callback(false) ;
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
// success - we're done
|
|
1435
|
-
debug('got success! ') ;
|
|
1436
|
-
finalUacSuccess = uacDialog ;
|
|
1437
|
-
|
|
1438
|
-
// for invites, we need to handle a very quick hangup coming before we establish the uas dialog
|
|
1439
|
-
uacDialog.on('destroy', (msg) => {
|
|
1440
|
-
debug('Srf#createBackToBackDialogs: got a BYE on B leg before A leg has ACK\'ed') ;
|
|
1441
|
-
uacBye = msg ;
|
|
1442
|
-
}) ;
|
|
1443
|
-
|
|
1444
|
-
//for subscribes, we need to handle the immediate notify that may come back
|
|
1445
|
-
//from the B leg before we establish the uas dialog
|
|
1446
|
-
if (uacDialog.dialogType === 'SUBSCRIBE') {
|
|
1447
|
-
uacDialog.on('notify', function(reqNotify, resNotify) {
|
|
1448
|
-
debug('Srf#createBackToBackDialogs: received immediate NOTIFY after SUBSCRIBE, ' +
|
|
1449
|
-
'queueing until we complete A leg dialog') ;
|
|
1450
|
-
reqImmediateNotify = reqNotify ;
|
|
1451
|
-
resImmediateNotify = resNotify ;
|
|
1452
|
-
}) ;
|
|
1453
|
-
}
|
|
1454
|
-
callback(true) ;
|
|
1455
|
-
},
|
|
1456
|
-
(provisionalRes) => {
|
|
1457
|
-
if (provisionalRes.status > 100) {
|
|
1458
|
-
debug('Srf#createBackToBackDialogs: received a provisional response %d', provisionalRes.status) ;
|
|
1459
|
-
|
|
1460
|
-
const opts = { headers: {} } ;
|
|
1461
|
-
proxyResponseHeaders.forEach((hdr) => {
|
|
1462
|
-
if (provisionalRes.has(hdr)) { opts.headers[hdr] = provisionalRes.get(hdr) ; }
|
|
1463
|
-
}) ;
|
|
1464
|
-
|
|
1465
|
-
if (provisionalRes.body) {
|
|
1466
|
-
produceSdpForALeg(provisionalRes.body, provisionalRes, (err, sdp) => {
|
|
1467
|
-
if (err) {
|
|
1468
|
-
console.error(`Srf#createBackToBackDialogs: failed in call to produceSdpForALeg; ' +
|
|
1469
|
-
'terminate dialog: ${err.message}`) ;
|
|
1470
|
-
|
|
1471
|
-
//TODO: now we have to hang up B and return a 503 or something to A
|
|
1472
|
-
}
|
|
1473
|
-
opts.body = sdp ;
|
|
1474
|
-
res.send(provisionalRes.status, provisionalRes.reason, opts) ;
|
|
1475
|
-
}) ;
|
|
1476
|
-
}
|
|
1477
|
-
else {
|
|
1478
|
-
res.send(provisionalRes.status, provisionalRes.reason, opts) ;
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
if (onProvisional) {
|
|
1482
|
-
onProvisional(provisionalRes) ;
|
|
1483
|
-
}
|
|
1484
|
-
// we're committed to this uac now
|
|
1485
|
-
receivedProvisional = true ;
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
);
|
|
1489
|
-
uacPromise.then((uacRequest) => {
|
|
1490
|
-
req.on('cancel', () => {
|
|
1491
|
-
debug('Srf#createBackToBackDialogs: received CANCEL as uas; sending CANCEL as uac') ;
|
|
1492
|
-
canceled = true ;
|
|
1493
|
-
finalUacFail = new SipError(487, 'Request Terminated') ;
|
|
1494
|
-
uacRequest.cancel() ;
|
|
1495
|
-
}) ;
|
|
1496
|
-
}) ;
|
|
1497
|
-
},
|
|
1498
|
-
|
|
1499
|
-
// final handler
|
|
1500
|
-
(successUri) => {
|
|
1501
|
-
const opts = { headers: {} } ;
|
|
1502
|
-
if (typeof successUri === 'undefined') {
|
|
1503
|
-
// all failed, send the final failure response back
|
|
1504
|
-
// (TODO: should we be tracking the "best" failure to return?)
|
|
1505
|
-
|
|
1506
|
-
// pass specified headers back to the A leg
|
|
1507
|
-
if (!finalUacFail.res) {
|
|
1508
|
-
res.send(503);
|
|
1509
|
-
}
|
|
1510
|
-
else {
|
|
1511
|
-
proxyResponseHeaders.forEach((hdr) => {
|
|
1512
|
-
if (finalUacFail.res.has(hdr)) { opts.headers[hdr] = finalUacFail.res.get(hdr) ; } }) ;
|
|
1513
|
-
res.send(finalUacFail.status, finalUacFail.reason, opts) ;
|
|
1514
|
-
}
|
|
1515
|
-
return cb(finalUacFail) ;
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
// success
|
|
1519
|
-
proxyResponseHeaders.forEach((hdr) => {
|
|
1520
|
-
if (finalUacSuccess.res.has(hdr)) {
|
|
1521
|
-
opts.headers[hdr] = finalUacSuccess.res.get(hdr) ;
|
|
1522
|
-
}
|
|
1523
|
-
}) ;
|
|
1524
|
-
produceSdpForALeg(finalUacSuccess.remote.sdp, finalUacSuccess.res, (err, sdp) => {
|
|
1525
|
-
opts.localSdp = sdp ;
|
|
1526
|
-
|
|
1527
|
-
// pass specified headers back to the A leg
|
|
1528
|
-
this.createUasDialog(req, res, opts, (err, uasDialog) => {
|
|
1529
|
-
if (err) {
|
|
1530
|
-
return cb(err);
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
finalUacSuccess.removeAllListeners('destroy') ;
|
|
1534
|
-
|
|
1535
|
-
// if B leg has already hung up, emit destroy event after caller has a chance to set up handlers
|
|
1536
|
-
if (uacBye) {
|
|
1537
|
-
setImmediate(() => {
|
|
1538
|
-
finalUacSuccess.emit('destroy', uacBye) ;
|
|
1539
|
-
}) ;
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
// for subscribe dialogs, stitch together the two dialogs
|
|
1543
|
-
// so that we automatically forward NOTIFY and SUBSCRIBE requests down the other leg
|
|
1544
|
-
// note: we don't currently do this for invite dialogs because it is trickier
|
|
1545
|
-
// to know how the app wants to handle re-invites
|
|
1546
|
-
if (uasDialog.dialogType === 'SUBSCRIBE') {
|
|
1547
|
-
|
|
1548
|
-
// remove listener for early / immediate notify and handle any such queued requests
|
|
1549
|
-
finalUacSuccess.removeAllListeners('notify') ;
|
|
1550
|
-
if (reqImmediateNotify) {
|
|
1551
|
-
setImmediate(() => {
|
|
1552
|
-
debug('Srf#createBackToBackDialogs: processing immediate notify') ;
|
|
1553
|
-
this._b2bRequestWithinDialog(uasDialog, reqImmediateNotify, resImmediateNotify,
|
|
1554
|
-
['Event', 'Subscription-State', 'Content-Type'], []) ;
|
|
1555
|
-
});
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
// notify requests come from the B leg
|
|
1559
|
-
finalUacSuccess.on('notify', (req, res) => {
|
|
1560
|
-
this._b2bRequestWithinDialog(uasDialog, req, res, ['Event', 'Subscription-State', 'Content-Type'], []) ;
|
|
1561
|
-
}) ;
|
|
1562
|
-
|
|
1563
|
-
// subscribes (to refresh or terminate) come from the A leg
|
|
1564
|
-
uasDialog.on('subscribe', (req, res) => {
|
|
1565
|
-
this._b2bRequestWithinDialog(finalUacSuccess, req, res, ['Event', 'Expires'],
|
|
1566
|
-
['Expires', 'Subscription-State', 'Allow-Events', 'Allow']) ;
|
|
1567
|
-
}) ;
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
cb(null, uasDialog, finalUacSuccess) ;
|
|
1571
|
-
}) ;
|
|
1572
|
-
}) ;
|
|
1573
|
-
}
|
|
1574
|
-
) ;
|
|
1575
|
-
return uacPromise ;
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
1192
|
addDialog(dialog) {
|
|
1579
1193
|
this._dialogs.set(dialog.id, dialog) ;
|
|
1580
1194
|
debug('Srf#addDialog: adding dialog with id %s type %s, dialog count is now %d ',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drachtio-srf",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.2",
|
|
4
4
|
"description": "drachtio signaling resource framework",
|
|
5
5
|
"main": "lib/srf.js",
|
|
6
6
|
"scripts": {
|
|
@@ -23,27 +23,25 @@
|
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://github.com/drachtio/drachtio-srf#readme",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"async": "^1.4.2",
|
|
27
26
|
"debug": "^3.2.7",
|
|
28
27
|
"delegates": "^0.1.0",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"only": "0.0.2",
|
|
28
|
+
"node-noop": "^0.0.1",
|
|
29
|
+
"only": "^0.0.2",
|
|
32
30
|
"sdp-transform": "^2.14.1",
|
|
33
|
-
"short-uuid": "^4.
|
|
31
|
+
"short-uuid": "^4.2.0",
|
|
34
32
|
"sip-methods": "^0.3.0",
|
|
35
33
|
"sip-status": "^0.1.0",
|
|
36
|
-
"utils-merge": "1.0.0",
|
|
34
|
+
"utils-merge": "^1.0.0",
|
|
37
35
|
"uuid": "^8.3.2"
|
|
38
36
|
},
|
|
39
37
|
"devDependencies": {
|
|
40
|
-
"config": "^3.3.
|
|
41
|
-
"eslint": "^7.
|
|
42
|
-
"eslint-plugin-promise": "^4.
|
|
43
|
-
"mocha": "^9.2.
|
|
38
|
+
"config": "^3.3.7",
|
|
39
|
+
"eslint": "^7.32.0",
|
|
40
|
+
"eslint-plugin-promise": "^4.3.1",
|
|
41
|
+
"mocha": "^9.2.2",
|
|
44
42
|
"nyc": "^15.1.0",
|
|
45
43
|
"should": "^13.2.3",
|
|
46
|
-
"sip-message-examples": "0.0.6",
|
|
47
|
-
"tape": "^5.
|
|
44
|
+
"sip-message-examples": "^0.0.6",
|
|
45
|
+
"tape": "^5.5.3"
|
|
48
46
|
}
|
|
49
47
|
}
|