/*! * \brief Get pointer to ucontact with given contact * \param _r record where to search the contacts * \param _c contact string * \param _callid callid * \param _path path * \param _cseq CSEQ number * \param _co found contact * \return 0 - found, 1 - not found, -1 - invalid found, * -2 - found, but to be skipped (same cseq) - don't forget to release_ucontact so dec. the ref counter */ int get_scontact(str* _c, str* _callid, str* _path, int _cseq, struct ucontact** _co) { unsigned int sl; ucontact_t* ptr; int with_callid = 0; ptr = 0; *_co = 0; sl = core_hash(_c, 0, contact_list->size); LM_DBG("looking for contact [%.*s] in slot %d\n", _c->len, _c->s, sl); get_act_time(); lock_contact_slot_i(sl); switch (matching_mode) { case CONTACT_ONLY: ptr = contact_match(sl, _c); break; case CONTACT_CALLID: ptr = contact_callid_match(sl, _c, _callid); with_callid = 1; break; case CONTACT_PATH: ptr = contact_path_match(sl, _c, _path); break; case CONTACT_PORT_IP_ONLY: ptr = contact_port_ip_match(sl, _c); break; default: LM_CRIT("unknown matching_mode %d\n", matching_mode); unlock_contact_slot_i(sl); return -1; } if (ptr) { LM_DBG("have partially found a contact\n"); /* found -> check callid and cseq */ if (!with_callid || (_callid && ptr->callid.len == _callid->len && memcmp(_callid->s, ptr->callid.s, _callid->len) == 0)) { if (_cseq < ptr->cseq) { LM_DBG("cseq less than expected\n"); } } LM_DBG("contact found p=[%p], aor:[%.*s] and contact:[%.*s], state [%d]\n", ptr, ptr->aor.len, ptr->aor.s, ptr->c.len, ptr->c.s, ptr->state); ref_contact_unsafe(ptr); *_co = ptr; unlock_contact_slot_i(sl); /*TODO: we probably need to ref count here..... */ return 0; } unlock_contact_slot_i(sl); return 1; }
/*! * \brief Add a new contact in memory * * Add a new contact in memory, contacts are ordered by: * 1) q value, 2) descending modification time * \param _r record this contact belongs to * \param _c contact * \param _ci contact information * \return pointer to new created contact on success, 0 on failure */ ucontact_t* mem_insert_scontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci) { ucontact_t* c; int sl; if ((c = new_ucontact(_r->domain, &_r->public_identity, _c, _ci)) == 0) { LM_ERR("failed to create new contact\n"); return 0; } counter_inc(ul_scscf_cnts_h.active_contacts); LM_DBG("Created new contact in memory with AOR: [%.*s] and hash [%d]\n", _c->len, _c->s, c->sl); sl = (c->sl); lock_contact_slot_i(sl); contact_slot_add(&contact_list->slot[sl], c); unlock_contact_slot_i(sl); return c; }
void lock_contact_slot(str* contact_uri) { unsigned int sl; sl = core_hash(contact_uri, 0, contact_list->size); lock_contact_slot_i(sl); }
/*! * \brief Run timer handler for given domain * \param _d domain */ void mem_timer_udomain(udomain_t* _d) { struct impurecord* ptr, *t; struct ucontact* contact_ptr, *tmp_contact_ptr; int i; //go through contacts first LM_DBG("*** mem_timer_udomain - checking contacts - START ***\n"); for (i = 0; i < contact_list->size; i++) { #ifdef EXTRA_DEBUG LM_DBG("looking for contacts in slot %d\n", i); #endif lock_contact_slot_i(i); contact_ptr = contact_list->slot[i].first; while (contact_ptr) { LM_DBG("We have a contact in the new contact list in slot %d = [%.*s] (%.*s) which expires in %lf seconds and has a ref count of %d\n", i, contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s, (double) contact_ptr->expires - time(NULL), contact_ptr->ref_count); if (contact_ptr->ref_count <= 0) { LM_DBG("Deleting contact [%.*s]\n", contact_ptr->c.len, contact_ptr->c.s); tmp_contact_ptr = contact_ptr->next; delete_ucontact(contact_ptr); contact_ptr = tmp_contact_ptr; } else { contact_ptr = contact_ptr->next; } } unlock_contact_slot_i(i); } LM_DBG("*** mem_timer_udomain - checking contacts - FINISHED ***\n"); int temp = 0; LM_DBG("*** mem_timer_udomain - checking IMPUs - START ***\n"); for (i = 0; i < _d->size; i++) { lock_ulslot(_d, i); ptr = _d->table[i].first; temp = 0; while (ptr) { temp = 1; #ifdef EXTRA_DEBUG LM_DBG("ULSLOT %d LOCKED\n", i); #endif t = ptr; ptr = ptr->next; timer_impurecord(t); // if (t->reg_state == IMPU_NOT_REGISTERED && t->shead == 0) { // //remove it - housekeeping - not sure why its still here...? // if (exists_ulcb_type(t->cbs, UL_IMPU_NR_DELETE)) // run_ul_callbacks(t->cbs, UL_IMPU_NR_DELETE, t, NULL); // // LM_DBG("about to delete impurecord\n"); // delete_impurecord(_d, &t->public_identity, t); // } //else if (t->reg_state == IMPU_UNREGISTERED) {//Remove IMPU record if it is in state IMPU_UNREGISTERED and has expired // // if (time_now >= t->expires) {//check here and only remove if no subscribes - if there is a subscribe then bump the validity by unreg_validity // if(t->shead != 0){ // LM_DBG("This impurecord still has subscriptions - extending the expiry"); // t->expires = time(NULL) + unreg_validity; // } else { // if (exists_ulcb_type(t->cbs, UL_IMPU_UNREG_EXPIRED)) // run_ul_callbacks(t->cbs, UL_IMPU_UNREG_EXPIRED, t, NULL); // LM_DBG("about to delete impurecord\n"); // delete_impurecord(_d, &t->public_identity, t); // } // } // //} else if (t->reg_state != IMPU_UNREGISTERED && t->contacts == 0) { /* Remove the entire record if it is empty IFF it is not an UNREGISTERED RECORD */ // } else if (t->reg_state != IMPU_UNREGISTERED && t->num_contacts == 0 && t->shead == 0) { /* Remove the entire record if it is empty IFF it is not an UNREGISTERED RECORD */ // /* TS 23.228 5.3.2.1 (release 11) */ // //need a way of distinguishing between deletes that need a SAR (expired) and deletes that do not need a SAR (explicit de reg) // //we only want to send one SAR for each implicit IMPU set // //make sure all IMPU's associated with this set are de-registered before calling the callbacks // int first=1; // int this_is_first = 0; // // lock_get(t->s->lock); // for (k = 0; k < t->s->service_profiles_cnt; k++){ // for (j = 0;j < t->s->service_profiles[k].public_identities_cnt;j++) { // impu = &(t->s->service_profiles[k].public_identities[j]); // // sl = core_hash(&impu->public_identity, 0, _d->size); // if (sl != i) // lock_udomain(_d, &impu->public_identity); // // if (first) { // first = 0; //dont do anything - we will leave this impu to be processed as normal // if (!strncmp(impu->public_identity.s, t->public_identity.s, t->public_identity.len)) { // //we are the first in the implicit set // this_is_first = 1; // } // } else { // //set all other implicits to not registered // if (update_impurecord(_d, &impu->public_identity, IMPU_NOT_REGISTERED, // -1/*barring*/, -1 /*do not change send sar on delete */, 0/*is_primary*/, NULL, NULL, NULL, NULL, NULL, &temp_impu) != 0) { // LM_ERR("Unable to update impurecord for <%.*s>\n", impu->public_identity.len, impu->public_identity.s); // } // } // if (sl != i) // unlock_udomain(_d, &impu->public_identity); // } // } // lock_release(t->s->lock); // // if (this_is_first) { // //now run a normal callback on our // if (exists_ulcb_type(t->cbs, UL_IMPU_REG_NC_DELETE)) // run_ul_callbacks(t->cbs, UL_IMPU_REG_NC_DELETE, t, NULL); // LM_DBG("about to delete impurecord\n"); // delete_impurecord(_d, &t->public_identity, t); // } // } } if (temp) { #ifdef EXTRA_DEBUG LM_DBG("ULSLOT %d UN-LOCKED\n", i); #endif } unlock_ulslot(_d, i); } LM_DBG("*** mem_timer_udomain - checking IMPUs - FINISHED ***\n"); }
/*! * \brief Expires timer for NO_DB db_mode * * Expires timer for NO_DB db_mode, process all contacts from * the record, delete the expired ones from memory. * \param _r processed record */ static inline void process_impurecord(impurecord_t* _r) { int flag, mustdeleteimpu = 1, n, k; unsigned int sl; ucontact_t* ptr; int hascontacts; udomain_t* _d; reg_subscriber *s; subs_t* sub_dialog; get_act_time(); s = _r->shead; LM_DBG("Checking validity of IMPU: <%.*s> registration subscriptions\n", _r->public_identity.len, _r->public_identity.s); while (s) { if (!valid_subscriber(s, act_time)) { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> expired and removed.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s); delete_subscriber(_r, s); } else { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> is valid and expires in %d seconds.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s, (unsigned int) (s->expires - time(NULL))); sl = core_hash(&s->call_id, &s->to_tag, sub_dialog_hash_size); LM_DBG("Hash size: <%i>", sub_dialog_hash_size); LM_DBG("Searching sub dialog hash info with call_id: <%.*s> and ttag <%.*s> ftag <%.*s> and hash code <%i>", s->call_id.len, s->call_id.s, s->to_tag.len, s->to_tag.s, s->from_tag.len, s->from_tag.s, sl); /* search the record in hash table */ lock_get(&sub_dialog_table[sl].lock); sub_dialog = pres_search_shtable(sub_dialog_table, s->call_id, s->to_tag, s->from_tag, sl); if (sub_dialog == NULL) { LM_ERR("DBG:registrar_timer: Subscription has no dialog record in hash table\n"); } else { LM_DBG("DBG:registrar_timer: Subscription has dialog record in hash table with presentity uri <%.*s>\n", sub_dialog->pres_uri.len, sub_dialog->pres_uri.s); } lock_release(&sub_dialog_table[sl].lock); mustdeleteimpu = 0; } s = s->next; } LM_DBG("\tPublic Identity %.*s, Barred: [%d], State: [%s]\n", _r->public_identity.len, _r->public_identity.s, _r->barring, get_impu_regstate_as_string(_r->reg_state)); flag = 0; hascontacts = 0; num_contacts_to_expire = 0; for (k = 0; (k < _r->num_contacts) && (k < MAX_CONTACTS_PER_IMPU); k++) { if ((ptr = _r->newcontacts[k])) { flag = 1; if (!VALID_CONTACT(ptr, act_time)) { if (ptr->state == CONTACT_DELETED) { LM_DBG("Contact: <%.*s> has been deleted - unlinking from IMPU\n", ptr->c.len, ptr->c.s); contacts_to_expire[num_contacts_to_expire] = ptr; num_contacts_to_expire++; } else if (ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY) { LM_DBG("Contact: <%.*s> is in state CONTACT_EXPIRE_PENDING_NOTIFY....running callback\n", ptr->c.len, ptr->c.s); if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE_CONTACT)) { LM_DBG("Running callback UL_IMPU_DELETE_CONTACT for contact [%.*s] and impu [%.*s]\n", ptr->c.len, ptr->c.s, _r->public_identity.len, _r->public_identity.s); run_ul_callbacks(_r->cbs, UL_IMPU_DELETE_CONTACT, _r, ptr); } hascontacts = 1; // we do this because the impu must only be deleted if in state deleted.... mustdeleteimpu = 0; } else if (ptr->state == CONTACT_VALID) { LM_DBG("Contact: <%.*s> is in state valid but it has expired.... ignoring as the contact check will set the appropriate action/state\n", ptr->c.len, ptr->c.s); mustdeleteimpu = 0; hascontacts = 1; } else { LM_WARN("Bogus state for contact [%.*s] - state: %d... ignoring", ptr->c.len, ptr->c.s, ptr->state); mustdeleteimpu = 0; hascontacts = 1; } } else { LM_DBG("\t\tContact #%i - %.*s, Ref [%d] (expires in %ld seconds) (State: %d)\n", k, ptr->c.len, ptr->c.s, ptr->ref_count, ptr->expires - act_time, ptr->state); mustdeleteimpu = 0; hascontacts = 1; } } else { LM_WARN("num_contacts and actual data not consistent... .aborting\n"); break; } } if (num_contacts_to_expire > 0) { LM_DBG("\tThere are %d contacts to expire/unlink\n", num_contacts_to_expire); for (n = 0; n < num_contacts_to_expire; n++) { ptr = contacts_to_expire[n]; LM_DBG("\t\texpiring contact %i: [%.*s] in slot [%d]\n", n, contacts_to_expire[n]->c.len, contacts_to_expire[n]->c.s, contacts_to_expire[n]->sl); sl = ptr->sl; lock_contact_slot_i(sl); unlink_contact_from_impu(_r, ptr, 1, 0 /*implicit dereg of contact from IMPU*/); unlock_contact_slot_i(sl); } } if (!flag) LM_DBG("no contacts\n"); if (mustdeleteimpu) { register_udomain("location", &_d); delete_impurecord(_d, &_r->public_identity, _r); } else { if (!hascontacts) { LM_DBG("This impu is not to be deleted but has no contacts - changing state to IMPU_UNREGISTERED\n"); _r->reg_state = IMPU_UNREGISTERED; } } }
/*! * \brief Run timer handler for given domain * \param _d domain */ void mem_timer_udomain(udomain_t* _d) { struct impurecord* ptr, *t; struct ucontact* contact_ptr; int i, n, temp; //go through contacts first n = contact_list->max_collisions; LM_DBG("*** mem_timer_udomain - checking contacts - START ***\n"); for (i = 0; i < contact_list->size; i++) { lock_contact_slot_i(i); contact_ptr = contact_list->slot[i].first; while (contact_ptr) { LM_DBG("We have a contact in the new contact list in slot %d = [%.*s] (%.*s) which expires in %lf seconds and has a ref count of %d\n", i, contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s, (double) contact_ptr->expires - time(NULL), contact_ptr->ref_count); //contacts are now deleted during impurecord processing contact_ptr = contact_ptr->next; } if (contact_list->slot[i].n > n) { n = contact_list->slot[i].n; } unlock_contact_slot_i(i); contact_list->max_collisions = n; } LM_DBG("*** mem_timer_udomain - checking contacts - FINISHED ***\n"); temp = 0; n = _d->max_collisions; LM_DBG("*** mem_timer_udomain - checking IMPUs - START ***\n"); for (i = 0; i < _d->size; i++) { lock_ulslot(_d, i); ptr = _d->table[i].first; temp = 0; while (ptr) { temp = 1; #ifdef EXTRA_DEBUG LM_DBG("ULSLOT %d LOCKED\n", i); #endif t = ptr; ptr = ptr->next; timer_impurecord(t); } if (temp) { #ifdef EXTRA_DEBUG LM_DBG("ULSLOT %d UN-LOCKED\n", i); #endif } if (_d->table[i].n > n) n = _d->table[i].n; unlock_ulslot(_d, i); _d->max_collisions = n; } LM_DBG("*** mem_timer_udomain - checking IMPUs - FINISHED ***\n"); n = ims_subscription_list->max_collisions; for (i = 0; i < ims_subscription_list->size; i++) { lock_subscription_slot(i); if (ims_subscription_list->slot[i].n > n) { n = ims_subscription_list->slot[i].n; } unlock_subscription_slot(i); } ims_subscription_list->max_collisions = n; }
void release_ucontact(struct ucontact* _c) { lock_contact_slot_i(_c->contact_hash); _c->ref_count--; unlock_contact_slot_i(_c->contact_hash); }
/*! * \brief Run timer handler for given domain * \param _d domain */ void mem_timer_udomain(udomain_t* _d, int istart, int istep) { struct impurecord* ptr, *t; struct ucontact* contact_ptr; unsigned int num_expired_contacts = 0; int i, n, temp; time_t now; int abort = 0; int slot; int ref_count_db; now = time(0); if (istart == 0) { int numcontacts = contact_list->size*2; //assume we should be ok for each slot to have 2 collisions if (expired_contacts_size < numcontacts) { LM_DBG("Changing expired_contacts list size from %d to %d\n", expired_contacts_size, numcontacts); if (expired_contacts){ pkg_free(expired_contacts); } expired_contacts = (ucontact_t**)pkg_malloc(numcontacts*sizeof(ucontact_t**)); if (!expired_contacts) { LM_ERR("no more pkg mem trying to allocate [%lu] bytes\n", numcontacts*sizeof(ucontact_t**)); return; } expired_contacts_size = numcontacts; } //go through contacts first n = contact_list->max_collisions; LM_DBG("*** mem_timer_udomain - checking contacts - START ***\n"); for (i=0; i < contact_list->size; i++) { lock_contact_slot_i(i); contact_ptr = contact_list->slot[i].first; while (contact_ptr) { if (num_expired_contacts >= numcontacts) { LM_WARN("we don't have enough space to expire all contacts in this pass - will continue in next pass\n"); abort = 1; break; } LM_DBG("We have a [3gpp=%d] contact in the new contact list in slot %d = [%.*s] (%.*s) which expires in %lf seconds and has a ref count of %d (state: %s)\n", contact_ptr->is_3gpp, i, contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s, (double) contact_ptr->expires - now, contact_ptr->ref_count, get_contact_state_as_string(contact_ptr->state)); //contacts are now deleted during impurecord processing if ((contact_ptr->expires-now) <= 0) { if (contact_ptr->state == CONTACT_DELAYED_DELETE) { if (contact_ptr->ref_count <= 0) { LM_DBG("contact in state CONTACT_DELATED_DELETE is about to be deleted"); expired_contacts[num_expired_contacts] = contact_ptr; num_expired_contacts++; } else { /* we could fall here not because contact is still referenced but also because we failed before to get a lock to unref the contact, so we check if contact is really referenced*/ if (db_mode != NO_DB) { LM_DBG("contact in state CONTACT_DELAYED_DELETE still has a ref count of [%d] in memory. Check on DB \n", contact_ptr->ref_count); ref_count_db = db_check_if_contact_is_linked(contact_ptr); if (ref_count_db < 0) { LM_ERR("Unable to check if contact is unlinked\n"); } else if (ref_count_db == 0) { LM_DBG("Contact has ref count [%d] but there's no link on the DB. Deleting contact", contact_ptr->ref_count); contact_ptr->ref_count = 0; expired_contacts[num_expired_contacts] = contact_ptr; num_expired_contacts++; } else { LM_DBG("Contact in state CONTACT_DELAYED_DELETE has ref count [%d] on DB", ref_count_db); } } else { LM_DBG("contact in state CONTACT_DELAYED_DELETE still has a ref count of [%d] in memory. Not doing anything for now \n", contact_ptr->ref_count); } } } else if (contact_ptr->state != CONTACT_DELETED) { LM_DBG("expiring contact [%.*s].... setting to CONTACT_EXPIRE_PENDING_NOTIFY\n", contact_ptr->aor.len, contact_ptr->aor.s); contact_ptr->state = CONTACT_EXPIRE_PENDING_NOTIFY; ref_contact_unsafe(contact_ptr); expired_contacts[num_expired_contacts] = contact_ptr; num_expired_contacts++; } } contact_ptr = contact_ptr->next; } if (contact_list->slot[i].n > n) { n = contact_list->slot[i].n; } unlock_contact_slot_i(i); contact_list->max_collisions = n; if (abort == 1) { break; } } LM_DBG("*** mem_timer_udomain - checking contacts - FINISHED ***\n"); } temp = 0; n = _d->max_collisions; LM_DBG("*** mem_timer_udomain - checking IMPUs - START ***\n"); for (i = istart; i < _d->size; i+=istep) { lock_ulslot(_d, i); ptr = _d->table[i].first; temp = 0; while (ptr) { temp = 1; #ifdef EXTRA_DEBUG LM_DBG("ULSLOT %d LOCKED\n", i); #endif t = ptr; ptr = ptr->next; timer_impurecord(t); } if (temp) { #ifdef EXTRA_DEBUG LM_DBG("ULSLOT %d UN-LOCKED\n", i); #endif } if (_d->table[i].n > n) n = _d->table[i].n; unlock_ulslot(_d, i); _d->max_collisions = n; } LM_DBG("*** mem_timer_udomain - checking IMPUs - FINISHED ***\n"); if (istart == 0) { n = ims_subscription_list->max_collisions; for (i = 0; i < ims_subscription_list->size; i++) { lock_subscription_slot(i); if (ims_subscription_list->slot[i].n > n) { n = ims_subscription_list->slot[i].n; } unlock_subscription_slot(i); } ims_subscription_list->max_collisions = n; /* now we delete the expired contacts. (mark them for deletion */ for (i=0; i<num_expired_contacts; i++) { slot = expired_contacts[i]->sl; lock_contact_slot_i(slot); if (expired_contacts[i]->state != CONTACT_DELAYED_DELETE) { LM_DBG("Setting contact state to CONTACT_DELETED for contact [%.*s]\n", expired_contacts[i]->aor.len, expired_contacts[i]->aor.s); expired_contacts[i]->state = CONTACT_DELETED; unref_contact_unsafe(expired_contacts[i]); } else { LM_DBG("deleting contact [%.*s]\n", expired_contacts[i]->aor.len, expired_contacts[i]->aor.s); delete_scontact(expired_contacts[i]); } unlock_contact_slot_i(slot); } } }