Пример #1
0
int ds_next_dst(struct sip_msg *msg, int mode)
{
	struct socket_info *sock;
	struct usr_avp *avp;
	struct usr_avp *tmp_avp;
	struct usr_avp *attr_avp;
	int_str avp_value;
	int_str sock_avp_value;

	if(!(ds_flags&DS_FAILOVER_ON) || dst_avp_name < 0)
	{
		LM_WARN("failover support disabled\n");
		return -1;
	}

	tmp_avp = search_first_avp(dst_avp_type, dst_avp_name, NULL, 0);
	if(tmp_avp==NULL)
		return -1; /* used avp deleted -- strange */

	/* get AVP with next destination URI */
	avp = search_next_avp(tmp_avp, &avp_value);
	destroy_avp(tmp_avp);

	/* remove old attribute AVP (from prev destination) */
	if (attrs_avp_name >= 0) {
		attr_avp = search_first_avp(attrs_avp_type, attrs_avp_name, NULL, 0);
		if (attr_avp)
			destroy_avp(attr_avp);
	}

	if(avp==NULL || !(avp->flags&AVP_VAL_STR))
		return -1; /* no more avps or value is int */

	/* get AVP with next destination socket */
	tmp_avp = search_first_avp(sock_avp_type, sock_avp_name,
	&sock_avp_value, 0);
	if (tmp_avp) {
		/* this shuold not happen, it is a bogus state */
		sock = NULL;
	} else {
		if (sscanf( sock_avp_value.s.s, "%p", (void**)&sock ) != 1)
			sock = NULL;
	}

	if(ds_update_dst(msg, &avp_value.s, sock, mode)!=0)
	{
		LM_ERR("cannot set dst addr\n");
		return -1;
	}
	LM_DBG("using [%.*s]\n", avp_value.s.len, avp_value.s.s);

	return 1;
}
Пример #2
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 n;

	n = 0;

	if ( (ap->flags&AVPOPS_VAL_NONE)==0)
	{
		/* avp name is known ->search by name */
		name_type = (((ap->flags&AVPOPS_VAL_INT))?0:AVP_NAME_STR);
		while ( (avp=search_first_avp( name_type, ap->val, 0))!=0 )
		{
			destroy_avp( avp );
			n++;
			if ( !(ap->flags&AVPOPS_FLAG_ALL) )
				break;
		}
	} 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->flags&(AVPOPS_VAL_INT|AVPOPS_VAL_STR))==0 ||
			((ap->flags&AVPOPS_VAL_INT)&&((avp->flags&AVP_NAME_STR))==0) ||
			((ap->flags&AVPOPS_VAL_STR)&&(avp->flags&AVP_NAME_STR)) )  )
				continue;
			/* remove avp */
			destroy_avp( avp );
			n++;
			if ( !(ap->flags&AVPOPS_FLAG_ALL) )
				break;
		}
	}

	DBG("DEBUG:avpops:remove_avps: %d avps were removed\n",n);

	return n?1:-1;
}
Пример #3
0
void destroy_index_avp( unsigned short flags, int name, int index)
{
	struct usr_avp *avp = NULL;

	avp = search_index_avp(flags, name, 0, index);
	if(avp== NULL) {
		LM_DBG("AVP with the specified index not found\n");
		return;
	}

	destroy_avp( avp );
}
Пример #4
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;
}
Пример #5
0
int destroy_avps( unsigned short flags, int name, int all)
{
	struct usr_avp *avp;
	int n;

	n = 0;
	while ( (avp=search_first_avp( flags, name, 0, 0))!=0 ) {
		destroy_avp( avp );
		n++;
		if ( !all )
			break;
	}
	return n;
}
Пример #6
0
static int del_attr(struct sip_msg* msg, char* p1, char* p2)
{
    fparam_t* fp;
    avp_t* avp;
    struct search_state st;	
    
    fp = (fparam_t*)p1;
    
    avp = search_avp(fp->v.avp, 0, &st);
    while (avp) {
	destroy_avp(avp);
	avp = search_next_avp(&st, 0);
    }
    return 1;
}
Пример #7
0
/* fixes an attribute containing xl formatted string to pure string runtime */
static int xlfix_attr(struct sip_msg* msg, char* p1, char* p2)
{
    avp_t* avp;
    avp_ident_t* avpid;
    avp_value_t val;
    xl_elog_t* format=NULL;
    int ret=-1;
    
    avpid = &((fparam_t*)p1)->v.avp;

    /* search the AVP */
    avp = search_avp(*avpid, &val, 0);
    if (!avp) {
	DBG("xlfix_attr: AVP does not exist\n");
	goto error;
    }
    if ((avp->flags & AVP_VAL_STR) == 0) {
	DBG("xlfix_attr: Not a string AVP\n");
	goto error;
    }

    /* parse the xl syntax -- AVP values are always
    zero-terminated */
    if (xl_parse(val.s.s, &format)<0) {
	LOG(L_ERR, "ERROR: xlfix_attr: wrong format[%s]\n", val.s.s);
	goto error;
    }

    if (xl_printstr(msg, format, &val.s.s, &val.s.len) > 0) {
	/* we must delete and re-add the AVP again */
	destroy_avp(avp);
	if (add_avp(avpid->flags | AVP_VAL_STR, avpid->name, val)) {
	    ERR("xlfix_attr:Error adding new AVP\n");
	    goto error;
	}
	/* everything went OK */
	ret = 1;
    }

error:
    /* free the parsed xl expression */
    if (format) xl_free(format);

    return ret;
}
Пример #8
0
void get_watchers_from_avp(str_lst_t **watchers, unsigned int *watcher_size,
				unsigned int *watchers_no)
{
	str_lst_t *new_watcher;
	struct usr_avp *avp;
	int_str val;
	unsigned int size;
	struct sip_uri parsed_uri;
	char *p;

	*watchers = NULL;
	*watcher_size = 0;
	*watchers_no = 0;
	for(;;) {
		avp = search_first_avp(watchers_avp_type, watchers_avp_name, &val, 0);
		if (avp == NULL)
			break;
		if(avp->flags&AVP_VAL_STR)
			if (parse_uri(val.s.s, val.s.len, &parsed_uri)<0)
				LM_WARN("discarding non URI watcher [%.*s]\n", val.s.len, val.s.s);
			else {
				LM_DBG("got watcher [%.*s]\n", val.s.len, val.s.s);
				size = sizeof(str_lst_t) + val.s.len;
				new_watcher = (str_lst_t *)pkg_malloc(size);
				if (new_watcher == NULL) {
					LM_ERR("OOM\n");
					return;
				}
				memset(new_watcher, 0, size);

				p = (char*)(new_watcher + 1);
				new_watcher->watcher.len = val.s.len;
				new_watcher->watcher.s = p;
				memcpy(p, val.s.s, val.s.len);
				add_watcher(watchers, new_watcher);
				*watcher_size += size;
				*watchers_no += 1;
			}
		else
			LM_WARN("Ignoring non STR AVP\n");
		destroy_avp(avp);
	}
	print_watchers(*watchers);
	return;
}
Пример #9
0
static int subst_attr(struct sip_msg* msg, char* p1, char* p2)
{
    avp_t* avp;
    avp_value_t val;
    str *res = NULL;
    int count;
    avp_ident_t* name = &((fparam_t*)p1)->v.avp;

    if ((avp = search_avp(*name, &val, NULL))) {
	if (avp->flags & AVP_VAL_STR) {
	    res = subst_str(val.s.s, msg, ((fparam_t*)p2)->v.subst, &count);
	    if (res == NULL) {
		ERR("avp_subst: error while running subst\n");
		goto error;
	    }

	    DBG("avp_subst: %d, result %.*s\n", count, res->len, ZSW(res->s));
	    val.s = *res;
	    
	    if (add_avp_before(avp, name->flags | AVP_VAL_STR, name->name, val)) {
		ERR("avp_subst: error while adding new AVP\n");
		goto error;
	    }
	    
	    destroy_avp(avp);
	    return 1;
	} else {
	    ERR("avp_subst: AVP has numeric value\n");
	    goto error;
	}
    } else {
	ERR("avp_subst: AVP[%.*s] index %d, flags %x not found\n", 
	    name->name.s.len, name->name.s.s,
	    name->index, name->flags);
	goto error;
    }

 error:
    if (res) pkg_free(res);
    return -1;
}
Пример #10
0
static int func_time_end(struct sip_msg *msg, char *key)
{
    char unix_time[20];
    char *endptr;
    long int start_time;
    int result;

    struct search_state st;

    get_milliseconds(unix_time);
    LM_DBG("Statsd: statsd_stop at %s\n",unix_time);
    avp_t* prev_avp;

    int_str avp_value, avp_name;
    avp_name.s.s = key;
    avp_name.s.len = strlen(avp_name.s.s);

    prev_avp = search_first_avp(
        AVP_NAME_STR|AVP_VAL_STR, avp_name, &avp_value, &st);
    if(avp_value.s.len == 0){
        LM_ERR("Statsd: statsd_stop not valid key(%s)\n",key);
        return 1;
    }

    start_time = strtol(avp_value.s.s, &endptr,10);
    if(strlen(endptr) >0){
      LM_DBG(
          "Statsd:statsd_stop not valid key(%s) it's not a number value=%s\n",
          key, avp_value.s.s);
      return 0;
    }

    result = atol(unix_time) - start_time;
    LM_DBG(
        "Statsd: statsd_stop Start_time=%ld unix_time=%ld (%i)\n",
        start_time, atol(unix_time), result);
    destroy_avp(prev_avp);
    return statsd_timing(key, result);
}
Пример #11
0
static int l_siplua_AVP_destroy(lua_State *L)
{
  struct usr_avp *first_avp;
  int name;
  str s;
  int_str val;
  int flags = 0;

  luaL_checkany(L, 1);
  s.s = (char *) lua_tostring(L, 1);
  s.len = strlen(s.s);
  name = get_avp_id(&s);
  first_avp = search_first_avp(flags, name, &val, NULL);
  if (first_avp != NULL)
    {
      destroy_avp(first_avp);
      lua_pushboolean(L, 1);
    }
  else
    lua_pushnil(L);
  return 1;
}
Пример #12
0
static void remove_avps(avp_t *avp)
{
	struct search_state ss;
	avp_name_t name;
	avp_t *a;
	str *s;
	
	if (avp->flags & AVP_NAME_STR) {
		s = get_avp_name(avp);
		if (s) name.s = *s;
		else {
			name.s.s = NULL;
			name.s.len = 0;
		}
	}
	else name.n = avp->id;
	
	a = search_first_avp(avp->flags, name, 0, &ss);
	while(a) {
		destroy_avp(a);
		a = search_next_avp(&ss, 0);
	}
}
Пример #13
0
int ops_copy_avp( struct sip_msg* msg, struct fis_param* src,
													struct fis_param* dst)
{
	struct usr_avp *avp;
	struct usr_avp *prev_avp;
	int_str         avp_val;
	int_str         avp_val2;
	unsigned short name_type1;
	unsigned short name_type2;
	int avp_name1;
	int avp_name2;
	int n;

