/* * Build SIP message for destination * param msg SIP message * param isfirst Is first destination * param type Main or branch route block * param format URI format * param redirect Is for redirect * return MODULE_RETURNCODE_TRUE success MODULE_RETURNCODE_FALSE failure */ static int ospPrepareDestination( struct sip_msg* msg, int isfirst, int type, int format, int redirect) { char buffer[OSP_HEADERBUF_SIZE]; str newuri = { buffer, sizeof(buffer) }; osp_dest* dest = ospGetNextOrigDestination(); int result = MODULE_RETURNCODE_FALSE; if (dest != NULL) { ospRebuildDestionationUri(&newuri, dest, format); LM_INFO("prepare route to URI '%.*s' for call_id '%.*s' transaction_id '%llu'\n", newuri.len, newuri.s, dest->callidsize, dest->callid, dest->transid); if (type == OSP_MAIN_ROUTE) { if (redirect) { dest->lastcode = 300; } if (isfirst == OSP_FIRST_ROUTE) { set_ruri(msg, &newuri); } else { append_branch(msg, &newuri, NULL, NULL, Q_UNSPECIFIED, 0, NULL); } /* Do not add route specific OSP information */ result = MODULE_RETURNCODE_TRUE; } else if (type == OSP_BRANCH_ROUTE) { /* For branch route, add route specific OSP information */ /* Update the Request-Line */ set_ruri(msg, &newuri); /* Add OSP token header */ ospAddOspHeader(msg, dest->token, dest->tokensize); /* Add branch-specific OSP Cookie */ ospRecordOrigTransaction(msg, dest->transid, dest->srcdev, dest->calling, dest->called, dest->authtime, dest->destcount); /* Handle calling number translation */ ospSetCalling(msg, dest); result = MODULE_RETURNCODE_TRUE; } else { LM_ERR("unsupported route block type\n"); } } else { LM_DBG("there is no more routes\n"); ospReportOrigSetupUsage(); } return result; }
static int dst_to_msg(struct sip_msg *s_msg, struct sip_msg *d_msg) { /* move RURI */ if (set_ruri( d_msg, GET_RURI(s_msg))<0) { LM_ERR("failed to set new RURI\n"); return -1; } /* move DURI (empty is accepted as reset) */ if (set_dst_uri( d_msg, &s_msg->dst_uri)<0) { LM_ERR("failed to set DST URI\n"); return -1; } /* move PATH (empty is accepted as reset) */ if (set_path_vector( d_msg, & s_msg->path_vec)<0) { LM_ERR("failed to set PATH\n"); return -1; } /* Qval */ set_ruri_q( d_msg, get_ruri_q(s_msg) ); /* BFLAGS */ setb0flags( d_msg, getb0flags(s_msg) ); /* socket info */ d_msg->force_send_socket = s_msg->force_send_socket; return 0; }
inline int set_alias_to_ruri(struct sip_msg* _msg, str *alias, int no, void *p) { /* set the RURI */ if(no==0) { if(set_ruri(_msg, alias)<0) { LM_ERR("cannot replace the R-URI\n"); return -1; } } else if (ald_append_branches) { if (append_branch(_msg, alias, 0, 0, MIN_Q, 0, 0) == -1) { LM_ERR("error while appending branches\n"); return -1; } } return 0; }
/* * Converts Request-URI, if it is tel URI, to SIP URI. Returns 1, if * conversion succeeded or if no conversion was needed, i.e., Request-URI * was not tel URI. Returns -1, if conversion failed. */ int tel2sip(struct sip_msg* _msg, char* _s1, char* _s2) { str *ruri; struct sip_uri *pfuri; str suri; char* at; ruri = GET_RURI(_msg); if (ruri->len < 4) return 1; if (strncasecmp(ruri->s, "tel:", 4) != 0){ return 1; } if ((pfuri=parse_from_uri(_msg))==NULL) { LM_ERR("parsing From header failed\n"); return -1; } suri.len = 4 + ruri->len - 4 + 1 + pfuri->host.len + 1 + 10; suri.s = pkg_malloc(suri.len); if (suri.s == 0) { LM_ERR("no more pkg memory\n"); return -1; } at = suri.s; memcpy(at, "sip:", 4); at = at + 4; memcpy(at, ruri->s + 4, ruri->len - 4); at = at + ruri->len - 4; *at = '@'; at = at + 1; memcpy(at, pfuri->host.s, pfuri->host.len); at = at + pfuri->host.len; *at = ';'; at = at + 1; memcpy(at, "user=phone", 10); if (set_ruri(_msg, &suri) == 1) { pkg_free(suri.s); return 1; } else { pkg_free(suri.s); return -1; } }
/* * Logic necessary to forward request to strict routers * * Returns 0 on success, negative number on an error */ static inline int handle_sr(struct sip_msg* _m, struct hdr_field* _hdr, rr_t* _r) { str uri; char* rem_off; int rem_len; /* Next hop is strict router, save R-URI here */ if (_r->next) { if (save_ruri(_m) < 0) { LM_ERR("failed to save Request-URI\n"); return -1; } } /* Put the first Route in Request-URI */ uri = _r->nameaddr.uri; if(get_maddr_uri(&uri, 0)!=0) { LM_ERR("failed to check maddr\n"); return RR_ERROR; } if (set_ruri(_m, &uri) < 0) { LM_ERR("failed to rewrite request URI\n"); return -2; } if (!_r->next) { rem_off = _hdr->name.s; rem_len = _hdr->len; } else { rem_off = _hdr->body.s; rem_len = _r->next->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 -9; } _r->deleted = 1; return 0; }
static inline int do_dns_failover(struct cell *t) { static struct sip_msg faked_req; struct sip_msg *shmem_msg; struct ua_client *uac; int ret; shmem_msg = t->uas.request; uac = &t->uac[picked_branch]; /* check if the DNS resolver can get at least one new IP */ if ( get_next_su( uac->proxy, &uac->request.dst.to, 1)!=0 ) return -1; LM_DBG("new destination available\n"); if (!fake_req(&faked_req, shmem_msg, &t->uas, uac)) { LM_ERR("fake_req failed\n"); return -1; } /* fake also the env. conforming to the fake msg */ faked_env( t, &faked_req); ret = -1; /* set info as current destination */ if ( set_ruri( &faked_req, &uac->uri)!= 0) goto done; setb0flags( uac->br_flags ); faked_req.force_send_socket = shmem_msg->force_send_socket; /* send it out */ if (t_forward_nonack( t, &faked_req, uac->proxy)==1) ret = 0; done: /* restore original environment and free the fake msg */ faked_env( t, 0); free_faked_req(&faked_req,t); 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, char* _t, char* _f, char* _s) { unsigned int flags; urecord_t* r; str aor, uri; ucontact_t* ptr,*it; int res; int ret; str path_dst; str flags_s; char* ua = NULL; char* re_end = NULL; int re_len = 0; char tmp; regex_t ua_re; int regexp_flags = 0; regmatch_t ua_match; pv_value_t val; int_str istr; str sip_instance = {0,0},call_id = {0,0}; /* branch index */ int idx; /* temporary branch values*/ int tlen; char *turi; qvalue_t tq; flags = 0; if (_f && _f[0]!=0) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid owner uri parameter"); return -1; } for( res=0 ; res< flags_s.len ; res++ ) { switch (flags_s.s[res]) { case 'm': flags |= REG_LOOKUP_METHODFILTER_FLAG; break; case 'b': flags |= REG_LOOKUP_NOBRANCH_FLAG; break; case 'r': flags |= REG_BRANCH_AOR_LOOKUP_FLAG; break; case 'u': if (flags_s.s[res+1] != '/') { LM_ERR("no regexp after 'u' flag"); break; } res++; if ((re_end = strrchr(flags_s.s+res+1, '/')) == NULL) { LM_ERR("no regexp after 'u' flag"); break; } res++; re_len = re_end-flags_s.s-res; if (re_len == 0) { LM_ERR("empty regexp"); break; } ua = flags_s.s+res; flags |= REG_LOOKUP_UAFILTER_FLAG; LM_DBG("found regexp /%.*s/", re_len, ua); res += re_len; break; case 'i': regexp_flags |= REG_ICASE; break; case 'e': regexp_flags |= REG_EXTENDED; break; default: LM_WARN("unsuported flag %c \n",flags_s.s[res]); } } } if (flags®_BRANCH_AOR_LOOKUP_FLAG) { /* extract all the branches for further usage */ nbranches = 0; while ( (turi=get_branch(nbranches, &tlen, &tq, NULL, NULL, NULL, NULL)) ) { /* copy uri */ branch_uris[nbranches].s = urimem[nbranches]; if (tlen) { memcpy(branch_uris[nbranches].s, turi, tlen); branch_uris[nbranches].len = tlen; } else { *branch_uris[nbranches].s = '\0'; branch_uris[nbranches].len = 0; } nbranches++; } clear_branches(); idx=0; } if (_s) { if (pv_get_spec_value( _m, (pv_spec_p)_s, &val)!=0) { LM_ERR("failed to get PV value\n"); return -1; } if ( (val.flags&PV_VAL_STR)==0 ) { LM_ERR("PV vals is not string\n"); return -1; } uri = val.rs; } else { if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; } if (extract_aor(&uri, &aor,&sip_instance,&call_id) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain((udomain_t*)_t, &aor); return -1; } if (flags & REG_LOOKUP_UAFILTER_FLAG) { tmp = *(ua+re_len); *(ua+re_len) = '\0'; if (regcomp(&ua_re, ua, regexp_flags) != 0) { LM_ERR("bad regexp '%s'\n", ua); *(ua+re_len) = tmp; return -1; } *(ua+re_len) = tmp; } ptr = r->contacts; ret = -1; /* look first for an un-expired and suported contact */ search_valid_contact: while ( (ptr) && !(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr,flags))) ptr = ptr->next; if (ptr==0) { /* nothing found */ LM_DBG("nothing found !\n"); goto done; } ua_re_check( ret = -1; ptr = ptr->next; goto search_valid_contact ); if (sip_instance.len && sip_instance.s) { LM_DBG("ruri has gruu in lookup\n"); /* uri has GRUU */ if (ptr->instance.len-2 != sip_instance.len || memcmp(ptr->instance.s+1,sip_instance.s,sip_instance.len)) { LM_DBG("no match to sip instace - [%.*s] - [%.*s]\n",ptr->instance.len-2,ptr->instance.s+1, sip_instance.len,sip_instance.s); /* not the targeted instance, search some more */ ptr = ptr->next; goto search_valid_contact; } LM_DBG("matched sip instace\n"); } if (call_id.len && call_id.s) { /* decide whether GRUU is expired or not * * first - match call-id */ if (ptr->callid.len != call_id.len || memcmp(ptr->callid.s,call_id.s,call_id.len)) { LM_DBG("no match to call id - [%.*s] - [%.*s]\n",ptr->callid.len,ptr->callid.s, call_id.len,call_id.s); ptr = ptr->next; goto search_valid_contact; } /* matched call-id, check if there are newer contacts with * same sip instace bup newer last_modified */ it = ptr->next; while ( it ) { if (VALID_CONTACT(it,act_time)) { if (it->instance.len-2 == sip_instance.len && sip_instance.s && memcmp(it->instance.s+1,sip_instance.s,sip_instance.len) == 0) if (it->last_modified > ptr->last_modified) { /* same instance id, but newer modified -> expired GRUU, no match at all */ break; } } it=it->next; } if (it != NULL) { ret = -1; goto done; } } LM_DBG("found a complete match\n"); ret = 1; if (ptr) { LM_DBG("setting as ruri <%.*s>\n",ptr->c.len,ptr->c.s); if (set_ruri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* 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( _m, ptr->q); setbflag( _m, 0, ptr->cflags); if (ptr->sock) _m->force_send_socket = ptr->sock; /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } ptr = ptr->next; } /* Append branches if enabled */ /* If we got to this point and the URI had a ;gr parameter and it was matched * to a contact. No point in branching */ if ( flags®_LOOKUP_NOBRANCH_FLAG || (sip_instance.len && sip_instance.s) ) goto done; LM_DBG("looking for branches\n"); do { for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m,ptr,flags)) { 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; } ua_re_check(continue); /* The same as for the first contact applies for branches * regarding path vs. received. */ LM_DBG("setting branch <%.*s>\n",ptr->c.len,ptr->c.s); if (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; } /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } } } /* 0 branches condition also filled; idx initially -1*/ if (!(flags®_BRANCH_AOR_LOOKUP_FLAG) || idx == nbranches) goto done; /* relsease old aor lock */ ul.unlock_udomain((udomain_t*)_t, &aor); ul.release_urecord(r, 0); /* idx starts from -1 */ uri = branch_uris[idx]; if (extract_aor(&uri, &aor, NULL, &call_id) < 0) { LM_ERR("failed to extract address of record for branch uri\n"); return -3; } /* release old urecord */ /* get lock on new aor */ LM_DBG("getting contacts from aor [%.*s]" "in branch %d\n", aor.len, aor.s, idx); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); goto done; } idx++; ptr = r->contacts; } while (1);
static int ul_contact_event_to_msg(struct sip_msg *req) { static enum ul_attrs { UL_URI, UL_RECEIVED, UL_PATH, UL_QVAL, UL_SOCKET, UL_BFLAGS, UL_ATTR, UL_MAX } ul_attr; /* keep the names of the AVPs aligned with the contact-related events * from USRLOC module !!!! */ static str ul_names[UL_MAX]= {str_init("uri"),str_init("received"), str_init("path"),str_init("qval"), str_init("socket"),str_init("bflags"), str_init("attr") }; static int avp_ids[UL_MAX] = { -1, -1, -1, -1, -1, -1, -1}; int_str vals[UL_MAX]; int proto, port; str host; str path_dst; if (avp_ids[0]==-1) { /* init the avp IDs mapping us on the UL event */ for( ul_attr=0 ; ul_attr<UL_MAX ; ul_attr++ ){ if (parse_avp_spec( &ul_names[ul_attr], &avp_ids[ul_attr])<0) { LM_ERR("failed to init UL AVP %d/%s\n", ul_attr,ul_names[ul_attr].s); avp_ids[0] = -1; return -1; } } } /* fetch the AVP values one by one */ for( ul_attr=0 ; ul_attr<UL_MAX ; ul_attr++ ) { if (search_first_avp(0, avp_ids[ul_attr], &vals[ul_attr], NULL)==NULL){ LM_ERR("cannot find AVP(%d) for event attr %d/%s\n", avp_ids[ul_attr], ul_attr, ul_names[ul_attr].s); return -1; } } /* OK, we have the values, lets inject them into the SIP msg */ LM_DBG("injecting new branch: uri=<%.*s>, received=<%.*s>," "path=<%.*s>, qval=%d, socket=<%.*s>, bflags=%X, attr=<%.*s>\n", vals[UL_URI].s.len, vals[UL_URI].s.s, vals[UL_RECEIVED].s.len, vals[UL_RECEIVED].s.s, vals[UL_PATH].s.len, vals[UL_PATH].s.s, vals[UL_QVAL].n, vals[UL_SOCKET].s.len, vals[UL_SOCKET].s.s, vals[UL_BFLAGS].n, vals[UL_ATTR].s.len, vals[UL_ATTR].s.s); /* contact URI goes as RURI */ if (set_ruri( req, &vals[UL_URI].s)<0) { LM_ERR("failed to set new RURI\n"); return -1; } /* contact PATH goes as path */ if (vals[UL_PATH].s.len) { if (get_path_dst_uri(&vals[UL_PATH].s, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); return -1; } if (set_dst_uri( req, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); return -1; } if (set_path_vector( req, &vals[UL_PATH].s)<0) { LM_ERR("failed to set PATH\n"); return -1; } } else /* contact RECEIVED goes as DURI */ if (vals[UL_RECEIVED].s.len) { if (set_dst_uri( req, &vals[UL_RECEIVED].s)<0) { LM_ERR("failed to set DST URI\n"); return -1; } } /* contact Qval goes as RURI Qval */ set_ruri_q( req, vals[UL_QVAL].n); /* contact BFLAGS goes as RURI bflags */ setb0flags( req, vals[UL_BFLAGS].n); /* socket info */ if (vals[UL_SOCKET].s.len) { if ( parse_phostport( vals[UL_SOCKET].s.s, vals[UL_SOCKET].s.len, &host.s, &host.len, &port, &proto) < 0) { LM_ERR("failed to parse socket from Event attr <%.*s>\n", vals[UL_SOCKET].s.len, vals[UL_SOCKET].s.s); } else { req->force_send_socket = grep_sock_info( &host, (unsigned short)port, (unsigned short)proto); } } return 0; }
int fix_route_dialog(struct sip_msg *req,struct dlg_cell *dlg) { struct dlg_leg *leg; struct hdr_field *it; char * buf,*route,*hdrs,*remote_contact; struct lump* lmp = NULL; int size; rr_t *head = NULL; struct sip_uri fru; int next_strict = 0; if (last_dst_leg<0 || last_dst_leg>=dlg->legs_no[DLG_LEGS_USED]) { log_bogus_dst_leg(dlg); LM_ERR("Script error - validate function before having a dialog\n"); return -1; } leg = & dlg->legs[ last_dst_leg ]; if (dlg->state <= DLG_STATE_EARLY && !(dlg->flags & DLG_FLAG_TOPHIDING)) return 0; /* check in the stored routes */ if ( leg->route_set.len && leg->route_set.s) { if(parse_uri(leg->route_uris[0].s, leg->route_uris[0].len, &fru) < 0) { LM_ERR("Failed to parse SIP uri\n"); return -1; } LM_DBG("Next params [%.*s]\n", fru.params.len, fru.params.s); if(is_strict(&fru.params)) next_strict = 1; } if (req->dst_uri.s && req->dst_uri.len) { /* reset dst_uri if previously set * either by loose route or manually */ pkg_free(req->dst_uri.s); req->dst_uri.s = NULL; req->dst_uri.len = 0; } /* r-uri is taken care of in all below cases, * no need for manual resetting */ //if ((*(d_rrb.routing_type) == ROUTING_LL) || (*d_rrb.routing_type) == ROUTING_SL ) if (!next_strict) { LM_DBG("Fixing message. Next hop is Loose router\n"); if (leg->contact.len && leg->contact.s) { LM_DBG("Setting new URI to <%.*s> \n",leg->contact.len, leg->contact.s); if (set_ruri(req,&leg->contact) != 0) { LM_ERR("failed setting ruri\n"); return -1; } } if( parse_headers( req, HDR_EOH_F, 0)<0 ) { LM_ERR("failed to parse headers when looking after ROUTEs\n"); return -1; } buf = req->buf; if (req->route) { for (it=req->route;it;it=it->sibling) if ((lmp = del_lump(req,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { LM_ERR("del_lump failed \n"); return -1; } } if ( leg->route_set.len !=0 && leg->route_set.s) { lmp = anchor_lump(req,req->headers->name.s - buf,0,0); if (lmp == 0) { LM_ERR("failed anchoring new lump\n"); return -1; } size = leg->route_set.len + ROUTE_LEN + CRLF_LEN; route = pkg_malloc(size+1); if (route == 0) { LM_ERR("no more pkg memory\n"); return -1; } memcpy(route,ROUTE_STR,ROUTE_LEN); memcpy(route+ROUTE_LEN,leg->route_set.s,leg->route_set.len); memcpy(route+ROUTE_LEN+leg->route_set.len,CRLF,CRLF_LEN); route[size] = 0; if ((lmp = insert_new_lump_after(lmp,route,size,HDR_ROUTE_T)) == 0) { LM_ERR("failed inserting new route set\n"); pkg_free(route); return -1; } LM_DBG("Setting route header to <%s> \n",route); if (parse_rr_body(leg->route_set.s,leg->route_set.len,&head) != 0) { LM_ERR("failed parsing route set\n"); return -1; } LM_DBG("setting dst_uri to <%.*s> \n",head->nameaddr.uri.len, head->nameaddr.uri.s); if (set_dst_uri(req,&head->nameaddr.uri) !=0 ) { LM_ERR("failed setting new dst uri\n"); free_rr(&head); return -1; } free_rr(&head); } } else { LM_DBG("Fixing message. Next hop is Strict router\n"); if( parse_headers( req, HDR_EOH_F, 0)<0 ) { LM_ERR("failed to parse headers when looking after ROUTEs\n"); return -1; } buf = req->buf; if (req->route) { for (it=req->route;it;it=it->sibling) if ((lmp = del_lump(req,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { LM_ERR("del_lump failed \n"); return -1; } } if ( leg->route_set.len !=0 && leg->route_set.s) { LM_DBG("setting R-URI to <%.*s> \n",leg->route_uris->len, leg->route_uris->s); if (set_ruri(req,leg->route_uris) !=0 ) { LM_ERR("failed setting new dst uri\n"); return -1; } /* If there are more routes other than the first, add them */ if (leg->nr_uris > 1) { /* FIXME - find a better way to skip the first route header. * Instead or parsing again the entire route set, maybe remmember * the needed pointer at the initial parsing of the route_set */ if (parse_rr_body(leg->route_set.s,leg->route_set.len,&head) != 0) { LM_ERR("failed parsing route set\n"); return -1; } lmp = anchor_lump(req,req->headers->name.s - buf,0,0); if (lmp == 0) { LM_ERR("failed anchoring new lump\n"); free_rr(&head); return -1; } hdrs = leg->route_set.s + head->len + 1; size = leg->route_set.len - head->len - 1 + ROUTE_LEN + CRLF_LEN; route = pkg_malloc(size); if (route == 0) { LM_ERR("no more pkg memory\n"); free_rr(&head); return -1; } memcpy(route,ROUTE_STR,ROUTE_LEN); memcpy(route+ROUTE_LEN,hdrs,leg->route_set.len - head->len-1); memcpy(route+ROUTE_LEN+leg->route_set.len - head->len-1,CRLF,CRLF_LEN); LM_DBG("Adding Route header : [%.*s] \n",size,route); if ((lmp = insert_new_lump_after(lmp,route,size,HDR_ROUTE_T)) == 0) { LM_ERR("failed inserting new route set\n"); pkg_free(route); free_rr(&head); return -1; } free_rr(&head); } if (lmp == NULL) { lmp = anchor_lump(req,req->headers->name.s - buf,0,0); if (lmp == 0) { LM_ERR("failed anchoring new lump\n"); return -1; } } if (leg->contact.len && leg->contact.s) { size = leg->contact.len + ROUTE_PREF_LEN + ROUTE_SUFF_LEN; remote_contact = pkg_malloc(size); if (remote_contact == NULL) { LM_ERR("no more pkg memory\n"); return -1; } memcpy(remote_contact,ROUTE_PREF,ROUTE_PREF_LEN); memcpy(remote_contact+ROUTE_PREF_LEN,leg->contact.s,leg->contact.len); memcpy(remote_contact+ROUTE_PREF_LEN+leg->contact.len, ROUTE_SUFF,ROUTE_SUFF_LEN); LM_DBG("Adding remote contact route header : [%.*s]\n", size,remote_contact); if (insert_new_lump_after(lmp,remote_contact,size,HDR_ROUTE_T) == 0) { LM_ERR("failed inserting remote contact route\n"); pkg_free(remote_contact); return -1; } } } } return 0; }
/* * Previous hop was a strict router, handle this case */ 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, *del_rt; char* rem_off; str uri; struct socket_info *si; unsigned short port, proto; hdr = _m->route; rt = (rr_t*)hdr->parsed; uri = rt->nameaddr.uri; del_rt = NULL; 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) && #ifdef ENABLE_USER_CHECK is_myself(&puri.user, &puri.host, puri.port_no) #else is_myself(&puri.host, puri.port_no) #endif ) { /* double route may occure due different IP and port, so force as * send interface the one advertise in second Route */ set_sip_defaults( puri.port_no, puri.proto); si = grep_sock_info( &puri.host, puri.port_no, puri.proto); if (si) { _m->force_send_socket = si; } else { if (enable_socket_mismatch_warning) LM_WARN("no socket found to match 2nd RR [%d][%.*s:%d]\n", puri.proto, puri.host.len, puri.host.s, puri.port_no); } /* mark route hdr as deleted */ rt->deleted = 1; 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("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; } } else { port = _m->parsed_uri.port_no; proto = _m->parsed_uri.proto; set_sip_defaults(port, proto); si = grep_sock_info( &_m->parsed_uri.host, port, proto); if (si) { _m->force_send_socket = si; } else { if (enable_socket_mismatch_warning) LM_WARN("no socket found to match RR [%d][%.*s:%d]\n", proto, _m->parsed_uri.host.len, _m->parsed_uri.host.s, port); } } /* set the hooks for the params -bogdan * important note: RURI is already parsed by the above function, so * we just used it without any checking */ ctx_rrparam_set( &_m->parsed_uri.params ); if (is_strict(&puri.params)) { LM_DBG("Next hop: '%.*s' is strict router\n", uri.len, ZSW(uri.s)); ctx_routing_set( ROUTING_SS ); /* 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 (set_ruri(_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; } rt->deleted = 1; } else { LM_DBG("Next hop: '%.*s' is loose router\n", uri.len, ZSW(uri.s)); ctx_routing_set( ROUTING_SL ); 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; } del_rt = (rr_t*)hdr->parsed; /* mark route hdr as deleted */ del_rt->deleted = 1; } 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 (set_ruri(_m, &uri) < 0) { LM_ERR("failed to rewrite R-URI\n"); return RR_ERROR; } /* mark remote contact route as deleted */ rt->deleted = 1; /* 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 && prev!=del_rt) { 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 -bogdan */ run_rr_callbacks( _m, ctx_rrparam_get() ); return RR_DRIVEN; }
/* * Build SIP message for destination * param msg SIP message * param isfirst Is first destination * param route Main or branch route block * param response Is for response * param rsptype SIP response type * return MODULE_RETURNCODE_TRUE success MODULE_RETURNCODE_FALSE failure */ static int ospPrepareDestination( struct sip_msg* msg, int isfirst, int route, int response, int* rsptype) { str cnam; char buffer[OSP_HEADERBUF_SIZE]; str newuri = { buffer, sizeof(buffer) }; osp_inbound* inbound = ospGetInboundInfo(); osp_dest* dest = ospGetNextOrigDestination(); int result = MODULE_RETURNCODE_TRUE; if (inbound != NULL) { if (dest != NULL) { if (response) { /* SIP 300 or 380 response */ if (route == OSP_MAIN_ROUTE) { if (dest->srvtype == OSPC_SERVICE_CNAMQUERY) { LM_INFO("prepare CNAM for call_id '%.*s' transaction_id '%llu'\n", dest->callidsize, dest->callid, dest->transid); if (dest->cnam[0] != '\0') { cnam.s = dest->cnam; cnam.len = strlen(dest->cnam); add_avp(_osp_cnam_avptype | AVP_VAL_STR, _osp_cnam_avpid, (int_str)cnam); } dest->lastcode = 380; *rsptype = 380; } else { /* For default service, voice service or ported number query service */ ospRebuildDestUri(&newuri, dest); LM_INFO("prepare route to URI '%.*s' for call_id '%.*s' transaction_id '%llu'\n", newuri.len, newuri.s, dest->callidsize, dest->callid, dest->transid); if (isfirst == OSP_FIRST_ROUTE) { set_ruri(msg, &newuri); } else { append_branch(msg, &newuri, NULL, NULL, Q_UNSPECIFIED, 0, NULL); } /* Do not add route specific OSP information */ dest->lastcode = 300; *rsptype = 300; } } else { LM_ERR("unsupported route block type\n"); result = MODULE_RETURNCODE_FALSE; } } else { /* Single destination or all destinations */ ospRebuildDestUri(&newuri, dest); LM_INFO("prepare route to URI '%.*s' for call_id '%.*s' transaction_id '%llu'\n", newuri.len, newuri.s, dest->callidsize, dest->callid, dest->transid); if (route == OSP_MAIN_ROUTE) { if (isfirst == OSP_FIRST_ROUTE) { set_ruri(msg, &newuri); } else { append_branch(msg, &newuri, NULL, NULL, Q_UNSPECIFIED, 0, NULL); } /* Do not add route specific OSP information */ } else if (route == OSP_BRANCH_ROUTE) { /* For branch route, add route specific OSP information */ /* Update the Request-Line */ set_ruri(msg, &newuri); /* Add OSP token header */ ospAddOspToken(msg, dest->token, dest->tokensize); /* Add branch-specific OSP Cookie */ ospRecordOrigTransaction(msg, inbound, dest); /* Handle calling number translation */ ospSetCalling(msg, inbound, dest); /* Set call attempt start time */ dest->starttime = time(NULL); } else { LM_ERR("unsupported route block type\n"); result = MODULE_RETURNCODE_FALSE; } } } else { LM_DBG("there is no more routes\n"); if (!response) { ospReportOrigSetupUsage(); } result = MODULE_RETURNCODE_FALSE; } } else { LM_ERR("internal error\n"); result = MODULE_RETURNCODE_FALSE; } return result; }
/* * Adds a new parameter to Request URI */ int add_uri_param(struct sip_msg* _msg, char* _param, char* _s2) { str *param, *cur_uri, new_uri; struct sip_uri *parsed_uri; char *at; param = (str*)_param; if (param->len == 0) { return 1; } if (parse_sip_msg_uri(_msg) < 0) { LM_ERR("ruri parsing failed\n"); return -1; } parsed_uri = &(_msg->parsed_uri); /* if current ruri has no headers, pad param at the end */ if (parsed_uri->headers.len == 0) { cur_uri = GET_RURI(_msg); new_uri.len = cur_uri->len + param->len + 1; if (new_uri.len > MAX_URI_SIZE) { LM_ERR("new ruri too long\n"); return -1; } new_uri.s = pkg_malloc(new_uri.len); if (new_uri.s == 0) { LM_ERR("add_uri_param(): Memory allocation failure\n"); return -1; } memcpy(new_uri.s, cur_uri->s, cur_uri->len); *(new_uri.s + cur_uri->len) = ';'; memcpy(new_uri.s + cur_uri->len + 1, param->s, param->len); if (set_ruri(_msg, &new_uri ) == 1) { goto ok; } else { goto nok; } } /* otherwise take the long path */ new_uri.len = 4 + (parsed_uri->user.len ? parsed_uri->user.len + 1 : 0) + (parsed_uri->passwd.len ? parsed_uri->passwd.len + 1 : 0) + parsed_uri->host.len + (parsed_uri->port.len ? parsed_uri->port.len + 1 : 0) + parsed_uri->params.len + param->len + 1 + parsed_uri->headers.len + 1; if (new_uri.len > MAX_URI_SIZE) { LM_ERR("new ruri too long\n"); return -1; } new_uri.s = pkg_malloc(new_uri.len); if (new_uri.s == 0) { LM_ERR("no more pkg memory\n"); return -1; } at = new_uri.s; memcpy(at, "sip:", 4); at = at + 4; if (parsed_uri->user.len) { memcpy(at, parsed_uri->user.s, parsed_uri->user.len); if (parsed_uri->passwd.len) { *at = ':'; at = at + 1; memcpy(at, parsed_uri->passwd.s, parsed_uri->passwd.len); at = at + parsed_uri->passwd.len; }; *at = '@'; at = at + 1; } memcpy(at, parsed_uri->host.s, parsed_uri->host.len); at = at + parsed_uri->host.len; if (parsed_uri->port.len) { *at = ':'; at = at + 1; memcpy(at, parsed_uri->port.s, parsed_uri->port.len); at = at + parsed_uri->port.len; } memcpy(at, parsed_uri->params.s, parsed_uri->params.len); at = at + parsed_uri->params.len; *at = ';'; at = at + 1; memcpy(at, param->s, param->len); at = at + param->len; *at = '?'; at = at + 1; memcpy(at, parsed_uri->headers.s, parsed_uri->headers.len); if (set_ruri(_msg, &new_uri) == 1) { goto ok; } nok: pkg_free(new_uri.s); return -1; ok: pkg_free(new_uri.s); return 1; }
int sd_lookup(struct sip_msg* _msg, char* _table, char* _owner) { static db_ps_t my_ps = NULL; str user_s, table_s, uri_s; int nr_keys; struct sip_uri *puri; struct sip_uri turi; db_key_t db_keys[4]; db_val_t db_vals[4]; db_key_t db_cols[1]; db_res_t* db_res = NULL; if(_table==NULL || fixup_get_svalue(_msg, (gparam_p)_table, &table_s)!=0) { LM_ERR("invalid table parameter"); return -1; } /* init */ nr_keys = 0; db_cols[0]=&new_uri_column; if(_owner) { memset(&turi, 0, sizeof(struct sip_uri)); if(fixup_get_svalue(_msg, (gparam_p)_owner, &uri_s)!=0) { LM_ERR("invalid owner uri parameter"); return -1; } if(parse_uri(uri_s.s, uri_s.len, &turi)!=0) { LM_ERR("bad owner SIP address!\n"); goto err_server; } LM_DBG("using user id [%.*s]\n", uri_s.len, uri_s.s); puri = &turi; } else { /* take username@domain from From header */ if ( (puri = parse_from_uri(_msg ))==NULL ) { LM_ERR("failed to parse FROM header\n"); goto err_server; } } db_keys[nr_keys]=&user_column; db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = puri->user.s; db_vals[nr_keys].val.str_val.len = puri->user.len; nr_keys++; if(use_domain>=1) { db_keys[nr_keys]=&domain_column; db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = puri->host.s; db_vals[nr_keys].val.str_val.len = puri->host.len; nr_keys++; if (dstrip_s.s!=NULL && dstrip_s.len>0 && dstrip_s.len<puri->host.len && strncasecmp(puri->host.s,dstrip_s.s,dstrip_s.len)==0) { db_vals[nr_keys].val.str_val.s += dstrip_s.len; db_vals[nr_keys].val.str_val.len -= dstrip_s.len; } } /* take sd from r-uri */ if (parse_sip_msg_uri(_msg) < 0) { LM_ERR("failed to parsing Request-URI\n"); goto err_server; } db_keys[nr_keys]=&sd_user_column; db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = _msg->parsed_uri.user.s; db_vals[nr_keys].val.str_val.len = _msg->parsed_uri.user.len; nr_keys++; if(use_domain>=2) { db_keys[nr_keys]=&sd_domain_column; db_vals[nr_keys].type = DB_STR; db_vals[nr_keys].nul = 0; db_vals[nr_keys].val.str_val.s = _msg->parsed_uri.host.s; db_vals[nr_keys].val.str_val.len = _msg->parsed_uri.host.len; nr_keys++; if (dstrip_s.s!=NULL && dstrip_s.len>0 && dstrip_s.len<_msg->parsed_uri.host.len && strncasecmp(_msg->parsed_uri.host.s,dstrip_s.s,dstrip_s.len)==0) { db_vals[nr_keys].val.str_val.s += dstrip_s.len; db_vals[nr_keys].val.str_val.len -= dstrip_s.len; } } db_funcs.use_table(db_handle, &table_s); CON_PS_REFERENCE(db_handle) = &my_ps; if(db_funcs.query(db_handle, db_keys, NULL, db_vals, db_cols, nr_keys /*no keys*/, 1 /*no cols*/, NULL, &db_res)!=0) { LM_ERR("failed to query database\n"); goto err_server; } if (RES_ROW_N(db_res)<=0 || RES_ROWS(db_res)[0].values[0].nul != 0) { LM_DBG("no sip addres found for R-URI\n"); if (db_res!=NULL && db_funcs.free_result(db_handle, db_res) < 0) LM_DBG("failed to free result of query\n"); return -1; } user_s.s = useruri_buf+4; switch(RES_ROWS(db_res)[0].values[0].type) { case DB_STRING: strcpy(user_s.s, (char*)RES_ROWS(db_res)[0].values[0].val.string_val); user_s.len = strlen(user_s.s); break; case DB_STR: strncpy(user_s.s, (char*)RES_ROWS(db_res)[0].values[0].val.str_val.s, RES_ROWS(db_res)[0].values[0].val.str_val.len); user_s.len = RES_ROWS(db_res)[0].values[0].val.str_val.len; user_s.s[user_s.len] = '\0'; break; case DB_BLOB: strncpy(user_s.s, (char*)RES_ROWS(db_res)[0].values[0].val.blob_val.s, RES_ROWS(db_res)[0].values[0].val.blob_val.len); user_s.len = RES_ROWS(db_res)[0].values[0].val.blob_val.len; user_s.s[user_s.len] = '\0'; default: LM_ERR("unknown type of DB new_uri column\n"); if (db_res != NULL && db_funcs.free_result(db_handle, db_res) < 0) { LM_DBG("failed to free result of query\n"); } goto err_server; } /* check 'sip:' */ if(user_s.len<4 || strncasecmp(user_s.s, "sip:", 4)) { memcpy(useruri_buf, "sip:", 4); user_s.s -= 4; user_s.len += 4; } /** * Free the result because we don't need it anymore */ if (db_res!=NULL && db_funcs.free_result(db_handle, db_res) < 0) LM_DBG("failed to free result of query\n"); /* set the URI */ LM_DBG("URI of sd from R-URI [%.*s]\n", user_s.len,user_s.s); if(set_ruri(_msg, &user_s)<0) { LM_ERR("failed to replace the R-URI\n"); goto err_server; } return 1; err_server: return -1; }
int enum_pv_query_3(struct sip_msg* _msg, char* _sp, char* _suffix, char* _service) { char *user_s; int user_len, i, j, first; char name[MAX_DOMAIN_SIZE]; char uri[MAX_URI_SIZE]; char new_uri[MAX_URI_SIZE]; unsigned int priority, curr_prio; qvalue_t q; char tostring[17]; struct rdata* head; struct rdata* l; struct naptr_rdata* naptr; str pattern, replacement, result, new_result; str *suffix, *service; char string[17]; pv_spec_t *sp; pv_value_t pv_val; sp = (pv_spec_t *)_sp; suffix = (str*)_suffix; service = (str*)_service; /* * Get R-URI user to tostring */ if (parse_sip_msg_uri(_msg) < 0) { LM_ERR("R-URI parsing failed\n"); return -1; } user_s = _msg->parsed_uri.user.s; user_len = _msg->parsed_uri.user.len; memcpy(&(tostring[0]), user_s, user_len); tostring[user_len] = (char)0; /* * Get E.164 number from pseudo variable */ if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) { if (pv_val.flags & PV_VAL_STR) { if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) { LM_DBG("Missing E.164 number\n"); return -1; } } else { LM_DBG("Pseudo variable value is not string\n"); return -1; } } else { LM_DBG("Cannot get pseudo variable value\n"); return -1; } if (is_e164(&(pv_val.rs)) == -1) { LM_ERR("pseudo variable does not contain an E164 number\n"); return -1; } user_s = pv_val.rs.s; user_len = pv_val.rs.len; memcpy(&(string[0]), user_s, user_len); string[user_len] = (char)0; j = 0; for (i = user_len - 1; i > 0; i--) { name[j] = user_s[i]; name[j + 1] = '.'; j = j + 2; } memcpy(name + j, suffix->s, suffix->len + 1); head = get_record(name, T_NAPTR); if (head == 0) { LM_DBG("No NAPTR record found for %s.\n", name); return -1; } naptr_sort(&head); q = MAX_Q - 10; curr_prio = 0; first = 1; for (l = head; l; l = l->next) { if (l->type != T_NAPTR) continue; /*should never happen*/ naptr = (struct naptr_rdata*)l->rdata; if (naptr == 0) { LM_ERR("Null rdata in DNS response\n"); continue; } LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags " "'%.*s', slen %u, services '%.*s', rlen %u, " "regexp '%.*s'\n", name, naptr->order, naptr->pref, naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len, (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, (int)(naptr->regexp_len), ZSW(naptr->regexp)); if (sip_match(naptr, service) == 0) continue; if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, &pattern, &replacement) < 0) { LM_ERR("Parsing of NAPTR regexp failed\n"); continue; } result.s = &(uri[0]); result.len = MAX_URI_SIZE; /* Avoid making copies of pattern and replacement */ pattern.s[pattern.len] = (char)0; replacement.s[replacement.len] = (char)0; if (reg_replace(pattern.s, replacement.s, &(tostring[0]), &result) < 0) { pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; LM_ERR("Regexp replace failed\n"); continue; } LM_DBG("Resulted in replacement: '%.*s'\n", result.len, ZSW(result.s)); pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; if (param.len > 0) { if (result.len + param.len > MAX_URI_SIZE - 1) { LM_ERR("URI is too long\n"); continue; } new_result.s = &(new_uri[0]); new_result.len = MAX_URI_SIZE; if (add_uri_param(&result, ¶m, &new_result) == 0) { LM_ERR("Parsing of URI <%.*s> failed\n", result.len, result.s); continue; } if (new_result.len > 0) { result = new_result; } } if (first) { if (set_ruri(_msg, &result) == -1) { goto done; } set_ruri_q(q); first = 0; curr_prio = ((naptr->order) << 16) + naptr->pref; } else { priority = ((naptr->order) << 16) + naptr->pref; if (priority > curr_prio) { q = q - 10; curr_prio = priority; } if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) { goto done; } } } done: free_rdata_list(head); return first ? -1 : 1; }
/* ret= 0! if action -> end of list(e.g DROP), > 0 to continue processing next actions and <0 on error */ int do_action(struct action* a, struct sip_msg* msg) { int ret; int v; int sec,usec; union sockaddr_union* to; struct proxy_l* p; char* tmp; char *new_uri, *end, *crt; int len,i; int user = 0; int expires = 0; str vals[5]; str result; struct sip_uri uri, next_hop; struct sip_uri *u; unsigned short port; int cmatch; struct action *aitem; struct action *adefault; pv_spec_t *spec; pv_elem_p model; pv_value_t val; pv_elem_t *pve; str name_s; struct timeval start; int end_time; action_elem_t *route_params_bak; int route_params_number_bak; /* reset the value of error to E_UNSPEC so avoid unknowledgable functions to return with error (status<0) and not setting it leaving there previous error; cache the previous value though for functions which want to process it */ prev_ser_error=ser_error; ser_error=E_UNSPEC; start_expire_timer(start,execmsgthreshold); ret=E_BUG; switch ((unsigned char)a->type){ case DROP_T: script_trace("core", "drop", msg, a->line) ; action_flags |= ACT_FL_DROP; case EXIT_T: script_trace("core", "exit", msg, a->line) ; ret=0; action_flags |= ACT_FL_EXIT; break; case RETURN_T: script_trace("core", "return", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL)) { ret=-1; } else { if(!(val.flags&PV_VAL_INT)) ret = 1; else ret = val.ri; } pv_value_destroy(&val); } else { ret=a->elem[0].u.number; } action_flags |= ACT_FL_RETURN; break; case FORWARD_T: script_trace("core", "forward", msg, a->line) ; if (a->elem[0].type==NOSUBTYPE){ /* parse uri and build a proxy */ if (msg->dst_uri.len) { ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop); u = &next_hop; } else { ret = parse_sip_msg_uri(msg); u = &msg->parsed_uri; } if (ret<0) { LM_ERR("forward: bad_uri dropping packet\n"); break; } /* create a temporary proxy*/ p=mk_proxy(u->maddr_val.len?&u->maddr_val:&u->host, u->port_no, u->proto, (u->type==SIPS_URI_T)?1:0 ); if (p==0){ LM_ERR("bad host name in uri, dropping packet\n"); ret=E_BAD_ADDRESS; goto error_fwd_uri; } ret=forward_request(msg, p); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); if (ret==0) ret=1; }else if ((a->elem[0].type==PROXY_ST)) { ret=forward_request(msg,(struct proxy_l*)a->elem[0].u.data); if (ret==0) ret=1; }else{ LM_ALERT("BUG in forward() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; } break; case SEND_T: script_trace("core", "send", msg, a->line) ; if (a->elem[0].type!= PROXY_ST){ LM_ALERT("BUG in send() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->elem[1].u.data) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST){ LM_ALERT("BUG in send() header type %d\n",a->elem[1].type); ret=E_BUG; break; } else { pve = (pv_elem_t *)a->elem[1].u.data; } } else { pve = NULL; } to=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } p=(struct proxy_l*)a->elem[0].u.data; ret=hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT ); if (ret==0){ if (pve) { if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_UNSPEC; break; } /* build new msg */ tmp = pkg_malloc(msg->len + name_s.len); if (!tmp) { LM_ERR("memory allocation failure\n"); ret = E_OUT_OF_MEM; break; } LM_DBG("searching for first line %d\n", msg->first_line.len); /* search first line of previous msg */ /* copy headers */ len = msg->first_line.len; memcpy(tmp, msg->buf, len); memcpy(tmp + len, name_s.s, name_s.len); memcpy(tmp + len + name_s.len, msg->buf + len, msg->len - len); ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, tmp, msg->len + name_s.len); pkg_free(tmp); } else { ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, msg->buf, msg->len); } if (ret!=0 && p->host.h_addr_list[p->addr_idx+1]) p->addr_idx++; } pkg_free(to); if (ret==0) ret=1; break; case LOG_T: script_trace("core", "log", msg, a->line) ; if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in log() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_GEN1(a->elem[0].u.number, "%s", a->elem[1].u.string); ret=1; break; case APPEND_BRANCH_T: script_trace("core", "append_branch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in append_branch %d\n", a->elem[0].type ); ret=E_BUG; break; } if (a->elem[0].u.s.s==NULL) { ret = append_branch(msg, 0, &msg->dst_uri, &msg->path_vec, get_ruri_q(), getb0flags(), msg->force_send_socket); /* reset all branch info */ msg->force_send_socket = 0; setb0flags(0); set_ruri_q(Q_UNSPECIFIED); 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; } else { ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, &msg->path_vec, a->elem[1].u.number, getb0flags(), msg->force_send_socket); } break; case REMOVE_BRANCH_T: script_trace("core", "remove_branch", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if( pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL) || !(val.flags&PV_VAL_INT) ) { ret=-1; break; } i = val.ri; } else { i=a->elem[0].u.number; } ret = (remove_branch((unsigned int)i)==0)?1:-1; break; case LEN_GT_T: script_trace("core", "len_gt", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in len_gt type %d\n", a->elem[0].type ); ret=E_BUG; break; } ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1; break; case SET_DEBUG_T: script_trace("core", "set_debug", msg, a->line) ; if (a->elem[0].type==NUMBER_ST) set_proc_debug_level(a->elem[0].u.number); else reset_proc_debug_level(); ret = 1; break; case SETFLAG_T: script_trace("core", "setflag", msg, a->line) ; ret = setflag( msg, a->elem[0].u.number ); break; case RESETFLAG_T: script_trace("core", "resetflag", msg, a->line) ; ret = resetflag( msg, a->elem[0].u.number ); break; case ISFLAGSET_T: script_trace("core", "isflagset", msg, a->line) ; ret = isflagset( msg, a->elem[0].u.number ); break; case SETSFLAG_T: script_trace("core", "setsflag", msg, a->line) ; ret = setsflag( a->elem[0].u.number ); break; case RESETSFLAG_T: script_trace("core", "resetsflag", msg, a->line) ; ret = resetsflag( a->elem[0].u.number ); break; case ISSFLAGSET_T: script_trace("core", "issflagset", msg, a->line) ; ret = issflagset( a->elem[0].u.number ); break; case SETBFLAG_T: script_trace("core", "setbflag", msg, a->line) ; ret = setbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case RESETBFLAG_T: script_trace("core", "resetbflag", msg, a->line) ; ret = resetbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case ISBFLAGSET_T: script_trace("core", "isbflagset", msg, a->line) ; ret = isbflagset( a->elem[0].u.number, a->elem[1].u.number ); break; case ERROR_T: script_trace("core", "error", msg, a->line) ; if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in error() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_ERR("error(\"%s\", \"%s\") not implemented yet\n", a->elem[0].u.string, a->elem[1].u.string); ret=1; break; case ROUTE_T: script_trace("route", rlist[a->elem[0].u.number].name, msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in route() type %d\n", a->elem[0].type); ret=E_BUG; break; } if ((a->elem[0].u.number>RT_NO)||(a->elem[0].u.number<0)){ LM_ALERT("BUG - invalid routing table number in" "route(%lu)\n", a->elem[0].u.number); ret=E_CFG; break; } /* check if the route has parameters */ if (a->elem[1].type != 0) { if (a->elem[1].type != NUMBER_ST || a->elem[2].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in route() type %d/%d\n", a->elem[1].type, a->elem[2].type); ret=E_BUG; break; } route_params_bak = route_params; route_params = (action_elem_t *)a->elem[2].u.data; route_params_number_bak = route_params_number; route_params_number = a->elem[1].u.number; return_code=run_actions(rlist[a->elem[0].u.number].a, msg); route_params = route_params_bak; route_params_number = route_params_number_bak; } else { return_code=run_actions(rlist[a->elem[0].u.number].a, msg); } ret=return_code; break; case REVERT_URI_T: script_trace("core", "revert_uri", msg, a->line) ; if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; /* invalidate current parsed uri*/ }; ret=1; break; case SET_HOST_T: case SET_HOSTPORT_T: case SET_USER_T: case SET_USERPASS_T: case SET_PORT_T: case SET_URI_T: case PREFIX_T: case STRIP_T: case STRIP_TAIL_T: script_trace("core", (unsigned char)a->type == SET_HOST_T ? "set_host" : (unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : (unsigned char)a->type == SET_USER_T ? "set_user" : (unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : (unsigned char)a->type == SET_PORT_T ? "set_port" : (unsigned char)a->type == SET_URI_T ? "set_uri" : (unsigned char)a->type == PREFIX_T ? "prefix" : (unsigned char)a->type == STRIP_T ? "strip" : "strip_tail", msg, a->line); user=0; if (a->type==STRIP_T || a->type==STRIP_TAIL_T) { if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); break; } } else if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->type==SET_URI_T) { if (set_ruri( msg, &a->elem[0].u.s) ) { LM_ERR("failed to set new RURI\n"); ret=E_OUT_OF_MEM; break; } ret=1; break; } if (msg->new_uri.s) { tmp=msg->new_uri.s; len=msg->new_uri.len; }else{ tmp=msg->first_line.u.request.uri.s; len=msg->first_line.u.request.uri.len; } if (parse_uri(tmp, len, &uri)<0){ LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); ret=E_UNSPEC; break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; /* begin copying */ len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; if (a->type==PREFIX_T) { if (crt+a->elem[0].u.s.len>end) goto error_uri; memcpy( crt, a->elem[0].u.s.s, a->elem[0].u.s.len); crt+=a->elem[0].u.s.len; /* whatever we had before, with prefix we have username now */ user=1; } if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else if (a->type==STRIP_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip asked; " " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s + a->elem[0].u.number; len=uri.user.len - a->elem[0].u.number; } } else if (a->type==STRIP_TAIL_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip_tail asked;" " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s; len=uri.user.len - a->elem[0].u.number; } } else { tmp=uri.user.s; len=uri.user.len; } if (len){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; user=1; /* we have an user field so mark it */ } if (a->type==SET_USERPASS_T) tmp=0; else tmp=uri.passwd.s; /* passwd */ if (tmp){ len=uri.passwd.len; if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* host */ if (user || tmp){ /* add @ */ if(crt+1>end) goto error_uri; *crt='@'; crt++; } if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.host.s; len = uri.host.len; } if (tmp){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; } /* port */ if (a->type==SET_HOSTPORT_T) tmp=0; else if (a->type==SET_PORT_T) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.port.s; len = uri.port.len; } if (tmp && len>0){ if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* params */ tmp=uri.params.s; if (tmp){ /* include in param string the starting ';' */ len=uri.params.len+1; tmp--; if(crt+len+1>end) goto error_uri; /* if a maddr param is present, strip it out */ if (uri.maddr.len && (a->type==SET_HOSTPORT_T || a->type==SET_HOST_T)) { memcpy(crt,tmp,uri.maddr.s-tmp-1); crt+=uri.maddr.s-tmp-1; memcpy(crt,uri.maddr_val.s+uri.maddr_val.len, tmp+len-uri.maddr_val.s-uri.maddr_val.len); crt+=tmp+len-uri.maddr_val.s-uri.maddr_val.len; } else { memcpy(crt,tmp,len);crt+=len; } } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt='?'; crt++; memcpy(crt,tmp,len);crt+=len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri.s=new_uri; msg->new_uri.len=crt-new_uri; msg->parsed_uri_ok=0; ret=1; break; case SET_DSTURI_T: script_trace("core", "set_dsturi", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in setdsturi() type %d\n", a->elem[0].type); ret=E_BUG; break; } if(set_dst_uri(msg, &a->elem[0].u.s)!=0) ret = -1; else ret = 1; break; case SET_DSTHOST_T: case SET_DSTPORT_T: script_trace("core", (unsigned char) a->type == SET_DSTHOST_T ? "set_dsturi" : "set_dstport", msg, a->line); if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in domain setting type %d\n", a->elem[0].type); ret=E_BUG; break; } tmp = msg->dst_uri.s; len = msg->dst_uri.len; if (tmp == NULL || len == 0) { LM_ERR("failure - null uri\n"); ret = E_UNSPEC; break; } if (a->type == SET_DSTHOST_T && (a->elem[0].u.s.s == NULL || a->elem[0].u.s.len == 0)) { LM_ERR("cannot set a null uri domain\n"); break; } if (parse_uri(tmp, len, &uri)<0) { LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri == NULL) { LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; /* user */ tmp = uri.user.s; len = uri.user.len; if (tmp) { if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; user = 1; } /* passwd */ tmp = uri.passwd.s; len = uri.passwd.len; if (user || tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* host */ if (a->type==SET_DSTHOST_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.host.s; len = uri.host.len; } if (tmp) { if (user) { if (crt+1>end) goto error_uri; *crt++='@'; } if (crt+len+1>end) goto error_uri; memcpy(crt, tmp, len); crt += len; } /* port */ if (a->type==SET_DSTPORT_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.port.s; len = uri.port.len; } if (tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* params */ tmp=uri.params.s; if (tmp){ len=uri.params.len; if(crt+len+1>end) goto error_uri; *crt++=';'; memcpy(crt,tmp,len); crt += len; } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt++='?'; memcpy(crt,tmp,len); crt += len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ pkg_free(msg->dst_uri.s); msg->dst_uri.s=new_uri; msg->dst_uri.len=crt-new_uri; ret = 1; break; case RESET_DSTURI_T: script_trace("core", "reset_dsturi", msg, a->line) ; if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; ret = 1; break; case ISDSTURISET_T: script_trace("core", "isdsturiset", msg, a->line) ; if(msg->dst_uri.s==0 || msg->dst_uri.len<=0) ret = -1; else ret = 1; break; case IF_T: script_trace("core", "if", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ /* hack to quit on DROP*/ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); return_code = ret; } else return_code = v; }else{ if ((a->elem[2].type==ACTIONS_ST)&&a->elem[2].u.data){ ret=run_action_list( (struct action*)a->elem[2].u.data,msg); return_code = ret; } else return_code = v; } } break; case WHILE_T: script_trace("core", "while", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ len = 0; while(1) { if(len++ >= max_while_loops) { LM_INFO("max while loops are encountered\n"); break; } v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST) &&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); /* check if return was done */ if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ break; } return_code = ret; } else { /* we should not get here */ return_code = v; break; } } else { /* condition was false */ return_code = v; break; } } } break; case CACHE_STORE_T: script_trace("core", "cache_store", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } if ((a->elem[2].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - third argument not of type" " string%d\n", a->elem[2].type ); ret=E_BUG; break; } str val_s; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* parse the value argument */ pve = (pv_elem_t *)a->elem[2].u.data; if ( pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* get the expires value */ if ( a->elem[3].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[3].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_store\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_store expires, not an integer [%.*s]\n", val.rs.len, val.rs.s); } expires = val.ri; } else if ( a->elem[3].type == NUMBER_ST ) { expires = (int)a->elem[3].u.number; } ret = cachedb_store( &a->elem[0].u.s, &name_s, &val_s,expires); break; case CACHE_REMOVE_T: script_trace("core", "cache_remove", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_remove( &a->elem[0].u.s, &name_s); break; case CACHE_FETCH_T: script_trace("core", "cache_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } str aux = {0, 0}; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_fetch( &a->elem[0].u.s, &name_s, &aux); if(ret > 0) { val.rs = aux; val.flags = PV_VAL_STR; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } pkg_free(aux.s); } break; case CACHE_COUNTER_FETCH_T: script_trace("core", "cache_counter_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } int aux_counter; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_counter_fetch( &a->elem[0].u.s, &name_s, &aux_counter); if(ret > 0) { val.ri = aux_counter; val.flags = PV_TYPE_INT|PV_VAL_INT; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } } break; case CACHE_ADD_T: script_trace("core", "cache_add", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int increment=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_add\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_add, not an integer [%.*s]\n", val.rs.len, val.rs.s); } increment = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { increment = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return the new value to script ? */ ret = cachedb_add(&a->elem[0].u.s, &name_s, increment,expires,NULL); break; case CACHE_SUB_T: script_trace("core", "cache_sub", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int decrement=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_sub\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_sub, not an integer [%.*s]\n", val.rs.len, val.rs.s); } decrement = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { decrement = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return new value to script ? */ ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,NULL); break; case CACHE_RAW_QUERY_T: if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].u.data != NULL && a->elem[2].type!=STR_ST){ LM_ALERT("BUG in cache_raw_query() type %d\n", a->elem[2].type); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } cdb_raw_entry **cdb_reply; int val_number=0,i,j; int key_number=0; pvname_list_t *cdb_res,*it; int_str avp_val; int_str avp_name; unsigned short avp_type; if (a->elem[2].u.data) { cdb_res = (pvname_list_t*)a->elem[2].u.data; for (it=cdb_res;it;it=it->next) val_number++; LM_DBG("The query expects %d results back\n",val_number); ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, &cdb_reply,val_number,&key_number); if (ret >= 0 && val_number > 0) { for (i=key_number-1; i>=0;i--) { it=cdb_res; for (j=0;j < val_number;j++) { avp_type = 0; if (pv_get_avp_name(msg,&it->sname.pvp,&avp_name.n, &avp_type) != 0) { LM_ERR("cannot get avp name [%d/%d]\n",i,j); goto next_avp; } switch (cdb_reply[i][j].type) { case CDB_INT: avp_val.n = cdb_reply[i][j].val.n; break; case CDB_STR: avp_type |= AVP_VAL_STR; avp_val.s = cdb_reply[i][j].val.s; break; default: LM_WARN("Unknown type %d\n",cdb_reply[i][j].type); goto next_avp; } if (add_avp(avp_type,avp_name.n,avp_val) != 0) { LM_ERR("Unable to add AVP\n"); free_raw_fetch(cdb_reply,val_number,key_number); return -1; } next_avp: if (it) { it = it->next; if (it==NULL); break; } } } free_raw_fetch(cdb_reply,val_number,key_number); } } else ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, NULL,0,NULL); break; case XDBG_T: script_trace("core", "xdbg", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ELEM_ST) { if (xdbg(msg, a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print message"); break; } } else { LM_ALERT("BUG in xdbg() type %d\n", a->elem[0].type); ret=E_BUG; } break; case XLOG_T: script_trace("core", "xlog", msg, a->line) ; if (a->elem[1].u.data != NULL) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type); ret=E_BUG; break; } if (a->elem[0].type != STR_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } else { if (a->elem[0].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_1(msg,a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } break; case RAISE_EVENT_T: script_trace("core", "raise_event", msg, a->line) ; if (a->elem[0].type != NUMBER_ST) { LM_ERR("invalid event id\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { /* three parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, a->elem[1].u.data, a->elem[2].u.data); } else { /* two parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, NULL, a->elem[1].u.data); } if (ret <= 0) { LM_ERR("cannot raise event\n"); ret=E_UNSPEC; break; } break; case SUBSCRIBE_EVENT_T: script_trace("core", "subscribe_event", msg, a->line) ; if (a->elem[0].type != STR_ST || a->elem[1].type != STR_ST) { LM_ERR("BUG in subscribe arguments\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { if (a->elem[2].type != NUMBER_ST) { LM_ERR("BUG in subscribe expiration time\n"); ret=E_BUG; break; } else { i = a->elem[2].u.number; } } else { i = 0; } name_s.s = a->elem[0].u.data; name_s.len = strlen(name_s.s); /* result should be the socket */ result.s = a->elem[1].u.data; result.len = strlen(result.s); ret = evi_event_subscribe(name_s, result, i, 0); break; case CONSTRUCT_URI_T: script_trace("core", "construct_uri", msg, a->line) ; for (i=0;i<5;i++) { pve = (pv_elem_t *)a->elem[i].u.data; if (pve->spec.getf) { if ( pv_printf_s(msg, pve, &vals[i])!=0 || vals[i].len == 0 || vals[i].s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; return -1; } } else vals[i] = pve->text; } result.s = construct_uri(&vals[0],&vals[1],&vals[2],&vals[3],&vals[4], &result.len); if (result.s) { int_str res; int avp_name; unsigned short avp_type; spec = (pv_spec_t*)a->elem[5].u.data; if (pv_get_avp_name( msg, &(spec->pvp), &avp_name, &avp_type)!=0){ LM_CRIT("BUG in getting AVP name\n"); return -1; } res.s = result; if (add_avp(AVP_VAL_STR|avp_type, avp_name, res)<0){ LM_ERR("cannot add AVP\n"); return -1; } } break; case GET_TIMESTAMP_T: script_trace("core", "get_timestamp", msg, a->line) ; if (get_timestamp(&sec,&usec) == 0) { int avp_name; int_str res; unsigned short avp_type; spec = (pv_spec_t*)a->elem[0].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = sec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } spec = (pv_spec_t*)a->elem[1].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = usec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } } else { LM_ERR("failed to get time\n"); return -1; } break; case SWITCH_T: script_trace("core", "switch", msg, a->line) ; if (a->elem[0].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in switch() type %d\n", a->elem[0].type); ret=E_BUG; break; } spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0) { LM_ALERT("BUG - no value in switch()\n"); ret=E_BUG; break; } /* get the value of pvar */ if(a->elem[1].type!=ACTIONS_ST) { LM_ALERT("BUG in switch() actions\n"); ret=E_BUG; break; } return_code=1; adefault = NULL; aitem = (struct action*)a->elem[1].u.data; cmatch=0; while(aitem) { if((unsigned char)aitem->type==DEFAULT_T) adefault=aitem; if(cmatch==0) { if(aitem->elem[0].type==STR_ST) { if(val.flags&PV_VAL_STR && val.rs.len==aitem->elem[0].u.s.len && strncasecmp(val.rs.s, aitem->elem[0].u.s.s, val.rs.len)==0) cmatch = 1; } else { /* number */ if(val.flags&PV_VAL_INT && val.ri==aitem->elem[0].u.number) cmatch = 1; } } if(cmatch==1) { if(aitem->elem[1].u.data) { return_code=run_action_list( (struct action*)aitem->elem[1].u.data, msg); if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT)) break; } if(aitem->elem[2].u.number==1) break; } aitem = aitem->next; } if((cmatch==0) && (adefault!=NULL)) { LM_DBG("switch: running default statement\n"); if(adefault->elem[0].u.data) return_code=run_action_list( (struct action*)adefault->elem[0].u.data, msg); } ret=return_code; break; case MODULE_T: script_trace("module", ((cmd_export_t*)(a->elem[0].u.data))->name, msg, a->line) ; if ( (a->elem[0].type==CMD_ST) && a->elem[0].u.data ) { ret=((cmd_export_t*)(a->elem[0].u.data))->function(msg, (char*)a->elem[1].u.data, (char*)a->elem[2].u.data, (char*)a->elem[3].u.data, (char*)a->elem[4].u.data, (char*)a->elem[5].u.data, (char*)a->elem[6].u.data); }else{ LM_ALERT("BUG in module call\n"); } break; case FORCE_RPORT_T: script_trace("core", "force_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_RPORT; ret=1; /* continue processing */ break; case FORCE_LOCAL_RPORT_T: script_trace("core", "force_local_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_LOCAL_RPORT; ret=1; /* continue processing */ break; case SET_ADV_ADDR_T: script_trace("core", "set_adv_addr", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_address() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } str adv_addr; pve = (pv_elem_t *)a->elem[0].u.data; if ( pv_printf_s(msg, pve, &adv_addr)!=0 || adv_addr.len == 0 || adv_addr.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } LM_DBG("adv address = [%.*s]\n",adv_addr.len,adv_addr.s); msg->set_global_address=adv_addr; ret=1; /* continue processing */ break; case SET_ADV_PORT_T: script_trace("core", "set_adv_port", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_port() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } msg->set_global_port=*((str*)a->elem[0].u.data); ret=1; /* continue processing */ break; #ifdef USE_TCP case FORCE_TCP_ALIAS_T: script_trace("core", "force_tcp_alias", msg, a->line) ; if ( msg->rcv.proto==PROTO_TCP #ifdef USE_TLS || msg->rcv.proto==PROTO_TLS #endif ){ if (a->elem[0].type==NOSUBTYPE) port=msg->via1->port; else if (a->elem[0].type==NUMBER_ST) port=(int)a->elem[0].u.number; else{ LM_ALERT("BUG in force_tcp_alias" " port type %d\n", a->elem[0].type); ret=E_BUG; break; } if (tcpconn_add_alias(msg->rcv.proto_reserved1, port, msg->rcv.proto)!=0){ LM_ERR("tcp alias failed\n"); ret=E_UNSPEC; break; } } #endif ret=1; /* continue processing */ break; case FORCE_SEND_SOCKET_T: script_trace("core", "force_send_socket", msg, a->line) ; if (a->elem[0].type!=SOCKETINFO_ST){ LM_ALERT("BUG in force_send_socket argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } msg->force_send_socket=(struct socket_info*)a->elem[0].u.data; ret=1; /* continue processing */ break; case SERIALIZE_BRANCHES_T: script_trace("core", "serialize_branches", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in serialize_branches argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } if (serialize_branches(msg,(int)a->elem[0].u.number)!=0) { LM_ERR("serialize_branches failed\n"); ret=E_UNSPEC; break; } ret=1; /* continue processing */ break; case NEXT_BRANCHES_T: script_trace("core", "next_branches", msg, a->line) ; if ((ret=next_branches(msg))<0) { LM_ERR("next_branches failed\n"); ret=E_UNSPEC; break; } /* continue processing */ break; case EQ_T: case COLONEQ_T: case PLUSEQ_T: case MINUSEQ_T: case DIVEQ_T: case MULTEQ_T: case MODULOEQ_T: case BANDEQ_T: case BOREQ_T: case BXOREQ_T: ret = do_assign(msg, a); break; case USE_BLACKLIST_T: script_trace("core", "use_blacklist", msg, a->line) ; mark_for_search((struct bl_head*)a->elem[0].u.data, 1); break; case UNUSE_BLACKLIST_T: script_trace("core", "unuse_blacklist", msg, a->line); mark_for_search((struct bl_head*)a->elem[0].u.data, 0); break; case PV_PRINTF_T: script_trace("core", "pv_printf", msg, a->line); ret = -1; spec = (pv_spec_p)a->elem[0].u.data; if(!pv_is_w(spec)) { LM_ERR("read only PV in first parameter of pv_printf\n"); goto error; } model = (pv_elem_p)a->elem[1].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_printf_s(msg, model, &val.rs)!=0) { LM_ERR("cannot eval second parameter\n"); goto error; } val.flags = PV_VAL_STR; if(pv_set_value(msg, spec, EQ_T, &val)<0) { LM_ERR("setting PV failed\n"); goto error; } ret = 1; break; case SCRIPT_TRACE_T: script_trace("core", "script_trace", msg, a->line); if (a->elem[0].type==NOSUBTYPE) { use_script_trace = 0; } else { use_script_trace = 1; if (a->elem[0].type != NUMBER_ST || a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ERR("BUG in use_script_trace() arguments\n"); ret=E_BUG; break; } if (a->elem[2].type!=NOSUBTYPE) { script_trace_info = (char *)a->elem[2].u.data; } else { script_trace_info = NULL; } script_trace_log_level = (int)a->elem[0].u.number; script_trace_elem = *(pv_elem_p)a->elem[1].u.data; } break; default: LM_ALERT("BUG - unknown type %d\n", a->type); goto error; } if((unsigned char)a->type!=IF_T && (unsigned char)a->type!=ROUTE_T) return_code = ret; /*skip:*/ update_longest_action(); return ret; error: LM_ERR("error at line: %d\n", a->line); update_longest_action(); return ret; error_uri: LM_ERR("set*: uri too long\n"); if (new_uri) pkg_free(new_uri); update_longest_action(); return E_UNSPEC; error_fwd_uri: update_longest_action(); return ret; }
/*! \brief * Adds to request a destination set that includes all highest priority * class contacts in "serial_avp" AVP. If called from a route block, * rewrites the request uri with first contact and adds the remaining * contacts as branches. If called from failure route block, adds all * contacts as brances. Removes added contacts from "serial_avp" AVP. */ int next_branches( struct sip_msg *msg) { struct usr_avp *avp, *prev; int_str val; struct socket_info *sock_info; qvalue_t q; str uri, dst_uri, path; char *p; unsigned int flags; int rval; if (route_type != REQUEST_ROUTE && route_type != FAILURE_ROUTE ) { /* unsupported route type */ LM_ERR("called from unsupported route type %d\n", route_type); goto error; } /* Find first avp */ avp = search_first_avp(0, serial_avp, &val, 0); if (!avp) { LM_DBG("no AVPs -- we are done!\n"); goto error; } if (!val.s.s) { LM_ERR("invalid avp value\n"); goto error; } /* *sock_info, flags, q, uri, 0, dst_uri, 0, path, 0,... */ p = val.s.s; sock_info = (struct socket_info*) *((long*) p); p += sizeof(long); flags = (unsigned int) *((long*) p); p += sizeof(long); q = (unsigned int) *((long*) p); p += sizeof(long); uri.s = p; uri.len = strlen(p); p += uri.len + 1; dst_uri.s = p; dst_uri.len = strlen(p); p += dst_uri.len + 1; path.s = p; path.len = strlen(p); /* Set Request-URI */ if ( set_ruri(msg, &uri) == -1 || set_dst_uri(msg, &dst_uri) == -1 || set_path_vector(msg, &path) == -1 ) goto error1; msg->force_send_socket = sock_info; set_ruri_q( q ); setb0flags( flags ); LM_DBG("Msg information <%.*s,%.*s,%.*s,%d,%u> (avp flag=%u)\n", uri.len, uri.s, dst_uri.len, dst_uri.s, path.len, path.s, q, flags, avp->flags); if (avp->flags & Q_FLAG) { destroy_avp(avp); goto done; } prev = avp; avp = search_next_avp(prev, &val); destroy_avp(prev); /* Append branches until out of branches or Q_FLAG is set */ while (avp != NULL) { if (!val.s.s) { LM_ERR("invalid avp value\n"); continue; } p = val.s.s; sock_info = (struct socket_info*) *((long*) p); p += sizeof(long); flags = (unsigned int) *((long*) p); p += sizeof(long); q = (unsigned int) *((long*) p); p += sizeof(long); uri.s = p; uri.len = strlen(p); p += strlen(p) + 1; dst_uri.s = p; dst_uri.len = strlen(p); p += strlen(p) + 1; path.s = p; path.len = strlen(p); LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u> (avp flag=%u)\n", uri.len, uri.s, dst_uri.len, dst_uri.s, path.len, path.s, q, flags, avp->flags); rval = append_branch(msg, &uri, &dst_uri, &path, q, flags, sock_info); if (rval == -1) { LM_ERR("append_branch failed\n"); goto error1; } if (avp->flags & Q_FLAG) { destroy_avp(avp); goto done; } prev = avp; avp = search_next_avp(prev, &val); destroy_avp(prev); } return 2; done: return (search_next_avp(avp, NULL)==NULL)?2:1; error1: destroy_avp(avp); error: return -1; }
int exec_str(struct sip_msg *msg, char *cmd, char *param, int param_len) { int cmd_len; FILE *pipe; char *cmd_line; int ret; int l1; static char uri_line[MAX_URI_SIZE+1]; int uri_cnt; str uri; int exit_status; pid_t pid; /* pessimist: assume error by default */ ret=-1; l1=strlen(cmd); if(param_len>0) cmd_len=l1+param_len+4; else cmd_len=l1+1; cmd_line=pkg_malloc(cmd_len); if (cmd_line==0) { ret=ser_error=E_OUT_OF_MEM; LM_ERR("no pkg mem for command\n"); goto error00; } /* 'command parameter \0' */ memcpy(cmd_line, cmd, l1); if(param_len>0) { cmd_line[l1]=' '; cmd_line[l1+1]='\''; memcpy(cmd_line+l1+2, param, param_len); cmd_line[l1+param_len+2]='\''; cmd_line[l1+param_len+3]=0; } else { cmd_line[l1] = 0; } pid = __popen3(cmd_line, NULL, &pipe, NULL); if (pid < 0) { LM_ERR("failed to run command: %s\n", cmd_line); ser_error=E_EXEC; goto error01; } LM_DBG("Forked pid %d\n", pid); schedule_to_kill(pid); wait(&exit_status); /* read now line by line */ uri_cnt=0; while (fgets(uri_line, MAX_URI_SIZE, pipe)) { uri.s = uri_line; uri.len=strlen(uri.s); trim_trailing(&uri); /* skip empty line */ if (uri.len==0) continue; /* ZT */ uri.s[uri.len]=0; if (uri_cnt==0) { if (set_ruri(msg, &uri)==-1 ) { LM_ERR("failed to set new RURI\n"); ser_error=E_OUT_OF_MEM; goto error02; } } else { if (append_branch(msg, &uri, 0, 0, Q_UNSPECIFIED, 0, 0)==-1) { LM_ERR("append_branch failed; too many or too long URIs?\n"); goto error02; } } uri_cnt++; } if (uri_cnt==0) { LM_ERR("no uri from %s\n", cmd_line ); goto error02; } /* success */ ret=1; error02: if (ferror(pipe)) { LM_ERR("in pipe: %s\n", strerror(errno)); ser_error=E_EXEC; ret=-1; } pclose(pipe); if (WIFEXITED(exit_status)) { /* exited properly .... */ /* return false if script exited with non-zero status */ if (WEXITSTATUS(exit_status)!=0) ret=-1; } else { /* exited erroneously */ LM_ERR("cmd %s failed. exit_status=%d, errno=%d: %s\n", cmd, exit_status, errno, strerror(errno) ); ret=-1; } error01: pkg_free(cmd_line); error00: 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, char* _t, char* _f, char* _s) { unsigned int flags; urecord_t* r; str aor, uri; ucontact_t* ptr,*it; int res; int ret; str path_dst; str flags_s; pv_value_t val; int_str istr; str sip_instance = {0,0},call_id = {0,0}; flags = 0; if (_f && _f[0]!=0) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid owner uri parameter"); return -1; } for( res=0 ; res< flags_s.len ; res++ ) { switch (flags_s.s[res]) { case 'm': flags |= REG_LOOKUP_METHODFILTER_FLAG; break; case 'b': flags |= REG_LOOKUP_NOBRANCH_FLAG; break; default: LM_WARN("unsuported flag %c \n",flags_s.s[res]); } } } if (_s) { if (pv_get_spec_value( _m, (pv_spec_p)_s, &val)!=0) { LM_ERR("failed to get PV value\n"); return -1; } if ( (val.flags&PV_VAL_STR)==0 ) { LM_ERR("PV vals is not string\n"); return -1; } uri = val.rs; } else { if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; } if (extract_aor(&uri, &aor,&sip_instance,&call_id) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain((udomain_t*)_t, &aor); return -1; } ptr = r->contacts; ret = -1; /* look first for an un-expired and suported contact */ search_valid_contact: while ( (ptr) && !(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr,flags))) ptr = ptr->next; if (ptr==0) { /* nothing found */ LM_DBG("nothing found !\n"); goto done; } if (sip_instance.len && sip_instance.s) { LM_DBG("ruri has gruu in lookup\n"); /* uri has GRUU */ if (ptr->instance.len-2 != sip_instance.len || memcmp(ptr->instance.s+1,sip_instance.s,sip_instance.len)) { LM_DBG("no match to sip instace - [%.*s] - [%.*s]\n",ptr->instance.len-2,ptr->instance.s+1, sip_instance.len,sip_instance.s); /* not the targeted instance, search some more */ ptr = ptr->next; goto search_valid_contact; } LM_DBG("matched sip instace\n"); } if (call_id.len && call_id.s) { /* decide whether GRUU is expired or not * * first - match call-id */ if (ptr->callid.len != call_id.len || memcmp(ptr->callid.s,call_id.s,call_id.len)) { LM_DBG("no match to call id - [%.*s] - [%.*s]\n",ptr->callid.len,ptr->callid.s, call_id.len,call_id.s); ptr = ptr->next; goto search_valid_contact; } /* matched call-id, check if there are newer contacts with * same sip instace bup newer last_modified */ it = ptr->next; while ( it ) { if (VALID_CONTACT(it,act_time)) { if (it->instance.len-2 == sip_instance.len && memcmp(it->instance.s+1,sip_instance.s,sip_instance.len) == 0) if (it->last_modified > ptr->last_modified) { /* same instance id, but newer modified -> expired GRUU, no match at all */ break; } } it=it->next; } if (it != NULL) { ret = -1; goto done; } } LM_DBG("found a complete match\n"); ret = 1; if (ptr) { LM_DBG("setting as ruri <%.*s>\n",ptr->c.len,ptr->c.s); if (set_ruri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* 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); setbflag( 0, ptr->cflags); if (ptr->sock) _m->force_send_socket = ptr->sock; /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } ptr = ptr->next; } /* Append branches if enabled */ /* If we got to this point and the URI had a ;gr parameter and it was matched * to a contact. No point in branching */ if ( flags®_LOOKUP_NOBRANCH_FLAG || (sip_instance.len && sip_instance.s) ) goto done; LM_DBG("looking for branches\n"); for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m,ptr,flags)) { 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("setting branch <%.*s>\n",ptr->c.len,ptr->c.s); if (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; } /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } } } done: ul.release_urecord(r); ul.unlock_udomain((udomain_t*)_t, &aor); return ret; }
/* returns : -1 - error * 0 - ok, but no contact added * n - ok and n contacts added */ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl, long max, pv_elem_t *reason) { static struct sip_msg dup_rpl; static str scontacts[MAX_CONTACTS_PER_REPLY]; static qvalue_t sqvalues[MAX_CONTACTS_PER_REPLY]; struct hdr_field *hdr; struct hdr_field *contact_hdr; contact_t *contacts; str backup_uri; int n,i; int added; int dup; int ret; dup = 0; /* sh_rpl not duplicated */ ret = 0; /* success and no contact added */ contact_hdr = NULL; hdr = NULL; if (sh_rpl==0 || sh_rpl==FAKED_REPLY) return 0; if ( sh_rpl->msg_flags&FL_SHM_CLONE ) { /* duplicate the reply into private memory to be able * to parse it and after words to free the parsed mems */ memcpy( &dup_rpl, sh_rpl, sizeof(struct sip_msg) ); LM_DBG("duplicating shm reply\n"); dup = 1; /* ok -> force the parsing of contact header */ if ( parse_headers( &dup_rpl, HDR_EOH_F, 0)<0 ) { LM_ERR("dup_rpl parse failed\n"); ret = -1; goto restore; } if (dup_rpl.contact==0) { LM_DBG("contact hdr not found in dup_rpl\n"); goto restore; } contact_hdr = dup_rpl.contact; } else { /* parse directly the current copy */ /* force the parsing of contact header */ if ( parse_headers( sh_rpl, HDR_EOH_F, 0)<0 ) { LM_ERR("sh_rpl parse failed\n"); ret = -1; goto restore; } if (sh_rpl->contact==0) { LM_DBG("contact hdr not found in sh_rpl\n"); goto restore; } contact_hdr = sh_rpl->contact; } /* iterate through all contact headers and extract the URIs */ for( n=0,hdr=contact_hdr ; hdr ; hdr=hdr->sibling ) { /* parse the body of contact header */ if (hdr->parsed==0) { if ( parse_contact(hdr)<0 ) { LM_ERR("contact hdr parse failed\n"); ret = -1; goto restore; } } /* we have the contact header and its body parsed -> sort the contacts * based on the q value */ contacts = ((contact_body_t*)hdr->parsed)->contacts; if (contacts==0) { LM_DBG("contact hdr has no contacts\n"); } else { sort_contacts( contacts, scontacts, sqvalues, &n); } /* clean currently added contact */ if (dup) free_contact( (contact_body_t**)(void*)(&hdr->parsed) ); } if (n==0) { LM_DBG("no contacts left after filtering\n"); goto restore; } /* to many branches ? */ if (max!=-1 && n>max) n = max; LM_DBG("%d contacts remaining after filtering and sorting\n",n); added = 0; /* add the sorted contacts as branches in dset and log this! */ for ( i=0 ; i<n ; i++ ) { LM_DBG("adding contact <%.*s>\n", scontacts[i].len, scontacts[i].s); if (i==0) { /* set RURI*/ if ( set_ruri( req, &scontacts[i])==-1 ) { LM_ERR("failed to set new RURI\n"); goto restore; } set_ruri_q(req, sqvalues[i]); } else { if (append_branch(0,&scontacts[i],0,0,sqvalues[i],0,0)<0) { LM_ERR("failed to add contact to dset\n"); continue; } } added++; if (rd_acc_fct!=0 && reason) { /* log the redirect */ backup_uri = req->new_uri; req->new_uri = scontacts[i]; //FIXME rd_acc_fct( req, (char*)reason, acc_db_table, NULL, NULL, NULL, NULL); req->new_uri = backup_uri; } } ret = (added==0)?-1:added; restore: if (dup==1) { /* free current parsed contact header */ if (hdr && hdr->parsed) free_contact( (contact_body_t**)(void*)(&hdr->parsed) ); /* are any new headers found? */ if (dup_rpl.last_header!=sh_rpl->last_header) { /* identify in the new headere list (from dup_rpl) * the sh_rpl->last_header and start remove everything after */ hdr = sh_rpl->last_header; free_hdr_field_lst(hdr->next); hdr->next=0; } } return ret; }
static inline int do_dns_failover(struct cell *t) { static struct sip_msg faked_req; struct sip_msg *shmem_msg; struct sip_msg *req; struct ua_client *uac; dlg_t dialog; int ret, sip_msg_len; uac = &t->uac[picked_branch]; /* check if the DNS resolver can get at least one new IP */ if ( get_next_su( uac->proxy, &uac->request.dst.to, 1)!=0 ) return -1; LM_DBG("new destination available\n"); if (t->uas.request==NULL) { if (!is_local(t)) { LM_CRIT("BUG: proxy transaction without UAS request :-/\n"); return -1; } /* create the cloned SIP msg -> first create a new SIP msg */ memset( &dialog, 0, sizeof(dialog)); dialog.send_sock = uac->request.dst.send_sock; dialog.hooks.next_hop = &uac->uri; req = buf_to_sip_msg(uac->request.buffer.s, uac->request.buffer.len, &dialog); if (req==NULL) { LM_ERR("failed to generate SIP msg from previous buffer\n"); return -1; } /* now do the actual cloning of the SIP message */ t->uas.request = sip_msg_cloner( req, &sip_msg_len, 1); if (t->uas.request==NULL) { LM_ERR("cloning failed\n"); free_sip_msg(req); return -1; } t->uas.end_request = ((char*)t->uas.request) + sip_msg_len; /* free the actual SIP message, keep the clone only */ free_sip_msg(req); /* the sip_msg structure is static in buf_to_sip_msg, so no need to free it */ } shmem_msg = t->uas.request; if (!fake_req(&faked_req, shmem_msg, &t->uas, uac, 1/*with dst_uri*/)) { LM_ERR("fake_req failed\n"); return -1; } /* fake also the env. conforming to the fake msg */ faked_env( t, &faked_req); ret = -1; /* set info as current destination */ if ( set_ruri( &faked_req, &uac->uri)!= 0) goto done; setb0flags( &faked_req, uac->br_flags ); faked_req.force_send_socket = shmem_msg->force_send_socket; /* send it out */ if (t_forward_nonack( t, &faked_req, uac->proxy)==1) ret = 0; done: /* restore original environment and free the fake msg */ faked_env( t, 0); free_faked_req(&faked_req,t); return ret; }
/* * Makes enum query on name. On success, rewrites user part and * replaces Request-URI. */ int do_query(struct sip_msg* _msg, char *user, char *name, str *service) { char uri[MAX_URI_SIZE]; char new_uri[MAX_URI_SIZE]; unsigned int priority, curr_prio, first; qvalue_t q; struct rdata* head; struct rdata* l; struct naptr_rdata* naptr; str pattern, replacement, result, new_result; head = get_record(name, T_NAPTR); if (head == 0) { LM_DBG("No NAPTR record found for %s.\n", name); return -1; } naptr_sort(&head); q = MAX_Q - 10; curr_prio = 0; first = 1; for (l = head; l; l = l->next) { if (l->type != T_NAPTR) continue; /*should never happen*/ naptr = (struct naptr_rdata*)l->rdata; if (naptr == 0) { LM_ERR("Null rdata in DNS response\n"); continue; } LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags '%.*s', " "slen %u, services '%.*s', rlen %u, regexp '%.*s'\n", name, naptr->order, naptr->pref, naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len, (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, (int)(naptr->regexp_len), ZSW(naptr->regexp)); if (sip_match(naptr, service) == 0) continue; if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, &pattern, &replacement) < 0) { LM_ERR("Parsing of NAPTR regexp failed\n"); continue; } result.s = &(uri[0]); result.len = MAX_URI_SIZE; /* Avoid making copies of pattern and replacement */ pattern.s[pattern.len] = (char)0; replacement.s[replacement.len] = (char)0; if (reg_replace(pattern.s, replacement.s, user, &result) < 0) { pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; LM_ERR("Regexp replace failed\n"); continue; } LM_DBG("Resulted in replacement: '%.*s'\n", result.len, ZSW(result.s)); pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; if (param.len > 0) { if (result.len + param.len > MAX_URI_SIZE - 1) { LM_ERR("URI is too long\n"); continue; } new_result.s = &(new_uri[0]); new_result.len = MAX_URI_SIZE; if (add_uri_param(&result, ¶m, &new_result) == 0) { LM_ERR("Parsing of URI <%.*s> failed\n", result.len, result.s); continue; } if (new_result.len > 0) { result = new_result; } } if (first) { if (set_ruri(_msg, &result) == -1) { goto done; } set_ruri_q(q); first = 0; curr_prio = ((naptr->order) << 16) + naptr->pref; } else { priority = ((naptr->order) << 16) + naptr->pref; if (priority > curr_prio) { q = q - 10; curr_prio = priority; } if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) { goto done; } } } done: free_rdata_list(head); return first ? -1 : 1; }
/* forwards the msg to the given location set; if flags has set the * CPL_PROXY_DONE, all locations will be added as branches, otherwise, the * first one will set as RURI (this is ha case when this is the first proxy * of the message) * The given list of location will be freed, returning 0 instead. * Returns: 0 - OK * -1 - error */ int cpl_proxy_to_loc_set( struct sip_msg *msg, struct location **locs, unsigned char flag) { struct location *foo; int bflags; int r; if (!*locs) { LM_ERR("empty loc set!!\n"); goto error; } /* use the first addr in loc_set to rewrite the RURI */ LM_DBG("rewriting Request-URI with <%s>\n",(*locs)->addr.uri.s); /* set RURI*/ if ( set_ruri( msg, &((*locs)->addr.uri))==-1 ) { LM_ERR("failed to set new RURI\n"); goto error; } /* set DST URI */ if((*locs)->addr.received.s && (*locs)->addr.received.len) { LM_DBG("rewriting Destination URI " "with <%s>\n",(*locs)->addr.received.s); if (set_dst_uri( msg, &((*locs)->addr.received) ) ) { LM_ERR("failed to set destination URI\n"); goto error; } } /* is the location NATED? */ bflags = ((*locs)->flags&CPL_LOC_NATED) ? cpl_fct.ulb.nat_flag : 0 ; setb0flags(bflags); /* free the location and point to the next one */ foo = (*locs)->next; free_location( *locs ); *locs = foo; /* add the rest of the locations as branches */ while(*locs) { bflags = ((*locs)->flags&CPL_LOC_NATED) ? cpl_fct.ulb.nat_flag : 0 ; LM_DBG("appending branch <%.*s>, flags %d\n", (*locs)->addr.uri.len, (*locs)->addr.uri.s, bflags); if(append_branch(msg, &(*locs)->addr.uri, &(*locs)->addr.received,0, Q_UNSPECIFIED, bflags, 0)==-1){ LM_ERR("failed when appending branch <%s>\n",(*locs)->addr.uri.s); goto error; } /* free the location and point to the next one */ foo = (*locs)->next; free_location( *locs ); *locs = foo; } /* run what proxy route is set */ if (cpl_env.proxy_route) { /* do not alter route type - it might be REQUEST or FAILURE */ run_top_route( rlist[cpl_env.proxy_route].a, msg); } /* do t_forward */ if ((r = cpl_fct.tmb.t_relay(msg, 0, 0, 0, 0, 0, 0)) < 0) { LM_ERR("t_relay failed! error=%d\n",r); goto error; } return 0; error: return -1; }