diff --git a/modules/registrar/api.c b/modules/registrar/api.c index cf8f37adfbe..0314a342a5a 100644 --- a/modules/registrar/api.c +++ b/modules/registrar/api.c @@ -103,7 +103,7 @@ int regapi_registered(struct sip_msg *msg, char *table) LM_ERR("usrloc domain [%s] not found\n", table); return -1; } - return registered(msg, d, NULL); + return registered(msg, d, NULL, 0); } /** diff --git a/modules/registrar/lookup.c b/modules/registrar/lookup.c index 6468e54047a..8e4f6141dd1 100644 --- a/modules/registrar/lookup.c +++ b/modules/registrar/lookup.c @@ -619,13 +619,16 @@ int lookup_branches(sip_msg_t *msg, udomain_t *d) * it is similar to lookup but registered neither rewrites * the Request-URI nor appends branches */ -int registered(struct sip_msg* _m, udomain_t* _d, str* _uri) +int registered(struct sip_msg* _m, udomain_t* _d, str* _uri, int match_flag) { str uri, aor; urecord_t* r; ucontact_t* ptr; int res; - int_str match_callid=(int_str)0; + str match_callid = {0,0}; + str match_received = {0,0}; + str match_contact = {0,0}; + sr_xavp_t *vavp = NULL; if(_uri!=NULL) { @@ -650,26 +653,61 @@ int registered(struct sip_msg* _m, udomain_t* _d, str* _uri) } if (res == 0) { - - if (reg_callid_avp_name.n) { - struct usr_avp *avp = - search_first_avp( reg_callid_avp_type, reg_callid_avp_name, &match_callid, 0); - if (!(avp && is_avp_str_val(avp))) - match_callid.n = 0; - match_callid.s.s = NULL; - } else { - match_callid.n = 0; - match_callid.s.s = NULL; + LM_DBG("searching with match flags (%d,%d)\n", match_flag, reg_match_flag_param); + if(reg_xavp_cfg.s!=NULL) { + + if((match_flag & 1) + && (vavp = xavp_get_child_with_sval(®_xavp_cfg, &match_callid_name)) != NULL + && vavp->val.v.s.len > 0) { + match_callid = vavp->val.v.s; + LM_DBG("matching with callid %.*s\n", match_callid.len, match_callid.s); + } + + if((match_flag & 2) + && (vavp = xavp_get_child_with_sval(®_xavp_cfg, &match_received_name)) != NULL + && vavp->val.v.s.len > 0) { + match_received = vavp->val.v.s; + LM_DBG("matching with received %.*s\n", match_received.len, match_received.s); + } + + if((match_flag & 4) + && (vavp = xavp_get_child_with_sval(®_xavp_cfg, &match_contact_name)) != NULL + && vavp->val.v.s.len > 0) { + match_contact = vavp->val.v.s; + LM_DBG("matching with contact %.*s\n", match_contact.len, match_contact.s); + } } for (ptr = r->contacts; ptr; ptr = ptr->next) { if(!VALID_CONTACT(ptr, act_time)) continue; - if (match_callid.s.s && /* optionally enforce tighter matching w/ Call-ID */ - memcmp(match_callid.s.s,ptr->callid.s,match_callid.s.len)) + if (match_callid.s && /* optionally enforce tighter matching w/ Call-ID */ + match_callid.len > 0 && + (match_callid.len != ptr->callid.len || + memcmp(match_callid.s, ptr->callid.s, match_callid.len))) continue; + if (match_received.s && /* optionally enforce tighter matching w/ ip:port */ + match_received.len > 0 && + (match_received.len != ptr->received.len || + memcmp(match_received.s, ptr->received.s, match_received.len))) + continue; + if (match_contact.s && /* optionally enforce tighter matching w/ Contact */ + match_contact.len > 0 && + (match_contact.len != ptr->c.len || + memcmp(match_contact.s, ptr->c.s, match_contact.len))) + continue; + + if(ptr->xavp!=NULL && reg_match_flag_param == 1) { + sr_xavp_t *xavp = xavp_clone_level_nodata(ptr->xavp); + if(xavp_add(xavp, NULL)<0) { + LM_ERR("error adding xavp for %.*s after successful match\n", aor.len, ZSW(aor.s)); + xavp_destroy_list(&xavp); + } + } + ul.release_urecord(r); ul.unlock_udomain(_d, &aor); LM_DBG("'%.*s' found in usrloc\n", aor.len, ZSW(aor.s)); + return 1; } } diff --git a/modules/registrar/lookup.h b/modules/registrar/lookup.h index 1e77bfeb7b1..9d06aa7126e 100644 --- a/modules/registrar/lookup.h +++ b/modules/registrar/lookup.h @@ -66,7 +66,7 @@ int lookup_branches(sip_msg_t *msg, udomain_t *d); * it is similar to lookup but registered neither rewrites * the Request-URI nor appends branches */ -int registered(struct sip_msg* _m, udomain_t* _d, str* _uri); +int registered(struct sip_msg* _m, udomain_t* _d, str* _uri, int match_flag); #endif /* LOOKUP_H */ diff --git a/modules/registrar/reg_mod.c b/modules/registrar/reg_mod.c index 437883cc6c9..3eba126e78a 100644 --- a/modules/registrar/reg_mod.c +++ b/modules/registrar/reg_mod.c @@ -69,6 +69,7 @@ static int w_lookup(struct sip_msg* _m, char* _d, char* _p2); static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _p2); static int w_lookup_branches(struct sip_msg* _m, char* _d, char* _p2); static int w_registered(struct sip_msg* _m, char* _d, char* _uri); +static int w_registered2(struct sip_msg* _m, char* _d, char* _uri, char* _flags); static int w_unregister(struct sip_msg* _m, char* _d, char* _uri); static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid); @@ -78,6 +79,7 @@ static int domain_uri_fixup(void** param, int param_no); static int save_fixup(void** param, int param_no); static int unreg_fixup(void** param, int param_no); static int fetchc_fixup(void** param, int param_no); +static int registered_fixup(void** param, int param_no); /*! \brief Functions */ static int add_sock_hdr(struct sip_msg* msg, char *str, char *foo); @@ -101,10 +103,10 @@ int reg_outbound_mode = 0; int reg_regid_mode = 0; int reg_flow_timer = 0; -/* Populate this AVP if testing for specific registration instance. */ -char *reg_callid_avp_param = 0; -unsigned short reg_callid_avp_type = 0; -int_str reg_callid_avp_name; +int reg_match_flag_param = 0; +str match_callid_name = str_init("match_callid"); +str match_received_name = str_init("match_received"); +str match_contact_name = str_init("match_contact"); char* rcv_avp_param = 0; unsigned short rcv_avp_type = 0; @@ -164,6 +166,8 @@ static cmd_export_t cmds[] = { REQUEST_ROUTE | FAILURE_ROUTE }, {"registered", (cmd_function)w_registered, 2, domain_uri_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE }, + {"registered", (cmd_function)w_registered2, 3, registered_fixup, 0, + REQUEST_ROUTE | FAILURE_ROUTE }, {"add_sock_hdr", (cmd_function)add_sock_hdr, 1, fixup_str_null, 0, REQUEST_ROUTE }, {"unregister", (cmd_function)w_unregister, 2, unreg_fixup, 0, @@ -200,22 +204,22 @@ static param_export_t params[] = { {"max_expires", INT_PARAM, &default_registrar_cfg.max_expires }, {"received_param", PARAM_STR, &rcv_param }, {"received_avp", PARAM_STRING, &rcv_avp_param }, - {"reg_callid_avp", PARAM_STRING, ®_callid_avp_param }, {"max_contacts", INT_PARAM, &default_registrar_cfg.max_contacts }, {"retry_after", INT_PARAM, &default_registrar_cfg.retry_after }, - {"sock_flag", INT_PARAM, &sock_flag }, - {"sock_hdr_name", PARAM_STR, &sock_hdr_name }, - {"method_filtering", INT_PARAM, &method_filtering }, - {"use_path", INT_PARAM, &path_enabled }, - {"path_mode", INT_PARAM, &path_mode }, - {"path_use_received", INT_PARAM, &path_use_params }, - {"path_check_local", INT_PARAM, &path_check_local }, - {"xavp_cfg", PARAM_STR, ®_xavp_cfg }, - {"xavp_rcd", PARAM_STR, ®_xavp_rcd }, - {"gruu_enabled", INT_PARAM, ®_gruu_enabled }, - {"outbound_mode", INT_PARAM, ®_outbound_mode }, + {"sock_flag", INT_PARAM, &sock_flag }, + {"sock_hdr_name", PARAM_STR, &sock_hdr_name }, + {"method_filtering", INT_PARAM, &method_filtering }, + {"use_path", INT_PARAM, &path_enabled }, + {"path_mode", INT_PARAM, &path_mode }, + {"path_use_received", INT_PARAM, &path_use_params }, + {"path_check_local", INT_PARAM, &path_check_local }, + {"xavp_cfg", PARAM_STR, ®_xavp_cfg }, + {"xavp_rcd", PARAM_STR, ®_xavp_rcd }, + {"gruu_enabled", INT_PARAM, ®_gruu_enabled }, + {"outbound_mode", INT_PARAM, ®_outbound_mode }, {"regid_mode", INT_PARAM, ®_regid_mode }, {"flow_timer", INT_PARAM, ®_flow_timer }, + {"reg_on_match_flag", INT_PARAM, ®_match_flag_param }, {0, 0, 0} }; @@ -285,8 +289,6 @@ static int mod_init(void) LM_ERR("Fail to declare the configuration\n"); return -1; } - - if (rcv_avp_param && *rcv_avp_param) { s.s = rcv_avp_param; s.len = strlen(s.s); @@ -306,24 +308,6 @@ static int mod_init(void) rcv_avp_type = 0; } - if (reg_callid_avp_param && *reg_callid_avp_param) { - s.s = reg_callid_avp_param; s.len = strlen(s.s); - if (pv_parse_spec(&s, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP %s AVP definition\n", reg_callid_avp_param); - return -1; - } - - if(pv_get_avp_name(0, &avp_spec.pvp, ®_callid_avp_name, ®_callid_avp_type)!=0) - { - LM_ERR("[%s]- invalid AVP definition\n", reg_callid_avp_param); - return -1; - } - } else { - reg_callid_avp_name.n = 0; - reg_callid_avp_type = 0; - } - bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) { LM_ERR("can't bind usrloc\n"); @@ -485,7 +469,24 @@ static int w_registered(struct sip_msg* _m, char* _d, char* _uri) LM_ERR("invalid uri parameter\n"); return -1; } - return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL); + return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, 0); +} + +static int w_registered2(struct sip_msg* _m, char* _d, char* _uri, char* _flags) +{ + str uri = {0}; + int flags = 0; + if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)) + { + LM_ERR("invalid uri parameter\n"); + return -1; + } + if(_flags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_flags, &flags)) < 0) + { + LM_ERR("invalid flags parameter\n"); + return -1; + } + return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, flags); } static int w_unregister(struct sip_msg* _m, char* _d, char* _uri) @@ -550,6 +551,18 @@ static int domain_uri_fixup(void** param, int param_no) return 0; } +static int registered_fixup(void** param, int param_no) +{ + if (param_no == 1) { + return domain_fixup(param, 1); + } else if (param_no == 2) { + return fixup_spve_null(param, 1); + } else if (param_no == 3) { + return fixup_igp_null(param, 1); + } + return 0; +} + /*! \brief * Convert char* parameter to udomain_t* pointer @@ -616,7 +629,6 @@ static int fetchc_fixup(void** param, int param_no) return 0; } - static void mod_destroy(void) { free_contact_buf(); diff --git a/modules/registrar/reg_mod.h b/modules/registrar/reg_mod.h index 892a60668d5..84eb27ef296 100644 --- a/modules/registrar/reg_mod.h +++ b/modules/registrar/reg_mod.h @@ -74,8 +74,12 @@ extern float def_q; extern unsigned short rcv_avp_type; extern int_str rcv_avp_name; -extern unsigned short reg_callid_avp_type; -extern int_str reg_callid_avp_name; + +extern int reg_match_flag_param; +extern str match_callid_name; +extern str match_received_name; +extern str match_contact_name; + extern str rcv_param; extern int method_filtering; diff --git a/modules/registrar/regpv.c b/modules/registrar/regpv.c index 719bec3ff0c..38d874d7bd3 100644 --- a/modules/registrar/regpv.c +++ b/modules/registrar/regpv.c @@ -35,10 +35,15 @@ #include "../../action.h" #include "../../lib/kcore/faked_msg.h" #include "../usrloc/usrloc.h" +#include "../../pvapi.h" +#include "../../xavp.h" #include "reg_mod.h" #include "common.h" #include "regpv.h" +#define REGPV_FIELD_DELIM ", " +#define REGPV_FIELD_DELIM_LEN (sizeof(REGPV_FIELD_DELIM) - 1) + typedef struct _regpv_profile { str pname; str domain; @@ -53,6 +58,7 @@ typedef struct _regpv_profile { typedef struct _regpv_name { regpv_profile_t *rp; int attr; + pv_xavp_name_t* xname; } regpv_name_t; static regpv_profile_t *_regpv_profile_list = NULL; @@ -110,6 +116,9 @@ static void regpv_free_profile(regpv_profile_t *rpp) ptr = rpp->contacts; while(ptr) { + if(ptr->xavp) { + xavp_destroy_list(&ptr->xavp); + } ptr0 = ptr; ptr = ptr->next; pkg_free(ptr0); @@ -151,6 +160,285 @@ void regpv_free_profiles(void) _regpv_profile_list = 0; } +char* regpv_xavp_fill_ni(str *in, pv_xavp_name_t *xname) +{ + char *p; + str idx; + int n; + + if(in->s==NULL || in->len<=0 || xname==NULL) + return NULL; + p = in->s; + + /* eat ws */ + while(ps+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) + p++; + if(p>in->s+in->len || *p=='\0') + goto error; + xname->name.s = p; + while(p < in->s + in->len) + { + if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r' || *p=='[') + break; + p++; + } + xname->name.len = p - xname->name.s; + if(p>in->s+in->len || *p=='\0') + return p; + /* eat ws */ + while(ps+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) + p++; + if(p>in->s+in->len || *p=='\0') + return p; + + if(*p!='[') + return p; + /* there is index */ + p++; + idx.s = p; + n = 0; + while(ps+in->len && *p!='\0') + { + if(*p==']') + { + if(n==0) + break; + n--; + } + if(*p == '[') + n++; + p++; + } + if(p>in->s+in->len || *p=='\0') + goto error; + + if(p==idx.s) + { + LM_ERR("xavp [\"%.*s\"] does not get empty index param\n", + in->len, in->s); + goto error; + } + idx.len = p - idx.s; + if(pv_parse_index(&xname->index, &idx)!=0) + { + LM_ERR("idx \"%.*s\" has an invalid index param [%.*s]\n", + in->len, in->s, idx.len, idx.s); + goto error; + } + xname->index.type = PVT_EXTRA; + p++; + return p; +error: + return NULL; +} + +int regpv_parse_xavp_name(pv_spec_p sp, str *in) +{ + pv_xavp_name_t *xname=NULL; + char *p; + str s; + + if(in->s==NULL || in->len<=0) + return -1; + + xname = (pv_xavp_name_t*)shm_malloc(sizeof(pv_xavp_name_t)); + if(xname==NULL) + return -1; + + memset(xname, 0, sizeof(pv_xavp_name_t)); + + s = *in; + + p = regpv_xavp_fill_ni(&s, xname); + if(p==NULL) { + goto error; + } + + if(*p!='=') { + goto done; + } + p++; + if(*p!='>') { + goto error; + } + p++; + + s.len = in->len - (int)(p - in->s); + s.s = p; + LM_INFO("xavp sublist [%.*s] - key [%.*s]\n", xname->name.len, + xname->name.s, s.len, s.s); + + xname->next = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t)); + if(xname->next==NULL) { + goto error; + } + + memset(xname->next, 0, sizeof(pv_xavp_name_t)); + + p = regpv_xavp_fill_ni(&s, xname->next); + if(p==NULL) { + goto error; + } + +done: + sp->pvp.pvn.u.dname = (void*)xname; + sp->pvp.pvn.type = PV_NAME_PVAR; + return 0; + +error: + if(xname!=NULL) { + pkg_free(xname); + } + return -1; +} + +int regpv_xavp_get_value(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res, sr_xavp_t *avp) +{ + static char _pv_xavp_buf[128]; + str s; + + switch(avp->val.type) { + case SR_XTYPE_NULL: + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_INT: + return pv_get_sintval(msg, param, res, avp->val.v.i); + break; + case SR_XTYPE_STR: + return pv_get_strval(msg, param, res, &avp->val.v.s); + break; + case SR_XTYPE_TIME: + if(snprintf(_pv_xavp_buf, 128, "%lu", (long unsigned)avp->val.v.t)<0) + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_LONG: + if(snprintf(_pv_xavp_buf, 128, "%ld", (long unsigned)avp->val.v.l)<0) + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_LLONG: + if(snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll)<0) + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_XAVP: + if(snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.xavp)<0) + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_DATA: + if(snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.data)<0) + return pv_get_null(msg, param, res); + break; + default: + return pv_get_null(msg, param, res); + } + s.s = _pv_xavp_buf; + s.len = strlen(_pv_xavp_buf); + return pv_get_strval(msg, param, res, &s); +} + +int regpv_get_xavp_from_start(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res, sr_xavp_t **start) +{ + pv_xavp_name_t *xname=NULL; + sr_xavp_t *avp=NULL; + int idxf = 0; + int idx = 0; + int count; + char *p, *p_ini; + int p_size; + + if(param==NULL) + { + LM_ERR("bad parameters\n"); + return -1; + } + xname = ((regpv_name_t*)param->pvn.u.dname)->xname; + + if(xname->index.type==PVT_EXTRA) + { + /* get the index */ + if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0) + { + LM_ERR("invalid index\n"); + return -1; + } + } + /* fix the index */ + if(idx<0) + { + count = xavp_count(&xname->name, start); + idx = count + idx; + } + avp = xavp_get_by_index(&xname->name, idx, start); + if(avp==NULL) { + LM_DBG("GET XAVP AVP = NULL\n"); + return pv_get_null(msg, param, res); + } + if(xname->next==NULL) { + LM_DBG("GET XAVP XNAME NEXT = NULL\n"); + return regpv_xavp_get_value(msg, param, res, avp); + } + + idx = 0; + idxf = 0; + if(xname->next->index.type==PVT_EXTRA) + { + /* get the index */ + if(pv_get_spec_index(msg, &xname->next->index.pvp, &idx, &idxf)!=0) + { + LM_ERR("invalid index\n"); + return -1; + } + } + /* fix the index */ + if(idx<0) + { + count = xavp_count(&xname->next->name, &avp->val.v.xavp); + idx = count + idx; + } + avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp); + if(avp==NULL) { + LM_DBG("GET XAVP AVP BY INDEX = NULL\n"); + return pv_get_null(msg, param, res); + } + /* get all values of second key */ + if(idxf==PV_IDX_ALL) + { + p_ini = pv_get_buffer(); + p = p_ini; + p_size = pv_get_buffer_size(); + do { + if(p!=p_ini) + { + if(p-p_ini+REGPV_FIELD_DELIM_LEN+1>p_size) + { + LM_ERR("local buffer length exceeded\n"); + return pv_get_null(msg, param, res); + } + memcpy(p, REGPV_FIELD_DELIM, REGPV_FIELD_DELIM_LEN); + p += REGPV_FIELD_DELIM_LEN; + } + if(regpv_xavp_get_value(msg, param, res, avp)<0) + { + LM_ERR("can get value\n"); + return pv_get_null(msg, param, res); + } + if(p-p_ini+res->rs.len+1>p_size) + { + LM_ERR("local buffer length exceeded!\n"); + return pv_get_null(msg, param, res); + } + memcpy(p, res->rs.s, res->rs.len); + p += res->rs.len; + } while ((avp=xavp_get_next(avp))!=0); + res->rs.s = p_ini; + res->rs.len = p - p_ini; + return 0; + } + return regpv_xavp_get_value(msg, param, res, avp); +} + + int pv_get_ulc(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { @@ -192,7 +480,7 @@ int pv_get_ulc(struct sip_msg *msg, pv_param_t *param, /* get contact */ i = 0; c = rpp->contacts; - while(rpp) + while(c) { if(i == idx) break; @@ -269,6 +557,10 @@ int pv_get_ulc(struct sip_msg *msg, pv_param_t *param, if(c->instance.len>0) return pv_get_strval(msg, param, res, &c->instance); break; + case 21: /* xavp */ + if(c->xavp) + return regpv_get_xavp_from_start(msg, param, res, &c->xavp); + break; } return pv_get_null(msg, param, res); @@ -333,6 +625,15 @@ int pv_parse_ulc_name(pv_spec_p sp, str *in) memset(rp, 0, sizeof(regpv_name_t)); rp->rp = rpp; + if(strstr(pa.s, "=>")) { + regpv_parse_xavp_name(sp, &pa); + pv_xavp_name_t* xname = (pv_xavp_name_t*)sp->pvp.pvn.u.dname; + LM_DBG("ulc parse xavp name [%.*s] \n", xname->name.len, xname->name.s); + rp->xname = xname; + rp->attr = 21; + goto done; + } + switch(pa.len) { case 1: @@ -402,6 +703,7 @@ int pv_parse_ulc_name(pv_spec_p sp, str *in) default: goto error; } +done: sp->pvp.pvn.u.dname = (void*)rp; sp->pvp.pvn.type = PV_NAME_PVAR; @@ -538,7 +840,10 @@ int pv_fetch_contacts(struct sip_msg* msg, char* table, char* uri, c0->instance.len = ptr->instance.len; p += c0->instance.len; } - + if(ptr->xavp != NULL && reg_match_flag_param == 1) + { + c0->xavp = xavp_clone_level_nodata(ptr->xavp); + } if(ptr0==NULL) { rpp->contacts = c0; @@ -679,6 +984,10 @@ void reg_ul_expired_contact(ucontact_t* ptr, int type, void* param) c0->instance.len = ptr->instance.len; p += c0->instance.len; } + if(ptr->xavp != NULL && reg_match_flag_param == 1) + { + c0->xavp = xavp_clone_level_nodata(ptr->xavp); + } rpp->contacts = c0; rpp->nrc = 1;