We are all aware of SER limitation due the fact it is *only* transaction
statefull at proxy level, any dialog support being missing. There are
many features/services which actually requires a dialog awareness, like
storing the information in the dialog creation stage, information which
will be used during the whole dialog existence.
The most urging example is NAT traversal, in dealing with the within the
dialog INVITEs (re-INVITEs). When processing the initial INVITE, the
proxy detects if the caller or callee is behind some NAT and fixes the
signalling and media parts - since not all the detection mechanism are
available for within the dialog requests (like usrloc), to be able to
fix correspondingly the sequential requests, the proxy must remember
that the original request was NAT processed.
There are many other cases where dialog awareness fixes or helps....it's
not my goal to make a list here....
The solution is to store additional dialog-related information in the
routing set, headers which show up in all sequential requests; by
routing set I would say the Route hdrs and RURI; the routing set is
build based on Record-Route and Contact hdrs.
So far, the way to go was using the Contact header (via parameters) as
carrier. In most of the cases works, but this mechanism is not RFC
reinforced - I had a talk with Juha and he found some phones which
actually ignore the Contact hdr parameters, which is perfect allowed by
RFC....Not to mention that which Contact hdr (UAC or UAS) appear in
routing info depends on the request direction (UAC->UAS or UAS->UAC) and
Record-Route parameters are re-infonced by RFC (see 12.1.1 UAS behavior)
So the next try is to add this information in the Record-Route header
inserted by the proxy. Within the dialog, this information can be found
(with no direction dependencies) in Route header (with or proxy address)...
And here is a patch for the RR module which adds this functionality:
1) adding parameters to Record-Route; since RR is inserted during req.
processing (as lump), no textops function can be apply to it. So use the
add_rr_param("param") function - it can be called also before or after
the record_route() call; I would say it's more convenient from scripting
point of view (no dependencies between doing record_route() and adding
params);
2) checking Route parameters: this could be done via textops, but it
would be dangerous -> you have to identify the Route header
corresponding to your proxy (which will be quite difficult to put as
regexp), So use check_route_param("regexp") function which will check
the proper Route parameters against the given regexp. Must be call after
loose_route().
Basic scenario (example):
UAC SER
PROXY UAS
------ INVITE ----------> record_route() ---------
INVITE -------->
add_rr_param(";foo=true")
----- reINVITE ---------> loose_route() --------
reINVITE ------->
check_route_param(";foo=true")
<---- reINVITE ---------- loose_route() <-------
reINVITE --------
check_route_param(";foo=true")
<-------- BYE ----------- loose_route() <--------- BYE
-----------
check_route_param(";foo=true")
The patch doesn't alter any of the previous functionality.
Jan take a look and let's put it on CVS.
bogdan
Index: modules/rr/loose.c
===================================================================
RCS file: /cvsroot/ser/sip_router/modules/rr/loose.c,v
retrieving revision 1.36
diff -u -r1.36 loose.c
--- modules/rr/loose.c 23 Feb 2005 17:16:05 -0000 1.36
+++ modules/rr/loose.c 15 Apr 2005 14:52:55 -0000
@@ -30,6 +30,8 @@
* ---------
* 2003-02-28 scratchpad compatibility abandoned (jiri)
* 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
+ * 2005-04-10 check_route_param() and all hooks for keeping reference to
+ * Route params added (bogdan)
*/
@@ -57,6 +59,10 @@
#define ROUTE_SUFFIX ">\r\n"
#define ROUTE_SUFFIX_LEN (sizeof(ROUTE_SUFFIX)-1)
+/* variables used to hook the param part of the local route -bogdan */
+static unsigned int routed_msg_id;
+static str routed_params = {0,0};
+
/*
* Test whether we are processing pre-loaded route set
@@ -511,12 +517,16 @@
if (is_myself(&puri.host, puri.port_no))
#endif
{
- /* if (enable_double_rr && is_2rr(&_ruri->params)) { */
- /* DBG("ras(): Removing 2nd URI of mine: '%.*s'\n",
rt->nameaddr.uri.len, ZSW(rt->nameaddr.uri.s)); */
+ /*if (enable_double_rr && is_2rr(&_ruri->params)) {
+ * DBG("ras(): Removing 2nd URI of mine: '%.*s'\n",
+ * rt->nameaddr.uri.len, ZSW(rt->nameaddr.uri.s)); */
+ /* set the hooks for the params -bogdan */
+ routed_msg_id = _m->id;
+ routed_params = puri.params;
if (!rt->next) {
- /* No next route in the same header, remove the whole header
- * field immediately
- */
+ /* No next route in the same header, remove the whole header
+ * field immediately
+ */
if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
LOG(L_ERR, "after_strict: Cannot remove Route HF\n");
return RR_ERROR;
@@ -661,11 +671,15 @@
if (is_myself(&puri.host, puri.port_no))
#endif
{
- DBG("after_loose: Topmost route URI: '%.*s' is me\n", uri->len,
ZSW(uri->s));
+ DBG("after_loose: Topmost route URI: '%.*s' is me\n",
+ uri->len, ZSW(uri->s));
+ /* set the hooks for the params -bogdan */
+ routed_msg_id = _m->id;
+ routed_params = puri.params;
if (!rt->next) {
- /* No next route in the same header, remove the whole header
- * field immediately
- */
+ /* No next route in the same header, remove the whole header
+ * field immediately
+ */
if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
LOG(L_ERR, "after_loose: Can't remove Route HF\n");
return RR_ERROR;
@@ -684,16 +698,16 @@
if (enable_double_rr && is_2rr(&puri.params)) {
if (!rt->next) {
- /* No next route in the same header, remove the whole header
- * field immediately
- */
+ /* No next route in the same header, remove the whole header
+ * field immediately
+ */
if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
LOG(L_ERR, "after_loose: Can't remove Route HF\n");
return RR_ERROR;
}
res = find_next_route(_m, &hdr);
if (res < 0) {
- LOG(L_ERR, "after_loose: Error while finding next route\n");
+ LOG(L_ERR,"after_loose: Error while finding next route\n");
return RR_ERROR;
}
if (res > 0) { /* No next route found */
@@ -783,3 +797,32 @@
}
}
}
+
+
+
+int check_route_param(struct sip_msg * msg, char *re, char *foo)
+{
+ regmatch_t pmatch;
+ char bk;
+
+ /* check if the hooked params belong to the same message */
+ if (routed_msg_id != msg->id)
+ return -1;
+
+ /* check if params are present */
+ if ( !routed_params.s || !routed_params.len )
+ return -1;
+
+ /* do the well-known trick to convert to null terminted */
+ bk = routed_params.s[routed_params.len];
+ routed_params.s[routed_params.len] = 0;
+ DBG("DEBUG:rr:check_route_param: params are <%s>\n", routed_params.s);
+ if (regexec( (regex_t*)re, routed_params.s, 1, &pmatch, 0)!=0) {
+ routed_params.s[routed_params.len] = bk;
+ return -1;
+ } else {
+ routed_params.s[routed_params.len] = bk;
+ return 1;
+ }
+}
+
Index: modules/rr/loose.h
===================================================================
RCS file: /cvsroot/ser/sip_router/modules/rr/loose.h,v
retrieving revision 1.3
diff -u -r1.3 loose.h
--- modules/rr/loose.h 24 Aug 2004 09:00:38 -0000 1.3
+++ modules/rr/loose.h 15 Apr 2005 14:52:56 -0000
@@ -40,4 +40,6 @@
int loose_route(struct sip_msg* _m, char* _s1, char* _s2);
+int check_route_param(struct sip_msg * msg, char *re, char *foo);
+
#endif /* LOOSE_H */
Index: modules/rr/record.c
===================================================================
RCS file: /cvsroot/ser/sip_router/modules/rr/record.c,v
retrieving revision 1.14
diff -u -r1.14 record.c
--- modules/rr/record.c 24 Aug 2004 09:00:38 -0000 1.14
+++ modules/rr/record.c 15 Apr 2005 14:52:56 -0000
@@ -29,6 +29,7 @@
* History:
* -------
* 2003-04-04 Extracted from common.[ch] (janakj)
+ * 2005-04-10 add_rr_param() function and all corresponing hooks added (bogdan)
*/
#include <string.h>
@@ -63,6 +64,22 @@
#define INBOUND 1 /* Insert inbound Record-Route */
#define OUTBOUND 0 /* Insert outbound Record-Route */
+#define RR_PARAM_BUF_SIZE 512
+
+static unsigned int last_rr_msg;
+
+/* RR suffix lump and offset - used for inserting RR params
+ * after RR was done; use a two values array for INBOUND and
+ * OUTBOUND RR -bogdan */
+static struct lump *rr_suffix_lump[2] = {0,0};
+static int rr_suffix_end_offset[2] = {0,0};
+
+/* RR param buffer - usd for storing RR param which are
+ * added before RR insertion -bogdan */
+static char rr_param_buf_ptr[RR_PARAM_BUF_SIZE];
+static str rr_param_buf = {rr_param_buf_ptr,0};
+static unsigned int rr_param_msg;
+
/*
* Extract username from the Request URI
@@ -104,16 +121,20 @@
{
char* prefix, *suffix, *crlf, *r2;
int suffix_len, prefix_len;
+ char *p;
prefix_len = RR_PREFIX_LEN + (user->len ? (user->len + 1) : 0);
prefix = pkg_malloc(prefix_len);
if (enable_full_lr) {
suffix_len = (_lr ? RR_LR_FULL_TERM_LEN : RR_SR_TERM_LEN) +
- ((tag && tag->len) ? (RR_FROMTAG_LEN + tag->len) : 0);
+ ((tag && tag->len) ? (RR_FROMTAG_LEN + tag->len) : 0) +
+ rr_param_buf.len;
} else {
suffix_len = (_lr ? RR_LR_TERM_LEN : RR_SR_TERM_LEN) +
- ((tag && tag->len) ? (RR_FROMTAG_LEN + tag->len) : 0);
+ ((tag && tag->len) ? (RR_FROMTAG_LEN + tag->len) : 0) +
+ rr_param_buf.len;
}
+ rr_suffix_end_offset[_inbound] = RR_SR_TERM_LEN;
suffix = pkg_malloc(suffix_len);
crlf = pkg_malloc(2);
@@ -145,21 +166,24 @@
#endif
prefix[RR_PREFIX_LEN + user->len] = '@';
}
-
+
+ p = suffix;
if (tag && tag->len) {
- memcpy(suffix, RR_FROMTAG, RR_FROMTAG_LEN);
- memcpy(suffix + RR_FROMTAG_LEN, tag->s, tag->len);
- if (enable_full_lr) {
- memcpy(suffix + RR_FROMTAG_LEN + tag->len, _lr ? RR_LR_FULL_TERM : RR_SR_TERM, _lr
? RR_LR_FULL_TERM_LEN : RR_SR_TERM_LEN);
- } else {
- memcpy(suffix + RR_FROMTAG_LEN + tag->len, _lr ? RR_LR_TERM : RR_SR_TERM, _lr ?
RR_LR_TERM_LEN : RR_SR_TERM_LEN);
- }
+ memcpy(p, RR_FROMTAG, RR_FROMTAG_LEN);
+ p += RR_FROMTAG_LEN;
+ memcpy(p, tag->s, tag->len);
+ p += tag->len;
+ }
+ if (rr_param_buf.len) {
+ memcpy( p, rr_param_buf.s, rr_param_buf.len);
+ p += rr_param_buf.len;
+ }
+ if (enable_full_lr) {
+ memcpy( p, _lr ? RR_LR_FULL_TERM : RR_SR_TERM,
+ _lr ? RR_LR_FULL_TERM_LEN : RR_SR_TERM_LEN);
} else {
- if (enable_full_lr) {
- memcpy(suffix, _lr ? RR_LR_FULL_TERM : RR_SR_TERM, _lr ? RR_LR_FULL_TERM_LEN :
RR_SR_TERM_LEN);
- } else {
- memcpy(suffix, _lr ? RR_LR_TERM : RR_SR_TERM, _lr ? RR_LR_TERM_LEN : RR_SR_TERM_LEN);
- }
+ memcpy( p, _lr ? RR_LR_TERM : RR_SR_TERM,
+ _lr ? RR_LR_TERM_LEN : RR_SR_TERM_LEN);
}
memcpy(crlf, CRLF, 2);
@@ -177,6 +201,7 @@
r2 = 0;
}
if (!(_l2 = insert_new_lump_before(_l2, suffix, suffix_len, 0))) goto lump_err;
+ rr_suffix_lump[_inbound] = _l2;
suffix = 0;
if (!(_l2 = insert_new_lump_before(_l2, crlf, 2, 0))) goto lump_err;
crlf = 0;
@@ -225,6 +250,12 @@
tag = 0;
}
+ if (rr_param_buf.len && rr_param_msg!=_m->id) {
+ /* rr_params were set for a different message -> reset buffer */
+ rr_param_buf.len = 0;
+ DBG("----> reset rr_param_buf\n");
+ }
+
if (enable_double_rr) {
l = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0);
l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0);
@@ -256,6 +287,8 @@
return -4;
}
+ /* reset the rr_param buffer */
+ rr_param_buf.len = 0;
return 0;
}
@@ -266,8 +299,6 @@
*/
static inline int do_RR(struct sip_msg* _m, int _lr)
{
- static unsigned int last_rr_msg;
-
if (_m->id == last_rr_msg) {
LOG(L_ERR, "record_route(): Double attempt to record-route\n");
return -1;
@@ -395,3 +426,72 @@
{
return do_RR(_m, 0);
}
+
+
+/*
+ * Appends a string to an existent lump
+ */
+static inline int append_to_lump( struct lump *l, str *s, int end_offset)
+{
+ char *p;
+
+ /* update buffer */
+ p = pkg_realloc( l->u.value, l->len+s->len);
+ if (p==0) {
+ LOG(L_ERR,"ERROR:rr:add_rr_param: no more pkg memory\n");
+ return -1;
+ }
+ memmove(p+l->len-end_offset+s->len, p+l->len-end_offset, end_offset);
+ memcpy( p+l->len-end_offset, s->s, s->len);
+ /* update lump structure */
+ l->len += s->len;
+ l->u.value = p;
+ return 0;
+}
+
+
+/*
+ * Appends a new Record-Route parameter
+ */
+int add_rr_param(struct sip_msg* msg, char* param, char* foo)
+{
+ str *rr_param;
+ int i;
+
+ rr_param = (str*)param;
+
+ if (last_rr_msg==msg->id) {
+ /* RR was already done -> have to modify the RR-sufix lump */
+ for( i=OUTBOUND ; i<=INBOUND ; i++ ) {
+ if ( !rr_suffix_lump[i] || !rr_suffix_end_offset[i] )
+ continue;
+ if (append_to_lump( rr_suffix_lump[i], rr_param,
+ rr_suffix_end_offset[i])!=0) {
+ LOG(L_ERR,"ERROR:rr:add_rr_param: failed to update lump\n");
+ goto error;
+ }
+ }
+ } else {
+ /* RR not done yet -> store the param in the static buffer */
+ if (rr_param_msg!=msg->id) {
+ /* it's about a different messge -> reset buffer */
+ rr_param_buf.len = 0;
+ rr_param_msg = msg->id;
+ }
+ if (rr_param_buf.len+rr_param->len>RR_PARAM_BUF_SIZE) {
+ LOG(L_ERR,"ERROR:rr:add_rr_param: maximum size of "
+ "rr_param_buf exceeded\n");
+ goto error;
+ }
+ memcpy( rr_param_buf.s+rr_param_buf.len, rr_param->s, rr_param->len);
+ rr_param_buf.len += rr_param->len;
+ DBG("DEBUG:rr:add_rr_param: rr_param_buf=<%.*s>\n",rr_param_buf.len,
+ rr_param_buf.s);
+ }
+ return 1;
+
+error:
+ return -1;
+}
+
+
Index: modules/rr/record.h
===================================================================
RCS file: /cvsroot/ser/sip_router/modules/rr/record.h,v
retrieving revision 1.2
diff -u -r1.2 record.h
--- modules/rr/record.h 24 Aug 2004 09:00:38 -0000 1.2
+++ modules/rr/record.h 15 Apr 2005 14:52:56 -0000
@@ -56,4 +56,10 @@
int record_route_strict(struct sip_msg* _m, char* _s1, char* _s2);
+/*
+ * Appends a new Record-Route parameter
+ */
+int add_rr_param(struct sip_msg* msg, char* param, char* foo);
+
+
#endif /* RECORD_H */
Index: modules/rr/rr_mod.c
===================================================================
RCS file: /cvsroot/ser/sip_router/modules/rr/rr_mod.c,v
retrieving revision 1.33
diff -u -r1.33 rr_mod.c
--- modules/rr/rr_mod.c 24 Aug 2004 09:00:38 -0000 1.33
+++ modules/rr/rr_mod.c 15 Apr 2005 14:52:57 -0000
@@ -33,11 +33,14 @@
* 2003-03-19 all mallocs/frees replaced w/ pkg_malloc/pkg_free (andrei)
* 2003-04-01 Added record_route with ip address parameter (janakj)
* 2003-04-14 enable_full_lr parameter introduced (janakj)
+ * 2005-04-10 add_rr_param() and check_route_param() added (bogdan)
*/
#include <stdio.h>
#include <stdlib.h>
+#include <regex.h>
+
#include "../../sr_module.h"
#include "../../ut.h"
#include "../../error.h"
@@ -61,6 +64,7 @@
static int mod_init(void);
static int str_fixup(void** param, int param_no);
+static int regexp_fixup(void** param, int param_no);
/*
@@ -74,10 +78,18 @@
* Oh, BTW, have I mentioned already that you shouldn't use strict routing ?
*/
static cmd_export_t cmds[] = {
- {"loose_route", loose_route, 0, 0, REQUEST_ROUTE},
- {"record_route", record_route, 0, 0, REQUEST_ROUTE},
- {"record_route_preset", record_route_preset, 1, str_fixup, REQUEST_ROUTE},
- {"record_route_strict" , record_route_strict, 0, 0, 0 },
+ {"loose_route", loose_route, 0, 0,
+ REQUEST_ROUTE},
+ {"record_route", record_route, 0, 0,
+ REQUEST_ROUTE},
+ {"record_route_preset", record_route_preset, 1, str_fixup,
+ REQUEST_ROUTE},
+ {"record_route_strict" , record_route_strict, 0, 0,
+ 0},
+ {"add_rr_param", add_rr_param, 1, str_fixup,
+ REQUEST_ROUTE},
+ {"check_route_param", check_route_param, 1, regexp_fixup,
+ REQUEST_ROUTE},
{0, 0, 0, 0, 0}
};
@@ -149,3 +161,29 @@
return 0;
}
+
+
+static int regexp_fixup(void** param, int param_no)
+{
+ regex_t* re;
+
+ if (param_no==1) {
+ if ((re=pkg_malloc(sizeof(regex_t)))==0) {
+ LOG(L_ERR,"ERROR:rr:regexp_fixup: no more pkg memory\n");
+ return E_OUT_OF_MEM;
+ }
+ if (regcomp(re, *param, REG_EXTENDED|REG_ICASE|REG_NEWLINE) ) {
+ pkg_free(re);
+ LOG(L_ERR, "ERROR:rr:regexp_fixup: bad regexp %s\n",(char*)*param);
+ return E_BAD_RE;
+ }
+ /* free string */
+ pkg_free(*param);
+ /* replace it with the compiled re */
+ *param=re;
+ }
+ return 0;
+}
+
+
+