Esempio n. 1
0
int dup_reg_avps(struct ucontact *dst, struct ucontact *src)
{
	struct usr_avp *avp, *dup;
	avp_t *first, *last;
	
	/* no locking here! TODO: do it in package memory !!! */

	if (!use_reg_avps()) return 0; /* don't use reg avps */
	
	/* destroy old AVPs */
	/* if (dst->avps) db_delete_reg_avps(dst); */
	destroy_avps(dst->avps);

	last = NULL;
	first = NULL;
	
	avp = src->avps;
	while (avp) {
		dup = avp_dup(avp);
		if (dup) {
			/* add AVP into list */
			if (last) last->next = dup;
			else first = dup;
			last = dup;
		}
		avp = avp->next;
	}

	dst->avps = first;
/*	if (dst->avps) db_save_reg_avps(dst); */
	
	return 0;
}
Esempio n. 2
0
static int delete_reg_avps_impl(struct ucontact *info)
{
/*	db_delete_reg_avps(info); */
	if (info->avps) destroy_avps(info->avps);
	info->avps = NULL;
	return 0;
}
Esempio n. 3
0
int ops_delete_avp(struct sip_msg* msg, struct fis_param *ap)
{
	struct usr_avp **avp_list;
	struct usr_avp *avp;
	struct usr_avp *avp_next;
	unsigned short name_type;
	int avp_name;
	int n;

	n = 0;

	if ((ap->opd&AVPOPS_VAL_NONE)==0)
	{
		/* avp name is known ->search by name */
		/* get avp name */
		if(avpops_get_aname(msg, ap, &avp_name, &name_type)!=0)
		{
			LM_ERR("failed to get dst AVP name\n");
			return -1;
		}
		n = destroy_avps( name_type, avp_name, ap->ops&AVPOPS_FLAG_ALL );
	} else {
		/* avp name is not given - we have just flags */
		/* -> go through all list */
		avp_list = get_avp_list();
		avp = *avp_list;

		for ( ; avp ; avp=avp_next )
		{
			avp_next = avp->next;
			/* check if type match */
			if ( !( (ap->opd&(AVPOPS_VAL_INT|AVPOPS_VAL_STR))==0 ||
			((ap->opd&AVPOPS_VAL_INT)&&((avp->flags&AVP_NAME_STR))==0) ||
			((ap->opd&AVPOPS_VAL_STR)&&(avp->flags&AVP_NAME_STR)) )  )
				continue;
			if((ap->u.sval.pvp.pvn.u.isname.type&AVP_SCRIPT_MASK)!=0
					&& ((ap->u.sval.pvp.pvn.u.isname.type&AVP_SCRIPT_MASK)
								&avp->flags)==0)
				continue;
			/* remove avp */
			destroy_avp( avp );
			n++;
			if ( !(ap->ops&AVPOPS_FLAG_ALL) )
				break;
		}
	}

	LM_DBG("%d avps were removed\n",n);

	return n?1:-1;
}
Esempio n. 4
0
static int save_reg_avps_impl(struct ucontact *c)
{
	int i;
	struct usr_avp *avp, *dup;
	avp_t *first, *last;
	static unsigned short lists[] = {
		AVP_CLASS_USER | AVP_TRACK_FROM, 
		AVP_CLASS_USER | AVP_TRACK_TO, 
		AVP_CLASS_URI | AVP_TRACK_FROM, 
		AVP_CLASS_URI | AVP_TRACK_TO, 
		0
	};

	/* destroy old AVPs */
	/* if (c->avps) db_delete_reg_avps(c); */
	destroy_avps(c->avps);

	last = NULL;
	first = NULL;
	
	for (i = 0; lists[i]; i++) {
		for (avp = get_avp_list(lists[i]); avp; avp = avp->next) {
			
			/* trace_avp("trying to save avp", avp); */
			
			if ((avp->flags & reg_avp_flag) == 0) continue;
			
			/* trace_avp("saving avp", avp); */
			
			dup = avp_dup(avp);
			if (dup) {
				/* add AVP into list */
				if (last) last->next = dup;
				else first = dup;
				last = dup;
			}
			
		}
	}

	c->avps = first;
/*	if (c->avps) db_save_reg_avps(c); */
	
	return 0;
}
Esempio n. 5
0
int do_lb_reset(struct sip_msg *req, struct lb_data *data)
{
	struct usr_avp *id_avp;
	struct usr_avp *res_avp, *del_res_avp;
	int_str id_val;
	int_str res_val;

	struct dlg_cell *dlg;
	struct lb_dst *it_d, *last_dst;
	struct lb_resource *it_r;

	if ( (dlg=lb_dlg_binds.get_dlg())==NULL ) {
		LM_ERR("no dialog found for this call, LB not started\n");
		return -1;
	}

	/* remove any saved AVPs */
	destroy_avps(0, group_avp_name, 0);
	destroy_avps(0, flags_avp_name, 0);
	destroy_avps(0, mask_avp_name, 0);

	/* get previous iteration destination, if any */
	last_dst = NULL;
	id_avp = search_first_avp(0, id_avp_name, &id_val, NULL);
	if( id_avp && (is_avp_str_val(id_avp) == 0) ) {
		for( it_d=data->dsts ; it_d ; it_d=it_d->next ) {
			if( it_d->id == id_val.n ) {
				last_dst = it_d;
				LM_DBG("reset LB - found previous dst %d [%.*s]\n",
					last_dst->id,
					last_dst->profile_id.len, last_dst->profile_id.s);
				break;
			}
		}
	}
	destroy_avps(0, id_avp_name, 0);

	/* any valid previous iteration ? */
	if(last_dst == NULL) {
		/* simply delete all possible resources */
		destroy_avps(0, res_avp_name, 1);
	} else {
		/* search and clean up previous iteration resources, if any */
		res_avp = search_first_avp(0, res_avp_name, &res_val, NULL);
		while (res_avp) {
			if ( (it_r=get_resource_by_name( data, &res_val.s))!=NULL ) {
				if( lb_dlg_binds.unset_profile(dlg, &last_dst->profile_id,
				it_r->profile) != 1 )
					LM_ERR("reset LB - failed to remove from profile [%.*s]->"
						"[%.*s]\n", res_val.s.len, res_val.s.s,
						last_dst->profile_id.len, last_dst->profile_id.s );
			} else {
					LM_WARN("reset LB - ignore unknown previous resource "
						"[%.*s]\n", res_val.s.len, res_val.s.s);
			}

			del_res_avp = res_avp;
			res_avp = search_next_avp(del_res_avp, &res_val);
			destroy_avp(del_res_avp);
		}
	}

	return 0;
}
Esempio n. 6
0
int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl,
						unsigned int flags, struct lb_data *data, int reuse)
{
	/* resources for previous iteration */
	static struct lb_resource **res_prev = NULL;
	static unsigned int res_prev_size = 0;
	/* resources for new iteration */
	static struct lb_resource **res_new = NULL;
	static unsigned int res_new_size = 0;
	/* probed destinations bitmap */
	static unsigned int *dst_bitmap = NULL;
	static unsigned int bitmap_size = 0;
	/* selected destinations buffer */
	static struct lb_dst **dsts = NULL;
	static unsigned int dsts_size = 0;

	/* control vars */
	struct lb_resource **res_cur;
	int res_prev_n, res_new_n, res_cur_n;
	struct lb_dst **dsts_cur;
	struct lb_dst *last_dst, *dst;
	unsigned int dsts_size_cur, dsts_size_max;
	unsigned int *dst_bitmap_cur;
	unsigned int bitmap_size_cur;
	struct dlg_cell *dlg;

	/* AVP related vars */
	struct usr_avp *group_avp;
	struct usr_avp *flags_avp;
	struct usr_avp *mask_avp;
	struct usr_avp *id_avp;
	struct usr_avp *res_avp;
	int_str group_val;
	int_str flags_val;
	int_str mask_val;
	int_str id_val;
	int_str res_val;

	/* iterators, e.t.c. */
	struct lb_dst *it_d;
	struct lb_resource *it_r;
	int load, it_l;
	int i, j, cond;


	/* init control vars state */
	res_cur = NULL;
	res_cur_n = res_prev_n = res_new_n = 0;
	last_dst = dst = NULL;
	dst_bitmap_cur = NULL;

	/* search and fill new resources references if we should not reuse
	   previous iteration data */
	if( !reuse ) {
		res_new_n = rl->n;
		/* adjust size of statically allocated buffer */
		if( res_new_n > res_new_size ) {
			res_new = (struct lb_resource **)pkg_realloc
				(res_new, (res_new_n * sizeof(struct lb_resource *)));
			if( res_new == NULL ) {
				res_new_size = 0;
				LM_ERR("no more pkg mem - resources ptr buffer realloc "
					"failure\n");
				return -1;
			}
			res_new_size = res_new_n;
		}
		/* fill resource references */
		for( it_r=data->resources,i=0 ; it_r ; it_r=it_r->next ) {
			if( search_resource_str(rl, &it_r->name) ) {
				res_new[i++] = it_r;
				LM_DBG("initial call of LB - found requested %d/%d "
					"resource [%.*s]\n", i, res_new_n,
					it_r->name.len, it_r->name.s);
			}
		}
		if( i != res_new_n ) {
			LM_ERR("initial call of LB - unknown resource found in "
				"input string\n");
			return -1;
		}

		/* set 'res_new' as current iteration buffer */
		res_cur = res_new;
		res_cur_n = res_new_n;
	}

	/* always search for previous iteration data,
	   no matter if we will reuse it or not */
	group_avp = search_first_avp(0, group_avp_name, &group_val, NULL);
	flags_avp = search_first_avp(0, flags_avp_name, &flags_val, NULL);
	mask_avp  = search_first_avp(0, mask_avp_name,  &mask_val,  NULL);
	id_avp    = search_first_avp(0, id_avp_name,    &id_val,    NULL);
	/* sanity checks for fetched AVPs */
	if( group_avp && !(is_avp_str_val(group_avp) == 0) )
		{ destroy_avp(group_avp); group_avp = NULL; }
	if( flags_avp && !(is_avp_str_val(flags_avp) == 0) )
		{ destroy_avp(flags_avp); flags_avp = NULL; }
	if( mask_avp  && !(is_avp_str_val(mask_avp)  != 0) )
		{ destroy_avp(mask_avp);  mask_avp  = NULL; }
	if( id_avp    && !(is_avp_str_val(id_avp)    == 0) )
		{ destroy_avp(id_avp);    id_avp    = NULL; }

	/* get previous iteration destination, if any */
	if( id_avp ) {
		for( it_d=data->dsts ; it_d ; it_d=it_d->next ) {
			if( it_d->id == id_val.n ) {
				last_dst = it_d;
				LM_DBG("%s call of LB - found previous dst %d [%.*s]\n",
					(reuse ? "sequential" : "initial"), last_dst->id,
					last_dst->profile_id.len, last_dst->profile_id.s);
				break;
			}
		}
	}
	/* search and fill previous iteration resources references only if... */
	if(
		/* we should reuse previous resources list */
		reuse ||
		/* we have 'last_dst', i.e. previous iteration was successfull and
		 * we need to clean it up */
		(last_dst != NULL)
	) {
		do {
			cond = 0; /* use it here as a 'start loop again' flag */
			res_prev_n = 0;
			res_avp = search_first_avp(0, res_avp_name, &res_val, NULL);
			for( ; res_avp ; res_avp=search_next_avp(res_avp, &res_val) ) {
				/* ignore AVPs with invalid type */
				if( !(is_avp_str_val(res_avp) != 0) ) continue;

				if ( (it_r=get_resource_by_name( data, &res_val.s))==NULL ) {
					LM_WARN("%s call of LB - ignore unknown previous "
						"resource [%.*s]\n", (reuse?"sequential":"initial"),
						res_val.s.len, res_val.s.s);
					continue;
				}
				/* fill buffer only if buffer size not exeeded */
				if( res_prev_n < res_prev_size ) {
					res_prev[res_prev_n] = it_r;
					LM_DBG("%s call of LB - found previous resource [%.*s]\n",
						(reuse ? "sequential" : "initial"),
						it_r->name.len, it_r->name.s);
				}
				res_prev_n++;
			}
			/* adjust size of statically allocated buffer */
			if( res_prev_n > res_prev_size ) {
				/* small hack: if we need to adjust 'res_prev' buffer adjust
				 * it according to 'res_new' size to minimize 
				 * future pkg_realloc()'s */
				if( !reuse && (res_prev_n < res_new_n) )
					res_prev_n = res_new_n;

				res_prev = (struct lb_resource **)pkg_realloc
					(res_prev, (res_prev_n * sizeof(struct lb_resource *)));
				if( res_prev == NULL ) {
					res_prev_size = 0;
					LM_ERR("no more pkg mem - previous resources ptr "
						"buffer realloc failure\n");
					return -1;
				}
				res_prev_size = res_prev_n;
				cond = 1;
			}
		}
		while( cond );
	}

	/* reuse previous iteration resources, group and flags */
	if( reuse ) {
		/* set 'res_prev' as current iteration buffer */
		res_cur = res_prev;
		res_cur_n = res_prev_n;
		if( res_cur_n == 0 ) {
			LM_ERR("sequential call of LB - cannot find previous resources\n");
			return -1;
		}
		if( group_avp )
			group = group_val.n;
		else {
			LM_ERR("sequential call of LB - cannot find previous group\n");
			return -1;
		}
		if( flags_avp )
			flags = flags_val.n;
		else
			flags = LB_FLAGS_DEFAULT;

		LM_DBG("sequential call of LB - found previous group %d and "
			"flags 0x%x\n", group, flags);
	}

	/* sanity check - double check that we have a resource list to work with */
	if( (res_cur == NULL) || (res_cur_n == 0) ) {
		LM_ERR("%s call of LB - no resources list to work with\n",
			(reuse ? "sequential" : "initial"));
		return -1;
	}


	/* [re-]initialize/reuse destinations mask */

	/* sanity check - always calculate current iteration
	 * res_cur[]->bitmap_size */
	bitmap_size_cur=(unsigned int)(-1);
	for( i=0 ; i<res_cur_n ; i++ ) {
		if( bitmap_size_cur > res_cur[i]->bitmap_size )
			bitmap_size_cur = res_cur[i]->bitmap_size;
	}
	/* always try to reuse 'mask' buffer from AVP, even if we need 
	 * to reinitialize it to avoid un-neded AVP ops */
	if(mask_avp && (mask_val.s.len==(bitmap_size_cur*sizeof(unsigned int)))) {
		dst_bitmap_cur = (unsigned int *)mask_val.s.s;
	}
	/* ...or use our static buffer */
	if( dst_bitmap_cur == NULL ) {
		/* adjust size of statically allocated buffer */
		if( bitmap_size_cur > bitmap_size ) {
			dst_bitmap = (unsigned int *)pkg_realloc
				(dst_bitmap, (bitmap_size_cur * sizeof(unsigned int)));
			if( dst_bitmap == NULL ) {
				bitmap_size = 0;
				LM_ERR("no more pkg mem - dst bitmap buffer realloc failed\n");
				return -1;
			}
			bitmap_size = bitmap_size_cur;
		}
		dst_bitmap_cur = dst_bitmap;
	}
	/* reinitalize buffer if... */
	if(
		(dst_bitmap_cur == dst_bitmap) || /* it is our static buffer */
		!reuse /* should not reuse previous iteration data */
	) {
		if( reuse ) {
			LM_WARN("sequential call of LB - cannot %s previous mask, routing "
				"will be re-started", (mask_avp ? "reuse" : "find"));
		}

		memset(dst_bitmap_cur, 0xff, (bitmap_size_cur * sizeof(unsigned int)));
		for( i=0 ; i<res_cur_n ; i++ ) {
			for( j=0 ; j<bitmap_size_cur ; j++ )
				dst_bitmap_cur[j] &= res_cur[i]->dst_bitmap[j];
		}
	}

	/* init selected destinations buff */
	dsts_cur = NULL;
	dsts_size_max = (flags & LB_FLAGS_RANDOM) ? data->dst_no : 1;
	if( dsts_size_max > 1 ) {
		if( dsts_size_max > dsts_size ) {
			dsts = (struct lb_dst **)pkg_realloc
				(dsts, (dsts_size_max * sizeof(struct lb_dst *)));
			if( dsts == NULL ) {
				dsts_size_max = dsts_size = 0;
				LM_WARN("no more pkg mem - dsts buffer realloc failed\n");
			}
			else
				dsts_size = dsts_size_max;
		}
		dsts_cur = dsts;
	}
	if( dsts_cur == NULL ) {
		/* fallback to no-buffer / 'select first' scenario */
		dsts_cur = &dst;
		dsts_size_max = 1;
	}

	/* be sure the dialog is created */
	if ( (dlg=lb_dlg_binds.get_dlg())==NULL ) {
		if( lb_dlg_binds.create_dlg(req, 0) != 1 ) {
			LM_ERR("%s call of LB - failed to create dialog\n",
				(reuse ? "sequential" : "initial"));
			return -1;
		}
		/* get the dialog reference */
		dlg = lb_dlg_binds.get_dlg();
	}

	/* we're initialized from here and no errors could abort us */

	/* remove the dialog from previous profiles, if any */
	if ( (last_dst != NULL) && (res_prev_n > 0) ) {
		for( i=0 ; i<res_prev_n ; i++ ) {
			if( lb_dlg_binds.unset_profile(dlg, &last_dst->profile_id,
			res_prev[i]->profile) != 1 )
				LM_ERR("%s call of LB - failed to remove from profile [%.*s]"
					"->[%.*s]\n", (reuse ? "sequential" : "initial"),
					res_prev[i]->profile->name.len,
					res_prev[i]->profile->name.s, last_dst->profile_id.len,
					last_dst->profile_id.s );
		}
	}


	/* lock resources */
	for( i=0 ; i<res_cur_n ; i++ )
		lock_get(res_cur[i]->lock);

	/* do the load-balancing */

	/*  select destinations */
	cond = 0; /* use it here as a 'first iteration' flag */
	load = it_l = 0;
	dsts_size_cur = 0;
	for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) {
		if( it_d->group == group ) {
			if( (dst_bitmap_cur[i] & (1 << j)) &&
			((it_d->flags & LB_DST_STAT_DSBL_FLAG) == 0) ) {
				/* valid destination (group & resources & status) */
				if( get_dst_load(res_cur, res_cur_n, it_d, flags, &it_l) ) {
					/* only valid load here */
					if( (it_l > 0) || (flags & LB_FLAGS_NEGATIVE) ) {
						/* only allowed load here */
						if( !cond/*first pass*/ || (it_l > load)/*new max*/ ) {
							cond = 1;
							/* restart buffer */
							dsts_size_cur = 0;
						} else if( it_l < load ) {
							/* lower availability -> new iteration */
							continue;
						}

						/* add destination to to selected destinations buffer,
						 * if we have a room for it */
						if( dsts_size_cur < dsts_size_max ) {
							load = it_l;
							dsts_cur[dsts_size_cur++] = it_d;

							LM_DBG("%s call of LB - destination %d <%.*s> "
								"selected for LB set with free=%d\n",
								(reuse ? "sequential" : "initial"),
								it_d->id, it_d->uri.len, it_d->uri.s, it_l
							);
						}
					}
				} else {
					LM_WARN("%s call of LB - skipping destination %d <%.*s> - "
						"unable to calculate free resources\n",
						(reuse ? "sequential" : "initial"),
						it_d->id, it_d->uri.len, it_d->uri.s
					);
				}
			}
			else {
				LM_DBG("%s call of LB - skipping destination %d <%.*s> "
					"(filtered=%d , disabled=%d)\n",
					(reuse ? "sequential" : "initial"),
					it_d->id, it_d->uri.len, it_d->uri.s,
					((dst_bitmap_cur[i] & (1 << j)) ? 0 : 1),
					((it_d->flags & LB_DST_STAT_DSBL_FLAG) ? 1 : 0)
				);
			}
		}
		if( ++j == (8 * sizeof(unsigned int)) ) { i++; j=0; }
	}
	/* choose one destination among selected */
	if( dsts_size_cur > 0 ) {
		if( (dsts_size_cur > 1) && (flags & LB_FLAGS_RANDOM) ) {
			dst = dsts_cur[rand() % dsts_size_cur];
		} else {
			dst = dsts_cur[0];
		}
	}


	if( dst != NULL ) {
		LM_DBG("%s call of LB - winning destination %d <%.*s> selected "
			"for LB set with free=%d\n",
			(reuse ? "sequential" : "initial"),
			dst->id, dst->uri.len, dst->uri.s, load );

		/* add to the profiles */
		for( i=0 ; i<res_cur_n ; i++ ) {
			if( lb_dlg_binds.set_profile(dlg, &dst->profile_id,
			res_cur[i]->profile, 0) != 0 )
				LM_ERR("%s call of LB - failed to add to profile [%.*s]->"
					"[%.*s]\n", (reuse ? "sequential" : "initial"),
					res_cur[i]->profile->name.len, res_cur[i]->profile->name.s,
					dst->profile_id.len, dst->profile_id.s);
		}

		/* set dst as used (not selected) */
		for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) {
			if( it_d == dst ) { dst_bitmap_cur[i] &= ~(1 << j); break; }
			if( ++j == (8 * sizeof(unsigned int)) ) { i++; j=0; }
		}
	} else {
		LM_DBG("%s call of LB - no destination found\n",
			(reuse ? "sequential" : "initial"));
	}

	/* unlock resources */
	for( i=0 ; i<res_cur_n ; i++ )
		lock_release(res_cur[i]->lock);

	/* we're done with load-balancing, now save state */

	/* save state - group */
	if( group_avp == NULL ) {
		group_val.n = group;
		if( add_avp(0, group_avp_name, group_val) != 0 ) {
			LM_ERR("failed to add GROUP AVP\n");
		}
	} else if( group_val.n != group ) {
		group_avp->data = (void *)(long)group;
	}
	/* save state - flags, save only if they are set */
	if( flags_avp == NULL ) {
		if( flags != LB_FLAGS_DEFAULT ) {
			flags_val.n = flags;
			if( add_avp(0, flags_avp_name, flags_val) != 0 ) {
				LM_ERR("failed to add FLAGS AVP\n");
			}
		}
	} else if( flags_val.n != flags ) {
		flags_avp->data = (void *)(long)flags;
	}
	/* save state - dst_bitmap mask */
	if( (mask_avp!=NULL) && (dst_bitmap_cur!=(unsigned int *)mask_val.s.s) ) {
		destroy_avp(mask_avp);
		mask_avp = NULL;
	}
	if( mask_avp == NULL ) {
		mask_val.s.s = (char *)dst_bitmap_cur;
		mask_val.s.len = bitmap_size_cur * sizeof(unsigned int);
		if( add_avp(AVP_VAL_STR, mask_avp_name, mask_val) != 0 ) {
			LM_ERR("failed to add MASK AVP\n");
		}
	}
	/* save state - dst, save only if we have one */
	if( id_avp == NULL ) {
		if( dst != NULL ) {
			id_val.n = dst->id;
			if( add_avp(0, id_avp_name, id_val) != 0 ) {
				LM_ERR("failed to add ID AVP\n");
			}
		}
	} else {
		if( dst != NULL ) {
			id_avp->data = (void *)(long)dst->id;
		} else {
			destroy_avp(id_avp);
			id_avp = NULL;
		}
	}
	/* save state - res */
	/* iterate AVPs once and delete old resources */
	destroy_avps(0, res_avp_name, 1 /*all*/);
	/* add new resources */
	for( i=0 ; i<res_cur_n ; i++ ) {
		res_val.s = res_cur[i]->name;
		if( add_avp(AVP_VAL_STR, res_avp_name, res_val) != 0 )
			LM_ERR("failed to add RES AVP\n");
	}

	/* outcome: set dst uri */
	if( (dst != NULL) && (set_dst_uri(req, &dst->uri) != 0) ) {
		LM_ERR("failed to set duri\n");
		return -2;
	}

	return dst ? 0 : -2;
}
Esempio n. 7
0
File: tm.c Progetto: Deni90/opensips
int pv_set_tm_branch_avp(struct sip_msg *msg, pv_param_t *param, int op,
		pv_value_t *val)
{
	int avp_name;
	int_str avp_val;
	int flags, res=0;
	unsigned short name_type;
	int idx, idxf;
	struct usr_avp **old_list=NULL;
	struct usr_avp **avp_list=NULL;

	if (!msg || !val)
		goto error;

	avp_list = get_bavp_list();
	if (!avp_list) {
		pv_get_null(msg, param, val);
		goto success;
	}

	if (!param) {
		LM_ERR("bad parameters\n");
		goto error;
	}

	if (pv_get_avp_name(msg, param, &avp_name, &name_type)) {
		LM_ALERT("BUG in getting bavp name\n");
		goto error;
	}

	/* get the index */
	if(pv_get_spec_index(msg, param, &idx, &idxf)!=0) {
		LM_ERR("invalid index\n");
		goto error;
	}

	/* setting the avp head */
	old_list = set_avp_list(avp_list);
	if (!old_list) {
		LM_CRIT("no bavp head list found\n");
		goto error;
	}

	if(val == NULL) {
		if(op == COLONEQ_T || idxf == PV_IDX_ALL)
			destroy_avps(name_type, avp_name, 1);
		else {
			if(idx < 0) {
				LM_ERR("index with negative value\n");
				goto error;
			}
			destroy_index_avp(name_type, avp_name, idx);
		}
		/* restoring head */
		goto success;
	}

	if(op == COLONEQ_T || idxf == PV_IDX_ALL)
		destroy_avps(name_type, avp_name, 1);

	flags = name_type;
	if(val->flags&PV_TYPE_INT) {
		avp_val.n = val->ri;
	} else {
		avp_val.s = val->rs;
		flags |= AVP_VAL_STR;
	}

	if(idxf == PV_IDX_INT || idxf == PV_IDX_PVAR) {
		if(replace_avp(flags, avp_name, avp_val, idx)< 0) {
			LM_ERR("failed to replace bavp\n");
			goto error;
		}
	} else {
		if (add_avp(flags, avp_name, avp_val)<0) {
			LM_ERR("error - cannot add bavp\n");
			goto error;
		}
	}
	goto success;

error:
	res = -1;
success:
	if (old_list)
		set_avp_list(old_list);
	return res;
}
Esempio n. 8
0
/*! \brief
 * Loads contacts in destination set into "serial_fork" AVP in reverse
 * priority order and associated each contact with Q_FLAG telling if
 * contact is the last one in its priority class.  Finally, removes
 * all branches from destination set.
 */
