diff --git a/digest.js b/digest.js index 8e3ddff..d235b0d 100644 --- a/digest.js +++ b/digest.js @@ -1,6 +1,6 @@ var crypto = require('crypto'); var util = require('util'); -var stringifyUri = require('./sip').stringifyUri; +var stringifyUri = require('./sip').stringifyUri; function unq(a) { if(a && a[0] === '"' && a[a.length-1] === '"') @@ -43,16 +43,16 @@ function calculateHA1(ctx) { var userhash = ctx.userhash || calculateUserRealmPasswordHash(ctx.user, ctx.realm, ctx.password); if(ctx.algorithm === 'md5-sess') return kd(userhash, ctx.nonce, ctx.cnonce); - return userhash; + return userhash; } exports.calculateHA1 = calculateHA1; function calculateDigest(ctx) { switch(ctx.qop) { - case 'auth-int': - return kd(ctx.ha1, ctx.nonce, ctx.nc, ctx.cnonce, ctx.qop, kd(ctx.method, ctx.uri, kd(ctx.entity))); - case 'auth': - return kd(ctx.ha1, ctx.nonce, ctx.nc, ctx.cnonce, ctx.qop, kd(ctx.method, ctx.uri)); + case 'auth-int': + return kd(ctx.ha1, ctx.nonce, ctx.nc, ctx.cnonce, ctx.qop, kd(ctx.method, ctx.uri, kd(ctx.entity))); + case 'auth': + return kd(ctx.ha1, ctx.nonce, ctx.nc, ctx.cnonce, ctx.qop, kd(ctx.method, ctx.uri)); } return kd(ctx.ha1, ctx.nonce, kd(ctx.method, ctx.uri)); @@ -95,7 +95,7 @@ function selectQop(challenge, preference) { if(!preference) return challenge[0]; - if(typeof(preference) === 'string') + if(typeof(preference) === 'string') preference = preference.split(','); for(var i = 0; i !== preference.length; ++i) @@ -140,14 +140,14 @@ exports.authenticateRequest = function(ctx, rq, creds) { var qop = unq(lowercase(response.qop)); ctx.nc = (ctx.nc || 0) +1; - + if(!ctx.ha1) { ctx.userhash = creds.hash || calculateUserRealmPasswordHash(creds.user, ctx.realm, creds.password); ctx.ha1 = ctx.userhash; if(ctx.algoritm === 'md5-sess') ctx.ha1 = kd(ctx.userhash, ctx.nonce, cnonce); } - + var digest = calculateDigest({ha1:ctx.ha1, method:rq.method, nonce:ctx.nonce, nc:numberTo8Hex(ctx.nc), cnonce:cnonce, qop:qop, uri:uri, entity:rq.content}); if(digest === unq(response.response)) { ctx.cnonce = cnonce; @@ -155,7 +155,7 @@ exports.authenticateRequest = function(ctx, rq, creds) { ctx.qop = qop; return true; - } + } return false; } @@ -180,13 +180,13 @@ function initClientContext(ctx, rs, creds) { } else challenge = findDigestRealm(rs.headers['www-authenticate'], creds.realm); - + if(ctx.nonce !== unq(challenge.nonce)) { ctx.nonce = unq(challenge.nonce); ctx.algorithm = unq(lowercase(challenge.algorithm)); ctx.qop = selectQop(lowercase(challenge.qop), ctx.qop); - + if(ctx.qop) { ctx.nc = 0; ctx.cnonce = rbytes(); @@ -201,7 +201,7 @@ function initClientContext(ctx, rs, creds) { ctx.ha1 = kd(ctx.ha1, ctx.nonce, ctx.cnonce); ctx.domain = unq(challenge.domain); - } + } ctx.opaque = unq(challenge.opaque); } @@ -214,23 +214,23 @@ exports.signRequest = function (ctx, rq, rs, creds) { var nc = ctx.nc !== undefined ? numberTo8Hex(++ctx.nc) : undefined; ctx.uri = stringifyUri(rq.uri); - + var signature = { scheme: 'Digest', realm: q(ctx.realm), username: q(ctx.user), - nonce: q(ctx.nonce), + nonce: q(ctx.nonce), uri: q(ctx.uri), nc: nc, algorithm: ctx.algorithm, cnonce: q(ctx.cnonce), qop: ctx.qop, opaque: q(ctx.opaque), - response: q(calculateDigest({ha1:ctx.ha1, method:rq.method, nonce:ctx.nonce, nc:nc, cnonce:ctx.cnonce, qop:ctx.qop, uri:ctx.uri, entity:rq.content})) + response: q(calculateDigest({ha1:ctx.ha1, method:rq.method, nonce:ctx.nonce, nc:nc, cnonce:ctx.cnonce, qop:ctx.qop, uri:ctx.uri, entity:rq.content})) }; - var hname = ctx.proxy ? 'proxy-authorization' : 'authorization'; - + var hname = ctx.proxy ? 'proxy-authorization' : 'authorization'; + rq.headers[hname] = (rq.headers[hname] || []).filter(function(x) { return unq(x.realm) !== ctx.realm; }); rq.headers[hname].push(signature); @@ -249,13 +249,13 @@ exports.authenticateResponse = function(ctx, rs) { ctx.nonce = nextnonce; ctx.nc = 0; - if(ctx.algorithm === 'md5-sess') + if(ctx.algorithm === 'md5-sess') ctx.ha1 = kd(ctx.userhash, ctx.nonce, ctx.cnonce); } return true; } - + return false; } diff --git a/proxy.js b/proxy.js index aae068e..3fa692d 100644 --- a/proxy.js +++ b/proxy.js @@ -21,7 +21,7 @@ exports.send = function(msg, callback) { sip.send.apply(sip, arguments); return; } - + return msg.method ? forwardRequest(ctx, msg, callback || defaultCallback) : forwardResponse(ctx, msg); }; @@ -90,7 +90,7 @@ exports.start = function(options, route) { if(ctx) { sip.send(sip.makeResponse(rq, 200)); - + ctx.cancelled = true; if(ctx.cancellers) { Object.keys(ctx.cancellers).forEach(function(c) { ctx.cancellers[c](); }); diff --git a/sdp.js b/sdp.js index 90c17f3..a83c046 100644 --- a/sdp.js +++ b/sdp.js @@ -34,42 +34,42 @@ var parsers = { exports.parse = function(sdp) { var sdp = sdp.split(/\r\n/); - + var root = {}; var m; root.m = []; for(var i = 0; i < sdp.length; ++i) { var tmp = /^(\w)=(.*)/.exec(sdp[i]); - + if(tmp) { - var c = (parsers[tmp[1]] || function(x) { return x;})(tmp[2]); - switch(tmp[1]) { - case 'm': - if(m) root.m.push(m); - m = c; - break; - case 'a': - var o = (m || root); - if(o.a === undefined) o.a = []; - o.a.push(c); - break; - default: - (m || root)[tmp[1]] = c; - break; - } + var c = (parsers[tmp[1]] || function(x) { return x;})(tmp[2]); + switch(tmp[1]) { + case 'm': + if(m) root.m.push(m); + m = c; + break; + case 'a': + var o = (m || root); + if(o.a === undefined) o.a = []; + o.a.push(c); + break; + default: + (m || root)[tmp[1]] = c; + break; + } } } if(m) root.m.push(m); - + return root; }; var stringifiers = { o: function(o) { - return [o.username || '-', o.id, o.version, o.nettype || 'IN', o.addrtype || 'IP4', o.address].join(' '); + return [o.username || '-', o.id, o.version, o.nettype || 'IN', o.addrtype || 'IP4', o.address].join(' '); }, c: function(c) { return [c.nettype || 'IN', c.addrtype || 'IP4', c.address].join(' '); @@ -96,7 +96,7 @@ function stringifyParam(sdp, type, def) { exports.stringify = function(sdp) { var s = ''; - + s += stringifyParam(sdp, 'v', 0); s += stringifyParam(sdp, 'o'); s += stringifyParam(sdp, 's', '-'); diff --git a/sip.js b/sip.js index 0e3bab0..173e0e3 100644 --- a/sip.js +++ b/sip.js @@ -16,15 +16,15 @@ function debug(e) { util.debug(util.inspect(e)); } -function toBase64(s) { +function toBase64(s) { switch(s.length % 3) { - case 1: - s += ' '; - break; - case 2: - s += ' '; - break; - default: + case 1: + s += ' '; + break; + case 2: + s += ' '; + break; + default: } return (new Buffer(s)).toString('base64').replace(/\//g, '_').replace(/\+/g, '-'); @@ -40,7 +40,7 @@ function parseResponse(rs, m) { m.reason = r[3]; return m; - } + } } function parseRequest(rq, m) { @@ -68,8 +68,8 @@ function applyRegex(regex, data) { function parseParams(data, hdr) { hdr.params = hdr.params || {}; - var re = /\s*;\s*([\w\-.!%*_+`'~]+)(?:\s*=\s*([\w\-.!%*_+`'~]+|"[^"\\]*(\\.[^"\\]*)*"))?/g; - + var re = /\s*;\s*([\w\-.!%*_+`'~]+)(?:\s*=\s*([\w\-.!%*_+`'~]+|"[^"\\]*(\\.[^"\\]*)*"))?/g; + for(var r = applyRegex(re, data); r; r = applyRegex(re, data)) { hdr.params[r[1].toLowerCase()] = r[2] || null; } @@ -238,7 +238,7 @@ function stringifyVersion(v) { function stringifyParams(params) { var s = ''; for(var n in params) { - s += ';'+n+(params[n]?'='+params[n]:''); + s += ';'+n+(params[n]?'='+params[n]:''); } return s; @@ -268,7 +268,7 @@ function stringifyUri(uri) { if(uri.headers) { var h = Object.keys(uri.headers).map(function(x){return x+'='+uri.headers[x];}).join('&'); if(h.length) - s += '?' + h; + s += '?' + h; } return s; } @@ -276,7 +276,7 @@ function stringifyUri(uri) { exports.stringifyUri = stringifyUri; function stringifyAOR(aor) { - return (aor.name || '') + ' <' + stringifyUri(aor.uri) + '>'+stringifyParams(aor.params); + return (aor.name || '') + ' <' + stringifyUri(aor.uri) + '>'+stringifyParams(aor.params); } function stringifyAuthHeader(a) { @@ -306,11 +306,11 @@ var stringifiers = { }, to: function(h) { return 'To: '+stringifyAOR(h) + '\r\n'; - }, + }, from: function(h) { return 'From: '+stringifyAOR(h)+'\r\n'; }, - contact: function(h) { + contact: function(h) { return 'Contact: '+ ((h !== '*' && h.length) ? h.map(stringifyAOR).join(', ') : '*') + '\r\n'; }, route: function(h) { @@ -319,23 +319,23 @@ var stringifiers = { 'record-route': function(h) { return h.length ? 'Record-Route: ' + h.map(stringifyAOR).join(', ') + '\r\n' : ''; }, - 'path': function(h) { + 'path': function(h) { return h.length ? 'Path: ' + h.map(stringifyAOR).join(', ') + '\r\n' : ''; }, - cseq: function(cseq) { + cseq: function(cseq) { return 'CSeq: '+cseq.seq+' '+cseq.method+'\r\n'; }, - 'www-authenticate': function(h) { + 'www-authenticate': function(h) { return h.map(function(x) { return 'WWW-Authenticate: '+stringifyAuthHeader(x)+'\r\n'; }).join(''); }, - 'proxy-authenticate': function(h) { + 'proxy-authenticate': function(h) { return h.map(function(x) { return 'Proxy-Authenticate: '+stringifyAuthHeader(x)+'\r\n'; }).join(''); }, 'authorization': function(h) { return h.map(function(x) { return 'Authorization: ' + stringifyAuthHeader(x) + '\r\n'}).join(''); }, 'proxy-authorization': function(h) { - return h.map(function(x) { return 'Proxy-Authorization: ' + stringifyAuthHeader(x) + '\r\n'}).join('');; + return h.map(function(x) { return 'Proxy-Authorization: ' + stringifyAuthHeader(x) + '\r\n'}).join('');; }, 'authentication-info': function(h) { return 'Authentication-Info: ' + stringifyAuthHeader(h) + '\r\n'; @@ -362,13 +362,13 @@ function stringify(m) { for(var n in m.headers) { if(typeof m.headers[n] !== "undefined") { - if(typeof m.headers[n] === 'string' || !stringifiers[n]) + if(typeof m.headers[n] === 'string' || !stringifiers[n]) s += prettifyHeaderName(n) + ': ' + m.headers[n] + '\r\n'; else s += stringifiers[n](m.headers[n], n); } } - + s += '\r\n'; if(m.content) @@ -425,7 +425,7 @@ exports.copyMessage = function(msg, deep) { content: msg.content }; - // always copy via array + // always copy via array r.headers.via = clone(msg.headers.via); return r; @@ -443,7 +443,7 @@ function makeStreamParser(onMessage, onFlood, maxBytesHeaders, maxContentLength) var m; var r = ''; - + function headers(data) { r += data; @@ -486,9 +486,9 @@ function makeStreamParser(onMessage, onFlood, maxBytesHeaders, maxContentLength) if(r.length >= m.headers['content-length']) { m.content = r.substring(0, m.headers['content-length']); - + onMessage(m); - + var s = r.substring(m.headers['content-length']); state = headers; r = ''; @@ -516,7 +516,7 @@ function parseMessage(s) { else { m.content = r[2]; } - + return m; } } @@ -569,23 +569,23 @@ function makeStreamTransport(protocol, maxBytesHeaders, maxContentLength, connec stream.setEncoding('binary'); stream.on('data', makeStreamParser( onMessage, onFlood, maxBytesHeaders, maxContentLength)); - + stream.on('close', function() { - if(flowid) delete flows[flowid]; + if(flowid) delete flows[flowid]; delete remotes[remoteid]; }); stream.on('connect', register_flow); stream.on('error', function() {}); - stream.on('end', function() { + stream.on('end', function() { if(refs !== 0) stream.emit('error', new Error('remote peer disconnected')); stream.end(); }); stream.on('timeout', function() { if(refs === 0) stream.destroy(); }); - stream.setTimeout(120000); + stream.setTimeout(120000); stream.setMaxListeners(10000); - + remotes[remoteid] = function(onError) { ++refs; if(onError) stream.on('error', onError); @@ -608,7 +608,7 @@ function makeStreamTransport(protocol, maxBytesHeaders, maxContentLength, connec } var server = createServer(function(stream) { - init(stream, {protocol: protocol, address: stream.remoteAddress, port: stream.remotePort}); + init(stream, {protocol: protocol, address: stream.remoteAddress, port: stream.remotePort}); }); return { @@ -631,10 +631,10 @@ function makeStreamTransport(protocol, maxBytesHeaders, maxContentLength, connec function makeTlsTransport(options, callback) { return makeStreamTransport( - 'TLS', + 'TLS', options.maxBytesHeaders, options.maxContentLength, - function(port, host, callback) { return tls.connect(port, host, options.tls, callback); }, + function(port, host, callback) { return tls.connect(port, host, options.tls, callback); }, function(callback) { var server = tls.createServer(options.tls, callback); server.listen(options.tls_port || 5061, options.address); @@ -649,7 +649,7 @@ function makeTcpTransport(options, callback) { options.maxBytesHeaders, options.maxContentLength, function(port, host, callback) { return net.connect(port, host, callback); }, - function(callback) { + function(callback) { var server = net.createServer(callback); server.listen(options.port || 5060, options.address); return server; @@ -661,11 +661,11 @@ function makeWsTransport(options, callback) { var flows = Object.create(null); var clients = Object.create(null); - + function init(ws) { var remote = {address: ws._socket.remoteAddress, port: ws._socket.remotePort}, - local = {address: ws._socket.address().address, port: ws._socket.address().port}, - flowid = [remote.address, remote.port, local.address, local.port].join(); + local = {address: ws._socket.address().address, port: ws._socket.address().port}, + flowid = [remote.address, remote.port, local.address, local.port].join(); flows[flowid] = ws; @@ -682,15 +682,15 @@ function makeWsTransport(options, callback) { if(clients[uri]) return clients[uri](); var socket = new WebSocket(uri, 'sip', {procotol: 'sip'}), - queue = [], - refs = 0; - + queue = [], + refs = 0; + function send_connecting(m) { queue.push(stringify(m)); } function send_open(m) { socket.send(new Buffer(typeof m === 'string' ? m : stringify(m), 'binary')); } var send = send_connecting; - socket.on('open', function() { - init(socket); + socket.on('open', function() { + init(socket); send = send_open; queue.splice(0).forEach(send); }); @@ -715,12 +715,12 @@ function makeWsTransport(options, callback) { if(options.tls) { var http = require('https'); var server = new WebSocket.Server({ - server: http.createServer(options.tls, function(rq,rs) { - rs.writeHead(200); - rs.end(""); - }).listen(options.ws_port) + server: http.createServer(options.tls, function(rq,rs) { + rs.writeHead(200); + rs.end(""); + }).listen(options.ws_port) }); - } + } else { var server = new WebSocket.Server({port:options.ws_port}); } @@ -737,16 +737,16 @@ function makeWsTransport(options, callback) { protocol: 'WS' }; } else { - console.log("Failed to get ws for target. Target/flow was:"); - console.log(util.inspect(flow)); - console.log("Flows[] were:"); - console.log(util.inspect(flows)); + console.log("Failed to get ws for target. Target/flow was:"); + console.log(util.inspect(flow)); + console.log("Flows[] were:"); + console.log(util.inspect(flows)); } } function open(target, onError) { if(target.local) - return get(target); + return get(target); else return makeClient('ws://'+target.host+':'+target.port)(onError); } @@ -761,7 +761,7 @@ function makeWsTransport(options, callback) { function makeUdpTransport(options, callback) { function onMessage(data, rinfo) { var msg = parseMessage(data); - + if(msg && checkMessage(msg)) { if(msg.method) { msg.headers.via[0].params.received = rinfo.address; @@ -776,20 +776,20 @@ function makeUdpTransport(options, callback) { var address = options.address || '0.0.0.0'; var port = options.port || 5060; - var socket = dgram.createSocket(net.isIPv6(address) ? 'udp6' : 'udp4', onMessage); + var socket = dgram.createSocket(net.isIPv6(address) ? 'udp6' : 'udp4', onMessage); socket.bind(port, address); function open(remote, error) { return { send: function(m) { var s = stringify(m); - socket.send(new Buffer(s, 'binary'), 0, s.length, remote.port, remote.address); + socket.send(new Buffer(s, 'binary'), 0, s.length, remote.port, remote.address); }, protocol: 'UDP', release : function() {} - }; + }; }; - + return { open: open, get: open, @@ -807,9 +807,9 @@ function makeTransport(options, callback) { callback(m, remote, stream); } } - + if(options.udp === undefined || options.udp) - protocols.UDP = makeUdpTransport(options, callbackAndLog); + protocols.UDP = makeUdpTransport(options, callbackAndLog); if(options.tcp === undefined || options.tcp) protocols.TCP = makeTcpTransport(options, callbackAndLog); if(options.tls) @@ -819,18 +819,18 @@ function makeTransport(options, callback) { function wrap(obj, target) { return Object.create(obj, {send: {value: function(m) { - if(m.method) { - m.headers.via[0].host = options.publicAddress || options.address || options.hostname || os.hostname(); - m.headers.via[0].port = options.port || defaultPort(this.protocol); - m.headers.via[0].protocol = this.protocol; + if(m.method) { + m.headers.via[0].host = options.publicAddress || options.address || options.hostname || os.hostname(); + m.headers.via[0].port = options.port || defaultPort(this.protocol); + m.headers.via[0].protocol = this.protocol; - if(this.protocol === 'UDP' && (!options.hasOwnProperty('rport') || options.rport)) { - m.headers.via[0].params.rport = null; - } - } - options.logger && options.logger.send && options.logger.send(m, target); - obj.send(m); - }}}); + if(this.protocol === 'UDP' && (!options.hasOwnProperty('rport') || options.rport)) { + m.headers.via[0].params.rport = null; + } + } + options.logger && options.logger.send && options.logger.send(m, target); + obj.send(m); + }}}); } return { @@ -850,7 +850,7 @@ function makeTransport(options, callback) { cn.release(); } }, - destroy: function() { + destroy: function() { var protos = protocols; protocols = []; Object.keys(protos).forEach(function(key) { protos[key].destroy(); }); @@ -862,14 +862,14 @@ exports.makeTransport = makeTransport; function makeWellBehavingResolver(resolve) { var outstanding = Object.create(null); - + return function(name, cb) { if(outstanding[name]) { outstanding[name].push(cb); } else { outstanding[name] = [cb]; - + resolve(name, function() { var o = outstanding[name]; delete outstanding[name]; @@ -892,7 +892,7 @@ function resolve(uri, action) { var protocol = uri.params.transport || 'UDP'; return action([{protocol: protocol, address: uri.host, port: uri.port || defaultPort(protocol)}]); } - + function resolve46(host, cb) { resolve4(host, function(e4, a4) { resolve6(host, function(e6, a6) { @@ -906,29 +906,29 @@ function resolve(uri, action) { if(uri.port) { var protocols = uri.params.transport ? [uri.params.transport] : ['UDP', 'TCP', 'TLS']; - + resolve46(uri.host, function(err, address) { address = (address || []).map(function(x) { return protocols.map(function(p) { return { protocol: p, address: x, port: uri.port || defaultPort(p)};});}) .reduce(function(arr,v) { return arr.concat(v); }, []); - action(address); + action(address); }); } else { var protocols = uri.params.transport ? [uri.params.transport] : ['tcp', 'udp', 'tls']; - + var n = protocols.length; var addresses = []; protocols.forEach(function(proto) { resolveSrv('_sip._'+proto+'.'+uri.host, function(e, r) { --n; - + if(Array.isArray(r)) { n += r.length; r.forEach(function(srv) { resolve46(srv.name, function(e, r) { addresses = addresses.concat((r||[]).map(function(a) { return {protocol: proto, address: a, port: srv.port};})); - + if((--n)===0) // all outstanding requests has completed action(addresses); }); @@ -968,14 +968,14 @@ function makeSM() { enter: function(newstate) { if(state && state.leave) state.leave(); - + state = newstate; Array.prototype.shift.apply(arguments); - if(state.enter) + if(state.enter) state.enter.apply(this, arguments); }, signal: function(s) { - if(state && state[s]) + if(state && state[s]) state[Array.prototype.shift.apply(arguments)].apply(state, arguments); } }; @@ -984,9 +984,9 @@ function makeSM() { function createInviteServerTransaction(transport, cleanup) { var sm = makeSM(); var rs; - + var proceeding = { - message: function() { + message: function() { if(rs) transport(rs); }, send: function(message) { @@ -996,7 +996,7 @@ function createInviteServerTransaction(transport, cleanup) { sm.enter(completed); else if(message.status >= 200) sm.enter(accepted); - + transport(rs); } } @@ -1004,7 +1004,7 @@ function createInviteServerTransaction(transport, cleanup) { var g, h; var completed = { enter: function () { - g = setTimeout(function retry(t) { + g = setTimeout(function retry(t) { g = setTimeout(retry, t*2, t*2); transport(rs) }, 500, 500); @@ -1021,8 +1021,8 @@ function createInviteServerTransaction(transport, cleanup) { transport(rs); } } - - var timer_i; + + var timer_i; var confirmed = { enter: function() { timer_i = setTimeout(sm.enter.bind(sm, terminated), 5000);}, leave: function() { clearTimeout(timer_i); } @@ -1032,14 +1032,14 @@ function createInviteServerTransaction(transport, cleanup) { var accepted = { enter: function() { l = setTimeout(sm.enter.bind(sm, terminated), 32000);}, leave: function() { clearTimeout(l); }, - send: function(m) { + send: function(m) { rs = m; transport(rs); - } + } }; var terminated = {enter: cleanup}; - + sm.enter(proceeding); return {send: sm.signal.bind(sm, 'send'), message: sm.signal.bind(sm,'message'), shutdown: function() { sm.enter(terminated); }}; @@ -1056,7 +1056,7 @@ function createServerTransaction(transport, cleanup) { transport(m); if(m.status >= 200) sm.enter(completed); } - }; + }; var j; var completed = { @@ -1086,7 +1086,7 @@ function createInviteClientTransaction(rq, transport, tu, cleanup, options) { a = setTimeout(resend, t*2, t*2); }, 500, 500); } - + b = setTimeout(function() { tu(makeResponse(rq, 408)); sm.enter(terminated); @@ -1101,8 +1101,8 @@ function createInviteClientTransaction(rq, transport, tu, cleanup, options) { if(message.status < 200) sm.enter(proceeding); - else if(message.status < 300) - sm.enter(accepted); + else if(message.status < 300) + sm.enter(accepted); else sm.enter(completed, message); } @@ -1111,7 +1111,7 @@ function createInviteClientTransaction(rq, transport, tu, cleanup, options) { var proceeding = { message: function(message) { tu(message); - + if(message.status >= 300) sm.enter(completed, message); else if(message.status >= 200) @@ -1127,7 +1127,7 @@ function createInviteClientTransaction(rq, transport, tu, cleanup, options) { cseq: {method: 'ACK', seq: rq.headers.cseq.seq}, 'call-id': rq.headers['call-id'], via: [rq.headers.via[0]], - 'max-forwards': (options && options['max-forwards']) || 70 + 'max-forwards': (options && options['max-forwards']) || 70 } }; @@ -1157,20 +1157,20 @@ function createInviteClientTransaction(rq, transport, tu, cleanup, options) { }; var terminated = {enter: cleanup}; - + process.nextTick(function(){ sm.enter(calling); }); - + return {message: sm.signal.bind(sm, 'message'), shutdown: function() { sm.enter(terminated); }}; } -function createClientTransaction(rq, transport, tu, cleanup) { +function createClientTransaction(rq, transport, tu, cleanup) { assert.ok(rq.method !== 'INVITE'); var sm = makeSM(); - + var e, f; var trying = { - enter: function() { + enter: function() { transport(rq); if(!transport.reliable) e = setTimeout(function() { sm.signal('timerE', 500); }, 500); @@ -1231,31 +1231,31 @@ function makeTransactionLayer(options, transport) { return { createServerTransaction: function(rq, cn) { var id = makeTransactionId(rq); - + return server_transactions[id] = (rq.method === 'INVITE' ? createInviteServerTransaction : createServerTransaction)( cn.send.bind(cn), - function() { + function() { delete server_transactions[id]; cn.release(); }); }, createClientTransaction: function(connection, rq, callback) { if(rq.method !== 'CANCEL') rq.headers.via[0].params.branch = generateBranch(); - - + + if(typeof rq.headers.cseq !== 'object') rq.headers.cseq = parseCSeq({s: rq.headers.cseq, i:0}); var send = connection.send.bind(connection); send.reliable = connection.protocol.toUpperCase() !== 'UDP'; - + var id = makeTransactionId(rq); - return client_transactions[id] = - (rq.method === 'INVITE' ? createInviteClientTransaction : createClientTransaction)(rq, send, callback, function() { - delete client_transactions[id]; - connection.release(); - }, - options); + return client_transactions[id] = + (rq.method === 'INVITE' ? createInviteClientTransaction : createClientTransaction)(rq, send, callback, function() { + delete client_transactions[id]; + connection.release(); + }, + options); }, getServer: function(m) { return server_transactions[makeTransactionId(m)]; @@ -1282,7 +1282,7 @@ function sequentialSearch(transaction, connect, addresses, rq, callback) { var lastStatusCode; function next() { onresponse = searching; - + if(addresses.length > 0) { try { var address = addresses.shift(); @@ -1291,10 +1291,10 @@ function sequentialSearch(transaction, connect, addresses, rq, callback) { console.log("err: ", err); } client.message(makeResponse(rq, 503)); - }), rq, function() { onresponse.apply(null, arguments); }); + }), rq, function() { onresponse.apply(null, arguments); }); } catch(e) { - onresponse(address.local ? makeResponse(rq, 430) : makeResponse(rq, 503)); + onresponse(address.local ? makeResponse(rq, 430) : makeResponse(rq, 503)); } } else { @@ -1309,10 +1309,10 @@ function sequentialSearch(transaction, connect, addresses, rq, callback) { return next(); else if(rs.status > 100) onresponse = callback; - + callback(rs); } - + next(); } @@ -1331,7 +1331,7 @@ exports.create = function(options, callback) { } catch(e) { t.send(makeResponse(m, '500', 'Internal Server Error')); throw e; - } + } } else if(m.method === 'ACK') { callback(m,remote); @@ -1340,12 +1340,12 @@ exports.create = function(options, callback) { else { t.message && t.message(m, remote); } - } + } catch(e) { errorLog(e); } }); - + var transaction = makeTransactionLayer(options, transport.open.bind(transport)); var hostname = options.publicAddress || options.address || options.hostname || os.hostname(); var rbytes = crypto.randomBytes(20); @@ -1364,8 +1364,8 @@ exports.create = function(options, callback) { var flow = {protocol: s[1], address: s[2], port: +s[3], local: {address: s[4], port: +s[5]}}; return encodeFlowToken(flow) == token ? flow : undefined; - } - + } + return { send: function(m, callback) { if(m.method === undefined) { @@ -1377,12 +1377,12 @@ exports.create = function(options, callback) { if(typeof m.headers.route === 'string') m.headers.route = parsers.route({s: m.headers.route, i:0}); - + if(m.headers.route && m.headers.route.length > 0) { hop = parseUri(m.headers.route[0].uri); if(hop.host === hostname) { m.headers.route.shift(); - } + } else if(hop.params.lr === undefined ) { m.headers.route.shift(); m.headers.route.push({uri: m.uri}); @@ -1404,7 +1404,7 @@ exports.create = function(options, callback) { if(m.headers.via.length === 0) m.headers.via.unshift({params: {branch: generateBranch()}}); - + if(addresses.length === 0) { errorLog(new Error("ACK: couldn't resolve " + stringifyUri(m.uri))); return; @@ -1413,7 +1413,7 @@ exports.create = function(options, callback) { var cn = transport.open(addresses[0], errorLog); try { cn.send(m); - } + } catch(e) { errorLog(e); } @@ -1422,7 +1422,7 @@ exports.create = function(options, callback) { } } else - sequentialSearch(transaction.createClientTransaction.bind(transaction), transport.open.bind(transport), addresses, m, callback || function() {}); + sequentialSearch(transaction.createClientTransaction.bind(transaction), transport.open.bind(transport), addresses, m, callback || function() {}); }); } }, @@ -1441,7 +1441,7 @@ exports.create = function(options, callback) { transaction.destroy(); transport.destroy(); } - } + } } exports.start = function(options, callback) {