all: updated FSF address in GPL text
[sip-router] / modules / presence / hash.c
1 /*
2  * $Id: hash.c 2583 2007-08-08 11:33:25Z anca_vamanu $
3  *
4  * presence module - presence server implementation
5  *
6  * Copyright (C) 2007 Voice Sistem S.R.L.
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License 
21  * along with this program; if not, write to the Free Software 
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  * History:
25  * --------
26  *  2007-08-20  initial version (Anca Vamanu)
27  */
28
29 /*! \file
30  * \brief Kamailio presence module
31  * \ingroup presence 
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include "../../mem/shm_mem.h"
37 #include "../../hashes.h"
38 #include "../../dprint.h"
39 #include "../../str.h"
40 #include "../pua/hash.h"
41 #include "presence.h"
42 #include "hash.h"
43 #include "notify.h"
44
45 shtable_t new_shtable(int hash_size)
46 {
47         shtable_t htable= NULL;
48         int i, j;
49
50         i = 0;
51         htable= (subs_entry_t*)shm_malloc(hash_size* sizeof(subs_entry_t));
52         if(htable== NULL)
53         {
54                 ERR_MEM(SHARE_MEM);
55         }
56         memset(htable, 0, hash_size* sizeof(subs_entry_t));
57         for(i= 0; i< hash_size; i++)
58         {
59                 if(lock_init(&htable[i].lock)== 0)
60                 {
61                         LM_ERR("initializing lock [%d]\n", i);
62                         goto error;
63                 }
64                 htable[i].entries= (subs_t*)shm_malloc(sizeof(subs_t));
65                 if(htable[i].entries== NULL)
66                 {
67                         lock_destroy(&htable[i].lock);
68                         ERR_MEM(SHARE_MEM);
69                 }
70                 memset(htable[i].entries, 0, sizeof(subs_t));
71                 htable[i].entries->next= NULL;
72         }
73
74         return htable;
75
76 error:
77         if(htable)
78         {
79                 for(j=0; j< i; j++)
80                 {
81                         lock_destroy(&htable[j].lock);
82                         shm_free(htable[j].entries);
83                 }
84                 shm_free(htable);
85         }
86         return NULL;
87
88 }
89
90 void destroy_shtable(shtable_t htable, int hash_size)
91 {
92         int i;
93
94         if(htable== NULL)
95                 return;
96
97         for(i= 0; i< hash_size; i++)
98         {
99                 lock_destroy(&htable[i].lock);
100                 free_subs_list(htable[i].entries->next, SHM_MEM_TYPE, 1);
101                 shm_free(htable[i].entries);
102         }
103         shm_free(htable);
104         htable= NULL;
105 }
106
107 subs_t* search_shtable(shtable_t htable,str callid,str to_tag,
108                 str from_tag,unsigned int hash_code)
109 {
110         subs_t* s;
111
112         s= htable[hash_code].entries->next;
113
114         while(s)
115         {
116                 if(s->callid.len==callid.len &&
117                                 strncmp(s->callid.s, callid.s, callid.len)==0 &&
118                         s->to_tag.len== to_tag.len &&
119                                 strncmp(s->to_tag.s, to_tag.s, to_tag.len)==0 &&
120                         s->from_tag.len== from_tag.len &&
121                                 strncmp(s->from_tag.s, from_tag.s, from_tag.len)== 0)
122                         return s;
123                 s= s->next;
124         }
125
126         return NULL;
127 }
128
129 subs_t* mem_copy_subs(subs_t* s, int mem_type)
130 {
131         int size;
132         subs_t* dest;
133
134         size= sizeof(subs_t)+ (s->pres_uri.len+ s->to_user.len
135                 + s->to_domain.len+ s->from_user.len+ s->from_domain.len+ s->callid.len
136                 + s->to_tag.len+ s->from_tag.len+s->sockinfo_str.len+s->event_id.len
137                 + s->local_contact.len+ s->contact.len+ s->record_route.len
138                 + s->reason.len+ s->watcher_user.len+ s->watcher_domain.len
139                 + 1)*sizeof(char);
140
141         if(mem_type & PKG_MEM_TYPE)
142                 dest= (subs_t*)pkg_malloc(size);
143         else
144                 dest= (subs_t*)shm_malloc(size);
145
146         if(dest== NULL)
147         {
148                 ERR_MEM((mem_type==PKG_MEM_TYPE)?PKG_MEM_STR:SHARE_MEM);
149         }
150         memset(dest, 0, size);
151         size= sizeof(subs_t);
152
153         CONT_COPY(dest, dest->pres_uri, s->pres_uri)
154         CONT_COPY(dest, dest->to_user, s->to_user)
155         CONT_COPY(dest, dest->to_domain, s->to_domain)
156         CONT_COPY(dest, dest->from_user, s->from_user)
157         CONT_COPY(dest, dest->from_domain, s->from_domain)
158         CONT_COPY(dest, dest->watcher_user, s->watcher_user)
159         CONT_COPY(dest, dest->watcher_domain, s->watcher_domain)
160         CONT_COPY(dest, dest->to_tag, s->to_tag)
161         CONT_COPY(dest, dest->from_tag, s->from_tag)
162         CONT_COPY(dest, dest->callid, s->callid)
163         CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str)
164         CONT_COPY(dest, dest->local_contact, s->local_contact)
165         CONT_COPY(dest, dest->contact, s->contact)
166         CONT_COPY(dest, dest->record_route, s->record_route)
167         if(s->event_id.s)
168                 CONT_COPY(dest, dest->event_id, s->event_id)
169         if(s->reason.s)
170                 CONT_COPY(dest, dest->reason, s->reason)
171
172         dest->event= s->event;
173         dest->local_cseq= s->local_cseq;
174         dest->remote_cseq= s->remote_cseq;
175         dest->status= s->status;
176         dest->version= s->version;
177         dest->send_on_cback= s->send_on_cback;
178         dest->expires= s->expires;
179         dest->db_flag= s->db_flag;
180
181         return dest;
182
183 error:
184         if(dest)
185         {
186                 if(mem_type & PKG_MEM_TYPE)
187                         pkg_free(dest);
188                 else
189                         shm_free(dest);
190         }
191         return NULL;
192 }
193
194
195 subs_t* mem_copy_subs_noc(subs_t* s)
196 {
197         int size;
198         subs_t* dest;
199
200         size= sizeof(subs_t)+ (s->pres_uri.len+ s->to_user.len
201                 + s->to_domain.len+ s->from_user.len+ s->from_domain.len+ s->callid.len
202                 + s->to_tag.len+ s->from_tag.len+s->sockinfo_str.len+s->event_id.len
203                 + s->local_contact.len + s->record_route.len+
204                 + s->reason.len+ s->watcher_user.len+ s->watcher_domain.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->record_route, s->record_route)
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
242         dest->contact.s= (char*)shm_malloc(s->contact.len* sizeof(char));
243         if(dest->contact.s== NULL)
244         {
245                 ERR_MEM(SHARE_MEM);
246         }
247         memcpy(dest->contact.s, s->contact.s, s->contact.len);
248         dest->contact.len= s->contact.len;
249
250         return dest;
251
252 error:
253         if(dest)
254                         shm_free(dest);
255         return NULL;
256 }
257
258 int insert_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs)
259 {
260         subs_t* new_rec= NULL;
261
262         new_rec= mem_copy_subs_noc(subs);
263         if(new_rec== NULL)
264         {
265                 LM_ERR("copying in share memory a subs_t structure\n");
266                 return -1;
267         }
268         new_rec->expires+= (int)time(NULL);
269
270         lock_get(&htable[hash_code].lock);
271         new_rec->next= htable[hash_code].entries->next;
272         htable[hash_code].entries->next= new_rec;
273         lock_release(&htable[hash_code].lock);
274
275         return 0;
276 }
277
278 int delete_shtable(shtable_t htable,unsigned int hash_code,subs_t* subs)
279 {
280         subs_t* s= NULL, *ps= NULL;
281         int found= -1;
282
283         lock_get(&htable[hash_code].lock);
284         
285         ps= htable[hash_code].entries;
286         s= ps->next;
287                 
288         while(s)
289         {
290                 if(s->callid.len==subs->callid.len &&
291                                 strncmp(s->callid.s, subs->callid.s, subs->callid.len)==0 &&
292                         s->to_tag.len== subs->to_tag.len &&
293                                 strncmp(s->to_tag.s, subs->to_tag.s, subs->to_tag.len)==0 &&
294                         s->from_tag.len== subs->from_tag.len &&
295                                 strncmp(s->from_tag.s, subs->from_tag.s, subs->from_tag.len)== 0)
296                 {
297                         found= s->local_cseq +1;
298                         ps->next= s->next;
299                         if(s->contact.s!=NULL)
300                                 shm_free(s->contact.s);
301                         shm_free(s);
302                         break;
303                 }
304                 ps= s;
305                 s= s->next;
306         }
307         lock_release(&htable[hash_code].lock);
308         return found;
309 }
310
311 void free_subs_list(subs_t* s_array, int mem_type, int ic)
312 {
313         subs_t* s;
314
315         while(s_array)
316         {
317                 s= s_array;
318                 s_array= s_array->next;
319                 if(mem_type & PKG_MEM_TYPE)
320                 {
321                         if(ic)
322                                 pkg_free(s->contact.s);
323                         pkg_free(s);
324                 }
325                 else
326                 {
327                         if(ic)
328                                 shm_free(s->contact.s);
329                         shm_free(s);
330                 }
331         }
332         
333 }
334
335 int update_shtable(shtable_t htable,unsigned int hash_code, 
336                 subs_t* subs, int type)
337 {
338         subs_t* s;
339
340         lock_get(&htable[hash_code].lock);
341
342         s= search_shtable(htable,subs->callid, subs->to_tag, subs->from_tag,
343                         hash_code);
344         if(s== NULL)
345         {
346                 LM_DBG("record not found in hash table\n");
347                 lock_release(&htable[hash_code].lock);
348                 return -1;
349         }
350
351         if(type & REMOTE_TYPE)
352         {
353                 s->expires= subs->expires+ (int)time(NULL);
354                 s->remote_cseq= subs->remote_cseq;
355         }
356         else
357         {
358                 subs->local_cseq = ++s->local_cseq;
359                 subs->version = ++s->version;
360         }
361         
362         if(strncmp(s->contact.s, subs->contact.s, subs->contact.len))
363         {
364                 shm_free(s->contact.s);
365                 s->contact.s= (char*)shm_malloc(subs->contact.len* sizeof(char));
366                 if(s->contact.s== NULL)
367                 {
368                         lock_release(&htable[hash_code].lock);
369                         LM_ERR("no more shared memory\n");
370                         return -1;
371                 }
372                 memcpy(s->contact.s, subs->contact.s, subs->contact.len);
373                 s->contact.len= subs->contact.len;
374         }
375
376         s->status= subs->status;
377         s->event= subs->event;
378         subs->db_flag= s->db_flag;
379
380         if(s->db_flag & NO_UPDATEDB_FLAG)
381                 s->db_flag= UPDATEDB_FLAG;
382
383         lock_release(&htable[hash_code].lock);
384         
385         return 0;
386 }
387
388 phtable_t* new_phtable(void)
389 {
390         phtable_t* htable= NULL;
391         int i, j;
392
393         i = 0;
394         htable= (phtable_t*)shm_malloc(phtable_size* sizeof(phtable_t));
395         if(htable== NULL)
396         {
397                 ERR_MEM(SHARE_MEM);
398         }
399         memset(htable, 0, phtable_size* sizeof(phtable_t));
400
401         for(i= 0; i< phtable_size; i++)
402         {
403                 if(lock_init(&htable[i].lock)== 0)
404                 {
405                         LM_ERR("initializing lock [%d]\n", i);
406                         goto error;
407                 }
408                 htable[i].entries= (pres_entry_t*)shm_malloc(sizeof(pres_entry_t));
409                 if(htable[i].entries== NULL)
410                 {
411                         ERR_MEM(SHARE_MEM);
412                 }
413                 memset(htable[i].entries, 0, sizeof(pres_entry_t));
414                 htable[i].entries->next= NULL;
415         }
416
417         return htable;
418
419 error:
420         if(htable)
421         {
422                 for(j=0; j< i; j++)
423                 {
424                         if(htable[i].entries)
425                                 shm_free(htable[i].entries);
426                         else 
427                                 break;
428                         lock_destroy(&htable[i].lock);
429                 }
430                 shm_free(htable);
431         }
432         return NULL;
433
434 }
435
436 void destroy_phtable(void)
437 {
438         int i;
439         pres_entry_t* p, *prev_p;
440
441         if(pres_htable== NULL)
442                 return;
443
444         for(i= 0; i< phtable_size; i++)
445         {
446                 lock_destroy(&pres_htable[i].lock);
447                 p= pres_htable[i].entries;
448                 while(p)
449                 {
450                         prev_p= p;
451                         p= p->next;
452                         if(prev_p->sphere)
453                                 shm_free(prev_p->sphere);
454                         shm_free(prev_p);
455                 }
456         }
457         shm_free(pres_htable);
458 }
459 /* entry must be locked before calling this function */
460
461 pres_entry_t* search_phtable(str* pres_uri,int event, unsigned int hash_code)
462 {
463         pres_entry_t* p;
464
465         LM_DBG("pres_uri= %.*s\n", pres_uri->len,  pres_uri->s);
466         p= pres_htable[hash_code].entries->next;
467         while(p)
468         {
469                 if(p->event== event && p->pres_uri.len== pres_uri->len &&
470                                 strncmp(p->pres_uri.s, pres_uri->s, pres_uri->len)== 0 )
471                         return p;
472                 p= p->next;
473         }
474         return NULL;
475 }
476
477 int insert_phtable(str* pres_uri, int event, char* sphere)
478 {
479         unsigned int hash_code;
480         pres_entry_t* p= NULL;
481         int size;
482
483         hash_code= core_hash(pres_uri, NULL, phtable_size);
484
485         lock_get(&pres_htable[hash_code].lock);
486         
487         p= search_phtable(pres_uri, event, hash_code);
488         if(p)
489         {
490                 p->publ_count++;
491                 lock_release(&pres_htable[hash_code].lock);
492                 return 0;
493         }
494         size= sizeof(pres_entry_t)+ pres_uri->len* sizeof(char);
495
496         p= (pres_entry_t*)shm_malloc(size);
497         if(p== NULL)
498         {
499                 lock_release(&pres_htable[hash_code].lock);
500                 ERR_MEM(SHARE_MEM);
501         }
502         memset(p, 0, size);
503
504         size= sizeof(pres_entry_t);
505         p->pres_uri.s= (char*)p+ size;
506         memcpy(p->pres_uri.s, pres_uri->s, pres_uri->len);
507         p->pres_uri.len= pres_uri->len;
508         
509         if(sphere)
510         {
511                 p->sphere= (char*)shm_malloc((strlen(sphere)+ 1)*sizeof(char));
512                 if(p->sphere== NULL)
513                 {
514                         lock_release(&pres_htable[hash_code].lock);
515                         ERR_MEM(SHARE_MEM);
516                 }
517                 strcpy(p->sphere, sphere);
518         }
519
520         p->event= event;
521         
522
523         p->next= pres_htable[hash_code].entries->next;
524         pres_htable[hash_code].entries->next= p;
525
526         lock_release(&pres_htable[hash_code].lock);
527         
528         return 0;
529
530 error:
531         return -1;
532 }
533
534 int delete_phtable(str* pres_uri, int event)
535 {
536         unsigned int hash_code;
537         pres_entry_t* p= NULL, *prev_p= NULL;
538
539         hash_code= core_hash(pres_uri, NULL, phtable_size);
540
541         lock_get(&pres_htable[hash_code].lock);
542         
543         p= search_phtable(pres_uri, event, hash_code);
544         if(p== NULL)
545         {
546                 LM_DBG("record not found\n");
547                 lock_release(&pres_htable[hash_code].lock);
548                 return 0;
549         }
550         
551         p->publ_count--;
552         if(p->publ_count== 0)
553         {
554                 /* delete record */     
555                 prev_p= pres_htable[hash_code].entries;
556                 while(prev_p->next)
557                 {
558                         if(prev_p->next== p)
559                                 break;
560                         prev_p= prev_p->next;
561                 }
562                 if(prev_p->next== NULL)
563                 {
564                         LM_ERR("record not found\n");
565                         lock_release(&pres_htable[hash_code].lock);
566                         return -1;
567                 }
568                 prev_p->next= p->next;
569                 if(p->sphere)
570                         shm_free(p->sphere);
571
572                 shm_free(p);
573         }
574         lock_release(&pres_htable[hash_code].lock);
575
576         return 0;       
577 }
578
579 int update_phtable(presentity_t* presentity, str pres_uri, str body)
580 {
581         char* sphere= NULL;
582         unsigned int hash_code;
583         pres_entry_t* p;
584         int ret= 0;
585         str* xcap_doc= NULL;
586
587         /* get new sphere */
588         sphere= extract_sphere(body);
589         if(sphere==NULL)
590         {
591                 LM_DBG("no sphere defined in new body\n");
592                 return 0;
593         }
594
595         /* search for record in hash table */
596         hash_code= core_hash(&pres_uri, NULL, phtable_size);
597         
598         lock_get(&pres_htable[hash_code].lock);
599
600         p= search_phtable(&pres_uri, presentity->event->evp->type, hash_code);
601         if(p== NULL)
602         {
603                 lock_release(&pres_htable[hash_code].lock);
604                 goto done;
605         }
606         
607         if(p->sphere)
608         {
609                 if(strcmp(p->sphere, sphere)!= 0)
610                 {
611                         /* new sphere definition */
612                         shm_free(p->sphere);
613                 }
614                 else
615                 {
616                         /* no change in sphere definition */
617                         lock_release(&pres_htable[hash_code].lock);
618                         pkg_free(sphere);
619                         return 0;
620                 }
621         
622         }
623
624
625         p->sphere= (char*)shm_malloc((strlen(sphere)+ 1)*sizeof(char));
626         if(p->sphere== NULL)
627         {
628                 lock_release(&pres_htable[hash_code].lock);
629                 ret= -1;
630                 goto done;
631         }
632         strcpy(p->sphere, sphere);
633                 
634         lock_release(&pres_htable[hash_code].lock);
635
636         /* call for watchers status update */
637
638         if(presentity->event->get_rules_doc(&presentity->user, &presentity->domain,
639                                 &xcap_doc)< 0)
640         {
641                 LM_ERR("failed to retrieve xcap document\n");
642                 ret= -1;
643                 goto done;
644         }
645
646         update_watchers_status(pres_uri, presentity->event, xcap_doc);
647
648
649 done:
650
651         if(xcap_doc)
652         {
653                 if(xcap_doc->s)
654                         pkg_free(xcap_doc->s);
655                 pkg_free(xcap_doc);
656         }
657
658         if(sphere)
659                 pkg_free(sphere);
660         return ret;
661 }