Module: sip-router
Branch: master
Commit: 7cbf4e9cbf4b877a661baf67446aeff10cd331cc
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=7cbf4e9…
Author: Miklos Tirpak <miklos(a)iptel.org>
Committer: Miklos Tirpak <miklos(a)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},