	n = 0;
	prev_avp = 0;

	/* get avp src name */
	if(avpops_get_aname(msg, src, &avp_name1, &name_type1)!=0)
	{
		LM_ERR("failed to get src AVP name\n");
		goto error;
	}
	/* get avp dst name */
	if(avpops_get_aname(msg, dst, &avp_name2, &name_type2)!=0)
	{
		LM_ERR("failed to get dst AVP name\n");
		goto error;
	}

	avp = search_first_avp( name_type1, avp_name1, &avp_val, 0);
	while ( avp )
	{
		/* build a new avp with new name, but old value */
		/* do we need cast conversion ?!?! */
		if((avp->flags&AVP_VAL_STR) && (dst->ops&AVPOPS_FLAG_CASTN)) {
			if(str2int(&avp_val.s, (unsigned int*)&avp_val2.n)!=0)
			{
				LM_ERR("cannot convert str to int\n");
				goto error;
			}
			if ( add_avp( name_type2, avp_name2, avp_val2)==-1 ) {
				LM_ERR("failed to create new avp!\n");
				goto error;
			}
		} else if(!(avp->flags&AVP_VAL_STR)&&(dst->ops&AVPOPS_FLAG_CASTS)) {
			avp_val2.s.s = int2str(avp_val.n, &avp_val2.s.len);
			if ( add_avp( name_type2|AVP_VAL_STR, avp_name2, avp_val2)==-1 ) {
				LM_ERR("failed to create new avp.\n");
				goto error;
			}
		} else {
			if ( add_avp( name_type2|(avp->flags&AVP_VAL_STR), avp_name2,
					avp_val)==-1 ) {
				LM_ERR("failed to create new avp\n");
				goto error;
			}
		}
		n++;
		/* copy all avps? */
		if ( !(dst->ops&AVPOPS_FLAG_ALL) ) {
			/* delete the old one? */
			if (dst->ops&AVPOPS_FLAG_DELETE)
				destroy_avp( avp );
			break;
		} else {
			prev_avp = avp;
			avp = search_first_avp( name_type1, avp_name1, &avp_val, prev_avp);
			/* delete the old one? */
			if (dst->ops&AVPOPS_FLAG_DELETE)
				destroy_avp( prev_avp );
		}
	}

