/*! * \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 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); } } }