Răsfoiți Sursa

Merge remote branch 'origin/hpw/branch_failure_route'

* origin/hpw/branch_failure_route:
  modules/tm: Fix t_next_contact_flow return value
  modules/tmx: Add $T_reply_ruid pv to return ruid for a branch reply
  modules/tm: Make ruid available in uac structure
  modules/registrar: Allow unregister for ruids in branch_failure_route
  modules/usrloc: Fix get_urecord_by_ruid to return static aor
  modules/tm: Fix setting instance in uac branches
  modules/tm: Enable retrieving of branch instance id from uac structure
  modules/xprint: Updated to use the new get_branch()/next_branch() functions
  modules/pv: Updated to use the new get_branch()/next_branch() functions
  modules/permissions: Updated to use the new get_branch()/next_branch() functions
  modules/domain: Updated to use the new get_branch()/next_branch() functions
  core: Update get_branch() to return instance from appended branches
  modules/tm: Update t_next_contact_flows for use in branch_failure event_route
  core: Add defines required for a new branch_failure_route type
  modules/tm: Create branch-failure event route
  Revert "core: Initial revision of branch_failure_route"
  core: Initial revision of branch_failure_route
  modules/tm: Initial revision of branch_failure_route
Hugh Waite 12 ani în urmă
părinte
comite
2168999d8f

+ 13 - 5
dset.c

@@ -216,7 +216,7 @@ void set_branch_iterator(int n)
 char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 		 str* path, unsigned int *flags,
 		 str* path, unsigned int *flags,
 		 struct socket_info** force_socket,
 		 struct socket_info** force_socket,
-		 str *ruid)
+		 str *ruid, str *instance)
 {
 {
 	if (i < nr_branches) {
 	if (i < nr_branches) {
 		*len = branches[i].len;
 		*len = branches[i].len;
@@ -237,6 +237,10 @@ char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 			ruid->len = branches[i].ruid_len;
 			ruid->len = branches[i].ruid_len;
 			ruid->s = (ruid->len)?branches[i].ruid:0;
 			ruid->s = (ruid->len)?branches[i].ruid:0;
 		}
 		}
+		if (instance) {
+			instance->len = branches[i].instance_len;
+			instance->s = (instance->len)?branches[i].instance:0;
+		}
 		return branches[i].uri;
 		return branches[i].uri;
 	} else {
 	} else {
 		*len = 0;
 		*len = 0;
@@ -257,6 +261,10 @@ char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 			ruid->s = 0;
 			ruid->s = 0;
 			ruid->len = 0;
 			ruid->len = 0;
 		}
 		}
+		if (instance) {
+			instance->s = 0;
+			instance->len = 0;
+		}
 		return 0;
 		return 0;
 	}
 	}
 }
 }
