Merge pull request #1810 from kamailio/grumvalski/siptrace_src_socket
[sip-router] / src / modules / presence / hash.c
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 "../../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"
36 #include "presence.h"
37 #include "hash.h"
38 #include "notify.h"
39
40 /* matching mode when removing subscriptions from memory */
41 extern int pres_subs_remove_match;
42
43 /**
44  * create the subscription hash table in shared memory
45  * - hash_size: number of slots
46  */
47 shtable_t new_shtable(int hash_size)
48 {
49         shtable_t htable = NULL;
50         int i, j;
51
52         i = 0;
53         htable = (subs_entry_t *)shm_malloc(hash_size * sizeof(subs_entry_t));
54         if(htable == NULL) {
55                 ERR_MEM(SHARE_MEM);
56         }
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);
61                         goto error;
62                 }
63                 htable[i].entries = (subs_t *)shm_malloc(sizeof(subs_t));
64                 if(htable[i].entries == NULL) {
65                         lock_destroy(&htable[i].lock);
66                         ERR_MEM(SHARE_MEM);
67                 }
68                 memset(htable[i].entries, 0, sizeof(subs_t));
69                 htable[i].entries->next = NULL;
70         }
71
72         return htable;
73
74 error:
75         if(htable) {
76                 for(j = 0; j < i; j++) {
77                         lock_destroy(&htable[j].lock);
78                         shm_free(htable[j].entries);
79                 }
80                 shm_free(htable);
81         }
82         return NULL;
83 }
84
85 void destroy_shtable(shtable_t htable, int hash_size)
86 {
87         int i;
88
89         if(htable == NULL)
90                 return;
91
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;
97         }
98         shm_free(htable);
99         htable = NULL;
100 }
101
102 subs_t *search_shtable(shtable_t htable, str callid, str to_tag, str from_tag,
103                 unsigned int hash_code)
104 {
105         subs_t *s;
106
107         s = htable[hash_code].entries ? htable[hash_code].entries->next : NULL;
108
109         while(s) {
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)
116                         return s;
117                 s = s->next;
118         }
119
120         return NULL;
121 }
122
123 subs_t *mem_copy_subs(subs_t *s, int mem_type)
124 {
125         int size;
126         subs_t *dest;
127
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)
135                                          * sizeof(char);
136
137         if(mem_type & PKG_MEM_TYPE)
138                 dest = (subs_t *)pkg_malloc(size);
139         else
140                 dest = (subs_t *)shm_malloc(size);
141
142         if(dest == NULL) {
143                 ERR_MEM((mem_type == PKG_MEM_TYPE) ? PKG_MEM_STR : SHARE_MEM);
144         }
145         memset(dest, 0, size);
146         size = sizeof(subs_t);
147
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);
163         if(s->event_id.s)
164                 CONT_COPY(dest, dest->event_id, s->event_id);
165         if(s->reason.s)
166                 CONT_COPY(dest, dest->reason, s->reason);
167
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;
177
178         return dest;
179
180 error:
181         return NULL;
182 }
183
184
185 subs_t *mem_copy_subs_noc(subs_t *s)
186 {
187         int size;
188         subs_t *dest;
189
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)
197                                          * sizeof(char);
198
199         dest = (subs_t *)shm_malloc(size);
200         if(dest == NULL) {
201                 ERR_MEM(SHARE_MEM);
202         }
203         memset(dest, 0, size);
204         size = sizeof(subs_t);
205
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);
219         if(s->event_id.s)
220                 CONT_COPY(dest, dest->event_id, s->event_id);
221         if(s->reason.s)
222                 CONT_COPY(dest, dest->reason, s->reason);
223
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;
233
234         dest->contact.s = (char *)shm_malloc(s->contact.len * sizeof(char));
235         if(dest->contact.s == NULL) {
236                 ERR_MEM(SHARE_MEM);
237         }
238         memcpy(dest->contact.s, s->contact.s, s->contact.len);
239         dest->contact.len = s->contact.len;
240
241         dest->record_route.s =
242                         (char *)shm_malloc((s->record_route.len + 1) * sizeof(char));
243         if(dest->record_route.s == NULL) {
244                 ERR_MEM(SHARE_MEM);
245         }
246         memcpy(dest->record_route.s, s->record_route.s, s->record_route.len);
247         dest->record_route.len = s->record_route.len;
248
249         return dest;
250
251 error:
252         if(dest)
253                 shm_free(dest);
254         return NULL;
255 }
256
257 int insert_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
258 {
259         subs_t *new_rec = NULL;
260
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");
264                 return -1;
265         }
266         new_rec->expires += (int)time(NULL);
267
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);
272
273         return 0;
274 }
275
276 int delete_shtable(shtable_t htable, unsigned int hash_code, subs_t *subs)
277 {
278         subs_t *s = NULL, *ps = NULL;
279         int found = -1;
280
281         lock_get(&htable[hash_code].lock);
282
283         ps = htable[hash_code].entries;
284         s = ps ? ps->next : NULL;
285
286         while(s) {
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)
291                                                            == 0) {
292                                 found = 0;
293                         }
294                 } else {
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)
300                                                            == 0
301                                         && strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)
302                                                            == 0
303                                         && strncmp(s->from_tag.s, subs->from_tag.s,
304                                                            subs->from_tag.len)
305                                                            == 0) {
306                                 found = 0;
307                         }
308                 }
309                 if(found == 0) {
310                         found = s->local_cseq + 1;
311                         ps->next = s->next;
312                         if(s->contact.s != NULL) {
313                                 shm_free(s->contact.s);
314                                 s->contact.s = NULL;
315                         }
316                         if(s->record_route.s != NULL) {
317                                 shm_free(s->record_route.s);
318                                 s->record_route.s = NULL;
319                         }
320                         if(s) {
321                                 shm_free(s);
322                                 s = NULL;
323                         }
324                         break;
325                 }
326                 ps = s;
327                 s = s->next;
328         }
329         lock_release(&htable[hash_code].lock);
330         return found;
331 }
332
333 void free_subs_list(subs_t *s_array, int mem_type, int ic)
334 {
335         subs_t *s;
336
337         while(s_array) {
338                 s = s_array;
339                 s_array = s_array->next;
340                 if(mem_type & PKG_MEM_TYPE) {
341                         if(ic) {
342                                 pkg_free(s->contact.s);
343                                 s->contact.s = NULL;
344                         }
345                         pkg_free(s);
346                         s = NULL;
347                 } else {
348                         if(ic) {
349                                 shm_free(s->contact.s);
350                                 s->contact.s = NULL;
351                         }
352                         shm_free(s);
353                         s = NULL;
354                 }
355         }
356 }
357
358 int update_shtable(
359                 shtable_t htable, unsigned int hash_code, subs_t *subs, int type)
360 {
361         subs_t *s;
362
363         lock_get(&htable[hash_code].lock);
364
365         s = search_shtable(
366                         htable, subs->callid, subs->to_tag, subs->from_tag, hash_code);
367         if(s == NULL) {
368                 LM_DBG("record not found in hash table\n");
369                 lock_release(&htable[hash_code].lock);
370                 return -1;
371         }
372
373         if(type & REMOTE_TYPE) {
374                 s->expires = subs->expires + (int)time(NULL);
375                 s->remote_cseq = subs->remote_cseq;
376         } else {
377                 subs->local_cseq = ++s->local_cseq;
378                 subs->version = ++s->version;
379         }
380
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");
387                         return -1;
388                 }
389                 memcpy(s->contact.s, subs->contact.s, subs->contact.len);
390                 s->contact.len = subs->contact.len;
391         }
392
393         shm_free(s->record_route.s);
394         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");
399                 return -1;
400         }
401         memcpy(s->record_route.s, subs->record_route.s, subs->record_route.len);
402         s->record_route.len = subs->record_route.len;
403
404         s->status = subs->status;
405         s->event = subs->event;
406         subs->db_flag = s->db_flag;
407
408         if(s->db_flag & NO_UPDATEDB_FLAG)
409                 s->db_flag = UPDATEDB_FLAG;
410
411         lock_release(&htable[hash_code].lock);
412
413         return 0;
414 }
415
416 phtable_t *new_phtable(void)
417 {
418         phtable_t *htable = NULL;
419         int i, j;
420
421         i = 0;
422         htable = (phtable_t *)shm_malloc(phtable_size * sizeof(phtable_t));
423         if(htable == NULL) {
424                 ERR_MEM(SHARE_MEM);
425         }
426         memset(htable, 0, phtable_size * sizeof(phtable_t));
427
428         for(i = 0; i < phtable_size; i++) {
429                 if(lock_init(&htable[i].lock) == 0) {
430                         LM_ERR("initializing lock [%d]\n", i);
431                         goto error;
432                 }
433                 htable[i].entries = (pres_entry_t *)shm_malloc(sizeof(pres_entry_t));
434                 if(htable[i].entries == NULL) {
435                         ERR_MEM(SHARE_MEM);
436                 }
437                 memset(htable[i].entries, 0, sizeof(pres_entry_t));
438                 htable[i].entries->next = NULL;
439         }
440
441         return htable;
442
443 error:
444         if(htable) {
445                 for(j = 0; j < i; j++) {
446                         if(htable[i].entries)
447                                 shm_free(htable[i].entries);
448                         else
449                                 break;
450                         lock_destroy(&htable[i].lock);
451                 }
452                 shm_free(htable);
453         }
454         return NULL;
455 }
456
457 void destroy_phtable(void)
458 {
459         int i;
460         pres_entry_t *p, *prev_p;
461
462         if(pres_htable == NULL)
463                 return;
464
465         for(i = 0; i < phtable_size; i++) {
466                 lock_destroy(&pres_htable[i].lock);
467                 p = pres_htable[i].entries;
468                 while(p) {
469                         prev_p = p;
470                         p = p->next;
471                         if(prev_p->sphere)
472                                 shm_free(prev_p->sphere);
473                         shm_free(prev_p);
474                 }
475         }
476         shm_free(pres_htable);
477 }
478 /* entry must be locked before calling this function */
479
480 pres_entry_t *search_phtable(str *pres_uri, int event, unsigned int hash_code)
481 {
482         pres_entry_t *p;
483
484         LM_DBG("pres_uri= %.*s\n", pres_uri->len, pres_uri->s);
485         p = pres_htable[hash_code].entries->next;
486         while(p) {
487                 if(p->event == event && p->pres_uri.len == pres_uri->len
488                                 && presence_sip_uri_match(&p->pres_uri, pres_uri) == 0)
489                         return p;
490                 p = p->next;
491         }
492         return NULL;
493 }
494
495 int insert_phtable(str *pres_uri, int event, char *sphere)
496 {
497         unsigned int hash_code;
498         pres_entry_t *p = NULL;
499         int size;
500
501         hash_code = core_case_hash(pres_uri, NULL, phtable_size);
502
503         lock_get(&pres_htable[hash_code].lock);
504
505         p = search_phtable(pres_uri, event, hash_code);
506         if(p) {
507                 p->publ_count++;
508                 lock_release(&pres_htable[hash_code].lock);
509                 return 0;
510         }
511         size = sizeof(pres_entry_t) + pres_uri->len * sizeof(char);
512
513         p = (pres_entry_t *)shm_malloc(size);
514         if(p == NULL) {
515                 lock_release(&pres_htable[hash_code].lock);
516                 ERR_MEM(SHARE_MEM);
517         }
518         memset(p, 0, size);
519
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;
524
525         if(sphere) {
526                 p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
527                 if(p->sphere == NULL) {
528                         lock_release(&pres_htable[hash_code].lock);
529                         shm_free(p);
530                         ERR_MEM(SHARE_MEM);
531                 }
532                 strcpy(p->sphere, sphere);
533         }
534
535         p->event = event;
536         p->publ_count = 1;
537
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;
541
542         lock_release(&pres_htable[hash_code].lock);
543
544         return 0;
545
546 error:
547         return -1;
548 }
549
550 int delete_phtable(str *pres_uri, int event)
551 {
552         unsigned int hash_code;
553         pres_entry_t *p = NULL, *prev_p = NULL;
554
555         hash_code = core_case_hash(pres_uri, NULL, phtable_size);
556
557         lock_get(&pres_htable[hash_code].lock);
558
559         p = search_phtable(pres_uri, event, hash_code);
560         if(p == NULL) {
561                 LM_DBG("record not found\n");
562                 lock_release(&pres_htable[hash_code].lock);
563                 return 0;
564         }
565
566         p->publ_count--;
567         if(p->publ_count == 0) {
568                 /* delete record */
569                 prev_p = pres_htable[hash_code].entries;
570                 while(prev_p->next) {
571                         if(prev_p->next == p)
572                                 break;
573                         prev_p = prev_p->next;
574                 }
575                 if(prev_p->next == NULL) {
576                         LM_ERR("record not found\n");
577                         lock_release(&pres_htable[hash_code].lock);
578                         return -1;
579                 }
580                 prev_p->next = p->next;
581                 if(p->sphere)
582                         shm_free(p->sphere);
583
584                 shm_free(p);
585         }
586         lock_release(&pres_htable[hash_code].lock);
587
588         return 0;
589 }
590
591 int update_phtable(presentity_t *presentity, str pres_uri, str body)
592 {
593         char *sphere = NULL;
594         unsigned int hash_code;
595         pres_entry_t *p;
596         int ret = 0;
597         str *xcap_doc = NULL;
598
599         /* get new sphere */
600         sphere = extract_sphere(body);
601         if(sphere == NULL) {
602                 LM_DBG("no sphere defined in new body\n");
603                 return 0;
604         }
605
606         /* search for record in hash table */
607         hash_code = core_case_hash(&pres_uri, NULL, phtable_size);
608
609         lock_get(&pres_htable[hash_code].lock);
610
611         p = search_phtable(&pres_uri, presentity->event->evp->type, hash_code);
612         if(p == NULL) {
613                 lock_release(&pres_htable[hash_code].lock);
614                 goto done;
615         }
616
617         if(p->sphere) {
618                 if(strcmp(p->sphere, sphere) != 0) {
619                         /* new sphere definition */
620                         shm_free(p->sphere);
621                 } else {
622                         /* no change in sphere definition */
623                         lock_release(&pres_htable[hash_code].lock);
624                         pkg_free(sphere);
625                         return 0;
626                 }
627         }
628
629
630         p->sphere = (char *)shm_malloc((strlen(sphere) + 1) * sizeof(char));
631         if(p->sphere == NULL) {
632                 lock_release(&pres_htable[hash_code].lock);
633                 ret = -1;
634                 goto done;
635         }
636         strcpy(p->sphere, sphere);
637
638         lock_release(&pres_htable[hash_code].lock);
639
640         /* call for watchers status update */
641
642         if(presentity->event->get_rules_doc(
643                            &presentity->user, &presentity->domain, &xcap_doc)
644                         < 0) {
645                 LM_ERR("failed to retrieve xcap document\n");
646                 ret = -1;
647                 goto done;
648         }
649
650         update_watchers_status(pres_uri, presentity->event, xcap_doc);
651
652
653 done:
654
655         if(xcap_doc) {
656                 if(xcap_doc->s)
657                         pkg_free(xcap_doc->s);
658                 pkg_free(xcap_doc);
659         }
660
661         if(sphere)
662                 pkg_free(sphere);
663         return ret;
664 }