	return n?1:-1;
error:
	return -1;
}
Пример #14
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;
}
Пример #15
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;
}
Пример #16
0
/*! \brief
 * Adds to request a destination set that includes all highest priority
 * class contacts in "serial_avp" AVP.   If called from a route block,
 * rewrites the request uri with first contact and adds the remaining
 * contacts as branches.  If called from failure route block, adds all
 * contacts as brances.  Removes added contacts from "serial_avp" AVP.
 */
int next_branches( struct sip_msg *msg)
{
	struct usr_avp *avp, *prev;
	int_str val;
	struct socket_info *sock_info;
	qvalue_t q;
	str uri, dst_uri, path;
	char *p;
	unsigned int flags;
	int rval;

	if (route_type != REQUEST_ROUTE && route_type != FAILURE_ROUTE ) {
		/* unsupported route type */
		LM_ERR("called from unsupported route type %d\n", route_type);
		goto error;
	}

	/* Find first avp  */
	avp = search_first_avp(0, serial_avp, &val, 0);

	if (!avp) {
		LM_DBG("no AVPs -- we are done!\n");
		goto error;
	}

	if (!val.s.s) {
		LM_ERR("invalid avp value\n");
		goto error;
	}

	/* *sock_info, flags, q, uri, 0, dst_uri, 0, path, 0,... */

	p = val.s.s;
	sock_info = (struct socket_info*) *((long*) p);
	p += sizeof(long);
	flags = (unsigned int) *((long*) p);
	p += sizeof(long);
	q = (unsigned int) *((long*) p);
	p += sizeof(long);
	uri.s = p;
	uri.len = strlen(p);
	p += uri.len + 1;
	dst_uri.s = p;
	dst_uri.len = strlen(p);
	p += dst_uri.len + 1;
	path.s = p;
	path.len = strlen(p);

	/* Set Request-URI */
	if ( set_ruri(msg, &uri) == -1
	|| set_dst_uri(msg, &dst_uri) == -1
	|| set_path_vector(msg, &path) == -1 )
		goto error1;

	msg->force_send_socket = sock_info;
	set_ruri_q( q );
	setb0flags( flags );

	LM_DBG("Msg information <%.*s,%.*s,%.*s,%d,%u> (avp flag=%u)\n",
				uri.len, uri.s,
				dst_uri.len, dst_uri.s,
				path.len, path.s,
				q, flags, avp->flags);


	if (avp->flags & Q_FLAG) {
		destroy_avp(avp);
		goto done;
	}

	prev = avp;
	avp = search_next_avp(prev, &val);
	destroy_avp(prev);

	/* Append branches until out of branches or Q_FLAG is set */
	while (avp != NULL) {

		if (!val.s.s) {
			LM_ERR("invalid avp value\n");
			continue;
		}

		p = val.s.s;
		sock_info = (struct socket_info*) *((long*) p);
		p += sizeof(long);
		flags = (unsigned int) *((long*) p);
		p += sizeof(long);
		q = (unsigned int) *((long*) p);
		p += sizeof(long);
		uri.s = p;
		uri.len = strlen(p);
		p += strlen(p) + 1;
		dst_uri.s = p;
		dst_uri.len = strlen(p);
		p += strlen(p) + 1;
		path.s = p;
		path.len = strlen(p);

		LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u> (avp flag=%u)\n",
				uri.len, uri.s,
				dst_uri.len, dst_uri.s,
				path.len, path.s,
				q, flags, avp->flags);


		rval = append_branch(msg, &uri, &dst_uri, &path,
				q, flags, sock_info);

		if (rval == -1) {
			LM_ERR("append_branch failed\n");
			goto error1;
		}

		if (avp->flags & Q_FLAG) {
			destroy_avp(avp);
			goto done;
		}

		prev = avp;
		avp = search_next_avp(prev, &val);
		destroy_avp(prev);
	}

	return 2;