@@ -268,12 +276,12 @@ char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
  */
  */
 char* next_branch(int* len, qvalue_t* q, str* dst_uri, str* path,
 char* next_branch(int* len, qvalue_t* q, str* dst_uri, str* path,
 		  unsigned int* flags, struct socket_info** force_socket,
 		  unsigned int* flags, struct socket_info** force_socket,
-		  str* ruid)
+		  str* ruid, str *instance)
 {
 {
 	char* ret;
 	char* ret;
 	
 	
 	ret=get_branch(branch_iterator, len, q, dst_uri, path, flags,
 	ret=get_branch(branch_iterator, len, q, dst_uri, path, flags,
-		       force_socket, ruid);
+		       force_socket, ruid, instance);
 	if (likely(ret))
 	if (likely(ret))
 		branch_iterator++;
 		branch_iterator++;
 	return ret;
 	return ret;
@@ -442,7 +450,7 @@ char* print_dset(struct sip_msg* msg, int* len)
 	crt_branch = get_branch_iterator();
 	crt_branch = get_branch_iterator();
 
 
 	init_branch_iterator();
 	init_branch_iterator();
-	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0))) {
+	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0))) {
 		cnt++;
 		cnt++;
 		*len += uri.len;
 		*len += uri.len;
 		if (q != Q_UNSPECIFIED) {
 		if (q != Q_UNSPECIFIED) {
@@ -483,7 +491,7 @@ char* print_dset(struct sip_msg* msg, int* len)
 	}
 	}
 
 
 	init_branch_iterator();
 	init_branch_iterator();
-	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0))) {
+	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0))) {
 		if (i) {
 		if (i) {
 			memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
 			memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
 			p += CONTACT_DELIM_LEN;
 			p += CONTACT_DELIM_LEN;

+ 2 - 2
dset.h

@@ -140,12 +140,12 @@ void set_branch_iterator(int n);
  */
  */
 char* next_branch(int* len, qvalue_t* q, str* dst_uri, str* path,
 char* next_branch(int* len, qvalue_t* q, str* dst_uri, str* path,
 		  unsigned int* flags, struct socket_info** force_socket,
 		  unsigned int* flags, struct socket_info** force_socket,
-		  str *ruid);
+		  str *ruid, str *instance);
 
 
 char* get_branch( unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 char* get_branch( unsigned int i, int* len, qvalue_t* q, str* dst_uri,
 		  str* path, unsigned int *flags,
 		  str* path, unsigned int *flags,
 		  struct socket_info** force_socket,
 		  struct socket_info** force_socket,
-		  str* ruid);
+		  str* ruid, str *instance);
 
 
 /*! \brief
 /*! \brief
  * Empty the array of branches
  * Empty the array of branches

+ 1 - 1
modules/domain/domain.c

@@ -142,7 +142,7 @@ int is_uri_host_local(struct sip_msg* _msg, char* _s1, char* _s2)
 	}
 	}
 	return hash_table_lookup(&(_msg->parsed_uri.host), &did, &attrs);
 	return hash_table_lookup(&(_msg->parsed_uri.host), &did, &attrs);
     } else if (is_route_type(FAILURE_ROUTE)) {
     } else if (is_route_type(FAILURE_ROUTE)) {
-	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0, 0);
+	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0, 0, 0);
 	if (branch.s) {
 	if (branch.s) {
 	    if (parse_uri(branch.s, branch.len, &puri) < 0) {
 	    if (parse_uri(branch.s, branch.len, &puri) < 0) {
 		LM_ERR("error while parsing branch URI\n");
 		LM_ERR("error while parsing branch URI\n");

+ 1 - 1
modules/permissions/permissions.c

@@ -406,7 +406,7 @@ static int check_routing(struct sip_msg* msg, int idx)
 	}
 	}
 
 
 check_branches:
 check_branches:
-	for( br_idx=0 ; (branch.s=get_branch(br_idx,&branch.len,&q,0,0,0,0,0))!=0 ;
+	for( br_idx=0 ; (branch.s=get_branch(br_idx,&branch.len,&q,0,0,0,0,0,0))!=0 ;
 			br_idx++ ) {
 			br_idx++ ) {
 		uri_str = get_plain_uri(&branch);
 		uri_str = get_plain_uri(&branch);
 		if (!uri_str) {
 		if (!uri_str) {

+ 1 - 1
modules/pv/pv_branch.c

@@ -49,7 +49,7 @@ int pv_get_branchx(struct sip_msg *msg, pv_param_t *param,
 		return pv_get_null(msg, param, res);
 		return pv_get_null(msg, param, res);
 	}
 	}
 
 
-	uri.s = get_branch(idx, &uri.len, &lq, &duri, &path, &fl, &fsocket, &ruid);
+	uri.s = get_branch(idx, &uri.len, &lq, &duri, &path, &fl, &fsocket, &ruid, 0);
 
 
 	/* branch(count) doesn't need a valid branch, everything else does */
 	/* branch(count) doesn't need a valid branch, everything else does */
 	if(uri.s == 0 && ( param->pvn.u.isname.name.n != 5/* count*/ ))
 	if(uri.s == 0 && ( param->pvn.u.isname.name.n != 5/* count*/ ))

+ 3 - 3
modules/pv/pv_core.c

@@ -1358,7 +1358,7 @@ int pv_get_branch(struct sip_msg *msg, pv_param_t *param,
 		return pv_get_null(msg, param, res);
 		return pv_get_null(msg, param, res);
 
 
 
 
-	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0, 0);
+	branch.s = get_branch(0, &branch.len, &q, 0, 0, 0, 0, 0, 0);
 	if (!branch.s) {
 	if (!branch.s) {
 		return pv_get_null(msg, param, res);
 		return pv_get_null(msg, param, res);
 	}
 	}
@@ -1387,7 +1387,7 @@ int pv_get_branches(struct sip_msg *msg, pv_param_t *param,
   
   
 	cnt = s.len = 0;
 	cnt = s.len = 0;
 
 
-	while ((uri.s = get_branch(cnt, &uri.len, &q, 0, 0, 0, 0, 0)))
+	while ((uri.s = get_branch(cnt, &uri.len, &q, 0, 0, 0, 0, 0, 0)))
 	{
 	{
 		cnt++;
 		cnt++;
 		s.len += uri.len;
 		s.len += uri.len;
@@ -1411,7 +1411,7 @@ int pv_get_branches(struct sip_msg *msg, pv_param_t *param,
 	i = 0;
 	i = 0;
 	p = pv_local_buf;
 	p = pv_local_buf;
 
 
-	while ((uri.s = get_branch(i, &uri.len, &q, 0, 0, 0, 0, 0)))
+	while ((uri.s = get_branch(i, &uri.len, &q, 0, 0, 0, 0, 0, 0)))
 	{
 	{
 		if (i)
 		if (i)
 		{
 		{

+ 1 - 1
modules/registrar/reg_mod.c

@@ -188,7 +188,7 @@ static cmd_export_t cmds[] = {
 	{"unregister",   (cmd_function)w_unregister,  2,  unreg_fixup, 0,
 	{"unregister",   (cmd_function)w_unregister,  2,  unreg_fixup, 0,
 			REQUEST_ROUTE| FAILURE_ROUTE },
 			REQUEST_ROUTE| FAILURE_ROUTE },
 	{"unregister",   (cmd_function)w_unregister2, 3, unreg_fixup, 0,
 	{"unregister",   (cmd_function)w_unregister2, 3, unreg_fixup, 0,
-			REQUEST_ROUTE| FAILURE_ROUTE },
+			REQUEST_ROUTE| FAILURE_ROUTE | BRANCH_FAILURE_ROUTE },
 	{"reg_fetch_contacts", (cmd_function)pv_fetch_contacts, 3, 
 	{"reg_fetch_contacts", (cmd_function)pv_fetch_contacts, 3, 
 			fetchc_fixup, 0,
 			fetchc_fixup, 0,
 			REQUEST_ROUTE| FAILURE_ROUTE },
 			REQUEST_ROUTE| FAILURE_ROUTE },

+ 0 - 1
modules/registrar/save.c

@@ -997,7 +997,6 @@ int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri, str *_ruid)
 			LM_WARN("could not delete contact\n");
 			LM_WARN("could not delete contact\n");
 			return -1;
 			return -1;
 		}
 		}
-		ul.release_urecord(r);
 		ul.unlock_udomain(_d, &aor);
 		ul.unlock_udomain(_d, &aor);
 	}
 	}
 
 

+ 2 - 0
modules/tm/h_table.h

@@ -229,6 +229,8 @@ typedef struct ua_client
 #endif
 #endif
 	str uri;
 	str uri;
 	str path;
 	str path;
+	str instance;
+	str ruid;
 	/* if we don't store, we at least want to know the status */
 	/* if we don't store, we at least want to know the status */
 	int             last_received;
 	int             last_received;
 
 

+ 143 - 11
modules/tm/t_fwd.c

@@ -187,7 +187,8 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 									str* next_hop,
 									str* next_hop,
 									struct socket_info* fsocket,
 									struct socket_info* fsocket,
 									snd_flags_t snd_flags,
 									snd_flags_t snd_flags,
-									int fproto, int flags)
+									int fproto, int flags,
+									str *instance, str *ruid)
 {
 {
 	char *shbuf;
 	char *shbuf;
 	struct lump* add_rm_backup, *body_lumps_backup;
 	struct lump* add_rm_backup, *body_lumps_backup;
@@ -200,6 +201,10 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 	int dst_uri_backed_up;
 	int dst_uri_backed_up;
 	str path_bak;
 	str path_bak;
 	int free_path;
 	int free_path;
+	str instance_bak;
+	int free_instance;
+	str ruid_bak;
+	int free_ruid;
 	int backup_route_type;
 	int backup_route_type;
 	snd_flags_t fwd_snd_flags_bak;
 	snd_flags_t fwd_snd_flags_bak;
 	snd_flags_t rpl_snd_flags_bak;
 	snd_flags_t rpl_snd_flags_bak;
@@ -219,6 +224,12 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 	path_bak.s=0;
 	path_bak.s=0;
 	path_bak.len=0;
 	path_bak.len=0;
 	free_path=0;
 	free_path=0;
+	instance_bak.s=0;
+	instance_bak.len=0;
+	free_instance=0;
+	ruid_bak.s=0;
+	ruid_bak.len=0;
+	free_ruid=0;
 	dst=&t->uac[branch].request.dst;
 	dst=&t->uac[branch].request.dst;
 
 
 	/* ... we calculate branch ... */	
 	/* ... we calculate branch ... */	
@@ -259,6 +270,8 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 	parsed_uri_bak=i_req->parsed_uri;
 	parsed_uri_bak=i_req->parsed_uri;
 	parsed_uri_ok_bak=i_req->parsed_uri_ok;
 	parsed_uri_ok_bak=i_req->parsed_uri_ok;
 	path_bak=i_req->path_vec;
 	path_bak=i_req->path_vec;
+	instance_bak=i_req->instance;
+	ruid_bak=i_req->ruid;
 	
 	
 	if (unlikely(branch_route || has_tran_tmcbs(t, TMCB_REQUEST_FWDED))){
 	if (unlikely(branch_route || has_tran_tmcbs(t, TMCB_REQUEST_FWDED))){
 		/* dup uris, path a.s.o. if we have a branch route or callback */
 		/* dup uris, path a.s.o. if we have a branch route or callback */
@@ -292,6 +305,37 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 			}
 			}
 			free_path=1;
 			free_path=1;
 		}
 		}
+		/* update instance */
+		/* if instance points to msg instance, it needs to be "fixed" so that we 
+		   can change/update msg->instance */
+		if (instance==&i_req->instance)
+			instance=&instance_bak;
+		/* zero it first so that set_instance will work */
+		i_req->instance.s=0;
+		i_req->instance.len=0;
+		if (unlikely(instance)){
+			if (unlikely(set_instance(i_req, instance)<0)){
+				ret=E_OUT_OF_MEM;
+				goto error03;
+			}
+			free_instance=1;
+		}
+
+		/* update ruid */
+		/* if ruid points to msg ruid, it needs to be "fixed" so that we 
+		   can change/update msg->ruid */
+		if (ruid==&i_req->ruid)
+			ruid=&ruid_bak;
+		/* zero it first so that set_ruid will work */
+		i_req->ruid.s=0;
+		i_req->ruid.len=0;
+		if (unlikely(ruid)){
+			if (unlikely(set_ruid(i_req, ruid)<0)){
+				ret=E_OUT_OF_MEM;
+				goto error03;
+			}
+			free_ruid=1;
+		}
 	
 	
 		/* backup dst uri  & zero it*/
 		/* backup dst uri  & zero it*/
 		dst_uri_bak=i_req->dst_uri;
 		dst_uri_bak=i_req->dst_uri;
@@ -397,6 +441,20 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 			i_req->path_vec.s=0;
 			i_req->path_vec.s=0;
 			i_req->path_vec.len=0;
 			i_req->path_vec.len=0;
 		}
 		}
+		if (unlikely(instance && (i_req->instance.s!=instance->s ||
+							  i_req->instance.len!=instance->len))){
+			i_req->instance=*instance;
+		}else if (unlikely(instance==0 && i_req->instance.len!=0)){
+			i_req->instance.s=0;
+			i_req->instance.len=0;
+		}
+		if (unlikely(ruid && (i_req->ruid.s!=ruid->s ||
+							  i_req->ruid.len!=ruid->len))){
+			i_req->ruid=*ruid;
+		}else if (unlikely(ruid==0 && i_req->ruid.len!=0)){
+			i_req->ruid.s=0;
+			i_req->ruid.len=0;
+		}
 	}
 	}
 	
 	
 	if (likely(next_hop!=0 || (flags & UAC_DNS_FAILOVER_F))){
 	if (likely(next_hop!=0 || (flags & UAC_DNS_FAILOVER_F))){
@@ -463,6 +521,36 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
 		t->uac[branch].path.s[i_req->path_vec.len]=0;
 		t->uac[branch].path.s[i_req->path_vec.len]=0;
 		memcpy( t->uac[branch].path.s, i_req->path_vec.s, i_req->path_vec.len);
 		memcpy( t->uac[branch].path.s, i_req->path_vec.s, i_req->path_vec.len);
 	}
 	}
+	if (unlikely(i_req->instance.s && i_req->instance.len)){
+		t->uac[branch].instance.s=shm_malloc(i_req->instance.len+1);
+		if (unlikely(t->uac[branch].instance.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=E_OUT_OF_MEM;
+			goto error01;
+		}
+		t->uac[branch].instance.len=i_req->instance.len;
+		t->uac[branch].instance.s[i_req->instance.len]=0;
+		memcpy( t->uac[branch].instance.s, i_req->instance.s, i_req->instance.len);
+	}
+	if (unlikely(i_req->ruid.s && i_req->ruid.len)){
+		t->uac[branch].ruid.s=shm_malloc(i_req->ruid.len+1);
+		if (unlikely(t->uac[branch].ruid.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=E_OUT_OF_MEM;
+			goto error01;
+		}
+		t->uac[branch].ruid.len=i_req->ruid.len;
+		t->uac[branch].ruid.s[i_req->ruid.len]=0;
+		memcpy( t->uac[branch].ruid.s, i_req->ruid.s, i_req->ruid.len);
+	}
 	ret=0;
 	ret=0;
 
 
 error01:
 error01:
@@ -474,6 +562,12 @@ error03:
 	if (unlikely(free_path)){
 	if (unlikely(free_path)){
 		reset_path_vector(i_req);
 		reset_path_vector(i_req);
 	}
 	}
+	if (unlikely(free_instance)){
+		reset_instance(i_req);
+	}
+	if (unlikely(free_ruid)){
+		reset_ruid(i_req);
+	}
 	if (dst_uri_backed_up){
 	if (dst_uri_backed_up){
 		reset_dst_uri(i_req); /* free dst_uri */
 		reset_dst_uri(i_req); /* free dst_uri */
 		i_req->dst_uri=dst_uri_bak;
 		i_req->dst_uri=dst_uri_bak;
@@ -483,6 +577,8 @@ error03:
 	i_req->parsed_uri=parsed_uri_bak;
 	i_req->parsed_uri=parsed_uri_bak;
 	i_req->parsed_uri_ok=parsed_uri_ok_bak;
 	i_req->parsed_uri_ok=parsed_uri_ok_bak;
 	i_req->path_vec=path_bak;
 	i_req->path_vec=path_bak;
+	i_req->instance=instance_bak;
+	i_req->ruid=ruid_bak;
 	
 	
 	/* Delete the duplicated lump lists, this will also delete
 	/* Delete the duplicated lump lists, this will also delete
 	 * all lumps created here, such as lumps created in per-branch
 	 * all lumps created here, such as lumps created in per-branch
@@ -646,7 +742,7 @@ int add_blind_uac( /*struct cell *t*/ )
 static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
 static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
 					str* next_hop, str* path, struct proxy_l *proxy,
 					str* next_hop, str* path, struct proxy_l *proxy,
 					struct socket_info* fsocket, snd_flags_t snd_flags,
 					struct socket_info* fsocket, snd_flags_t snd_flags,
-					int proto, int flags)
+					int proto, int flags, str *instance, str *ruid)
 {
 {
 
 
 	int ret;
 	int ret;
@@ -691,7 +787,7 @@ static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
 	/* now message printing starts ... */
 	/* now message printing starts ... */
 	if (unlikely( (ret=prepare_new_uac(t, request, branch, uri, path,
 	if (unlikely( (ret=prepare_new_uac(t, request, branch, uri, path,
 										next_hop, fsocket, snd_flags,
 										next_hop, fsocket, snd_flags,
-										proto, flags)) < 0)){
+										proto, flags, instance, ruid)) < 0)){
 		ser_error=ret;
 		ser_error=ret;
 		goto error01;
 		goto error01;
 	}
 	}
@@ -731,7 +827,8 @@ static int add_uac_from_buf( struct cell *t, struct sip_msg *request,
 								struct socket_info* fsocket,
 								struct socket_info* fsocket,
 								snd_flags_t send_flags,
 								snd_flags_t send_flags,
 								int proto,
 								int proto,
-								char *buf, short buf_len)
+								char *buf, short buf_len,
+								str *instance, str *ruid)
 {
 {
 
 
 	int ret;
 	int ret;
@@ -802,6 +899,38 @@ static int add_uac_from_buf( struct cell *t, struct sip_msg *request,
 		t->uac[branch].path.s[path->len]=0;
 		t->uac[branch].path.s[path->len]=0;
 		memcpy( t->uac[branch].path.s, path->s, path->len);
 		memcpy( t->uac[branch].path.s, path->s, path->len);
 	}
 	}
+	/* copy the instance */
+	if (unlikely(instance && instance->s)){
+		t->uac[branch].instance.s=shm_malloc(instance->len+1);
+		if (unlikely(t->uac[branch].instance.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=ser_error=E_OUT_OF_MEM;
+			goto error;
+		}
+		t->uac[branch].instance.len=instance->len;
+		t->uac[branch].instance.s[instance->len]=0;
+		memcpy( t->uac[branch].instance.s, instance->s, instance->len);
+	}
+	/* copy the ruid */
+	if (unlikely(ruid && ruid->s)){
+		t->uac[branch].ruid.s=shm_malloc(ruid->len+1);
+		if (unlikely(t->uac[branch].ruid.s==0)) {
+			shm_free(shbuf);
+			t->uac[branch].request.buffer=0;
+			t->uac[branch].request.buffer_len=0;
+			t->uac[branch].uri.s=0;
+			t->uac[branch].uri.len=0;
+			ret=ser_error=E_OUT_OF_MEM;
+			goto error;
+		}
+		t->uac[branch].ruid.len=ruid->len;
+		t->uac[branch].ruid.s[ruid->len]=0;
+		memcpy( t->uac[branch].ruid.s, ruid->s, ruid->len);
+	}
 	membar_write(); /* to allow lockless ops (e.g. prepare_to_cancel()) we want
 	membar_write(); /* to allow lockless ops (e.g. prepare_to_cancel()) we want
 					   to be sure everything above is fully written before
 					   to be sure everything above is fully written before
 					   updating branches no. */
 					   updating branches no. */
@@ -873,7 +1002,8 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
 							old_uac->request.dst.send_flags,
 							old_uac->request.dst.send_flags,
 							old_uac->request.dst.proto,
 							old_uac->request.dst.proto,
 							old_uac->request.buffer,
 							old_uac->request.buffer,
-							old_uac->request.buffer_len);
+							old_uac->request.buffer_len,
+							&old_uac->instance, &old_uac->ruid);
 			}else
 			}else
 				/* add_uac will use dns_h => next_hop will be ignored.
 				/* add_uac will use dns_h => next_hop will be ignored.
 				 * Unfortunately we can't reuse the old buffer, the branch id
 				 * Unfortunately we can't reuse the old buffer, the branch id
@@ -884,7 +1014,8 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg* msg,
 								SND_F_FORCE_SOCKET)?
 								SND_F_FORCE_SOCKET)?
 									old_uac->request.dst.send_sock:0,
 									old_uac->request.dst.send_sock:0,
 							old_uac->request.dst.send_flags,
 							old_uac->request.dst.send_flags,
-							old_uac->request.dst.proto, UAC_DNS_FAILOVER_F);
+							old_uac->request.dst.proto, UAC_DNS_FAILOVER_F,
+							&old_uac->instance, &old_uac->ruid);
 
 
 			if (ret<0){
 			if (ret<0){
 				/* failed, delete the copied dns_h */
 				/* failed, delete the copied dns_h */
@@ -959,7 +1090,8 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
 		if (unlikely((ret=prepare_new_uac( t_cancel, cancel_msg, branch,
 		if (unlikely((ret=prepare_new_uac( t_cancel, cancel_msg, branch,
 									&t_invite->uac[branch].uri,
 									&t_invite->uac[branch].uri,
 									&t_invite->uac[branch].path,
 									&t_invite->uac[branch].path,
-									0, 0, snd_flags, PROTO_NONE, 0)) <0)){
+									0, 0, snd_flags, PROTO_NONE, 0,
+									NULL, NULL)) <0)){
 			ser_error=ret;
 			ser_error=ret;
 			goto error;
 			goto error;
 		}
 		}
@@ -1418,7 +1550,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 	int success_branch;
 	int success_branch;
 	int try_new;
 	int try_new;
 	int lock_replies;
 	int lock_replies;
-	str dst_uri, path;
+	str dst_uri, path, instance, ruid;
 	struct socket_info* si;
 	struct socket_info* si;
 	flag_t backup_bflags = 0;
 	flag_t backup_bflags = 0;
 	flag_t bflags = 0;
 	flag_t bflags = 0;
@@ -1484,7 +1616,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 		branch_ret=add_uac( t, p_msg, GET_RURI(p_msg), GET_NEXT_HOP(p_msg),
 		branch_ret=add_uac( t, p_msg, GET_RURI(p_msg), GET_NEXT_HOP(p_msg),
 							&p_msg->path_vec, proxy, p_msg->force_send_socket,
 							&p_msg->path_vec, proxy, p_msg->force_send_socket,
 							p_msg->fwd_send_flags, proto,
 							p_msg->fwd_send_flags, proto,
-							(p_msg->dst_uri.len)?0:UAC_SKIP_BR_DST_F);
+							(p_msg->dst_uri.len)?0:UAC_SKIP_BR_DST_F, &p_msg->instance, &p_msg->ruid);
 		if (branch_ret>=0) 
 		if (branch_ret>=0) 
 			added_branches |= 1<<branch_ret;
 			added_branches |= 1<<branch_ret;
 		else
 		else
@@ -1493,14 +1625,14 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
 
 
 	init_branch_iterator();
 	init_branch_iterator();
 	while((current_uri.s=next_branch( &current_uri.len, &q, &dst_uri, &path,
 	while((current_uri.s=next_branch( &current_uri.len, &q, &dst_uri, &path,
-										&bflags, &si, 0))) {
+										&bflags, &si, &ruid, &instance))) {
 		try_new++;
 		try_new++;
 		setbflagsval(0, bflags);
 		setbflagsval(0, bflags);
 
 
 		branch_ret=add_uac( t, p_msg, &current_uri,
 		branch_ret=add_uac( t, p_msg, &current_uri,
 							(dst_uri.len) ? (&dst_uri) : &current_uri,
 							(dst_uri.len) ? (&dst_uri) : &current_uri,
 							&path, proxy, si, p_msg->fwd_send_flags,
 							&path, proxy, si, p_msg->fwd_send_flags,
-							proto, (dst_uri.len)?0:UAC_SKIP_BR_DST_F);
+							proto, (dst_uri.len)?0:UAC_SKIP_BR_DST_F, &instance, &ruid);
 		/* pick some of the errors in case things go wrong;
 		/* pick some of the errors in case things go wrong;
 		   note that picking lowest error is just as good as
 		   note that picking lowest error is just as good as
 		   any other algorithm which picks any other negative
 		   any other algorithm which picks any other negative

+ 5 - 1
modules/tm/t_hooks.h

@@ -82,7 +82,9 @@ struct cell;
 #endif
 #endif
 #define TMCB_REQUEST_SENT_N     22
 #define TMCB_REQUEST_SENT_N     22
 #define TMCB_RESPONSE_SENT_N    23
 #define TMCB_RESPONSE_SENT_N    23
-#define TMCB_MAX_N              23
+#define TMCB_ON_BRANCH_FAILURE_RO_N 24
+#define TMCB_ON_BRANCH_FAILURE_N 25
+#define TMCB_MAX_N              25
 
 
 
 
 #define TMCB_REQUEST_IN       (1<<TMCB_REQUEST_IN_N)
 #define TMCB_REQUEST_IN       (1<<TMCB_REQUEST_IN_N)
@@ -111,6 +113,8 @@ struct cell;
 #endif
 #endif
 #define TMCB_REQUEST_SENT      (1<<TMCB_REQUEST_SENT_N)
 #define TMCB_REQUEST_SENT      (1<<TMCB_REQUEST_SENT_N)
 #define TMCB_RESPONSE_SENT     (1<<TMCB_RESPONSE_SENT_N)
 #define TMCB_RESPONSE_SENT     (1<<TMCB_RESPONSE_SENT_N)
+#define TMCB_ON_BRANCH_FAILURE (1<<TMCB_ON_BRANCH_FAILURE_N)
+#define TMCB_ON_BRANCH_FAILURE_RO (1<<TMCB_ON_BRANCH_FAILURE_RO_N)
 #define TMCB_MAX              ((1<<(TMCB_MAX_N+1))-1)
 #define TMCB_MAX              ((1<<(TMCB_MAX_N+1))-1)
 
 
 
 

+ 129 - 0
modules/tm/t_reply.c

@@ -172,6 +172,8 @@ char *tm_tag_suffix;
 
 
 /* where to go if there is no positive reply (>=300) */
 /* where to go if there is no positive reply (>=300) */
 static int goto_on_failure=0;
 static int goto_on_failure=0;
+/* where to go if a failure is returned on a branch */
+int goto_on_branch_failure=0;
 /* where to go on receipt of reply */
 /* where to go on receipt of reply */
 static int goto_on_reply=0;
 static int goto_on_reply=0;
 /* where to go on receipt of reply without transaction context */
 /* where to go on receipt of reply without transaction context */
@@ -1039,6 +1041,62 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
 }
 }
 
 
 
 
+/* return 1 if a failure_route processes */
+int run_branch_failure_handlers(struct cell *t, struct sip_msg *rpl,
+					int code, int extra_flags)
+{
+	static struct sip_msg faked_req;
+	struct sip_msg *shmem_msg = t->uas.request;
+
+	/* failure_route for a local UAC? */
+	if (!shmem_msg) {
+		LOG(L_WARN,"Warning: run_branch_failure_handlers: no UAC support (%d, %d) \n",
+			goto_on_branch_failure, t->tmcb_hl.reg_types);
+		return 0;
+	}
+
+	/* don't start faking anything if we don't have to */
+	if (unlikely((goto_on_branch_failure < 0) && !has_tran_tmcbs( t, TMCB_ON_BRANCH_FAILURE))) {
+		LOG(L_WARN,
+			"Warning: run_failure_handlers: no branch_failure handler (%d, %d)\n",
+			goto_on_branch_failure, t->tmcb_hl.reg_types);
+		return 1;
+	}
+
+	if (!fake_req(&faked_req, shmem_msg, extra_flags, &t->uac[picked_branch])) {
+		LOG(L_ERR, "ERROR: run_branch_failure_handlers: fake_req failed\n");
+		return 0;
+	}
+	/* fake also the env. conforming to the fake msg */
+	faked_env( t, &faked_req);
+	set_route_type(BRANCH_FAILURE_ROUTE);
+	set_t(t, picked_branch);
+	/* DONE with faking ;-) -> run the branch_failure handlers */
+
+	if (unlikely(has_tran_tmcbs( t, TMCB_ON_BRANCH_FAILURE)) ) {
+		run_trans_callbacks( TMCB_ON_BRANCH_FAILURE, t, &faked_req, rpl, code);
+	}
+	if (goto_on_branch_failure >= 0) {
+		if (exec_pre_script_cb(&faked_req, BRANCH_FAILURE_CB_TYPE)>0) {
+			/* run a branch_failure_route action if some was marked */
+			if (run_top_route(event_rt.rlist[goto_on_branch_failure], &faked_req, 0)<0)
+				LOG(L_ERR, "ERROR: run_branch_failure_handlers: Error in run_top_route\n");
+			exec_post_script_cb(&faked_req, BRANCH_FAILURE_CB_TYPE);
+		}
+		/* update message flags, if changed in branch_failure route */
+		t->uas.request->flags = faked_req.flags;
+	}
+
+	/* restore original environment and free the fake msg */
+	faked_env( t, 0);
+	free_faked_req(&faked_req,t);
+
+	/* if branch_failure handler changed flag, update transaction context */
+	shmem_msg->flags = faked_req.flags;
+	return 1;
+}
+
+
 
 
 /* 401, 407, 415, 420, and 484 have priority over the other 4xx*/
 /* 401, 407, 415, 420, and 484 have priority over the other 4xx*/
 inline static short int get_4xx_prio(unsigned char xx)
 inline static short int get_4xx_prio(unsigned char xx)
@@ -1252,6 +1310,25 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
 
 
 		Trans->uac[branch].last_received=new_code;
 		Trans->uac[branch].last_received=new_code;
 
 
+/* New branch failure route code */
+		/* also append the current reply to the transaction to
+		 * make it available in failure routes - a kind of "fake"
+		 * save of the final reply per branch */
+		Trans->uac[branch].reply = reply;
+		if (unlikely(goto_on_branch_failure > 0 )) {
+			extra_flags=
+				((Trans->uac[branch].request.flags & F_RB_TIMEOUT)?
+							FL_TIMEOUT:0) | 
+				((Trans->uac[branch].request.flags & F_RB_REPLIED)?
+						 	FL_REPLIED:0);
+			tm_ctx_set_branch_index(branch);
+			picked_branch = branch;
+			run_branch_failure_handlers( Trans, Trans->uac[branch].reply,
+									new_code, extra_flags);
+		}
+/* END - New branch failure route code */
+
+
 		/* if all_final return lowest */
 		/* if all_final return lowest */
 		picked_branch=t_pick_branch(branch,new_code, Trans, &picked_code);
 		picked_branch=t_pick_branch(branch,new_code, Trans, &picked_code);
 		if (picked_branch==-2) { /* branches open yet */
 		if (picked_branch==-2) { /* branches open yet */
@@ -2530,6 +2607,58 @@ void t_drop_replies(int v)
 	drop_replies = v;
 	drop_replies = v;
 }
 }
 
 
+int t_get_this_branch_instance(struct sip_msg *msg, str *instance)
+{
+	struct cell *t;
+	if (!msg || !instance)
+	{
+		LM_ERR("Invalid params\n");
+		return -1;
+	}
+	if (get_route_type() != BRANCH_FAILURE_ROUTE)
+	{
+		LM_ERR("Called t_get_this_branch_instance not in a branch_failure_route\n");
+		return -1;
+	}
+
+	t = 0;
+	/* first get the transaction */
+	if (t_check(msg, 0 ) == -1) return -1;
+	if ((t = get_t()) == 0) {
+		LOG(L_ERR, "ERROR: t_check_status: cannot check status for a reply "
+			"which has no T-state established\n");
+		return -1;
+	}
+	*instance = t->uac[get_t_branch()].instance;
+	return 1;
+}
+
+int t_get_this_branch_ruid(struct sip_msg *msg, str *ruid)
+{
+	struct cell *t;
+	if (!msg || !ruid)
+	{
+		LM_ERR("Invalid params\n");
+		return -1;
+	}
+	if (get_route_type() != BRANCH_FAILURE_ROUTE)
+	{
+		LM_ERR("Called t_get_this_branch_ruid not in a branch_failure_route\n");
+		return -1;
+	}
+
+	t = 0;
+	/* first get the transaction */
+	if (t_check(msg, 0 ) == -1) return -1;
+	if ((t = get_t()) == 0) {
+		LOG(L_ERR, "ERROR: t_check_status: cannot check status for a reply "
+			"which has no T-state established\n");
+		return -1;
+	}
+	*ruid = t->uac[get_t_branch()].ruid;
+	return 1;
+}
+
 #if 0
 #if 0
 static int send_reply(struct cell *trans, unsigned int code, str* text, str* body, str* headers, str* to_tag)
 static int send_reply(struct cell *trans, unsigned int code, str* text, str* body, str* headers, str* to_tag)
 {
 {

+ 9 - 0
modules/tm/t_reply.h

@@ -61,6 +61,7 @@ enum rps {
 extern char tm_tags[TOTAG_VALUE_LEN];
 extern char tm_tags[TOTAG_VALUE_LEN];
 extern char *tm_tag_suffix;
 extern char *tm_tag_suffix;
 
 
+extern int goto_on_branch_failure;
 extern int goto_on_sl_reply;
 extern int goto_on_sl_reply;
 
 
 extern int failure_reply_mode;
 extern int failure_reply_mode;
@@ -161,6 +162,11 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
 					int code, int extra_flags);
 					int code, int extra_flags);
 typedef int (*run_failure_handlers_f)(struct cell*, struct sip_msg*, int, int);
 typedef int (*run_failure_handlers_f)(struct cell*, struct sip_msg*, int, int);
 
 
+/* return 1 if a branch_failure_route processes */
+int run_branch_failure_handlers(struct cell *t, struct sip_msg *rpl,
+					int code, int extra_flags);
+typedef int (*run_branch_failure_handlers_f)(struct cell*, struct sip_msg*, int, int);
+
 
 
 /* Retransmits the last sent inbound reply.
 /* Retransmits the last sent inbound reply.
  * Returns  -1 - error
  * Returns  -1 - error
@@ -237,4 +243,7 @@ void free_faked_req(struct sip_msg *faked_req, struct cell *t);
 typedef int (*tget_picked_f)(void);
 typedef int (*tget_picked_f)(void);
 int t_get_picked_branch(void);
 int t_get_picked_branch(void);
 
 
+int t_get_this_branch_instance(struct sip_msg *msg, str *instance);
+int t_get_this_branch_ruid(struct sip_msg *msg, str *ruid);
+
 #endif
 #endif

+ 85 - 189
modules/tm/t_serial.c

@@ -365,7 +365,7 @@ void add_contact_flows_avp(str *uri, str *dst_uri, str *path, str *sock_str,
  * Adds to request a new destination set that includes highest
  * Adds to request a new destination set that includes highest
  * priority class contacts in contacts_avp, but only one contact with same
  * priority class contacts in contacts_avp, but only one contact with same
  * +sip.instance value is included.  Others are added to contact_flows_avp
  * +sip.instance value is included.  Others are added to contact_flows_avp
- * for later consumption by next_contact_flows().
+ * for later consumption by next_contact_flow().
  * Request URI is rewritten with first contact and the remaining contacts
  * Request URI is rewritten with first contact and the remaining contacts
  * (if any) are added as branches. Removes all highest priority contacts
  * (if any) are added as branches. Removes all highest priority contacts
  * from contacts_avp.
  * from contacts_avp.
@@ -461,6 +461,7 @@ int t_next_contacts(struct sip_msg* msg, char* key, char* value)
 	il->instance.len = instance.len;
 	il->instance.len = instance.len;
 	memcpy(il->instance.s, instance.s, instance.len);
 	memcpy(il->instance.s, instance.s, instance.len);
 	il->next = (struct instance_list *)0;
 	il->next = (struct instance_list *)0;
+	set_instance(msg, &instance);
     }
     }
 
 
     vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
     vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
@@ -588,7 +589,12 @@ int t_next_contacts(struct sip_msg* msg, char* key, char* value)
         vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
         vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
         ruid = vavp->val.v.s;
         ruid = vavp->val.v.s;
 
 
-	if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, 0, 0,
+	LM_DBG("Appending branch uri-'%.*s' dst-'%.*s' path-'%.*s' inst-'%.*s'\n",
+		uri.len, uri.s,
+		dst_uri.len, dst_uri.s,
+		path.len, path.s,
+		instance.len, instance.s);
+	if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, &instance, 0,
 			  &ruid) != 1) {
 			  &ruid) != 1) {
 	    LM_ERR("appending branch failed\n");
 	    LM_ERR("appending branch failed\n");
 	    free_instance_list(il);
 	    free_instance_list(il);
@@ -622,15 +628,15 @@ int t_next_contacts(struct sip_msg* msg, char* key, char* value)
  * Returns 1, if contact_flows_avp was not empty and a destination set was
  * Returns 1, if contact_flows_avp was not empty and a destination set was
  * successfully added.  Returns -2, if contact_flows_avp was empty and thus
  * successfully added.  Returns -2, if contact_flows_avp was empty and thus
  * there was nothing to do. Returns -1 in case of an error. */
  * there was nothing to do. Returns -1 in case of an error. */
-int t_next_contact_flows(struct sip_msg* msg, char* key, char* value)
+int t_next_contact_flow(struct sip_msg* msg, char* key, char* value)
 {
 {
     str uri, dst_uri, path, instance, host, ruid;
     str uri, dst_uri, path, instance, host, ruid;
+	str this_instance;
     struct socket_info *sock;
     struct socket_info *sock;
     unsigned int flags;
     unsigned int flags;
     sr_xavp_t *xavp_list, *xavp, *next_xavp, *vavp;
     sr_xavp_t *xavp_list, *xavp, *next_xavp, *vavp;
     char *tmp;
     char *tmp;
     int port, proto;
     int port, proto;
-    struct instance_list *il, *ilp;
 
 
     /* Check if contact_flows_avp has been defined */
     /* Check if contact_flows_avp has been defined */
     if (contact_flows_avp.len == 0) {
     if (contact_flows_avp.len == 0) {
@@ -640,208 +646,98 @@ int t_next_contact_flows(struct sip_msg* msg, char* key, char* value)
     }
     }
 
 
     /* Load Request-URI and branches */
     /* Load Request-URI and branches */
+	t_get_this_branch_instance(msg, &this_instance);
 
 
-    /* Find first contact_flows_avp value */
-    xavp_list = xavp_get(&contact_flows_avp, NULL);
-    if (!xavp_list) {
-	LM_DBG("no contacts in contact_flows_avp - we are done!\n");
-	return -2;
-    }
-
-    xavp = xavp_list;
-    next_xavp = xavp_get_next(xavp);
-
-    vavp = xavp_get(&uri_name, xavp->val.v.xavp);
-    uri = vavp->val.v.s;
-
-    vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	dst_uri = vavp->val.v.s;
-    } else {
-	dst_uri.s = 0;
-	dst_uri.len = 0;
-    }
-
-    vavp = xavp_get(&path_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	path = vavp->val.v.s;
-    } else {
-	path.s = 0;
-	path.len = 0;
-    }
-
-    vavp = xavp_get(&sock_name, xavp->val.v.xavp);
-    if (vavp != NULL) {
-	tmp = vavp->val.v.s.s;
-	if (parse_phostport(tmp, &host.s, &host.len, &port, &proto) != 0) {
-	    LM_ERR("parsing of socket info <%s> failed\n", tmp);
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
+	if (this_instance.len == 0)
+	{
+		LM_DBG("No instance on this branch\n");
+		return -2;
 	}
 	}
-	sock = grep_sock_info(&host, (unsigned short)port,
-			      (unsigned short)proto);
-	if (sock == 0) {
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
+	/* Find first contact_flows_avp value */
+	xavp_list = xavp_get(&contact_flows_avp, NULL);
+	if (!xavp_list) {
+		LM_DBG("no contacts in contact_flows_avp - we are done!\n");
+		return -2;
 	}
 	}
-    } else {
-	sock = NULL;
-    }
 
 
-    vavp = xavp_get(&flags_name, xavp->val.v.xavp);
-    flags = vavp->val.v.i;
-
-    vavp = xavp_get(&instance_name, xavp->val.v.xavp);
-    il = (struct instance_list *)0;
-    if ((vavp != NULL) && next_xavp) {
-	instance = vavp->val.v.s;
-	il = (struct instance_list *)pkg_malloc(sizeof(struct instance_list));
-	if (!il) {
-	    LM_ERR("no memory for instance list entry\n");
-	    return -1;
-	}
-	il->instance.s = pkg_malloc(instance.len);
-	if (!il->instance.s) {
-	    pkg_free(il);
-	    LM_ERR("no memory for instance list instance\n");
-	    return -1;
-	}
-	il->instance.len = instance.len;
-	memcpy(il->instance.s, instance.s, instance.len);
-	il->next = (struct instance_list *)0;
-    }
-
-    vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
-    ruid = vavp->val.v.s;
-
-    /* Rewrite Request-URI */
-    rewrite_uri(msg, &uri);
-
-    if (dst_uri.len) {
-	set_dst_uri(msg, &dst_uri);
-    } else {
-	reset_dst_uri(msg);
-    }
-
-    if (path.len) {
-	set_path_vector(msg, &path);
-    } else {
-	reset_path_vector(msg);
-    }
-
-    set_force_socket(msg, sock);
-
-    set_ruid(msg, &ruid);
-
-    setbflagsval(0, flags);
+	xavp = xavp_list;
 
 
-    /* Append branches until out of branches. */
-    /* Do not include a branch that has same instance value as some */
-    /* previous branch. */
+	while (xavp) {
+		next_xavp = xavp_get_next(xavp);
 
 
-    xavp_rm(xavp, NULL);
-    xavp = next_xavp;
-
-    while (xavp) {
-	
-	next_xavp = xavp_get_next(xavp);
-
-	vavp = xavp_get(&instance_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    instance = vavp->val.v.s;
-	    ilp = il;
-	    while (ilp) {
-		if ((instance.len == ilp->instance.len) &&
-		    (strncmp(instance.s, ilp->instance.s, instance.len) == 0))
-		    break;
-		ilp = ilp->next;
-	    }
-	    if (ilp) {
-		/* skip already appended instance */
-		xavp = next_xavp;
-		continue;
-	    }
-	    if (next_xavp) {
-		ilp = (struct instance_list *)
-		pkg_malloc(sizeof(struct instance_list));
-		if (!ilp) {
-		    LM_ERR("no memory for new instance list entry\n");
-		    free_instance_list(il);
-		    return -1;
+	   	vavp = xavp_get(&instance_name, xavp->val.v.xavp);
+		if (vavp == NULL)
+		{
+			/* Does not match this instance */
+			goto next_xavp;
 		}
 		}
-		ilp->instance.s = pkg_malloc(instance.len);
-		if (!ilp->instance.s) {
-		    pkg_free(il);
-		    LM_ERR("no memory for instance list instance\n");
-		    return -1;
+		else
+		{
+			instance = vavp->val.v.s;
+			if ((instance.len != this_instance.len) ||
+			    (strncmp(instance.s, this_instance.s, instance.len) != 0))
+				/* Does not match this instance */
+				goto next_xavp;
 		}
 		}
-		ilp->instance.len = instance.len;
-		memcpy(ilp->instance.s, instance.s, instance.len);
-		ilp->next = il;
-		il = ilp;
-	    } else {
-		LM_ERR("instance missing from contact_flow_avp contact\n");
-		free_instance_list(il);
-		return -1;
-	    }
-	}
 
 
-	vavp = xavp_get(&uri_name, xavp->val.v.xavp);
-	uri = vavp->val.v.s;
+		vavp = xavp_get(&uri_name, xavp->val.v.xavp);
+		uri = vavp->val.v.s;
 
 
-	vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    dst_uri = vavp->val.v.s;
-	} else {
-	    dst_uri.len = 0;
-	}
+		vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			dst_uri = vavp->val.v.s;
+		} else {
+			dst_uri.len = 0;
+		}
 
 
-	vavp = xavp_get(&path_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    path = vavp->val.v.s;
-	} else {
-	    path.len = 0;
-	}
+		vavp = xavp_get(&path_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			path = vavp->val.v.s;
+		} else {
+			path.len = 0;
+		}
 
 
-	vavp = xavp_get(&sock_name, xavp->val.v.xavp);
-	if (vavp != NULL) {
-	    tmp = vavp->val.v.s.s;
-	    if (parse_phostport(tmp, &host.s, &host.len, &port, &proto) != 0) {
-		LM_ERR("parsing of socket info <%s> failed\n", tmp);
-		free_instance_list(il);
-		xavp_destroy_list(&xavp_list);
-		return -1;
-	    }
-	    sock = grep_sock_info(&host, (unsigned short)port,
+		vavp = xavp_get(&sock_name, xavp->val.v.xavp);
+		if (vavp != NULL) {
+			tmp = vavp->val.v.s.s;
+			if (parse_phostport(tmp, &host.s, &host.len, &port, &proto) != 0) {
+				LM_ERR("parsing of socket info <%s> failed\n", tmp);
+				xavp_rm(xavp, NULL);
+				return -1;
+			}
+			sock = grep_sock_info(&host, (unsigned short)port,
 				  (unsigned short)proto);
 				  (unsigned short)proto);
-	    if (sock == 0) {
-		free_instance_list(il);
-		xavp_destroy_list(&xavp_list);
-		return -1;
-	    }
-	} else {
-	    sock = NULL;
-	}
+			if (sock == 0) {
+				xavp_rm(xavp, NULL);
+				return -1;
+			}
+		} else {
+			sock = NULL;
+		}
 
 
-	vavp = xavp_get(&flags_name, xavp->val.v.xavp);
-	flags = vavp->val.v.i;
+		vavp = xavp_get(&flags_name, xavp->val.v.xavp);
+		flags = vavp->val.v.i;
 
 
-        vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
-        ruid = vavp->val.v.s;
+		vavp = xavp_get(&ruid_name, xavp->val.v.xavp);
+		ruid = vavp->val.v.s;
 
 
-	if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, 0, 0,
+		LM_DBG("Appending branch uri-'%.*s' dst-'%.*s' path-'%.*s' inst-'%.*s'\n",
+			uri.len, uri.s,
+			dst_uri.len, dst_uri.s,
+			path.len, path.s,
+			instance.len, instance.s);
+		if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, &instance, 0,
 			  &ruid) != 1) {
 			  &ruid) != 1) {
-	    LM_ERR("appending branch failed\n");
-	    free_instance_list(il);
-	    xavp_destroy_list(&xavp_list);
-	    return -1;
-	}
-
-	xavp_rm(xavp, NULL);
-	xavp = next_xavp;
-    }
+			LM_ERR("appending branch failed\n");
+			xavp_destroy_list(&xavp_list);
+			return -1;
+		}
 
 
-    free_instance_list(il);
+		xavp_rm(xavp, NULL);
+		return 1;
+next_xavp:
+		xavp = next_xavp;
+	}
 
 
-    return 1;
+	return -1;
 }
 }