int serialize_branches(struct sip_msg *msg, int clean_before )
{
	static struct serial_contact contacts[MAX_BRANCHES];
	int n, last, first, i, prev;
	str branch, *ruri;
	qvalue_t q, ruri_q;
	char *p;
	str dst_uri, path, enc_info;
	unsigned int flags;
	struct socket_info *sock_info;
	int_str val;
	int idx;

	/* Check if anything needs to be done */
	if (nr_branches == 0) {
		LM_DBG("nothing to do - no branches!\n");
		return 0;
	}

	ruri = GET_RURI(msg);
	ruri_q = get_ruri_q();
	flags = getb0flags();

	for (idx = 0; (branch.s = get_branch(idx,&branch.len,&q,0,0,0,0)); idx++) {
		if (q != ruri_q)
			break;
	}

	if (branch.s == 0) {
		LM_DBG("nothing to do - all same q!\n");
		return 0;
	}

	/* reset contact array */
	n = 0;

	/* Insert Request-URI to contact list */
	enc_info.len = 3 * sizeof(long)
			+ ruri->len + msg->dst_uri.len + msg->path_vec.len + 3;
	enc_info.s = (char*) pkg_malloc (enc_info.len);

	if (!enc_info.s) {
		LM_ERR("no pkg memory left\n");
		goto error; /* nothing to free here */
	}

	memset(enc_info.s, 0, enc_info.len);
	p = enc_info.s;

	LM_DBG("Msg information <%.*s,%.*s,%.*s,%d,%u>\n",
			ruri->len, ruri->s,
			msg->dst_uri.len, msg->dst_uri.s,
			msg->path_vec.len, msg->path_vec.s,
			ruri_q, flags);

	*((long*) p) = (long)msg->force_send_socket;
	p += sizeof(long);
	*((long*) p) = (long)flags;
	p += sizeof(long);
	*((long*) p) = (long)ruri_q;
	p += sizeof(long);

	memcpy(p , ruri->s, ruri->len);
	p += ruri->len + 1;
	memcpy(p, msg->dst_uri.s, msg->dst_uri.len);
	p += msg->dst_uri.len + 1;
	memcpy(p, msg->path_vec.s, msg->path_vec.len);

	contacts[n].enc_info = enc_info;
	contacts[n].q = ruri_q;
	contacts[n].next = -1;
	last = n;
	first = n;
	n++;

	/* Insert branch URIs to contact list in increasing q order */
	for (idx = 0;(branch.s = get_branch(idx, &branch.len, &q,
					&dst_uri, &path, &flags, &sock_info)); idx++){

		enc_info.len = 3 * sizeof(long)
						+ branch.len + dst_uri.len + path.len + 3;
		enc_info.s = (char*) pkg_malloc (enc_info.len);

		if (!enc_info.s) {
			LM_ERR("no pkg memory left\n");
			goto error_free;
		}

		memset(enc_info.s, 0, enc_info.len);
		p = enc_info.s;

		LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u>\n", 
				branch.len, branch.s,
				dst_uri.len, dst_uri.s,
				path.len, path.s,
				q, flags);

		*((long*) p) = (long)sock_info;
		p += sizeof(long);
		*((long*) p) = (long)flags;
		p += sizeof(long);
		*((long*) p) = (long)q;
		p += sizeof(long);

		memcpy(p , branch.s, branch.len);
		p += branch.len + 1;
		memcpy(p, dst_uri.s, dst_uri.len);
		p += dst_uri.len + 1;
		memcpy(p, path.s, path.len);

		contacts[n].enc_info = enc_info;
		contacts[n].q = q;

		/* insert based on q */
		for (i = first, prev=-1; i != -1 && contacts[i].q < q; prev=i,i = contacts[i].next);

		if (i == -1) {
			/* append */
			last = contacts[last].next = n;
			contacts[n].next = -1;
		} else {
			if (i == first) {
				/* first element */
				contacts[n].next = first;
				first = n;
			} else {
				/* before pos i */
				contacts[n].next = contacts[prev].next;
				contacts[prev].next = n;
			}
		}

		n++;
	}

	/* Assign values for q_flags */
	for (i = first; contacts[i].next != -1; i = contacts[i].next) {
		if (contacts[i].q < contacts[contacts[i].next].q)
			contacts[contacts[i].next].q_flag = Q_FLAG;
		else
			contacts[contacts[i].next].q_flag = 0;
	}

	if (clean_before)
		destroy_avps( 0/*type*/, serial_avp, 1/*all*/);

	/* Add contacts to "contacts" AVP */
	for (i = first; i != -1; i = contacts[i].next) {
		val.s = contacts[i].enc_info;

		if (add_avp( AVP_VAL_STR|contacts[i].q_flag, serial_avp, val)) {
			LM_ERR("failed to add avp\n");
			goto error_free;
		}

		pkg_free(contacts[i].enc_info.s);
		contacts[i].enc_info.s = NULL;
	}

	/* Clear all branches */
	clear_branches();

	return 0;