done:
	return (search_next_avp(avp, NULL)==NULL)?2:1;
error1:
	destroy_avp(avp);
error:
	return -1;
}
Пример #17
0
/*
 * Adds to request a new destination set that includes all highest
 * priority class contacts in contacts_avp.   Request URI is rewritten with
 * first contact and the remaining contacts (if any) are added as branches.
 * Removes used contacts from contacts_avp.  Returns 1, if contacts_avp
 * was not empty and a destination set was successfully added.  Returns -2,
 * if contacts_avp was empty and thus there was nothing to do.
 * Returns -1 in case of an error. */
int t_next_contacts(struct sip_msg* msg, char* key, char* value)
{
    struct usr_avp *avp, *prev;
    int_str val;
    str uri, dst, path;
    struct socket_info *sock;
    unsigned int flags;
    struct search_state st;

    /* Check if contacts_avp has been defined */
    if (contacts_avp.n == 0) {
		LM_ERR("feature has been disabled - "
			   "to enable define contacts_avp module parameter");
		return -1;
    }

    /* Load Request-URI and branches */

    /* Find first contacts_avp value */
    avp = search_first_avp(contacts_avp_type, contacts_avp, &val, &st);
    if (!avp) {
	LM_DBG("no AVPs - we are done!\n");
	return -2;
    }

    LM_DBG("next contact is <%.*s>\n", STR_FMT(&val.s));

    if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)
	== 0) {
	LM_ERR("decoding of branch info <%.*s> failed\n", STR_FMT(&val.s));
	destroy_avp(avp);
	return -1;
    }
    
    /* Rewrite Request-URI */
    rewrite_uri(msg, &uri);
    if (dst.s && dst.len) set_dst_uri(msg, &dst);
    else reset_dst_uri(msg);
    if (path.s && path.len) set_path_vector(msg, &path);
    else reset_path_vector(msg);
    set_force_socket(msg, sock);
    setbflagsval(0, flags);

    if (avp->flags & Q_FLAG) {
	destroy_avp(avp);
	return 1;
    }
		
    /* Append branches until out of branches or Q_FLAG is set */
    prev = avp;
    while ((avp = search_next_avp(&st, &val))) {
	destroy_avp(prev);
	LM_DBG("next contact is <%.*s>\n", STR_FMT(&val.s));
	
	if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)
	    == 0) {
	    LM_ERR("decoding of branch info <%.*s> failed\n", STR_FMT(&val.s));
	    destroy_avp(avp);
	    return -1;
	}

	if (append_branch(msg, &uri, &dst, &path, 0, flags, sock) != 1) {
	    LM_ERR("appending branch failed\n");
	    destroy_avp(avp);
	    return -1;
	}

	if (avp->flags & Q_FLAG) {
	    destroy_avp(avp);
	    return 1;
	}
	prev = avp;
    }

    destroy_avp(prev);

    return 1;
}
Пример #18
0
int ops_subst(struct sip_msg* msg, struct fis_param** src,
		struct subst_expr* se)
{
	struct usr_avp *avp;
	struct usr_avp *prev_avp;
	int_str         avp_val;
	unsigned short name_type1;
	unsigned short name_type2;
	int            avp_name1;
	int            avp_name2;
	int n;
	int nmatches;
	str* result;

