1 /*
2  * presence module - presence server implementation
3  *
4  * Copyright (C) 2007 Voice Sistem S.R.L.
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23 
24 /*! \file
25  * \brief Kamailio presence module
26  * \ingroup presence
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <time.h>
32 #include "../../core/mem/shm_mem.h"
33 #include "../../core/hashes.h"
34 #include "../../core/dprint.h"
35 #include "../../core/str.h"
36 #include "../pua/hash.h"
37 #include "presence.h"
38 #include "hash.h"
39 #include "notify.h"
40 
41 /* matching mode when removing subscriptions from memory */
42 extern int pres_subs_remove_match;
43 
44 /**
45  * create the subscription hash table in shared memory
46  * - hash_size: number of slots
47  */
new_shtable(int hash_size)48 shtable_t new_shtable(int hash_size)
49 {
50 	shtable_t htable = NULL;
51 	int i, j;
52 
53 	i = 0;
54 	htable = (subs_entry_t *)shm_malloc(hash_size * sizeof(subs_entry_t));
55 	if(htable == NULL) {
56 		ERR_MEM(SHARE_MEM);
57 	}
58 	memset(htable, 0, hash_size * sizeof(subs_entry_t));
59 	for(i = 0; i < hash_size; i++) {
60 		if(lock_init(&htable[i].lock) == 0) {
61 			LM_ERR("initializing lock [%d]\n", i);
62 			goto error;
63 		}
64 		htable[i].entries = (subs_t *)shm_malloc(sizeof(subs_t));
65 		if(htable[i].entries == NULL) {
66 			lock_destroy(&htable[i].lock);
67 			ERR_MEM(SHARE_MEM);
68 		}
69 		memset(htable[i].entries, 0, sizeof(subs_t));
70 		htable[i].entries->next = NULL;
71 	}
72 
73 	return htable;
74 
75 error:
76 	if(htable) {
77 		for(j = 0; j < i; j++) {
78 			lock_destroy(&htable[j].lock);
79 			shm_free(htable[j].entries);
80 		}
81 		shm_free(htable);
82 	}
83 	return NULL;
84 }
85 
destroy_shtable(shtable_t htable,int hash_size)86 void destroy_shtable(shtable_t htable, int hash_size)
87 {
88 	int i;
89 
90 	if(htable == NULL)
91 		return;
92 
93 	for(i = 0; i < hash_size; i++) {
94 		lock_destroy(&htable[i].lock);
95 		free_subs_list(htable[i].entries->next, SHM_MEM_TYPE, 1);
96 		shm_free(htable[i].entries);
97 		htable[i].entries = NULL;
98 	}
99 	shm_free(htable);
100 	htable = NULL;
101 }
102 
search_shtable(shtable_t htable,str callid,str to_tag,str from_tag,unsigned int hash_code)103 subs_t *search_shtable(shtable_t htable, str callid, str to_tag, str from_tag,
104 		unsigned int hash_code)
105 {
106 	subs_t *s;
107 
108 	s = htable[hash_code].entries ? htable[hash_code].entries->next : NULL;
109 
110 	while(s) {
111 		if(s->callid.len == callid.len
112 				&& strncmp(s->callid.s, callid.s, callid.len) == 0
113 				&& s->to_tag.len == to_tag.len
114 				&& strncmp(s->to_tag.s, to_tag.s, to_tag.len) == 0
115 				&& s->from_tag.len == from_tag.len
116 				&& strncmp(s->from_tag.s, from_tag.s, from_tag.len) == 0)
117 			return s;
118 		s = s->next;
119 	}
120 
121 	return NULL;
122 }
123 
mem_copy_subs(subs_t * s,int mem_type)124 subs_t *mem_copy_subs(subs_t *s, int mem_type)
125 {
126 	int size;
127 	subs_t *dest;
128 
129 	size = sizeof(subs_t)
130 		   + (s->pres_uri.len + s->to_user.len + s->to_domain.len
131 					 + s->from_user.len + s->from_domain.len + s->callid.len
132 					 + s->to_tag.len + s->from_tag.len + s->sockinfo_str.len
133 					 + s->event_id.len + s->local_contact.len + s->contact.len
134 					 + s->record_route.len + s->reason.len + s->watcher_user.len
135 					 + s->watcher_domain.len + s->user_agent.len + 1)
136 					 * sizeof(char);
137 
138 	if(mem_type & PKG_MEM_TYPE)
139 		dest = (subs_t *)pkg_malloc(size);
140 	else
141 		dest = (subs_t *)shm_malloc(size);
142 
143 	if(dest == NULL) {
144 		ERR_MEM((mem_type == PKG_MEM_TYPE) ? PKG_MEM_STR : SHARE_MEM);
145 	}
146 	memset(dest, 0, size);
147 	size = sizeof(subs_t);
148 
149 	CONT_COPY(dest, dest->pres_uri, s->pres_uri);
150 	CONT_COPY(dest, dest->to_user, s->to_user);
151 	CONT_COPY(dest, dest->to_domain, s->to_domain);
152 	CONT_COPY(dest, dest->from_user, s->from_user);
153 	CONT_COPY(dest, dest->from_domain, s->from_domain);
154 	CONT_COPY(dest, dest->watcher_user, s->watcher_user);
155 	CONT_COPY(dest, dest->watcher_domain, s->watcher_domain);
156 	CONT_COPY(dest, dest->to_tag, s->to_tag);
157 	CONT_COPY(dest, dest->from_tag, s->from_tag);
158 	CONT_COPY(dest, dest->callid, s->callid);
159 	CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str);
160 	CONT_COPY(dest, dest->local_contact, s->local_contact);
161 	CONT_COPY(dest, dest->contact, s->contact);
162 	CONT_COPY(dest, dest->record_route, s->record_route);
163 	CONT_COPY(dest, dest->user_agent, s->user_agent);
164 	if(s->event_id.s)
165 		CONT_COPY(dest, dest->event_id, s->event_id);
166 	if(s->reason.s)
167 		CONT_COPY(dest, dest->reason, s->reason);
168 
169 	dest->event = s->event;
170 	dest->local_cseq = s->local_cseq;
171 	dest->remote_cseq = s->remote_cseq;
172 	dest->status = s->status;
173 	dest->version = s->version;
174 	dest->send_on_cback = s->send_on_cback;
175 	dest->expires = s->expires;
176 	dest->db_flag = s->db_flag;
177 	dest->flags = s->flags;
178 
179 	return dest;
180 
181 error:
182 	return NULL;
183 }
184 
185 
mem_copy_subs_noc(subs_t * s)186 subs_t *mem_copy_subs_noc(subs_t *s)
187 {
188 	int size;
189 	subs_t *dest;
190 
191 	size = sizeof(subs_t)
192 		   + (s->pres_uri.len + s->to_user.len + s->to_domain.len
193 					 + s->from_user.len + s->from_domain.len + s->callid.len
194 					 + s->to_tag.len + s->from_tag.len + s->sockinfo_str.len
195 					 + s->event_id.len + s->local_contact.len + s->reason.len
196 					 + s->watcher_user.len + s->watcher_domain.len
197 					 + s->user_agent.len + 1)
198 					 * sizeof(char);
199 
200 	dest = (subs_t *)shm_malloc(size);
201 	if(dest == NULL) {
202 		ERR_MEM(SHARE_MEM);
203 	}
204 	memset(dest, 0, size);
205 	size = sizeof(subs_t);
206 
207 	CONT_COPY(dest, dest->pres_uri, s->pres_uri);
208 	CONT_COPY(dest, dest->to_user, s->to_user);
209 	CONT_COPY(dest, dest->to_domain, s->to_domain);
210 	CONT_COPY(dest, dest->from_user, s->from_user);
211 	CONT_COPY(dest, dest->from_domain, s->from_domain);
212 	CONT_COPY(dest, dest->watcher_user, s->watcher_user);
213 	CONT_COPY(dest, dest->watcher_domain, s->watcher_domain);
214 	CONT_COPY(dest, dest->to_tag, s->to_tag);
215 	CONT_COPY(dest, dest->from_tag, s->from_tag);
216 	CONT_COPY(dest, dest->callid, s->callid);
217 	CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str);
218 	CONT_COPY(dest, dest->local_contact, s->local_contact);
219 	CONT_COPY(dest, dest->user_agent, s->user_agent);
220 	if(s->event_id.s)
221 		CONT_COPY(dest, dest->event_id, s->event_id);
222 	if(s->reason.s)
223 		CONT_COPY(dest, dest->reason, s->reason);
224 
225 	dest->event = s->event;
226 	dest->local_cseq = s->local_cseq;
227 	dest->remote_cseq = s->remote_cseq;
228 	dest->status = s->status;
229 	dest->version = s->version;
230 	dest->send_on_cback = s->send_on_cback;
231 	dest->expires = s->expires;
232 	dest->db_flag = s->db_flag;
233 	dest->flags = s->flags;
234 
235 	dest->contact.s = (char *)shm_malloc(s->contact.len * sizeof(char));
236 	if(dest->contact.s == NULL) {
237 		ERR_MEM(SHARE_MEM);
238 	}
239 	memcpy(dest->contact.s, s->contact.s, s->contact.len);
240 	dest->contact.len = s->contact.len;
241 
242 	dest->record_route.s =
243 			(char *)shm_malloc((s->record_route.len + 1) * sizeof(char));
244 	if(dest->record_route.s == NULL) {
245 		ERR_MEM(SHARE_MEM);
246 	}
247 	memcpy(dest->record_route.s, s->record_route.s, s->record_route.len);
248 	dest->record_route.len = s->record_route.len;
249 
250 	return dest;
251 
252 error:
253 	if(dest)
254 		shm_free(dest);
255 	return NULL;
256 }
257 
insert_shtable(shtable_t htable,unsigned int hash_code,subs_t * subs)258 int insert_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
259 {
260 	subs_t *new_rec = NULL;
261 
262 	if (pres_delete_same_subs) {
263 		subs_t* rec = NULL, *prev_rec = NULL;
264 
265 		lock_get(&htable[hash_code].lock);
266 		/* search if there is another record with the same pres_uri & callid */
267 		rec = htable[hash_code].entries->next;
268 		while (rec) {
269 			if (subs->pres_uri.len == rec->pres_uri.len && subs->callid.len == rec->callid.len &&
270 					memcmp(subs->pres_uri.s, rec->pres_uri.s, subs->pres_uri.len) == 0 &&
271 					memcmp(subs->callid.s, rec->callid.s, subs->callid.len) == 0) {
272 				LM_NOTICE("Found another record with the same pres_uri[%.*s] and callid[%.*s]\n",
273 					subs->pres_uri.len, subs->pres_uri.s, subs->callid.len, subs->callid.s);
274 				/* delete this record */
275 
276 				if (prev_rec) {
277 					prev_rec->next = rec->next;
278 				} else {
279 					htable[hash_code].entries->next = rec->next;
280 				}
281 
282 				if (pres_subs_dbmode != NO_DB) {
283 					delete_db_subs(&rec->to_tag, &rec->from_tag, &rec->callid);
284 				}
285 
286 				if (rec->contact.s!=NULL) {
287 					shm_free(rec->contact.s);
288 				}
289 
290 				shm_free(rec);
291 				break;
292 			}
293 			prev_rec = rec;
294 			rec = rec->next;
295 		}
296 		lock_release(&htable[hash_code].lock);
297 	}
298 
299 	new_rec = mem_copy_subs_noc(subs);
300 	if(new_rec == NULL) {
301 		LM_ERR("copying in share memory a subs_t structure\n");
302 		return -1;
303 	}
304 	new_rec->expires += (int)time(NULL);
305 
306 	lock_get(&htable[hash_code].lock);
307 	new_rec->next = htable[hash_code].entries->next;
308 	htable[hash_code].entries->next = new_rec;
309 	lock_release(&htable[hash_code].lock);
310 
311 	return 0;
312 }
313 
delete_shtable(shtable_t htable,unsigned int hash_code,subs_t * subs)314 int delete_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
315 {
316 	subs_t *s = NULL, *ps = NULL;
317 	int found = -1;
318 
319 	lock_get(&htable[hash_code].lock);
320 
321 	ps = htable[hash_code].entries;
322 	s = ps ? ps->next : NULL;
323 
324 	while(s) {
325 		if(pres_subs_remove_match == 0) {
326 			/* match on to-tag only (unique, local generated - faster) */
327 			if(s->to_tag.len == subs->to_tag.len
328 					&& strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
329 							   == 0) {
330 				found = 0;
331 			}
332 		} else {
333 			/* match on all dialog attributes (distributed systems) */
334 			if(s->callid.len == subs->callid.len
335 					&& s->to_tag.len == subs->to_tag.len
336 					&& s->from_tag.len == subs->from_tag.len
337 					&& strncmp(s->callid.s, subs->callid.s, subs->callid.len)
338 							   == 0
339 					&& strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
340 							   == 0
341 					&& strncmp(s->from_tag.s, subs->from_tag.s,
342 							   subs->from_tag.len)
343 							   == 0) {
344 				found = 0;
345 			}
346 		}
347 		if(found == 0) {
348 			found = s->local_cseq + 1;
349 			ps->next = s->next;
350 			if(s->contact.s != NULL) {
351 				shm_free(s->contact.s);
352 				s->contact.s = NULL;
353 			}
354 			if(s->record_route.s != NULL) {
355 				shm_free(s->record_route.s);
356 				s->record_route.s = NULL;
357 			}
358 			if(s) {
359 				shm_free(s);
360 				s = NULL;
361 			}
362 			break;
363 		}
364 		ps = s;
365 		s = s->next;
366 	}
367 	lock_release(&htable[hash_code].lock);
368 	return found;
369 }
370 
free_subs_list(subs_t * s_array,int mem_type,int ic)371 void free_subs_list(subs_t *s_array, int mem_type, int ic)
372 {
373 	subs_t *s;
374 
375 	while(s_array) {
376 		s = s_array;
377 		s_array = s_array->next;
378 		if(mem_type & PKG_MEM_TYPE) {
379 			if(ic) {
380 				pkg_free(s->contact.s);
381 				s->contact.s = NULL;
382 			}
383 			pkg_free(s);
384 			s = NULL;
385 		} else {
386 			if(ic) {
387 				shm_free(s->contact.s);
388 				s->contact.s = NULL;
389 			}
390 			shm_free(s);
391 			s = NULL;
392 		}
393 	}
394 }
395 
update_shtable(shtable_t htable,unsigned int hash_code,subs_t * subs,int type)396 int update_shtable(
397 		shtable_t htable, unsigned int hash_code, subs_t *subs, int type)
398 {
399 	subs_t *s;
400 
401 	lock_get(&htable[hash_code].lock);
402 
403 	s = search_shtable(
404 			htable, subs->callid, subs->to_tag, subs->from_tag, hash_code);
405 	if(s == NULL) {
406 		LM_DBG("record not found in hash table\n");
407 		lock_release(&htable[hash_code].lock);
408 		return -1;
409 	}
410 
411 	if(type & REMOTE_TYPE) {
412 		s->expires = subs->expires + (int)time(NULL);
413 		s->remote_cseq = subs->remote_cseq;
414 	} else {
415 		subs->local_cseq = ++s->local_cseq;
416 		subs->version = ++s->version;
417 	}
418 
419 	if(presence_sip_uri_match(&s->contact, &subs->contact)) {
420 		shm_free(s->contact.s);
421 		s->contact.s = (char *)shm_malloc(subs->contact.len * sizeof(char));
422 		if(s->contact.s == NULL) {
423 			lock_release(&htable[hash_code].lock);
424 			LM_ERR("no more shared memory\n");
425 			return -1;
426 		}
427 		memcpy(s->contact.s, subs->contact.s, subs->contact.len);
428 		s->contact.len = subs->contact.len;
429 	}
430 
431 	shm_free(s->record_route.s);
432 	s->record_route.s =
433 			(char *)shm_malloc(subs->record_route.len * sizeof(char));
434 	if(s->record_route.s == NULL) {
435 		lock_release(&htable[hash_code].lock);
436 		LM_ERR("no more shared memory\n");
437 		return -1;
438 	}
439 	memcpy(s->record_route.s, subs->record_route.s, subs->record_route.len);
440 	s->record_route.len = subs->record_route.len;
441 
442 	s->status = subs->status;
443 	s->event = subs->event;
444 	subs->db_flag = s->db_flag;
445 
446 	if(s->db_flag & NO_UPDATEDB_FLAG)
447 		s->db_flag = UPDATEDB_FLAG;
448 
449 	lock_release(&htable[hash_code].lock);
450 
451 	return 0;
452 }
453 
new_phtable(void)454 phtable_t *new_phtable(void)
455 {
456 	phtable_t *htable = NULL;
457 	int i, j;
458 
459 	i = 0;
460 	htable = (phtable_t *)shm_malloc(phtable_size * sizeof(phtable_t));
461 	if(htable == NULL) {
462 		ERR_MEM(SHARE_MEM);
463 	}
464 	memset(htable, 0, phtable_size * sizeof(phtable_t));
465 
466 	for(i = 0; i < phtable_size; i++) {
467 		if(lock_init(&htable[i].lock) == 0) {
468 			LM_ERR("initializing lock [%d]\n", i);
469 			goto error;
470 		}
471 		htable[i].entries = (pres_entry_t *)shm_malloc(sizeof(pres_entry_t));
472 		if(htable[i].entries == NULL) {
473 			ERR_MEM(SHARE_MEM);
474 		}
475 		memset(htable[i].entries, 0, sizeof(pres_entry_t));
476 		htable[i].entries->next = NULL;
477 	}
478 
479 	return htable;
480 
481 error:
482 	if(htable) {
483 		for(j = 0; j < i; j++) {
484 			if(htable[i].entries)
485 				shm_free(htable[i].entries);
486 			else
487 				break;
488 			lock_destroy(&htable[i].lock);
489 		}
490 		shm_free(htable);
491 	}
492 	return NULL;
493 }
494 
destroy_phtable(void)495 void destroy_phtable(void)
496 {
497 	int i;
498 	pres_entry_t *p, *prev_p;
499 
500 	if(pres_htable == NULL)
501 		return;
502 
503 	for(i = 0; i < phtable_size; i++) {
504 		lock_destroy(&pres_htable[i].lock);
505 		p = pres_htable[i].entries;
506 		while(p) {
507 			prev_p = p;
508 			p = p->next;
509 			if(prev_p->sphere)
510 				shm_free(prev_p->sphere);
511 			shm_free(prev_p);
512 		}
513 	}
514 	shm_free(pres_htable);
515 }
516 /* entry must be locked before calling this function */
517 
search_phtable(str * pres_uri,int event,unsigned int hash_code)518 pres_entry_t *search_phtable(str *pres_uri, int event, unsigned int hash_code)
519 {
520 	pres_entry_t *p;
521 
522 	LM_DBG("pres_uri= %.*s\n", pres_uri->len, pres_uri->s);
523 	p = pres_htable[hash_code].entries->next;
524 	while(p) {
525 		if(p->event == event && p->pres_uri.len == pres_uri->len
526 				&& presence_sip_uri_match(&p->pres_uri, pres_uri) == 0)
527 			return p;
528 		p = p->next;
529 	}
530 	return NULL;
531 }
532 
insert_phtable(str * pres_uri,int event,char * sphere)533 int insert_phtable(str *pres_uri, int event, char *sphere)
534 {
535 	unsigned int hash_code;
536 	pres_entry_t *p = NULL;
537 	int size;
538 
539 	hash_code = core_case_hash(pres_uri, NULL, phtable_size);
540 
541 	lock_get(&pres_htable[hash_code].lock);
542 
543 	p = search_phtable(pres_uri, event, hash_code);
544 	if(p) {
545 		p->publ_count++;
546 		lock_release(&pres_htable[hash_code].lock);
547 		return 0;
548 	}
549 	size = sizeof(pres_entry_t) + pres_uri->len * sizeof(char);
550 
551 	p = (pres_entry_t *)shm_malloc(size);
552 	if(p == NULL) {
553 		lock_release(&pres_htable[hash_code].lock);
554 		ERR_MEM(SHARE_MEM);
555 	}
556 	memset(p, 0, size);
557 
558 	size = sizeof(pres_entry_t);
559 	p->pres_uri.s = (char *)p + size;
560 	memcpy(p->pres_uri.s, pres_uri->s, pres_uri->len);
561 	p->pres_uri.len = pres_uri->len;
562 
563 	if(sphere) {
564 		p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
565 		if(p->sphere == NULL) {
566 			lock_release(&pres_htable[hash_code].lock);
567 			shm_free(p);
568 			ERR_MEM(SHARE_MEM);
569 		}
570 		strcpy(p->sphere, sphere);
571 	}
572 
573 	p->event = event;
574 	p->publ_count = 1;
575 
576 	/* link the item in the hash table */
577 	p->next = pres_htable[hash_code].entries->next;
578 	pres_htable[hash_code].entries->next = p;
579 
580 	lock_release(&pres_htable[hash_code].lock);
581 
582 	return 0;
583 
584 error:
585 	return -1;
586 }
587 
delete_phtable(str * pres_uri,int event)588 int delete_phtable(str *pres_uri, int event)
589 {
590 	unsigned int hash_code;
591 	pres_entry_t *p = NULL, *prev_p = NULL;
592 
593 	hash_code = core_case_hash(pres_uri, NULL, phtable_size);
594 
595 	lock_get(&pres_htable[hash_code].lock);
596 
597 	p = search_phtable(pres_uri, event, hash_code);
598 	if(p == NULL) {
599 		LM_DBG("record not found\n");
600 		lock_release(&pres_htable[hash_code].lock);
601 		return 0;
602 	}
603 
604 	p->publ_count--;
605 	if(p->publ_count == 0) {
606 		/* delete record */
607 		prev_p = pres_htable[hash_code].entries;
608 		while(prev_p->next) {
609 			if(prev_p->next == p)
610 				break;
611 			prev_p = prev_p->next;
612 		}
613 		if(prev_p->next == NULL) {
614 			LM_ERR("record not found\n");
615 			lock_release(&pres_htable[hash_code].lock);
616 			return -1;
617 		}
618 		prev_p->next = p->next;
619 		if(p->sphere)
620 			shm_free(p->sphere);
621 
622 		shm_free(p);
623 	}
624 	lock_release(&pres_htable[hash_code].lock);
625 
626 	return 0;
627 }
628 
update_phtable(presentity_t * presentity,str * pres_uri,str * body)629 int update_phtable(presentity_t *presentity, str *pres_uri, str *body)
630 {
631 	char *sphere = NULL;
632 	unsigned int hash_code;
633 	pres_entry_t *p;
634 	int ret = 0;
635 	str *xcap_doc = NULL;
636 
637 	/* get new sphere */
638 	sphere = extract_sphere(body);
639 	if(sphere == NULL) {
640 		LM_DBG("no sphere defined in new body\n");
641 		return 0;
642 	}
643 
644 	/* search for record in hash table */
645 	hash_code = core_case_hash(pres_uri, NULL, phtable_size);
646 
647 	lock_get(&pres_htable[hash_code].lock);
648 
649 	p = search_phtable(pres_uri, presentity->event->evp->type, hash_code);
650 	if(p == NULL) {
651 		lock_release(&pres_htable[hash_code].lock);
652 		goto done;
653 	}
654 
655 	if(p->sphere) {
656 		if(strcmp(p->sphere, sphere) != 0) {
657 			/* new sphere definition */
658 			shm_free(p->sphere);
659 		} else {
660 			/* no change in sphere definition */
661 			lock_release(&pres_htable[hash_code].lock);
662 			pkg_free(sphere);
663 			return 0;
664 		}
665 	}
666 
667 
668 	p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
669 	if(p->sphere == NULL) {
670 		lock_release(&pres_htable[hash_code].lock);
671 		ret = -1;
672 		goto done;
673 	}
674 	strcpy(p->sphere, sphere);
675 
676 	lock_release(&pres_htable[hash_code].lock);
677 
678 	/* call for watchers status update */
679 
680 	if(presentity->event->get_rules_doc(
681 			   &presentity->user, &presentity->domain, &xcap_doc)
682 			< 0) {
683 		LM_ERR("failed to retrieve xcap document\n");
684 		ret = -1;
685 		goto done;
686 	}
687 
688 	update_watchers_status(pres_uri, presentity->event, xcap_doc);
689 
690 
691 done:
692 
693 	if(xcap_doc) {
694 		if(xcap_doc->s)
695 			pkg_free(xcap_doc->s);
696 		pkg_free(xcap_doc);
697 	}
698 
699 	if(sphere)
700 		pkg_free(sphere);
701 	return ret;
702 }
703 
704 /**
705  * ==============================
706  *  in-memory presentity records
707  * ==============================
708  */
709 
710 static ps_ptable_t *_ps_ptable = NULL;
711 
ps_ptable_get(void)712 ps_ptable_t *ps_ptable_get(void)
713 {
714 	return _ps_ptable;
715 }
716 
717 #define PS_PRESENTITY_FIELD_COPY(field) do { \
718 		if (pt->field.s) { \
719 			ptn->field.s = p; \
720 			memcpy(ptn->field.s, pt->field.s, pt->field.len); \
721 		} \
722 		ptn->field.len = pt->field.len; \
723 		p += pt->field.len + 1; \
724 	} while(0)
725 
726 /**
727  *
728  */
ps_presentity_new(ps_presentity_t * pt,int mtype)729 ps_presentity_t *ps_presentity_new(ps_presentity_t *pt, int mtype)
730 {
731 	uint32_t bsize = 0;
732 	ps_presentity_t *ptn = NULL;
733 	char *p = NULL;
734 
735 	if(pt==NULL) {
736 		return NULL;
737 	}
738 	bsize = sizeof(ps_presentity_t)
739 			+ pt->user.len + 1
740 			+ pt->domain.len + 1
741 			+ pt->etag.len + 1
742 			+ pt->event.len + 1
743 			+ pt->ruid.len + 1
744 			+ pt->sender.len + 1
745 			+ pt->body.len + 1;
746 	if(mtype==0) {
747 		ptn = (ps_presentity_t*)shm_malloc(bsize);
748 	} else {
749 		ptn = (ps_presentity_t*)pkg_malloc(bsize);
750 	}
751 	if(ptn==NULL) {
752 		if(mtype==0) {
753 			SHM_MEM_ERROR;
754 		} else {
755 			PKG_MEM_ERROR;
756 		}
757 		return NULL;
758 	}
759 	memset(ptn, 0, bsize);
760 
761 	ptn->bsize = bsize;
762 	ptn->hashid = core_case_hash(&pt->user, &pt->domain, 0);
763 	ptn->expires = pt->expires;
764 	ptn->received_time = pt->received_time;
765 	ptn->priority = pt->priority;
766 
767 	p = (char*)ptn + sizeof(ps_presentity_t);
768 	PS_PRESENTITY_FIELD_COPY(user);
769 	PS_PRESENTITY_FIELD_COPY(domain);
770 	PS_PRESENTITY_FIELD_COPY(etag);
771 	PS_PRESENTITY_FIELD_COPY(event);
772 	PS_PRESENTITY_FIELD_COPY(ruid);
773 	PS_PRESENTITY_FIELD_COPY(sender);
774 	PS_PRESENTITY_FIELD_COPY(body);
775 
776 	return ptn;
777 }
778 
779 /**
780  *
781  */
ps_presentity_free(ps_presentity_t * pt,int mtype)782 void ps_presentity_free(ps_presentity_t *pt, int mtype)
783 {
784 	if(pt==NULL) {
785 		return;
786 	}
787 	if(mtype==0) {
788 		shm_free(pt);
789 	} else {
790 		pkg_free(pt);
791 	}
792 }
793 
794 /**
795  *
796  */
ps_presentity_list_free(ps_presentity_t * pt,int mtype)797 void ps_presentity_list_free(ps_presentity_t *pt, int mtype)
798 {
799 	ps_presentity_t *ptc = NULL;
800 	ps_presentity_t *ptn = NULL;
801 
802 	if(pt==NULL) {
803 		return;
804 	}
805 
806 	ptn = pt;
807 	while(ptn!=NULL) {
808 		ptc = ptn;
809 		ptn = ptn->next;
810 		ps_presentity_free(ptc, mtype);
811 	}
812 }
813 
814 #define PS_PRESENTITY_FIELD_SHIFT(field) do { \
815 		if (pt->field.s) { \
816 			ptn->field.s = p; \
817 		} \
818 		p += pt->field.len + 1; \
819 	} while(0)
820 
821 /**
822  *
823  */
ps_presentity_dup(ps_presentity_t * pt,int mtype)824 ps_presentity_t *ps_presentity_dup(ps_presentity_t *pt, int mtype)
825 {
826 	ps_presentity_t *ptn = NULL;
827 	char *p = NULL;
828 
829 	if(pt==NULL) {
830 		return NULL;
831 	}
832 	if(mtype==0) {
833 		ptn = (ps_presentity_t*)shm_malloc(pt->bsize);
834 	} else {
835 		ptn = (ps_presentity_t*)pkg_malloc(pt->bsize);
836 	}
837 	if(ptn==NULL) {
838 		if(mtype==0) {
839 			SHM_MEM_ERROR;
840 		} else {
841 			PKG_MEM_ERROR;
842 		}
843 		return NULL;
844 	}
845 
846 	memcpy((void*)ptn, pt, pt->bsize);
847 
848 	p = (char*)ptn + sizeof(ps_presentity_t);
849 	PS_PRESENTITY_FIELD_SHIFT(user);
850 	PS_PRESENTITY_FIELD_SHIFT(domain);
851 	PS_PRESENTITY_FIELD_SHIFT(etag);
852 	PS_PRESENTITY_FIELD_SHIFT(event);
853 	PS_PRESENTITY_FIELD_SHIFT(ruid);
854 	PS_PRESENTITY_FIELD_SHIFT(sender);
855 	PS_PRESENTITY_FIELD_SHIFT(body);
856 
857 	ptn->next = NULL;
858 	ptn->prev = NULL;
859 
860 	return ptn;
861 }
862 
863 /**
864  * match presentity with various conditions
865  *   0 - only user and domain
866  *   1 - match also event
867  *   2 - match also etag
868  */
ps_presentity_match(ps_presentity_t * pta,ps_presentity_t * ptb,int mmode)869 int ps_presentity_match(ps_presentity_t *pta, ps_presentity_t *ptb, int mmode)
870 {
871 	if(pta->hashid != ptb->hashid) {
872 		return 0;
873 	}
874 
875 	if(pta->user.len != ptb->user.len || pta->domain.len != ptb->domain.len) {
876 		return 0;
877 	}
878 
879 	if(mmode > 0) {
880 		if(pta->event.len != ptb->event.len) {
881 			return 0;
882 		}
883 	}
884 
885 	if(mmode > 1) {
886 		if(pta->etag.len != ptb->etag.len) {
887 			return 0;
888 		}
889 	}
890 
891 	if(strncmp(pta->user.s, ptb->user.s, pta->user.len)!=0) {
892 		return 0;
893 	}
894 
895 	if(strncmp(pta->domain.s, ptb->domain.s, pta->domain.len)!=0) {
896 		return 0;
897 	}
898 
899 	if(mmode > 0) {
900 		if(strncmp(pta->event.s, ptb->event.s, pta->event.len)!=0) {
901 			return 0;
902 		}
903 	}
904 
905 	if(mmode > 1) {
906 		if(strncmp(pta->etag.s, ptb->etag.s, pta->etag.len)!=0) {
907 			return 0;
908 		}
909 	}
910 	return 1;
911 }
912 
913 /**
914  *
915  */
ps_ptable_init(int ssize)916 int ps_ptable_init(int ssize)
917 {
918 	size_t tsize = 0;
919 	int i = 0;
920 
921 	if(_ps_ptable!=NULL) {
922 		return 0;
923 	}
924 	tsize = sizeof(ps_ptable_t) + (ssize * sizeof(ps_pslot_t));
925 	_ps_ptable = (ps_ptable_t*)shm_malloc(tsize);
926 	if(_ps_ptable==NULL) {
927 		SHM_MEM_ERROR;
928 		return -1;
929 	}
930 	memset(_ps_ptable, 0, tsize);
931 	_ps_ptable->ssize = ssize;
932 	_ps_ptable->slots = (ps_pslot_t*)((char*)_ps_ptable + sizeof(ps_ptable_t));
933 	for(i=0; i<ssize; i++) {
934 		if(lock_init(&_ps_ptable->slots[i].lock) == 0) {
935 			LM_ERR("initializing lock on slot [%d]\n", i);
936 			goto error;
937 		}
938 	}
939 
940 	return 0;
941 
942 error:
943 	i--;
944 	while(i>=0) {
945 		lock_destroy(&_ps_ptable->slots[i].lock);
946 		i--;
947 	}
948 	shm_free(_ps_ptable);
949 	_ps_ptable = NULL;
950 	return -1;
951 }
952 
953 /**
954  *
955  */
ps_ptable_destroy(void)956 void ps_ptable_destroy(void)
957 {
958 	int i = 0;
959 	ps_presentity_t *pt = NULL;
960 	ps_presentity_t *ptn = NULL;
961 
962 	if(_ps_ptable==NULL) {
963 		return;
964 	}
965 	for(i=0; i<_ps_ptable->ssize; i++) {
966 		lock_destroy(&_ps_ptable->slots[i].lock);
967 		pt = _ps_ptable->slots[i].plist;
968 		while(pt!=NULL) {
969 			ptn = pt->next;
970 			ps_presentity_free(pt, 0);
971 			pt = ptn;
972 		}
973 	}
974 	shm_free(_ps_ptable);
975 	_ps_ptable = NULL;
976 	return;
977 }
978 
979 /**
980  *
981  */
ps_ptable_insert(ps_presentity_t * pt)982 int ps_ptable_insert(ps_presentity_t *pt)
983 {
984 	ps_presentity_t ptc;
985 	ps_presentity_t *ptn = NULL;
986 	uint32_t idx = 0;
987 
988 	/* copy struct to fill in missing fields */
989 	memcpy(&ptc, pt, sizeof(ps_presentity_t));
990 
991 	ptc.hashid = core_case_hash(&pt->user, &pt->domain, 0);
992 
993 	if(ptc.ruid.s == NULL) {
994 		if(sruid_next(&pres_sruid) < 0) {
995 			return -1;
996 		}
997 		ptc.ruid = pres_sruid.uid;
998 	}
999 
1000 	ptn = ps_presentity_new(&ptc, 0);
1001 	if(ptn==NULL) {
1002 		return -1;
1003 	}
1004 
1005 	idx = core_hash_idx(ptn->hashid, _ps_ptable->ssize);
1006 
1007 	lock_get(&_ps_ptable->slots[idx].lock);
1008 	if(_ps_ptable->slots[idx].plist == NULL) {
1009 		_ps_ptable->slots[idx].plist = ptn;
1010 	} else {
1011 		_ps_ptable->slots[idx].plist->prev = ptn;
1012 		ptn->next = _ps_ptable->slots[idx].plist;
1013 		_ps_ptable->slots[idx].plist = ptn;
1014 	}
1015 	lock_release(&_ps_ptable->slots[idx].lock);
1016 
1017 	return 0;
1018 }
1019 
1020 /**
1021  *
1022  */
ps_ptable_replace(ps_presentity_t * ptm,ps_presentity_t * pt)1023 int ps_ptable_replace(ps_presentity_t *ptm, ps_presentity_t *pt)
1024 {
1025 	ps_presentity_t ptc;
1026 	ps_presentity_t ptv;
1027 	ps_presentity_t *ptn = NULL;
1028 	uint32_t idx = 0;
1029 
1030 	/* copy struct to fill in missing fields */
1031 	memcpy(&ptc, ptm, sizeof(ps_presentity_t));
1032 	memcpy(&ptv, pt, sizeof(ps_presentity_t));
1033 
1034 	ptc.hashid = core_case_hash(&pt->user, &pt->domain, 0);
1035 	ptv.hashid = core_case_hash(&pt->user, &pt->domain, 0);
1036 
1037 	if(ptv.ruid.s == NULL) {
1038 		if(sruid_next(&pres_sruid) < 0) {
1039 			return -1;
1040 		}
1041 		ptv.ruid = pres_sruid.uid;
1042 	}
1043 
1044 	idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
1045 
1046 	lock_get(&_ps_ptable->slots[idx].lock);
1047 	ptn = _ps_ptable->slots[idx].plist;
1048 	while(ptn!=NULL) {
1049 		if(ps_presentity_match(ptn, &ptc, 2)==1) {
1050 			if(ptn->next) {
1051 				ptn->next->prev = ptn->prev;
1052 			}
1053 			if(ptn->prev) {
1054 				ptn->prev->next = ptn->next;
1055 			} else {
1056 				_ps_ptable->slots[idx].plist = ptn->next;
1057 			}
1058 			break;
1059 		}
1060 		ptn = ptn->next;
1061 	}
1062 
1063 	if(ptn!=NULL) {
1064 		ps_presentity_free(ptn, 0);
1065 	}
1066 
1067 	ptn = ps_presentity_new(&ptv, 0);
1068 	if(ptn==NULL) {
1069 		lock_release(&_ps_ptable->slots[idx].lock);
1070 		return -1;
1071 	}
1072 
1073 	if(_ps_ptable->slots[idx].plist == NULL) {
1074 		_ps_ptable->slots[idx].plist = ptn;
1075 	} else {
1076 		_ps_ptable->slots[idx].plist->prev = ptn;
1077 		ptn->next = _ps_ptable->slots[idx].plist;
1078 		_ps_ptable->slots[idx].plist = ptn;
1079 	}
1080 	lock_release(&_ps_ptable->slots[idx].lock);
1081 
1082 	return 0;
1083 }
1084 
1085 /**
1086  *
1087  */
ps_ptable_update(ps_presentity_t * ptm,ps_presentity_t * pt)1088 int ps_ptable_update(ps_presentity_t *ptm, ps_presentity_t *pt)
1089 {
1090 	ps_presentity_t ptc;
1091 	ps_presentity_t ptv;
1092 	ps_presentity_t *ptn = NULL;
1093 	uint32_t idx = 0;
1094 
1095 	/* copy struct to fill in missing fields */
1096 	memcpy(&ptc, ptm, sizeof(ps_presentity_t));
1097 	memcpy(&ptv, pt, sizeof(ps_presentity_t));
1098 
1099 	ptc.hashid = core_case_hash(&ptm->user, &ptm->domain, 0);
1100 	ptv.hashid = core_case_hash(&pt->user, &pt->domain, 0);
1101 
1102 	if(ptv.ruid.s == NULL) {
1103 		if(sruid_next(&pres_sruid) < 0) {
1104 			return -1;
1105 		}
1106 		ptv.ruid = pres_sruid.uid;
1107 	}
1108 
1109 	idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
1110 
1111 	lock_get(&_ps_ptable->slots[idx].lock);
1112 	ptn = _ps_ptable->slots[idx].plist;
1113 	while(ptn!=NULL) {
1114 		if(ps_presentity_match(ptn, &ptc, 2)==1) {
1115 			if(ptn->next) {
1116 				ptn->next->prev = ptn->prev;
1117 			}
1118 			if(ptn->prev) {
1119 				ptn->prev->next = ptn->next;
1120 			} else {
1121 				_ps_ptable->slots[idx].plist = ptn->next;
1122 			}
1123 			break;
1124 		}
1125 		ptn = ptn->next;
1126 	}
1127 
1128 	if(ptn == NULL) {
1129 		lock_release(&_ps_ptable->slots[idx].lock);
1130 		return 0; /* affected items */
1131 	}
1132 	ps_presentity_free(ptn, 0);
1133 
1134 	ptn = ps_presentity_new(&ptv, 0);
1135 	if(ptn==NULL) {
1136 		lock_release(&_ps_ptable->slots[idx].lock);
1137 		return -1;
1138 	}
1139 
1140 	if(_ps_ptable->slots[idx].plist == NULL) {
1141 		_ps_ptable->slots[idx].plist = ptn;
1142 	} else {
1143 		_ps_ptable->slots[idx].plist->prev = ptn;
1144 		ptn->next = _ps_ptable->slots[idx].plist;
1145 		_ps_ptable->slots[idx].plist = ptn;
1146 	}
1147 	lock_release(&_ps_ptable->slots[idx].lock);
1148 
1149 	return 1; /* affected items */
1150 }
1151 
1152 /**
1153  *
1154  */
ps_ptable_remove(ps_presentity_t * pt)1155 int ps_ptable_remove(ps_presentity_t *pt)
1156 {
1157 	ps_presentity_t ptc;
1158 	ps_presentity_t *ptn = NULL;
1159 	uint32_t idx = 0;
1160 
1161 	/* copy struct to fill in missing fields */
1162 	memcpy(&ptc, pt, sizeof(ps_presentity_t));
1163 
1164 	ptc.hashid = core_case_hash(&pt->user, &pt->domain, 0);
1165 	idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
1166 
1167 	lock_get(&_ps_ptable->slots[idx].lock);
1168 	ptn = _ps_ptable->slots[idx].plist;
1169 	while(ptn!=NULL) {
1170 		if(ps_presentity_match(ptn, &ptc, 2)==1) {
1171 			if(ptn->next) {
1172 				ptn->next->prev = ptn->prev;
1173 			}
1174 			if(ptn->prev) {
1175 				ptn->prev->next = ptn->next;
1176 			} else {
1177 				_ps_ptable->slots[idx].plist = ptn->next;
1178 			}
1179 			break;
1180 		}
1181 		ptn = ptn->next;
1182 	}
1183 	lock_release(&_ps_ptable->slots[idx].lock);
1184 
1185 	if(ptn != NULL) {
1186 		ps_presentity_free(ptn, 0);
1187 	}
1188 	return 0;
1189 }
1190 
1191 /**
1192  *
1193  */
ps_ptable_get_list(str * user,str * domain)1194 ps_presentity_t *ps_ptable_get_list(str *user, str *domain)
1195 {
1196 	ps_presentity_t ptc;
1197 	ps_presentity_t *ptn = NULL;
1198 	ps_presentity_t *ptl = NULL;
1199 	ps_presentity_t *ptd = NULL;
1200 	ps_presentity_t *pte = NULL;
1201 	uint32_t idx = 0;
1202 
1203 	memset(&ptc, 0, sizeof(ps_presentity_t));
1204 
1205 	ptc.user = *user;
1206 	ptc.domain = *domain;
1207 	ptc.hashid = core_case_hash(&ptc.user, &ptc.domain, 0);
1208 	idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
1209 
1210 	lock_get(&_ps_ptable->slots[idx].lock);
1211 	ptn = _ps_ptable->slots[idx].plist;
1212 	while(ptn!=NULL) {
1213 		if(ps_presentity_match(ptn, &ptc, 0)==1) {
1214 			ptd = ps_presentity_dup(ptn, 1);
1215 			if(ptd == NULL) {
1216 				break;
1217 			}
1218 			if(pte==NULL) {
1219 				ptl = ptd;
1220 			} else {
1221 				pte->next = ptd;
1222 				ptd->prev = pte;
1223 			}
1224 			pte = ptd;
1225 		}
1226 		ptn = ptn->next;
1227 	}
1228 	lock_release(&_ps_ptable->slots[idx].lock);
1229 
1230 	if(ptd==NULL && ptl != NULL) {
1231 		ps_presentity_list_free(ptl, 1);
1232 		return NULL;
1233 	}
1234 
1235 	return ptl;
1236 }
1237 
1238 /**
1239  *
1240  */
ps_ptable_search(ps_presentity_t * ptm,int mmode,int rmode)1241 ps_presentity_t *ps_ptable_search(ps_presentity_t *ptm, int mmode, int rmode)
1242 {
1243 	ps_presentity_t *ptn = NULL;
1244 	ps_presentity_t *ptl = NULL;
1245 	ps_presentity_t *ptd = NULL;
1246 	ps_presentity_t *pte = NULL;
1247 	uint32_t idx = 0;
1248 	int pmax = 0;
1249 
1250 	ptm->hashid = core_case_hash(&ptm->user, &ptm->domain, 0);
1251 	idx = core_hash_idx(ptm->hashid, _ps_ptable->ssize);
1252 
1253 	lock_get(&_ps_ptable->slots[idx].lock);
1254 	ptn = _ps_ptable->slots[idx].plist;
1255 	while(ptn!=NULL) {
1256 		if((ps_presentity_match(ptn, ptm, mmode)==1)
1257 				&& (ptm->expires==0 || ptn->expires > ptm->expires)) {
1258 			ptd = ps_presentity_dup(ptn, 1);
1259 			if(ptd == NULL) {
1260 				break;
1261 			}
1262 			if(pte==NULL) {
1263 				ptl = ptd;
1264 			} else {
1265 				pte->next = ptd;
1266 				ptd->prev = pte;
1267 			}
1268 			pte = ptd;
1269 		}
1270 		ptn = ptn->next;
1271 	}
1272 	lock_release(&_ps_ptable->slots[idx].lock);
1273 
1274 	if(ptd==NULL && ptl != NULL) {
1275 		ps_presentity_list_free(ptl, 1);
1276 		return NULL;
1277 	}
1278 
1279 	if(rmode==1) {
1280 		/* order list by priority */
1281 		pte = NULL;
1282 		while(ptl!=NULL) {
1283 			pmax = 0;
1284 			ptn = ptl;
1285 			ptd = ptl;
1286 			while(ptn!=NULL) {
1287 				if(ptn->priority >= pmax) {
1288 					pmax = ptn->priority;
1289 					ptd = ptn;
1290 				}
1291 				ptn = ptn->next;
1292 			}
1293 			if(ptd == ptl) {
1294 				ptl = ptl->next;
1295 				if(ptl) {
1296 					ptl->prev = NULL;
1297 				}
1298 				ptd->next = pte;
1299 				if(pte) {
1300 					pte->prev = ptd;
1301 				}
1302 				pte = ptd;
1303 			} else {
1304 				if(ptd->prev) {
1305 					ptd->prev->next = ptd->next;
1306 				}
1307 				if(ptd->next) {
1308 					ptd->next->prev = ptd->prev;
1309 				}
1310 				ptd->next = pte;
1311 				ptd->prev = NULL;
1312 				if(pte) {
1313 					pte->prev = ptd;
1314 				}
1315 				pte = ptd;
1316 			}
1317 		}
1318 		return pte;
1319 	}
1320 
1321 	/* default ordered by received time */
1322 	return ptl;
1323 }
1324 
1325 /**
1326  *
1327  */
ps_ptable_get_item(str * user,str * domain,str * event,str * etag)1328 ps_presentity_t *ps_ptable_get_item(str *user, str *domain, str *event, str *etag)
1329 {
1330 	ps_presentity_t ptc;
1331 	ps_presentity_t *ptn = NULL;
1332 	ps_presentity_t *ptd = NULL;
1333 	uint32_t idx = 0;
1334 
1335 	memset(&ptc, 0, sizeof(ps_presentity_t));
1336 
1337 	ptc.user = *user;
1338 	ptc.domain = *domain;
1339 	ptc.event = *event;
1340 	ptc.etag = *etag;
1341 	ptc.hashid = core_case_hash(&ptc.user, &ptc.domain, 0);
1342 	idx = core_hash_idx(ptc.hashid, _ps_ptable->ssize);
1343 
1344 	lock_get(&_ps_ptable->slots[idx].lock);
1345 	ptn = _ps_ptable->slots[idx].plist;
1346 	while(ptn!=NULL) {
1347 		if(ps_presentity_match(ptn, &ptc, 2)==1) {
1348 			ptd = ps_presentity_dup(ptn, 1);
1349 			break;
1350 		}
1351 		ptn = ptn->next;
1352 	}
1353 	lock_release(&_ps_ptable->slots[idx].lock);
1354 
1355 	return ptd;
1356 }
1357 
1358 /**
1359  *
1360  */
ps_ptable_get_expired(int eval)1361 ps_presentity_t *ps_ptable_get_expired(int eval)
1362 {
1363 	ps_presentity_t *ptn = NULL;
1364 	ps_presentity_t *ptl = NULL;
1365 	ps_presentity_t *ptd = NULL;
1366 	ps_presentity_t *pte = NULL;
1367 	int i = 0;
1368 
1369 	if(_ps_ptable == NULL) {
1370 		return NULL;
1371 	}
1372 
1373 	for(i=0; i<_ps_ptable->ssize; i++) {
1374 		lock_get(&_ps_ptable->slots[i].lock);
1375 		ptn = _ps_ptable->slots[i].plist;
1376 		while(ptn!=NULL) {
1377 			if(ptn->expires > 0 && ptn->expires <= eval) {
1378 				ptd = ps_presentity_dup(ptn, 1);
1379 				if(ptd == NULL) {
1380 					break;
1381 				}
1382 				if(pte==NULL) {
1383 					ptl = ptd;
1384 				} else {
1385 					pte->next = ptd;
1386 					ptd->prev = pte;
1387 				}
1388 				pte = ptd;
1389 			}
1390 			ptn = ptn->next;
1391 		}
1392 		lock_release(&_ps_ptable->slots[i].lock);
1393 	}
1394 
1395 	if(ptd==NULL && ptl != NULL) {
1396 		ps_presentity_list_free(ptl, 1);
1397 		return NULL;
1398 	}
1399 
1400 	return ptl;
1401 }
1402