text: var sip=require('sip');
  var util=require('util');
  
  var contexts = {};
  
  function makeContextId(msg) {
    var via = msg.headers.via[0];
    return [via.params.branch, via.protocol, via.host, via.port, msg.headers['call-id'], msg.headers.cseq.seq];
  }
  
  function defaultCallback(rs) {
    rs.headers.via.shift();
    exports.send(rs);
  }
  
  
  exports.send = function(msg, callback) {
    try
    {
      var ctx = contexts[makeContextId(msg)];
  
      if(!ctx) {
        sip.send.apply(sip, arguments);
        return;
      }
  
      return msg.method ? forwardRequest(ctx, msg, callback || defaultCallback) : forwardResponse(ctx, msg);
    } catch (e) {
      if (global && global.console && global.console.error && typeof (global.console.error) == 'function') {
        global.console.error({
          type:'sip-send-error',
          info:msg,
          message:e
        })
      }
    }
  };
  
  
  function forwardResponse(ctx, rs, callback) {
    if(+rs.status >= 200) {
      delete contexts[makeContextId(rs)];
    }
  
    sip.send(rs);
  }
  
  
  function sendCancel(rq, via, route) {
    sip.send({
      method: 'CANCEL',
      uri: rq.uri,
      headers: {
        via: [via],
        to: rq.headers.to,
        from: rq.headers.from,
        'call-id': rq.headers['call-id'],
        route: route,
        cseq: {method: 'CANCEL', seq: rq.headers.cseq.seq}
      }
    });
  }
  
  
  function forwardRequest(ctx, rq, callback) {
    var route = rq.headers.route && rq.headers.route.slice();
    sip.send(rq, function(rs, remote) {
      if(+rs.status < 200) {
        var via = rs.headers.via[0];
        ctx.cancellers[rs.headers.via[0].params.branch] = function() { sendCancel(rq, via, route); };
  
        if(ctx.cancelled)
          sendCancel(rq, via, route);
      }
      else {
          if(rs.headers && rs.headers.via && rs.headers.via[0] && rs.headers.via[0].params)
          {
              delete ctx.cancellers[rs.headers.via[0].params.branch];
          }
      }
  
      callback(rs, remote);
    });
  }
  
  
  function onRequest(rq, route, remote) {
    var id = makeContextId(rq);
    contexts[id] = { cancellers: {} };
  
    try {
      route(sip.copyMessage(rq), remote);
    } catch(e) {
      delete contexts[id];
      throw e;
    }
  };
  
  
  exports.start = function(options, route) {
    sip.start(options, function(rq, remote) {
      if(rq.method === 'CANCEL') {
        var ctx = contexts[makeContextId(rq)];
  
        if(ctx) {
          sip.send(sip.makeResponse(rq, 200));
  
          ctx.cancelled = true;
          if(ctx.cancellers) {
            Object.keys(ctx.cancellers).forEach(function(c) { ctx.cancellers[c](); });
          }
        }
        else {
          sip.send(sip.makeResponse(rq, 481));
        }
      }
      else {
        onRequest(rq, route, remote);
      }
    });
  };
  
  exports.stop = sip.stop;
  
  