+ 1 - 1
modules/tm/t_serial.h

@@ -34,4 +34,4 @@ int t_load_contacts(struct sip_msg* msg, char* key, char* value);
 
 
 int t_next_contacts(struct sip_msg* msg, char* key, char* value);
 int t_next_contacts(struct sip_msg* msg, char* key, char* value);
 
 
-int t_next_contact_flows(struct sip_msg* msg, char* key, char* value);
+int t_next_contact_flow(struct sip_msg* msg, char* key, char* value);

+ 12 - 8
modules/tm/tm.c

@@ -414,7 +414,7 @@ static cmd_export_t cmds[]={
 	{"t_on_branch",       w_t_on_branch,         1, fixup_on_branch,
 	{"t_on_branch",       w_t_on_branch,         1, fixup_on_branch,
 			REQUEST_ROUTE | FAILURE_ROUTE },
 			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"t_check_status",     t_check_status,          1, fixup_t_check_status,
 	{"t_check_status",     t_check_status,          1, fixup_t_check_status,
-			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_FAILURE_ROUTE},
 	{"t_write_req",       t_write_req,              2, fixup_t_write,
 	{"t_write_req",       t_write_req,              2, fixup_t_write,
 			REQUEST_ROUTE | FAILURE_ROUTE },
 			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"t_write_unix",      t_write_unix,             2, fixup_t_write,
 	{"t_write_unix",      t_write_unix,             2, fixup_t_write,
@@ -475,8 +475,8 @@ static cmd_export_t cmds[]={
 			REQUEST_ROUTE | FAILURE_ROUTE},
 			REQUEST_ROUTE | FAILURE_ROUTE},
 	{"t_next_contacts", t_next_contacts,            0, 0,
 	{"t_next_contacts", t_next_contacts,            0, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE},
 			REQUEST_ROUTE | FAILURE_ROUTE},
-	{"t_next_contact_flows", t_next_contact_flows,            0, 0,
-			REQUEST_ROUTE | FAILURE_ROUTE},
+	{"t_next_contact_flow", t_next_contact_flow,            0, 0,
+			REQUEST_ROUTE | BRANCH_FAILURE_ROUTE},
 
 
 	/* not applicable from the script */
 	/* not applicable from the script */
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,   0, 0},
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,   0, 0},
@@ -601,7 +601,6 @@ static int fixup_on_failure(void** param, int param_no)
 }
 }
 
 
 
 
