diff --git a/core/AmConfig.cpp b/core/AmConfig.cpp index 472a1358..cf2a33bc 100644 --- a/core/AmConfig.cpp +++ b/core/AmConfig.cpp @@ -107,6 +107,7 @@ bool AmConfig::LogEvents = false; int AmConfig::UnhandledReplyLoglevel = 0; bool AmConfig::SkipGenerateDirectionBoth = false; +bool AmConfig::IgnoreRouteSetOnPrack = false; #ifdef WITH_ZRTP bool AmConfig::enable_zrtp = true; @@ -412,6 +413,10 @@ int AmConfig::readConfiguration() SkipGenerateDirectionBoth = (cfg.getParameter("skip_generate_direction_both") == "yes"); } + if(cfg.hasParameter("ignore_routeset_on_prack")) { + IgnoreRouteSetOnPrack = (cfg.getParameter("ignore_routeset_on_prack") == "yes"); + } + if(cfg.hasParameter("sip_nat_handling")) { SipNATHandling = (cfg.getParameter("sip_nat_handling") == "yes"); } diff --git a/core/AmConfig.h b/core/AmConfig.h index b32e97f0..58c63bc4 100644 --- a/core/AmConfig.h +++ b/core/AmConfig.h @@ -207,6 +207,11 @@ struct AmConfig static vector CodecOrder; static bool SkipGenerateDirectionBoth; + /** strict RFC 3261 behavior for the 200 OK on PRACK: when true, the route + * set is not updated (it is taken once when the dialog is created) and the + * remote tag is only taken from the 200 OK on PRACK if it was not yet set. + * false (default) keeps the legacy behavior of updating both. */ + static bool IgnoreRouteSetOnPrack; enum ApplicationSelector { App_RURIUSER, diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index 82b9933d..3979da4e 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -598,14 +598,26 @@ bool AmSipDialog::onRxReplyStatus(const AmSipReply& reply) /* PRACK */ } else if (reply.cseq_method == SIP_METH_PRACK) { /* do not update call leg status for transactions not involving INVITE. - * In this case just update the to-tag and route set */ - if (!reply.to_tag.empty()) { - ILOG_DLG(L_DBG, "Updating remote tag (to tag) to: '%s'.\n", reply.to_tag.c_str()); - setRemoteTag(reply.to_tag); - } - if (!reply.route.empty()) { - ILOG_DLG(L_DBG, "Updating route set to: '%s'.\n", reply.route.c_str()); - setRouteSet(reply.route); + * With ignore_routeset_on_prack=yes the route set is taken once when the + * dialog is created and is not updated by the 200 OK on PRACK; the remote + * tag is still taken from the 200 OK on PRACK only if it was not already + * known. The default (no) keeps the legacy behavior of updating both from + * the 200 OK on PRACK. + */ + if (AmConfig::IgnoreRouteSetOnPrack) { + if (!reply.to_tag.empty() && getRemoteTag().empty()) { + ILOG_DLG(L_DBG, "Taking remote tag (to tag) from PRACK 200 OK: '%s'.\n", reply.to_tag.c_str()); + setRemoteTag(reply.to_tag); + } + } else { + if (!reply.to_tag.empty()) { + ILOG_DLG(L_DBG, "Updating remote tag (to tag) to: '%s'.\n", reply.to_tag.c_str()); + setRemoteTag(reply.to_tag); + } + if (!reply.route.empty()) { + ILOG_DLG(L_DBG, "Updating route set to: '%s'.\n", reply.route.c_str()); + setRouteSet(reply.route); + } } } diff --git a/core/etc/sems.conf.cmake b/core/etc/sems.conf.cmake index fbd165de..f241faec 100644 --- a/core/etc/sems.conf.cmake +++ b/core/etc/sems.conf.cmake @@ -426,6 +426,18 @@ use_default_signature=yes # #100rel=require +# ignore the route set from the 200 OK on PRACK? [yes, no] +# +# yes - strict RFC 3261: the route set is taken once when the dialog is +# created and not updated, and the remote tag is taken from the 200 OK +# on PRACK only if it was not already known. +# no - legacy behavior: the route set and remote tag are updated from the +# 200 OK on PRACK. +# +# Default: no +# +#ignore_routeset_on_prack=yes + # Make SIP authenticated requests sticky to the proxy? [yes | no] # # If enabled, host of request-URI of out-of-dialog requests that are diff --git a/core/etc/sems.conf.sample b/core/etc/sems.conf.sample index 354d744a..4bcd5847 100644 --- a/core/etc/sems.conf.sample +++ b/core/etc/sems.conf.sample @@ -576,6 +576,18 @@ use_default_signature=yes # #100rel=require +# ignore the route set from the 200 OK on PRACK? [yes, no] +# +# yes - strict RFC 3261: the route set is taken once when the dialog is +# created and not updated, and the remote tag is taken from the 200 OK +# on PRACK only if it was not already known. +# no - legacy behavior: the route set and remote tag are updated from the +# 200 OK on PRACK. +# +# Default: no +# +#ignore_routeset_on_prack=yes + # force the use of outbound interface? [yes, no] # # Useful in case of overlapping networks, or if OS routing can/should not be used.