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 new_rec = mem_copy_subs_noc(subs);
262 if(new_rec == NULL) {
263 LM_ERR("copying in share memory a subs_t structure\n");
266 new_rec->expires += (int)time(NULL);
268 lock_get(&htable[hash_code].lock);
269 new_rec->next = htable[hash_code].entries->next;
270 htable[hash_code].entries->next = new_rec;
271 lock_release(&htable[hash_code].lock);
276 int delete_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
278 subs_t *s = NULL, *ps = NULL;
281 lock_get(&htable[hash_code].lock);
283 ps = htable[hash_code].entries;
284 s = ps ? ps->next : NULL;
287 if(pres_subs_remove_match == 0) {
288 /* match on to-tag only (unique, local generated - faster) */
289 if(s->to_tag.len == subs->to_tag.len
290 && strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
295 /* match on all dialog attributes (distributed systems) */
296 if(s->callid.len == subs->callid.len
297 && s->to_tag.len == subs->to_tag.len
298 && s->from_tag.len == subs->from_tag.len
299 && strncmp(s->callid.s, subs->callid.s, subs->callid.len)
301 && strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
303 && strncmp(s->from_tag.s, subs->from_tag.s,
310 found = s->local_cseq + 1;
312 if(s->contact.s != NULL) {
313 shm_free(s->contact.s);
316 if(s->record_route.s != NULL) {
317 shm_free(s->record_route.s);
318 s->record_route.s = NULL;
329 lock_release(&htable[hash_code].lock);
333 void free_subs_list(subs_t *s_array, int mem_type, int ic)
339 s_array = s_array->next;
340 if(mem_type & PKG_MEM_TYPE) {
342 pkg_free(s->contact.s);
349 shm_free(s->contact.s);
359 shtable_t htable, unsigned int hash_code, subs_t *subs, int type)
363 lock_get(&htable[hash_code].lock);
366 htable, subs->callid, subs->to_tag, subs->from_tag, hash_code);
368 LM_DBG("record not found in hash table\n");
369 lock_release(&htable[hash_code].lock);
373 if(type & REMOTE_TYPE) {
374 s->expires = subs->expires + (int)time(NULL);
375 s->remote_cseq = subs->remote_cseq;
377 subs->local_cseq = ++s->local_cseq;
378 subs->version = ++s->version;
381 if(presence_sip_uri_match(&s->contact, &subs->contact)) {
382 shm_free(s->contact.s);
383 s->contact.s = (char *)shm_malloc(subs->contact.len * sizeof(char));
384 if(s->contact.s == NULL) {
385 lock_release(&htable[hash_code].lock);
386 LM_ERR("no more shared memory\n");
389 memcpy(s->contact.s, subs->contact.s, subs->contact.len);
390 s->contact.len = subs->contact.len;
393 shm_free(s->record_route.s);
395 (char *)shm_malloc(subs->record_route.len * sizeof(char));
396 if(s->record_route.s == NULL) {
397 lock_release(&htable[hash_code].lock);
398 LM_ERR("no more shared memory\n");
401 memcpy(s->record_route.s, subs->record_route.s, subs->record_route.len);
402 s->record_route.len = subs->record_route.len;
404 s->status = subs->status;
405 s->event = subs->event;
406 subs->db_flag = s->db_flag;
408 if(s->db_flag & NO_UPDATEDB_FLAG)
409 s->db_flag = UPDATEDB_FLAG;
411 lock_release(&htable[hash_code].lock);
416 phtable_t *new_phtable(void)
418 phtable_t *htable = NULL;
422 htable = (phtable_t *)shm_malloc(phtable_size * sizeof(phtable_t));
426 memset(htable, 0, phtable_size * sizeof(phtable_t));
428 for(i = 0; i < phtable_size; i++) {
429 if(lock_init(&htable[i].lock) == 0) {
430 LM_ERR("initializing lock [%d]\n", i);
433 htable[i].entries = (pres_entry_t *)shm_malloc(sizeof(pres_entry_t));
434 if(htable[i].entries == NULL) {
437 memset(htable[i].entries, 0, sizeof(pres_entry_t));
438 htable[i].entries->next = NULL;
445 for(j = 0; j < i; j++) {
446 if(htable[i].entries)
447 shm_free(htable[i].entries);
450 lock_destroy(&htable[i].lock);
457 void destroy_phtable(void)
460 pres_entry_t *p, *prev_p;
462 if(pres_htable == NULL)
465 for(i = 0; i < phtable_size; i++) {
466 lock_destroy(&pres_htable[i].lock);
467 p = pres_htable[i].entries;
472 shm_free(prev_p->sphere);
476 shm_free(pres_htable);
478 /* entry must be locked before calling this function */
480 pres_entry_t *search_phtable(str *pres_uri, int event, unsigned int hash_code)
484 LM_DBG("pres_uri= %.*s\n", pres_uri->len, pres_uri->s);
485 p = pres_htable[hash_code].entries->next;
487 if(p->event == event && p->pres_uri.len == pres_uri->len
488 && presence_sip_uri_match(&p->pres_uri, pres_uri) == 0)
495 int insert_phtable(str *pres_uri, int event, char *sphere)
497 unsigned int hash_code;
498 pres_entry_t *p = NULL;
501 hash_code = core_case_hash(pres_uri, NULL, phtable_size);
503 lock_get(&pres_htable[hash_code].lock);
505 p = search_phtable(pres_uri, event, hash_code);
508 lock_release(&pres_htable[hash_code].lock);
511 size = sizeof(pres_entry_t) + pres_uri->len * sizeof(char);
513 p = (pres_entry_t *)shm_malloc(size);
515 lock_release(&pres_htable[hash_code].lock);
520 size = sizeof(pres_entry_t);
521 p->pres_uri.s = (char *)p + size;
522 memcpy(p->pres_uri.s, pres_uri->s, pres_uri->len);
523 p->pres_uri.len = pres_uri->len;
526 p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
527 if(p->sphere == NULL) {
528 lock_release(&pres_htable[hash_code].lock);
532 strcpy(p->sphere, sphere);
538 /* link the item in the hash table */
539 p->next = pres_htable[hash_code].entries->next;
540 pres_htable[hash_code].entries->next = p;
542 lock_release(&pres_htable[hash_code].lock);
550 int delete_phtable(str *pres_uri, int event)
552 unsigned int hash_code;
553 pres_entry_t *p = NULL, *prev_p = NULL;
555 hash_code = core_case_hash(pres_uri, NULL, phtable_size);
557 lock_get(&pres_htable[hash_code].lock);
559 p = search_phtable(pres_uri, event, hash_code);
561 LM_DBG("record not found\n");
562 lock_release(&pres_htable[hash_code].lock);
567 if(p->publ_count == 0) {
569 prev_p = pres_htable[hash_code].entries;
570 while(prev_p->next) {
571 if(prev_p->next == p)
573 prev_p = prev_p->next;
575 if(prev_p->next == NULL) {
576 LM_ERR("record not found\n");
577 lock_release(&pres_htable[hash_code].lock);
580 prev_p->next = p->next;
586 lock_release(&pres_htable[hash_code].lock);
591 int update_phtable(presentity_t *presentity, str pres_uri, str body)
594 unsigned int hash_code;
597 str *xcap_doc = NULL;
600 sphere = extract_sphere(body);
602 LM_DBG("no sphere defined in new body\n");
606 /* search for record in hash table */
607 hash_code = core_case_hash(&pres_uri, NULL, phtable_size);
609 lock_get(&pres_htable[hash_code].lock);
611 p = search_phtable(&pres_uri, presentity->event->evp->type, hash_code);
613 lock_release(&pres_htable[hash_code].lock);
618 if(strcmp(p->sphere, sphere) != 0) {
619 /* new sphere definition */
622 /* no change in sphere definition */
623 lock_release(&pres_htable[hash_code].lock);
630 p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
631 if(p->sphere == NULL) {
632 lock_release(&pres_htable[hash_code].lock);
636 strcpy(p->sphere, sphere);
638 lock_release(&pres_htable[hash_code].lock);
640 /* call for watchers status update */
642 if(presentity->event->get_rules_doc(
643 &presentity->user, &presentity->domain, &xcap_doc)
645 LM_ERR("failed to retrieve xcap document\n");
650 update_watchers_status(pres_uri, presentity->event, xcap_doc);
657 pkg_free(xcap_doc->s);