-
 static int fixup_on_reply(void** param, int param_no)
 static int fixup_on_reply(void** param, int param_no)
 {
 {
 	if (param_no==1){
 	if (param_no==1){
@@ -855,6 +854,9 @@ static int mod_init(void)
 	    return -1;
 	    return -1;
 	}
 	}
 
 
+	goto_on_branch_failure = route_lookup(&event_rt, "tm:branch-failure");
+	if (goto_on_branch_failure >= 0 && event_rt.rlist[goto_on_branch_failure]==0)
+		goto_on_branch_failure = -1; /* disable */
 #ifdef WITH_EVENT_LOCAL_REQUEST
 #ifdef WITH_EVENT_LOCAL_REQUEST
 	goto_on_local_req=route_lookup(&event_rt, "tm:local-request");
 	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)
 	if (goto_on_local_req>=0 && event_rt.rlist[goto_on_local_req]==0)
@@ -894,8 +896,6 @@ static int child_init(int rank)
 
 
 
 
 
 
-
-
 /**************************** wrapper functions ***************************/
 /**************************** wrapper functions ***************************/
 static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
 static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
 {
 {
@@ -979,7 +979,10 @@ static int t_check_status(struct sip_msg* msg, char *p1, char *foo)
 		}
 		}
 		status = int2str( lowest_status , 0);
 		status = int2str( lowest_status , 0);
 		break;
 		break;
-
+	case BRANCH_FAILURE_ROUTE:
+#warning add the status for branch failure route
+		status = int2str(t->uac[get_t_branch()].last_received, 0);
+		break;
 	default:
 	default:
 		LOG(L_ERR,"ERROR:t_check_status: unsupported route type %d\n",
 		LOG(L_ERR,"ERROR:t_check_status: unsupported route type %d\n",
 				get_route_type());
 				get_route_type());
@@ -1368,6 +1371,7 @@ inline static int w_t_on_failure( struct sip_msg* msg, char *go_to, char *foo)
 	return 1;
 	return 1;
 }
 }
 
 
