/*! * \brief Update ucontact with new values * \param _r record the contact belongs to * \param _c updated contact * \param _ci new contact informations * \return 0 on success, -1 on failure */ int update_ucontact(struct impurecord* _r, ucontact_t* _c, ucontact_info_t* _ci) { /* we have to update memory in any case, but database directly * only in db_mode 1 */ LM_DBG("Updating contact aor: [%.*s] and contact uri: [%.*s]\n", _c->aor.len, _c->aor.s, _c->c.len, _c->c.s); if (mem_update_ucontact(_c, _ci) < 0) { LM_ERR("failed to update memory\n"); return -1; } if (db_mode == WRITE_THROUGH && (db_insert_ucontact(_r, _c) != 0)) { /* this is an insert/update */ LM_ERR("failed to update contact in DB [%.*s]\n", _c->aor.len, _c->aor.s); return -1; } //make sure IMPU is linked to this contact link_contact_to_impu(_r, _c, 1); /* run callbacks for UPDATE event */ if (exists_ulcb_type(_c->cbs, UL_CONTACT_UPDATE)) { LM_DBG("exists callback for type= UL_CONTACT_UPDATE\n"); run_ul_callbacks(_c->cbs, UL_CONTACT_UPDATE, _r, _c); } if (exists_ulcb_type(_r->cbs, UL_IMPU_UPDATE_CONTACT)) { run_ul_callbacks(_r->cbs, UL_IMPU_UPDATE_CONTACT, _r, _c); } // update_contact_pos(_r, _c); return 0; }
/*! * \brief Create and insert new contact into impurecord * \param _r record into the new contact should be inserted * \param _contact contact string * \param _ci contact information * \param _c new created contact * \return 0 on success, -1 on failure */ int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucontact_t** _c) { //First check our constraints if (maxcontact > 0 && maxcontact_behaviour > 0) { ucontact_t* contact = _r->contacts; int numcontacts = 0; while (contact) { numcontacts++; contact = contact->next; } if (numcontacts >= maxcontact) { switch (maxcontact_behaviour) { case 1://reject LM_ERR("too many contacts already registered for IMPU <%.*s>\n", _r->public_identity.len, _r->public_identity.s); return -1; case 2://overwrite oldest LM_DBG("Too many contacts already registered, overwriting oldest for IMPU <%.*s>\n", _r->public_identity.len, _r->public_identity.s); //we can just remove the first one seeing the contacts are ordered on insertion with newest last and oldest first mem_delete_ucontact(_r, _r->contacts); break; default://unknown LM_ERR("unknown maxcontact behaviour..... ignoring\n"); break; } } } //at this stage we are safe to insert the new contact LM_DBG("INSERTing ucontact in usrloc module\n"); if (((*_c) = mem_insert_ucontact(_r, _contact, _ci)) == 0) { LM_ERR("failed to insert contact\n"); return -1; } /*DB?*/ if (db_mode == WRITE_THROUGH && db_insert_ucontact(_r, *_c) != 0) { LM_ERR("error inserting contact into db"); return -1; } if (exists_ulcb_type(NULL, UL_CONTACT_INSERT)) { run_ul_callbacks(NULL, UL_CONTACT_INSERT, _r, *_c); } if (exists_ulcb_type(_r->cbs, UL_IMPU_NEW_CONTACT)) { run_ul_callbacks(_r->cbs, UL_IMPU_NEW_CONTACT, _r, *_c); } return 0; }
/*! * \brief Write through timer, used for WRITE_THROUGH db_mode * * Write through timer, used for WRITE_THROUGH db_mode. Process all * contacts from the record, delete all expired ones from the DB. * \param _r processed record * \note currently unused, this mode is also handled by the wb_timer */ static inline void wt_timer(urecord_t* _r) { ucontact_t* ptr, *t; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) { run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); } LM_DBG("Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; if (db_delete_ucontact(t) < 0) { LM_ERR("deleting contact from database failed\n"); } mem_delete_ucontact(_r, t); update_stat( _r->slot->d->expires, 1); } else { ptr = ptr->next; } } }
/* * Create and insert new contact * into urecord */ int insert_ucontact(urecord_t* _r, str* aor, str* _c, time_t _e, qvalue_t _q, str* _cid, int _cs, unsigned int _flags, struct ucontact** _con, str* _ua, str* _recv, struct socket_info* sock, str* _inst, int sid) { if (mem_insert_ucontact(_r, aor, _c, _e, _q, _cid, _cs, _flags, _con, _ua, _recv, sock, _inst, sid) < 0) { LOG(L_ERR, "insert_ucontact(): Error while inserting contact\n"); return -1; } notify_watchers(_r, *_con, (_e > 0) ? PRES_ONLINE : PRES_OFFLINE); if (exists_ulcb_type(UL_CONTACT_INSERT)) { run_ul_callbacks( UL_CONTACT_INSERT, *_con); } save_reg_avps(*_con); if (db_mode == WRITE_THROUGH) { if (db_store_ucontact(*_con) < 0) { LOG(L_ERR, "insert_ucontact(): Error while inserting in database\n"); } (*_con)->state = CS_SYNC; } return 0; }
/*! * \brief Write-back timer, used for WRITE_BACK db_mode * * Write-back timer, used for WRITE_BACK db_mode. Process * all contacts from the record, delete expired ones from the DB. * Furthermore it updates changed contacts, and also insert new * ones in the DB. * \param _r processed record */ static inline void wb_timer(urecord_t* _r) { ucontact_t* ptr, *t; cstate_t old_state; int op; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) { run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); } LM_DBG("Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); update_stat( _r->slot->d->expires, 1); t = ptr; ptr = ptr->next; /* Should we remove the contact from the database ? */ if (st_expired_ucontact(t) == 1) { if (db_delete_ucontact(t) < 0) { LM_ERR("failed to delete contact from the database\n"); } } mem_delete_ucontact(_r, t); } else { /* Determine the operation we have to do */ old_state = ptr->state; op = st_flush_ucontact(ptr); switch(op) { case 0: /* do nothing, contact is synchronized */ break; case 1: /* insert */ if (db_insert_ucontact(ptr) < 0) { LM_ERR("inserting contact into database failed\n"); ptr->state = old_state; } break; case 2: /* update */ if (db_update_ucontact(ptr) < 0) { LM_ERR("updating contact in db failed\n"); ptr->state = old_state; } break; } ptr = ptr->next; } } }
static inline void nodb_timer(pcontact_t* _c) { LM_DBG("Running nodb timer on <%.*s>, " "Reg state: %s, " "Expires: %d, " "Expires in: %d seconds, " "Received: %.*s:%d, " "Path: %.*s, " "Proto: %d, " "Hash: %u, " "Slot: %u\n", _c->aor.len, _c->aor.s, reg_state_to_string(_c->reg_state), (int)_c->expires, (int)(_c->expires - time(NULL)), _c->received_host.len, _c->received_host.s, _c->received_port, _c->path.len, _c->path.s, _c->received_proto, _c->aorhash, _c->sl); get_act_time(); if ((_c->expires - act_time) + expires_grace <= 0) {//we've allowed some grace time TODO: add as parameter //if ((_c->expires - act_time) <= -10) {//we've allowed some grace time TODO: add as parameter LM_DBG("pcscf contact <%.*s> has expired and will be removed\n", _c->aor.len, _c->aor.s); if (exists_ulcb_type(PCSCF_CONTACT_EXPIRE)) { run_ul_callbacks(PCSCF_CONTACT_EXPIRE, _c); } if (db_mode == WRITE_THROUGH && db_delete_pcontact(_c) != 0) { LM_ERR("Error deleting ims_usrloc_pcscf record in DB"); } update_stat(_c->slot->d->expired, 1); mem_delete_pcontact(_c->slot->d, _c); return; } //TODO: this is just for tmp debugging // p = _c->head; // while (p) { // if (p->is_default) // LM_DBG("public identity %i (default): <%.*s>\n", i, p->public_identity.len, p->public_identity.s); // else // LM_DBG("public identity %i: <%.*s>\n", i, p->public_identity.len, p->public_identity.s); // i++; // p=p->next; // } // // LM_DBG("There are %i service routes as follows:\n", _c->num_service_routes); // for (i=0; i<_c->num_service_routes; i++) { // LM_DBG("service route %i: <%.*s>\n", i+1, _c->service_routes[i].len, _c->service_routes[i].s); // } }
/*! * \brief Delete ucontact from impurecord * \param _r record where the contact belongs to * \param _c deleted contact * \return 0 on success, -1 on failure */ int delete_ucontact(impurecord_t* _r, struct ucontact* _c) { int ret = 0; if (exists_ulcb_type(_c->cbs, UL_CONTACT_DELETE)) { run_ul_callbacks(_c->cbs, UL_CONTACT_DELETE, _r, _c); } if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE_CONTACT)) { run_ul_callbacks(_r->cbs, UL_IMPU_DELETE_CONTACT, _r, _c); } /*DB?*/ if (db_mode == WRITE_THROUGH && db_delete_ucontact(_r, _c) != 0) { LM_ERR("error removing contact from DB [%.*s]... will still remove from memory\n", _c->c.len, _c->c.s); } mem_delete_ucontact(_r, _c); return ret; }
int delete_pcontact(udomain_t* _d, str* _aor, struct pcontact* _c) { if (_c==0) { if (get_pcontact(_d, _aor, &_c) > 0) { return 0; } } if (exists_ulcb_type(PCSCF_CONTACT_DELETE)) { run_ul_callbacks(PCSCF_CONTACT_DELETE, _c); } mem_delete_pcontact(_d, _c); return 0; }
/*! * \brief Update ucontact with new values * \param _r record the contact belongs to * \param _c updated contact * \param _ci new contact informations * \return 0 on success, -1 on failure */ int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci) { int res; /* we have to update memory in any case, but database directly * only in db_mode 1 */ if (mem_update_ucontact( _c, _ci) < 0) { LM_ERR("failed to update memory\n"); return -1; } /* run callbacks for UPDATE event */ if (exists_ulcb_type(UL_CONTACT_UPDATE)) { LM_DBG("exists callback for type= UL_CONTACT_UPDATE\n"); run_ul_callbacks( UL_CONTACT_UPDATE, _c); } if (_r && db_mode!=DB_ONLY) update_contact_pos( _r, _c); st_update_ucontact(_c); if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) { /* * prevent problems when we're in a failover situation: the first DB contains * the complete location entries, the other misses some of them. Before the * update it checks for a entry in the first DB, this is ok. But the update * in the second DB will not work. Thus the expire mechanism don't work, it * takes too long until both DBs have the same number of entries again. */ if (ul_db_update_as_insert) res = db_insert_ucontact(_c); else res = db_update_ucontact(_c); if (res < 0 ) { LM_ERR("failed to update database\n"); return -1; } else { _c->state = CS_SYNC; } } return 0; }
/* * This routine is used when db_mode is * set to WRITE_THROUGH */ static inline int wt_timer(urecord_t* _r) { ucontact_t* ptr, *t; int not = 0; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) { run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); } notify_watchers(_r, ptr, PRES_OFFLINE); LOG(L_NOTICE, "Binding '%.*s','%.*s' has expired\n", ptr->uid->len, ZSW(ptr->uid->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; /* it was the last contact and it was in normal * state, so notify */ if (!ptr && t->state == CS_SYNC) not=1; if (db_delete_ucontact(t) < 0) { LOG(L_ERR, "wt_timer(): Error while deleting contact from " "database\n"); } delete_reg_avps(t); mem_delete_ucontact(_r, t); _r->slot->d->expired++; } else { /* the contact was unregistered and is not marked * for replication so remove it, but the notify was * already done during unregister */ ptr = ptr->next; } } return 0; }
/*! * \brief Delete ucontact from urecord * \param _r record where the contact belongs to * \param _c deleted contact * \return 0 on success, -1 on failure */ int delete_ucontact(urecord_t* _r, struct ucontact* _c) { int ret = 0; if (exists_ulcb_type(UL_CONTACT_DELETE)) { run_ul_callbacks( UL_CONTACT_DELETE, _c); } if (st_delete_ucontact(_c) > 0) { if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) { if (db_delete_ucontact(_c) < 0) { LM_ERR("failed to remove contact from database\n"); ret = -1; } } mem_delete_ucontact(_r, _c); } return ret; }
int delete_pcontact(udomain_t* _d, str* _aor, struct pcontact* _c) { if (_c==0) { if (get_pcontact(_d, _aor, &_c) > 0) { return 0; } } if (exists_ulcb_type(PCSCF_CONTACT_DELETE)) { run_ul_callbacks(PCSCF_CONTACT_DELETE, _c); } if (db_mode == WRITE_THROUGH && db_delete_pcontact(_c) != 0) { LM_ERR("Error deleting contact from DB"); return -1; } mem_delete_pcontact(_d, _c); return 0; }
/* * Delete ucontact from urecord */ int delete_ucontact(urecord_t* _r, struct ucontact* _c) { if (exists_ulcb_type(UL_CONTACT_DELETE)) { run_ul_callbacks( UL_CONTACT_DELETE, _c); } notify_watchers(_r, _c, PRES_OFFLINE); if (st_delete_ucontact(_c) > 0) { if (db_mode == WRITE_THROUGH) { if (db_delete_ucontact(_c) < 0) { LOG(L_ERR, "delete_ucontact(): Can't remove contact from " "database\n"); } } delete_reg_avps(_c); mem_delete_ucontact(_r, _c); } return 0; }
/*! * \brief Create and insert new contact into urecord * \param _r record into the new contact should be inserted * \param _contact contact string * \param _ci contact information * \param _c new created contact * \return 0 on success, -1 on failure */ int insert_ucontact(urecord_t* _r, str* _contact, ucontact_info_t* _ci, ucontact_t** _c) { if ( ((*_c)=mem_insert_ucontact(_r, _contact, _ci)) == 0) { LM_ERR("failed to insert contact\n"); return -1; } if (exists_ulcb_type(UL_CONTACT_INSERT)) { run_ul_callbacks( UL_CONTACT_INSERT, *_c); } if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) { if (db_insert_ucontact(*_c) < 0) { LM_ERR("failed to insert in database\n"); return -1; } else { (*_c)->state = CS_SYNC; } } return 0; }
/*! * \brief Delete a impurecord from domain * \param _d domain where the record should be deleted * \param _aor address of record * \param _r deleted record * \return 0 on success, -1 if the record could not be deleted */ int delete_impurecord(udomain_t* _d, str* _aor, struct impurecord* _r) { // struct ucontact* c;//, *t; LM_DBG("Deleting IMPURECORD [%.*s]\n", _r->public_identity.len, _r->public_identity.s); if (_r == 0) { if (get_impurecord(_d, _aor, &_r) > 0) { return 0; } } //TODO: need to unref the contacts in the contact list (not delete them), the timer should delete all contacts that are unreffed // c = _r->contacts; // while (c) { // t = c; // c = c->next; // if (delete_ucontact(_r, t) < 0) { // LM_ERR("deleting contact failed [%.*s]\n", c->aor.len, c->aor.s); // return -1; // } // } if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE)) { run_ul_callbacks(_r->cbs, UL_IMPU_DELETE, _r, 0); } /*DB?*/ if (db_mode == WRITE_THROUGH && db_delete_impurecord(_d, _r) != 0) { LM_ERR("error deleting IMPU record from db"); return 0; } mem_delete_impurecord(_d, _r); return 0; }
/*! * \brief Delete a impurecord from domain * \param _d domain where the record should be deleted * \param _aor address of record - used only if _r in next param is null * \param _r deleted record to delete - if null will use the aor to search (assumed that domain is locked). * \return 0 on success, -1 if the record could not be deleted */ int delete_impurecord(udomain_t* _d, str* _aor, struct impurecord* _r) { LM_DBG("Deleting IMPURECORD [%.*s]\n", _r->public_identity.len, _r->public_identity.s); if (_r == 0) { LM_DBG("no impurecord passed in - let's search\n"); if (get_impurecord(_d, _aor, &_r) != 0) { return 0; } } if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE)) { run_ul_callbacks(_r->cbs, UL_IMPU_DELETE, _r, 0); } /*DB?*/ if (db_mode == WRITE_THROUGH && db_delete_impurecord(_d, _r) != 0) { LM_ERR("error deleting IMPU record from db...continuing to remove from memory\n"); } mem_delete_impurecord(_d, _r); return 0; }
/* * This timer routine is used when * db_mode is set to NO_DB or READONLY */ static inline int nodb_timer(urecord_t* _r) { ucontact_t* ptr, *t; int not = 0; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); notify_watchers(_r, ptr, PRES_OFFLINE); LOG(L_NOTICE, "Binding '%.*s','%.*s' has expired\n", ptr->uid->len, ZSW(ptr->uid->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; /* it was the last contact and it was in normal * state, so notify */ if (!ptr && t->state == CS_NEW) not=1; delete_reg_avps(t); mem_delete_ucontact(_r, t); _r->slot->d->expired++; } else { ptr = ptr->next; } } return 0; }
/* * Write-back timer */ static inline int wb_timer(urecord_t* _r) { ucontact_t* ptr, *t; int op; int not = 0; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) { run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); } notify_watchers(_r, ptr, PRES_OFFLINE); LOG(L_NOTICE, "Binding '%.*s','%.*s' has expired\n", ptr->uid->len, ZSW(ptr->uid->s), ptr->c.len, ZSW(ptr->c.s)); if (ptr->next == 0) not=1; _r->slot->d->expired++; t = ptr; ptr = ptr->next; /* Should we remove the contact from the database ? */ if (st_expired_ucontact(t) == 1) { if (db_delete_ucontact(t) < 0) { LOG(L_ERR, "wb_timer(): Can't delete contact from the database\n"); } } delete_reg_avps(t); mem_delete_ucontact(_r, t); } else { /* Determine the operation we have to do */ op = st_flush_ucontact(ptr); switch(op) { case 0: /* do nothing, contact is synchronized */ break; case 1: /* insert */ if (db_store_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Error while inserting contact into database\n"); } break; case 2: /* update */ if (db_store_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Error while updating contact in db\n"); } break; case 4: /* delete */ if (db_delete_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Can't delete contact from database\n"); } /* fall through to the next case statement */ case 3: /* delete from memory */ delete_reg_avps(ptr); mem_delete_ucontact(_r, ptr); break; } ptr = ptr->next; } } return 0; }
int update_pcontact(struct udomain* _d, struct pcontact_info* _ci, struct pcontact* _c) //TODO: should prob move this to pcontact { int is_default = 1; ppublic_t* ppublic_ptr; int i; _c->reg_state = _ci->reg_state; if (_ci->expires > 0) { _c->expires = _ci->expires; } if (_ci->num_service_routes > 0 && _ci->service_routes) { //replace all existing service routes if (_c->service_routes) { //remove old service routes for (i=0; i<_c->num_service_routes; i++) { if (_c->service_routes[i].s) shm_free(_c->service_routes[i].s); shm_free(_c->service_routes); _c->service_routes=0; _c->num_service_routes=0; } } //now add the new service routes if (_ci->num_service_routes > 0) { _c->service_routes = shm_malloc(_ci->num_service_routes*sizeof(str)); if (!_c->service_routes) { LM_ERR("no more shm mem trying to allocate [%ld bytes]\n", _ci->num_service_routes*sizeof(str)); goto out_of_memory; } else { for (i=0; i<_ci->num_service_routes; i++) { STR_SHM_DUP(_c->service_routes[i], _ci->service_routes[i], "update_pcontact"); } _c->num_service_routes = _ci->num_service_routes; } } } if (_ci->num_public_ids > 0 && _ci->public_ids) { if (_c->head) { LM_DBG("ppublic's already exist.... .not updating\n"); } else { for (i = 0; i < _ci->num_public_ids; i++) { if (i > 0) is_default = 0; //only the first one is default - P-Associated-uri (first one is default) if (new_ppublic(&_ci->public_ids[i], is_default, &ppublic_ptr) != 0) { LM_ERR("unable to create new ppublic\n"); } else { insert_ppublic(_c, ppublic_ptr); } } } } // update received info (if info is available): if (_ci->received_host.len > 0) { if (_c->received_host.s) shm_free(_c->received_host.s); STR_SHM_DUP(_c->received_host, _ci->received_host, "update_pcontact"); } if (_ci->received_port > 0) _c->received_port = _ci->received_port; if (_ci->received_proto > 0) _c->received_proto = _ci->received_proto; //TODO: update path, etc run_ul_callbacks(PCSCF_CONTACT_UPDATE, _c); return 0; out_of_memory: return -1; }
/* update an existing impurecord. if one doesnt exist it will be created. * make sure yuo lock the domain before calling this and unlock it afterwards * return: 0 on success, -1 on failure */ int update_impurecord(struct udomain* _d, str* public_identity, int reg_state, int send_sar_on_delete, int barring, int is_primary, ims_subscription** s, str* ccf1, str* ccf2, str* ecf1, str* ecf2, struct impurecord** _r) { int res; res = get_impurecord(_d, public_identity, _r); if (res != 0) { if (reg_state != IMPU_NOT_REGISTERED && s) { LM_DBG("No existing impu record for <%.*s>.... creating new one\n", public_identity->len, public_identity->s); res = insert_impurecord(_d, public_identity, reg_state, barring, s, ccf1, ccf2, ecf1, ecf2, _r); //for the first time we create an IMPU we must set the primary record (we don't worry about it on updates - ignored) (*_r)->is_primary = is_primary; //TODO = this should prob move to insert_impurecord fn if (reg_state == IMPU_UNREGISTERED) { //update unreg expiry so the unreg record is not stored 'forever' (*_r)->expires = time(NULL) + unreg_validity; } if (res != 0) { LM_ERR("Unable to insert new IMPU for <%.*s>\n", public_identity->len, public_identity->s); return -1; } else { run_ul_callbacks(NULL, UL_IMPU_INSERT, *_r, NULL); return 0; } } else { LM_DBG("no IMPU found to update and data not valid to create new one - not a problem record was probably removed as it has no contacts\n"); return 0; } } //if we get here, we have a record to update LM_DBG("updating IMPU record with public identity for <%.*s>\n", public_identity->len, public_identity->s); (*_r)->reg_state = reg_state; if (reg_state == IMPU_UNREGISTERED) { //update unreg expiry so the unreg record is not stored 'forever' (*_r)->expires = time(NULL) + unreg_validity; } if (barring >= 0) (*_r)->barring = barring; if (send_sar_on_delete >= 0) (*_r)->send_sar_on_delete = send_sar_on_delete; if (ccf1) { if ((*_r)->ccf1.s) shm_free((*_r)->ccf1.s); STR_SHM_DUP((*_r)->ccf1, *ccf1, "SHM CCF1"); } if (ccf2) { if ((*_r)->ccf2.s) shm_free((*_r)->ccf2.s); STR_SHM_DUP((*_r)->ccf2, *ccf2, "SHM CCF2"); } if (ecf1) { if ((*_r)->ecf1.s) shm_free((*_r)->ecf1.s); STR_SHM_DUP((*_r)->ecf1, *ecf1, "SHM ECF1"); } if (ecf2) { if ((*_r)->ecf2.s) shm_free((*_r)->ecf2.s); STR_SHM_DUP((*_r)->ecf2, *ecf2, "SHM ECF2"); } if (s) { LM_DBG("we have a new ims_subscription\n"); if ((*_r)->s) { lock_get((*_r)->s->lock); if ((*_r)->s->ref_count == 1) { LM_DBG("freeing user data as no longer referenced\n"); free_ims_subscription_data((*_r)->s); //no need to release lock after this. its gone ;) (*_r)->s = 0; } else { (*_r)->s->ref_count--; LM_DBG("new ref count for ims sub is %d\n", (*_r)->s->ref_count); lock_release((*_r)->s->lock); } } (*_r)->s = *s; lock_get((*_r)->s->lock); (*_r)->s->ref_count++; lock_release((*_r)->s->lock); } run_ul_callbacks((*_r)->cbs, UL_IMPU_UPDATE, *_r, NULL); return 0; out_of_memory: unlock_udomain(_d, public_identity); return -1; }
/*! * \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 nodb_timer(impurecord_t* _r) { ucontact_t* ptr, *t; unsigned int hash_code = 0; 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)) { 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))); hash_code = 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, hash_code); /* search the record in hash table */ lock_get(&sub_dialog_table[hash_code].lock); sub_dialog= pres_search_shtable(sub_dialog_table, s->call_id, s->to_tag, s->from_tag, hash_code); 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[hash_code].lock); } s = s->next; } ptr = _r->contacts; LM_DBG("Checking validity of IMPU: <%.*s> contacts\n", _r->public_identity.len, _r->public_identity.s); while (ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(ptr->cbs, UL_CONTACT_EXPIRE)) run_ul_callbacks(ptr->cbs, UL_CONTACT_EXPIRE, _r, ptr); if (exists_ulcb_type(_r->cbs, UL_IMPU_EXPIRE_CONTACT)) { run_ul_callbacks(_r->cbs, UL_IMPU_EXPIRE_CONTACT, _r, ptr); } LM_DBG("Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; if (db_mode == WRITE_THROUGH && db_delete_ucontact(_r, t) != 0) { LM_ERR("error removing contact from DB [%.*s]... will still remove from memory\n", t->c.len, t->c.s); } mem_delete_ucontact(_r, t); update_stat(_r->slot->d->expires, 1); } else { LM_DBG("IMPU:<%.*s> - contact:<%.*s> is valid and expires in %d seconds\n", _r->public_identity.len, _r->public_identity.s, ptr->c.len, ptr->c.s, (unsigned int) (ptr->expires - time(NULL))); ptr = ptr->next; } } }
/*! * \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; } } }