-
Notifications
You must be signed in to change notification settings - Fork 171
/
proxy.js
110 lines (85 loc) · 2.25 KB
/
proxy.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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) {
var ctx = contexts[makeContextId(msg)];
if(!ctx) {
sip.send.apply(sip, arguments);
return;
}
return msg.method ? forwardRequest(ctx, msg, callback || defaultCallback) : forwardResponse(ctx, msg);
};
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 {
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;