[Serusers] Re: Record-Route and Route parameters patch

Jan Janak jan at iptel.org
Tue Apr 19 13:04:01 CEST 2005


Thanks for the patch, I will integrate it, some comments are inline.

On 15-04 18:38, Bogdan-Andrei Iancu wrote:
> 
> 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);

  How about using AVPs for this ? Wouldn't it be more flexible ? One
  could possibly create a set of AVPs (with a given name pattern or
  numbers) which could be encoded into the Record-Route header field.
  Later, something like, restore_route_avps() could restore the contents
  of the AVPs...

> 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.

  How are those parameters encoded in the Record-Route header field ? As
  URI parameters or as header field parameters ?

    Jan.

> 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;
> +}
> +
> +
> +




More information about the sr-users mailing list