everything: shotgun attempt to put PROTO_WS and PROTO_WSS across core and in modules...
[sip-router] / modules / tm / tm.c
index bd1b54a..a251826 100644 (file)
  *  2008-08-11  sctp support: t_relay_to_sctp, t_replicate_sctp,
  *               t_forward_nonack_sctp (andrei)
  *  2009-03-18  added a new param: auto_inv_100_reason (aheise) 
+ *  2010-03-03  added new params: local_cancel_reason and e2e_cancel_reason
+ *              (andrei)
  */
 
-/*!
- * \file 
- * \brief TM :: Module API (core)
- * \ingroup tm
+/** TM :: Module API (core).
+ * @file 
+ * @ingroup tm
  */
 
-/*!
- * \defgroup tm TM :: Transaction stateful proxy support
+/**
+ * @defgroup tm TM :: Transaction stateful proxy support
  *
    The TM module enables stateful processing of SIP transactions. The main use
    of stateful logic, which is costly in terms of memory and CPU, is some
@@ -283,16 +284,20 @@ static int w_t_reset_max_lifetime(struct sip_msg* msg, char* foo, char* bar);
 static int t_set_auto_inv_100(struct sip_msg* msg, char* on_off, char* foo);
 static int t_set_disable_6xx(struct sip_msg* msg, char* on_off, char* foo);
 static int t_set_disable_failover(struct sip_msg* msg, char* on_off, char* f);
+#ifdef CANCEL_REASON_SUPPORT
+static int t_set_no_e2e_cancel_reason(struct sip_msg* msg, char* on_off,
+                                                                               char* f);
+#endif /* CANCEL_REASON_SUPPORT */
 static int t_branch_timeout(struct sip_msg* msg, char*, char*);
 static int t_branch_replied(struct sip_msg* msg, char*, char*);
 static int t_any_timeout(struct sip_msg* msg, char*, char*);
 static int t_any_replied(struct sip_msg* msg, char*, char*);
-static int t_is_canceled(struct sip_msg* msg, char*, char*);
+static int w_t_is_canceled(struct sip_msg* msg, char*, char*);
 static int t_is_expired(struct sip_msg* msg, char*, char*);
 static int t_grep_status(struct sip_msg* msg, char*, char*);
 static int w_t_drop_replies(struct sip_msg* msg, char* foo, char* bar);
 static int w_t_save_lumps(struct sip_msg* msg, char* foo, char* bar);