error_free:
	for( i=0 ; i<n ; i++) {
		if (contacts[i].enc_info.s)
			pkg_free(contacts[i].enc_info.s);
	}
error:
	return -1;
}
Esempio n. 9
0
int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode, int max_results)
{
	int i, cnt, i_unwrapped;
	unsigned int ds_hash;
	int_str avp_val;
	int ds_id;
	ds_set_p idx = NULL;
	int inactive_dst_count = 0;
	int destination_entries_to_skip = 0;
	/* used to sort the destinations for LB algo */
	ds_dest_p dest = NULL;
	ds_dest_p selected = NULL;
	static ds_dest_p *sorted_set = NULL;

	if(msg==NULL)
	{
		LM_ERR("bad parameters\n");
		return -1;
	}
	
	if(_ds_list==NULL || _ds_list_nr<=0)
	{
		LM_DBG("empty destination set\n");
		return -1;
	}

	if((mode==0) && (ds_force_dst==0)
			&& (msg->dst_uri.s!=NULL || msg->dst_uri.len>0))
	{
		LM_ERR("destination already set [%.*s]\n", msg->dst_uri.len,
				msg->dst_uri.s);
		return -1;
	}
	

	/* get the index of the set */
	if(ds_get_index(set, &idx)!=0)
	{
		LM_ERR("destination set [%d] not found\n", set);
		return -1;
	}
	
	LM_DBG("set [%d]\n", set);

	ds_hash = 0;
	ds_id = -1;
	switch(alg)
	{
		case 0:
			if(ds_hash_callid(msg, &ds_hash)!=0)
			{
				LM_ERR("can't get callid hash\n");
				return -1;
			}
		break;
		case 1:
			if(ds_hash_fromuri(msg, &ds_hash)!=0)
			{
				LM_ERR("can't get From uri hash\n");
				return -1;
			}
		break;
		case 2:
			if(ds_hash_touri(msg, &ds_hash)!=0)
			{
				LM_ERR("can't get To uri hash\n");
				return -1;
			}
		break;
		case 3:
			if (ds_hash_ruri(msg, &ds_hash)!=0)
			{
				LM_ERR("can't get ruri hash\n");
				return -1;
			}
		break;
		case 4:
			ds_id = idx->last;
			idx->last = (idx->last+1) % idx->nr;
		break;
		case 5:
			i = ds_hash_authusername(msg, &ds_hash);
			switch (i)
			{
				case 0:
					/* Authorization-Header found: Nothing to be done here */
				break;
				case 1:
					/* No Authorization found: Use round robin */
					ds_id = idx->last;
					idx->last = (idx->last+1) % idx->nr;
				break;
				default:
					LM_ERR("can't get authorization hash\n");
					return -1;
				break;
			}
		break;
		case 6:
			ds_hash = rand();
		break;
		case 7:
			if (ds_hash_pvar(msg, &ds_hash)!=0)
			{
				LM_ERR("can't get PV hash\n");
				return -1;
			}
		break;
		case 8:
			ds_id = 0;
		break;
		case 9:
			if (!ds_has_pattern && ds_pattern_suffix.len == 0 ) {
				LM_WARN("no pattern specified - using first entry...\n");
				alg = 8;
				break;
			}
			if ((ds_id = ds_pvar_algo(msg, idx, &sorted_set)) <= 0)
			{
				LM_ERR("can't get destination index\n");
				return -1;
			}
			ds_id = 0;
		break;
		default:
			LM_WARN("algo %d not implemented - using first entry...\n", alg);
			ds_id = 0;
	}

	if (ds_id==-1) {
		/* no destination yet actually selected -> do it based on hash */
		if (idx->weight_sum==0) {
			ds_id = ds_hash % idx->nr;
		} else {
			ds_hash = ds_hash%idx->weight_sum;
			/* get the ds id based on weights */
			for( ds_id=0 ; ds_id<idx->nr ; ds_id++ )
				if (ds_hash<idx->dlist[ds_id].weight)
					break;
		}
	}

	LM_DBG("alg hash [%u], id [%u]\n", ds_hash, ds_id);
	cnt = 0;

	if (alg != 9) {
		i=ds_id;
		while ( idx->dlist[i].flags&(DS_INACTIVE_DST|DS_PROBING_DST) )
		{
			if(ds_use_default!=0) {
				if (idx->nr>1)
					i = (i+1)%(idx->nr-1);
			} else {
				i = (i+1)%idx->nr;
			}
			if(i==ds_id)
			{
				if(ds_use_default!=0)
				{
					i = idx->nr-1;
					if (idx->dlist[i].flags&(DS_INACTIVE_DST|DS_PROBING_DST))
						return -1;
					break;
				} else {
					return -1;
				}
			}
		}
		ds_id = i;
		selected = &idx->dlist[ds_id];
	} else {
		selected = sorted_set[0];
	}

	if(ds_update_dst(msg, &selected->uri, selected->sock, mode)!=0)
	{
		LM_ERR("cannot set dst addr\n");
		return -1;
	}
	/* if alg is round-robin then update the shortcut to next to be used */
	if(alg==4)
		idx->last = (ds_id+1) % idx->nr;
	
	LM_DBG("selected [%d-%d/%d] <%.*s>\n", alg, set, ds_id,
			selected->uri.len, selected->uri.s);

	if(!(ds_flags&DS_FAILOVER_ON))
		goto done;

	/* do some AVP cleanup before start populating new ones */
	destroy_avps( 0 /*all types*/, dst_avp_name, 1 /*all*/);
	destroy_avps( 0 /*all types*/, grp_avp_name, 1 /*all*/);
	destroy_avps( 0 /*all types*/, cnt_avp_name, 1 /*all*/);
	destroy_avps( 0 /*all types*/,sock_avp_name, 1 /*all*/);
	if (attrs_avp_name>0)
		destroy_avps( 0 /*all types*/,attrs_avp_name, 1 /*all*/);


	if(ds_use_default!=0 && ds_id!=idx->nr-1)
	{
		if (push_ds_2_avps( &idx->dlist[idx->nr-1] ) != 0 )
			return -1;
		cnt++;
	}

	inactive_dst_count = count_inactive_destinations(idx);
	/* don't count inactive and default entries into total */
	destination_entries_to_skip = idx->nr - inactive_dst_count - (ds_use_default!=0);
	destination_entries_to_skip -= max_results;

	/* add to avp */

	for(i_unwrapped = ds_id-1+idx->nr; i_unwrapped>ds_id; i_unwrapped--) {
		i = i_unwrapped % idx->nr;
		dest = (alg == 9 ? sorted_set[i] : &idx->dlist[i]);

		if((dest->flags & DS_INACTIVE_DST)
				|| (ds_use_default!=0 && i==(idx->nr-1)))
			continue;
		if(destination_entries_to_skip > 0) {
			LM_DBG("skipped entry [%d/%d] (would create more than %i results)\n", set, i, max_results);
			destination_entries_to_skip--;
			continue;
		}

		LM_DBG("using entry [%d/%d]\n", set, i);
		if (push_ds_2_avps( dest ) != 0 )
			return -1;
		cnt++;
	}

	/* add to avp the first used dst */
	avp_val.s = selected->uri;
	if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
		return -1;
	cnt++;

done:
	if (attrs_avp_name>0) {
		avp_val.s = selected->attrs;
		if(add_avp(AVP_VAL_STR|attrs_avp_type,attrs_avp_name,avp_val)!=0)
			return -1;
	}

	/* add to avp the group id */
	avp_val.n = set;
	if(add_avp(grp_avp_type, grp_avp_name, avp_val)!=0)
		return -1;

	/* add to avp the number of dst */
	avp_val.n = cnt;
	if(add_avp(cnt_avp_type, cnt_avp_name, avp_val)!=0)
		return -1;

	return 1;
}