+
 inline static int w_t_on_branch( struct sip_msg* msg, char *go_to, char *foo)
 inline static int w_t_on_branch( struct sip_msg* msg, char *go_to, char *foo)
 {
 {
 	t_on_branch( (unsigned int )(long) go_to );
 	t_on_branch( (unsigned int )(long) go_to );
@@ -1438,7 +1442,7 @@ inline static int _w_t_relay_to(struct sip_msg  *p_msg ,
 	struct cell *t;
 	struct cell *t;
 	int res;
 	int res;
 
 
-	if (is_route_type(FAILURE_ROUTE)) {
+	if (is_route_type(FAILURE_ROUTE|BRANCH_FAILURE_ROUTE)) {
 		t=get_t();
 		t=get_t();
 		if (!t || t==T_UNDEFINED) {
 		if (!t || t==T_UNDEFINED) {
 			LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
 			LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");

+ 1 - 0
modules/tm/tm_load.c

@@ -110,6 +110,7 @@ int load_tm( struct tm_binds *tmb)
 	tmb->t_uac_with_ids = t_uac_with_ids;
 	tmb->t_uac_with_ids = t_uac_with_ids;
 	tmb->t_unref = t_unref;
 	tmb->t_unref = t_unref;
 	tmb->run_failure_handlers = run_failure_handlers;
 	tmb->run_failure_handlers = run_failure_handlers;
+	tmb->run_branch_failure_handlers = run_branch_failure_handlers;
 	tmb->cancel_uacs = cancel_uacs;
 	tmb->cancel_uacs = cancel_uacs;
 	tmb->cancel_all_uacs = cancel_all_uacs;
 	tmb->cancel_all_uacs = cancel_all_uacs;
 	tmb->prepare_request_within = prepare_req_within;
 	tmb->prepare_request_within = prepare_req_within;

+ 1 - 0
modules/tm/tm_load.h

@@ -88,6 +88,7 @@ struct tm_binds {
 	trelease_f         t_release;
 	trelease_f         t_release;
 	tunref_f           t_unref;
 	tunref_f           t_unref;
 	run_failure_handlers_f run_failure_handlers;
 	run_failure_handlers_f run_failure_handlers;
+	run_branch_failure_handlers_f run_branch_failure_handlers;
 	cancel_uacs_f      cancel_uacs;
 	cancel_uacs_f      cancel_uacs;
 	cancel_all_uacs_f  cancel_all_uacs;
 	cancel_all_uacs_f  cancel_all_uacs;
 	prepare_request_within_f  prepare_request_within;
 	prepare_request_within_f  prepare_request_within;

+ 72 - 69
modules/tmx/README

@@ -1,3 +1,4 @@
+
 TMX Module
 TMX Module
 
 
 Daniel-Constantin Mierla
 Daniel-Constantin Mierla
@@ -11,8 +12,8 @@ Daniel-Constantin Mierla
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2009 Daniel-Constantin Mierla
-     __________________________________________________________________
+   Copyright © 2009 Daniel-Constantin Mierla
+     _________________________________________________________________
 
 
    Table of Contents
    Table of Contents
 
 
@@ -26,24 +27,24 @@ Daniel-Constantin Mierla
 
 
         3. Functions
         3. Functions
 
 
-              3.1. t_cancel_branches(which)
-              3.2. t_cancel_callid(callid, cseq, flag)
-              3.3. t_reply_callid(callid, cseq, code, reason)
-              3.4. t_flush_flags()
-              3.5. t_is_failure_route()
-              3.6. t_is_branch_route()
-              3.7. t_is_reply_route()
-              3.8. t_suspend()
-              3.9. t_continue(tindex, tlabel, rtname)
+              3.1. t_cancel_branches(which) 
+              3.2. t_cancel_callid(callid, cseq, flag) 
+              3.3. t_reply_callid(callid, cseq, code, reason) 
+              3.4. t_flush_flags() 
+              3.5. t_is_failure_route() 
+              3.6. t_is_branch_route() 
+              3.7. t_is_reply_route() 
+              3.8. t_suspend() 
+              3.9. t_continue(tindex, tlabel, rtname) 
 
 
         4. Exported pseudo-variables
         4. Exported pseudo-variables
         5. MI Commands
         5. MI Commands
 
 
-              5.1. t_uac_dlg
-              5.2. t_uac_cancel
-              5.3. t_hash
-              5.4. t_reply
-              5.5. t_reply_callid
+              5.1. t_uac_dlg 
+              5.2. t_uac_cancel 
+              5.3. t_hash 
+              5.4. t_reply 
+              5.5. t_reply_callid 
 
 
         6. Statistics
         6. Statistics
 
 
@@ -83,24 +84,24 @@ Chapter 1. Admin Guide
 
 
    3. Functions
    3. Functions
 
 
-        3.1. t_cancel_branches(which)
-        3.2. t_cancel_callid(callid, cseq, flag)
-        3.3. t_reply_callid(callid, cseq, code, reason)
-        3.4. t_flush_flags()
-        3.5. t_is_failure_route()
-        3.6. t_is_branch_route()
-        3.7. t_is_reply_route()
-        3.8. t_suspend()
-        3.9. t_continue(tindex, tlabel, rtname)
+        3.1. t_cancel_branches(which) 
+        3.2. t_cancel_callid(callid, cseq, flag) 
+        3.3. t_reply_callid(callid, cseq, code, reason) 
+        3.4. t_flush_flags() 
+        3.5. t_is_failure_route() 
+        3.6. t_is_branch_route() 
+        3.7. t_is_reply_route() 
+        3.8. t_suspend() 
+        3.9. t_continue(tindex, tlabel, rtname) 
 
 
    4. Exported pseudo-variables
    4. Exported pseudo-variables
    5. MI Commands
    5. MI Commands
 
 
-        5.1. t_uac_dlg
-        5.2. t_uac_cancel
-        5.3. t_hash
-        5.4. t_reply
-        5.5. t_reply_callid
+        5.1. t_uac_dlg 
+        5.2. t_uac_cancel 
+        5.3. t_hash 
+        5.4. t_reply 
+        5.5. t_reply_callid 
 
 
    6. Statistics
    6. Statistics
 
 
@@ -135,25 +136,25 @@ Chapter 1. Admin Guide
 
 
 2.2. External Libraries or Applications
 2.2. External Libraries or Applications
 
 
-   The following libraries or applications must be installed before
+   The  following  libraries  or  applications  must  be installed before
    running Kamailio with this module loaded:
    running Kamailio with this module loaded:
      * None.
      * None.
 
 
 3. Functions
 3. Functions
 
 
-   3.1. t_cancel_branches(which)
-   3.2. t_cancel_callid(callid, cseq, flag)
-   3.3. t_reply_callid(callid, cseq, code, reason)
-   3.4. t_flush_flags()
-   3.5. t_is_failure_route()
-   3.6. t_is_branch_route()
-   3.7. t_is_reply_route()
-   3.8. t_suspend()
-   3.9. t_continue(tindex, tlabel, rtname)
+   3.1. t_cancel_branches(which) 
+   3.2. t_cancel_callid(callid, cseq, flag) 
+   3.3. t_reply_callid(callid, cseq, code, reason) 
+   3.4. t_flush_flags() 
+   3.5. t_is_failure_route() 
+   3.6. t_is_branch_route() 
+   3.7. t_is_reply_route() 
+   3.8. t_suspend() 
+   3.9. t_continue(tindex, tlabel, rtname) 
 
 
 3.1.  t_cancel_branches(which)
 3.1.  t_cancel_branches(which)
 
 
-   Cancel branches of an active SIP transaction. The function can be
+   Cancel  branches  of  an  active  SIP transaction. The function can be
    called for a SIP reply that will identify the current branch.
    called for a SIP reply that will identify the current branch.
 
 
    Parameter can be:.
    Parameter can be:.
@@ -210,9 +211,9 @@ if (t_reply_callid("123qaz", "5", "458", "Replied remotely")) {
 
 
 3.4.  t_flush_flags()
 3.4.  t_flush_flags()
 
 
-   Flush the flags from current SIP message into the already created
-   transaction. It make sense only in routing block if the transaction was
-   created via t_newtran() and the flags have been altered since.
+   Flush  the  flags  from  current  SIP message into the already created
+   transaction.  It  make  sense only in routing block if the transaction
+   was created via t_newtran() and the flags have been altered since.
 
 
    This function can be used from ANY_ROUTE .
    This function can be used from ANY_ROUTE .
 
 
@@ -274,8 +275,8 @@ route[abc] {
 
 
 3.8.  t_suspend()
 3.8.  t_suspend()
 
 
-   Suspend the execution of SIP request in a transaction. If transaction
-   was not created yet, it is created by this function. Returns true in
+   Suspend  the execution of SIP request in a transaction. If transaction
+   was  not  created yet, it is created by this function. Returns true in
    case of success and internal transaction index and label are available
    case of success and internal transaction index and label are available
    via $T(id_index) and $T(id_label).
    via $T(id_index) and $T(id_label).
 
 
@@ -292,15 +293,15 @@ if(t_suspend())
 
 
 3.9.  t_continue(tindex, tlabel, rtname)
 3.9.  t_continue(tindex, tlabel, rtname)
 
 
-   Continue the execution of the transaction identified by tindex and
+   Continue  the  execution  of  the transaction identified by tindex and
    tlabel with the actions defined in route[rtname].
    tlabel with the actions defined in route[rtname].
 
 
    Parameters:.
    Parameters:.
-     * tindex - internal index of transaction. Can be an integer or a
+     * tindex  -  internal  index  of transaction. Can be an integer or a
        pseudo-variable.
        pseudo-variable.
-     * tlabel - internal label of transaction. Can be an integer or a
+     * tlabel  -  internal  label  of transaction. Can be an integer or a
        pseudo-variable.
        pseudo-variable.
-     * rtname - the name of the route block to execute. Can be a static
+     * rtname  -  the name of the route block to execute. Can be a static
        string value or a dynamic string with pseudo-variables.
        string value or a dynamic string with pseudo-variables.
 
 
    This function can be used in ANY_ROUTE.
    This function can be used in ANY_ROUTE.
@@ -318,17 +319,18 @@ tcontinue('123', '456', 'MYROUTE');
      * $T_reply_last
      * $T_reply_last
      * $T_req(pv)
      * $T_req(pv)
      * $T_rpl(pv)
      * $T_rpl(pv)
+     * $T_reply_ruid
 
 
    Exported pseudo-variables are documented at
    Exported pseudo-variables are documented at
    http://www.kamailio.org/dokuwiki/.
    http://www.kamailio.org/dokuwiki/.
 
 
 5. MI Commands
 5. MI Commands
 
 
-   5.1. t_uac_dlg
-   5.2. t_uac_cancel
-   5.3. t_hash
-   5.4. t_reply
-   5.5. t_reply_callid
+   5.1. t_uac_dlg 
+   5.2. t_uac_cancel 
+   5.3. t_hash 
+   5.4. t_reply 
+   5.5. t_reply_callid 
 
 
 5.1.  t_uac_dlg
 5.1.  t_uac_dlg
 
 
@@ -337,13 +339,13 @@ tcontinue('123', '456', 'MYROUTE');
    Parameters:
    Parameters:
      * method - request method
      * method - request method
      * RURI - request SIP URI
      * RURI - request SIP URI
-     * NEXT HOP - next hop SIP URI (OBP); use “.� if no value.
-     * socket - local socket to be used for sending the request; use “.�
+     * NEXT HOP - next hop SIP URI (OBP); use "." if no value.
+     * socket  - local socket to be used for sending the request; use "."
        if no value.
        if no value.
      * headers - set of additional headers to be added to the request; at
      * headers - set of additional headers to be added to the request; at
-       least “From� and “To� headers must be specify)
-     * body - (optional, may not be present) request body (if present,
-       requires the “Content-Type� and “Content-length� headers)
+       least "From" and "To" headers must be specify)
+     * body  -  (optional,  may not be present) request body (if present,
+       requires the "Content-Type" and "Content-length" headers)
 
 
 5.2.  t_uac_cancel
 5.2.  t_uac_cancel
 
 
@@ -367,12 +369,13 @@ tcontinue('123', '456', 'MYROUTE');
    Parameters:
    Parameters:
      * code - reply code
      * code - reply code
      * reason - reason phrase.
      * reason - reason phrase.
-     * trans_id - transaction identifier (has the hash_entry:label format)
+     * trans_id   -  transaction  identifier  (has  the  hash_entry:label
+       format)
      * to_tag - To tag to be added to TO header
      * to_tag - To tag to be added to TO header
      * new_headers - extra headers to be appended to the reply; use a dot
      * new_headers - extra headers to be appended to the reply; use a dot
-       (“.�) char only if there are no headers;
-     * body - (optional, may not be present) reply body (if present,
-       requires the “Content-Type� and “Content-length� headers)
+       (".") char only if there are no headers;
+     * body  -  (optional,  may  not  be present) reply body (if present,
+       requires the "Content-Type" and "Content-length" headers)
 
 
 5.5.  t_reply_callid
 5.5.  t_reply_callid
 
 
@@ -385,9 +388,9 @@ tcontinue('123', '456', 'MYROUTE');
      * cseq - SIP CSeq header
      * cseq - SIP CSeq header
      * to_tag - To tag to be added to TO header
      * to_tag - To tag to be added to TO header
      * new_headers - extra headers to be appended to the reply; use a dot
      * new_headers - extra headers to be appended to the reply; use a dot
-       (“.�) char only if there are no headers;
-     * body - (optional, may not be present) reply body (if present,
-       requires the “Content-Type� and “Content-length� headers)
+       (".") char only if there are no headers;
+     * body  -  (optional,  may  not  be present) reply body (if present,
+       requires the "Content-Type" and "Content-length" headers)
 
 
 6. Statistics
 6. Statistics
 
 
@@ -403,8 +406,8 @@ tcontinue('123', '456', 'MYROUTE');
    6.10. 6xx_transactions
    6.10. 6xx_transactions
    6.11. inuse_transactions
    6.11. inuse_transactions
 
 
-   Exported statistics are listed in the next sections. All statistics
-   except “inuse_transactions� can be reset.
+   Exported  statistics  are  listed in the next sections. All statistics
+   except "inuse_transactions" can be reset.
 
 
 6.1. received_replies
 6.1. received_replies
 
 

+ 3 - 0
modules/tmx/doc/tmx_admin.xml

@@ -355,6 +355,9 @@ tcontinue('123', '456', 'MYROUTE');
 			<listitem><para>
 			<listitem><para>
 				<emphasis>$T_rpl(pv)</emphasis>
 				<emphasis>$T_rpl(pv)</emphasis>
 			</para></listitem>
 			</para></listitem>
+			<listitem><para>
+				<emphasis>$T_reply_ruid</emphasis>
+			</para></listitem>
 		</itemizedlist>
 		</itemizedlist>
 		<para>
 		<para>
 		Exported pseudo-variables are documented at &kamwikilink;.
 		Exported pseudo-variables are documented at &kamwikilink;.

+ 37 - 0
modules/tmx/t_var.c

@@ -417,6 +417,42 @@ int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param,
 	return 0;
 	return 0;
 }
 }
 
 
+int pv_get_tm_reply_ruid(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	struct cell *t;
+	int branch;
+
+	if(msg==NULL || res==NULL)
+		return -1;
+
+	/* first get the transaction */
+	if (_tmx_tmb.t_check( msg , 0 )==-1) return -1;
+	if ( (t=_tmx_tmb.t_gett())==0) {
+		/* no T */
+		res->rs = _empty_str;
+	} else {
+		switch (get_route_type()) {
+			case FAILURE_ROUTE:
+			case BRANCH_FAILURE_ROUTE:
+				/* use the reason of the winning reply */
+				if ( (branch=_tmx_tmb.t_get_picked_branch())<0 ) {
+					LM_CRIT("no picked branch (%d) for a final response"
+							" in MODE_ONFAILURE\n", branch);
+					return -1;
+				}
+				res->rs = t->uac[branch].ruid;
+				break;
+			default:
+				LM_ERR("unsupported route_type %d\n", get_route_type());
+				return -1;
+		}
+	}
+	LM_DBG("reply ruid is [%.*s]\n", res->rs.len, res->rs.s);
+	res->flags = PV_VAL_STR;
+	return 0;
+}
+
 int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
 int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 		pv_value_t *res)
 {
 {
@@ -449,6 +485,7 @@ int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
 				code = msg->first_line.u.reply.statuscode;
 				code = msg->first_line.u.reply.statuscode;
 				break;
 				break;
 			case FAILURE_ROUTE:
 			case FAILURE_ROUTE:
+			case BRANCH_FAILURE_ROUTE:
 				/* use the status of the winning reply */
 				/* use the status of the winning reply */
 				if ( (branch=_tmx_tmb.t_get_picked_branch())<0 ) {
 				if ( (branch=_tmx_tmb.t_get_picked_branch())<0 ) {
 					LM_CRIT("no picked branch (%d) for a final response"
 					LM_CRIT("no picked branch (%d) for a final response"

+ 2 - 0
modules/tmx/t_var.h

@@ -38,6 +38,8 @@ int pv_parse_t_var_name(pv_spec_p sp, str *in);
 
 
 int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param,
 int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 		pv_value_t *res);
+int pv_get_tm_reply_ruid(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
 int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
 int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 		pv_value_t *res);
 int pv_get_tm_reply_reason(struct sip_msg *msg, pv_param_t *param,
 int pv_get_tm_reply_reason(struct sip_msg *msg, pv_param_t *param,

+ 3 - 0
modules/tmx/tmx_mod.c

@@ -123,6 +123,9 @@ static pv_export_t mod_pvs[] = {
 	{ {"T_branch_idx", sizeof("T_branch_idx")-1}, PVT_OTHER,
 	{ {"T_branch_idx", sizeof("T_branch_idx")-1}, PVT_OTHER,
 		pv_get_tm_branch_idx, 0,
 		pv_get_tm_branch_idx, 0,
 		 0, 0, 0, 0 },
 		 0, 0, 0, 0 },
+	{ {"T_reply_ruid", sizeof("T_reply_ruid")-1}, PVT_OTHER,
+		pv_get_tm_reply_ruid, 0,
+		 0, 0, 0, 0 },
 	{ {"T_reply_code", sizeof("T_reply_code")-1}, PVT_OTHER,
 	{ {"T_reply_code", sizeof("T_reply_code")-1}, PVT_OTHER,
 		pv_get_tm_reply_code, 0,
 		pv_get_tm_reply_code, 0,
 		 0, 0, 0, 0 },
 		 0, 0, 0, 0 },

+ 4 - 2
modules/usrloc/udomain.c

@@ -648,7 +648,7 @@ urecord_t* db_load_urecord_by_ruid(db1_con_t* _c, udomain_t* _d, str *_ruid)
 	db_row_t *row;
 	db_row_t *row;
 	str contact;
 	str contact;
 	str aor;
 	str aor;
-	char aorbuf[512];
+	static char aorbuf[512];
 	str domain;
 	str domain;
 
 
 	urecord_t* r;
 	urecord_t* r;
@@ -1031,7 +1031,7 @@ int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
  * \param _ruid record internal unique id
  * \param _ruid record internal unique id
  * \param _r store pointer to location record
  * \param _r store pointer to location record
  * \param _c store pointer to contact structure
  * \param _c store pointer to contact structure
- * \return 0 if a record was found, 1 if nothing could be found
+ * \return 0 if a record was found, -1 if nothing could be found
  */
  */
 int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
 int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
 		str *_ruid, struct urecord** _r, struct ucontact** _c)
 		str *_ruid, struct urecord** _r, struct ucontact** _c)
@@ -1057,6 +1057,7 @@ int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
 						*_c = c;
 						*_c = c;
 						return 0;
 						return 0;
 					}
 					}
+					c = c->next;
 				}
 				}
 			}
 			}
 			r = r->next;
 			r = r->next;
@@ -1074,6 +1075,7 @@ int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
 						*_c = c;
 						*_c = c;
 						return 0;
 						return 0;
 					}
 					}
+					c = c->next;
 				}
 				}
 			}
 			}
 		}
 		}

