From 1e4a2316ec64f666ffa8fe865294fadcb06ebdac Mon Sep 17 00:00:00 2001 From: jaybeepee Date: Mon, 29 Feb 2016 14:09:14 +0200 Subject: [PATCH] modules/ims_usrloc_pcscf, ims_usrloc_scscf, ims_qos: pass contact state into search requests - more flexibility on state of contact to search for --- modules/ims_qos/cdpeventprocessor.c | 1 + modules/ims_qos/mod.c | 1 + modules/ims_qos/rx_aar.c | 1 + modules/ims_registrar_pcscf/save.c | 59 +++++-- modules/ims_registrar_pcscf/service_routes.c | 172 +++++++++++-------- modules/ims_usrloc_pcscf/udomain.c | 57 +++--- modules/ims_usrloc_pcscf/usrloc.h | 13 +- 7 files changed, 181 insertions(+), 123 deletions(-) diff --git a/modules/ims_qos/cdpeventprocessor.c b/modules/ims_qos/cdpeventprocessor.c index cd790759849..390b5a5b1c7 100644 --- a/modules/ims_qos/cdpeventprocessor.c +++ b/modules/ims_qos/cdpeventprocessor.c @@ -265,6 +265,7 @@ void cdp_cb_event_process() { contact_info.via_port = p_session_data->via_port; contact_info.via_prot = p_session_data->via_proto; contact_info.aor = p_session_data->registration_aor; + contact_info.reg_state = PCONTACT_ANY; if (ul.get_pcontact(domain, &contact_info, &pcontact) != 0) { LM_DBG("no contact found for terminated Rx reg session..... ignoring\n"); diff --git a/modules/ims_qos/mod.c b/modules/ims_qos/mod.c index 4e3b35627e4..c330afefa14 100644 --- a/modules/ims_qos/mod.c +++ b/modules/ims_qos/mod.c @@ -1091,6 +1091,7 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char* contact_info.searchflag = SEARCH_NORMAL; contact_info.received_host.s = 0; contact_info.received_host.len = 0; + contact_info.reg_state = PCONTACT_ANY; //search for any state if (ul.get_pcontact(domain_t, &contact_info, &pcontact) != 0) { LM_ERR("This contact does not exist in PCSCF usrloc - error in cfg file\n"); diff --git a/modules/ims_qos/rx_aar.c b/modules/ims_qos/rx_aar.c index 15de3584407..5aa387ea5a3 100644 --- a/modules/ims_qos/rx_aar.c +++ b/modules/ims_qos/rx_aar.c @@ -297,6 +297,7 @@ void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long e contact_info.via_host = local_data->via_host; contact_info.via_port = local_data->via_port; contact_info.via_prot = local_data->via_proto; + contact_info.reg_state = PCONTACT_ANY; if (ul.get_pcontact(domain_t, &contact_info, &pcontact) != 0) { LM_ERR("Shouldn't get here, can't find contact....\n"); diff --git a/modules/ims_registrar_pcscf/save.c b/modules/ims_registrar_pcscf/save.c index c3d58061a31..1f8fba4f1de 100644 --- a/modules/ims_registrar_pcscf/save.c +++ b/modules/ims_registrar_pcscf/save.c @@ -97,6 +97,26 @@ static inline int calc_contact_expires(contact_t *c,int expires_hdr, int local_t return local_time_now + r; } +static inline char* strnistr(const char *s, const char *find, size_t slen) +{ + char c, sc; + size_t len; + + if ((c = *find++) != '\0') { + len = strlen(find); + do { + do { + if ((sc = *s++) == '\0' || slen-- < 1) + return (NULL); + } while (sc != c); + if (len > slen) + return (NULL); + } while (strncasecmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} + /** * Updates the registrar with the new values @@ -118,11 +138,8 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma struct hdr_field* h; contact_t* c; struct sip_uri puri; - struct sip_uri parsed_received; struct pcontact_info ci; pcontact_t* pcontact; - char srcip[50]; - int_str val; unsigned short port; pcscf_act_time(); @@ -151,13 +168,15 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma ci.num_public_ids = public_id_cnt; ci.service_routes = service_route; ci.num_service_routes = service_route_cnt; - ci.reg_state = PCONTACT_REGISTERED; + ci.reg_state = PCONTACT_REGISTERED|PCONTACT_REG_PENDING|PCONTACT_REG_PENDING_AAR; //we don't want to add contacts that did not come through us (pcscf) + if (c->uri.len > 6 && (strnistr(c->uri.s, "alias=", c->uri.len))) { + LM_DBG("contact has an alias - we can use that as the received.... - TODO\n"); + } ci.received_host.len = 0; ci.received_host.s = 0; ci.received_port = 0; ci.received_proto = 0; - port = puri.port_no?puri.port_no:5060; ci.via_host = puri.host; ci.via_port = port; @@ -169,16 +188,17 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma goto next_contact; } - LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now); - - if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) { - LM_ERR("Failed inserting new pcontact\n"); - } else { - //register for callbacks on this contact so we can send PUBLISH to SCSCF should status change - LM_DBG("registering for UL callback\n"); - ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL); - //we also need to subscribe to reg event of this contact at SCSCF - } + LM_DBG("We don't add contact from the 200OK that did not go through us (ie, not present in explicit REGISTER that went through us\n"); +// LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now); +// ci.reg_state = PCONTACT_REGISTERED; +// if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) { +// LM_ERR("Failed inserting new pcontact\n"); +// } else { +// //register for callbacks on this contact so we can send PUBLISH to SCSCF should status change +// LM_DBG("registering for UL callback\n"); +// ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL); +// //we also need to subscribe to reg event of this contact at SCSCF +// } } else { //contact already exists - update LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state)); if ((expires-local_time_now)<=0) { //remove contact - de-register @@ -192,6 +212,7 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma pcontact->expires-local_time_now, expires, expires-local_time_now); + ci.reg_state = PCONTACT_REGISTERED; if (ul.update_pcontact(_d, &ci, pcontact) != 0) { LM_ERR("failed to update pcscf contact\n"); } @@ -203,8 +224,6 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma } } return 1; -error: - return 0; } /** @@ -268,7 +287,8 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) { ci.num_public_ids=0; ci.num_service_routes=0; ci.expires=local_time_now + pending_reg_expires; - ci.reg_state=PCONTACT_REG_PENDING; + ci.reg_state=PCONTACT_ANY; + ci.searchflag=SEARCH_RECEIVED; //we want to make sure we are very specific with this search to make sure we get the correct contact to put into reg_pending. // Received Info: First try AVP, otherwise simply take the source of the request: memset(&val, 0, sizeof(int_str)); @@ -301,6 +321,7 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) { ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot); if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s); + ci.reg_state=PCONTACT_REG_PENDING; if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) { LM_ERR("Failed inserting new pcontact\n"); } else { @@ -345,7 +366,7 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags) { expires_hdr = cscf_get_expires_hdr(_m, 0); cb = cscf_parse_contacts(_m); if (!cb || (!cb->contacts && !cb->star)) { - LM_ERR("No contact headers and not *\n"); + LM_DBG("No contact headers and not *\n"); goto error; } cscf_get_p_associated_uri(_m, &public_ids, &num_public_ids, 1); diff --git a/modules/ims_registrar_pcscf/service_routes.c b/modules/ims_registrar_pcscf/service_routes.c index 00d6076ff2e..3d29d6109fd 100644 --- a/modules/ims_registrar_pcscf/service_routes.c +++ b/modules/ims_registrar_pcscf/service_routes.c @@ -154,10 +154,13 @@ int checkcontact(struct sip_msg* _m, pcontact_t * c) { received_host.len, received_host.s); // Finally really compare the "received_host" - if (!memcmp(c->received_host.s, received_host.s, received_host.len)) + if (!memcmp(c->received_host.s, received_host.s, received_host.len)) { + LM_DBG("check contact passed\n"); return 0; } } + } + LM_DBG("check contact failed\n"); return 1; } @@ -165,21 +168,25 @@ int checkcontact(struct sip_msg* _m, pcontact_t * c) { * get PContact-Structure for message * (search only once per Request) */ -pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d) { - ppublic_t * p; - contact_body_t *b = 0; - contact_t *ct; - pcontact_info_t search_ci; - str received_host = {0, 0}; - char srcip[50]; - struct via_body *vb; - unsigned short port, proto; - str host; - sip_uri_t contact_uri; +pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d, enum pcontact_reg_states reg_state) { + ppublic_t * p; + contact_body_t *b = 0; + contact_t *ct; + pcontact_info_t search_ci; + str received_host = {0, 0}; + char srcip[50]; + struct via_body *vb; + unsigned short port, proto; + str host; + sip_uri_t contact_uri; + int mustRetryViaSearch = 0; + int mustRetryReceivedSearch = 0; b = cscf_parse_contacts(_m); if (_m->first_line.type == SIP_REPLY && _m->contact && _m->contact->parsed && b->contacts) { + mustRetryViaSearch = 1; + mustRetryReceivedSearch = 1; LM_DBG("This is a reply - to look for contact we favour the contact header above the via (b2bua)... if no contact we will use last via\n"); ct = b->contacts; host = ct->uri; @@ -214,65 +221,93 @@ pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d) { // if (_m->id != current_msg_id) { current_msg_id = _m->id; c = NULL; - search_ci.received_host.s = received_host.s; - search_ci.received_host.len = received_host.len; - search_ci.received_port = _m->rcv.src_port; - search_ci.received_proto = _m->rcv.proto; - search_ci.searchflag = SEARCH_NORMAL; - search_ci.via_host = host; - search_ci.via_port = port; - search_ci.via_prot = proto; - search_ci.aor.s = 0; - search_ci.aor.len = 0; - - if (c == NULL) { - b = cscf_parse_contacts(_m); - - if (b && b->contacts) { - for (ct = b->contacts; ct; ct = ct->next) { - search_ci.aor = ct->uri; - if (ul.get_pcontact(_d, &search_ci, &c) == 0) { - if (checkcontact(_m, c) != 0) { - c = NULL; - } else { - break; - } - } - } - } else { - LM_WARN("No contact-header found?!?\n"); - } - } + //search_ci.reg_state = PCONTACT_REGISTERED; //we can do this because this function is always called expecting a REGISTERED contact + search_ci.reg_state = reg_state; + search_ci.received_host.s = received_host.s; + search_ci.received_host.len = received_host.len; + search_ci.received_port = _m->rcv.src_port; + search_ci.received_proto = _m->rcv.proto; + search_ci.searchflag = SEARCH_RECEIVED; + search_ci.via_host = host; + search_ci.via_port = port; + search_ci.via_prot = proto; + search_ci.aor.s = 0; + search_ci.aor.len = 0; + +// b = cscf_parse_contacts(_m); +tryagain: + if (b && b->contacts) { + for (ct = b->contacts; ct; ct = ct->next) { + search_ci.aor = ct->uri; + if (ul.get_pcontact(_d, &search_ci, &c) == 0) { + if (checkcontact(_m, c) != 0) { + c = NULL; + } else { + break; + } + } + } + } else { + LM_WARN("No contact-header found...\n"); + } - if ((c == NULL) && (is_registered_fallback2ip == 1)) { - LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n"); - // received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); - // received_host.s = srcip; - if (ul.get_pcontact(_d, &search_ci, &c) == 1) { - LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto); - } else { - if (checkcontact(_m, c) != 0) { - c = NULL; - } - } - } -// } - asserted_identity = NULL; - registration_contact = NULL; - if (c) { - registration_contact = &c->contact_user; - p = c->head; - while (p) { - if (p->is_default == 1) - asserted_identity = &p->public_identity; - p = p->next; + if ((c == NULL) && (is_registered_fallback2ip == 1)) { + LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n"); + // received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); + // received_host.s = srcip; + if (ul.get_pcontact(_d, &search_ci, &c) == 1) { + LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto); + } else { + if (checkcontact(_m, c) != 0) { + c = NULL; + } + } + } + + asserted_identity = NULL; + registration_contact = NULL; + if (c) { + LM_DBG("Trying to set asserted identity field"); + registration_contact = &c->contact_user; + p = c->head; + while (p) { + LM_DBG("Checking through contact users"); + if (p->is_default == 1) { + LM_DBG("Found default contact user so setting asserted identity"); + asserted_identity = &p->public_identity; + } + p = p->next; + } + } + if (asserted_identity != NULL && asserted_identity->len > 0) { + LM_DBG("Have set the asserted_identity param to [%.*s]\n", asserted_identity->len, asserted_identity->s); + } else { + LM_DBG("Asserted identity not set"); } - } + // LM_DBG("pcontact flag is [%d]\n", c->flags); // if (c && (c->flags & (1<host; + search_ci.via_port = vb->port ? vb->port : 5060; + search_ci.via_prot = vb->proto; + mustRetryViaSearch = 0; + goto tryagain; + } + + if (!c && mustRetryReceivedSearch) { + LM_DBG("This is a reply and we still don't have a match - will try src ip/port of message\n"); + search_ci.via_host = received_host; + search_ci.via_port = _m->rcv.src_port; + search_ci.via_prot = _m->rcv.proto; + mustRetryReceivedSearch = 0; + goto tryagain; + } return c; } @@ -308,7 +343,7 @@ int check_service_routes(struct sip_msg* _m, udomain_t* _d) { /* Lock this record while working with the data: */ ul.lock_udomain(_d, &vb->host, port, proto); - pcontact_t * c = getContactP(_m, _d); + pcontact_t * c = getContactP(_m, _d, PCONTACT_REGISTERED); if (!c) { LM_DBG("no contact found in usrloc when checking for service route\n"); goto error; @@ -405,7 +440,7 @@ int force_service_routes(struct sip_msg* _m, udomain_t* _d) { str new_route_header; struct lump* lmp = NULL; char * buf; - pcontact_t * c = getContactP(_m, _d); + pcontact_t * c = getContactP(_m, _d, PCONTACT_REGISTERED); // char srcip[20]; // str received_host; struct via_body* vb; @@ -510,7 +545,7 @@ int force_service_routes(struct sip_msg* _m, udomain_t* _d) { * Check, if source is registered. */ int is_registered(struct sip_msg* _m, udomain_t* _d) { - if (getContactP(_m, _d) != NULL) return 1; + if (getContactP(_m, _d, PCONTACT_REGISTERED) != NULL) return 1; return -1; } @@ -549,7 +584,7 @@ int assert_identity(struct sip_msg* _m, udomain_t* _d, str identity) { } LM_DBG("Identity to assert: %.*s\n", identity.len, identity.s); - if (getContactP(_m, _d) != NULL) { + if (getContactP(_m, _d, PCONTACT_REGISTERED|PCONTACT_REG_PENDING_AAR|PCONTACT_REG_PENDING) != NULL) { for (p = c->head; p; p = p->next) { LM_DBG("Public identity: %.*s\n", p->public_identity.len, p->public_identity.s); /* Check length: */ @@ -654,6 +689,7 @@ int pcscf_unregister(udomain_t* _d, str * uri, str * received_host, int received search_ci.via_prot = search_ci.received_proto; search_ci.aor.s = uri->s; search_ci.aor.len = uri->len; + search_ci.reg_state = PCONTACT_ANY; if (ul.get_pcontact(_d, &search_ci, &pcontact) == 0) { /* Lock this record while working with the data: */ diff --git a/modules/ims_usrloc_pcscf/udomain.c b/modules/ims_usrloc_pcscf/udomain.c index 736f1943008..fbb0a062f77 100644 --- a/modules/ims_usrloc_pcscf/udomain.c +++ b/modules/ims_usrloc_pcscf/udomain.c @@ -506,22 +506,33 @@ int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact** for (i = 0; i < _d->table[sl].n; i++) { LM_DBG("comparing contact with aorhash [%u], aor [%.*s]\n", c->aorhash, c->aor.len, c->aor.s); LM_DBG(" contact host [%.*s:%d]\n", c->contact_host.len, c->contact_host.s, c->contact_port); - - if ((c->aorhash == aorhash) && (c->contact_host.len == contact_info->via_host.len) && (memcmp(contact_info->via_host.s, c->contact_host.s, c->contact_host.len)==0) && (c->contact_port == contact_info->via_port) - && (!(contact_info->searchflag&SEARCH_RECEIVED) || ((contact_info->searchflag&SEARCH_RECEIVED) - && ((c->received_host.len == contact_info->received_host.len) && (memcmp(c->received_host.s, contact_info->received_host.s, contact_info->received_host.len)==0)) - && (c->received_port == contact_info->received_port)))) { - LM_DBG("found contact with URI [%.*s]\n", c->aor.len, c->aor.s); - if (has_rinstance) { - LM_DBG("confirming rinstance is the same - search has [%.*s] and proposed found contact has [%.*s]", - rinstance.len, rinstance.s, - c->rinstance.len, c->rinstance.s); - if ((rinstance.len == c->rinstance.len) && memcmp(rinstance.s, c->rinstance.s, rinstance.len) != 0) { - LM_DBG("rinstance does not match - not match here...\n"); - c = c->next; - continue; + LM_DBG("contact received [%d:%.*s:%d]\n", c->received_proto, c->received_host.len, c->received_host.s, c->received_port); + + if ((c->aorhash == aorhash) && + (((c->contact_host.len == contact_info->via_host.len) + && (memcmp(contact_info->via_host.s, c->contact_host.s, c->contact_host.len) == 0) + && (c->contact_port == contact_info->via_port) + && !(contact_info->searchflag & SEARCH_RECEIVED)) + || ((contact_info->searchflag & SEARCH_RECEIVED) + && ((c->received_host.len == contact_info->received_host.len) && (memcmp(c->received_host.s, contact_info->received_host.s, contact_info->received_host.len) == 0)) + && ((c->received_port == contact_info->received_port) || (c->contact_port == contact_info->received_port))))) { /*volte comes from a different port.... typically uses 4060*/ + LM_DBG("found contact with URI [%.*s]\n", c->aor.len, c->aor.s); + if (has_rinstance) { + LM_DBG("confirming rinstance is the same - search has [%.*s] and proposed found contact has [%.*s]", + rinstance.len, rinstance.s, + c->rinstance.len, c->rinstance.s); + if ((rinstance.len == c->rinstance.len) && memcmp(rinstance.s, c->rinstance.s, rinstance.len) != 0) { + LM_DBG("rinstance does not match - no match here...\n"); + c = c->next; + continue; + } + } + //finally check state being searched for + if ( (contact_info->reg_state != PCONTACT_ANY) && ((contact_info->reg_state & c->reg_state) == 0)) { + LM_DBG("can't find contact for requested reg state [%d] - (have [%d])\n", contact_info->reg_state, c->reg_state); + c = c->next; + continue; } - } *_c = c; return 0; } @@ -534,21 +545,6 @@ int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact** return 1; /* Nothing found */ } -int get_pcontact_by_src(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c) { - str s_contact; - pcontact_info_t contact_info; - int ret; - - LM_DBG("Trying to find contact by src with URI: [%.*s]\n", s_contact.len, s_contact.s); - contact_info.via_host = *_host; - contact_info.via_port = _port; - contact_info.via_prot = _proto; - - ret = get_pcontact(_d, &contact_info, _c); - - return ret; -} - int update_security(udomain_t* _d, security_type _t, security_t* _s, struct pcontact* _c) { if (db_mode == WRITE_THROUGH && db_update_pcontact_security(_c, _t, _s) != 0) { LM_ERR("Error updating security for contact in DB\n"); @@ -667,6 +663,7 @@ static inline pcontact_info_t* dbrow2info( db_val_t *vals, str *contact) if (VAL_NULL(vals+4) || !received.s || !received.s[0]) { LM_DBG("Empty received for contact [%.*s]....\n", contact->len, contact->s); /*this could happen if you have been notified about a contact from S-CSCF*/ received.len = 0; + received.s = 0; } else { received.len = strlen(received.s); } diff --git a/modules/ims_usrloc_pcscf/usrloc.h b/modules/ims_usrloc_pcscf/usrloc.h index cf7b01d7d8f..084e875104a 100644 --- a/modules/ims_usrloc_pcscf/usrloc.h +++ b/modules/ims_usrloc_pcscf/usrloc.h @@ -148,12 +148,13 @@ typedef struct ppublic { /** Enumeration for public identity Registration States */ enum pcontact_reg_states { - PCONTACT_NOT_REGISTERED = 0, /**< User not-registered, no profile stored */ - PCONTACT_REGISTERED = 1, /**< User registered */ - PCONTACT_REG_PENDING = -1, /**< User not-registered, profile stored */ - PCONTACT_REG_PENDING_AAR = -2, /**< User not-registered, profile stored, AAR sent */ - PCONTACT_DEREGISTERED = -3, - PCONTACT_DEREG_PENDING_PUBLISH = -4 + PCONTACT_ANY = 0, + PCONTACT_NOT_REGISTERED = 1<<0, /**< User not-registered, no profile stored */ + PCONTACT_REGISTERED = 1<<1, /**< User registered */ + PCONTACT_REG_PENDING = 1<<2, /**< User not-registered, profile stored */ + PCONTACT_REG_PENDING_AAR = 1<<3, /**< User not-registered, profile stored, AAR sent */ + PCONTACT_DEREGISTERED = 1<<4, + PCONTACT_DEREG_PENDING_PUBLISH = 1<<5 }; static inline char* reg_state_to_string(enum pcontact_reg_states reg_state) {