/** * @brief config file function for replicating SIP message to all nodes (wraps t_replicate) */ int cfg_dmq_t_replicate(struct sip_msg* msg, char* s) { dmq_node_t* node; struct socket_info* sock; int i = 0; int first = 1; /* avoid loops - do not replicate if message has come from another node * (override if optional parameter is set) */ if ((!s || (get_int_fparam(&i, msg, (fparam_t*)s)==0 && !i)) && (is_from_remote_node(msg) > 0)) { LM_DBG("message is from another node - skipping replication\n"); return -1; } /* TODO - backup/restore original send socket */ sock = lookup_local_socket(&dmq_server_socket); if (sock) { set_force_socket(msg, sock); } lock_get(&node_list->lock); node = node_list->nodes; while(node) { /* we do not send the message to the following: * - ourself * - any inactive nodes */ if(node->local || node->status != DMQ_NODE_ACTIVE) { LM_DBG("skipping node %.*s\n", STR_FMT(&node->orig_uri)); node = node->next; continue; } if (!first) { if (append_branch(msg, 0, 0, 0, Q_UNSPECIFIED, 0, sock, 0, 0, 0, 0) == -1) { LM_ERR("failed to append a branch\n"); node = node->next; continue; } } else { first = 0; } if(tmb.t_replicate(msg, &node->orig_uri) < 0) { LM_ERR("error calling t_replicate\n"); goto error; } node = node->next; } lock_release(&node_list->lock); return 0; error: lock_release(&node_list->lock); return -1; }
static int ki_set_socket_helper(sip_msg_t *msg, str *ssock, int smode) { socket_info_t *si; int port, proto; str host; if(msg==NULL) { LM_ERR("bad parameters\n"); return -1; } if(ssock==NULL || ssock->len<=0) { reset_force_socket(msg); return 1; } if (parse_phostport(ssock->s, &host.s, &host.len, &port, &proto) < 0) { LM_ERR("invalid socket specification [%.*s] (%d)\n", ssock->len, ssock->s, smode); goto error; } si = grep_sock_info(&host, (unsigned short)port, (unsigned short)proto); if (si!=NULL) { if(smode==0) { /* send socket */ set_force_socket(msg, si); } else { /* recv socket */ msg->rcv.bind_address = si; msg->rcv.dst_port = si->port_no; msg->rcv.dst_ip = si->address; msg->rcv.proto = si->proto; msg->rcv.proto_reserved1 = 0; msg->rcv.proto_reserved2 = 0; } } else { LM_WARN("no socket found to match [%.*s] (%d)\n", ssock->len, ssock->s, smode); } return 1; error: return -1; }
/*! * \brief Previous hop was a loose router, handle this case * \param _m SIP message * \param preloaded do we have a preloaded route set * \return -1 on failure, 1 on success */ static inline int after_loose(struct sip_msg* _m, int preloaded) { struct hdr_field* hdr; struct sip_uri puri; rr_t* rt; int res; int status = RR_DRIVEN; str uri; struct socket_info *si; int uri_is_myself, next_is_strict; int use_ob = 0; hdr = _m->route; rt = (rr_t*)hdr->parsed; uri = rt->nameaddr.uri; /* reset rr handling static vars for safety in error case */ routed_msg_id = 0; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse the first route URI\n"); return RR_ERROR; } next_is_strict = is_strict(&puri.params); routed_params = puri.params; uri_is_myself = is_myself(&puri); /* IF the URI was added by me, remove it */ if (uri_is_myself>0) { LM_DBG("Topmost route URI: '%.*s' is me\n", uri.len, ZSW(uri.s)); /* set the hooks for the params */ routed_msg_id = _m->id; if ((use_ob = process_outbound(_m, puri.user)) < 0) { LM_INFO("failed to process outbound flow-token\n"); return FLOW_TOKEN_BROKEN; } if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LM_ERR("failed to find next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ LM_DBG("No next URI found\n"); status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN); goto done; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; if (enable_double_rr && is_2rr(&puri.params)) { /* double route may occure due different IP and port, so force as * send interface the one advertise in second Route */ if (parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)<0) { LM_ERR("failed to parse the double route URI\n"); return RR_ERROR; } if (!use_ob) { si = grep_sock_info( &puri.host, puri.port_no, puri.proto); if (si) { set_force_socket(_m, si); } else { if (enable_socket_mismatch_warning) LM_WARN("no socket found for match second RR\n"); } } if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LM_ERR("failed to find next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ LM_DBG("no next URI found\n"); status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN); goto done; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; } uri = rt->nameaddr.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse the first route URI\n"); return RR_ERROR; } } else { #ifdef ENABLE_USER_CHECK /* check if it the ignored user */ if(uri_is_myself < 0) return NOT_RR_DRIVEN; #endif LM_DBG("Topmost URI is NOT myself\n"); routed_params.s = NULL; routed_params.len = 0; } LM_DBG("URI to be processed: '%.*s'\n", uri.len, ZSW(uri.s)); if (next_is_strict) { LM_DBG("Next URI is a strict router\n"); if (handle_sr(_m, hdr, rt) < 0) { LM_ERR("failed to handle strict router\n"); return RR_ERROR; } } else { /* Next hop is loose router */ LM_DBG("Next URI is a loose router\n"); if (!use_ob) { if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("checking maddr failed\n"); return RR_ERROR; } if (set_dst_uri(_m, &uri) < 0) { LM_ERR("failed to set dst_uri\n"); return RR_ERROR; } /* dst_uri changed, so it makes sense to re-use the current uri for forking */ ruri_mark_new(); /* re-use uri for serial forking */ } /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ if (rt != hdr->parsed) { if (!del_lump(_m, hdr->body.s - _m->buf, rt->nameaddr.name.s - hdr->body.s, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } } } done: if (use_ob == 1) status = RR_OB_DRIVEN; /* run RR callbacks only if we have Route URI parameters */ if(routed_params.len > 0) run_rr_callbacks( _m, &routed_params ); return status; }
/*! * \brief Previous hop was a strict router, handle this case * \param _m SIP message * \return -1 on error, 1 on success */ static inline int after_strict(struct sip_msg* _m) { int res, rem_len; struct hdr_field* hdr; struct sip_uri puri; rr_t* rt, *prev; char* rem_off; str uri; struct socket_info *si; hdr = _m->route; rt = (rr_t*)hdr->parsed; uri = rt->nameaddr.uri; /* reset rr handling static vars for safety in error case */ routed_msg_id = 0; routed_params.s = NULL; routed_params.len = 0; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse the first route URI\n"); return RR_ERROR; } if ( enable_double_rr && is_2rr(&puri.params) && is_myself(&puri)) { /* double route may occure due different IP and port, so force as * send interface the one advertise in second Route */ si = grep_sock_info( &puri.host, puri.port_no, puri.proto); if (si) { set_force_socket(_m, si); } else { if (enable_socket_mismatch_warning) LM_WARN("no socket found for match second RR\n"); } if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LM_ERR("searching next route failed\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ LM_DBG("after_strict: No next URI found\n"); return NOT_RR_DRIVEN; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; /* parse the new found uri */ uri = rt->nameaddr.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse URI\n"); return RR_ERROR; } } /* set the hooks for the param * important note: RURI is already parsed by the above function, so * we just used it without any checking */ routed_msg_id = _m->id; routed_params = _m->parsed_uri.params; if (is_strict(&puri.params)) { LM_DBG("Next hop: '%.*s' is strict router\n", uri.len, ZSW(uri.s)); /* Previous hop was a strict router and the next hop is strict * router too. There is no need to save R-URI again because it * is saved already. In fact, in this case we will behave exactly * like a strict router. */ /* Note: when there is only one Route URI left (endpoint), it will * always be a strict router because endpoints don't use ;lr parameter * In this case we will simply put the URI in R-URI and forward it, * which will work perfectly */ if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("failed to check maddr\n"); return RR_ERROR; } if (rewrite_uri(_m, &uri) < 0) { LM_ERR("failed to rewrite request URI\n"); return RR_ERROR; } if (rt->next) { rem_off = hdr->body.s; rem_len = rt->next->nameaddr.name.s - hdr->body.s; } else { rem_off = hdr->name.s; rem_len = hdr->len; } if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } } else { LM_DBG("Next hop: '%.*s' is loose router\n", uri.len, ZSW(uri.s)); if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("failed to check maddr\n"); return RR_ERROR; } if (set_dst_uri(_m, &uri) < 0) { LM_ERR("failed to set dst_uri\n"); return RR_ERROR; } /* Next hop is a loose router - Which means that is is not endpoint yet * In This case we have to recover from previous strict routing, that * means we have to find the last Route URI and put in in R-URI and * remove the last Route URI. */ if (rt != hdr->parsed) { /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ rem_off = hdr->body.s; rem_len = rt->nameaddr.name.s - hdr->body.s; if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } } res = find_rem_target(_m, &hdr, &rt, &prev); if (res < 0) { LM_ERR("searching for last Route URI failed\n"); return RR_ERROR; } else if (res > 0) { /* No remote target is an error */ return RR_ERROR; } uri = rt->nameaddr.uri; if(get_maddr_uri(&uri, 0)!=0) { LM_ERR("checking maddr failed\n"); return RR_ERROR; } if (rewrite_uri(_m, &uri) < 0) { LM_ERR("failed to rewrite R-URI\n"); return RR_ERROR; } /* The first character if uri will be either '<' when it is the * only URI in a Route header field or ',' if there is more than * one URI in the header field */ LM_DBG("The last route URI: '%.*s'\n", rt->nameaddr.uri.len, ZSW(rt->nameaddr.uri.s)); if (prev) { rem_off = prev->nameaddr.name.s + prev->len; rem_len = rt->nameaddr.name.s + rt->len - rem_off; } else { rem_off = hdr->name.s; rem_len = hdr->len; } if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } } /* run RR callbacks only if we have Route URI parameters */ if(routed_params.len > 0) run_rr_callbacks( _m, &routed_params ); return RR_DRIVEN; }
/*! * \brief Perform outbound processing - force local socket and set destination URI * \param _m SIP message * \param flow_token string containing the flow-token extracted from the Route: header * \param dst_uri string to write the destination URI to (extracted from flow-token) * \return -1 on error, 0 when outbound not in use, 1 when outbound in use */ static inline int process_outbound(struct sip_msg *_m, str flow_token) { int ret; struct receive_info *rcv = NULL; struct socket_info *si; str dst_uri; if (!rr_obb.decode_flow_token) return 0; ret = rr_obb.decode_flow_token(_m, &rcv, flow_token); if (ret == -2) { LM_DBG("no flow token found - outbound not in use\n"); return 0; } else if (ret == -1) { LM_INFO("failed to decode flow token\n"); return -1; } else if (!ip_addr_cmp(&rcv->src_ip, &_m->rcv.src_ip) || rcv->src_port != _m->rcv.src_port) { LM_DBG("\"incoming\" request found. Using flow-token for" "routing\n"); /* First, force the local socket */ si = find_si(&rcv->dst_ip, rcv->dst_port, rcv->proto); if (si) set_force_socket(_m, si); else { LM_INFO("cannot find socket from flow-token\n"); return -1; } /* Second, override the destination URI */ dst_uri.s = uri_buf; dst_uri.len = 0; dst_uri.len += snprintf(dst_uri.s + dst_uri.len, MAX_ROUTE_URI_LEN - dst_uri.len, "sip:%s", rcv->src_ip.af == AF_INET6 ? "[" : ""); dst_uri.len += ip_addr2sbuf(&rcv->src_ip, dst_uri.s + dst_uri.len, MAX_ROUTE_URI_LEN - dst_uri.len); dst_uri.len += snprintf(dst_uri.s + dst_uri.len, MAX_ROUTE_URI_LEN - dst_uri.len, "%s:%d;transport=%s", rcv->src_ip.af == AF_INET6 ? "]" : "", rcv->src_port, get_proto_name(rcv->proto)); if (set_dst_uri(_m, &dst_uri) < 0) { LM_ERR("failed to set dst_uri\n"); return -1; } ruri_mark_new(); return 1; } LM_DBG("Not using flow-token for routing\n"); 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) { 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; }
/* * Lookup contact in the database and rewrite Request-URI */ int lookup(struct sip_msg* _m, char* _t, char* _s) { urecord_t* r; str uid; ucontact_t* ptr; int res; unsigned int nat; str new_uri; nat = 0; if (get_to_uid(&uid, _m) < 0) return -1; get_act_time(); ul.lock_udomain((udomain_t*)_t); res = ul.get_urecord((udomain_t*)_t, &uid, &r); if (res < 0) { LOG(L_ERR, "lookup(): Error while querying usrloc\n"); ul.unlock_udomain((udomain_t*)_t); return -2; } if (res > 0) { DBG("lookup(): '%.*s' Not found in usrloc\n", uid.len, ZSW(uid.s)); ul.unlock_udomain((udomain_t*)_t); return -3; } ptr = r->contacts; while ((ptr) && !VALID_CONTACT(ptr, act_time)) ptr = ptr->next; if (ptr) { if (ptr->received.s && ptr->received.len) { if (received_to_uri){ if (add_received(&new_uri, &ptr->c, &ptr->received)<0){ LOG(L_ERR, "ERROR: lookup(): out of memory\n"); return -4; } /* replace the msg uri */ if (_m->new_uri.s) pkg_free(_m->new_uri.s); _m->new_uri=new_uri; _m->parsed_uri_ok=0; ruri_mark_new(); goto skip_rewrite_uri; }else if (set_dst_uri(_m, &ptr->received) < 0) { ul.unlock_udomain((udomain_t*)_t); return -4; } } if (rewrite_uri(_m, &ptr->c) < 0) { LOG(L_ERR, "lookup(): Unable to rewrite Request-URI\n"); ul.unlock_udomain((udomain_t*)_t); return -4; } if (ptr->sock) { set_force_socket(_m, ptr->sock); } skip_rewrite_uri: set_ruri_q(ptr->q); nat |= ptr->flags & FL_NAT; ptr = ptr->next; } else { /* All contacts expired */ ul.unlock_udomain((udomain_t*)_t); return -5; } /* Append branches if enabled */ if (!append_branches) goto skip; while(ptr) { if (VALID_CONTACT(ptr, act_time)) { if (received_to_uri && ptr->received.s && ptr->received.len){ if (add_received(&new_uri, &ptr->c, &ptr->received)<0){ LOG(L_ERR, "ERROR: lookup(): branch: out of memory\n"); goto cont; /* try to continue */ } if (append_branch(_m, &new_uri, 0, 0, ptr->q, 0, 0) == -1) { LOG(L_ERR, "lookup(): Error while appending a branch\n"); pkg_free(new_uri.s); if (ser_error==E_TOO_MANY_BRANCHES) goto skip; else goto cont; /* try to continue, maybe we have an oversized contact */ } pkg_free(new_uri.s); /* append_branch doesn't free it */ }else{ if (append_branch(_m, &ptr->c, &ptr->received, 0 /* path */, ptr->q, 0 /* brflags*/, ptr->sock) == -1) { LOG(L_ERR, "lookup(): Error while appending a branch\n"); goto skip; /* Return OK here so the function succeeds */ } } nat |= ptr->flags & FL_NAT; } cont: ptr = ptr->next; } skip: ul.unlock_udomain((udomain_t*)_t); if (nat) setflag(_m, load_nat_flag); return 1; }
/* * Lookup contact in the database and rewrite Request-URI, * and filter them by aor */ int lookup2(struct sip_msg* msg, char* table, char* p2) { urecord_t* r; str uid; ucontact_t* ptr; int res; unsigned int nat; str new_uri, aor; fparam_t* fp; nat = 0; fp = (fparam_t*)p2; if (get_str_fparam(&aor, msg, (fparam_t*)p2) != 0) { ERR("Unable to get the AOR value\n"); return -1; } if (get_to_uid(&uid, msg) < 0) return -1; get_act_time(); ul.lock_udomain((udomain_t*)table); res = ul.get_urecord((udomain_t*)table, &uid, &r); if (res < 0) { ERR("Error while querying usrloc\n"); ul.unlock_udomain((udomain_t*)table); return -2; } if (res > 0) { DBG("'%.*s' Not found in usrloc\n", uid.len, ZSW(uid.s)); ul.unlock_udomain((udomain_t*)table); return -3; } ptr = r->contacts; while (ptr && (!VALID_CONTACT(ptr, act_time) || !VALID_AOR(ptr, aor))) ptr = ptr->next; if (ptr) { if (ptr->received.s && ptr->received.len) { if (received_to_uri){ if (add_received(&new_uri, &ptr->c, &ptr->received) < 0) { ERR("Out of memory\n"); return -4; } /* replace the msg uri */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri = new_uri; msg->parsed_uri_ok = 0; ruri_mark_new(); goto skip_rewrite_uri; } else if (set_dst_uri(msg, &ptr->received) < 0) { ul.unlock_udomain((udomain_t*)table); return -4; } } if (rewrite_uri(msg, &ptr->c) < 0) { ERR("Unable to rewrite Request-URI\n"); ul.unlock_udomain((udomain_t*)table); return -4; } if (ptr->sock) { set_force_socket(msg, ptr->sock); } skip_rewrite_uri: set_ruri_q(ptr->q); nat |= ptr->flags & FL_NAT; ptr = ptr->next; } else { /* All contacts expired */ ul.unlock_udomain((udomain_t*)table); return -5; } /* Append branches if enabled */ if (!append_branches) goto skip; while(ptr) { if (VALID_CONTACT(ptr, act_time) && VALID_AOR(ptr, aor)) { if (received_to_uri && ptr->received.s && ptr->received.len) { if (add_received(&new_uri, &ptr->c, &ptr->received) < 0) { ERR("branch: out of memory\n"); goto cont; /* try to continue */ } if (append_branch(msg, &new_uri, 0, 0, ptr->q, 0, 0) == -1) { ERR("Error while appending a branch\n"); pkg_free(new_uri.s); if (ser_error == E_TOO_MANY_BRANCHES) goto skip; else goto cont; /* try to continue, maybe we have an oversized contact */ } pkg_free(new_uri.s); /* append_branch doesn't free it */ } else { if (append_branch(msg, &ptr->c, &ptr->received, 0 /* path */, ptr->q, 0, ptr->sock) == -1) { ERR("Error while appending a branch\n"); goto skip; /* Return OK here so the function succeeds */ } } nat |= ptr->flags & FL_NAT; } cont: ptr = ptr->next; } skip: ul.unlock_udomain((udomain_t*)table); if (nat) setflag(msg, load_nat_flag); return 1; }
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 Apply DP-DDDS policy to current SIP message * * Apply DP-DDDS policy to current SIP message. This means * build a new destination URI from the policy AVP and export it * as AVP. Then in kamailio.cfg this new target AVP can be pushed * into the destination URI $duri * \param _msg SIP message * \param _s1 unused * \param _s2 unused * \return negative on failure, positive on succes */ int dp_apply_policy(struct sip_msg* _msg, char* _s1, char* _s2) { str *domain; int_str val; struct usr_avp *avp; char duri[MAX_URI_SIZE]; str duri_str; int len, didsomething; char *at; /* pointer to current location inside duri */ str host; int port, proto; struct socket_info* si; if (!is_route_type(REQUEST_ROUTE)) { LM_ERR("unsupported route type\n"); return -1; } /* * set the send_socket */ /* search for send_socket AVP */ avp = search_first_avp(send_socket_avp_name_str, send_socket_name, &val, 0); if (avp) { if ( !(avp->flags&AVP_VAL_STR) || !val.s.s || !val.s.len) { LM_ERR("empty or non-string send_socket_avp, " "return with error ...\n"); return -1; } LM_DBG("send_socket_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s)); /* parse phostport - AVP str val is asciiz */ /* FIXME: This code relies on the fact that the string value of an AVP * is zero terminated, which may or may not be true in the future */ if (parse_phostport(val.s.s, &(host.s), &(host.len), &port, &proto)) { LM_ERR("could not parse send_socket, return with error ...\n"); return -1; } si = grep_sock_info( &host, (unsigned short) port, (unsigned short) proto); if (si) { set_force_socket(_msg, si); } else { LM_WARN("could not find socket for" "send_socket '%.*s'\n", val.s.len, ZSW(val.s.s)); } } else { LM_DBG("send_socket_avp not found\n"); } /* * set the destination URI */ didsomething = 0; /* if no AVP is set, there is no need to set the DURI in the end */ if (parse_sip_msg_uri(_msg) < 0) { LM_ERR("failed to parse R-URI\n"); return -1; } at = (char *)&(duri[0]); len = 0; if ( (len + 4) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to add uri schema\n"); return -1; } memcpy(at, "sip:", 4); at = at + 4; len = len + 4; domain = &(_msg->parsed_uri.host); LM_DBG("domain is %.*s.\n", domain->len, ZSW(domain->s)); /* search for prefix and add it to duri buffer */ avp = search_first_avp(domain_prefix_avp_name_str, domain_prefix_name, &val, 0); if (avp) { if ( !(avp->flags&AVP_VAL_STR) || !val.s.s || !val.s.len) { LM_ERR("empty or non-string domain_prefix_avp, return with error ...\n"); return -1; } LM_DBG("domain_prefix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s)); if ( (len + val.s.len +1) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to add domain prefix\n"); return -1; } memcpy(at, val.s.s, val.s.len); at = at + val.s.len; *at = '.'; at = at + 1; /* add . as delimiter between prefix and domain */ didsomething = 1; } else { LM_DBG("domain_prefix_avp not found\n"); } /* add domain to duri buffer */ avp = search_first_avp(domain_replacement_avp_name_str, domain_replacement_name, &val, 0); if (avp) { if ( !(avp->flags&AVP_VAL_STR) || !val.s.s || !val.s.len) { LM_ERR("empty or non-string domain_replacement_avp, return with" "error ...\n"); return -1; } LM_DBG("domain_replacement_avp found='%.*s'\n",val.s.len, ZSW(val.s.s)); if ( (len + val.s.len +1) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to add domain replacement\n"); return -1; } memcpy(at, val.s.s, val.s.len); at = at + val.s.len; didsomething = 1; } else { LM_DBG("domain_replacement_avp not found, using original domain '" "%.*s'\n",domain->len, domain->s); if ( (len + domain->len) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to add domain\n"); return -1; } memcpy(at, domain->s, domain->len); at = at + domain->len; } /* search for suffix and add it to duri buffer */ avp = search_first_avp(domain_suffix_avp_name_str, domain_suffix_name, &val, 0); if (avp) { if ( !(avp->flags&AVP_VAL_STR) || !val.s.s || !val.s.len) { LM_ERR("empty or non-string domain_suffix_avp,return with error .." "\n"); return -1; } LM_DBG("domain_suffix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s)); if ( (len + val.s.len + 1) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to add domain suffix\n"); return -1; } *at = '.'; at = at + 1; /* add . as delimiter between domain and suffix */ memcpy(at, val.s.s, val.s.len); at = at + val.s.len; didsomething = 1; } else { LM_DBG("domain_suffix_avp not found\n"); } /* search for port override and add it to duri buffer */ avp = search_first_avp(port_override_avp_name_str, port_override_name, &val, 0); if (avp) { if ( !(avp->flags&AVP_VAL_STR) || !val.s.s || !val.s.len) { LM_ERR("empty or non-string port_override_avp, return with error ...\n"); return -1; } LM_DBG("port_override_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s)); /* We do not check if the port is valid */ if ( (len + val.s.len + 1) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to add domain suffix\n"); return -1; } *at = ':'; at = at + 1; /* add : as delimiter between domain and port */ memcpy(at, val.s.s, val.s.len); at = at + val.s.len; didsomething = 1; } else { LM_DBG("port_override_avp not found, using original port\n"); if (_msg->parsed_uri.port.len) { LM_DBG("port found in RURI, reusing it for DURI\n"); if ( (len + _msg->parsed_uri.port.len + 1) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to copy port\n"); return -1; } *at = ':'; at = at + 1; /* add : as delimiter between domain and port */ memcpy(at, _msg->parsed_uri.port.s, _msg->parsed_uri.port.len); at = at + _msg->parsed_uri.port.len; } else { LM_DBG("port not found in RURI, no need to copy it to DURI\n"); } } /* search for transport override and add it to duri buffer */ avp = search_first_avp(transport_override_avp_name_str, transport_override_name, &val, 0); if (avp) { if ( !(avp->flags&AVP_VAL_STR) || !val.s.s || !val.s.len) { LM_ERR("empty or non-string transport_override_avp, " "return with error ...\n"); return -1; } LM_DBG("transport_override_avp found='%.*s'\n",val.s.len, ZSW(val.s.s)); if ( (len + val.s.len + 11) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to add transport override\n"); return -1; } /* add : as transport parameter to duri; NOTE: no checks if transport parameter is valid */ memcpy(at, ";transport=", 11); at = at + 11; memcpy(at, val.s.s, val.s.len); at = at + val.s.len; didsomething = 1; } else { LM_DBG("transport_override_avp not found, using original transport\n"); if (_msg->parsed_uri.transport.len) { LM_DBG("transport found in RURI, reusing it for DURI\n"); if ( (len + _msg->parsed_uri.transport.len + 1) > MAX_URI_SIZE) { LM_ERR("duri buffer to small to copy transport\n"); return -1; } *at = ';'; at = at + 1; /* add : as delimiter between domain and port */ memcpy(at, _msg->parsed_uri.transport.s, _msg->parsed_uri.transport.len); at = at + _msg->parsed_uri.transport.len; } else { LM_DBG("transport not found in RURI, no need to copy it to DURI\n"); } } /* write new target DURI into DURI */ if (didsomething == 0) { LM_DBG("no domainpolicy AVP set, no need to push new DURI\n"); return 2; } duri_str.s = (char *)&(duri[0]); duri_str.len = at - duri_str.s; LM_DBG("new DURI is '%.*s'\n",duri_str.len, ZSW(duri_str.s)); if(set_dst_uri(_msg, &duri_str)<0) { LM_ERR("failed to se dst uri\n"); return -1; } /* dst_uri changes, so it makes sense to re-use the current uri for forking */ ruri_mark_new(); /* re-use uri for serial forking */ return 1; }
/* Actions are composed as follows: * (the action length and type as always= 5 bytes) * * TODO performance speedup: instead of using * dynamically allocated memory for headers,body,totag,reason and my_msg * use static buffers. * */ int ac_sl_msg(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len) { struct sip_msg *my_msg; str *uri; struct proxy_l *proxy; rr_t *my_route; int k,retval; //enum sip_protos proto; my_msg=NULL; k=0; proxy=0; if(!(my_msg = parse_ac_msg(HDR_EOH_F,action+k,len-k))){ LM_ERR("out of memory!\n"); goto error; } if(my_msg->first_line.type == SIP_REQUEST) LM_DBG("forwarding request:\"%.*s\" statelessly \n",my_msg->first_line.u.request.method.len+1+\ my_msg->first_line.u.request.uri.len,my_msg->first_line.u.request.method.s); else LM_DBG("forwarding reply:\"%.*s\" statelessly \n",my_msg->first_line.u.reply.status.len+1+\ my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.status.s); if (my_msg->route) { if (parse_rr(my_msg->route) < 0) { LM_ERR( "Error while parsing Route body\n"); goto error; } my_route = (rr_t*)my_msg->route->parsed; uri=&(my_route->nameaddr.uri); }else{ uri = GET_RURI(my_msg); } set_force_socket(my_msg, grep_sock_info(&my_msg->via1->host, my_msg->via1->port, my_msg->via1->proto) ); /* or also could be: my_msg->force_send_socket=the_as->binds[processor_id].bind_address; not sure which is better... */ /*proxy=uri2proxy(uri,PROTO_NONE); if (proxy==0) { LM_ERR("unable to create proxy from URI \n"); goto error; } proto=proxy->proto; */ //TODO my_msg->recvd if(0>forward_sl_request(my_msg,uri,PROTO_NONE)) goto error; retval=0; goto exit; error: retval = -1; exit: if(proxy){ free_proxy(proxy); pkg_free(proxy); } if(my_msg){ free_sip_msg_lite(my_msg); pkg_free(my_msg); } return retval; }
/*! \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; }
/* * 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; }
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; }