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