Пример #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
static int w_ds_select(struct sip_msg* msg, char* part_set, char* alg,
											char* max_results_flags, int mode)
{
	int ret = -1;
	int _ret;
	int run_prev_ds_select = 0;
	ds_select_ctl_t prev_ds_select_ctl, ds_select_ctl;
	char selected_dst_sock_buf[PTR_STRING_SIZE]; /* a hexa string */
	ds_selected_dst selected_dst;
	struct socket_info *sock = NULL;

	if(msg==NULL)
		return -1;

	ds_select_ctl.mode = mode;
	ds_select_ctl.max_results = 1000;
	ds_select_ctl.reset_AVP = 1;
	ds_select_ctl.set_destination = 1;
	ds_select_ctl.ds_flags = 0;

	memset(&selected_dst, 0, sizeof(ds_selected_dst));
	selected_dst.socket.s = selected_dst_sock_buf;

	/* Retrieve dispatcher set */
	ds_param_t *part_set_param = (ds_param_t*)part_set;

	if (fixup_get_partition(msg, &part_set_param->partition,
			&ds_select_ctl.partition) != 0 ||ds_select_ctl.partition == NULL) {
		LM_ERR("unknown partition\n");
		return -1;
	}

	int_list_t *set_list = part_set_param->sets;
	int_list_t *set_list_exp_start = NULL, *set_list_exp_end = NULL;

	/* Retrieve dispatcher algorithm */
	int_list_t *alg_list = (int_list_t *)alg;
	int_list_t *alg_list_exp_start = NULL, *alg_list_exp_end = NULL;

	/* In case this parameter is not specified */
	max_list_param_p max_param = (max_list_param_p)max_results_flags;
	str max_list_str;

	int_list_t *max_list=NULL, *max_list_free;
	if (max_param && max_param->type == MAX_LIST_TYPE_STR) {
		max_list = (int_list_t*)max_param->lst.list;
	} else if (max_param && max_param->type == MAX_LIST_TYPE_PV) {
		if (pv_printf_s(msg, max_param->lst.elem, &max_list_str) != 0) {
			LM_ERR("cannot get max list from pv\n");
			return -1;
		}

		if (set_list_from_string(max_list_str, &max_list) != 0
				|| max_list == NULL)
			return -1;
	}

	/* Avoid compiler warning */
	memset(&prev_ds_select_ctl, 0, sizeof(ds_select_ctl_t));

	ds_select_ctl.set_destination = 0;

	/* Parse the params in reverse order.
	 * We need to runt the first entry last to properly populate ds_select_dst
	 *  AVPs.
	 * On the first ds_select_dst run we need to reset AVPs.
	 * On the last ds_select_dst run we need to set destination.  */
	do {
		CHECK_AND_EXPAND_LIST(set_list);
		ds_select_ctl.set = set_list->v.ival;

		CHECK_AND_EXPAND_LIST(alg_list);
		ds_select_ctl.alg = alg_list->v.ival;

		if (max_results_flags) {
			ds_select_ctl.max_results = max_list->v.ival;
			ds_select_ctl.ds_flags    = max_list->flags;
		}

		if (run_prev_ds_select) {
			LM_DBG("ds_select: %d %d %d %d %d\n",
				prev_ds_select_ctl.set, prev_ds_select_ctl.alg,
				prev_ds_select_ctl.max_results,
				prev_ds_select_ctl.reset_AVP,
				prev_ds_select_ctl.set_destination);
			_ret = ds_select_dst(msg, &prev_ds_select_ctl, &selected_dst,
				prev_ds_select_ctl.ds_flags);
			if (_ret>=0) ret = _ret;
			/* stop resetting AVPs. */
			ds_select_ctl.reset_AVP = 0;
		} else {
			/* Enable running ds_select_dst on next loop. */
			run_prev_ds_select = 1;
		}
		prev_ds_select_ctl = ds_select_ctl;

		set_list = set_list->next;
		alg_list = alg_list->next;
		if (max_results_flags) {
			max_list_free = max_list;
			max_list = max_list->next;

			if (max_param->type == MAX_LIST_TYPE_PV)
				pkg_free(max_list_free);
		}

		TRY_FREE_EXPANDED_LIST(set_list);
		TRY_FREE_EXPANDED_LIST(alg_list);

	} while (set_list && alg_list &&
			(max_results_flags ? max_list : set_list));

	if (max_results_flags &&  max_list != NULL) {
		LM_ERR("extra max slot(s) and/or flag(s)\n");
		ret = -2;
		goto error;
	}

	if (set_list != NULL) {
		LM_ERR("extra set(s)\n");
		ret = -2;
		goto error;
	}

	if (alg_list != NULL) {
		LM_ERR("extra algorithm(s)\n");
		ret = -2;
		goto error;
	}

	/* last ds_select_dst run: setting destination. */
	ds_select_ctl.set_destination = 1;
	LM_DBG("ds_select: %d %d %d %d %d\n",
		ds_select_ctl.set, ds_select_ctl.alg, ds_select_ctl.max_results,
		ds_select_ctl.reset_AVP, ds_select_ctl.set_destination);
	_ret = ds_select_dst(msg, &ds_select_ctl, &selected_dst,
		ds_select_ctl.ds_flags);
	if (_ret>=0) {
		ret = _ret;
	}
	else {
		if (selected_dst.uri.s != NULL) {
			if (selected_dst.socket.len != 0) {
				if (sscanf( selected_dst.socket.s, "%p", (void**)&sock ) != 1){
					LM_ERR("unable to read forced destination socket\n");
					ret = -4;
					goto error;
				}
			}
			if (ds_update_dst(msg, &selected_dst.uri, sock, ds_select_ctl.mode)
			!= 0) {
				LM_ERR("cannot set dst addr\n");
				ret = -3;
				goto error;
			}
		}
		else {
			ret = -1;
			goto error;
		}
	}

error:
	if (selected_dst.uri.s != NULL) pkg_free(selected_dst.uri.s);
	return ret;
}
Пример #3
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;
}