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;
280 if (subs_dbmode != NO_DB)
281 delete_db_subs(&rec->to_tag, &rec->from_tag, &rec->callid);
283 if (rec->contact.s!=NULL)
284 shm_free(rec->contact.s);
292 lock_release(&htable[hash_code].lock);
295 new_rec = mem_copy_subs_noc(subs);
296 if(new_rec == NULL) {
297 LM_ERR("copying in share memory a subs_t structure\n");
300 new_rec->expires += (int)time(NULL);
302 lock_get(&htable[hash_code].lock);
303 new_rec->next = htable[hash_code].entries->next;
304 htable[hash_code].entries->next = new_rec;
305 lock_release(&htable[hash_code].lock);
310 int delete_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
312 subs_t *s = NULL, *ps = NULL;
315 lock_get(&htable[hash_code].lock);
317 ps = htable[hash_code].entries;
318 s = ps ? ps->next : NULL;
321 if(pres_subs_remove_match == 0) {
322 /* match on to-tag only (unique, local generated - faster) */
323 if(s->to_tag.len == subs->to_tag.len
324 && strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
329 /* match on all dialog attributes (distributed systems) */
330 if(s->callid.len == subs->callid.len
331 && s->to_tag.len == subs->to_tag.len
332 && s->from_tag.len == subs->from_tag.len
333 && strncmp(s->callid.s, subs->callid.s, subs->callid.len)
335 && strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
337 && strncmp(s->from_tag.s, subs->from_tag.s,
344 found = s->local_cseq + 1;
346 if(s->contact.s != NULL) {
347 shm_free(s->contact.s);
350 if(s->record_route.s != NULL) {
351 shm_free(s->record_route.s);
352 s->record_route.s = NULL;
363 lock_release(&htable[hash_code].lock);
367 void free_subs_list(subs_t *s_array, int mem_type, int ic)
373 s_array = s_array->next;
374 if(mem_type & PKG_MEM_TYPE) {
376 pkg_free(s->contact.s);
383 shm_free(s->contact.s);
393 shtable_t htable, unsigned int hash_code, subs_t *subs, int type)
397 lock_get(&htable[hash_code].lock);
400 htable, subs->callid, subs->to_tag, subs->from_tag, hash_code);
402 LM_DBG("record not found in hash table\n");
403 lock_release(&htable[hash_code].lock);
407 if(type & REMOTE_TYPE) {
408 s->expires = subs->expires + (int)time(NULL);
409 s->remote_cseq = subs->remote_cseq;
411 subs->local_cseq = ++s->local_cseq;
412 subs->version = ++s->version;
415 if(presence_sip_uri_match(&s->contact, &subs->contact)) {
416 shm_free(s->contact.s);
417 s->contact.s = (char *)shm_malloc(subs->contact.len * sizeof(char));
418 if(s->contact.s == NULL) {
419 lock_release(&htable[hash_code].lock);
420 LM_ERR("no more shared memory\n");
423 memcpy(s->contact.s, subs->contact.s, subs->contact.len);
424 s->contact.len = subs->contact.len;
427 shm_free(s->record_route.s);
429 (char *)shm_malloc(subs->record_route.len * sizeof(char));
430 if(s->record_route.s == NULL) {
431 lock_release(&htable[hash_code].lock);
432 LM_ERR("no more shared memory\n");
435 memcpy(s->record_route.s, subs->record_route.s, subs->record_route.len);
436 s->record_route.len = subs->record_route.len;
438 s->status = subs->status;
439 s->event = subs->event;
440 subs->db_flag = s->db_flag;
442 if(s->db_flag & NO_UPDATEDB_FLAG)
443 s->db_flag = UPDATEDB_FLAG;
445 lock_release(&htable[hash_code].lock);
450 phtable_t *new_phtable(void)
452 phtable_t *htable = NULL;
456 htable = (phtable_t *)shm_malloc(phtable_size * sizeof(phtable_t));
460 memset(htable, 0, phtable_size * sizeof(phtable_t));
462 for(i = 0; i < phtable_size; i++) {
463 if(lock_init(&htable[i].lock) == 0) {
464 LM_ERR("initializing lock [%d]\n", i);
467 htable[i].entries = (pres_entry_t *)shm_malloc(sizeof(pres_entry_t));
468 if(htable[i].entries == NULL) {
471 memset(htable[i].entries, 0, sizeof(pres_entry_t));
472 htable[i].entries->next = NULL;
479 for(j = 0; j < i; j++) {
480 if(htable[i].entries)
481 shm_free(htable[i].entries);
484 lock_destroy(&htable[i].lock);
491 void destroy_phtable(void)
494 pres_entry_t *p, *prev_p;
496 if(pres_htable == NULL)
499 for(i = 0; i < phtable_size; i++) {
500 lock_destroy(&pres_htable[i].lock);
501 p = pres_htable[i].entries;
506 shm_free(prev_p->sphere);
510 shm_free(pres_htable);
512 /* entry must be locked before calling this function */
514 pres_entry_t *search_phtable(str *pres_uri, int event, unsigned int hash_code)
518 LM_DBG("pres_uri= %.*s\n", pres_uri->len, pres_uri->s);
519 p = pres_htable[hash_code].entries->next;
521 if(p->event == event && p->pres_uri.len == pres_uri->len
522 && presence_sip_uri_match(&p->pres_uri, pres_uri) == 0)
529 int insert_phtable(str *pres_uri, int event, char *sphere)
531 unsigned int hash_code;
532 pres_entry_t *p = NULL;
535 hash_code = core_case_hash(pres_uri, NULL, phtable_size);
537 lock_get(&pres_htable[hash_code].lock);
539 p = search_phtable(pres_uri, event, hash_code);
542 lock_release(&pres_htable[hash_code].lock);
545 size = sizeof(pres_entry_t) + pres_uri->len * sizeof(char);
547 p = (pres_entry_t *)shm_malloc(size);
549 lock_release(&pres_htable[hash_code].lock);
554 size = sizeof(pres_entry_t);
555 p->pres_uri.s = (char *)p + size;
556 memcpy(p->pres_uri.s, pres_uri->s, pres_uri->len);
557 p->pres_uri.len = pres_uri->len;
560 p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
561 if(p->sphere == NULL) {
562 lock_release(&pres_htable[hash_code].lock);
566 strcpy(p->sphere, sphere);
572 /* link the item in the hash table */
573 p->next = pres_htable[hash_code].entries->next;
574 pres_htable[hash_code].entries->next = p;
576 lock_release(&pres_htable[hash_code].lock);
584 int delete_phtable(str *pres_uri, int event)
586 unsigned int hash_code;
587 pres_entry_t *p = NULL, *prev_p = NULL;
589 hash_code = core_case_hash(pres_uri, NULL, phtable_size);
591 lock_get(&pres_htable[hash_code].lock);
593 p = search_phtable(pres_uri, event, hash_code);
595 LM_DBG("record not found\n");
596 lock_release(&pres_htable[hash_code].lock);
601 if(p->publ_count == 0) {
603 prev_p = pres_htable[hash_code].entries;
604 while(prev_p->next) {
605 if(prev_p->next == p)
607 prev_p = prev_p->next;
609 if(prev_p->next == NULL) {
610 LM_ERR("record not found\n");
611 lock_release(&pres_htable[hash_code].lock);
614 prev_p->next = p->next;
620 lock_release(&pres_htable[hash_code].lock);
625 int update_phtable(presentity_t *presentity, str pres_uri, str body)
628 unsigned int hash_code;
631 str *xcap_doc = NULL;
634 sphere = extract_sphere(body);
636 LM_DBG("no sphere defined in new body\n");
640 /* search for record in hash table */
641 hash_code = core_case_hash(&pres_uri, NULL, phtable_size);
643 lock_get(&pres_htable[hash_code].lock);
645 p = search_phtable(&pres_uri, presentity->event->evp->type, hash_code);
647 lock_release(&pres_htable[hash_code].lock);
652 if(strcmp(p->sphere, sphere) != 0) {
653 /* new sphere definition */
656 /* no change in sphere definition */
657 lock_release(&pres_htable[hash_code].lock);
664 p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
665 if(p->sphere == NULL) {
666 lock_release(&pres_htable[hash_code].lock);
670 strcpy(p->sphere, sphere);
672 lock_release(&pres_htable[hash_code].lock);
674 /* call for watchers status update */
676 if(presentity->event->get_rules_doc(
677 &presentity->user, &presentity->domain, &xcap_doc)
679 LM_ERR("failed to retrieve xcap document\n");
684 update_watchers_status(pres_uri, presentity->event, xcap_doc);
691 pkg_free(xcap_doc->s);