/** * append new branches with generic parameters */ int corex_append_branch(sip_msg_t *msg, gparam_t *pu, gparam_t *pq) { str uri = {0}; str qv = {0}; int ret = 0; qvalue_t q = Q_UNSPECIFIED; flag_t branch_flags = 0; if (pu!=NULL) { if(fixup_get_svalue(msg, pu, &uri)!=0) { LM_ERR("cannot get the URI parameter\n"); return -1; } } if (pq!=NULL) { if(fixup_get_svalue(msg, pq, &qv)!=0) { LM_ERR("cannot get the Q parameter\n"); return -1; } if(qv.len>0 && str2q(&q, qv.s, qv.len)<0) { LM_ERR("cannot parse the Q parameter\n"); return -1; } } getbflagsval(0, &branch_flags); ret = append_branch(msg, (uri.len>0)?&uri:0, &msg->dst_uri, &msg->path_vec, q, branch_flags, msg->force_send_socket, 0, 0, 0, 0); if(uri.len<=0) { /* reset all branch attributes if r-uri was shifted to branch */ reset_force_socket(msg); setbflagsval(0, 0); if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; /* if this is a cloned message, don't free the path vector as it was copied into shm memory and will be freed as contiguous block*/ if (!(msg->msg_flags&FL_SHM_CLONE)) { if(msg->path_vec.s!=0) pkg_free(msg->path_vec.s); msg->path_vec.s = 0; msg->path_vec.len = 0; } } return ret; }
/** * append new branches with generic parameters */ int corex_append_branch(sip_msg_t *msg, gparam_t *pu, gparam_t *pq) { str uri = {0}; str qv = {0}; int ret = 0; qvalue_t q = Q_UNSPECIFIED; flag_t branch_flags = 0; if (pu!=NULL) { if(fixup_get_svalue(msg, pu, &uri)!=0) { LM_ERR("cannot get the URI parameter\n"); return -1; } } if (pq!=NULL) { if(fixup_get_svalue(msg, pq, &qv)!=0) { LM_ERR("cannot get the Q parameter\n"); return -1; } if(qv.len>0 && str2q(&q, qv.s, qv.len)<0) { LM_ERR("cannot parse the Q parameter\n"); return -1; } } getbflagsval(0, &branch_flags); ret = append_branch(msg, (uri.len>0)?&uri:0, &msg->dst_uri, &msg->path_vec, q, branch_flags, msg->force_send_socket, 0, 0); if(uri.len<=0) { /* reset all branch attributes if r-uri was shifted to branch */ reset_force_socket(msg); setbflagsval(0, 0); if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; if(msg->path_vec.s!=0) pkg_free(msg->path_vec.s); msg->path_vec.s = 0; msg->path_vec.len = 0; } return ret; }
/*! \brief * Lookup contact in the database and rewrite Request-URI * \return: -1 : not found * -2 : found but method not allowed * -3 : error */ int lookup(struct sip_msg* _m, udomain_t* _d) { impurecord_t* r; str aor, uri; ucontact_t* ptr; int res; int ret; str path_dst; flag_t old_bflags; int i = 0; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; if (extract_aor(&uri, &aor) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain(_d, &aor); res = ul.get_impurecord(_d, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain(_d, &aor); return -1; } ret = -1; while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { LM_DBG("Found a valid contact [%.*s]\n", ptr->c.len, ptr->c.s); i++; break; } i++; } /* look first for an un-expired and suported contact */ if (ptr == 0) { /* nothing found */ goto done; } ret = 1; if (ptr) { if (rewrite_uri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* reset next hop address */ reset_dst_uri(_m); /* If a Path is present, use first path-uri in favour of * received-uri because in that case the last hop towards the uac * has to handle NAT. - agranig */ if (ptr->path.s && ptr->path.len) { if (get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); ret = -3; goto done; } if (set_path_vector(_m, &ptr->path) < 0) { LM_ERR("failed to set path vector\n"); ret = -3; goto done; } if (set_dst_uri(_m, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); ret = -3; goto done; } } else if (ptr->received.s && ptr->received.len) { if (set_dst_uri(_m, &ptr->received) < 0) { ret = -3; goto done; } } set_ruri_q(ptr->q); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags | ptr->cflags); if (ptr->sock) set_force_socket(_m, ptr->sock); ptr = ptr->next; } /* Append branches if enabled */ if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done; //the last i was the first valid contact we found - let's go through the rest of valid contacts and append the branches. while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { path_dst.len = 0; if (ptr->path.s && ptr->path.len && get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); continue; } /* The same as for the first contact applies for branches * regarding path vs. received. */ if (km_append_branch(_m, &ptr->c, path_dst.len ? &path_dst : &ptr->received, &ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) { LM_ERR("failed to append a branch\n"); /* Also give a chance to the next branches*/ continue; } } i++; } done: ul.unlock_udomain(_d, &aor); return ret; }
int sbranch_set_ruri(sip_msg_t *msg) { str sv; flag_t old_bflags; branch_t *br; int ret; ret = 0; br = &_pv_sbranch; if(br->len==0) return -1; sv.s = br->uri; sv.len = br->len; if (rewrite_uri(msg, &sv) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto error; } /* reset next hop address */ reset_dst_uri(msg); if(br->dst_uri_len>0) { sv.s = br->dst_uri; sv.len = br->dst_uri_len; if (set_dst_uri(msg, &sv) < 0) { ret = -3; goto error; } } reset_path_vector(msg); if(br->path_len==0) { sv.s = br->path; sv.len = br->path_len; if(set_path_vector(msg, &sv) < 0) { ret = -4; goto error; } } reset_instance(msg); if (br->instance_len) { sv.s = br->instance; sv.len = br->instance_len; if (set_instance(msg, &sv) < 0) { ret = -5; goto error; } } reset_ruid(msg); if (br->ruid_len) { sv.s = br->ruid; sv.len = br->ruid_len; if (set_ruid(msg, &sv) < 0) { ret = -6; goto error; } } reset_ua(msg); if (br->location_ua_len) { sv.s = br->location_ua; sv.len = br->location_ua_len; if (set_ua(msg, &sv) < 0) { ret = -7; goto error; } } if (br->force_send_socket) set_force_socket(msg, br->force_send_socket); msg->reg_id = br->reg_id; set_ruri_q(br->q); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags|br->flags); return 0; error: return ret; }
/*! \brief * Fills the common part (for all contacts) of the info structure */ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, unsigned int _e, unsigned int _f, int _use_regid) { static ucontact_info_t ci; static str no_ua = str_init("n/a"); static str callid; static str path_received = {0,0}; static str path; static str received = {0,0}; static int received_found; static unsigned int allowed, allow_parsed; static struct sip_msg *m = 0; int_str val; if (_m!=0) { memset( &ci, 0, sizeof(ucontact_info_t)); /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); if (callid.len > CALLID_MAX_SIZE) { rerrno = R_CALLID_LEN; LM_ERR("callid too long\n"); goto error; } ci.callid = &callid; /* Get CSeq number of the message */ if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) { rerrno = R_INV_CSEQ; LM_ERR("failed to convert cseq number\n"); goto error; } /* set received socket */ if (_m->flags&sock_flag) { ci.sock = get_sock_val(_m); if (ci.sock==0) ci.sock = _m->rcv.bind_address; } else { ci.sock = _m->rcv.bind_address; } /* set tcp connection id */ if (_m->rcv.proto==PROTO_TCP || _m->rcv.proto==PROTO_TLS || _m->rcv.proto==PROTO_WS || _m->rcv.proto==PROTO_WSS) { ci.tcpconn_id = _m->rcv.proto_reserved1; } else { ci.tcpconn_id = -1; } /* additional info from message */ if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent && _m->user_agent->body.len>0 && _m->user_agent->body.len<MAX_UA_SIZE) { ci.user_agent = &_m->user_agent->body; } else { ci.user_agent = &no_ua; } /* extract Path headers */ if (path_enabled) { if (build_path_vector(_m, &path, &path_received) < 0) { rerrno = R_PARSE_PATH; goto error; } if (path.len && path.s) { ci.path = &path; if (path_mode != PATH_MODE_OFF) { /* save in msg too for reply */ if (set_path_vector(_m, &path) < 0) { rerrno = R_PARSE_PATH; goto error; } } } } ci.last_modified = act_time; /* set flags */ ci.flags = _f; getbflagsval(0, &ci.cflags); /* get received */ if (path_received.len && path_received.s) { ci.cflags |= ul.nat_flag; ci.received = path_received; } allow_parsed = 0; /* not parsed yet */ received_found = 0; /* not found yet */ m = _m; /* remember the message */ } else { memset( &ci.instance, 0, sizeof(str)); } if(_c!=0) { /* hook uri address - should be more than 'sip:' chars */ if(_c->uri.s!=NULL && _c->uri.len>4) ci.c = &_c->uri; /* Calculate q value of the contact */ if (m && m->id == q_override_msg_id) { ci.q = q_override_value; } else if (calc_contact_q(_c->q, &ci.q) < 0) { rerrno = R_INV_Q; LM_ERR("failed to calculate q\n"); goto error; } /* set expire time */ ci.expires = _e; /* Get methods of contact */ if (_c->methods) { if (parse_methods(&(_c->methods->body), &ci.methods) < 0) { rerrno = R_PARSE; LM_ERR("failed to parse contact methods\n"); goto error; } } else { /* check on Allow hdr */ if (allow_parsed == 0) { if (m && parse_allow( m ) != -1) { allowed = get_allow_methods(m); } else { allowed = ALL_METHODS; } allow_parsed = 1; } ci.methods = allowed; } /* get received */ if (ci.received.len==0) { if (_c->received) { ci.received = _c->received->body; } else { if (received_found==0) { memset(&val, 0, sizeof(int_str)); if (rcv_avp_name.n!=0 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0) && val.s.len > 0) { if (val.s.len>RECEIVED_MAX_SIZE) { rerrno = R_CONTACT_LEN; LM_ERR("received too long\n"); goto error; } received = val.s; } else { received.s = 0; received.len = 0; } received_found = 1; } ci.received = received; } } if(_c->instance!=NULL && _c->instance->body.len>0) ci.instance = _c->instance->body; if(_use_regid && _c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) { if(str2int(&_c->reg_id->body, &ci.reg_id)<0 || ci.reg_id==0) { LM_ERR("invalid reg-id value\n"); goto error; } } if(sruid_next(&_reg_sruid)<0) goto error; ci.ruid = _reg_sruid.uid; LM_DBG("generated ruid is: %.*s\n", ci.ruid.len, ci.ruid.s); } return &ci; error: return 0; }
/*! \brief * Lookup contact in the database and rewrite Request-URI * \return: -1 : not found * -2 : found but method not allowed * -3 : error */ int lookup(struct sip_msg* _m, udomain_t* _d, str* _uri) { urecord_t* r; str aor, uri; sip_uri_t puri; ucontact_t* ptr = 0; int res; int ret; str path_dst; flag_t old_bflags; int i; str inst = {0}; unsigned int ahash = 0; sr_xavp_t *xavp=NULL; sr_xavp_t *list=NULL; str xname = {"ruid", 4}; sr_xval_t xval; ret = -1; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; if (extract_aor((_uri)?_uri:&uri, &aor, &puri) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } /* check if gruu */ if(puri.gr.s!=NULL) { if(puri.gr_val.len>0) { /* pub-gruu */ inst = puri.gr_val; LM_DBG("looking up pub gruu [%.*s]\n", inst.len, inst.s); } else { /* temp-gruu */ ahash = 0; inst = puri.user; for(i=inst.len-1; i>=0; i--) { if(inst.s[i]==REG_GRUU_SEP) break; ahash <<= 4; if(inst.s[i] >='0' && inst.s[i] <='9') ahash+=inst.s[i] -'0'; else if (inst.s[i] >='a' && inst.s[i] <='f') ahash+=inst.s[i] -'a'+10; else if (inst.s[i] >='A' && inst.s[i] <='F') ahash+=inst.s[i] -'A'+10; else { LM_ERR("failed to extract temp gruu - invalid hash\n"); return -3; } } if(i<0) { LM_ERR("failed to extract temp gruu - invalid format\n"); return -3; } inst.len = i; LM_DBG("looking up temp gruu [%u / %.*s]\n", ahash, inst.len, inst.s); } } get_act_time(); if(puri.gr.s==NULL || puri.gr_val.len>0) { /* aor or pub-gruu lookup */ ul.lock_udomain(_d, &aor); res = ul.get_urecord(_d, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain(_d, &aor); return -1; } ptr = r->contacts; ret = -1; /* look first for an un-expired and suported contact */ while (ptr) { if(VALID_CONTACT(ptr,act_time)) { if(allowed_method(_m,ptr)) { /* match on instance, if pub-gruu */ if(inst.len>0) { if(reg_cmp_instances(&inst, &ptr->instance)==0) { /* pub-gruu - found by instance */ LM_DBG("contact for [%.*s] found by pub gruu [%.*s]\n", aor.len, ZSW(aor.s), inst.len, inst.s); break; } } else { /* no-gruu - found by address */ LM_DBG("contact for [%.*s] found by address\n", aor.len, ZSW(aor.s)); break; } } else { LM_DBG("contact for [%.*s] cannot handle the SIP method\n", aor.len, ZSW(aor.s)); ret = -2; } } ptr = ptr->next; } if (ptr==0) { /* nothing found */ LM_DBG("'%.*s' has no valid contact in usrloc\n", aor.len, ZSW(aor.s)); goto done; } } else { /* temp-gruu lookup */ res = ul.get_urecord_by_ruid(_d, ahash, &inst, &r, &ptr); if(res<0) { LM_DBG("temp gruu '%.*s' not found in usrloc\n", aor.len, ZSW(aor.s)); return -1; } aor = *ptr->aor; /* test if un-expired and suported contact */ if( (ptr) && !(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr))) goto done; LM_DBG("contact for [%.*s] found by temp gruu [%.*s / %u]\n", aor.len, ZSW(aor.s), inst.len, inst.s, ahash); } ret = 1; if (ptr) { if (rewrite_uri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* reset next hop address */ reset_dst_uri(_m); /* add xavp with details of the record (ruid, ...) */ if(reg_xavp_rcd.s!=NULL) { list = xavp_get(®_xavp_rcd, NULL); xavp = list; memset(&xval, 0, sizeof(sr_xval_t)); xval.type = SR_XTYPE_STR; xval.v.s = ptr->ruid; xavp_add_value(&xname, &xval, &xavp); if(list==NULL) { /* no reg_xavp_rcd xavp in root list - add it */ xval.type = SR_XTYPE_XAVP; xval.v.xavp = xavp; xavp_add_value(®_xavp_rcd, &xval, NULL); } } /* If a Path is present, use first path-uri in favour of * received-uri because in that case the last hop towards the uac * has to handle NAT. - agranig */ if (ptr->path.s && ptr->path.len) { if (get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); ret = -3; goto done; } if (set_path_vector(_m, &ptr->path) < 0) { LM_ERR("failed to set path vector\n"); ret = -3; goto done; } if (set_dst_uri(_m, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); ret = -3; goto done; } } else if (ptr->received.s && ptr->received.len) { if (set_dst_uri(_m, &ptr->received) < 0) { ret = -3; goto done; } } if (ptr->instance.len) { if (set_instance(_m, &(ptr->instance)) < 0) { ret = -3; goto done; } } _m->reg_id = ptr->reg_id; if (ptr->ruid.len) { if (set_ruid(_m, &(ptr->ruid)) < 0) { ret = -3; goto done; } } if (ptr->user_agent.len) { if (set_ua(_m, &(ptr->user_agent)) < 0) { ret = -3; goto done; } } set_ruri_q(ptr->q); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags|ptr->cflags); if (ptr->sock) set_force_socket(_m, ptr->sock); if(ptr->xavp!=NULL) { xavp = xavp_clone_level_nodata(ptr->xavp); if(xavp_add(xavp, NULL)<0) { ret = -3; goto done; } } ptr = ptr->next; } /* if was gruu, no more branches */ if(inst.len>0) goto done; /* Append branches if enabled */ if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done; for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { path_dst.len = 0; if(ptr->path.s && ptr->path.len && get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); continue; } /* The same as for the first contact applies for branches * regarding path vs. received. */ LM_DBG("instance is %.*s\n", ptr->instance.len, ptr->instance.s); if (append_branch(_m, &ptr->c, path_dst.len?&path_dst:&ptr->received, &ptr->path, ptr->q, ptr->cflags, ptr->sock, ptr->instance.len?&(ptr->instance):0, ptr->instance.len?ptr->reg_id:0, &ptr->ruid, &ptr->user_agent) == -1) { LM_ERR("failed to append a branch\n"); /* Also give a chance to the next branches*/ continue; } if(ptr->xavp!=NULL) { xavp = xavp_clone_level_nodata(ptr->xavp); if(xavp_insert(xavp, nr_branches, NULL)<0) { ret = -3; goto done; } } } } done: ul.release_urecord(r); ul.unlock_udomain(_d, &aor); return ret; }
/*! \brief * Lookup contacts in the database for all branches, including R-URI * \return: -1 : not found * -2 : found but method not allowed (for r-uri) * -3 : error */ int lookup_branches(sip_msg_t *msg, udomain_t *d) { unsigned int nr_branches_start; unsigned int i; int ret; int found; str new_uri; str ruri_b_uri = {0}; str ruri_b_dst_uri = {0}; str ruri_b_path = {0}; int ruri_b_q = Q_UNSPECIFIED; struct socket_info *ruri_b_socket = 0; flag_t ruri_b_flags = 0; str ruri_b_instance = {0}; unsigned int ruri_b_reg_id = 0; str ruri_b_ruid = {0}; str ruri_b_ua = {0}; branch_t *crt = NULL; ret = 1; found = 0; nr_branches_start = nr_branches; /* first lookup the r-uri */ ret = lookup(msg, d, NULL); /* if no other branches -- all done */ if(nr_branches_start==0) return ret; if(ret>0) found = 1; /* backup r-uri branch */ ruri_b_uri = msg->new_uri; ruri_b_dst_uri = msg->dst_uri; ruri_b_path = msg->path_vec; ruri_b_q = get_ruri_q(); ruri_b_socket = msg->force_send_socket; getbflagsval(0, &ruri_b_flags); ruri_b_instance = msg->instance; ruri_b_reg_id = msg->reg_id; ruri_b_ruid = msg->ruid; ruri_b_ua = msg->location_ua; reset_ruri_branch(msg); /* set new uri buf to null, otherwise is freed or overwritten by * rewrite_uri() during branch lookup */ msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; for(i=0; i<nr_branches_start; i++) { crt = get_sip_branch(i); /* it has to be a clean branch to do lookup for it */ if(crt->len <= 0 || crt->dst_uri_len > 0 || crt->path_len > 0 || crt->force_send_socket!=NULL || crt->flags !=0) continue; /* set the new uri from branch and lookup */ new_uri.s = crt->uri; new_uri.len = crt->len; if (rewrite_uri(msg, &new_uri) < 0) { LM_ERR("unable to rewrite Request-URI for branch %u\n", i); ret = -3; goto done; } ret = lookup(msg, d, NULL); if(ret>0) { /* move r-uri branch attributes to crt branch */ found = 1; if (unlikely(msg->new_uri.len > MAX_URI_SIZE - 1)) { LM_ERR("too long uri: %.*s\n", msg->new_uri.len, msg->new_uri.s); ret = -3; goto done; } /* copy the dst_uri */ if (msg->dst_uri.len>0 && msg->dst_uri.s!=NULL) { if (unlikely(msg->dst_uri.len > MAX_URI_SIZE - 1)) { LM_ERR("too long dst_uri: %.*s\n", msg->dst_uri.len, msg->dst_uri.s); ret = -3; goto done; } memcpy(crt->dst_uri, msg->dst_uri.s, msg->dst_uri.len); crt->dst_uri[msg->dst_uri.len] = 0; crt->dst_uri_len = msg->dst_uri.len; } /* copy the path string */ if (unlikely(msg->path_vec.len>0 && msg->path_vec.s!=NULL)) { if (unlikely(msg->path_vec.len > MAX_PATH_SIZE - 1)) { LM_ERR("too long path: %.*s\n", msg->path_vec.len, msg->path_vec.s); ret = -3; goto done; } memcpy(crt->path, msg->path_vec.s, msg->path_vec.len); crt->path[msg->path_vec.len] = 0; crt->path_len = msg->path_vec.len; } /* copy the ruri */ memcpy(crt->uri, msg->new_uri.s, msg->new_uri.len); crt->uri[msg->new_uri.len] = 0; crt->len = msg->new_uri.len; crt->q = get_ruri_q(); crt->force_send_socket = msg->force_send_socket; getbflagsval(0, &crt->flags); } reset_ruri_branch(msg); } done: reset_ruri_branch(msg); /* new uri could be set to allocated buffer by branch lookup */ if(msg->new_uri.s!=NULL) pkg_free(msg->new_uri.s); msg->new_uri = ruri_b_uri; ruri_mark_new(); msg->parsed_uri_ok = 0; msg->dst_uri = ruri_b_dst_uri; msg->path_vec = ruri_b_path; set_ruri_q(ruri_b_q); set_force_socket(msg, ruri_b_socket); setbflagsval(0, ruri_b_flags); msg->instance = ruri_b_instance; msg->reg_id = ruri_b_reg_id; msg->ruid = ruri_b_ruid; msg->location_ua = ruri_b_ua; return (found)?1:ret; }
/* * Loads contacts in destination set into contacts_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 t_load_contacts(struct sip_msg* msg, char* key, char* value) { str uri, tmp, dst_uri, path, branch_info, *ruri; qvalue_t first_q, q; struct contact *contacts, *next, *prev, *curr; int_str val; int first_idx, idx; struct socket_info* sock; unsigned int flags; /* 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; } /* Check if anything needs to be done */ if (nr_branches == 0) { LM_DBG("t_load_contacts(): nothing to do - no branches!\n"); return 1; } ruri = (str *)0; /* Take first q from Request-URI */ ruri = GET_RURI(msg); if (!ruri) { LM_ERR("no Request-URI found\n"); return -1; } first_q = get_ruri_q(); first_idx = 0; /* Check if all q values are equal */ for(idx = first_idx; (tmp.s = get_branch(idx, &tmp.len, &q, 0, 0, 0, 0)) != 0; idx++) { if (q != first_q) { goto rest; } } LM_DBG("t_load_contacts(): nothing to do - all contacts have same q!\n"); return 1; rest: /* Allocate memory for first contact */ contacts = (struct contact *)pkg_malloc(sizeof(struct contact)); if (!contacts) { LM_ERR("no memory for contact info\n"); return -1; } /* Insert Request-URI branch to first contact */ contacts->uri.s = ruri->s; contacts->uri.len = ruri->len; contacts->dst_uri = msg->dst_uri; contacts->sock = msg->force_send_socket; getbflagsval(0, &contacts->flags); contacts->path = msg->path_vec; contacts->q = first_q; contacts->next = (struct contact *)0; /* Insert (remaining) branches to contact list in increasing q order */ for(idx = first_idx; (uri.s = get_branch(idx,&uri.len,&q,&dst_uri,&path,&flags,&sock)) != 0; idx++ ) { next = (struct contact *)pkg_malloc(sizeof(struct contact)); if (!next) { LM_ERR("no memory for contact info\n"); free_contact_list(contacts); return -1; } next->uri = uri; next->q = q; next->dst_uri = dst_uri; next->path = path; next->flags = flags; next->sock = sock; next->next = (struct contact *)0; prev = (struct contact *)0; curr = contacts; while (curr && (curr->q < q)) { prev = curr; curr = curr->next; } if (!curr) { next->next = (struct contact *)0; prev->next = next; } else { next->next = curr; if (prev) { prev->next = next; } else { contacts = next; } } } /* Assign values for q_flags */ curr = contacts; curr->q_flag = 0; while (curr->next) { if (curr->q < curr->next->q) { curr->next->q_flag = Q_FLAG; } else { curr->next->q_flag = 0; } curr = curr->next; } /* Add contacts to contacts_avp */ curr = contacts; while (curr) { if (encode_branch_info(&branch_info, curr) == 0) { LM_ERR("encoding of branch info failed\n"); free_contact_list(contacts); if (branch_info.s) pkg_free(branch_info.s); return -1; } val.s = branch_info; add_avp(contacts_avp_type|AVP_VAL_STR|(curr->q_flag), contacts_avp, val); pkg_free(branch_info.s); LM_DBG("loaded contact <%.*s> with q_flag <%d>\n", STR_FMT(&val.s), curr->q_flag); curr = curr->next; } /* Clear all branches */ clear_branches(); /* Free contact list */ free_contact_list(contacts); return 1; }
int rtjson_init_serial(sip_msg_t *msg, srjson_doc_t *jdoc, sr_xavp_t *iavp) { srjson_t *tj = NULL; srjson_t *nj = NULL; srjson_t *rj = NULL; str val; unsigned int bflags = 0; unsigned int old_bflags = 0; struct socket_info* fsocket = NULL; tj = srjson_GetObjectItem(jdoc, jdoc->root, "routes"); if(tj==NULL || tj->type!=srjson_Array || tj->child==NULL) { LM_ERR("missing or invalid routes field\n"); goto error; } nj = tj->child; clear_branches(); rj = srjson_GetObjectItem(jdoc, nj, "uri"); if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) { val.s = rj->valuestring; val.len = strlen(val.s); LM_DBG("rewrite r-uri to: [%.*s]\n", val.len, val.s); if (rewrite_uri(msg, &val) < 0) { LM_ERR("unable to rewrite Request-URI\n"); goto error; } } reset_dst_uri(msg); reset_path_vector(msg); reset_instance(msg); reset_ruid(msg); reset_ua(msg); reset_force_socket(msg); msg->reg_id = 0; set_ruri_q(0); rj = srjson_GetObjectItem(jdoc, nj, "dst_uri"); if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) { val.s = rj->valuestring; val.len = strlen(val.s); LM_DBG("rewrite dst-uri to: [%.*s]\n", val.len, val.s); if (set_dst_uri(msg, &val) < 0) { LM_ERR("unable to set destination uri\n"); goto error; } } rj = srjson_GetObjectItem(jdoc, nj, "path"); if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) { val.s = rj->valuestring; val.len = strlen(val.s); LM_DBG("rewrite path to: [%.*s]\n", val.len, val.s); if (set_path_vector(msg, &val) < 0) { LM_ERR("unable to set path\n"); goto error; } } rj = srjson_GetObjectItem(jdoc, nj, "socket"); if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) { val.s = rj->valuestring; val.len = strlen(val.s); LM_DBG("trying to set send socket to: [%.*s]\n", val.len, val.s); fsocket = lookup_local_socket(&val); if(fsocket) { set_force_socket(msg, fsocket); } } rj = srjson_GetObjectItem(jdoc, nj, "branch_flags"); if(rj!=NULL && rj->type==srjson_Number && SRJSON_GET_UINT(rj)!=0) { bflags = SRJSON_GET_UINT(rj); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags|bflags); } iavp->val.v.i++; return 0; error: return -1; }