Bez popisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sip.js 38KB

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