	n = 0;
	prev_avp = 0;

	/* avp name is known ->search by name */
	/* get src avp name */
	if(avpops_get_aname(msg, src[0], &avp_name1, &name_type1)!=0)
	{
		LM_ERR("failed to get src AVP name\n");
		return -1;
	}

	avp = search_first_avp(name_type1, avp_name1, &avp_val, 0);

	if(avp==NULL)
		return -1;

	if(src[1]!=0)
	{
		/* get dst avp name */
		if(avpops_get_aname(msg, src[1], &avp_name2, &name_type2)!=0)
		{
			LM_ERR("failed to get dst AVP name\n");
			return -1;
		}
	} else {
		name_type2 = name_type1;
		avp_name2 = avp_name1;
	}
/* TODO: delete?
	if(name_type2&AVP_NAME_STR)
	{
		if(avp_name2.s.len>=STR_BUF_SIZE)
		{
			LM_ERR("dst name too long\n");
			goto error;
		}
		strncpy(str_buf, avp_name2.s.s, avp_name2.s.len);
		str_buf[avp_name2.s.len] = '\0';
		avp_name2.s.s = str_buf;
	}
*/
	while(avp)
	{
		if(!is_avp_str_val(avp))
		{
			prev_avp = avp;
			avp = search_first_avp(name_type1, avp_name1, &avp_val, prev_avp);
			continue;
		}

		result=subst_str(avp_val.s.s, msg, se, &nmatches);
		if(result!=NULL)
		{
			/* build a new avp with new name */
			avp_val.s = *result;
			if(add_avp(name_type2|AVP_VAL_STR, avp_name2, avp_val)==-1 ) {
				LM_ERR("failed to create new avp\n");
				if(result->s!=0)
					pkg_free(result->s);
				pkg_free(result);
				goto error;
			}
			if(result->s!=0)
				pkg_free(result->s);
			pkg_free(result);
			n++;
			/* copy all avps? */
			if (!(src[0]->ops&AVPOPS_FLAG_ALL) ) {
				/* delete the old one? */
				if (src[0]->ops&AVPOPS_FLAG_DELETE || src[1]==0)
					destroy_avp(avp);
				break;
			} else {
				prev_avp = avp;
				avp = search_first_avp(name_type1,avp_name1,&avp_val,prev_avp);
				/* delete the old one? */
				if (src[0]->ops&AVPOPS_FLAG_DELETE || src[1]==0)
					destroy_avp( prev_avp );
			}
		} else {
			prev_avp = avp;
			avp = search_first_avp(name_type1, avp_name1, &avp_val, prev_avp);
		}

	}
	LM_DBG("subst to %d avps\n", n);
	return n?1:-1;
error:
	return -1;
}
Пример #19
0
int ops_op_avp( struct sip_msg* msg, struct fis_param** av,
													struct fis_param* val)
{
	unsigned short    name_type1;
	unsigned short    name_type2;
	unsigned short    name_type3;
	struct fis_param* src;
	struct usr_avp    *avp1;
	struct usr_avp    *avp2;
	struct usr_avp    *prev_avp;
	int               avp_name1;
	int               avp_name2;
	int               avp_name3;
	int_str           avp_val;
	int_str           op_val;
	int               result;
	pv_value_t        xvalue;

