ring-client-api 9.25.0-beta.1 → 10.0.0-beta.0

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/lib/api/sip.js DELETED
@@ -1,1314 +0,0 @@
1
- "use strict";
2
- /**
3
- * Modified from https://github.com/kirm/sip.js/blob/master/sip.js
4
- *
5
- * Copyright (c) 2010 Kirill Mikhailov (kirill.mikhailov@gmail.com)
6
- * Permission is hereby granted, free of charge, to any person obtaining a copy
7
- * of this software and associated documentation files (the "Software"), to deal
8
- * in the Software without restriction, including without limitation the rights
9
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- * copies of the Software, and to permit persons to whom the Software is
11
- * furnished to do so, subject to the following conditions:
12
- *
13
- * The above copyright notice and this permission notice shall be included in
14
- * all copies or substantial portions of the Software.
15
- *
16
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- * THE SOFTWARE.
23
- */
24
- /* eslint-disable */
25
- var net = require('net'), dns = require('dns'), assert = require('assert'), tls = require('tls'), os = require('os'), crypto = require('crypto');
26
- const RING_KEEPALIVE_PING = '\r\n\r\n';
27
- function toBase64(s) {
28
- switch (s.length % 3) {
29
- case 1:
30
- s += ' ';
31
- break;
32
- case 2:
33
- s += ' ';
34
- break;
35
- default:
36
- }
37
- return new Buffer.from(s)
38
- .toString('base64')
39
- .replace(/\//g, '_')
40
- .replace(/\+/g, '-');
41
- }
42
- // Actual stack code begins here
43
- function parseResponse(rs, m) {
44
- var r = rs.match(/^SIP\/(\d+\.\d+)\s+(\d+)\s*(.*)\s*$/);
45
- if (r) {
46
- m.version = r[1];
47
- m.status = +r[2];
48
- m.reason = r[3];
49
- return m;
50
- }
51
- }
52
- function parseRequest(rq, m) {
53
- var r = rq.match(/^([\w\-.!%*_+`'~]+)\s([^\s]+)\sSIP\s*\/\s*(\d+\.\d+)/);
54
- if (r) {
55
- m.method = unescape(r[1]);
56
- m.uri = r[2];
57
- m.version = r[3];
58
- return m;
59
- }
60
- }
61
- function applyRegex(regex, data) {
62
- regex.lastIndex = data.i;
63
- var r = regex.exec(data.s);
64
- if (r && r.index === data.i) {
65
- data.i = regex.lastIndex;
66
- return r;
67
- }
68
- }
69
- function parseParams(data, hdr) {
70
- hdr.params = hdr.params || {};
71
- var re = /\s*;\s*([\w\-.!%*_+`'~]+)(?:\s*=\s*([\w\-.!%*_+`'~]+|"[^"\\]*(\\.[^"\\]*)*"))?/g;
72
- for (var r = applyRegex(re, data); r; r = applyRegex(re, data)) {
73
- hdr.params[r[1].toLowerCase()] = r[2] || null;
74
- }
75
- return hdr;
76
- }
77
- function parseMultiHeader(parser, d, h) {
78
- h = h || [];
79
- var re = /\s*,\s*/g;
80
- do {
81
- h.push(parser(d));
82
- } while (d.i < d.s.length && applyRegex(re, d));
83
- return h;
84
- }
85
- function parseGenericHeader(d, h) {
86
- return h ? h + ',' + d.s : d.s;
87
- }
88
- function parseAOR(data) {
89
- var r = applyRegex(/((?:[\w\-.!%*_+`'~]+)(?:\s+[\w\-.!%*_+`'~]+)*|"[^"\\]*(?:\\.[^"\\]*)*")?\s*\<\s*([^>]*)\s*\>|((?:[^\s@"<]@)?[^\s;]+)/g, data);
90
- return parseParams(data, { name: r[1], uri: r[2] || r[3] || '' });
91
- }
92
- exports.parseAOR = parseAOR;
93
- function parseAorWithUri(data) {
94
- var r = parseAOR(data);
95
- r.uri = parseUri(r.uri);
96
- return r;
97
- }
98
- function parseVia(data) {
99
- var r = applyRegex(/SIP\s*\/\s*(\d+\.\d+)\s*\/\s*([\S]+)\s+([^\s;:]+)(?:\s*:\s*(\d+))?/g, data);
100
- return parseParams(data, {
101
- version: r[1],
102
- protocol: r[2],
103
- host: r[3],
104
- port: r[4] && +r[4],
105
- });
106
- }
107
- function parseCSeq(d) {
108
- var r = /(\d+)\s*([\S]+)/.exec(d.s);
109
- return { seq: +r[1], method: unescape(r[2]) };
110
- }
111
- function parseAuthHeader(d) {
112
- var r1 = applyRegex(/([^\s]*)\s+/g, d), a = { scheme: r1[1] }, r2 = applyRegex(/([^\s,"=]*)\s*=\s*([^\s,"]+|"[^"\\]*(?:\\.[^"\\]*)*")\s*/g, d);
113
- a[r2[1]] = r2[2];
114
- while ((r2 = applyRegex(/,\s*([^\s,"=]*)\s*=\s*([^\s,"]+|"[^"\\]*(?:\\.[^"\\]*)*")\s*/g, d))) {
115
- a[r2[1]] = r2[2];
116
- }
117
- return a;
118
- }
119
- function parseAuthenticationInfoHeader(d) {
120
- var a = {}, r = applyRegex(/([^\s,"=]*)\s*=\s*([^\s,"]+|"[^"\\]*(?:\\.[^"\\]*)*")\s*/g, d);
121
- a[r[1]] = r[2];
122
- while ((r = applyRegex(/,\s*([^\s,"=]*)\s*=\s*([^\s,"]+|"[^"\\]*(?:\\.[^"\\]*)*")\s*/g, d))) {
123
- a[r[1]] = r[2];
124
- }
125
- return a;
126
- }
127
- var compactForm = {
128
- i: 'call-id',
129
- m: 'contact',
130
- e: 'contact-encoding',
131
- l: 'content-length',
132
- c: 'content-type',
133
- f: 'from',
134
- s: 'subject',
135
- k: 'supported',
136
- t: 'to',
137
- v: 'via',
138
- }, parsers = {
139
- to: parseAOR,
140
- from: parseAOR,
141
- contact: function (v, h) {
142
- if (v == '*')
143
- return v;
144
- return parseMultiHeader(parseAOR, v, h);
145
- },
146
- route: parseMultiHeader.bind(0, parseAorWithUri),
147
- 'record-route': parseMultiHeader.bind(0, parseAorWithUri),
148
- path: parseMultiHeader.bind(0, parseAorWithUri),
149
- cseq: parseCSeq,
150
- 'content-length': function (v) {
151
- return +v.s;
152
- },
153
- via: parseMultiHeader.bind(0, parseVia),
154
- 'www-authenticate': parseMultiHeader.bind(0, parseAuthHeader),
155
- 'proxy-authenticate': parseMultiHeader.bind(0, parseAuthHeader),
156
- authorization: parseMultiHeader.bind(0, parseAuthHeader),
157
- 'proxy-authorization': parseMultiHeader.bind(0, parseAuthHeader),
158
- 'authentication-info': parseAuthenticationInfoHeader,
159
- 'refer-to': parseAOR,
160
- };
161
- function parse(data) {
162
- data = data.split(/\r\n(?![ \t])/);
163
- if (data[0] === '')
164
- return;
165
- var m = {};
166
- if (!(parseResponse(data[0], m) || parseRequest(data[0], m)))
167
- return;
168
- m.headers = {};
169
- for (var i = 1; i < data.length; ++i) {
170
- var r = data[i].match(/^([\S]*?)\s*:\s*([\s\S]*)$/);
171
- if (!r) {
172
- return;
173
- }
174
- var name = unescape(r[1]).toLowerCase();
175
- name = compactForm[name] || name;
176
- try {
177
- m.headers[name] = (parsers[name] || parseGenericHeader)({ s: r[2], i: 0 }, m.headers[name]);
178
- }
179
- catch (e) { }
180
- }
181
- return m;
182
- }
183
- function parseUri(s) {
184
- if (typeof s === 'object')
185
- return s;
186
- var re = /^(sips?):(?:([^\s>:@]+)(?::([^\s@>]+))?@)?([\w\-\.]+)(?::(\d+))?((?:;[^\s=\?>;]+(?:=[^\s?\;]+)?)*)(?:\?(([^\s&=>]+=[^\s&=>]+)(&[^\s&=>]+=[^\s&=>]+)*))?$/, r = re.exec(s);
187
- if (r) {
188
- return {
189
- schema: r[1],
190
- user: r[2],
191
- password: r[3],
192
- host: r[4],
193
- port: +r[5],
194
- params: (r[6].match(/([^;=]+)(=([^;=]+))?/g) || [])
195
- .map(function (s) {
196
- return s.split('=');
197
- })
198
- .reduce(function (params, x) {
199
- params[x[0]] = x[1] || null;
200
- return params;
201
- }, {}),
202
- headers: ((r[7] || '').match(/[^&=]+=[^&=]+/g) || [])
203
- .map(function (s) {
204
- return s.split('=');
205
- })
206
- .reduce(function (params, x) {
207
- params[x[0]] = x[1];
208
- return params;
209
- }, {}),
210
- };
211
- }
212
- }
213
- exports.parseUri = parseUri;
214
- function stringifyVersion(v) {
215
- return v || '2.0';
216
- }
217
- function stringifyParams(params) {
218
- var s = '';
219
- for (var n in params) {
220
- s += ';' + n + (params[n] ? '=' + params[n] : '');
221
- }
222
- return s;
223
- }
224
- function stringifyUri(uri) {
225
- if (typeof uri === 'string')
226
- return uri;
227
- var s = (uri.schema || 'sip') + ':';
228
- if (uri.user) {
229
- if (uri.password)
230
- s += uri.user + ':' + uri.password + '@';
231
- else
232
- s += uri.user + '@';
233
- }
234
- s += uri.host;
235
- if (uri.port)
236
- s += ':' + uri.port;
237
- if (uri.params)
238
- s += stringifyParams(uri.params);
239
- if (uri.headers) {
240
- var h = Object.keys(uri.headers)
241
- .map(function (x) {
242
- return x + '=' + uri.headers[x];
243
- })
244
- .join('&');
245
- if (h.length)
246
- s += '?' + h;
247
- }
248
- return s;
249
- }
250
- exports.stringifyUri = stringifyUri;
251
- function stringifyAOR(aor) {
252
- return ((aor.name || '') +
253
- ' <' +
254
- stringifyUri(aor.uri) +
255
- '>' +
256
- stringifyParams(aor.params));
257
- }
258
- function stringifyAuthHeader(a) {
259
- var s = [];
260
- for (var n in a) {
261
- if (n !== 'scheme' && a[n] !== undefined) {
262
- s.push(n + '=' + a[n]);
263
- }
264
- }
265
- return a.scheme ? a.scheme + ' ' + s.join(',') : s.join(',');
266
- }
267
- exports.stringifyAuthHeader = stringifyAuthHeader;
268
- var stringifiers = {
269
- via: function (h) {
270
- return h
271
- .map(function (via) {
272
- if (via.host) {
273
- return ('Via: SIP/' +
274
- stringifyVersion(via.version) +
275
- '/' +
276
- via.protocol.toUpperCase() +
277
- ' ' +
278
- via.host +
279
- (via.port ? ':' + via.port : '') +
280
- stringifyParams(via.params) +
281
- '\r\n');
282
- }
283
- return '';
284
- })
285
- .join('');
286
- },
287
- to: function (h) {
288
- return 'To: ' + stringifyAOR(h) + '\r\n';
289
- },
290
- from: function (h) {
291
- return 'From: ' + stringifyAOR(h) + '\r\n';
292
- },
293
- contact: function (h) {
294
- return ('Contact: ' +
295
- (h !== '*' && h.length ? h.map(stringifyAOR).join(', ') : '*') +
296
- '\r\n');
297
- },
298
- route: function (h) {
299
- return h.length ? 'Route: ' + h.map(stringifyAOR).join(', ') + '\r\n' : '';
300
- },
301
- 'record-route': function (h) {
302
- return h.length
303
- ? 'Record-Route: ' + h.map(stringifyAOR).join(', ') + '\r\n'
304
- : '';
305
- },
306
- path: function (h) {
307
- return h.length ? 'Path: ' + h.map(stringifyAOR).join(', ') + '\r\n' : '';
308
- },
309
- cseq: function (cseq) {
310
- return 'CSeq: ' + cseq.seq + ' ' + cseq.method + '\r\n';
311
- },
312
- 'www-authenticate': function (h) {
313
- return h
314
- .map(function (x) {
315
- return 'WWW-Authenticate: ' + stringifyAuthHeader(x) + '\r\n';
316
- })
317
- .join('');
318
- },
319
- 'proxy-authenticate': function (h) {
320
- return h
321
- .map(function (x) {
322
- return 'Proxy-Authenticate: ' + stringifyAuthHeader(x) + '\r\n';
323
- })
324
- .join('');
325
- },
326
- authorization: function (h) {
327
- return h
328
- .map(function (x) {
329
- return 'Authorization: ' + stringifyAuthHeader(x) + '\r\n';
330
- })
331
- .join('');
332
- },
333
- 'proxy-authorization': function (h) {
334
- return h
335
- .map(function (x) {
336
- return 'Proxy-Authorization: ' + stringifyAuthHeader(x) + '\r\n';
337
- })
338
- .join('');
339
- },
340
- 'authentication-info': function (h) {
341
- return 'Authentication-Info: ' + stringifyAuthHeader(h) + '\r\n';
342
- },
343
- 'refer-to': function (h) {
344
- return 'Refer-To: ' + stringifyAOR(h) + '\r\n';
345
- },
346
- };
347
- function prettifyHeaderName(s) {
348
- if (s == 'call-id')
349
- return 'Call-ID';
350
- return s.replace(/\b([a-z])/g, function (a) {
351
- return a.toUpperCase();
352
- });
353
- }
354
- function stringify(m) {
355
- var s;
356
- if (m.status) {
357
- s =
358
- 'SIP/' +
359
- stringifyVersion(m.version) +
360
- ' ' +
361
- m.status +
362
- ' ' +
363
- m.reason +
364
- '\r\n';
365
- }
366
- else {
367
- s =
368
- m.method +
369
- ' ' +
370
- stringifyUri(m.uri) +
371
- ' SIP/' +
372
- stringifyVersion(m.version) +
373
- '\r\n';
374
- }
375
- m.headers['content-length'] = (m.content || '').length;
376
- for (var n in m.headers) {
377
- if (typeof m.headers[n] !== 'undefined') {
378
- if (typeof m.headers[n] === 'string' || !stringifiers[n]) {
379
- s += prettifyHeaderName(n) + ': ' + m.headers[n] + '\r\n';
380
- }
381
- else
382
- s += stringifiers[n](m.headers[n], n);
383
- }
384
- }
385
- s += '\r\n';
386
- if (m.content)
387
- s += m.content;
388
- return s;
389
- }
390
- exports.stringify = stringify;
391
- function makeResponse(rq, status, reason, extension) {
392
- var rs = {
393
- status: status,
394
- reason: reason || '',
395
- version: rq.version,
396
- headers: {
397
- via: rq.headers.via,
398
- to: rq.headers.to,
399
- from: rq.headers.from,
400
- 'call-id': rq.headers['call-id'],
401
- cseq: rq.headers.cseq,
402
- },
403
- };
404
- if (extension) {
405
- if (extension.headers) {
406
- Object.keys(extension.headers).forEach(function (h) {
407
- rs.headers[h] = extension.headers[h];
408
- });
409
- }
410
- rs.content = extension.content;
411
- }
412
- return rs;
413
- }
414
- exports.makeResponse = makeResponse;
415
- function clone(o, deep) {
416
- if (o !== null && typeof o === 'object') {
417
- var r = Array.isArray(o) ? [] : {};
418
- Object.keys(o).forEach(function (k) {
419
- r[k] = deep ? clone(o[k], deep) : o[k];
420
- });
421
- return r;
422
- }
423
- return o;
424
- }
425
- exports.copyMessage = function (msg, deep) {
426
- if (deep)
427
- return clone(msg, true);
428
- var r = {
429
- uri: deep ? clone(msg.uri, deep) : msg.uri,
430
- method: msg.method,
431
- status: msg.status,
432
- reason: msg.reason,
433
- headers: clone(msg.headers, deep),
434
- content: msg.content,
435
- };
436
- // always copy via array
437
- r.headers.via = clone(msg.headers.via);
438
- return r;
439
- };
440
- function defaultPort(proto) {
441
- return proto.toUpperCase() === 'TLS' ? 5061 : 5060;
442
- }
443
- function makeStreamParser(onMessage, onFlood, maxBytesHeaders, maxContentLength) {
444
- onFlood = onFlood || function () { };
445
- maxBytesHeaders = maxBytesHeaders || 60480;
446
- maxContentLength = maxContentLength || 604800;
447
- var m, r = '';
448
- function headers(data) {
449
- r += data;
450
- if (r.length > maxBytesHeaders) {
451
- r = '';
452
- onFlood();
453
- return;
454
- }
455
- var a = r.match(/^\s*([\S\s]*?)\r\n\r\n([\S\s]*)$/);
456
- if (a) {
457
- r = a[2];
458
- m = parse(a[1]);
459
- if (m && m.headers['content-length'] !== undefined) {
460
- if (m.headers['content-length'] > maxContentLength) {
461
- r = '';
462
- onFlood();
463
- }
464
- state = content;
465
- content('');
466
- }
467
- else
468
- headers('');
469
- }
470
- }
471
- function content(data) {
472
- r += data;
473
- if (r.length >= m.headers['content-length']) {
474
- m.content = r.substring(0, m.headers['content-length']);
475
- onMessage(m);
476
- var s = r.substring(m.headers['content-length']);
477
- state = headers;
478
- r = '';
479
- headers(s);
480
- }
481
- }
482
- var state = headers;
483
- return function (data) {
484
- if (data === RING_KEEPALIVE_PING) {
485
- // Received PONG from Ring
486
- return;
487
- }
488
- state(data);
489
- };
490
- }
491
- exports.makeStreamParser = makeStreamParser;
492
- function parseMessage(s) {
493
- var r = s.toString('binary').match(/^\s*([\S\s]*?)\r\n\r\n([\S\s]*)$/);
494
- if (r) {
495
- var m = parse(r[1]);
496
- if (m) {
497
- if (m.headers['content-length']) {
498
- var c = Math.max(0, Math.min(m.headers['content-length'], r[2].length));
499
- m.content = r[2].substring(0, c);
500
- }
501
- else {
502
- m.content = r[2];
503
- }
504
- return m;
505
- }
506
- }
507
- }
508
- exports.parse = parseMessage;
509
- function checkMessage(msg) {
510
- return ((msg.method || (msg.status >= 100 && msg.status <= 999)) &&
511
- msg.headers &&
512
- Array.isArray(msg.headers.via) &&
513
- msg.headers.via.length > 0 &&
514
- msg.headers['call-id'] &&
515
- msg.headers.to &&
516
- msg.headers.from &&
517
- msg.headers.cseq);
518
- }
519
- function makeStreamTransport(protocol, maxBytesHeaders, maxContentLength, connect, createServer, callback) {
520
- var remotes = Object.create(null), flows = Object.create(null);
521
- function init(stream, remote) {
522
- var remoteid = [remote.address, remote.port].join(), flowid = undefined, refs = 0;
523
- const pingInterval = setInterval(() => {
524
- stream.write(RING_KEEPALIVE_PING, 'binary');
525
- }, 5000);
526
- function register_flow() {
527
- flowid = [remoteid, stream.localAddress, stream.localPort].join();
528
- flows[flowid] = remotes[remoteid];
529
- }
530
- var onMessage = function (m) {
531
- if (checkMessage(m)) {
532
- if (m.method)
533
- m.headers.via[0].params.received = remote.address;
534
- callback(m, {
535
- protocol: remote.protocol,
536
- address: stream.remoteAddress,
537
- port: stream.remotePort,
538
- local: { address: stream.localAddress, port: stream.localPort },
539
- }, stream);
540
- }
541
- }, onFlood = function () {
542
- console.log('Flood attempt, destroying stream');
543
- stream.destroy();
544
- };
545
- stream.setEncoding('binary');
546
- stream.on('data', makeStreamParser(onMessage, onFlood, maxBytesHeaders, maxContentLength));
547
- stream.on('close', function () {
548
- clearInterval(pingInterval);
549
- if (flowid)
550
- delete flows[flowid];
551
- delete remotes[remoteid];
552
- });
553
- stream.on('connect', register_flow);
554
- stream.on('error', function () { });
555
- stream.on('end', function () {
556
- if (refs !== 0) {
557
- stream.emit('error', new Error('remote peer disconnected'));
558
- }
559
- stream.end();
560
- });
561
- stream.on('timeout', function () {
562
- if (refs === 0)
563
- stream.destroy();
564
- });
565
- stream.setTimeout(120000);
566
- stream.setMaxListeners(10000);
567
- remotes[remoteid] = function (onError) {
568
- ++refs;
569
- if (onError)
570
- stream.on('error', onError);
571
- return {
572
- release: function () {
573
- if (onError)
574
- stream.removeListener('error', onError);
575
- if (--refs === 0)
576
- stream.emit('no_reference');
577
- },
578
- send: function (m) {
579
- stream.write(stringify(m), 'binary');
580
- },
581
- protocol: protocol,
582
- };
583
- };
584
- if (stream.localPort)
585
- register_flow();
586
- return remotes[remoteid];
587
- }
588
- var server = createServer(function (stream) {
589
- init(stream, {
590
- protocol: protocol,
591
- address: stream.remoteAddress,
592
- port: stream.remotePort,
593
- });
594
- });
595
- return {
596
- open: function (remote, error) {
597
- var remoteid = [remote.address, remote.port].join();
598
- if (remoteid in remotes)
599
- return remotes[remoteid](error);
600
- return init(connect(remote.port, remote.address), remote)(error);
601
- },
602
- get: function (address, error) {
603
- var c = address.local
604
- ? flows[[
605
- address.address,
606
- address.port,
607
- address.local.address,
608
- address.local.port,
609
- ].join()]
610
- : remotes[[address.address, address.port].join()];
611
- return c && c(error);
612
- },
613
- destroy: function () {
614
- server.close();
615
- },
616
- };
617
- }
618
- function makeTlsTransport(options, callback) {
619
- return makeStreamTransport('TLS', options.maxBytesHeaders, options.maxContentLength, function (port, host, callback) {
620
- return tls.connect(port, host, options.tls, callback);
621
- }, function (callback) {
622
- var server = tls.createServer(options.tls, callback);
623
- server.listen();
624
- return server;
625
- }, callback);
626
- }
627
- function makeTransport(options, callback) {
628
- var protocols = {}, callbackAndLog = callback;
629
- if (options.logger && options.logger.recv) {
630
- callbackAndLog = function (m, remote, stream) {
631
- options.logger.recv(m, remote);
632
- callback(m, remote, stream);
633
- };
634
- }
635
- protocols.TLS = makeTlsTransport(options, callbackAndLog);
636
- function wrap(obj, target) {
637
- return Object.create(obj, {
638
- send: {
639
- value: function (m) {
640
- if (m.method) {
641
- m.headers.via[0].host =
642
- options.publicAddress ||
643
- options.address ||
644
- options.hostname ||
645
- os.hostname();
646
- m.headers.via[0].port = options.port || defaultPort(this.protocol);
647
- m.headers.via[0].protocol = this.protocol;
648
- if (this.protocol === 'UDP' &&
649
- (!options.hasOwnProperty('rport') || options.rport)) {
650
- m.headers.via[0].params.rport = null;
651
- }
652
- }
653
- options.logger &&
654
- options.logger.send &&
655
- options.logger.send(m, target);
656
- obj.send(m);
657
- },
658
- },
659
- });
660
- }
661
- return {
662
- open: function (target, error) {
663
- return wrap(protocols[target.protocol.toUpperCase()].open(target, error), target);
664
- },
665
- get: function (target, error) {
666
- var flow = protocols[target.protocol.toUpperCase()].get(target, error);
667
- return flow && wrap(flow, target);
668
- },
669
- send: function (target, message) {
670
- var cn = this.open(target);
671
- try {
672
- cn.send(message);
673
- }
674
- finally {
675
- cn.release();
676
- }
677
- },
678
- destroy: function () {
679
- var protos = protocols;
680
- protocols = [];
681
- Object.keys(protos).forEach(function (key) {
682
- protos[key].destroy();
683
- });
684
- },
685
- };
686
- }
687
- exports.makeTransport = makeTransport;
688
- function makeWellBehavingResolver(resolve) {
689
- var outstanding = Object.create(null);
690
- return function (name, cb) {
691
- if (outstanding[name]) {
692
- outstanding[name].push(cb);
693
- }
694
- else {
695
- outstanding[name] = [cb];
696
- resolve(name, function () {
697
- var o = outstanding[name];
698
- delete outstanding[name];
699
- var args = arguments;
700
- o.forEach(function (x) {
701
- x.apply(null, args);
702
- });
703
- });
704
- }
705
- };
706
- }
707
- var resolveSrv = makeWellBehavingResolver(dns.resolveSrv), resolve4 = makeWellBehavingResolver(dns.resolve4), resolve6 = makeWellBehavingResolver(dns.resolve6);
708
- function resolve(uri, action) {
709
- if (uri.params.transport === 'ws') {
710
- return action([
711
- {
712
- protocol: uri.schema === 'sips' ? 'WSS' : 'WS',
713
- host: uri.host,
714
- port: uri.port || (uri.schema === 'sips' ? 433 : 80),
715
- },
716
- ]);
717
- }
718
- if (net.isIP(uri.host)) {
719
- var protocol = uri.params.transport || 'UDP';
720
- return action([
721
- {
722
- protocol: protocol,
723
- address: uri.host,
724
- port: uri.port || defaultPort(protocol),
725
- },
726
- ]);
727
- }
728
- function resolve46(host, cb) {
729
- resolve4(host, function (e4, a4) {
730
- resolve6(host, function (e6, a6) {
731
- if ((a4 || a6) && (a4 || a6).length) {
732
- cb(null, (a4 || []).concat(a6 || []));
733
- }
734
- else
735
- cb(e4 || e6, []);
736
- });
737
- });
738
- }
739
- if (uri.port) {
740
- var protocols = uri.params.transport
741
- ? [uri.params.transport]
742
- : ['UDP', 'TCP', 'TLS'];
743
- resolve46(uri.host, function (err, address) {
744
- address = (address || [])
745
- .map(function (x) {
746
- return protocols.map(function (p) {
747
- return { protocol: p, address: x, port: uri.port || defaultPort(p) };
748
- });
749
- })
750
- .reduce(function (arr, v) {
751
- return arr.concat(v);
752
- }, []);
753
- action(address);
754
- });
755
- }
756
- else {
757
- var protocols = uri.params.transport
758
- ? [uri.params.transport]
759
- : ['tcp', 'udp', 'tls'], n = protocols.length, addresses = [];
760
- protocols.forEach(function (proto) {
761
- resolveSrv('_sip._' + proto + '.' + uri.host, function (e, r) {
762
- --n;
763
- if (Array.isArray(r)) {
764
- n += r.length;
765
- r.forEach(function (srv) {
766
- resolve46(srv.name, function (e, r) {
767
- addresses = addresses.concat((r || []).map(function (a) {
768
- return { protocol: proto, address: a, port: srv.port };
769
- }));
770
- if (--n === 0) {
771
- // all outstanding requests has completed
772
- action(addresses);
773
- }
774
- });
775
- });
776
- }
777
- else if (0 === n) {
778
- if (addresses.length) {
779
- action(addresses);
780
- }
781
- else {
782
- // all srv requests failed
783
- resolve46(uri.host, function (err, address) {
784
- address = (address || [])
785
- .map(function (x) {
786
- return protocols.map(function (p) {
787
- return {
788
- protocol: p,
789
- address: x,
790
- port: uri.port || defaultPort(p),
791
- };
792
- });
793
- })
794
- .reduce(function (arr, v) {
795
- return arr.concat(v);
796
- }, []);
797
- action(address);
798
- });
799
- }
800
- }
801
- });
802
- });
803
- }
804
- }
805
- exports.resolve = resolve;
806
- //transaction layer
807
- function generateBranch() {
808
- return ['z9hG4bK', Math.round(Math.random() * 1000000)].join('');
809
- }
810
- exports.generateBranch = generateBranch;
811
- function makeSM() {
812
- var state;
813
- return {
814
- enter: function (newstate) {
815
- if (state && state.leave)
816
- state.leave();
817
- state = newstate;
818
- Array.prototype.shift.apply(arguments);
819
- if (state.enter)
820
- state.enter.apply(this, arguments);
821
- },
822
- signal: function (s) {
823
- if (state && state[s]) {
824
- state[Array.prototype.shift.apply(arguments)].apply(state, arguments);
825
- }
826
- },
827
- };
828
- }
829
- function createInviteServerTransaction(transport, cleanup) {
830
- var sm = makeSM(), rs, proceeding = {
831
- message: function () {
832
- if (rs)
833
- transport(rs);
834
- },
835
- send: function (message) {
836
- rs = message;
837
- if (message.status >= 300)
838
- sm.enter(completed);
839
- else if (message.status >= 200)
840
- sm.enter(accepted);
841
- transport(rs);
842
- },
843
- }, g, h, completed = {
844
- enter: function () {
845
- g = setTimeout(function retry(t) {
846
- g = setTimeout(retry, t * 2, t * 2);
847
- transport(rs);
848
- }, 500, 500);
849
- h = setTimeout(sm.enter.bind(sm, terminated), 32000);
850
- },
851
- leave: function () {
852
- clearTimeout(g);
853
- clearTimeout(h);
854
- },
855
- message: function (m) {
856
- if (m.method === 'ACK')
857
- sm.enter(confirmed);
858
- else
859
- transport(rs);
860
- },
861
- }, timer_i, confirmed = {
862
- enter: function () {
863
- timer_i = setTimeout(sm.enter.bind(sm, terminated), 5000);
864
- },
865
- leave: function () {
866
- clearTimeout(timer_i);
867
- },
868
- }, l, accepted = {
869
- enter: function () {
870
- l = setTimeout(sm.enter.bind(sm, terminated), 32000);
871
- },
872
- leave: function () {
873
- clearTimeout(l);
874
- },
875
- send: function (m) {
876
- rs = m;
877
- transport(rs);
878
- },
879
- }, terminated = { enter: cleanup };
880
- sm.enter(proceeding);
881
- return {
882
- send: sm.signal.bind(sm, 'send'),
883
- message: sm.signal.bind(sm, 'message'),
884
- shutdown: function () {
885
- sm.enter(terminated);
886
- },
887
- };
888
- }
889
- function createServerTransaction(transport, cleanup) {
890
- var sm = makeSM(), rs, trying = {
891
- message: function () {
892
- if (rs)
893
- transport(rs);
894
- },
895
- send: function (m) {
896
- rs = m;
897
- transport(m);
898
- if (m.status >= 200)
899
- sm.enter(completed);
900
- },
901
- }, j, completed = {
902
- message: function () {
903
- transport(rs);
904
- },
905
- enter: function () {
906
- j = setTimeout(function () {
907
- sm.enter(terminated);
908
- }, 32000);
909
- },
910
- leave: function () {
911
- clearTimeout(j);
912
- },
913
- }, terminated = { enter: cleanup };
914
- sm.enter(trying);
915
- return {
916
- send: sm.signal.bind(sm, 'send'),
917
- message: sm.signal.bind(sm, 'message'),
918
- shutdown: function () {
919
- sm.enter(terminated);
920
- },
921
- };
922
- }
923
- function createInviteClientTransaction(rq, transport, tu, cleanup, options) {
924
- var sm = makeSM(), a, b, calling = {
925
- enter: function () {
926
- transport(rq);
927
- if (!transport.reliable) {
928
- a = setTimeout(function resend(t) {
929
- transport(rq);
930
- a = setTimeout(resend, t * 2, t * 2);
931
- }, 500, 500);
932
- }
933
- b = setTimeout(function () {
934
- tu(makeResponse(rq, 408));
935
- sm.enter(terminated);
936
- }, 32000);
937
- },
938
- leave: function () {
939
- clearTimeout(a);
940
- clearTimeout(b);
941
- },
942
- message: function (message) {
943
- tu(message);
944
- if (message.status < 200)
945
- sm.enter(proceeding);
946
- else if (message.status < 300)
947
- sm.enter(accepted);
948
- else
949
- sm.enter(completed, message);
950
- },
951
- }, proceeding = {
952
- message: function (message) {
953
- tu(message);
954
- if (message.status >= 300)
955
- sm.enter(completed, message);
956
- else if (message.status >= 200)
957
- sm.enter(accepted);
958
- },
959
- }, ack = {
960
- method: 'ACK',
961
- uri: rq.uri,
962
- headers: {
963
- from: rq.headers.from,
964
- cseq: { method: 'ACK', seq: rq.headers.cseq.seq },
965
- 'call-id': rq.headers['call-id'],
966
- via: [rq.headers.via[0]],
967
- 'max-forwards': (options && options['max-forwards']) || 70,
968
- },
969
- }, d, completed = {
970
- enter: function (rs) {
971
- ack.headers.to = rs.headers.to;
972
- transport(ack);
973
- d = setTimeout(sm.enter.bind(sm, terminated), 32000);
974
- },
975
- leave: function () {
976
- clearTimeout(d);
977
- },
978
- message: function (message, remote) {
979
- if (remote)
980
- transport(ack); // we don't want to ack internally generated messages
981
- },
982
- }, timer_m, accepted = {
983
- enter: function () {
984
- timer_m = setTimeout(function () {
985
- sm.enter(terminated);
986
- }, 32000);
987
- },
988
- leave: function () {
989
- clearTimeout(timer_m);
990
- },
991
- message: function (m) {
992
- if (m.status >= 200 && m.status <= 299)
993
- tu(m);
994
- },
995
- }, terminated = { enter: cleanup };
996
- process.nextTick(function () {
997
- sm.enter(calling);
998
- });
999
- return {
1000
- message: sm.signal.bind(sm, 'message'),
1001
- shutdown: function () {
1002
- sm.enter(terminated);
1003
- },
1004
- };
1005
- }
1006
- function createClientTransaction(rq, transport, tu, cleanup) {
1007
- assert.ok(rq.method !== 'INVITE');
1008
- var sm = makeSM(), e, f, trying = {
1009
- enter: function () {
1010
- transport(rq);
1011
- if (!transport.reliable) {
1012
- e = setTimeout(function () {
1013
- sm.signal('timerE', 500);
1014
- }, 500);
1015
- }
1016
- f = setTimeout(function () {
1017
- sm.signal('timerF');
1018
- }, 32000);
1019
- },
1020
- leave: function () {
1021
- clearTimeout(e);
1022
- clearTimeout(f);
1023
- },
1024
- message: function (message, remote) {
1025
- if (message.status >= 200)
1026
- sm.enter(completed);
1027
- else
1028
- sm.enter(proceeding);
1029
- tu(message);
1030
- },
1031
- timerE: function (t) {
1032
- transport(rq);
1033
- e = setTimeout(function () {
1034
- sm.signal('timerE', t * 2);
1035
- }, t * 2);
1036
- },
1037
- timerF: function () {
1038
- tu(makeResponse(rq, 408));
1039
- sm.enter(terminated);
1040
- },
1041
- }, proceeding = {
1042
- message: function (message, remote) {
1043
- if (message.status >= 200)
1044
- sm.enter(completed);
1045
- tu(message);
1046
- },
1047
- }, k, completed = {
1048
- enter: function () {
1049
- k = setTimeout(function () {
1050
- sm.enter(terminated);
1051
- }, 5000);
1052
- },
1053
- leave: function () {
1054
- clearTimeout(k);
1055
- },
1056
- }, terminated = { enter: cleanup };
1057
- process.nextTick(function () {
1058
- sm.enter(trying);
1059
- });
1060
- return {
1061
- message: sm.signal.bind(sm, 'message'),
1062
- shutdown: function () {
1063
- sm.enter(terminated);
1064
- },
1065
- };
1066
- }
1067
- function makeTransactionId(m) {
1068
- if (m.method === 'ACK') {
1069
- return [
1070
- 'INVITE',
1071
- m.headers['call-id'],
1072
- m.headers.via[0].params.branch,
1073
- ].join();
1074
- }
1075
- return [
1076
- m.headers.cseq.method,
1077
- m.headers['call-id'],
1078
- m.headers.via[0].params.branch,
1079
- ].join();
1080
- }
1081
- function makeTransactionLayer(options, transport) {
1082
- var server_transactions = Object.create(null), client_transactions = Object.create(null);
1083
- return {
1084
- createServerTransaction: function (rq, cn) {
1085
- var id = makeTransactionId(rq);
1086
- return (server_transactions[id] = (rq.method === 'INVITE'
1087
- ? createInviteServerTransaction
1088
- : createServerTransaction)(cn.send.bind(cn), function () {
1089
- delete server_transactions[id];
1090
- cn.release();
1091
- }));
1092
- },
1093
- createClientTransaction: function (connection, rq, callback) {
1094
- if (rq.method !== 'CANCEL') {
1095
- rq.headers.via[0].params.branch = generateBranch();
1096
- }
1097
- if (typeof rq.headers.cseq !== 'object') {
1098
- rq.headers.cseq = parseCSeq({ s: rq.headers.cseq, i: 0 });
1099
- }
1100
- var send = connection.send.bind(connection);
1101
- send.reliable = connection.protocol.toUpperCase() !== 'UDP';
1102
- var id = makeTransactionId(rq);
1103
- return (client_transactions[id] = (rq.method === 'INVITE'
1104
- ? createInviteClientTransaction
1105
- : createClientTransaction)(rq, send, callback, function () {
1106
- delete client_transactions[id];
1107
- connection.release();
1108
- }, options));
1109
- },
1110
- getServer: function (m) {
1111
- return server_transactions[makeTransactionId(m)];
1112
- },
1113
- getClient: function (m) {
1114
- return client_transactions[makeTransactionId(m)];
1115
- },
1116
- destroy: function () {
1117
- Object.keys(client_transactions).forEach(function (x) {
1118
- client_transactions[x].shutdown();
1119
- });
1120
- Object.keys(server_transactions).forEach(function (x) {
1121
- server_transactions[x].shutdown();
1122
- });
1123
- },
1124
- };
1125
- }
1126
- exports.makeTransactionLayer = makeTransactionLayer;
1127
- function sequentialSearch(transaction, connect, addresses, rq, callback) {
1128
- if (rq.method !== 'CANCEL') {
1129
- if (!rq.headers.via)
1130
- rq.headers.via = [];
1131
- rq.headers.via.unshift({ params: {} });
1132
- }
1133
- var onresponse, lastStatusCode;
1134
- function next() {
1135
- onresponse = searching;
1136
- if (addresses.length > 0) {
1137
- try {
1138
- var address = addresses.shift(), client = transaction(connect(address, function (err) {
1139
- if (err) {
1140
- console.log('err: ', err);
1141
- }
1142
- client.message(makeResponse(rq, 503));
1143
- }), rq, function () {
1144
- onresponse.apply(null, arguments);
1145
- });
1146
- }
1147
- catch (e) {
1148
- onresponse(address.local ? makeResponse(rq, 430) : makeResponse(rq, 503));
1149
- }
1150
- }
1151
- else {
1152
- onresponse = callback;
1153
- onresponse(makeResponse(rq, lastStatusCode || 404));
1154
- }
1155
- }
1156
- function searching(rs) {
1157
- lastStatusCode = rs.status;
1158
- if (rs.status === 503)
1159
- return next();
1160
- else if (rs.status > 100)
1161
- onresponse = callback;
1162
- callback(rs);
1163
- }
1164
- next();
1165
- }
1166
- exports.create = function (options, callback) {
1167
- var errorLog = (options.logger && options.logger.error) || function () { }, transport = makeTransport(options, function (m, remote) {
1168
- try {
1169
- var t = m.method ? transaction.getServer(m) : transaction.getClient(m);
1170
- if (!t) {
1171
- if (m.method && m.method !== 'ACK') {
1172
- var t = transaction.createServerTransaction(m, transport.get(remote));
1173
- try {
1174
- callback(m, remote);
1175
- }
1176
- catch (e) {
1177
- t.send(makeResponse(m, '500', 'Internal Server Error'));
1178
- throw e;
1179
- }
1180
- }
1181
- else if (m.method === 'ACK') {
1182
- callback(m, remote);
1183
- }
1184
- }
1185
- else {
1186
- t.message && t.message(m, remote);
1187
- }
1188
- }
1189
- catch (e) {
1190
- errorLog(e);
1191
- }
1192
- }), transaction = makeTransactionLayer(options, transport.open.bind(transport)), hostname = options.publicAddress ||
1193
- options.address ||
1194
- options.hostname ||
1195
- os.hostname(), rbytes = crypto.randomBytes(20);
1196
- function encodeFlowToken(flow) {
1197
- var s = [
1198
- flow.protocol,
1199
- flow.address,
1200
- flow.port,
1201
- flow.local.address,
1202
- flow.local.port,
1203
- ].join(), h = crypto.createHmac('sha1', rbytes);
1204
- h.update(s);
1205
- return toBase64([h.digest('base64'), s].join());
1206
- }
1207
- function decodeFlowToken(token) {
1208
- var s = new Buffer.from(token, 'base64').toString('ascii').split(',');
1209
- if (s.length !== 6)
1210
- return;
1211
- var flow = {
1212
- protocol: s[1],
1213
- address: s[2],
1214
- port: +s[3],
1215
- local: { address: s[4], port: +s[5] },
1216
- };
1217
- return encodeFlowToken(flow) === token ? flow : undefined;
1218
- }
1219
- return {
1220
- send: function (m, callback) {
1221
- if (m.method === undefined) {
1222
- var t = transaction.getServer(m);
1223
- t && t.send && t.send(m);
1224
- }
1225
- else {
1226
- var hop = parseUri(m.uri);
1227
- if (typeof m.headers.route === 'string') {
1228
- try {
1229
- m.headers.route = parsers.route({ s: m.headers.route, i: 0 });
1230
- }
1231
- catch (e) {
1232
- m.headers.route = undefined;
1233
- }
1234
- }
1235
- if (m.headers.route && m.headers.route.length > 0) {
1236
- hop = parseUri(m.headers.route[0].uri);
1237
- if (hop.host === hostname) {
1238
- m.headers.route.shift();
1239
- }
1240
- else if (hop.params.lr === undefined) {
1241
- m.headers.route.shift();
1242
- m.headers.route.push({ uri: m.uri });
1243
- m.uri = hop;
1244
- }
1245
- }
1246
- ;
1247
- (function (callback) {
1248
- if (hop.host === hostname) {
1249
- var flow = decodeFlowToken(hop.user);
1250
- callback(flow ? [flow] : []);
1251
- }
1252
- else
1253
- resolve(hop, callback);
1254
- })(function (addresses) {
1255
- if (m.method === 'ACK') {
1256
- if (!Array.isArray(m.headers.via))
1257
- m.headers.via = [];
1258
- if (m.headers.via.length === 0) {
1259
- m.headers.via.unshift({ params: { branch: generateBranch() } });
1260
- }
1261
- if (addresses.length === 0) {
1262
- errorLog(new Error("ACK: couldn't resolve " + stringifyUri(m.uri)));
1263
- return;
1264
- }
1265
- var cn = transport.open(addresses[0], errorLog);
1266
- try {
1267
- cn.send(m);
1268
- }
1269
- catch (e) {
1270
- errorLog(e);
1271
- }
1272
- finally {
1273
- cn.release();
1274
- }
1275
- }
1276
- else
1277
- sequentialSearch(transaction.createClientTransaction.bind(transaction), transport.open.bind(transport), addresses, m, callback || function () { });
1278
- });
1279
- }
1280
- },
1281
- encodeFlowUri: function (flow) {
1282
- return {
1283
- schema: flow.protocol === 'TLS' ? 'sips' : 'sip',
1284
- user: encodeFlowToken(flow),
1285
- host: hostname,
1286
- params: {},
1287
- };
1288
- },
1289
- decodeFlowUri: function (uri) {
1290
- uri = parseUri(uri);
1291
- return uri.host === hostname ? decodeFlowToken(uri.user) : undefined;
1292
- },
1293
- isFlowUri: function (uri) {
1294
- return !decodeFlowUri(uri);
1295
- },
1296
- hostname: function () {
1297
- return hostname;
1298
- },
1299
- destroy: function () {
1300
- transaction.destroy();
1301
- transport.destroy();
1302
- },
1303
- makeResponse,
1304
- };
1305
- };
1306
- exports.start = function (options, callback) {
1307
- var r = exports.create(options, callback);
1308
- exports.send = r.send;
1309
- exports.stop = r.destroy;
1310
- exports.encodeFlowUri = r.encodeFlowUri;
1311
- exports.decodeFlowUri = r.decodeFlowUri;
1312
- exports.isFlowUri = r.isFlowUri;
1313
- exports.hostname = r.hostname;
1314
- };