presence: user core macro for hash slot index
[sip-router] / src / modules / presence / hash.c
index bf6bc83..f6abcdc 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <time.h>
 #include "../../core/mem/shm_mem.h"
 #include "../../core/hashes.h"
 #include "../../core/dprint.h"
@@ -258,6 +259,43 @@ int insert_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
 {
        subs_t *new_rec = NULL;
 
+       if (pres_delete_same_subs) {
+               subs_t* rec = NULL, *prev_rec = NULL;
+
+               lock_get(&htable[hash_code].lock);
+               /* search if there is another record with the same pres_uri & callid */
+               rec = htable[hash_code].entries->next;
+               while (rec) {
+                       if (subs->pres_uri.len == rec->pres_uri.len && subs->callid.len == rec->callid.len &&
+                                       memcmp(subs->pres_uri.s, rec->pres_uri.s, subs->pres_uri.len) == 0 &&
+                                       memcmp(subs->callid.s, rec->callid.s, subs->callid.len) == 0) {
+                               LM_NOTICE("Found another record with the same pres_uri[%.*s] and callid[%.*s]\n",
+                                       subs->pres_uri.len, subs->pres_uri.s, subs->callid.len, subs->callid.s);
+                               /* delete this record */
+
+                               if (prev_rec) {
+                                       prev_rec->next = rec->next;
+                               } else {
+                                       htable[hash_code].entries->next = rec->next;
+                               }
+
+                               if (pres_subs_dbmode != NO_DB) {
+                                       delete_db_subs(&rec->to_tag, &rec->from_tag, &rec->callid);
+                               }
+
+                               if (rec->contact.s!=NULL) {
+                                       shm_free(rec->contact.s);
+                               }
+
+                               shm_free(rec);
+                               break;
+                       }
+                       prev_rec = rec;
+                       rec = rec->next;
+               }
+               lock_release(&htable[hash_code].lock);
+       }
+
        new_rec = mem_copy_subs_noc(subs);
        if(new_rec == NULL) {
                LM_ERR("copying in share memory a subs_t structure\n");
@@ -588,7 +626,7 @@ int delete_phtable(str *pres_uri, int event)
        return 0;
 }
 
-int update_phtable(presentity_t *presentity, str pres_uri, str body)
+int update_phtable(presentity_t *presentity, str *pres_uri, str *body)
 {
        char *sphere = NULL;
        unsigned int hash_code;
@@ -604,11 +642,11 @@ int update_phtable(presentity_t *presentity, str pres_uri, str body)
        }
 
        /* search for record in hash table */
-       hash_code = core_case_hash(&pres_uri, NULL, phtable_size);
+       hash_code = core_case_hash(pres_uri, NULL, phtable_size);
 
        lock_get(&pres_htable[hash_code].lock);
 
-       p = search_phtable(&pres_uri, presentity->event->evp->type, hash_code);
+       p = search_phtable(pres_uri, presentity->event->evp->type, hash_code);
        if(p == NULL) {
                lock_release(&pres_htable[hash_code].lock);
                goto done;
@@ -662,3 +700,595 @@ done:
                pkg_free(sphere);
        return ret;
 }
+
+/**
+ * ==============================
+ *  in-memory presentity records
+ * ==============================
+ */
+
+static ps_ptable_t *_ps_ptable = NULL;
+
+ps_ptable_t *ps_ptable_get(void)
+{
+       return _ps_ptable;
+}
+
+#define PS_PRESENTITY_FIELD_COPY(field) do { \
+               if (pt->field.s) { \
+                       ptn->field.s = p; \
+                       memcpy(ptn->field.s, pt->field.s, pt->field.len); \
+               } \
+               ptn->field.len = pt->field.len; \
+               p += pt->field.len + 1; \
+       } while(0)
+
+/**
+ *
+ */
+ps_presentity_t *ps_presentity_new(ps_presentity_t *pt, int mtype)
+{
+       uint32_t bsize = 0;
+       ps_presentity_t *ptn = NULL;
+       char *p = NULL;
+
+       if(pt==NULL) {
+               return NULL;
+       }
+       bsize = sizeof(ps_presentity_t)
+                       + pt->user.len + 1
+                       + pt->domain.len + 1
+                       + pt->etag.len + 1
+                       + pt->event.len + 1
+                       + pt->ruid.len + 1
+                       + pt->sender.len + 1
+                       + pt->body.len + 1;
+       if(mtype==0) {
+               ptn = (ps_presentity_t*)shm_malloc(bsize);
+       } else {
+               ptn = (ps_presentity_t*)pkg_malloc(bsize);
+       }
+       if(ptn==NULL) {
+               if(mtype==0) {
+                       SHM_MEM_ERROR;
+               } else {
+                       PKG_MEM_ERROR;
+               }
+               return NULL;
+       }
+       memset(ptn, 0, bsize);
+
+       ptn->bsize = bsize;
+       ptn->hashid = core_case_hash(&pt->user, &pt->domain, 0);
+       ptn->expires = pt->expires;
+       ptn->received_time = pt->received_time;
+       ptn->priority = pt->priority;
+
+       p = (char*)ptn + sizeof(ps_presentity_t);
+       PS_PRESENTITY_FIELD_COPY(user);
+       PS_PRESENTITY_FIELD_COPY(domain);
+       PS_PRESENTITY_FIELD_COPY(etag);
+       PS_PRESENTITY_FIELD_COPY(event);
+       PS_PRESENTITY_FIELD_COPY(ruid);
+       PS_PRESENTITY_FIELD_COPY(sender);
+       PS_PRESENTITY_FIELD_COPY(body);
+
+       return ptn;
+}
+
+/**
+ *
+ */
+void ps_presentity_free(ps_presentity_t *pt, int mtype)
+{
+       if(pt==NULL) {
+               return;
+       }
+       if(mtype==0) {
+               shm_free(pt);
+       } else {
+               pkg_free(pt);
+       }
+}
+
+/**
+ *
+ */
+void ps_presentity_list_free(ps_presentity_t *pt, int mtype)
+{
+       ps_presentity_t *ptc = NULL;
+       ps_presentity_t *ptn = NULL;
+
+       if(pt==NULL) {
+               return;
+       }
+
+       ptn = pt;
+       while(ptn!=NULL) {
+               ptc = ptn;
+               ptn = ptn->next;
+               ps_presentity_free(ptc, mtype);
+       }
+}
+
+#define PS_PRESENTITY_FIELD_SHIFT(field) do { \
+               if (pt->field.s) { \
+                       ptn->field.s = p; \
+               } \
+               p += pt->field.len + 1; \
+       } while(0)
+
+/**
+ *
+ */
+ps_presentity_t *ps_presentity_dup(ps_presentity_t *pt, int mtype)
+{
+       ps_presentity_t *ptn = NULL;
+       char *p = NULL;
+
+       if(pt==NULL) {
+               return NULL;
+       }
+       if(mtype==0) {
+               ptn = (ps_presentity_t*)shm_malloc(pt->bsize);
+       } else {
+               ptn = (ps_presentity_t*)pkg_malloc(pt->bsize);
+       }
+       if(ptn==NULL) {
+               if(mtype==0) {
+                       SHM_MEM_ERROR;
+               } else {
+                       PKG_MEM_ERROR;
+               }
+               return NULL;
+       }
+
+       memcpy((void*)ptn, pt, pt->bsize);
+
+       p = (char*)ptn + sizeof(ps_presentity_t);
+       PS_PRESENTITY_FIELD_SHIFT(user);
+       PS_PRESENTITY_FIELD_SHIFT(domain);
+       PS_PRESENTITY_FIELD_SHIFT(etag);
+       PS_PRESENTITY_FIELD_SHIFT(event);
+       PS_PRESENTITY_FIELD_SHIFT(ruid);
+       PS_PRESENTITY_FIELD_SHIFT(sender);
+       PS_PRESENTITY_FIELD_SHIFT(body);
+
+       ptn->next = NULL;
+       ptn->prev = NULL;
+
+       return ptn;
+}
+
+/**
+ *
+ */
+int ps_presentity_match(ps_presentity_t *pta, ps_presentity_t *ptb, int mmode)
+{
+       if(pta->hashid != ptb->hashid) {
+               return 0;
+       }
+
+       if(pta->user.len != ptb->user.len || pta->domain.len != ptb->domain.len) {
+               return 0;
+       }
+
+       if(mmode == 0) {
+               if(pta->etag.len != ptb->etag.len || pta->event.len != ptb->event.len) {
+                       return 0;
+               }
+       }
+
+       if(strncmp(pta->user.s, ptb->user.s, pta->user.len)!=0) {
+               return 0;
+       }
+
+       if(strncmp(pta->domain.s, ptb->domain.s, pta->domain.len)!=0) {
+               return 0;
+       }
+
+       if(mmode==0) {
+               if(strncmp(pta->etag.s, ptb->etag.s, pta->etag.len)!=0) {
+                       return 0;
+               }
+
+               if(strncmp(pta->event.s, ptb->event.s, pta->event.len)!=0) {
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+/**
+ *
+ */
+int ps_ptable_init(int ssize)
+{
+       size_t tsize = 0;
+       int i = 0;
+
+       if(_ps_ptable!=NULL) {
+               return 0;
+       }
+       tsize = sizeof(ps_ptable_t) + (ssize * sizeof(ps_pslot_t));
+       _ps_ptable = (ps_ptable_t*)shm_malloc(tsize);
+       if(_ps_ptable==NULL) {
+               SHM_MEM_ERROR;
+               return -1;
+       }
+       memset(_ps_ptable, 0, tsize);
+       _ps_ptable->ssize = ssize;
+       _ps_ptable->slots = (ps_pslot_t*)((char*)_ps_ptable + sizeof(ps_ptable_t));
+       for(i=0; i<ssize; i++) {
+               if(lock_init(&_ps_ptable->slots[i].lock) == 0) {
+                       LM_ERR("initializing lock on slot [%d]\n", i);
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       i--;
+       while(i>=0) {
+               lock_destroy(&_ps_ptable->slots[i].lock);
+               i--;
+       }
+       shm_free(_ps_ptable);
+       _ps_ptable = NULL;
+       return -1;
+}
+
+/**
+ *
+ */
+void ps_ptable_destroy(void)
+{
+       int i = 0;
+       ps_presentity_t *pt = NULL;
+       ps_presentity_t *ptn = NULL;
+
+       if(_ps_ptable==NULL) {
+               return;
+       }
+       for(i=0; i<_ps_ptable->ssize; i++) {
+               lock_destroy(&_ps_ptable->slots[i].lock);
+               pt = _ps_ptable->slots[i].plist;
+               while(pt!=NULL) {
+                       ptn = pt->next;
+                       ps_presentity_free(pt, 0);
+                       pt = ptn;
+               }
+       }
+       shm_free(_ps_ptable);
+       _ps_ptable = NULL;
+       return;
+}
+
+/**
+ *
+ */
+int ps_ptable_insert(ps_presentity_t *pt)
+{
+       ps_presentity_t ptc;
+       ps_presentity_t *ptn = NULL;
+       uint32_t idx = 0;
+
+       /* copy struct to fill in missing fields */
+       memcpy(&ptc, pt, sizeof(ps_presentity_t));
+
+       ptc.hashid = core_case_hash(&pt->user, &pt->domain, 0);
+
+       if(ptc.ruid.s == NULL) {
+               if(sruid_next(&pres_sruid) < 0) {
+                       return -1;
+               }
+               ptc.ruid = pres_sruid.uid;
+       }
+
+       ptn = ps_presentity_new(&ptc, 0);
+       if(ptn==NULL) {
+               return -1;
+       }
+
+       idx = core_hash_idx(ptn->hashid, _ps_ptable->ssize);
+
+       lock_get(&_ps_ptable->slots[idx].lock);
+       if(_ps_ptable->slots[idx].plist == NULL) {
+               _ps_ptable->slots[idx].plist = ptn;
+       } else {
+               _ps_ptable->slots[idx].plist->prev = ptn;
+               ptn->next = _ps_ptable->slots[idx].plist;
+               _ps_ptable->slots[idx].plist = ptn;
+       }
+       lock_release(&_ps_ptable->slots[idx].lock);
+
+       return 0;
+}
+
+/**
+ *
+ */
+int ps_ptable_replace(ps_presentity_t *pt)
+{
+       ps_presentity_t ptc;
+       ps_presentity_t *ptn = NULL;
+       uint32_t idx = 0;
+
+       /* copy struct to fill in missing fields */
+       memcpy(&ptc, pt, sizeof(ps_presentity_t));
+
+       ptc.hashid = core_case_hash(&pt->user, &pt->domain, 0);
+
+       if(ptc.ruid.s == NULL) {
+               if(sruid_next(&pres_sruid) < 0) {
+                       return -1;
+               }
+               ptc.ruid = pres_sruid.uid;
+       }
+
+       idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
+
+       lock_get(&_ps_ptable->slots[idx].lock);
+       ptn = _ps_ptable->slots[idx].plist;
+       while(ptn!=NULL) {
+               if(ps_presentity_match(ptn, &ptc, 0)==1) {
+                       if(ptn->next) {
+                               ptn->next->prev = ptn->prev;
+                       }
+                       if(ptn->prev) {
+                               ptn->prev->next = ptn->next;
+                       } else {
+                               _ps_ptable->slots[idx].plist = ptn->next;
+                       }
+                       break;
+               }
+               ptn = ptn->next;
+       }
+
+       if(ptn!=NULL) {
+               ps_presentity_free(ptn, 0);
+       }
+
+       ptn = ps_presentity_new(&ptc, 0);
+       if(ptn==NULL) {
+               lock_release(&_ps_ptable->slots[idx].lock);
+               return -1;
+       }
+
+       if(_ps_ptable->slots[idx].plist == NULL) {
+               _ps_ptable->slots[idx].plist = ptn;
+       } else {
+               _ps_ptable->slots[idx].plist->prev = ptn;
+               ptn->next = _ps_ptable->slots[idx].plist;
+               _ps_ptable->slots[idx].plist = ptn;
+       }
+       lock_release(&_ps_ptable->slots[idx].lock);
+
+       return 0;
+}
+
+/**
+ *
+ */
+int ps_ptable_update(ps_presentity_t *pt)
+{
+       ps_presentity_t ptc;
+       ps_presentity_t *ptn = NULL;
+       uint32_t idx = 0;
+
+       /* copy struct to fill in missing fields */
+       memcpy(&ptc, pt, sizeof(ps_presentity_t));
+
+       ptc.hashid = core_case_hash(&pt->user, &pt->domain, 0);
+
+       if(ptc.ruid.s == NULL) {
+               if(sruid_next(&pres_sruid) < 0) {
+                       return -1;
+               }
+               ptc.ruid = pres_sruid.uid;
+       }
+
+       idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
+
+       lock_get(&_ps_ptable->slots[idx].lock);
+       ptn = _ps_ptable->slots[idx].plist;
+       while(ptn!=NULL) {
+               if(ps_presentity_match(ptn, &ptc, 0)==1) {
+                       if(ptn->next) {
+                               ptn->next->prev = ptn->prev;
+                       }
+                       if(ptn->prev) {
+                               ptn->prev->next = ptn->next;
+                       } else {
+                               _ps_ptable->slots[idx].plist = ptn->next;
+                       }
+                       break;
+               }
+               ptn = ptn->next;
+       }
+
+       if(ptn == NULL) {
+               lock_release(&_ps_ptable->slots[idx].lock);
+               return 0; /* affected items */
+       }
+       ps_presentity_free(ptn, 0);
+
+       ptn = ps_presentity_new(&ptc, 0);
+       if(ptn==NULL) {
+               lock_release(&_ps_ptable->slots[idx].lock);
+               return -1;
+       }
+
+       if(_ps_ptable->slots[idx].plist == NULL) {
+               _ps_ptable->slots[idx].plist = ptn;
+       } else {
+               _ps_ptable->slots[idx].plist->prev = ptn;
+               ptn->next = _ps_ptable->slots[idx].plist;
+               _ps_ptable->slots[idx].plist = ptn;
+       }
+       lock_release(&_ps_ptable->slots[idx].lock);
+
+       return 1; /* affected items */
+}
+
+/**
+ *
+ */
+int ps_ptable_remove(ps_presentity_t *pt)
+{
+       ps_presentity_t ptc;
+       ps_presentity_t *ptn = NULL;
+       uint32_t idx = 0;
+
+       /* copy struct to fill in missing fields */
+       memcpy(&ptc, pt, sizeof(ps_presentity_t));
+
+       ptc.hashid = core_case_hash(&pt->user, &pt->domain, 0);
+       idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
+
+       lock_get(&_ps_ptable->slots[idx].lock);
+       ptn = _ps_ptable->slots[idx].plist;
+       while(ptn!=NULL) {
+               if(ps_presentity_match(ptn, &ptc, 0)==1) {
+                       if(ptn->next) {
+                               ptn->next->prev = ptn->prev;
+                       }
+                       if(ptn->prev) {
+                               ptn->prev->next = ptn->next;
+                       } else {
+                               _ps_ptable->slots[idx].plist = ptn->next;
+                       }
+                       break;
+               }
+               ptn = ptn->next;
+       }
+       lock_release(&_ps_ptable->slots[idx].lock);
+
+       if(ptn != NULL) {
+               ps_presentity_free(ptn, 0);
+       }
+       return 0;
+}
+
+/**
+ *
+ */
+ps_presentity_t *ps_ptable_get_list(str *user, str *domain)
+{
+       ps_presentity_t ptc;
+       ps_presentity_t *ptn = NULL;
+       ps_presentity_t *ptl = NULL;
+       ps_presentity_t *ptd = NULL;
+       ps_presentity_t *pte = NULL;
+       uint32_t idx = 0;
+
+       memset(&ptc, 0, sizeof(ps_presentity_t));
+
+       ptc.user = *user;
+       ptc.domain = *domain;
+       ptc.hashid = core_case_hash(&ptc.user, &ptc.domain, 0);
+       idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
+
+       lock_get(&_ps_ptable->slots[idx].lock);
+       ptn = _ps_ptable->slots[idx].plist;
+       while(ptn!=NULL) {
+               if(ps_presentity_match(ptn, &ptc, 1)==1) {
+                       ptd = ps_presentity_dup(ptn, 1);
+                       if(ptd == NULL) {
+                               break;
+                       }
+                       if(pte==NULL) {
+                               ptl = ptd;
+                       } else {
+                               pte->next = ptd;
+                               ptd->prev = pte;
+                       }
+                       pte = ptd;
+               }
+               ptn = ptn->next;
+       }
+       lock_release(&_ps_ptable->slots[idx].lock);
+
+       if(ptd==NULL && ptl != NULL) {
+               ps_presentity_list_free(ptl, 1);
+               return NULL;
+       }
+
+       return ptl;
+}
+
+/**
+ *
+ */
+ps_presentity_t *ps_ptable_get_item(str *user, str *domain, str *event, str *etag)
+{
+       ps_presentity_t ptc;
+       ps_presentity_t *ptn = NULL;
+       ps_presentity_t *ptd = NULL;
+       uint32_t idx = 0;
+
+       memset(&ptc, 0, sizeof(ps_presentity_t));
+
+       ptc.user = *user;
+       ptc.domain = *domain;
+       ptc.event = *event;
+       ptc.etag = *etag;
+       ptc.hashid = core_case_hash(&ptc.user, &ptc.domain, 0);
+       idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
+
+       lock_get(&_ps_ptable->slots[idx].lock);
+       ptn = _ps_ptable->slots[idx].plist;
+       while(ptn!=NULL) {
+               if(ps_presentity_match(ptn, &ptc, 0)==1) {
+                       ptd = ps_presentity_dup(ptn, 1);
+                       break;
+               }
+               ptn = ptn->next;
+       }
+       lock_release(&_ps_ptable->slots[idx].lock);
+
+       return ptd;
+}
+
+/**
+ *
+ */
+ps_presentity_t *ps_ptable_get_expired(int eval)
+{
+       ps_presentity_t *ptn = NULL;
+       ps_presentity_t *ptl = NULL;
+       ps_presentity_t *ptd = NULL;
+       ps_presentity_t *pte = NULL;
+       int i = 0;
+
+       for(i=0; i<_ps_ptable->ssize; i++) {
+               lock_get(&_ps_ptable->slots[i].lock);
+               ptn = _ps_ptable->slots[i].plist;
+               while(ptn!=NULL) {
+                       if(ptn->expires > 0 && ptn->expires <= eval) {
+                               ptd = ps_presentity_dup(ptn, 1);
+                               if(ptd == NULL) {
+                                       break;
+                               }
+                               if(pte==NULL) {
+                                       ptl = ptd;
+                               } else {
+                                       pte->next = ptd;
+                                       ptd->prev = pte;
+                               }
+                               pte = ptd;
+                       }
+                       ptn = ptn->next;
+               }
+               lock_release(&_ps_ptable->slots[i].lock);
+       }
+
+       if(ptd==NULL && ptl != NULL) {
+               ps_presentity_list_free(ptl, 1);
+               return NULL;
+       }
+
+       return ptl;
+}
\ No newline at end of file