void mem_timer_udomain(udomain_t* _d) { struct pcontact* ptr; int i; for(i=0; i<_d->size; i++) { lock_ulslot(_d, i); ptr = _d->table[i].first; while(ptr) { timer_pcontact(ptr); /* Remove the entire record if it is empty */ //if (ptr->contacts == 0) { // t = ptr; // ptr = ptr->next; // mem_delete_pcontact(_d, t); //}//// else { // ptr = ptr->next; //} ptr = ptr->next; } unlock_ulslot(_d, i); } }
/*! * \brief Run timer handler for given domain * \param _d domain */ void mem_timer_udomain(udomain_t* _d) { struct urecord* ptr, *t; int i; for(i=0; i<_d->size; i++) { lock_ulslot(_d, i); ptr = _d->table[i].first; while(ptr) { timer_urecord(ptr); /* Remove the entire record if it is empty */ if (ptr->contacts == 0) { t = ptr; ptr = ptr->next; mem_delete_urecord(_d, t); } else { ptr = ptr->next; } } unlock_ulslot(_d, i); } }
/*! * \brief Free all memory allocated for the domain * \param _d freed domain */ void free_udomain(udomain_t* _d) { int i; if (_d->table) { for (i = 0; i < _d->size; i++) { lock_ulslot(_d, i); deinit_slot(_d->table + i); unlock_ulslot(_d, i); } shm_free(_d->table); } shm_free(_d); }
/*! * \brief Obtain a urecord pointer if the urecord exists in domain (lock slot) * \param _d domain to search the record * \param _aorhash hash id for address of record * \param _ruid record internal unique id * \param _r store pointer to location record * \param _c store pointer to contact structure * \return 0 if a record was found, 1 if nothing could be found */ int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash, str *_ruid, struct urecord** _r, struct ucontact** _c) { unsigned int sl, i; urecord_t* r; ucontact_t* c; sl = _aorhash&(_d->size-1); lock_ulslot(_d, sl); if (db_mode!=DB_ONLY) { /* search in cache */ r = _d->table[sl].first; for(i = 0; i < _d->table[sl].n; i++) { if(r->aorhash==_aorhash) { c = r->contacts; while(c) { if(c->ruid.len==_ruid->len && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) { *_r = r; *_c = c; return 0; } } } r = r->next; } } else { /* search in DB */ r = db_load_urecord_by_ruid(_d, _ruid); if (r) { if(r->aorhash==_aorhash) { c = r->contacts; while(c) { if(c->ruid.len==_ruid->len && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) { *_r = r; *_c = c; return 0; } } } } } unlock_ulslot(_d, (_aorhash & (_d->size - 1))); return -1; /* Nothing found */ }
int ul_refresh_keepalive(unsigned int _aorhash, str *_ruid) { dlist_t *p; urecord_t *r; ucontact_t *c; int i; /* todo: get location domain via param */ for (p = root; p != NULL; p = p->next) { i = _aorhash&(p->d->size-1); lock_ulslot(p->d, i); if(p->d->table[i].n<=0) { unlock_ulslot(p->d, i); continue; } for (r = p->d->table[i].first; r != NULL; r = r->next) { if(r->aorhash==_aorhash) { for (c = r->contacts; c != NULL; c = c->next) { if (c->c.len <= 0 || c->ruid.len<=0) continue; if(c->ruid.len==_ruid->len && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) { /* found */ c->last_keepalive = time(NULL); LM_DBG("updated keepalive for [%.*s:%u] to %u\n", _ruid->len, _ruid->s, _aorhash, (unsigned int)c->last_keepalive); unlock_ulslot(p->d, i); return 0; } } } } unlock_ulslot(p->d, i); } return 0; }
void mem_timer_udomain(udomain_t* _d) { struct pcontact* ptr, *tmp; int i; for(i=0; i<_d->size; i++) { lock_ulslot(_d, i); ptr = _d->table[i].first; while(ptr) { tmp = ptr; ptr = ptr->next; timer_pcontact(tmp); } unlock_ulslot(_d, i); } }
/*! * \brief Get all contacts from the memory, in partitions if wanted * \see get_all_ucontacts * \param buf target buffer * \param len length of buffer * \param flags contact flags * \param part_idx part index * \param part_max maximal part * \param options options * \return 0 on success, positive if buffer size was not sufficient, negative on failure */ static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags, unsigned int part_idx, unsigned int part_max, int options) { dlist_t *p; urecord_t *r; ucontact_t *c; void *cp; int shortage; int needed; int i = 0; cp = buf; shortage = 0; time_t tnow = 0; if(ul_keepalive_timeout>0) tnow = time(NULL); /* Reserve space for terminating 0000 */ len -= sizeof(c->c.len); for (p = root; p != NULL; p = p->next) { for(i=0; i<p->d->size; i++) { if ( (i % part_max) != part_idx ) continue; lock_ulslot(p->d, i); if(p->d->table[i].n<=0) { unlock_ulslot(p->d, i); continue; } for (r = p->d->table[i].first; r != NULL; r = r->next) { for (c = r->contacts; c != NULL; c = c->next) { if (c->c.len <= 0) continue; /* * List only contacts that have all requested * flags set */ if ((c->cflags & flags) != flags) continue; if(options&GAU_OPT_SERVER_ID && server_id!=c->server_id) continue; if(ul_keepalive_timeout>0 && c->last_keepalive>0) { if(c->sock!=NULL && c->sock->proto==PROTO_UDP) { if(c->last_keepalive+ul_keepalive_timeout < tnow) { /* set contact as expired in 10s */ if(c->expires > tnow + 10) c->expires = tnow + 10; continue; } } } needed = (int)(sizeof(c->c.len) + c->c.len + sizeof(c->received.len) + c->received.len + sizeof(c->sock) + sizeof(c->cflags) + sizeof(c->path.len) + c->path.len + sizeof(c->ruid.len) + c->ruid.len + sizeof(r->aorhash)); if (len >= needed) { memcpy(cp, &c->c.len, sizeof(c->c.len)); cp = (char*)cp + sizeof(c->c.len); memcpy(cp, c->c.s, c->c.len); cp = (char*)cp + c->c.len; memcpy(cp,&c->received.len,sizeof(c->received.len)); cp = (char*)cp + sizeof(c->received.len); memcpy(cp, c->received.s, c->received.len); cp = (char*)cp + c->received.len; memcpy(cp, &c->sock, sizeof(c->sock)); cp = (char*)cp + sizeof(c->sock); memcpy(cp, &c->cflags, sizeof(c->cflags)); cp = (char*)cp + sizeof(c->cflags); memcpy(cp, &c->path.len, sizeof(c->path.len)); cp = (char*)cp + sizeof(c->path.len); memcpy(cp, c->path.s, c->path.len); cp = (char*)cp + c->path.len; memcpy(cp, &c->ruid.len, sizeof(c->ruid.len)); cp = (char*)cp + sizeof(c->ruid.len); memcpy(cp, c->ruid.s, c->ruid.len); cp = (char*)cp + c->ruid.len; memcpy(cp, &r->aorhash, sizeof(r->aorhash)); cp = (char*)cp + sizeof(r->aorhash); len -= needed; } else { shortage += needed; } } } unlock_ulslot(p->d, i); } } /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */ if (len >= 0) memset(cp, 0, sizeof(c->c.len)); /* Shouldn't happen */ if (shortage > 0 && len > shortage) { abort(); } shortage -= len; return shortage > 0 ? shortage : 0; }
/*! * \brief Dump the content of the usrloc * \param cmd mi_root containing the parameter * \param param not used * \return mi_root with the result or 0 on failure */ struct mi_root* mi_usrloc_dump(struct mi_root *cmd, void *param) { struct mi_root *rpl_tree; struct mi_node *rpl, *node; struct mi_attr *attr; struct urecord* r; dlist_t* dl; udomain_t* dom; time_t t; char *p; int max, len, n, i, short_dump; node = cmd->node.kids; if (node && node->next) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); if (node && node->value.len==5 && !strncasecmp(node->value.s, "brief", 5)){ /* short version */ short_dump = 1; } else { short_dump = 0; } rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==NULL) return 0; rpl = &rpl_tree->node; t = time(0); for( dl=root ; dl ; dl=dl->next ) { /* add a domain node */ node = add_mi_node_child( rpl, 0, "Domain", 6, dl->name.s, dl->name.len); if (node==0) goto error; dom = dl->d; /* add some attributes to the domain node */ p= int2str((unsigned long)dom->size, &len); attr = add_mi_attr( node, MI_DUP_VALUE, "table", 5, p, len); if (attr==0) goto error; /* add the entries per hash */ for(i=0,n=0,max=0; i<dom->size; i++) { lock_ulslot( dom, i); n += dom->table[i].n; if(max<dom->table[i].n) max= dom->table[i].n; for( r = dom->table[i].first ; r ; r=r->next ) { /* add entry */ if (mi_add_aor_node( node, r, t, short_dump)!=0) { unlock_ulslot( dom, i); goto error; } } unlock_ulslot( dom, i); } /* add more attributes to the domain node */ p= int2str((unsigned long)n, &len); attr = add_mi_attr( node, MI_DUP_VALUE, "records", 7, p, len); if (attr==0) goto error; p= int2str((unsigned long)max, &len); attr = add_mi_attr( node, MI_DUP_VALUE, "max_slot", 8, p, len); if (attr==0) goto error; } return rpl_tree; error: free_mi_tree(rpl_tree); return 0; }
/*! * \brief Get lock for a domain * \param _d domain * \param _aor adress of record, used as hash source for the lock slot */ void lock_udomain(udomain_t* _d, str* _aor) { unsigned int sl; sl = core_hash(_aor, 0, _d->size); lock_ulslot(_d, sl); }
static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags, unsigned int part_idx, unsigned int part_max) { dlist_t *p; pcontact_t *c; void *cp; int shortage; int needed; int i = 0; cp = buf; shortage = 0; unsigned int received_len = 0; char received_s[60]; // IPv6-Address (39) + "sip:" (4) + ":" (1) + Port (5); 60 should be plenty. /* Reserve space for terminating 0000 */ len -= sizeof(int); for (p = root; p != NULL; p = p->next) { for(i=0; i<p->d->size; i++) { if ( (i % part_max) != part_idx ) continue; lock_ulslot(p->d, i); if(p->d->table[i].n<=0) { unlock_ulslot(p->d, i); continue; } for (c = p->d->table[i].first; c != NULL; c = c->next) { if (c->received_host.s) { received_len = snprintf(received_s, sizeof(received_s), "sip:%.*s:%x", c->received_host.len, c->received_host.s, c->received_port) - 1; needed = (int)(sizeof(received_len) + received_len + sizeof(c->sock) + sizeof(unsigned int) + sizeof(c->path.len) + c->path.len); if (len >= needed) { cp = (char*)cp + received_len; cp = (char*)cp + sizeof(received_len); memcpy(cp, received_s, received_len); cp = (char*)cp + received_len; memcpy(cp, &c->sock, sizeof(c->sock)); cp = (char*)cp + sizeof(c->sock); memset(cp, 0, sizeof(unsigned int)); cp = (char*)cp + sizeof(unsigned int); memcpy(cp, &c->path.len, sizeof(c->path.len)); cp = (char*)cp + sizeof(c->path.len); memcpy(cp, c->path.s, c->path.len); cp = (char*)cp + c->path.len; len -= needed; } else { shortage += needed; } } } unlock_ulslot(p->d, i); } } /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */ if (len >= 0) memset(cp, 0, sizeof(int)); /* Shouldn't happen */ if (shortage > 0 && len > shortage) { abort(); } shortage -= len; return shortage > 0 ? shortage : 0; }
static int receive_sync_request(int node_id) { bin_packet_t *sync_packet; dlist_t *dl; udomain_t *dom; map_iterator_t it; struct urecord *r; ucontact_t* c; str st; void **p; int i; for (dl = root; dl; dl = dl->next) { dom = dl->d; for(i = 0; i < dom->size; i++) { lock_ulslot(dom, i); for (map_first(dom->table[i].records, &it); iterator_is_valid(&it); iterator_next(&it)) { p = iterator_val(&it); if (p == NULL) goto error_unlock; r = (urecord_t *)*p; sync_packet = clusterer_api.sync_chunk_start(&contact_repl_cap, location_cluster, node_id); if (!sync_packet) goto error_unlock; /* urecord in this chunk */ bin_push_int(sync_packet, 0); bin_push_str(sync_packet, r->domain); bin_push_str(sync_packet, &r->aor); for (c = r->contacts; c; c = c->next) { sync_packet = clusterer_api.sync_chunk_start(&contact_repl_cap, location_cluster, node_id); if (!sync_packet) goto error_unlock; /* contact in this chunk */ bin_push_int(sync_packet, 1); bin_push_str(sync_packet, r->domain); bin_push_str(sync_packet, &r->aor); bin_push_str(sync_packet, &c->c); bin_push_str(sync_packet, &c->callid); bin_push_str(sync_packet, &c->user_agent); bin_push_str(sync_packet, &c->path); bin_push_str(sync_packet, &c->attr); bin_push_str(sync_packet, &c->received); bin_push_str(sync_packet, &c->instance); st.s = (char *)&c->expires; st.len = sizeof c->expires; bin_push_str(sync_packet, &st); st.s = (char *)&c->q; st.len = sizeof c->q; bin_push_str(sync_packet, &st); bin_push_str(sync_packet, c->sock?&c->sock->sock_str:NULL); bin_push_int(sync_packet, c->cseq); bin_push_int(sync_packet, c->flags); bin_push_int(sync_packet, c->cflags); bin_push_int(sync_packet, c->methods); st.s = (char *)&c->last_modified; st.len = sizeof c->last_modified; bin_push_str(sync_packet, &st); } } unlock_ulslot(dom, i); } } return 0; error_unlock: unlock_ulslot(dom, i); 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); } } }
/* can't assume we are locked here */ int get_pcontact_by_src(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c) { int i; struct pcontact* c; unsigned int aorhash, sl; char c_contact[256], *p; str s_contact; if (hashing_type == 1) {//we hash on IP:PORT - so no need to search sequentially.. /* get_aor_hash in this mode expects to see contact as host:port */ memset(c_contact, 0, 256); memcpy(c_contact, _host->s, _host->len); p = c_contact + _host->len; *p = ':'; p++; sprintf(p,"%d", _port); s_contact.s = c_contact; s_contact.len = strlen(c_contact); aorhash = get_aor_hash(_d, &s_contact); sl = aorhash & (_d->size - 1); c = _d->table[sl].first; for (i = 0; i < _d->table[sl].n; i++) { lock_ulslot(_d, i); LM_DBG("Searching for contact in P-CSCF usrloc [%.*s]\n", s_contact.len, s_contact.s); // First check, if Proto and Port matches: if ((c->received_port == _port) && (c->received_proto == _proto)) { LM_DBG("Received host len %d (search %d)\n", c->received_host.len, _host->len); // Then check the length: if (c->received_host.len == _host->len) { LM_DBG("Received host %.*s (search %.*s)\n", c->received_host.len, c->received_host.s, _host->len, _host->s); // Finally really compare the "received_host" if (!memcmp(c->received_host.s, _host->s, _host->len)) { *_c = c; return 0; } } } unlock_ulslot(_d, i); } } else { /* search sequentially */ for(i=0; i<_d->size; i++) { c = _d->table[i].first; while(c) { LM_DBG("Port %d (search %d), Proto %d (search %d), reg_state %s (search %s)\n", c->received_port, _port, c->received_proto, _proto, reg_state_to_string(c->reg_state), reg_state_to_string(PCONTACT_REGISTERED) ); // First check, if Proto and Port matches: if ((c->received_port == _port) && (c->received_proto == _proto)) { LM_DBG("Received host len %d (search %d)\n", c->received_host.len, _host->len); // Then check the length: if (c->received_host.len == _host->len) { LM_DBG("Received host %.*s (search %.*s)\n", c->received_host.len, c->received_host.s, _host->len, _host->s); // Finally really compare the "received_host" if (!memcmp(c->received_host.s, _host->s, _host->len)) { *_c = c; return 0; } } } c = c->next; } } } return 1; /* Nothing found */ }
/*! * \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 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; }
/*! * \brief Get all contacts from the memory, in partitions if wanted * \see get_all_ucontacts * \param buf target buffer * \param len length of buffer * \param flags contact flags * \param part_idx part index * \param part_max maximal part * \return 0 on success, positive if buffer size was not sufficient, negative on failure */ static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags, unsigned int part_idx, unsigned int part_max) { dlist_t *p; impurecord_t *r; ucontact_t *c; void *cp; int shortage; int needed; int i = 0; cp = buf; shortage = 0; /* Reserve space for terminating 0000 */ len -= sizeof(c->c.len); for (p = root; p != NULL; p = p->next) { for(i=0; i<p->d->size; i++) { if ( (i % part_max) != part_idx ) continue; lock_ulslot(p->d, i); if(p->d->table[i].n<=0) { unlock_ulslot(p->d, i); continue; } for (r = p->d->table[i].first; r != NULL; r = r->next) { for (c = r->contacts; c != NULL; c = c->next) { if (c->c.len <= 0) continue; /* * List only contacts that have all requested * flags set */ if ((c->cflags & flags) != flags) continue; if (c->received.s) { needed = (int)(sizeof(c->received.len) + c->received.len + sizeof(c->sock) + sizeof(c->cflags) + sizeof(c->path.len) + c->path.len); if (len >= needed) { memcpy(cp,&c->received.len,sizeof(c->received.len)); cp = (char*)cp + sizeof(c->received.len); memcpy(cp, c->received.s, c->received.len); cp = (char*)cp + c->received.len; memcpy(cp, &c->sock, sizeof(c->sock)); cp = (char*)cp + sizeof(c->sock); memcpy(cp, &c->cflags, sizeof(c->cflags)); cp = (char*)cp + sizeof(c->cflags); memcpy(cp, &c->path.len, sizeof(c->path.len)); cp = (char*)cp + sizeof(c->path.len); memcpy(cp, c->path.s, c->path.len); cp = (char*)cp + c->path.len; len -= needed; } else { shortage += needed; } } else { needed = (int)(sizeof(c->c.len) + c->c.len + sizeof(c->sock) + sizeof(c->cflags) + sizeof(c->path.len) + c->path.len); if (len >= needed) { memcpy(cp, &c->c.len, sizeof(c->c.len)); cp = (char*)cp + sizeof(c->c.len); memcpy(cp, c->c.s, c->c.len); cp = (char*)cp + c->c.len; memcpy(cp, &c->sock, sizeof(c->sock)); cp = (char*)cp + sizeof(c->sock); memcpy(cp, &c->cflags, sizeof(c->cflags)); cp = (char*)cp + sizeof(c->cflags); memcpy(cp, &c->path.len, sizeof(c->path.len)); cp = (char*)cp + sizeof(c->path.len); memcpy(cp, c->path.s, c->path.len); cp = (char*)cp + c->path.len; len -= needed; } else { shortage += needed; } } } } unlock_ulslot(p->d, i); } } /* len < 0 is possible, if size of the buffer < sizeof(c->c.len) */ if (len >= 0) memset(cp, 0, sizeof(c->c.len)); /* Shouldn't happen */ if (shortage > 0 && len > shortage) { abort(); } shortage -= len; return shortage > 0 ? shortage : 0; }
static void ul_rpc_dump(rpc_t* rpc, void* ctx) { struct urecord* r; dlist_t* dl; udomain_t* dom; time_t t; str brief = {0, 0}; str empty_str = {"[not set]", 9}; str state_str = {"[not set]", 9}; str socket_str = {"[not set]", 9}; int summary = 0; ucontact_t* c; void* th; void* ah; void* ih; void* vh; void* sh; int max, n, i; rpc->scan(ctx, "*S", &brief); if(brief.len==5 && (strncmp(brief.s, "brief", 5)==0)) summary = 1; t = time(0); for( dl=root ; dl ; dl=dl->next ) { dom = dl->d; if (rpc->add(ctx, "{", &th) < 0) { rpc->fault(ctx, 500, "Internal error creating top rpc"); return; } if(rpc->struct_add(th, "Sd{", "Domain", &dl->name, "Size", (int)dom->size, "AoRs", &ah)<0) { rpc->fault(ctx, 500, "Internal error creating inner struct"); return; } for(i=0,n=0,max=0; i<dom->size; i++) { lock_ulslot( dom, i); n += dom->table[i].n; if(max<dom->table[i].n) max= dom->table[i].n; for( r = dom->table[i].first ; r ; r=r->next ) { if(summary==1) { if(rpc->struct_add(ah, "S", "AoR", &r->aor)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error creating aor struct"); return; } } else { if(rpc->struct_add(ah, "Sd{", "AoR", &r->aor, "HashID", r->aorhash, "Contacts", &ih)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error creating aor struct"); return; } for( c=r->contacts ; c ; c=c->next) { if(rpc->struct_add(ih, "{", "Contact", &vh)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error creating contact struct"); return; } if(rpc->struct_add(vh, "S", "Address", &c->c)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding addr"); return; } if (c->expires == 0) { if(rpc->struct_add(vh, "s", "Expires", "permanent")<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding expire"); return; } } else if (c->expires == UL_EXPIRED_TIME) { if(rpc->struct_add(vh, "s", "Expires", "deleted")<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding expire"); return; } } else if (t > c->expires) { if(rpc->struct_add(vh, "s", "Expires", "expired")<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding expire"); return; } } else { if(rpc->struct_add(vh, "d", "Expires", (int)(c->expires - t))<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding expire"); return; } } if (c->state == CS_NEW) { state_str.s = "CS_NEW"; state_str.len = 6; } else if (c->state == CS_SYNC) { state_str.s = "CS_SYNC"; state_str.len = 7; } else if (c->state== CS_DIRTY) { state_str.s = "CS_DIRTY"; state_str.len = 8; } else { state_str.s = "CS_UNKNOWN"; state_str.len = 10; } if(c->sock) { socket_str.s = c->sock->sock_str.s; socket_str.len = c->sock->sock_str.len; } if(rpc->struct_add(vh, "f", "Q", c->q)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding q"); return; } if(rpc->struct_add(vh, "S", "Call-ID", &c->callid)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding callid"); return; } if(rpc->struct_add(vh, "d", "CSeq", c->cseq)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding cseq"); return; } if(rpc->struct_add(vh, "S", "User-Agent", (c->user_agent.len)?&c->user_agent: &empty_str)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding user-agent"); return; } if(rpc->struct_add(vh, "S", "Received", (c->received.len)?&c->received: &empty_str)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding received"); return; } if(rpc->struct_add(vh, "S", "Path", (c->path.len)?&c->path: &empty_str)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding path"); return; } if(rpc->struct_add(vh, "S", "State", &state_str)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding state"); return; } if(rpc->struct_add(vh, "d", "Flags", c->flags)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding flags"); return; } if(rpc->struct_add(vh, "d", "CFlags", c->cflags)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding cflags"); return; } if(rpc->struct_add(vh, "S", "Socket", &socket_str)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding socket"); return; } if(rpc->struct_add(vh, "d", "Methods", c->methods)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding methods"); return; } if(rpc->struct_add(vh, "S", "Ruid", (c->ruid.len)?&c->ruid: &empty_str)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding ruid"); return; } if(rpc->struct_add(vh, "S", "Instance", (c->instance.len)?&c->instance: &empty_str)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding instance"); return; } if(rpc->struct_add(vh, "d", "Reg-Id", c->reg_id)<0) { unlock_ulslot( dom, i); rpc->fault(ctx, 500, "Internal error adding reg_id"); return; } } } } unlock_ulslot( dom, i); } /* extra attributes node */ if(rpc->struct_add(th, "{", "Stats", &sh)<0) { rpc->fault(ctx, 500, "Internal error creating stats struct"); return; } if(rpc->struct_add(sh, "dd", "Records", n, "Max-Slots", max)<0) { rpc->fault(ctx, 500, "Internal error adding stats"); return; } } }