int pv_set_branchx_helper(sip_msg_t *msg, pv_param_t *param, int op, pv_value_t *val, int btype) { int idx = 0; int idxf = 0; branch_t *br; struct socket_info *si; int port, proto; str host; char backup; if(msg==NULL || param==NULL) { LM_ERR("bad parameters\n"); return -1; } if(btype==1) { br = &_pv_sbranch; } else { /* get the index */ if(pv_get_spec_index(msg, param, &idx, &idxf)!=0) { LM_ERR("invalid index\n"); return -1; } if(idx<0) { if((int)nr_branches + idx >= 0) { idx += nr_branches; } else { LM_ERR("index too low: %d (%u)\n", idx, nr_branches); return -1; } } LM_DBG("managing branch index %d (%u)\n", idx, nr_branches); br = get_sip_branch(idx); } if(br==NULL) { LM_DBG("no branch to operate on\n"); return -1; } switch(param->pvn.u.isname.name.n) { case 1: /* dst uri */ if(val==NULL || (val->flags&PV_VAL_NULL)) { br->dst_uri[0] = '\0'; br->dst_uri_len = 0; break; } if(!(val->flags&PV_VAL_STR)) { LM_ERR("str value required to set branch dst uri\n"); return -1; } if(val->rs.len<=0) { br->dst_uri[0] = '\0'; br->dst_uri_len = 0; break; } if (unlikely(val->rs.len > MAX_URI_SIZE - 1)) { LM_ERR("too long dst uri: %.*s\n", val->rs.len, val->rs.s); return -1; } memcpy(br->dst_uri, val->rs.s, val->rs.len); br->dst_uri[val->rs.len] = 0; br->dst_uri_len = val->rs.len; break; case 2: /* path */ if(val==NULL || (val->flags&PV_VAL_NULL)) { br->path[0] = '\0'; br->path_len = 0; break; } if(!(val->flags&PV_VAL_STR)) { LM_ERR("str value required to set branch path\n"); return -1; } if(val->rs.len<=0) { br->path[0] = '\0'; br->path_len = 0; break; } if (unlikely(val->rs.len > MAX_PATH_SIZE - 1)) { LM_ERR("path too long: %.*s\n", val->rs.len, val->rs.s); return -1; } memcpy(br->path, val->rs.s, val->rs.len); br->path[val->rs.len] = 0; br->path_len = val->rs.len; break; case 3: /* Q */ if(val==NULL || (val->flags&PV_VAL_NULL)) { br->q = Q_UNSPECIFIED; break; } if(!(val->flags&PV_VAL_INT)) { LM_ERR("int value required to set branch q\n"); return -1; } br->q = val->ri; break; case 4: /* send socket */ if(val==NULL || (val->flags&PV_VAL_NULL)) { br->force_send_socket = NULL; break; } if(!(val->flags&PV_VAL_STR)) { LM_ERR("str value required to set branch send sock\n"); return -1; } if(val->rs.len<=0) { br->force_send_socket = NULL; break; } backup = val->rs.s[val->rs.len]; val->rs.s[val->rs.len] = '\0'; if (parse_phostport(val->rs.s, &host.s, &host.len, &port, &proto) < 0) { LM_ERR("invalid socket specification\n"); val->rs.s[val->rs.len] = backup; return -1; } val->rs.s[val->rs.len] = backup; si = grep_sock_info(&host, (unsigned short)port, (unsigned short)proto); if (si!=NULL) { br->force_send_socket = si; } else { LM_WARN("no socket found to match [%.*s]\n", val->rs.len, val->rs.s); br->force_send_socket = NULL; } break; case 5: /* count */ /* do nothing - cannot set the branch counter */ break; case 6: /* flags */ if(val==NULL || (val->flags&PV_VAL_NULL)) { br->flags = 0; break; } if(!(val->flags&PV_VAL_INT)) { LM_ERR("int value required to set branch flags\n"); return -1; } br->flags = val->ri; break; case 7: /* ruid */ /* do nothing - cannot set the ruid */ break; case 8: /* location_ua */ /* do nothing - cannot set the location_ua */ break; default: /* 0 - uri */ if(val==NULL || (val->flags&PV_VAL_NULL)) { if(btype==1) { memset(br, 0, sizeof(branch_t)); } else { drop_sip_branch(idx); } } else { if(!(val->flags&PV_VAL_STR)) { LM_ERR("str value required to set branch uri\n"); return -1; } if(val->rs.len<=0) { if(btype==1) { memset(br, 0, sizeof(branch_t)); } else { drop_sip_branch(idx); } } else { if (unlikely(val->rs.len > MAX_URI_SIZE - 1)) { LM_ERR("too long r-uri: %.*s\n", val->rs.len, val->rs.s); return -1; } memcpy(br->uri, val->rs.s, val->rs.len); br->uri[val->rs.len] = 0; br->len = val->rs.len; } } } return 0; }
int pv_get_branchx_helper(sip_msg_t *msg, pv_param_t *param, pv_value_t *res, int btype) { int idx = 0; int idxf = 0; branch_t *br; if(btype==1) { br = &_pv_sbranch; } else { /* get the index */ if(pv_get_spec_index(msg, param, &idx, &idxf)!=0) { LM_ERR("invalid index\n"); return pv_get_null(msg, param, res); } br = get_sip_branch(idx); if(br==NULL) { return pv_get_null(msg, param, res); } } /* branch(count) doesn't need a valid branch, everything else does */ if(br->len == 0 && ( param->pvn.u.isname.name.n != 5/* count*/ )) { LM_ERR("error accessing branch [%d]\n", idx); return pv_get_null(msg, param, res); } switch(param->pvn.u.isname.name.n) { case 1: /* dst uri */ if(br->dst_uri_len==0) return pv_get_null(msg, param, res); return pv_get_strlval(msg, param, res, br->dst_uri, br->dst_uri_len); case 2: /* path */ if(br->path_len==0) return pv_get_null(msg, param, res); return pv_get_strlval(msg, param, res, br->path, br->path_len); case 3: /* Q */ if(br->q == Q_UNSPECIFIED) return pv_get_null(msg, param, res); return pv_get_sintval(msg, param, res, br->q); case 4: /* send socket */ if(br->force_send_socket!=0) return pv_get_strval(msg, param, res, &br->force_send_socket->sock_str); return pv_get_null(msg, param, res); case 5: /* count */ return pv_get_uintval(msg, param, res, nr_branches); case 6: /* flags */ return pv_get_uintval(msg, param, res, br->flags); case 7: /* ruid */ if(br->ruid_len==0) return pv_get_null(msg, param, res); return pv_get_strlval(msg, param, res, br->ruid, br->ruid_len); case 8: /* location_ua */ if(br->location_ua_len==0) return pv_get_null(msg, param, res); return pv_get_strlval(msg, param, res, br->location_ua, br->location_ua_len); default: /* 0 - uri */ return pv_get_strlval(msg, param, res, br->uri, br->len); } return 0; }
/*! \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; }