presence: extra columns updated for dbmode 2
[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         {
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         {
61                 if(lock_init(&htable[i].lock)== 0)
62                 {
63                         LM_ERR("initializing lock [%d]\n", i);
64                         goto error;
65                 }
66                 htable[i].entries= (subs_t*)shm_malloc(sizeof(subs_t));
67                 if(htable[i].entries== NULL)
68                 {
69                         lock_destroy(&htable[i].lock);
70                         ERR_MEM(SHARE_MEM);
71                 }
72                 memset(htable[i].entries, 0, sizeof(subs_t));
73                 htable[i].entries->next= NULL;
74         }
75
76         return htable;
77
78 error:
79         if(htable)
80         {
81                 for(j=0; j< i; j++)
82                 {
83                         lock_destroy(&htable[j].lock);
84                         shm_free(htable[j].entries);
85                 }
86                 shm_free(htable);
87         }
88         return NULL;
89
90 }
91
92 void destroy_shtable(shtable_t htable, int hash_size)
93 {
94         int i;
95
96         if(htable== NULL)
97                 return;
98
99         for(i= 0; i< hash_size; i++)
100         {
101                 lock_destroy(&htable[i].lock);
102                 free_subs_list(htable[i].entries->next, SHM_MEM_TYPE, 1);
103                 shm_free(htable[i].entries);
104                 htable[i].entries = NULL;
105         }
106         shm_free(htable);
107         htable= NULL;
108 }
109
110 subs_t* search_shtable(shtable_t htable,str callid,str to_tag,
111                 str from_tag,unsigned int hash_code)
112 {
113         subs_t* s;
114
115         s= htable[hash_code].entries?htable[hash_code].entries->next:NULL;
116
117         while(s)
118         {
119                 if(s->callid.len==callid.len &&
120                                 strncmp(s->callid.s, callid.s, callid.len)==0 &&
121                         s->to_tag.len== to_tag.len &&
122                                 strncmp(s->to_tag.s, to_tag.s, to_tag.len)==0 &&
123                         s->from_tag.len== from_tag.len &&
124                                 strncmp(s->from_tag.s, from_tag.s, from_tag.len)== 0)
125                         return s;
126                 s= s->next;
127         }
128
129         return NULL;
130 }
131
132 subs_t* mem_copy_subs(subs_t* s, int mem_type)
133 {
134         int size;
135         subs_t* dest;
136
137         size= sizeof(subs_t)+ (s->pres_uri.len+ s->to_user.len
138                 + s->to_domain.len+ s->from_user.len+ s->from_domain.len+ s->callid.len
139                 + s->to_tag.len+ s->from_tag.len+s->sockinfo_str.len+s->event_id.len
140                 + s->local_contact.len+ s->contact.len+ s->record_route.len
141                 + s->reason.len+ s->watcher_user.len+ s->watcher_domain.len
142                 + s->user_agent.len
143                 + 1)*sizeof(char);
144
145         if(mem_type & PKG_MEM_TYPE)
146                 dest= (subs_t*)pkg_malloc(size);
147         else
148                 dest= (subs_t*)shm_malloc(size);
149
150         if(dest== NULL)
151         {
152                 ERR_MEM((mem_type==PKG_MEM_TYPE)?PKG_MEM_STR:SHARE_MEM);
153         }
154         memset(dest, 0, size);
155         size= sizeof(subs_t);
156
157         CONT_COPY(dest, dest->pres_uri, s->pres_uri);
158         CONT_COPY(dest, dest->to_user, s->to_user);
159         CONT_COPY(dest, dest->to_domain, s->to_domain);
160         CONT_COPY(dest, dest->from_user, s->from_user);
161         CONT_COPY(dest, dest->from_domain, s->from_domain);
162         CONT_COPY(dest, dest->watcher_user, s->watcher_user);
163         CONT_COPY(dest, dest->watcher_domain, s->watcher_domain);
164         CONT_COPY(dest, dest->to_tag, s->to_tag);
165         CONT_COPY(dest, dest->from_tag, s->from_tag);
166         CONT_COPY(dest, dest->callid, s->callid);
167         CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str);
168         CONT_COPY(dest, dest->local_contact, s->local_contact);
169         CONT_COPY(dest, dest->contact, s->contact);
170         CONT_COPY(dest, dest->record_route, s->record_route);
171         CONT_COPY(dest, dest->user_agent, s->user_agent);
172         if(s->event_id.s)
173                 CONT_COPY(dest, dest->event_id, s->event_id);
174         if(s->reason.s)
175                 CONT_COPY(dest, dest->reason, s->reason);
176
177         dest->event= s->event;
178         dest->local_cseq= s->local_cseq;
179         dest->remote_cseq= s->remote_cseq;
180         dest->status= s->status;
181         dest->version= s->version;
182         dest->send_on_cback= s->send_on_cback;
183         dest->expires= s->expires;
184         dest->db_flag= s->db_flag;
185         dest->flags= s->flags;
186
187         return dest;
188
189 error:
190         return NULL;
191 }
192
193
194 subs_t* mem_copy_subs_noc(subs_t* s)
195 {
196         int size;
197         subs_t* dest;
198
199         size= sizeof(subs_t)+ (s->pres_uri.len+ s->to_user.len
200                 + s->to_domain.len+ s->from_user.len+ s->from_domain.len+ s->callid.len
201                 + s->to_tag.len+ s->from_tag.len+s->sockinfo_str.len+s->event_id.len
202                 + s->local_contact.len
203                 + s->reason.len+ s->watcher_user.len+ s->watcher_domain.len
204                 + s->user_agent.len
205                 + 1)*sizeof(char);
206
207         dest= (subs_t*)shm_malloc(size);
208         if(dest== NULL)
209         {
210                 ERR_MEM(SHARE_MEM);
211         }
212         memset(dest, 0, size);
213         size= sizeof(subs_t);
214
215         CONT_COPY(dest, dest->pres_uri, s->pres_uri);
216         CONT_COPY(dest, dest->to_user, s->to_user);
217         CONT_COPY(dest, dest->to_domain, s->to_domain);
218         CONT_COPY(dest, dest->from_user, s->from_user);
219         CONT_COPY(dest, dest->from_domain, s->from_domain);
220         CONT_COPY(dest, dest->watcher_user, s->watcher_user);
221         CONT_COPY(dest, dest->watcher_domain, s->watcher_domain);
222         CONT_COPY(dest, dest->to_tag, s->to_tag);
223         CONT_COPY(dest, dest->from_tag, s->from_tag);
224         CONT_COPY(dest, dest->callid, s->callid);
225         CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str);
226         CONT_COPY(dest, dest->local_contact, s->local_contact);
227         CONT_COPY(dest, dest->user_agent, s->user_agent);
228         if(s->event_id.s)
229                 CONT_COPY(dest, dest->event_id, s->event_id);
230         if(s->reason.s)
231                 CONT_COPY(dest, dest->reason, s->reason);
232
233         dest->event= s->event;
234         dest->local_cseq= s->local_cseq;
235         dest->remote_cseq= s->remote_cseq;
236         dest->status= s->status;
237         dest->version= s->version;
238         dest->send_on_cback= s->send_on_cback;
239         dest->expires= s->expires;
240         dest->db_flag= s->db_flag;
241         dest->flags= s->flags;
242
243         dest->contact.s= (char*)shm_malloc(s->contact.len* sizeof(char));
244         if(dest->contact.s== NULL)
245         {
246                 ERR_MEM(SHARE_MEM);
247         }
248         memcpy(dest->contact.s, s->contact.s, s->contact.len);
249         dest->contact.len= s->contact.len;
250
251         dest->record_route.s= (char*)shm_malloc((s->record_route.len + 1) * sizeof(char));
252         if(dest->record_route.s== NULL)
253         {
254                 ERR_MEM(SHARE_MEM);
255         }
256         memcpy(dest->record_route.s, s->record_route.s, s->record_route.len);
257         dest->record_route.len= s->record_route.len;
258
259         return dest;
260
261 error:
262         if(dest)
263                         shm_free(dest);
264         return NULL;
265 }
266
267 int insert_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs)
268 {
269         subs_t* new_rec= NULL;
270
271         new_rec= mem_copy_subs_noc(subs);
272         if(new_rec== NULL)
273         {
274                 LM_ERR("copying in share memory a subs_t structure\n");
275                 return -1;
276         }
277         new_rec->expires+= (int)time(NULL);
278
279         lock_get(&htable[hash_code].lock);
280         new_rec->next= htable[hash_code].entries->next;
281         htable[hash_code].entries->next= new_rec;
282         lock_release(&htable[hash_code].lock);
283
284         return 0;
285 }
286
287 int delete_shtable(shtable_t htable,unsigned int hash_code,subs_t* subs)
288 {
289         subs_t* s= NULL, *ps= NULL;
290         int found= -1;
291
292         lock_get(&htable[hash_code].lock);
293         
294         ps= htable[hash_code].entries;
295         s= ps?ps->next:NULL;
296                 
297         while(s)
298         {
299                 if(pres_subs_remove_match==0) {
300                         /* match on to-tag only (unique, local generated - faster) */
301                         if(s->to_tag.len==subs->to_tag.len
302                                 && strncmp(s->to_tag.s,subs->to_tag.s,subs->to_tag.len)==0)
303                         {
304                                 found = 0;
305                         }
306                 } else {
307                         /* match on all dialog attributes (distributed systems) */
308                         if(s->callid.len==subs->callid.len
309                                 && s->to_tag.len==subs->to_tag.len
310                                 && s->from_tag.len==subs->from_tag.len
311                                 && strncmp(s->callid.s,subs->callid.s,subs->callid.len)==0
312                                 && strncmp(s->to_tag.s,subs->to_tag.s,subs->to_tag.len)==0
313                                 && strncmp(s->from_tag.s,subs->from_tag.s,subs->from_tag.len)==0)
314                         {
315                                 found = 0;
316                         }
317                 }
318                 if(found==0)
319                 {
320                         found= s->local_cseq +1;
321                         ps->next= s->next;
322                         if(s->contact.s!=NULL) {
323                                 shm_free(s->contact.s);
324                                 s->contact.s = NULL;
325                         }
326                         if(s->record_route.s!=NULL) {
327                                 shm_free(s->record_route.s);
328                                 s->record_route.s = NULL;
329                         }
330                         if (s) {
331                                 shm_free(s);
332                                 s = NULL;
333                         }
334                         break;
335                 }
336                 ps= s;
337                 s= s->next;
338         }
339         lock_release(&htable[hash_code].lock);
340         return found;
341 }
342
343 void free_subs_list(subs_t* s_array, int mem_type, int ic)
344 {
345         subs_t* s;
346
347         while(s_array)
348         {
349                 s= s_array;
350                 s_array= s_array->next;
351                 if(mem_type & PKG_MEM_TYPE)
352                 {
353                         if(ic) {
354                                 pkg_free(s->contact.s);
355                                 s->contact.s = NULL;
356                         }
357                         pkg_free(s);
358                         s = NULL;
359                 }
360                 else
361                 {
362                         if(ic) {
363                                 shm_free(s->contact.s);
364                                 s->contact.s = NULL;
365                         }
366                         shm_free(s);
367                         s = NULL;
368                 }
369         }
370         
371 }
372
373 int update_shtable(shtable_t htable,unsigned int hash_code, 
374                 subs_t* subs, int type)
375 {
376         subs_t* s;
377
378         lock_get(&htable[hash_code].lock);
379
380         s= search_shtable(htable,subs->callid, subs->to_tag, subs->from_tag,
381                         hash_code);
382         if(s== NULL)
383         {
384                 LM_DBG("record not found in hash table\n");
385                 lock_release(&htable[hash_code].lock);
386                 return -1;
387         }
388
389         if(type & REMOTE_TYPE)
390         {
391                 s->expires= subs->expires+ (int)time(NULL);
392                 s->remote_cseq= subs->remote_cseq;
393         }
394         else
395         {
396                 subs->local_cseq = ++s->local_cseq;
397                 subs->version = ++s->version;
398         }
399         
400         if(presence_sip_uri_match(&s->contact, &subs->contact))
401         {
402                 shm_free(s->contact.s);
403                 s->contact.s= (char*)shm_malloc(subs->contact.len* sizeof(char));
404                 if(s->contact.s== NULL)
405                 {
406                         lock_release(&htable[hash_code].lock);
407                         LM_ERR("no more shared memory\n");
408                         return -1;
409                 }
410                 memcpy(s->contact.s, subs->contact.s, subs->contact.len);
411                 s->contact.len= subs->contact.len;
412         }
413
414         shm_free(s->record_route.s);
415         s->record_route.s= (char*)shm_malloc(subs->record_route.len* sizeof(char));
416         if(s->record_route.s== NULL)
417         {
418                 lock_release(&htable[hash_code].lock);
419                 LM_ERR("no more shared memory\n");
420                 return -1;
421         }
422         memcpy(s->record_route.s, subs->record_route.s, subs->record_route.len);
423         s->record_route.len= subs->record_route.len;
424
425         s->status= subs->status;
426         s->event= subs->event;
427         subs->db_flag= s->db_flag;
428
429         if(s->db_flag & NO_UPDATEDB_FLAG)
430                 s->db_flag= UPDATEDB_FLAG;
431
432         lock_release(&htable[hash_code].lock);
433         
434         return 0;
435 }
436
437 phtable_t* new_phtable(void)
438 {
439         phtable_t* htable= NULL;
440         int i, j;
441
442         i = 0;
443         htable= (phtable_t*)shm_malloc(phtable_size* sizeof(phtable_t));
444         if(htable== NULL)
445         {
446                 ERR_MEM(SHARE_MEM);
447         }
448         memset(htable, 0, phtable_size* sizeof(phtable_t));
449
450         for(i= 0; i< phtable_size; i++)
451         {
452                 if(lock_init(&htable[i].lock)== 0)
453                 {
454                         LM_ERR("initializing lock [%d]\n", i);
455                         goto error;
456                 }
457                 htable[i].entries= (pres_entry_t*)shm_malloc(sizeof(pres_entry_t));
458                 if(htable[i].entries== NULL)
459                 {
460                         ERR_MEM(SHARE_MEM);
461                 }
462                 memset(htable[i].entries, 0, sizeof(pres_entry_t));
463                 htable[i].entries->next= NULL;
464         }
465
466         return htable;
467
468 error:
469         if(htable)
470         {
471                 for(j=0; j< i; j++)
472                 {
473                         if(htable[i].entries)
474                                 shm_free(htable[i].entries);
475                         else 
476                                 break;
477                         lock_destroy(&htable[i].lock);
478                 }
479                 shm_free(htable);
480         }
481         return NULL;
482
483 }
484
485 void destroy_phtable(void)
486 {
487         int i;
488         pres_entry_t* p, *prev_p;
489
490         if(pres_htable== NULL)
491                 return;
492
493         for(i= 0; i< phtable_size; i++)
494         {
495                 lock_destroy(&pres_htable[i].lock);
496                 p= pres_htable[i].entries;
497                 while(p)
498                 {
499                         prev_p= p;
500                         p= p->next;
501                         if(prev_p->sphere)
502                                 shm_free(prev_p->sphere);
503                         shm_free(prev_p);
504                 }
505         }
506         shm_free(pres_htable);
507 }
508 /* entry must be locked before calling this function */
509
510 pres_entry_t* search_phtable(str* pres_uri,int event, unsigned int hash_code)
511 {
512         pres_entry_t* p;
513
514         LM_DBG("pres_uri= %.*s\n", pres_uri->len,  pres_uri->s);
515         p= pres_htable[hash_code].entries->next;
516         while(p)
517         {
518                 if(p->event== event && p->pres_uri.len== pres_uri->len &&
519                                 presence_sip_uri_match(&p->pres_uri, pres_uri)== 0 )
520                         return p;
521                 p= p->next;
522         }
523         return NULL;
524 }
525
526 int insert_phtable(str* pres_uri, int event, char* sphere)
527 {
528         unsigned int hash_code;
529         pres_entry_t* p= NULL;
530         int size;
531
532         hash_code= core_case_hash(pres_uri, NULL, phtable_size);
533
534         lock_get(&pres_htable[hash_code].lock);
535         
536         p= search_phtable(pres_uri, event, hash_code);
537         if(p)
538         {
539                 p->publ_count++;
540                 lock_release(&pres_htable[hash_code].lock);
541                 return 0;
542         }
543         size= sizeof(pres_entry_t)+ pres_uri->len* sizeof(char);
544
545         p= (pres_entry_t*)shm_malloc(size);
546         if(p== NULL)
547         {
548                 lock_release(&pres_htable[hash_code].lock);
549                 ERR_MEM(SHARE_MEM);
550         }
551         memset(p, 0, size);
552
553         size= sizeof(pres_entry_t);
554         p->pres_uri.s= (char*)p+ size;
555         memcpy(p->pres_uri.s, pres_uri->s, pres_uri->len);
556         p->pres_uri.len= pres_uri->len;
557         
558         if(sphere)
559         {
560                 p->sphere= (char*)shm_malloc((strlen(sphere)+ 1)*sizeof(char));
561                 if(p->sphere== NULL)
562                 {
563                         lock_release(&pres_htable[hash_code].lock);
564                         shm_free(p);
565                         ERR_MEM(SHARE_MEM);
566                 }
567                 strcpy(p->sphere, sphere);
568         }
569
570         p->event= event;
571         p->publ_count=1;
572
573         /* link the item in the hash table */
574         p->next= pres_htable[hash_code].entries->next;
575         pres_htable[hash_code].entries->next= p;
576
577         lock_release(&pres_htable[hash_code].lock);
578         
579         return 0;
580
581 error:
582         return -1;
583 }
584
585 int delete_phtable(str* pres_uri, int event)
586 {
587         unsigned int hash_code;
588         pres_entry_t* p= NULL, *prev_p= NULL;
589
590         hash_code= core_case_hash(pres_uri, NULL, phtable_size);
591
592         lock_get(&pres_htable[hash_code].lock);
593         
594         p= search_phtable(pres_uri, event, hash_code);
595         if(p== NULL)
596         {
597                 LM_DBG("record not found\n");
598                 lock_release(&pres_htable[hash_code].lock);
599                 return 0;
600         }
601         
602         p->publ_count--;
603         if(p->publ_count== 0)
604         {
605                 /* delete record */     
606                 prev_p= pres_htable[hash_code].entries;
607                 while(prev_p->next)
608                 {
609                         if(prev_p->next== p)
610                                 break;
611                         prev_p= prev_p->next;
612                 }
613                 if(prev_p->next== NULL)
614                 {
615                         LM_ERR("record not found\n");
616                         lock_release(&pres_htable[hash_code].lock);
617                         return -1;
618                 }
619                 prev_p->next= p->next;
620                 if(p->sphere)
621                         shm_free(p->sphere);
622
623                 shm_free(p);
624         }
625         lock_release(&pres_htable[hash_code].lock);
626
627         return 0;       
628 }
629
630 int update_phtable(presentity_t* presentity, str pres_uri, str body)
631 {
632         char* sphere= NULL;
633         unsigned int hash_code;
634         pres_entry_t* p;
635         int ret= 0;
636         str* xcap_doc= NULL;
637
638         /* get new sphere */
639         sphere= extract_sphere(body);
640         if(sphere==NULL)
641         {
642                 LM_DBG("no sphere defined in new body\n");
643                 return 0;
644         }
645
646         /* search for record in hash table */
647         hash_code= core_case_hash(&pres_uri, NULL, phtable_size);
648         
649         lock_get(&pres_htable[hash_code].lock);
650
651         p= search_phtable(&pres_uri, presentity->event->evp->type, hash_code);
652         if(p== NULL)
653         {
654                 lock_release(&pres_htable[hash_code].lock);
655                 goto done;
656         }
657         
658         if(p->sphere)
659         {
660                 if(strcmp(p->sphere, sphere)!= 0)
661                 {
662                         /* new sphere definition */
663                         shm_free(p->sphere);
664                 }
665                 else
666                 {
667                         /* no change in sphere definition */
668                         lock_release(&pres_htable[hash_code].lock);
669                         pkg_free(sphere);
670                         return 0;
671                 }
672         
673         }
674
675
676         p->sphere= (char*)shm_malloc((strlen(sphere)+ 1)*sizeof(char));
677         if(p->sphere== NULL)
678         {
679                 lock_release(&pres_htable[hash_code].lock);
680                 ret= -1;
681                 goto done;
682         }
683         strcpy(p->sphere, sphere);
684                 
685         lock_release(&pres_htable[hash_code].lock);
686
687         /* call for watchers status update */
688
689         if(presentity->event->get_rules_doc(&presentity->user, &presentity->domain,
690                                 &xcap_doc)< 0)
691         {
692                 LM_ERR("failed to retrieve xcap document\n");
693                 ret= -1;
694                 goto done;
695         }
696
697         update_watchers_status(pres_uri, presentity->event, xcap_doc);
698
699
700 done:
701
702         if(xcap_doc)
703         {
704                 if(xcap_doc->s)
705                         pkg_free(xcap_doc->s);
706                 pkg_free(xcap_doc);
707         }
708
709         if(sphere)
710                 pkg_free(sphere);
711         return ret;
712 }