Hi, i have a problem about the handling of the "cancel" message.
The call flow is this:
A -----------------> (Invite) Proxy (P) B
(100 Tryng) <---------------------------
----------------->(Invite) B
(100 Tryng) <---------------------------
(183 Progress) <---------------------------
(183 Progress) <---------------------------
(200 OK) <---------------------------
(200 OK) <---------------------------
--------------------------------->(CANCEL)
(200 canceling) <---------------------------
(200 OK) <---------------------------
(200 OK) <---------------------------
----------------->(ACK)
----------------->(ACK)
(BYE) <---------------------------
(BYE) <---------------------------
----------------->(481 Call Leg/Transaction Does Not Exist)
----------------->(481 Call Leg/Transaction Does Not Exist)
The B side answer with OK, after a while , a send a CANCEL. I don't know why Kamailio don't forward this message to the B side.
B retry to send the OK message, then A send the ACK.
At the end , B send BYE , but A don't have the transactin.
In this situation, kamailio should deliver the "CANCEL" to the B side ? (even if, before B send the OK )
Or the proxy should not consider the CANCEL because B has answered with "OK" ?
Where is the error on my configuration ?
Thanks
I have Kamailio 1.5.3 and my configuration is this:
modparam("siptrace", "trace_on", 0)
modparam("carrierroute", "config_source", "db")
modparam("auth_db", "password_column", "ha1")
modparam("auth_db", "use_domain", 1)
modparam("usrloc", "db_mode", 2)
#modparam("usrloc","nat_bflag", 8)
modparam("permissions", "trusted_table", "trusted")
modparam("permissions", "db_mode", 1)
modparam("permissions", "peer_tag_avp", "$avp(i:707)")
modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
modparam("avpops","avp_table","usr_preferences")
modparam("avpops","attribute_column","attribute")
modparam("avpops","value_column","value")
modparam("uac","from_restore_mode","auto")
modparam("tm", "fr_timer", 12)
modparam("tm", "wt_timer", 32)
modparam("rr", "append_fromtag", 1)
#modparam("rr", "enable_full_lr", 1)
modparam("userblacklist", "use_domain", 0)
#modparam("dialog", "dlg_flag", 2)
modparam("registrar|nathelper", "received_avp", "$avp(i:42)")
#modparam("registrar", "min_expires", 17000)
modparam("acc", "db_flag", 2)
modparam("acc", "db_missed_flag", 3)
modparam("acc", "db_table_acc", "acc")
modparam("acc", "db_table_missed_calls", "missed_calls")
modparam("acc", "detect_direction", 1)
route{
# -----------------------------------------------------------------
# Sanity Check Section
# -----------------------------------------------------------------
if (!mf_process_maxfwd_header("10"))
{
sl_send_reply("483", "Too Many Hops");
exit;
};
if (msg:len > max_len)
{
sl_send_reply("513", "Message Overflow");
exit;
};
# -----------------------------------------------------------------
# Preprocessing
# -----------------------------------------------------------------
if (!method=="REGISTER") record_route();
# -----------------------------------------------------------------
# NAT Detection
# -----------------------------------------------------------------
force_rport();
if (nat_uac_test("19")) {
if (method=="REGISTER") {
fix_nated_register();
} else {
fix_nated_contact();
}
setflag(7);
}
# -----------------------------------------------------------------
#
# -----------------------------------------------------------------
sip_trace();
##Loose_route packets
if (has_totag()) {
if (loose_route()) {
if(method=="BYE") {
#Account BYE transactions
setflag(2);
};
route(2);
} else {
if ( is_method("ACK") ) {
if ( t_check_trans() ) {
# non loose-route, but stateful ACK;
# must be an ACK after a 487 or e.g. 404 from upstream server
t_relay();
exit;
} else {
# ACK without matching transaction ... ignore and discard.\n");
exit;
}
}
sl_send_reply("404","Not here");
}
exit;
}
# -----------------------------------------------------------------
# CANCEL processing
# -----------------------------------------------------------------
if (is_method("CANCEL")) {
if (t_check_trans()) t_relay();
exit;
};
t_check_trans();
# -----------------------------------------------------------------
#
# -----------------------------------------------------------------
if (method =="OPTIONS" || method=="SUBSCRIBE") {exit;};
if (method =="REGISTER") {route(3);};
route(1);
}
route[2]
{
t_on_reply("1");
if (!t_relay()) {
sl_reply_error();
};
exit;
}
..
failure_route[2] {
if (t_was_cancelled()) {
# xlog("INFO:cancelled transaction--\n");
exit;
}
revert_uri();
..
t_on_failure("2");
append_branch();
if (!t_relay()) {
exit;
};
}
2010/4/29 pars3c pars3c@gmail.com:
Hi, i have a problem about the handling of the “cancel” message.
The B side answer with OK, after a while , a send a CANCEL. I don’t know why Kamailio don’t forward this message to the B side.
Because Kamailio already received a 200 for the INVITE transaction so it's terminated, there is nothing to cancel hen the CANCEL arrives.
B retry to send the OK message, then A send the ACK.
At the end , B send BYE , but A don’t have the transactin.
This is because Kamailio replied 200 to the CANCEL so A still believes it has cancelled and has terminated it locally.
Perhaps Kamailio should reply 404 to the CANCEL as a 200 was already received for the INVITE (could it be a bug?).
However your UAC is doing strange things: - Why does A send a CANCEL after receiving a 200 OK for the INVITE? - Also if A sends an ACK for the 200 (INVITE) it *does* know that the transaction is still alive so shouldn't reply 481.
The behavior of UAC A is not very common and seems buggy IMHO.
200 OK seems correct as long as the transaction is still in memory.
http://tools.ietf.org/html/rfc3261#section-9.2
regards klaus
Am 30.04.2010 10:22, schrieb Iñaki Baz Castillo:
2010/4/29 pars3cpars3c@gmail.com:
Hi, i have a problem about the handling of the “cancel” message.
The B side answer with OK, after a while , a send a CANCEL. I don’t know why Kamailio don’t forward this message to the B side.
Because Kamailio already received a 200 for the INVITE transaction so it's terminated, there is nothing to cancel hen the CANCEL arrives.
B retry to send the OK message, then A send the ACK.
At the end , B send BYE , but A don’t have the transactin.
This is because Kamailio replied 200 to the CANCEL so A still believes it has cancelled and has terminated it locally.
Perhaps Kamailio should reply 404 to the CANCEL as a 200 was already received for the INVITE (could it be a bug?).
However your UAC is doing strange things:
- Why does A send a CANCEL after receiving a 200 OK for the INVITE?
- Also if A sends an ACK for the 200 (INVITE) it *does* know that the
transaction is still alive so shouldn't reply 481.
The behavior of UAC A is not very common and seems buggy IMHO.
2010/4/30 Klaus Darilion klaus.mailinglists@pernau.at:
200 OK seems correct as long as the transaction is still in memory.
I don't agree. As per RFC 3261 when a proxy receives a 200 for an INVITE the transaction is terminated so a CANCEL after the 200 should not match such transaction. Then the proxy should reply 481 to the CANCEL rather than a 200.
Am 30.04.2010 11:37, schrieb Iñaki Baz Castillo:
2010/4/30 Klaus Darilionklaus.mailinglists@pernau.at:
200 OK seems correct as long as the transaction is still in memory.
I don't agree. As per RFC 3261 when a proxy receives a 200 for an INVITE the transaction is terminated so a CANCEL after the 200 should not match such transaction. Then the proxy should reply 481 to the CANCEL rather than a 200.
If the transaction for the original request still exists, the behavior of the UAS on receiving a CANCEL request depends on whether it has already sent a final response for the original request.
This means that the transaction may still exists although the 200 OK was already sent (to absorb retransmissions)
Regardless of the method of the original request, as long as the CANCEL matched an existing transaction, the UAS answers the CANCEL request itself with a 200 (OK) response.
So 200 OK is fine. If it makes sense is a different point.
regards klaus
2010/4/30 Klaus Darilion klaus.mailinglists@pernau.at:
I don't agree. As per RFC 3261 when a proxy receives a 200 for an INVITE the transaction is terminated so a CANCEL after the 200 should not match such transaction. Then the proxy should reply 481 to the CANCEL rather than a 200.
If the transaction for the original request still exists, the behavior of the UAS on receiving a CANCEL request depends on whether it has already sent a final response for the original request.
This means that the transaction may still exists although the 200 OK was already sent (to absorb retransmissions)
No, in RFC 3261 a INVTE transaction ends after a 200 is received, there is no state to absorbe retransmissions. In draft invfix the transaction is not inmediately removed upon receipt of a 200, instead it gets into a new "Accepted" state which allows absorbing ***INVITE*** retransmissions.
But anyway, if the INVITE has been replied with a 200 it makes no sense at all to send a CANCEL so the proxy shouldn't reply 200 to the CANCEL, but a 481.
Regardless of the method of the original request, as long as the CANCEL matched an existing transaction, the UAS answers the CANCEL request itself with a 200 (OK) response.
So 200 OK is fine. If it makes sense is a different point.
Again, RFC 3261 states that the transaction MUST be terminated when the 200 arrives so the CANCEL after it shouldn't match the transaction. In case of draft invfix, IMHO it has a bug in the specification (still a draft) since it says nothing aobut the CANCEL. It doesn't make sense that a proxy or UAS replies 200 to a CANCEL if the proxy or UAS already sent a 200 for the INVITE.
draft invfix: http://tools.ietf.org/html/draft-ietf-sipcore-invfix-01
2010/4/30 Iñaki Baz Castillo ibc@aliax.net:
But anyway, if the INVITE has been replied with a 200 it makes no sense at all to send a CANCEL so the proxy shouldn't reply 200 to the CANCEL, but a 481.
Not exactly, sorry, the proxy should forward the CANCEL stateless:
16.10 CANCEL Processing [...] If a response context is not found, the element does not have any knowledge of the request to apply the CANCEL to. It MUST statelessly forward the CANCEL request (it may have statelessly forwarded the associated request previously).
On Friday 30 April 2010, Iñaki Baz Castillo wrote:
[..] Not exactly, sorry, the proxy should forward the CANCEL stateless:
16.10 CANCEL Processing [...] If a response context is not found, the element does not have any knowledge of the request to apply the CANCEL to. It MUST statelessly forward the CANCEL request (it may have statelessly forwarded the associated request previously).
Hi Iñaki,
ok, but i think in the default server configuration we don't do it this way:
if (is_method("CANCEL")) { if (t_check_trans()) t_relay(); exit; }
We just drop them. In the sr configuration i think there is also a similar method implemented (etc/sip-router.cfg, route[CATCH_CANCEL]). In the past on our systems we've tried to forward them stateless, but this created some loop conditions, if i remember correctly. Sending a final response to the CANCEL (e.g. 491) also not worked out really well.
Henning
2010/5/3 Henning Westerholt henning.westerholt@1und1.de:
16.10 CANCEL Processing [...] If a response context is not found, the element does not have any knowledge of the request to apply the CANCEL to. It MUST statelessly forward the CANCEL request (it may have statelessly forwarded the associated request previously).
Hi Iñaki,
ok, but i think in the default server configuration we don't do it this way:
if (is_method("CANCEL")) { if (t_check_trans()) t_relay(); exit; }
We just drop them. In the sr configuration i think there is also a similar method implemented (etc/sip-router.cfg, route[CATCH_CANCEL]). In the past on our systems we've tried to forward them stateless, but this created some loop conditions, if i remember correctly. Sending a final response to the CANCEL (e.g. 491) also not worked out really well.
Hi Henning, the problem is that the transaction still remains in memory for a while after the 200 has been routed (this is correct according to invfix draft which covers a bug in RFC 3261). So the CANCEL after the 200 *does* match the transaction in TM and then kamailio replies 200 for the CANCEL (which doesn't make sense as there is nothing to cancel).
After the proxy relays the 200 for the INVITE the transaction gets in "Accepted" state (draft invfix) for a while. During this state a CANCEL would match the transaction but it shouldn't generate a 200 for such CANCEL (it's better to ignore it or reply 481).
Regards.
PS: I've open a thread in sip-implementors about this topic.
On Monday 03 May 2010, Iñaki Baz Castillo wrote:
We just drop them. In the sr configuration i think there is also a similar method implemented (etc/sip-router.cfg, route[CATCH_CANCEL]). In the past on our systems we've tried to forward them stateless, but this created some loop conditions, if i remember correctly. Sending a final response to the CANCEL (e.g. 491) also not worked out really well.
Hi Henning, the problem is that the transaction still remains in memory for a while after the 200 has been routed (this is correct according to invfix draft which covers a bug in RFC 3261). So the CANCEL after the 200 *does* match the transaction in TM and then kamailio replies 200 for the CANCEL (which doesn't make sense as there is nothing to cancel).
After the proxy relays the 200 for the INVITE the transaction gets in "Accepted" state (draft invfix) for a while. During this state a CANCEL would match the transaction but it shouldn't generate a 200 for such CANCEL (it's better to ignore it or reply 481).
Hi Iñaki,
ah, i thought you refer here to the general handling of CANCEL messages. Now it makes more sense for me, thanks for the clarification.
Cheers,
Henning
Iñaki Baz Castillo wrote:
2010/4/30 Klaus Darilion klaus.mailinglists@pernau.at:
200 OK seems correct as long as the transaction is still in memory.
I don't agree. As per RFC 3261 when a proxy receives a 200 for an INVITE the transaction is terminated so a CANCEL after the 200 should not match such transaction.
That's a bug in the RFC and we shall not better projects RFC bugs in implementations :) A well behaving proxy shall keep the context for some period of time.
Then the proxy should reply 481 to the CANCEL rather than a 200.
well, once the transaction is gone, forwarding the CANCEL statelessly would seem a legitimiate behaviour, as long as the proxy is in position to produce branch ID consistently with that for INVITE.
-jiri
2010/4/30 Jiri Kuthan jiri@iptel.org:
I don't agree. As per RFC 3261 when a proxy receives a 200 for an INVITE the transaction is terminated so a CANCEL after the 200 should not match such transaction.
That's a bug in the RFC and we shall not better projects RFC bugs in implementations :) A well behaving proxy shall keep the context for some period of time.
Yes, I agree. In fact draft invfix solves it by adding a new state "Accepted" so when a 200 is sent the server transaction remains in memory for a while (to absorbe INVITE retransmissions).
But anyway the transaction is in "Accepted" state, and not in "Proceeding", so a CANCEL should have no effect and the proxy shouldn't reply 200 for the CANCEL as the proxy has canceled *nothing*.
Then the proxy should reply 481 to the CANCEL rather than a 200.
well, once the transaction is gone, forwarding the CANCEL statelessly would seem a legitimiate behaviour, as long as the proxy is in position to produce branch ID consistently with that for INVITE.
Yes, in fact this is the behavior RFC 3261:
16.10 CANCEL Processing [...] If a response context is not found, the element does not have any knowledge of the request to apply the CANCEL to. It MUST statelessly forward the CANCEL request (it may have statelessly forwarded the associated request previously).
But again, what does "response context is not found"?:
- In RFC 3261 it means that the transaction server is terminated as per RFC 3261 it is ended when a 200 arrives and is forwarded (immediately).
- But in draft invfix the transaction remains in "Accepted" state upon receipt of a 200 (to absorbe INVITE retransmissions). So the section 16.10 should be rewriten as: "If a response context in state Proceeding is not found, the element does not have any knowledge of the request to apply the CANCEL to."
Regards.
On Friday 30 April 2010 13:25:13 Iñaki Baz Castillo wrote:
Yes, I agree. In fact draft invfix solves it by adding a new state "Accepted" so when a 200 is sent the server transaction remains in memory for a while (to absorbe INVITE retransmissions).
But anyway the transaction is in "Accepted" state, and not in "Proceeding", so a CANCEL should have no effect and the proxy shouldn't reply 200 for the CANCEL as the proxy has canceled *nothing*.
The response to the CANCEL doesn't indicate if anything has been canceled (just that the CANCEL is well received), the response to the INVITE does. Answering 200 OK to the CANCEL is the least interuptive response as it won't trigger an error in the UAC. A 481 might trigger that the call is aborted as the UAC might think the dialog is invalid. If the 200 OK is received by the UAC, it should handle it just like the well known INVITE + 200 OK / CANCEL race for which it should send a BYE if the dialog is to be ended.
2010/5/4 Alex Hermann alex@speakup.nl:
On Friday 30 April 2010 13:25:13 Iñaki Baz Castillo wrote:
Yes, I agree. In fact draft invfix solves it by adding a new state "Accepted" so when a 200 is sent the server transaction remains in memory for a while (to absorbe INVITE retransmissions).
But anyway the transaction is in "Accepted" state, and not in "Proceeding", so a CANCEL should have no effect and the proxy shouldn't reply 200 for the CANCEL as the proxy has canceled *nothing*.
The response to the CANCEL doesn't indicate if anything has been canceled (just that the CANCEL is well received), the response to the INVITE does. Answering 200 OK to the CANCEL is the least interuptive response as it won't trigger an error in the UAC. A 481 might trigger that the call is aborted as the UAC might think the dialog is invalid. If the 200 OK is received by the UAC, it should handle it just like the well known INVITE + 200 OK / CANCEL race for which it should send a BYE if the dialog is to be ended.
Interesting point of view. Maybe it's just easier as you describe.