+ 3 - 3
modules/xprint/xp_lib.c

@@ -700,7 +700,7 @@ static int xl_get_branch(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
 
 
 
 
 	init_branch_iterator();
 	init_branch_iterator();
-	branch.s = next_branch(&branch.len, &q, 0, 0, 0, 0, 0);
+	branch.s = next_branch(&branch.len, &q, 0, 0, 0, 0, 0, 0);
 	if (!branch.s) {
 	if (!branch.s) {
 		return xl_get_null(msg, res, hp, hi, hf);
 		return xl_get_null(msg, res, hp, hi, hf);
 	}
 	}
@@ -731,7 +731,7 @@ static int xl_get_branches(struct sip_msg *msg, str *res, str *hp, int hi, int h
 	cnt = len = 0;
 	cnt = len = 0;
 
 
 	init_branch_iterator();
 	init_branch_iterator();
-	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0)))
+	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0)))
 	{
 	{
 		cnt++;
 		cnt++;
 		len += uri.len;
 		len += uri.len;
@@ -756,7 +756,7 @@ static int xl_get_branches(struct sip_msg *msg, str *res, str *hp, int hi, int h
 	p = local_buf;
 	p = local_buf;
 
 
 	init_branch_iterator();
 	init_branch_iterator();
-	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0)))
+	while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0)))
 	{
 	{
 		if (i)
 		if (i)
 		{
 		{

+ 1 - 0
route.h

@@ -53,6 +53,7 @@
 #define ERROR_ROUTE   (1 << 5)
 #define ERROR_ROUTE   (1 << 5)
 #define LOCAL_ROUTE   (1 << 6)
 #define LOCAL_ROUTE   (1 << 6)
 #define CORE_ONREPLY_ROUTE (1 << 7)
 #define CORE_ONREPLY_ROUTE (1 << 7)
+#define BRANCH_FAILURE_ROUTE (1 << 8)
 #define ONREPLY_ROUTE (TM_ONREPLY_ROUTE|CORE_ONREPLY_ROUTE)
 #define ONREPLY_ROUTE (TM_ONREPLY_ROUTE|CORE_ONREPLY_ROUTE)
 #define EVENT_ROUTE   REQUEST_ROUTE
 #define EVENT_ROUTE   REQUEST_ROUTE
 #define ANY_ROUTE     (0xFFFFFFFF)
 #define ANY_ROUTE     (0xFFFFFFFF)

+ 1 - 1
script_cb.c

@@ -53,7 +53,7 @@
 #include "mem/mem.h"
 #include "mem/mem.h"
 
 
 /* Number of cb types = last cb type */
 /* Number of cb types = last cb type */
-#define SCRIPT_CB_NUM	EVENT_CB_TYPE
+#define SCRIPT_CB_NUM	(MAX_CB_TYPE-1)
 
 
 static struct script_cb *pre_script_cb[SCRIPT_CB_NUM];
 static struct script_cb *pre_script_cb[SCRIPT_CB_NUM];
 static struct script_cb *post_script_cb[SCRIPT_CB_NUM];
 static struct script_cb *post_script_cb[SCRIPT_CB_NUM];

+ 2 - 2
script_cb.h

@@ -49,14 +49,14 @@ typedef int (cb_function)(struct sip_msg *msg, unsigned int flags, void *param);
  */
  */
 enum script_cb_flag { REQUEST_CB=1, FAILURE_CB=2, ONREPLY_CB=4,
 enum script_cb_flag { REQUEST_CB=1, FAILURE_CB=2, ONREPLY_CB=4,
 			BRANCH_CB=8, ONSEND_CB=16, ERROR_CB=32,
 			BRANCH_CB=8, ONSEND_CB=16, ERROR_CB=32,
-			LOCAL_CB=64, EVENT_CB=128 };
+			LOCAL_CB=64, EVENT_CB=128, BRANCH_FAILURE_CB=256 };
 
 
 /* Callback types used for executing the callbacks.
 /* Callback types used for executing the callbacks.
  * Keep in sync with script_cb_flag!!!
  * Keep in sync with script_cb_flag!!!
  */
  */
 enum script_cb_type { REQUEST_CB_TYPE=1, FAILURE_CB_TYPE, ONREPLY_CB_TYPE,
 enum script_cb_type { REQUEST_CB_TYPE=1, FAILURE_CB_TYPE, ONREPLY_CB_TYPE,
 			BRANCH_CB_TYPE, ONSEND_CB_TYPE, ERROR_CB_TYPE,
 			BRANCH_CB_TYPE, ONSEND_CB_TYPE, ERROR_CB_TYPE,
-			LOCAL_CB_TYPE, EVENT_CB_TYPE };
+			LOCAL_CB_TYPE, EVENT_CB_TYPE, BRANCH_FAILURE_CB_TYPE, MAX_CB_TYPE };
 
 
 struct script_cb{
 struct script_cb{
 	cb_function *cbf;
 	cb_function *cbf;

+ 3 - 3
select_core.c

@@ -1621,7 +1621,7 @@ int select_branch_uri(str* res, select_t* s, struct sip_msg* msg) {
 		char *c;
 		char *c;
 		init_branch_iterator();
 		init_branch_iterator();
 		len = 0;
 		len = 0;
-		while ((c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0))) {
+		while ((c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0, 0))) {
 
 
 			if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
 			if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
 				l = dst_uri.len;
 				l = dst_uri.len;
@@ -1645,7 +1645,7 @@ int select_branch_uri(str* res, select_t* s, struct sip_msg* msg) {
 		init_branch_iterator();
 		init_branch_iterator();
 		res->len = 0;
 		res->len = 0;
 		n = 0;
 		n = 0;
-		while ((c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0))) {
+		while ((c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0, 0))) {
 			if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
 			if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
 				l = dst_uri.len;
 				l = dst_uri.len;
 				c = dst_uri.s;
 				c = dst_uri.s;
@@ -1687,7 +1687,7 @@ int select_branch_uri(str* res, select_t* s, struct sip_msg* msg) {
 		if (n < 0 || n >= nr_branches) 
 		if (n < 0 || n >= nr_branches) 
 			return -1;
 			return -1;
 		init_branch_iterator();
 		init_branch_iterator();
-		for (; (c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0)) && n; n--);
+		for (; (c = next_branch(&l, &q, &dst_uri, 0, 0, 0, 0, 0)) && n; n--);
 		if (!c) return 1;
 		if (!c) return 1;
 		
 		
 		if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {
 		if (s->params[SEL_POS].v.i & SEL_BRANCH_DST_URI) {