Selaa lähdekoodia

presence: function to search presentity items for in memory subscriptions

Daniel-Constantin Mierla 5 vuotta sitten
vanhempi
commit
737d92bbc0
3 muutettua tiedostoa jossa 316 lisäystä ja 13 poistoa
  1. 105 12
      src/modules/presence/hash.c
  2. 1 0
      src/modules/presence/hash.h
  3. 210 1
      src/modules/presence/notify.c

+ 105 - 12
src/modules/presence/hash.c

@@ -861,7 +861,10 @@ ps_presentity_t *ps_presentity_dup(ps_presentity_t *pt, int mtype)
 }
 
 /**
- *
+ * match presentity with various conditions
+ *   0 - only user and domain
+ *   1 - match also event
+ *   2 - match also etag
  */
 int ps_presentity_match(ps_presentity_t *pta, ps_presentity_t *ptb, int mmode)
 {
@@ -873,8 +876,14 @@ int ps_presentity_match(ps_presentity_t *pta, ps_presentity_t *ptb, int mmode)
 		return 0;
 	}
 
-	if(mmode == 0) {
-		if(pta->etag.len != ptb->etag.len || pta->event.len != ptb->event.len) {
+	if(mmode > 0) {
+		if(pta->event.len != ptb->event.len) {
+			return 0;
+		}
+	}
+
+	if(mmode > 1) {
+		if(pta->etag.len != ptb->etag.len) {
 			return 0;
 		}
 	}
@@ -887,16 +896,17 @@ int ps_presentity_match(ps_presentity_t *pta, ps_presentity_t *ptb, int mmode)
 		return 0;
 	}
 
-	if(mmode==0) {
-		if(strncmp(pta->etag.s, ptb->etag.s, pta->etag.len)!=0) {
+	if(mmode > 0) {
+		if(strncmp(pta->event.s, ptb->event.s, pta->event.len)!=0) {
 			return 0;
 		}
+	}
 
-		if(strncmp(pta->event.s, ptb->event.s, pta->event.len)!=0) {
+	if(mmode > 1) {
+		if(strncmp(pta->etag.s, ptb->etag.s, pta->etag.len)!=0) {
 			return 0;
 		}
 	}
-
 	return 1;
 }
 
@@ -1036,7 +1046,7 @@ int ps_ptable_replace(ps_presentity_t *ptm, ps_presentity_t *pt)
 	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(ps_presentity_match(ptn, &ptc, 2)==1) {
 			if(ptn->next) {
 				ptn->next->prev = ptn->prev;
 			}
@@ -1101,7 +1111,7 @@ int ps_ptable_update(ps_presentity_t *ptm, ps_presentity_t *pt)
 	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(ps_presentity_match(ptn, &ptc, 2)==1) {
 			if(ptn->next) {
 				ptn->next->prev = ptn->prev;
 			}
@@ -1157,7 +1167,7 @@ int ps_ptable_remove(ps_presentity_t *pt)
 	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(ps_presentity_match(ptn, &ptc, 2)==1) {
 			if(ptn->next) {
 				ptn->next->prev = ptn->prev;
 			}
@@ -1200,7 +1210,51 @@ ps_presentity_t *ps_ptable_get_list(str *user, str *domain)
 	lock_get(&_ps_ptable->slots[idx].lock);
 	ptn = _ps_ptable->slots[idx].plist;
 	while(ptn!=NULL) {
-		if(ps_presentity_match(ptn, &ptc, 1)==1) {
+		if(ps_presentity_match(ptn, &ptc, 0)==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_search(ps_presentity_t *ptm, int rmode)
+{
+	ps_presentity_t *ptn = NULL;
+	ps_presentity_t *ptl = NULL;
+	ps_presentity_t *ptd = NULL;
+	ps_presentity_t *pte = NULL;
+	uint32_t idx = 0;
+	int pmax = 0;
+
+	ptm->hashid = core_case_hash(&ptm->user, &ptm->domain, 0);
+	idx = core_hash_idx(ptm->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, ptm, 1)==1)
+				&& (ptm->expires==0 || ptn->expires > ptm->expires)) {
 			ptd = ps_presentity_dup(ptn, 1);
 			if(ptd == NULL) {
 				break;
@@ -1222,6 +1276,45 @@ ps_presentity_t *ps_ptable_get_list(str *user, str *domain)
 		return NULL;
 	}
 
+	if(rmode==1) {
+		/* order list by priority */
+		pte = NULL;
+		while(ptl!=NULL) {
+			pmax = 0;
+			ptn = ptl;
+			ptd = ptl;
+			while(ptn!=NULL) {
+				if(ptn->priority >= pmax) {
+					pmax = ptn->priority;
+					ptd = ptn;
+				}
+				ptn = ptn->next;
+			}
+			if(ptd == ptl) {
+				ptl = ptl->next;
+				if(ptl) {
+					ptl->prev = NULL;
+				}
+				ptd->next = pte;
+				pte->prev = ptd;
+				pte = ptd;
+			} else {
+				if(ptd->prev) {
+					ptd->prev->next = ptd->next;
+				}
+				if(ptd->next) {
+					ptd->next->prev = ptd->prev;
+				}
+				ptd->next = pte;
+				ptd->prev = NULL;
+				pte->prev = ptd;
+				pte = ptd;
+			}
+		}
+		return pte;
+	}
+
+	/* default ordered by received time */
 	return ptl;
 }
 
@@ -1247,7 +1340,7 @@ ps_presentity_t *ps_ptable_get_item(str *user, str *domain, str *event, str *eta
 	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(ps_presentity_match(ptn, &ptc, 2)==1) {
 			ptd = ps_presentity_dup(ptn, 1);
 			break;
 		}

+ 1 - 0
src/modules/presence/hash.h

@@ -181,6 +181,7 @@ int ps_ptable_update(ps_presentity_t *ptm, ps_presentity_t *pt);
 int ps_ptable_remove(ps_presentity_t *pt);
 ps_presentity_t *ps_ptable_get_list(str *user, str *domain);
 ps_presentity_t *ps_ptable_get_item(str *user, str *domain, str *event, str *etag);
+ps_presentity_t *ps_ptable_search(ps_presentity_t *ptm, int rmode);
 ps_presentity_t *ps_ptable_get_expired(int eval);
 ps_ptable_t *ps_ptable_get(void);
 

+ 210 - 1
src/modules/presence/notify.c

@@ -579,7 +579,8 @@ error:
 	return NULL;
 }
 
-str *get_p_notify_body(str pres_uri, pres_ev_t *event, str *etag, str *contact)
+str *ps_db_get_p_notify_body(str pres_uri, pres_ev_t *event, str *etag,
+		str *contact)
 {
 	db_key_t query_cols[4];
 	db_val_t query_vals[4];
@@ -862,6 +863,214 @@ error:
 	return NULL;
 }
 
+str *ps_cache_get_p_notify_body(str pres_uri, pres_ev_t *event, str *etag,
+		str *contact)
+{
+	sip_uri_t uri;
+	ps_presentity_t ptm;
+	ps_presentity_t *pti;
+	ps_presentity_t *ptlist = NULL;
+	int n = 0;
+	int i = 0;
+	str **body_array = NULL;
+	str *notify_body = NULL;
+	str *body;
+	int size = 0;
+	int build_off_n = -1;
+
+	if(parse_uri(pres_uri.s, pres_uri.len, &uri) < 0) {
+		LM_ERR("while parsing uri\n");
+		return NULL;
+	}
+	memset(&ptm, 0, sizeof(ps_presentity_t));
+
+	ptm.user = uri.user;
+	ptm.domain = uri.host;
+	ptm.event = event->name;
+	if(pres_startup_mode == 1) {
+		ptm.expires = (int)time(NULL);
+	}
+
+	ptlist = ps_ptable_search(&ptm, pres_retrieve_order);
+
+	if(ptlist == NULL) {
+		LM_DBG("the query returned no result\n[username]= %.*s"
+			   "\t[domain]= %.*s\t[event]= %.*s\n",
+				uri.user.len, uri.user.s, uri.host.len, uri.host.s,
+				event->name.len, event->name.s);
+
+		if(event->agg_nbody) {
+			notify_body = event->agg_nbody(&uri.user, &uri.host, NULL, 0, -1);
+			if(notify_body) {
+				goto done;
+			}
+		}
+		return NULL;
+	}
+
+	if(event->agg_nbody == NULL) {
+		LM_DBG("event does not require aggregation\n");
+		pti = ptlist;
+		while(pti->next) {
+			pti = pti->next;
+		}
+
+		/* if event BLA - check if sender is the same as contact */
+		/* if so, send an empty dialog info document */
+		if(EVENT_DIALOG_SLA(event->evp) && contact) {
+			if(pti->sender.s == NULL || pti->sender.len <= 0) {
+				LM_DBG("no sender address\n");
+				goto after_sender_check;
+			}
+
+			if(pti->sender.len == contact->len
+					&& presence_sip_uri_match(&pti->sender, contact) == 0) {
+				notify_body = build_empty_bla_body(pres_uri);
+				ps_presentity_list_free(ptlist, 1);
+				return notify_body;
+			}
+		}
+
+	after_sender_check:
+		if(pti->body.s == NULL || pti->body.len <= 0) {
+			LM_ERR("NULL notify body record\n");
+			goto error;
+		}
+
+		notify_body = (str *)pkg_malloc(sizeof(str));
+		if(notify_body == NULL) {
+			ERR_MEM(PKG_MEM_STR);
+		}
+		memset(notify_body, 0, sizeof(str));
+		notify_body->s = (char *)pkg_malloc((pti->body.len+1) * sizeof(char));
+		if(notify_body->s == NULL) {
+			pkg_free(notify_body);
+			ERR_MEM(PKG_MEM_STR);
+		}
+		memcpy(notify_body->s, pti->body.s, pti->body.len);
+		notify_body->len = pti->body.len;
+		ps_presentity_list_free(ptlist, 1);
+
+		return notify_body;
+	}
+
+	LM_DBG("event requires aggregation\n");
+
+	n = 0;
+	pti = ptlist;
+	while(pti) {
+		n++;
+		pti = pti->next;
+	}
+	body_array = (str **)pkg_malloc((n + 2) * sizeof(str *));
+	if(body_array == NULL) {
+		ERR_MEM(PKG_MEM_STR);
+	}
+	memset(body_array, 0, (n + 2) * sizeof(str *));
+
+	if(etag != NULL) {
+		LM_DBG("searched etag = %.*s len= %d\n", etag->len, etag->s,
+				etag->len);
+		LM_DBG("etag not NULL\n");
+		pti = ptlist;
+		i = 0;
+		while(pti) {
+			LM_DBG("etag = %.*s len= %d\n", pti->etag.len, pti->etag.s,
+					pti->etag.len);
+			if((pti->etag.len == etag->len)
+					&& (strncmp(pti->etag.s, etag->s, pti->etag.len) == 0)) {
+				LM_DBG("found etag\n");
+				build_off_n = i;
+			}
+			if(pti->body.s == NULL || pti->body.len <= 0) {
+				LM_ERR("Empty notify body record\n");
+				goto error;
+			}
+
+			size = sizeof(str) + (pti->body.len +1) * sizeof(char);
+			body = (str *)pkg_malloc(size);
+			if(body == NULL) {
+				ERR_MEM(PKG_MEM_STR);
+			}
+			memset(body, 0, size);
+			size = sizeof(str);
+			body->s = (char *)body + size;
+			memcpy(body->s, pti->body.s, pti->body.len);
+			body->len = pti->body.len;
+
+			body_array[i] = body;
+			i++;
+			pti = pti->next;
+		}
+	} else {
+		pti = ptlist;
+		i = 0;
+		while(pti) {
+			if(pti->body.s == NULL || pti->body.len <= 0) {
+				LM_ERR("Empty notify body record\n");
+				goto error;
+			}
+
+			size = sizeof(str) + (pti->body.len+1) * sizeof(char);
+			body = (str *)pkg_malloc(size);
+			if(body == NULL) {
+				ERR_MEM(PKG_MEM_STR);
+			}
+			memset(body, 0, size);
+			size = sizeof(str);
+			body->s = (char *)body + size;
+			memcpy(body->s, pti->body.s, pti->body.len);
+			body->len = pti->body.len;
+
+			body_array[i] = body;
+			i++;
+			pti = pti->next;
+		}
+	}
+
+	ps_presentity_list_free(ptlist, 1);
+
+	notify_body = event->agg_nbody(
+			&uri.user, &uri.host, body_array, n, build_off_n);
+
+done:
+	if(body_array != NULL) {
+		for(i = 0; i < n; i++) {
+			if(body_array[i]) {
+				pkg_free(body_array[i]);
+			}
+		}
+		pkg_free(body_array);
+	}
+	return notify_body;
+
+error:
+	if(ptlist != NULL) {
+		ps_presentity_list_free(ptlist, 1);
+	}
+
+	if(body_array != NULL) {
+		for(i = 0; i < n; i++) {
+			if(body_array[i])
+				pkg_free(body_array[i]);
+			else
+				break;
+		}
+
+		pkg_free(body_array);
+	}
+	return NULL;
+}
+
+str *get_p_notify_body(str pres_uri, pres_ev_t *event, str *etag, str *contact)
+{
+	if(publ_cache_mode == PS_PCACHE_RECORD) {
+		return ps_cache_get_p_notify_body(pres_uri, event, etag, contact);
+	} else {
+		return ps_db_get_p_notify_body(pres_uri, event, etag, contact);
+	}
+}
+
 void free_notify_body(str *body, pres_ev_t *ev)
 {
 	if(body != NULL) {