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; }
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; }
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; }
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; }
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; }
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; }
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; }
/*! \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; }
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; }