-static int t_check_trans(struct sip_msg* msg, char* foo, char* bar);
+static int w_t_check_trans(struct sip_msg* msg, char* foo, char* bar);
 
 
 /* by default the fr timers avps are not set, so that the avps won't be
@@ -314,32 +319,32 @@ static cmd_export_t cmds[]={
                        REQUEST_ROUTE},
        {"t_lookup_cancel",    w_t_lookup_cancel,       1, fixup_int_1,
                        REQUEST_ROUTE},
-       {T_REPLY,              w_t_reply,               2, fixup_t_reply,
-                       REQUEST_ROUTE | FAILURE_ROUTE },
+       {"t_reply",              w_t_reply,               2, fixup_t_reply,
+                       REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
        {"t_retransmit_reply", w_t_retransmit_reply,    0, 0,
                        REQUEST_ROUTE},
        {"t_release",          w_t_release,             0, 0,
                        REQUEST_ROUTE},
-       {T_RELAY_TO_UDP,       w_t_relay_to_udp,        2, fixup_hostport2proxy,
+       {"t_relay_to_udp",       w_t_relay_to_udp,        2, fixup_hostport2proxy,
                        REQUEST_ROUTE|FAILURE_ROUTE},
-       {T_RELAY_TO_UDP,       w_t_relay_to_udp_uri,    0, 0,
+       {"t_relay_to_udp",       w_t_relay_to_udp_uri,    0, 0,
                        REQUEST_ROUTE|FAILURE_ROUTE},
 #ifdef USE_TCP
-       {T_RELAY_TO_TCP,       w_t_relay_to_tcp,        2, fixup_hostport2proxy,
+       {"t_relay_to_tcp",       w_t_relay_to_tcp,        2, fixup_hostport2proxy,
                        REQUEST_ROUTE|FAILURE_ROUTE},
-       {T_RELAY_TO_TCP,       w_t_relay_to_tcp_uri,    0, 0,
+       {"t_relay_to_tcp",       w_t_relay_to_tcp_uri,    0, 0,
                        REQUEST_ROUTE|FAILURE_ROUTE},
 #endif
 #ifdef USE_TLS
-       {T_RELAY_TO_TLS,       w_t_relay_to_tls,        2, fixup_hostport2proxy,
+       {"t_relay_to_tls",       w_t_relay_to_tls,        2, fixup_hostport2proxy,
                        REQUEST_ROUTE|FAILURE_ROUTE},
-       {T_RELAY_TO_TLS,       w_t_relay_to_tls_uri,    0, 0,
+       {"t_relay_to_tls",       w_t_relay_to_tls_uri,    0, 0,
                        REQUEST_ROUTE|FAILURE_ROUTE},
 #endif
 #ifdef USE_SCTP
-       {T_RELAY_TO_SCTP,       w_t_relay_to_sctp,       2, fixup_hostport2proxy,
+       {"t_relay_to_sctp",       w_t_relay_to_sctp,       2, fixup_hostport2proxy,
                        REQUEST_ROUTE|FAILURE_ROUTE},
-       {T_RELAY_TO_SCTP,       w_t_relay_to_sctp_uri,    0, 0,
+       {"t_relay_to_sctp",       w_t_relay_to_sctp_uri,    0, 0,
                        REQUEST_ROUTE|FAILURE_ROUTE},
 #endif
        {"t_replicate",        w_t_replicate_uri,       1, fixup_var_str_1,
@@ -362,9 +367,9 @@ static cmd_export_t cmds[]={
 #endif
        {"t_replicate_to", w_t_replicate_to,            2, fixup_proto_hostport2proxy,
                        REQUEST_ROUTE},
-       {T_RELAY,              w_t_relay,               0, 0,
+       {"t_relay",              w_t_relay,               0, 0,
                        REQUEST_ROUTE | FAILURE_ROUTE },
-       {T_RELAY,              w_t_relay2,              2, fixup_hostport2proxy,
+       {"t_relay",              w_t_relay2,              2, fixup_hostport2proxy,
                        REQUEST_ROUTE | FAILURE_ROUTE },
        {"t_relay_to_avp", w_t_relay_to_avp,            2, fixup_proto_hostport2proxy,
                        REQUEST_ROUTE},
@@ -374,22 +379,22 @@ static cmd_export_t cmds[]={
                        REQUEST_ROUTE | FAILURE_ROUTE },
        {"t_relay_to",                  w_t_relay_to,           2, fixup_t_relay_to,
                        REQUEST_ROUTE | FAILURE_ROUTE },
-       {T_FORWARD_NONACK,     w_t_forward_nonack,      2, fixup_hostport2proxy,
+       {"t_forward_nonack",     w_t_forward_nonack,      2, fixup_hostport2proxy,
                        REQUEST_ROUTE},
-       {T_FORWARD_NONACK_URI, w_t_forward_nonack_uri,  0, 0,
+       {"t_forward_nonack_uri", w_t_forward_nonack_uri,  0, 0,
                        REQUEST_ROUTE},
-       {T_FORWARD_NONACK_UDP, w_t_forward_nonack_udp,  2, fixup_hostport2proxy,
+       {"t_forward_nonack_udp", w_t_forward_nonack_udp,  2, fixup_hostport2proxy,
                        REQUEST_ROUTE},
 #ifdef USE_TCP
-       {T_FORWARD_NONACK_TCP, w_t_forward_nonack_tcp,  2, fixup_hostport2proxy,
+       {"t_forward_nonack_tcp", w_t_forward_nonack_tcp,  2, fixup_hostport2proxy,
                        REQUEST_ROUTE},
 #endif
 #ifdef USE_TLS
-       {T_FORWARD_NONACK_TLS, w_t_forward_nonack_tls,  2, fixup_hostport2proxy,
+       {"t_forward_nonack_tls", w_t_forward_nonack_tls,  2, fixup_hostport2proxy,
                        REQUEST_ROUTE},
 #endif
 #ifdef USE_SCTP
-       {T_FORWARD_NONACK_SCTP, w_t_forward_nonack_sctp, 2, fixup_hostport2proxy,
+       {"t_forward_nonack_sctp", w_t_forward_nonack_sctp, 2, fixup_hostport2proxy,
                        REQUEST_ROUTE},
 #endif
        {"t_forward_nonack_to", w_t_forward_nonack_to,  2, fixup_proto_hostport2proxy,
@@ -397,9 +402,9 @@ static cmd_export_t cmds[]={
        {"t_relay_cancel",     w_t_relay_cancel,        0, 0,
                        REQUEST_ROUTE},
        {"t_on_failure",       w_t_on_negative,         1, fixup_on_failure,
-                       REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
+                       REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
        {"t_on_reply",         w_t_on_reply,            1, fixup_on_reply,
-                       REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
+                       REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
        {"t_on_branch",       w_t_on_branch,         1, fixup_on_branch,
                        REQUEST_ROUTE | FAILURE_ROUTE },
        {"t_check_status",     t_check_status,          1, fixup_t_check_status,
@@ -409,44 +414,53 @@ static cmd_export_t cmds[]={
        {"t_write_unix",      t_write_unix,             2, fixup_t_write,
                        REQUEST_ROUTE | FAILURE_ROUTE },
        {"t_set_fr",          t_set_fr_inv,             1, fixup_var_int_1,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_set_fr",          t_set_fr_all,             2, fixup_var_int_12,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_reset_fr",        w_t_reset_fr,             0, 0,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_set_retr",        w_t_set_retr,               2, fixup_var_int_12,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_reset_retr",      w_t_reset_retr,           0, 0,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_set_max_lifetime", w_t_set_max_lifetime,      2, fixup_var_int_12,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_reset_max_lifetime", w_t_reset_max_lifetime, 0, 0,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_set_auto_inv_100", t_set_auto_inv_100,       1, fixup_var_int_1,
                                                                                                          REQUEST_ROUTE},
        {"t_set_disable_6xx", t_set_disable_6xx,         1, fixup_var_int_1,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_set_disable_failover", t_set_disable_failover, 1, fixup_var_int_1,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+#ifdef CANCEL_REASON_SUPPORT
+       {"t_set_no_e2e_cancel_reason", t_set_no_e2e_cancel_reason, 1,
+               fixup_var_int_1,
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+       /* alias for t_set_no_e2e_cancel_reason */
+       {"t_disable_e2e_cancel_reason", t_set_no_e2e_cancel_reason, 1,
+               fixup_var_int_1,
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+#endif /* CANCEL_REASON_SUPPORT */
        {"t_branch_timeout",  t_branch_timeout,         0, 0,  FAILURE_ROUTE},
        {"t_branch_replied",  t_branch_replied,         0, 0,  FAILURE_ROUTE},
        {"t_any_timeout",     t_any_timeout,            0, 0, 
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_any_replied",     t_any_replied,            0, 0, 
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
-       {"t_is_canceled",     t_is_canceled,            0, 0,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+       {"t_is_canceled",     w_t_is_canceled,          0, 0,
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_is_expired",      t_is_expired,             0, 0,
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_grep_status",     t_grep_status,            1, fixup_var_int_1, 
-                       REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
+                       REQUEST_ROUTE|TM_ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE },
        {"t_drop_replies",    w_t_drop_replies,         0, 0,
                        FAILURE_ROUTE},
        {"t_drop_replies",    w_t_drop_replies,         1, 0,
                        FAILURE_ROUTE},
        {"t_save_lumps",      w_t_save_lumps,           0, 0,
                        REQUEST_ROUTE},
-       {"t_check_trans",       t_check_trans,                          0, 0,
+       {"t_check_trans",         w_t_check_trans,                      0, 0,
                        REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE },
 
        {"t_load_contacts", t_load_contacts,            0, 0,
@@ -455,40 +469,8 @@ static cmd_export_t cmds[]={
                        REQUEST_ROUTE | FAILURE_ROUTE},
 
        /* not applicable from the script */
-       {"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,   0, 0},
        {"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,   0, 0},
-       {T_REPLY_WB,           (cmd_function)t_reply_with_body, NO_SCRIPT,   0, 0},
-       {T_IS_LOCAL,           (cmd_function)t_is_local,        NO_SCRIPT,   0, 0},
-       {T_GET_TI,             (cmd_function)t_get_trans_ident, NO_SCRIPT,   0, 0},
-       {T_LOOKUP_IDENT,       (cmd_function)t_lookup_ident,    NO_SCRIPT,   0, 0},
-       {T_ADDBLIND,           (cmd_function)add_blind_uac,     NO_SCRIPT,   0, 0},
-       {"t_request_within",   (cmd_function)req_within,        NO_SCRIPT,   0, 0},
-       {"t_request_outside",  (cmd_function)req_outside,       NO_SCRIPT,   0, 0},
-       {"t_request",          (cmd_function)request,           NO_SCRIPT,   0, 0},
-       {"new_dlg_uac",        (cmd_function)new_dlg_uac,       NO_SCRIPT,   0, 0},
-       {"dlg_response_uac",   (cmd_function)dlg_response_uac,  NO_SCRIPT,   0, 0},
-       {"new_dlg_uas",        (cmd_function)new_dlg_uas,       NO_SCRIPT,   0, 0},
-       {"update_dlg_uas",     (cmd_function)update_dlg_uas,    NO_SCRIPT,   0, 0},
-       {"dlg_request_uas",    (cmd_function)dlg_request_uas,   NO_SCRIPT,   0, 0},
-       {"set_dlg_target",     (cmd_function)set_dlg_target,    NO_SCRIPT,   0, 0},
-       {"free_dlg",           (cmd_function)free_dlg,          NO_SCRIPT,   0, 0},
-       {"print_dlg",          (cmd_function)print_dlg,         NO_SCRIPT,   0, 0},
-       {T_GETT,               (cmd_function)get_t,             NO_SCRIPT,   0, 0},
-       {"calculate_hooks",    (cmd_function)w_calculate_hooks, NO_SCRIPT,   0, 0},
-       {"t_uac",              (cmd_function)t_uac,             NO_SCRIPT,   0, 0},
-       {"t_uac_with_ids",     (cmd_function)t_uac_with_ids,    NO_SCRIPT,   0, 0},
-       {"t_unref",            (cmd_function)t_unref,           NO_SCRIPT,   0, 0},
-       {"run_failure_handlers", (cmd_function)run_failure_handlers, NO_SCRIPT,   0, 0},
-       {"cancel_uacs",        (cmd_function)cancel_uacs,       NO_SCRIPT,   0, 0},
-       {"cancel_all_uacs",    (cmd_function)cancel_all_uacs,        NO_SCRIPT,   0, 0},
-#ifdef WITH_AS_SUPPORT
-       {"ack_local_uac",      (cmd_function)ack_local_uac,     NO_SCRIPT,   0, 0},
-       {"t_get_canceled_ident",   (cmd_function)t_get_canceled_ident,  NO_SCRIPT,
-                       0, 0},
-#endif
-       {"t_suspend",          (cmd_function)t_suspend,         NO_SCRIPT,   0, 0},
-       {"t_continue",         (cmd_function)t_continue,        NO_SCRIPT,   0, 0},
-       {"t_cancel_suspend",   (cmd_function)t_cancel_suspend,  NO_SCRIPT,   0, 0},
+       {"load_xtm",           (cmd_function)load_xtm,          NO_SCRIPT,   0, 0},
        {0,0,0,0,0}
 };
 
@@ -498,11 +480,10 @@ static param_export_t params[]={
        {"via1_matching",       PARAM_INT, &default_tm_cfg.via1_matching         },
        {"fr_timer",            PARAM_INT, &default_tm_cfg.fr_timeout            },
        {"fr_inv_timer",        PARAM_INT, &default_tm_cfg.fr_inv_timeout        },
-       {"fr_inv_timer_next",   PARAM_INT, &default_tm_cfg.fr_inv_timeout_next   },
        {"wt_timer",            PARAM_INT, &default_tm_cfg.wait_timeout          },
        {"delete_timer",        PARAM_INT, &default_tm_cfg.delete_timeout        },
-       {"retr_timer1",         PARAM_INT, &default_tm_cfg.rt_t1_timeout         },
-       {"retr_timer2"  ,       PARAM_INT, &default_tm_cfg.rt_t2_timeout         },
+       {"retr_timer1",         PARAM_INT, &default_tm_cfg.rt_t1_timeout_ms      },
+       {"retr_timer2"  ,       PARAM_INT, &default_tm_cfg.rt_t2_timeout_ms      },
        {"max_inv_lifetime",    PARAM_INT, &default_tm_cfg.tm_max_inv_lifetime   },
        {"max_noninv_lifetime", PARAM_INT, &default_tm_cfg.tm_max_noninv_lifetime},
        {"noisy_ctimer",        PARAM_INT, &default_tm_cfg.noisy_ctimer          },
@@ -535,6 +516,12 @@ static param_export_t params[]={
        {"contacts_avp",        PARAM_STRING, &contacts_avp_param                },
        {"disable_6xx_block",   PARAM_INT, &default_tm_cfg.disable_6xx           },
        {"local_ack_mode",      PARAM_INT, &default_tm_cfg.local_ack_mode        },
+       {"failure_reply_mode",  PARAM_INT, &failure_reply_mode                   },
+       {"faked_reply_prio",    PARAM_INT, &faked_reply_prio                     },
+#ifdef CANCEL_REASON_SUPPORT
+       {"local_cancel_reason", PARAM_INT, &default_tm_cfg.local_cancel_reason   },
+       {"e2e_cancel_reason",   PARAM_INT, &default_tm_cfg.e2e_cancel_reason     },
+#endif /* CANCEL_REASON_SUPPORT */
        {0,0,0}
 };
 
@@ -736,14 +723,11 @@ static int script_init( struct sip_msg *foo, unsigned int flags, void *bar)
        t_on_reply(0);
        t_on_branch(0);
        /* reset the kr status */
-       reset_kr(0);
+       reset_kr();
        /* set request mode so that multiple-mode actions know
         * how to behave */
        set_route_type(REQUEST_ROUTE);
-
-#ifdef POSTPONE_MSG_CLONING
        lumps_are_cloned = 0;
-#endif
        return 1;
 }
 
@@ -858,6 +842,8 @@ static int mod_init(void)
        goto_on_local_req=route_lookup(&event_rt, "tm:local-request");
        if (goto_on_local_req>=0 && event_rt.rlist[goto_on_local_req]==0)
                goto_on_local_req=-1; /* disable */
+       if (goto_on_local_req>=0)
+               set_child_rpc_sip_mode();
 #endif /* WITH_EVENT_LOCAL_REQUEST */
        if (goto_on_sl_reply && onreply_rt.rlist[goto_on_sl_reply]==0)
                WARN("empty/non existing on_sl_reply route\n");
@@ -902,7 +888,7 @@ static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
        str tmp;
        
        fp = (fparam_t*)p1;
-       
+       t = 0;
        /* first get the transaction */
        if (t_check(msg, 0 ) == -1) return -1;
        if ((t = get_t()) == 0) {
@@ -940,13 +926,14 @@ static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
                break;
        }
        
-       switch(route_type) {
+       switch(get_route_type()) {
        case REQUEST_ROUTE:
                /* use the status of the last sent reply */
                status = int2str( t->uas.status, 0);
                break;
                
-       case ONREPLY_ROUTE:
+       case TM_ONREPLY_ROUTE:
+       case CORE_ONREPLY_ROUTE:
                /* use the status of the current reply */
                status = msg->first_line.u.reply.status.s;
                backup = status[msg->first_line.u.reply.status.len];
@@ -973,7 +960,8 @@ static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
                break;
 
        default:
-               LOG(L_ERR,"ERROR:t_check_status: unsupported route type %d\n",route_type);
+               LOG(L_ERR,"ERROR:t_check_status: unsupported route type %d\n",
+                               get_route_type());
                goto error;
        }
 
@@ -987,11 +975,23 @@ static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
                regfree(re);
                pkg_free(re);
        }
-
+       
+       if (unlikely(t && is_route_type(CORE_ONREPLY_ROUTE))){
+               /* t_check() above has the side effect of setting T and
+                  REFerencing T => we must unref and unset it.  */
+               UNREF( t );
+               set_t(T_UNDEFINED, T_BR_UNDEFINED);
+       }
        if (n!=0) return -1;
        return 1;
 
  error:
+       if (unlikely(t && is_route_type(CORE_ONREPLY_ROUTE))){
+               /* t_check() above has the side effect of setting T and
+                  REFerencing T => we must unref and unset it.  */
+               UNREF( t );
+               set_t(T_UNDEFINED, T_BR_UNDEFINED);
+       }
        if (s) pkg_free(s);
        if ((fp->type != FPARAM_REGEX) && re) {
                regfree(re);
@@ -1039,7 +1039,12 @@ inline static int str2proto(char *s, int len) {
                return PROTO_TLS;       
        else if (len == 4 && !strncasecmp(s, "sctp", 4))
                return PROTO_SCTP;
-       else
+       else if (len == 2 && !strncasecmp(s, "ws", 2))
+               return PROTO_WS;
+       else if (len == 3 && !strncasecmp(s, "wss", 3)) {
+               LM_WARN("\"wss\" used somewhere...\n");
+               return PROTO_WS;
+       } else
                return PROTO_NONE;
 }
 
@@ -1208,6 +1213,7 @@ inline static int w_t_forward_nonack_to( struct sip_msg  *p_msg ,
        if (proxy) {
                r = _w_t_forward_nonack(p_msg, proxy, proxy->proto);            
                free_proxy(proxy);
+               pkg_free(proxy);
        }
        return r;
 }
@@ -1253,6 +1259,23 @@ inline static int w_t_reply(struct sip_msg* msg, char* p1, char* p2)
                ret = t_reply_unsafe(t, msg, code, r);
        } else if (is_route_type(REQUEST_ROUTE)) {
                ret = t_reply( t, msg, code, r);
+       } else if (is_route_type(ONREPLY_ROUTE)) {
+               if (likely(t->uas.request)){
+                       if (is_route_type(CORE_ONREPLY_ROUTE))
+                               ret=t_reply(t, t->uas.request, code, r);
+                       else
+                               ret=t_reply_unsafe(t, t->uas.request, code, r);
+               }else
+                       ret=-1;
+               /* t_check() above has the side effect of setting T and
+                  REFerencing T => we must unref and unset it.
+                  Note: this is needed only in the CORE_ONREPLY_ROUTE and not also in
+                  the TM_ONREPLY_ROUTE.
+                */
+               if (is_route_type(CORE_ONREPLY_ROUTE)) {
+                       UNREF( t );
+                       set_t(T_UNDEFINED, T_BR_UNDEFINED);
+               }
        } else {
                LOG(L_CRIT, "BUG: w_t_reply entered in unsupported mode\n");
                ret = -1;
@@ -1268,6 +1291,12 @@ inline static int w_t_release(struct sip_msg* msg, char* str, char* str2)
        struct cell *t;
        int ret;
        
+       if(get_route_type()!=REQUEST_ROUTE)
+       {
+               LM_INFO("invalid usage - not in request route\n");
+               return -1;
+       }
+
        if (t_check( msg  , 0  )==-1) return -1;
        t=get_t();
        if ( t && t!=T_UNDEFINED ) {
@@ -1337,6 +1366,7 @@ inline static int _w_t_relay_to(struct sip_msg  *p_msg ,
                                                                        struct proxy_l *proxy, int force_proto)
 {
        struct cell *t;
+       int res;
 
        if (is_route_type(FAILURE_ROUTE)) {
                t=get_t();
@@ -1344,10 +1374,13 @@ inline static int _w_t_relay_to(struct sip_msg  *p_msg ,
                        LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
                        return -1;
                }
-               if (t_forward_nonack(t, p_msg, proxy, force_proto)<=0 ) {
-                       LOG(L_ERR, "ERROR: w_t_relay_to: t_relay_to failed\n");
-                       /* let us save the error code, we might need it later
-                       when the failure_route has finished (Miklos) */
+               res = t_forward_nonack(t, p_msg, proxy, force_proto);
+               if (res <= 0) {
+                       if (res != E_CFG) {
+                           LOG(L_ERR, "ERROR: w_t_relay_to: t_relay_to failed\n");
+                           /* let us save the error code, we might need it later
+                              when the failure_route has finished (Miklos) */
+                       }
                        tm_error=ser_error;
                        return -1;
                }
@@ -1355,8 +1388,9 @@ inline static int _w_t_relay_to(struct sip_msg  *p_msg ,
        }
        if (is_route_type(REQUEST_ROUTE))
                return t_relay_to( p_msg, proxy, force_proto,
-                       0 /* no replication */ );
-       LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported route type: %d\n", route_type);
+                                                       0 /* no replication */ );
+       LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported route type: %d\n",
+                       get_route_type());
        return 0;
 }
 
@@ -1438,26 +1472,19 @@ inline static int w_t_relay_to_avp( struct sip_msg  *p_msg ,
        if (proxy) {
                r = _w_t_relay_to(p_msg, proxy, PROTO_NONE);
                free_proxy(proxy);
+               pkg_free(proxy);
        }
        return r;
 }
 
-inline static int w_t_replicate_uri(struct sip_msg  *msg ,
-                               char *uri,       /* sip uri as string or variable */
-                               char *_foo       /* nothing expected */ )
+int t_replicate_uri(struct sip_msg *msg, str *suri)
 {
        struct proxy_l *proxy;
        struct sip_uri turi;
-       str suri;
        int r = -1;
 
        memset(&turi, 0, sizeof(struct sip_uri));
-       if(fixup_get_svalue(msg, (gparam_p)uri, &suri)!=0)
-       {
-               LM_ERR("invalid replicate uri parameter");
-               return -1;
-       }
-       if(parse_uri(suri.s, suri.len, &turi)!=0)
+       if(parse_uri(suri->s, suri->len, &turi)!=0)
        {
                LM_ERR("bad replicate SIP address!\n");
                return -1;
@@ -1466,14 +1493,28 @@ inline static int w_t_replicate_uri(struct sip_msg  *msg ,
        proxy=mk_proxy(&turi.host, turi.port_no, turi.proto);
        if (proxy==0) {
                LM_ERR("cannot create proxy from URI <%.*s>\n",
-                       suri.len, suri.s );
+                       suri->len, suri->s );
                return -1;
        }
 
        r = t_replicate(msg, proxy, proxy->proto);
        free_proxy(proxy);
+       pkg_free(proxy);
        return r;
+}
 
+inline static int w_t_replicate_uri(struct sip_msg  *msg ,
+                               char *uri,       /* sip uri as string or variable */
+                               char *_foo       /* nothing expected */ )
+{
+       str suri;
+
+       if(fixup_get_svalue(msg, (gparam_p)uri, &suri)!=0)
+       {
+               LM_ERR("invalid replicate uri parameter");
+               return -1;
+       }
+       return t_replicate_uri(msg, &suri);
 }
 
 inline static int w_t_replicate( struct sip_msg  *p_msg ,
@@ -1529,8 +1570,9 @@ inline static int w_t_replicate_to( struct sip_msg  *p_msg ,
        int r = -1;
        proxy = t_protoaddr2proxy(proto_par, addr_par);
        if (proxy) {
-               r = t_replicate(p_msg, proxy, proxy->proto);            
+               r = t_replicate(p_msg, proxy, proxy->proto);
                free_proxy(proxy);
+               pkg_free(proxy);
        }
        return r;
 }
@@ -1704,6 +1746,11 @@ T_SET_FLAG_GEN_FUNC(t_set_disable_6xx, T_DISABLE_6xx)
 T_SET_FLAG_GEN_FUNC(t_set_disable_failover, T_DISABLE_FAILOVER)
 
 
+#ifdef CANCEL_REASON_SUPPORT
+/* disable/enable e2e cancel reason copy for the current transaction */
+T_SET_FLAG_GEN_FUNC(t_set_no_e2e_cancel_reason, T_NO_E2E_CANCEL_REASON)
+#endif /* CANCEL_REASON_SUPPORT */
+
 
 /* script function, FAILURE_ROUTE only, returns true if the 
  * choosed "failure" branch failed because of a timeout, 
@@ -1725,7 +1772,7 @@ int t_branch_replied(struct sip_msg* msg, char* foo, char* bar)
 
 
 /* script function, returns: 1 if the transaction was canceled, -1 if not */
-int t_is_canceled(struct sip_msg* msg, char* foo, char* bar)
+int t_is_canceled(struct sip_msg* msg)
 {
        struct cell *t;
        int ret;
@@ -1743,6 +1790,11 @@ int t_is_canceled(struct sip_msg* msg, char* foo, char* bar)
        return ret;
 }
 
+static int w_t_is_canceled(struct sip_msg* msg, char* foo, char* bar)
+{
+       return t_is_canceled(msg);
+}
+
 /* script function, returns: 1 if the transaction lifetime interval has already elapsed, -1 if not */
 int t_is_expired(struct sip_msg* msg, char* foo, char* bar)
 {
@@ -1852,37 +1904,25 @@ static int w_t_drop_replies(struct sip_msg* msg, char* foo, char* bar)
 /* save the message lumps after t_newtran() but before t_relay() */
 static int w_t_save_lumps(struct sip_msg* msg, char* foo, char* bar)
 {
-#ifdef POSTPONE_MSG_CLONING
        struct cell *t;
 
-       t=get_t();
-       if (!t || t==T_UNDEFINED) {
-               LOG(L_ERR, "ERROR: w_t_save_lumps: transaction has not been created yet\n");
-               return -1;
-       }
+       if (is_route_type(REQUEST_ROUTE)) {
+               t=get_t();
+               if (!t || t==T_UNDEFINED) {
+                       LOG(L_ERR, "ERROR: w_t_save_lumps: transaction has not been created yet\n");
+                       return -1;
+               }
 
-       if (save_msg_lumps(t->uas.request, msg)) {
-               LOG(L_ERR, "ERROR: w_t_save_lumps: "
-                       "failed to save the message lumps\n");
-               return -1;
-       }
+               if (save_msg_lumps(t->uas.request, msg)) {
+                       LOG(L_ERR, "ERROR: w_t_save_lumps: "
+                               "failed to save the message lumps\n");
+                       return -1;
+               }
+       } /* else nothing to do, the lumps have already been saved */
        return 1;
-#else
-       LOG(L_ERR, "ERROR: w_t_save_lumps: POSTPONE_MSG_CLONING is not defined,"
-                       " thus, the functionality is not supported\n");
-       return -1;
-#endif
 }
 
-static rpc_export_t tm_rpc[] = {
-       {"tm.cancel", rpc_cancel,   rpc_cancel_doc,   0},
-       {"tm.reply",  rpc_reply,    rpc_reply_doc,    0},
-       {"tm.stats",  tm_rpc_stats, tm_rpc_stats_doc, 0},
-       {"tm.hash_stats",  tm_rpc_hash_stats, tm_rpc_hash_stats_doc, 0},
-       {"tm.t_uac_start", rpc_t_uac_start, rpc_t_uac_start_doc, 0 },
-       {"tm.t_uac_wait",  rpc_t_uac_wait,  rpc_t_uac_wait_doc, RET_ARRAY},
-       {0, 0, 0, 0}
-};
+
 
 /* wrapper function needed after changes in w_t_reply */
 int w_t_reply_wrp(struct sip_msg *m, unsigned int code, char *txt)
@@ -1913,15 +1953,20 @@ int w_t_reply_wrp(struct sip_msg *m, unsigned int code, char *txt)
  *       reliable: if the ACK  is delayed the proxied transaction might
  *       be already deleted when it reaches the proxy (wait_timeout))
  */
-static int t_check_trans(struct sip_msg* msg, char* foo, char* bar)
+int t_check_trans(struct sip_msg* msg)
 {
        struct cell* t;
+       int branch;
+       int ret;
        
-       if (msg->first_line.type==SIP_REPLY)
-               return w_t_check(msg, 0 ,0);
-       else if (msg->REQ_METHOD==METHOD_CANCEL)
+       if (msg->first_line.type==SIP_REPLY) {
+               branch = 0;
+               ret = (t_check_msg( msg , &branch)==1) ? 1 : -1;
+               tm_ctx_set_branch_index(branch);
+               return ret;
+       } else if (msg->REQ_METHOD==METHOD_CANCEL) {
                return w_t_lookup_cancel(msg, 0, 0);
-       else{
+       } else {
                switch(t_check_msg(msg, 0)){
                        case -2: /* possible e2e ack */
                                return 1;
@@ -1952,6 +1997,11 @@ static int t_check_trans(struct sip_msg* msg, char* foo, char* bar)
        return -1;
 }
 
+static int w_t_check_trans(struct sip_msg* msg, char* foo, char* bar)
+{
+       return t_check_trans(msg);
+}
+
 static int hexatoi(str *s, unsigned int* result)
 {
        int i, xv, fact;
@@ -2111,3 +2161,53 @@ inline static int w_t_relay_to(struct sip_msg *msg, char *proxy, char *flags)
        return _w_t_relay_to(msg, px, PROTO_NONE);
 }
 
+
+
+/* rpc docs */
+
+static const char* rpc_cancel_doc[2] = {
+       "Cancel a pending transaction",
+       0
+};
+
+static const char* rpc_reply_doc[2] = {
+       "Reply transaction",
+       0
+};
+
+static const char* tm_rpc_stats_doc[2] = {
+       "Print transaction statistics.",
+       0
+};
+
+static const char* tm_rpc_hash_stats_doc[2] = {
+       "Prints hash table statistics (can be used only if tm is compiled"
+               " with -DTM_HASH_STATS).",
+       0
+};
+
+static const char* rpc_t_uac_start_doc[2] = {
+       "starts a tm uac using  a list of string parameters: method, ruri, dst_uri"
+               ", send_sock, headers (CRLF separated) and body (optional)",
+       0
+};
+
+static const char* rpc_t_uac_wait_doc[2] = {
+       "starts a tm uac and waits for the final reply, using a list of string "
+               "parameters: method, ruri, dst_uri send_sock, headers (CRLF separated)"
+               " and body (optional)",
+       0
+};
+
+
+/* rpc exports */
+static rpc_export_t tm_rpc[] = {
+       {"tm.cancel", rpc_cancel,   rpc_cancel_doc,   0},
+       {"tm.reply",  rpc_reply,    rpc_reply_doc,    0},
+       {"tm.stats",  tm_rpc_stats, tm_rpc_stats_doc, 0},
+       {"tm.hash_stats",  tm_rpc_hash_stats, tm_rpc_hash_stats_doc, 0},
+       {"tm.t_uac_start", rpc_t_uac_start, rpc_t_uac_start_doc, 0 },
+       {"tm.t_uac_wait",  rpc_t_uac_wait,  rpc_t_uac_wait_doc, RET_ARRAY},
+       {0, 0, 0, 0}
+};
+