Module: sip-router Branch: master Commit: 7cbf4e9cbf4b877a661baf67446aeff10cd331cc URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=7cbf4e9c...
Author: Miklos Tirpak miklos@iptel.org Committer: Miklos Tirpak miklos@iptel.org Date: Wed Nov 11 12:51:16 2009 +0100
tm: new select functions
New select functions have been introduced: - @tm.uac.response_retransmission Returns "1" if the response is a retransmission otherwise "-1". - @tm.uac.last_status Returns the last saved status code of the current branch. - @tm.uas.request.neg_ack_retransmission Returns "1" if the negative ACK request is a retransmission otherwise "-1". Note: This select function can be used only for negative ACK messages (ACK for >=300 responses), it should be enhanced in the future to work on any type of requests.
---
modules/tm/select.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 94 insertions(+), 0 deletions(-)
diff --git a/modules/tm/select.c b/modules/tm/select.c index a477512..0024a61 100644 --- a/modules/tm/select.c +++ b/modules/tm/select.c @@ -36,6 +36,7 @@ #include "../../ut.h" #include "../../select.h" #include "../../select_buf.h" +#include "../../parser/msg_parser.h"
#define RETURN0_res(x) {*res=(x);return 0;}
@@ -121,6 +122,26 @@ static int select_tm_uas_response(str* res, select_t* s, struct sip_msg* msg) { return 0; }
+/* TODO: implement a general select function that works with any + * kind of requests not only with negative ACKs + */ +static int select_tm_uas_request_neg_ack_retransmission(str* res, select_t* s, struct sip_msg* msg) { + int rv; + + SELECT_check(msg); + rv = ((msg->REQ_METHOD == METHOD_ACK) + && (t->uas.status >= 300) + /* Misuse the timer flag of the 200 retransmission buffer + * to check whether or not this is an ACK retransmission. + * Warning: this check is not 100% fail-safe because two + * ACKs can be processed in parallel and none of them + * may be considered a retransmission - Miklos */ + && (t->uas.response.t_active == 0)) ? 1 : -1; + + return int_to_static_buffer(res, rv); +} + + static ABSTRACT_F(select_tm_uac);
static int select_tm_uac_count(str* res, select_t* s, struct sip_msg* msg) { @@ -135,6 +156,76 @@ static int select_tm_uac_relayed(str* res, select_t* s, struct sip_msg* msg) {
static ABSTRACT_F(select_tm_uac_branch);
+/** + * Get last_status from current branch. Helper function. + * @see selects select_tm_uac_last_status + * @see select_tm_uac_response_retransmission + */ +static int get_last_status(struct sip_msg* msg, int *last_status) +{ + unsigned int branch; + char *bptr; + int blen; + struct cell *t; + +/* DBG("select_tm_uac_last_status: branch param name: '%.*s', value: '%.*s'\n", + msg->via1->branch->name.len, + msg->via1->branch->name.s, + msg->via1->branch->value.len, + msg->via1->branch->value.s); +*/ + + /* branch ID consist of MAGIC '.' HASHID '.' BRANCH_ID */ + blen = 0; + for (bptr = msg->via1->branch->value.s + msg->via1->branch->value.len - 1; + bptr != msg->via1->branch->value.s; + bptr--, blen++) + { + if (*bptr == '.') break; + } + bptr++; + /* we have a pointer to the branch number */ +/* DBG("branch number: '%.*s'\n", blen, bptr); */ + if (reverse_hex2int(bptr, blen, &branch) < 0) { + ERR("Wrong branch number in Via1 branch param\n"); + return -1; + } + + t = get_t(); + if ( (t == NULL) || (t == T_UNDEFINED) ) { + ERR("get_last_status: no transaction\n"); + return -1; + } + +/* DBG("select_tm_uac_last_status: branch = %d\n", branch); */ + *last_status = t->uac[branch].last_received; + return 1; +} +/** + * Get last status in current branch. + */ +static int select_tm_uac_last_status(str* res, select_t* s, struct sip_msg* msg) { + int last_status; + if (get_last_status(msg, &last_status) < 0) return -1; + return int_to_static_buffer(res, last_status); +} +/** + * Comparison function which compares current status and last status + * in current branch. + * It is a simplified method how to detect incoming retransmited responses. + * @return 1 if @status is less or equal @tm.uac.last_status (retransmited response) + * otherwise returns -1 (not retransmited response). + * @see get_last_status + */ +static int select_tm_uac_response_retransmission(str* res, select_t* s, struct sip_msg* msg) { + int last_status, rv; + if (get_last_status(msg, &last_status) < 0) return -1; + rv = msg->first_line.u.reply.statuscode <= last_status ? 1 : -1; + +/* DBG("select_tm_uac_response_retransmission: %d\n", rv); */ + return int_to_static_buffer(res, rv); +} + static int select_tm_uac_status(str* res, select_t* s, struct sip_msg* msg) { SELECT_check_branch(s, msg); return int_to_static_buffer(res, t->uac[BRANCH_NO(s)].last_received); @@ -174,10 +265,13 @@ static select_row_t select_declaration[] = { { select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("local_to_tag"), select_tm_uas_local_to_tag, 0}, { select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("response"), select_tm_uas_response, 0}, { select_tm_uas, SEL_PARAM_STR, STR_STATIC_INIT("resp"), select_tm_uas_response, 0}, + { select_tm_uas_request, SEL_PARAM_STR, STR_STATIC_INIT("neg_ack_retransmission"), select_tm_uas_request_neg_ack_retransmission, 0},
{ select_tm, SEL_PARAM_STR, STR_STATIC_INIT("uac"), select_tm_uac, SEL_PARAM_EXPECTED}, { select_tm_uac, SEL_PARAM_STR, STR_STATIC_INIT("count"), select_tm_uac_count, 0}, { select_tm_uac, SEL_PARAM_STR, STR_STATIC_INIT("relayed"), select_tm_uac_relayed, 0}, + { select_tm_uac, SEL_PARAM_STR, STR_STATIC_INIT("last_status"), select_tm_uac_last_status, 0}, /* last status of current branch */ + { select_tm_uac, SEL_PARAM_STR, STR_STATIC_INIT("response_retransmission"), select_tm_uac_response_retransmission, 0}, /* last status of current branch */ { select_tm_uac, SEL_PARAM_INT, STR_NULL, select_tm_uac_branch, SEL_PARAM_EXPECTED}, { select_tm_uac_branch, SEL_PARAM_STR, STR_STATIC_INIT("status"), select_tm_uac_status, 0}, { select_tm_uac_branch, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_tm_uac_uri, 0},