	src = av[0];
	/* look if the required avp(s) is/are present */
			/* search for the avp */
	if(avpops_get_aname(msg, src, &avp_name1, &name_type1)!=0)
	{
		LM_ERR("failed to get src AVP name\n");
		goto error;
	}
	avp1 = search_first_avp(name_type1, avp_name1, &avp_val, 0);
	if (avp1==0)
	{
		LM_DBG(" no src avp found\n");
		goto error;
	}

	while(avp1!=0)
	{
		if(!(avp1->flags&AVP_VAL_STR))
			break;
		avp1 = search_first_avp(name_type1, avp_name1, &avp_val, avp1);
	}
	if (avp1==0 && !(val->ops&AVPOPS_OP_BNOT)) {
		LM_DBG("no proper avp found\n");
		goto error;
	}
	name_type3 = name_type1;
	avp_name3 = avp_name1;
	if(av[1]!=0)
	{
		if(avpops_get_aname(msg, av[1], &avp_name3, &name_type3)!=0)
		{
			LM_ERR("failed to get dst AVP name\n");
			goto error;
		}
	}
/* TODO: delete?
	if(name_type3&AVP_NAME_STR)
	{
		if(avp_name3.s.len>=STR_BUF_SIZE)
		{
			LM_ERR("failed to get dst name too long\n");
			goto error;
		}
		strncpy(str_buf, avp_name3.s.s, avp_name3.s.len);
		str_buf[avp_name3.s.len] = '\0';
		avp_name3.s.s = str_buf;
	}
*/
	prev_avp = 0;
	result = 0;

cycle1:
	if (val->opd&AVPOPS_VAL_PVAR)
	{
		/* the 2nd operator is variable -> get value */
		if(val->u.sval.type==PVT_AVP)
		{
			/* search for the avp */
			if(avpops_get_aname(msg, val, &avp_name2, &name_type2)!=0)
			{
				LM_ERR("failed to get dst AVP name\n");
				goto error;
			}
			avp2 = search_first_avp( name_type2, avp_name2, &op_val, 0);
			while(avp2!=0)
			{
				if(!(avp2->flags&AVP_VAL_STR))
					break;
				avp2 = search_first_avp( name_type2, avp_name2, &op_val, avp2);
			}
			if (avp2==0)
			{
				LM_DBG("no dst avp found\n");
				goto error;
			}
		} else {
			avp2 = 0;
			if(pv_get_spec_value(msg, &(val->u.sval), &xvalue)!=0)
			{
				LM_ERR("cannot get dst value\n");
				goto error;
			}
			if(xvalue.flags&PV_TYPE_INT)
			{
				op_val.n = xvalue.ri;
			} else {
				LM_ERR("dst value is str\n");
				goto error;
			}
		}
	} else {
		if(val->type == AVPOPS_VAL_INT)
			op_val.n = val->u.n;
		else
			op_val.s = val->u.s;
		avp2 = 0;
	}

cycle2:
	/* do operation */
	LM_DBG(" use <%d> and <%d>\n",
			avp_val.n, op_val.n);
	if (val->ops&AVPOPS_OP_ADD)
	{
		result = avp_val.n+op_val.n;
	} else 	if (val->ops&AVPOPS_OP_SUB) {
		result = avp_val.n-op_val.n;
	} else  if (val->ops&AVPOPS_OP_MUL) {
		result = avp_val.n*op_val.n;
	} else if (val->ops&AVPOPS_OP_DIV) {
		if(op_val.n!=0)
			result = (int)(avp_val.n/op_val.n);
		else
		{
			LM_ERR("division by 0\n");
			result = 0;
		}
	} else if (val->ops&AVPOPS_OP_MOD) {
		if(op_val.n!=0)
			result = avp_val.n%op_val.n;
		else
		{
			LM_ERR("modulo by 0\n");
			result = 0;
		}
	} else if (val->ops&AVPOPS_OP_BAND) {
		result = avp_val.n&op_val.n;
	} else if (val->ops&AVPOPS_OP_BOR) {
		result = avp_val.n|op_val.n;
	} else if (val->ops&AVPOPS_OP_BXOR) {
		result = avp_val.n^op_val.n;
	} else if (val->ops&AVPOPS_OP_BNOT) {
		result = ~op_val.n;
	} else {
		LM_CRIT("unknown operation (flg=%d)\n",val->ops);
		goto error;
	}

	/* add the new avp */
	avp_val.n = result;
	if(add_avp(name_type3, avp_name3, avp_val)==-1 ) {
		LM_ERR("failed to create new avp\n");
		goto error;
	}

	/* cycle for the second value (only if avp can have multiple vals) */
	while((avp2!=NULL)
		&&(avp2=search_first_avp( name_type2, avp_name2, &op_val, avp2))!=0)
	{
		if(!(avp2->flags&AVP_VAL_STR))
			goto cycle2;
	}
	prev_avp = avp1;
	/* cycle for the first value -> next avp */
	while((avp1!=NULL)
		&&(avp1=search_first_avp(name_type1, avp_name1, &avp_val, avp1))!=0)
	{
		if (!(avp1->flags&AVP_VAL_STR))
		{
			if(val->ops&AVPOPS_FLAG_DELETE && prev_avp!=0)
			{
				destroy_avp(prev_avp);
				prev_avp = 0;
			}
			goto cycle1;
		}
	}
	LM_DBG("done\n");
	if(val->ops&AVPOPS_FLAG_DELETE && prev_avp!=0)
	{
		destroy_avp(prev_avp);
		prev_avp = 0;
	}
	return 1;

error:
	return -1;
}