2 * presence module - presence server implementation
4 * Copyright (C) 2007 Voice Sistem S.R.L.
6 * This file is part of Kamailio, a free SIP server.
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
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.
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
25 * \brief Kamailio presence module
31 #include "../../core/mem/shm_mem.h"
32 #include "../../core/hashes.h"
33 #include "../../core/dprint.h"
34 #include "../../core/str.h"
35 #include "../pua/hash.h"
40 /* matching mode when removing subscriptions from memory */
41 extern int pres_subs_remove_match;
44 * create the subscription hash table in shared memory
45 * - hash_size: number of slots
47 shtable_t new_shtable(int hash_size)
49 shtable_t htable = NULL;
53 htable = (subs_entry_t *)shm_malloc(hash_size * sizeof(subs_entry_t));
57 memset(htable, 0, hash_size * sizeof(subs_entry_t));
58 for(i = 0; i < hash_size; i++) {
59 if(lock_init(&htable[i].lock) == 0) {
60 LM_ERR("initializing lock [%d]\n", i);
63 htable[i].entries = (subs_t *)shm_malloc(sizeof(subs_t));
64 if(htable[i].entries == NULL) {
65 lock_destroy(&htable[i].lock);
68 memset(htable[i].entries, 0, sizeof(subs_t));
69 htable[i].entries->next = NULL;
76 for(j = 0; j < i; j++) {
77 lock_destroy(&htable[j].lock);
78 shm_free(htable[j].entries);
85 void destroy_shtable(shtable_t htable, int hash_size)
92 for(i = 0; i < hash_size; i++) {
93 lock_destroy(&htable[i].lock);
94 free_subs_list(htable[i].entries->next, SHM_MEM_TYPE, 1);
95 shm_free(htable[i].entries);
96 htable[i].entries = NULL;
102 subs_t *search_shtable(shtable_t htable, str callid, str to_tag, str from_tag,
103 unsigned int hash_code)
107 s = htable[hash_code].entries ? htable[hash_code].entries->next : NULL;
110 if(s->callid.len == callid.len
111 && strncmp(s->callid.s, callid.s, callid.len) == 0
112 && s->to_tag.len == to_tag.len
113 && strncmp(s->to_tag.s, to_tag.s, to_tag.len) == 0
114 && s->from_tag.len == from_tag.len
115 && strncmp(s->from_tag.s, from_tag.s, from_tag.len) == 0)
123 subs_t *mem_copy_subs(subs_t *s, int mem_type)
128 size = sizeof(subs_t)
129 + (s->pres_uri.len + s->to_user.len + s->to_domain.len
130 + s->from_user.len + s->from_domain.len + s->callid.len
131 + s->to_tag.len + s->from_tag.len + s->sockinfo_str.len
132 + s->event_id.len + s->local_contact.len + s->contact.len
133 + s->record_route.len + s->reason.len + s->watcher_user.len
134 + s->watcher_domain.len + s->user_agent.len + 1)
137 if(mem_type & PKG_MEM_TYPE)
138 dest = (subs_t *)pkg_malloc(size);
140 dest = (subs_t *)shm_malloc(size);
143 ERR_MEM((mem_type == PKG_MEM_TYPE) ? PKG_MEM_STR : SHARE_MEM);
145 memset(dest, 0, size);
146 size = sizeof(subs_t);
148 CONT_COPY(dest, dest->pres_uri, s->pres_uri);
149 CONT_COPY(dest, dest->to_user, s->to_user);
150 CONT_COPY(dest, dest->to_domain, s->to_domain);
151 CONT_COPY(dest, dest->from_user, s->from_user);
152 CONT_COPY(dest, dest->from_domain, s->from_domain);
153 CONT_COPY(dest, dest->watcher_user, s->watcher_user);
154 CONT_COPY(dest, dest->watcher_domain, s->watcher_domain);
155 CONT_COPY(dest, dest->to_tag, s->to_tag);
156 CONT_COPY(dest, dest->from_tag, s->from_tag);
157 CONT_COPY(dest, dest->callid, s->callid);
158 CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str);
159 CONT_COPY(dest, dest->local_contact, s->local_contact);
160 CONT_COPY(dest, dest->contact, s->contact);
161 CONT_COPY(dest, dest->record_route, s->record_route);
162 CONT_COPY(dest, dest->user_agent, s->user_agent);
164 CONT_COPY(dest, dest->event_id, s->event_id);
166 CONT_COPY(dest, dest->reason, s->reason);
168 dest->event = s->event;
169 dest->local_cseq = s->local_cseq;
170 dest->remote_cseq = s->remote_cseq;
171 dest->status = s->status;
172 dest->version = s->version;
173 dest->send_on_cback = s->send_on_cback;
174 dest->expires = s->expires;
175 dest->db_flag = s->db_flag;
176 dest->flags = s->flags;
185 subs_t *mem_copy_subs_noc(subs_t *s)
190 size = sizeof(subs_t)
191 + (s->pres_uri.len + s->to_user.len + s->to_domain.len
192 + s->from_user.len + s->from_domain.len + s->callid.len
193 + s->to_tag.len + s->from_tag.len + s->sockinfo_str.len
194 + s->event_id.len + s->local_contact.len + s->reason.len
195 + s->watcher_user.len + s->watcher_domain.len
196 + s->user_agent.len + 1)
199 dest = (subs_t *)shm_malloc(size);
203 memset(dest, 0, size);
204 size = sizeof(subs_t);
206 CONT_COPY(dest, dest->pres_uri, s->pres_uri);
207 CONT_COPY(dest, dest->to_user, s->to_user);
208 CONT_COPY(dest, dest->to_domain, s->to_domain);
209 CONT_COPY(dest, dest->from_user, s->from_user);
210 CONT_COPY(dest, dest->from_domain, s->from_domain);
211 CONT_COPY(dest, dest->watcher_user, s->watcher_user);
212 CONT_COPY(dest, dest->watcher_domain, s->watcher_domain);
213 CONT_COPY(dest, dest->to_tag, s->to_tag);
214 CONT_COPY(dest, dest->from_tag, s->from_tag);
215 CONT_COPY(dest, dest->callid, s->callid);
216 CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str);
217 CONT_COPY(dest, dest->local_contact, s->local_contact);
218 CONT_COPY(dest, dest->user_agent, s->user_agent);
220 CONT_COPY(dest, dest->event_id, s->event_id);
222 CONT_COPY(dest, dest->reason, s->reason);
224 dest->event = s->event;
225 dest->local_cseq = s->local_cseq;
226 dest->remote_cseq = s->remote_cseq;
227 dest->status = s->status;
228 dest->version = s->version;
229 dest->send_on_cback = s->send_on_cback;
230 dest->expires = s->expires;
231 dest->db_flag = s->db_flag;
232 dest->flags = s->flags;
234 dest->contact.s = (char *)shm_malloc(s->contact.len * sizeof(char));
235 if(dest->contact.s == NULL) {
238 memcpy(dest->contact.s, s->contact.s, s->contact.len);
239 dest->contact.len = s->contact.len;
241 dest->record_route.s =
242 (char *)shm_malloc((s->record_route.len + 1) * sizeof(char));
243 if(dest->record_route.s == NULL) {
246 memcpy(dest->record_route.s, s->record_route.s, s->record_route.len);
247 dest->record_route.len = s->record_route.len;
257 int insert_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
259 subs_t *new_rec = NULL;
261 if (pres_delete_same_subs) {
262 subs_t* rec = NULL, *prev_rec = NULL;
264 lock_get(&htable[hash_code].lock);
265 /* search if there is another record with the same pres_uri & callid */
266 rec = htable[hash_code].entries->next;
268 if (subs->pres_uri.len == rec->pres_uri.len && subs->callid.len == rec->callid.len &&
269 memcmp(subs->pres_uri.s, rec->pres_uri.s, subs->pres_uri.len) == 0 &&
270 memcmp(subs->callid.s, rec->callid.s, subs->callid.len) == 0) {
271 LM_NOTICE("Found another record with the same pres_uri[%.*s] and callid[%.*s]\n",
272 subs->pres_uri.len, subs->pres_uri.s, subs->callid.len, subs->callid.s);
273 /* delete this record */
276 prev_rec->next = rec->next;
278 htable[hash_code].entries->next = rec->next;
281 if (pres_subs_dbmode != NO_DB) {
282 delete_db_subs(&rec->to_tag, &rec->from_tag, &rec->callid);
285 if (rec->contact.s!=NULL) {
286 shm_free(rec->contact.s);
295 lock_release(&htable[hash_code].lock);
298 new_rec = mem_copy_subs_noc(subs);
299 if(new_rec == NULL) {
300 LM_ERR("copying in share memory a subs_t structure\n");
303 new_rec->expires += (int)time(NULL);
305 lock_get(&htable[hash_code].lock);
306 new_rec->next = htable[hash_code].entries->next;
307 htable[hash_code].entries->next = new_rec;
308 lock_release(&htable[hash_code].lock);
313 int delete_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
315 subs_t *s = NULL, *ps = NULL;
318 lock_get(&htable[hash_code].lock);
320 ps = htable[hash_code].entries;
321 s = ps ? ps->next : NULL;
324 if(pres_subs_remove_match == 0) {
325 /* match on to-tag only (unique, local generated - faster) */
326 if(s->to_tag.len == subs->to_tag.len
327 && strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
332 /* match on all dialog attributes (distributed systems) */
333 if(s->callid.len == subs->callid.len
334 && s->to_tag.len == subs->to_tag.len
335 && s->from_tag.len == subs->from_tag.len
336 && strncmp(s->callid.s, subs->callid.s, subs->callid.len)
338 && strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
340 && strncmp(s->from_tag.s, subs->from_tag.s,
347 found = s->local_cseq + 1;
349 if(s->contact.s != NULL) {
350 shm_free(s->contact.s);
353 if(s->record_route.s != NULL) {
354 shm_free(s->record_route.s);
355 s->record_route.s = NULL;
366 lock_release(&htable[hash_code].lock);
370 void free_subs_list(subs_t *s_array, int mem_type, int ic)
376 s_array = s_array->next;
377 if(mem_type & PKG_MEM_TYPE) {
379 pkg_free(s->contact.s);
386 shm_free(s->contact.s);
396 shtable_t htable, unsigned int hash_code, subs_t *subs, int type)
400 lock_get(&htable[hash_code].lock);
403 htable, subs->callid, subs->to_tag, subs->from_tag, hash_code);
405 LM_DBG("record not found in hash table\n");
406 lock_release(&htable[hash_code].lock);
410 if(type & REMOTE_TYPE) {
411 s->expires = subs->expires + (int)time(NULL);
412 s->remote_cseq = subs->remote_cseq;
414 subs->local_cseq = ++s->local_cseq;
415 subs->version = ++s->version;
418 if(presence_sip_uri_match(&s->contact, &subs->contact)) {
419 shm_free(s->contact.s);
420 s->contact.s = (char *)shm_malloc(subs->contact.len * sizeof(char));
421 if(s->contact.s == NULL) {
422 lock_release(&htable[hash_code].lock);
423 LM_ERR("no more shared memory\n");
426 memcpy(s->contact.s, subs->contact.s, subs->contact.len);
427 s->contact.len = subs->contact.len;
430 shm_free(s->record_route.s);
432 (char *)shm_malloc(subs->record_route.len * sizeof(char));
433 if(s->record_route.s == NULL) {
434 lock_release(&htable[hash_code].lock);
435 LM_ERR("no more shared memory\n");
438 memcpy(s->record_route.s, subs->record_route.s, subs->record_route.len);
439 s->record_route.len = subs->record_route.len;
441 s->status = subs->status;
442 s->event = subs->event;
443 subs->db_flag = s->db_flag;
445 if(s->db_flag & NO_UPDATEDB_FLAG)
446 s->db_flag = UPDATEDB_FLAG;
448 lock_release(&htable[hash_code].lock);
453 phtable_t *new_phtable(void)
455 phtable_t *htable = NULL;
459 htable = (phtable_t *)shm_malloc(phtable_size * sizeof(phtable_t));
463 memset(htable, 0, phtable_size * sizeof(phtable_t));
465 for(i = 0; i < phtable_size; i++) {
466 if(lock_init(&htable[i].lock) == 0) {
467 LM_ERR("initializing lock [%d]\n", i);
470 htable[i].entries = (pres_entry_t *)shm_malloc(sizeof(pres_entry_t));
471 if(htable[i].entries == NULL) {
474 memset(htable[i].entries, 0, sizeof(pres_entry_t));
475 htable[i].entries->next = NULL;
482 for(j = 0; j < i; j++) {
483 if(htable[i].entries)
484 shm_free(htable[i].entries);
487 lock_destroy(&htable[i].lock);
494 void destroy_phtable(void)
497 pres_entry_t *p, *prev_p;
499 if(pres_htable == NULL)
502 for(i = 0; i < phtable_size; i++) {
503 lock_destroy(&pres_htable[i].lock);
504 p = pres_htable[i].entries;
509 shm_free(prev_p->sphere);
513 shm_free(pres_htable);
515 /* entry must be locked before calling this function */
517 pres_entry_t *search_phtable(str *pres_uri, int event, unsigned int hash_code)
521 LM_DBG("pres_uri= %.*s\n", pres_uri->len, pres_uri->s);
522 p = pres_htable[hash_code].entries->next;
524 if(p->event == event && p->pres_uri.len == pres_uri->len
525 && presence_sip_uri_match(&p->pres_uri, pres_uri) == 0)
532 int insert_phtable(str *pres_uri, int event, char *sphere)
534 unsigned int hash_code;
535 pres_entry_t *p = NULL;
538 hash_code = core_case_hash(pres_uri, NULL, phtable_size);
540 lock_get(&pres_htable[hash_code].lock);
542 p = search_phtable(pres_uri, event, hash_code);
545 lock_release(&pres_htable[hash_code].lock);
548 size = sizeof(pres_entry_t) + pres_uri->len * sizeof(char);
550 p = (pres_entry_t *)shm_malloc(size);
552 lock_release(&pres_htable[hash_code].lock);
557 size = sizeof(pres_entry_t);
558 p->pres_uri.s = (char *)p + size;
559 memcpy(p->pres_uri.s, pres_uri->s, pres_uri->len);
560 p->pres_uri.len = pres_uri->len;
563 p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
564 if(p->sphere == NULL) {
565 lock_release(&pres_htable[hash_code].lock);
569 strcpy(p->sphere, sphere);
575 /* link the item in the hash table */
576 p->next = pres_htable[hash_code].entries->next;
577 pres_htable[hash_code].entries->next = p;
579 lock_release(&pres_htable[hash_code].lock);
587 int delete_phtable(str *pres_uri, int event)
589 unsigned int hash_code;
590 pres_entry_t *p = NULL, *prev_p = NULL;
592 hash_code = core_case_hash(pres_uri, NULL, phtable_size);
594 lock_get(&pres_htable[hash_code].lock);
596 p = search_phtable(pres_uri, event, hash_code);
598 LM_DBG("record not found\n");
599 lock_release(&pres_htable[hash_code].lock);
604 if(p->publ_count == 0) {
606 prev_p = pres_htable[hash_code].entries;
607 while(prev_p->next) {
608 if(prev_p->next == p)
610 prev_p = prev_p->next;
612 if(prev_p->next == NULL) {
613 LM_ERR("record not found\n");
614 lock_release(&pres_htable[hash_code].lock);
617 prev_p->next = p->next;
623 lock_release(&pres_htable[hash_code].lock);
628 int update_phtable(presentity_t *presentity, str pres_uri, str body)
631 unsigned int hash_code;
634 str *xcap_doc = NULL;
637 sphere = extract_sphere(body);
639 LM_DBG("no sphere defined in new body\n");
643 /* search for record in hash table */
644 hash_code = core_case_hash(&pres_uri, NULL, phtable_size);
646 lock_get(&pres_htable[hash_code].lock);
648 p = search_phtable(&pres_uri, presentity->event->evp->type, hash_code);
650 lock_release(&pres_htable[hash_code].lock);
655 if(strcmp(p->sphere, sphere) != 0) {
656 /* new sphere definition */
659 /* no change in sphere definition */
660 lock_release(&pres_htable[hash_code].lock);
667 p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
668 if(p->sphere == NULL) {
669 lock_release(&pres_htable[hash_code].lock);
673 strcpy(p->sphere, sphere);
675 lock_release(&pres_htable[hash_code].lock);
677 /* call for watchers status update */
679 if(presentity->event->get_rules_doc(
680 &presentity->user, &presentity->domain, &xcap_doc)
682 LM_ERR("failed to retrieve xcap document\n");
687 update_watchers_status(pres_uri, presentity->event, xcap_doc);
694 pkg_free(xcap_doc->s);