pua: convert to PKG/SHM memory logging helper functions
[kamailio] / src / modules / pua / hash.c
1 /*
2  * pua module - presence user agent module
3  *
4  * Copyright (C) 2006 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 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "../../core/mem/mem.h"
29 #include "../../core/mem/shm_mem.h"
30 #include "../../core/dprint.h"
31 #include "../../core/hashes.h"
32 #include "../../core/parser/msg_parser.h"
33 #include "../../core/parser/parse_from.h"
34 #include "hash.h"
35 #include "pua.h"
36 #include "pua_db.h"
37 #include "send_publish.h"
38
39 void print_ua_pres(ua_pres_t* p)
40 {
41         LM_DBG("\tpres_uri= %.*s   len= %d\n", p->pres_uri->len, p->pres_uri->s, p->pres_uri->len);
42         if(p->watcher_uri)
43         {
44                 LM_DBG("\twatcher_uri= %.*s  len= %d\n", p->watcher_uri->len, p->watcher_uri->s, p->watcher_uri->len);
45                 LM_DBG("\tcall_id= %.*s   len= %d\n", p->call_id.len, p->call_id.s, p->call_id.len);
46                 LM_DBG("\tfrom_tag= %.*s   len= %d\n", p->from_tag.len, p->from_tag.s, p->from_tag.len);
47                 LM_DBG("\tto_tag= %.*s  len= %d\n", p->to_tag.len, p->to_tag.s, p->to_tag.len);
48                 LM_DBG("\tflag= %d\n", p->flag);
49                 LM_DBG("\tevent= %d\n", p->event);
50         }
51         else
52         {
53                 LM_DBG("\tetag= %.*s - len= %d\n", p->etag.len, p->etag.s, p->etag.len);
54                 if(p->id.s)
55                         LM_DBG("\tid= %.*s\n", p->id.len, p->id.s);
56         }
57         LM_DBG("\texpires= %d\n", p->expires- (int)time(NULL));
58 }
59
60 htable_t* new_htable(void)
61 {
62         htable_t* H= NULL;
63         int i= 0, j;
64         H= (htable_t*)shm_malloc(sizeof(htable_t));
65
66         if (dbmode==PUA_DB_ONLY)
67         {
68                 LM_ERR( "new_htable shouldn't be called in PUA_DB_ONLY mode\n" );
69                 return(NULL);
70         }
71
72         if(H== NULL)
73         {
74                 SHM_MEM_ERROR;
75                 return NULL;
76         }
77         memset(H, 0, sizeof(htable_t));
78
79         H->p_records= (hash_entry_t*)shm_malloc(HASH_SIZE* sizeof(hash_entry_t));
80         if(H->p_records== NULL)
81         {
82                 SHM_MEM_ERROR;
83                 goto error;
84         }
85
86         for(i=0; i<HASH_SIZE; i++)
87         {
88                 if(lock_init(&H->p_records[i].lock)== 0)
89                 {
90                         LM_CRIT("initializing lock [%d]\n", i);
91                         goto error;
92                 }
93                 H->p_records[i].entity= (ua_pres_t*)shm_malloc(sizeof(ua_pres_t));
94                 if(H->p_records[i].entity== NULL)
95                 {
96                         SHM_MEM_ERROR;
97                         goto error;
98                 }
99                 H->p_records[i].entity->next= NULL;
100         }
101         return H;
102
103 error:
104
105         if(H->p_records)
106         {
107                 for(j=0; j< i; j++)
108                 {
109                         if(H->p_records[j].entity)
110                                 shm_free(H->p_records[j].entity);
111                         lock_destroy(&H->p_records[j].lock);
112
113                 }
114                 shm_free(H->p_records);
115         }
116         shm_free(H);
117         return NULL;
118
119 }
120
121 ua_pres_t* search_htable(ua_pres_t* pres, unsigned int hash_code)
122 {
123         ua_pres_t* p= NULL,* L= NULL;
124         L= HashT->p_records[hash_code].entity;
125
126         if (dbmode==PUA_DB_ONLY)
127         {
128                 LM_ERR( "search_htable shouldn't be called in PUA_DB_ONLY mode\n" );
129                 return(NULL);
130         }
131
132         LM_DBG("core_hash= %u\n", hash_code);
133
134         for(p= L->next; p; p=p->next)
135         {
136                 if((p->flag & pres->flag) && (p->event & pres->event))
137                 {
138                         if((p->pres_uri->len==pres->pres_uri->len) &&
139                                         (strncmp(p->pres_uri->s, pres->pres_uri->s,pres->pres_uri->len)==0))
140                         {
141                                 if(pres->id.s && pres->id.len)
142                                 {
143                                         if(!(pres->id.len== p->id.len &&
144                                                 strncmp(p->id.s, pres->id.s,pres->id.len)==0))
145                                                         continue;
146                                 }
147
148                                 if(pres->watcher_uri)
149                                 {
150                                         if(p->watcher_uri->len==pres->watcher_uri->len &&
151                                                 (strncmp(p->watcher_uri->s, pres->watcher_uri->s,
152                                                                   pres->watcher_uri->len )==0))
153                                         {
154                                                 if (check_remote_contact == 0)
155                                                         break;
156
157                                                 if(pres->remote_contact.s)
158                                                         if(pres->remote_contact.len== p->remote_contact.len &&
159                                                                 strncmp(pres->remote_contact.s, p->remote_contact.s,
160                                                                                  p->remote_contact.len)== 0)
161                                                                 break;
162                                         }
163                                 }
164                                 else
165                                 {
166                                         if(pres->etag.s)
167                                         {
168                                                 if(pres->etag.len== p->etag.len &&
169                                                         strncmp(p->etag.s, pres->etag.s,pres->etag.len)==0)
170                                                         break;
171                                         }
172                                         else
173                                         {
174                                                 LM_DBG("no etag restriction\n");
175                                                 break;
176                                         }
177                                 }
178                         }
179                 }
180         }
181
182         if(p)
183                 LM_DBG("found record\n");
184         else
185                 LM_DBG("record not found\n");
186
187         return p;
188 }
189
190 void update_htable(ua_pres_t* p, time_t desired_expires, int expires,
191                 str* etag, unsigned int hash_code, str* contact)
192 {
193
194         if (dbmode==PUA_DB_ONLY)
195         {
196                 LM_ERR( "update_htable shouldn't be called in PUA_DB_ONLY mode\n" );
197                 return;
198         }
199
200         if(etag)
201         {
202                 shm_free(p->etag.s);
203                 p->etag.s= (char*)shm_malloc(etag->len);
204                 if(p->etag.s == NULL) {
205                         SHM_MEM_ERROR;
206                         return;
207                 }
208                 memcpy(p->etag.s, etag->s, etag->len);
209                 p->etag.len= etag->len;
210         }
211
212         p->expires= expires+ (int)time(NULL);
213         p->desired_expires= desired_expires;
214
215         if(p->db_flag & NO_UPDATEDB_FLAG)
216                 p->db_flag= UPDATEDB_FLAG;
217
218         if(p->watcher_uri)
219                 p->cseq++;
220
221         if(contact)
222         {
223                 if(!(p->remote_contact.len== contact->len &&
224                                 strncmp(p->remote_contact.s, contact->s, contact->len)==0))
225                 {
226                         /* update remote contact */
227                         shm_free(p->remote_contact.s);
228                         p->remote_contact.s= (char*)shm_malloc(contact->len* sizeof(char));
229                         if(p->remote_contact.s== NULL)
230                         {
231                                 SHM_MEM_ERROR;
232                                 return;
233                         }
234                         memcpy(p->remote_contact.s, contact->s, contact->len);
235                         p->remote_contact.len= contact->len;
236                 }
237         }
238 }
239 /* insert in front; so when searching the most recent result is returned*/
240 void insert_htable(ua_pres_t* presentity, unsigned int hash_code)
241 {
242         ua_pres_t* p= NULL;
243
244         if (dbmode==PUA_DB_ONLY)
245         {
246                 LM_ERR( "insert_htable shouldn't be called in PUA_DB_ONLY mode\n" );
247                 return;
248         }
249
250         p= HashT->p_records[hash_code].entity;
251
252         presentity->db_flag= INSERTDB_FLAG;
253         presentity->next= p->next;
254
255         p->next= presentity;
256 }
257
258 /* This function used to perform a search to find the hash table
259    entry that matches the presentity it is passed.  However,
260    everywhere it is used it is passed a pointer to the correct
261    hash table entry already...  so let's just delete that */
262 void delete_htable(ua_pres_t* presentity, unsigned int hash_code)
263 {
264         ua_pres_t *q = NULL;
265
266         if (dbmode==PUA_DB_ONLY)
267         {
268                 LM_ERR( "delete_htable shouldn't be called in PUA_DB_ONLY mode\n" );
269                 return;
270         }
271
272         if (presentity == NULL)
273                 return;
274
275         q = HashT->p_records[hash_code].entity;
276
277         while (q->next != presentity)
278                 q = q->next;
279         q->next = presentity->next;
280
281         if(presentity->etag.s)
282                 shm_free(presentity->etag.s);
283         else
284                 if(presentity->remote_contact.s)
285                         shm_free(presentity->remote_contact.s);
286
287         shm_free(presentity);
288         presentity = NULL;
289
290 }
291
292 void destroy_htable(void)
293 {
294         ua_pres_t* p= NULL,*q= NULL;
295         int i;
296
297         if (dbmode==PUA_DB_ONLY)
298         {
299                 LM_ERR( "destroy_htable shouldn't be called in PUA_DB_ONLY mode\n" );
300                 return;
301         }
302
303         for(i=0; i<HASH_SIZE; i++)
304         {
305                 lock_destroy(&HashT->p_records[i].lock);
306                 p=HashT->p_records[i].entity;
307                 while(p->next)
308                 {
309                         q=p->next;
310                         p->next=q->next;
311                         if(q->etag.s)
312                                 shm_free(q->etag.s);
313                         else
314                                 if(q->remote_contact.s)
315                                         shm_free(q->remote_contact.s);
316
317                         shm_free(q);
318                         q= NULL;
319                 }
320                 shm_free(p);
321         }
322     shm_free(HashT->p_records);
323         shm_free(HashT);
324
325   return;
326 }
327
328 int convert_temporary_dialog(ua_pres_t *dialog)
329 {
330         ua_pres_t *temp_dialog;
331         unsigned int hash_code;
332
333         hash_code= core_hash(dialog->pres_uri,dialog->watcher_uri, HASH_SIZE);
334         lock_get(&HashT->p_records[hash_code].lock);
335
336         temp_dialog = get_temporary_dialog(dialog, hash_code);
337         if (temp_dialog)
338                 delete_htable(temp_dialog, hash_code);
339         else {
340                 lock_release(&HashT->p_records[hash_code].lock);
341                 return -1;
342         }
343
344         insert_htable(dialog, hash_code);
345
346         lock_release(&HashT->p_records[hash_code].lock);
347
348         return 1;
349 }
350
351 /* must lock the record line before calling this function*/
352 ua_pres_t* get_dialog(ua_pres_t* dialog, unsigned int hash_code)
353 {
354         ua_pres_t* p= NULL, *L;
355
356         if (dbmode==PUA_DB_ONLY)
357         {
358                 LM_ERR( "get_dialog shouldn't be called in PUA_DB_ONLY mode\n" );
359                 return(NULL);
360         }
361
362         if (dialog->to_tag.len == 0 || dialog->to_tag.s == NULL)
363                 return(NULL);
364
365         LM_DBG("core_hash= %u\n", hash_code);
366
367         L= HashT->p_records[hash_code].entity;
368         for(p= L->next; p; p=p->next)
369         {
370
371                 if(p->flag& dialog->flag)
372                 {
373                         LM_DBG("pres_uri= %.*s\twatcher_uri=%.*s\n\t"
374                                         "callid= %.*s\tto_tag= %.*s\tfrom_tag= %.*s\n",
375                                 p->pres_uri->len, p->pres_uri->s, p->watcher_uri->len,
376                                 p->watcher_uri->s,p->call_id.len, p->call_id.s,
377                                 p->to_tag.len, p->to_tag.s, p->from_tag.len, p->from_tag.s);
378
379                         LM_DBG("searched to_tag= %.*s\tfrom_tag= %.*s\n",
380                                  p->to_tag.len, p->to_tag.s, p->from_tag.len, p->from_tag.s);
381
382                         if( (strncmp(p->call_id.s, dialog->call_id.s, p->call_id.len)== 0) &&
383                                 p->to_tag.len > 0 &&
384                                 (strncmp(p->to_tag.s, dialog->to_tag.s, p->to_tag.len)== 0) &&
385                                 (strncmp(p->from_tag.s, dialog->from_tag.s, p->from_tag.len)== 0) )
386                                 {
387                                         LM_DBG("FOUND dialog\n");
388                                         break;
389                                 }
390                 }
391
392         }
393
394         return p;
395 }
396
397 /* must lock the record line before calling this function*/
398 ua_pres_t* get_temporary_dialog(ua_pres_t* dialog, unsigned int hash_code)
399 {
400         ua_pres_t* p= NULL, *L;
401         LM_DBG("core_hash= %u\n", hash_code);
402
403         L= HashT->p_records[hash_code].entity;
404         for(p= L->next; p; p=p->next)
405         {
406                 LM_DBG("pres_uri= %.*s\twatcher_uri=%.*s\n\t"
407                                 "callid= %.*s\tfrom_tag= %.*s\n",
408                         p->pres_uri->len, p->pres_uri->s, p->watcher_uri->len,
409                         p->watcher_uri->s,p->call_id.len, p->call_id.s,
410                         p->from_tag.len, p->from_tag.s);
411
412                 if((p->call_id.len == dialog->call_id.len) &&
413                         (strncmp(p->call_id.s, dialog->call_id.s, p->call_id.len)== 0) &&
414                         (p->from_tag.len == dialog->from_tag.len) &&
415                         (strncmp(p->from_tag.s, dialog->from_tag.s, p->from_tag.len)== 0))
416                 {
417                         LM_DBG("FOUND temporary dialog\n");
418                         break;
419                 }
420         }
421
422         return p;
423 }
424
425 int get_record_id(ua_pres_t* dialog, str** rec_id)
426 {
427         unsigned int hash_code;
428         ua_pres_t* rec;
429         str* id;
430
431         if (dbmode==PUA_DB_ONLY)
432         {
433                 return( get_record_id_puadb( dialog, rec_id ) );
434         }
435
436         *rec_id= NULL;
437
438         hash_code= core_hash(dialog->pres_uri, dialog->watcher_uri, HASH_SIZE);
439         lock_get(&HashT->p_records[hash_code].lock);
440
441         rec= get_dialog(dialog, hash_code);
442         if(rec== NULL)
443         {
444                 LM_DBG("Record not found - looking for temporary\n");
445                 rec = get_temporary_dialog(dialog, hash_code);
446                 if (rec == NULL)
447                 {
448                         LM_DBG("Temporary record not found\n");
449                         lock_release(&HashT->p_records[hash_code].lock);
450                         return 0;
451                 }
452         }
453         id= (str*)pkg_malloc(sizeof(str));
454         if(id== NULL)
455         {
456                 PKG_MEM_ERROR;
457                 lock_release(&HashT->p_records[hash_code].lock);
458                 return -1;
459         }
460         id->s= (char*)pkg_malloc(rec->id.len* sizeof(char));
461         if(id->s== NULL)
462         {
463                 PKG_MEM_ERROR;
464                 pkg_free(id);
465                 lock_release(&HashT->p_records[hash_code].lock);
466                 return -1;
467         }
468         memcpy(id->s, rec->id.s, rec->id.len);
469         id->len= rec->id.len;
470
471         lock_release(&HashT->p_records[hash_code].lock);
472
473         LM_DBG("rec did= %.*s\n", id->len, id->s);
474
475         *rec_id= id;
476
477         return 0;
478 }
479
480 /**
481  * return -1 on not found, 0 on established dialog, 1 on temporary dialog
482  */
483 int is_dialog(ua_pres_t* dialog)
484 {
485         int ret_code= 0;
486         unsigned int hash_code;
487
488         if (dbmode==PUA_DB_ONLY)
489         {
490                 return( is_dialog_puadb(dialog) );
491         }
492
493         hash_code= core_hash(dialog->pres_uri, dialog->watcher_uri, HASH_SIZE);
494         lock_get(&HashT->p_records[hash_code].lock);
495
496         if(get_dialog(dialog, hash_code)==NULL)
497         {
498                 if(get_temporary_dialog(dialog, hash_code)==NULL)
499                         ret_code= -1;
500                 else
501                         ret_code= 1;
502         } else {
503                 ret_code= 0;
504         }
505         lock_release(&HashT->p_records[hash_code].lock);
506
507         return ret_code;
508
509 }
510
511 int ki_pua_update_contact(struct sip_msg* msg)
512 {
513         ua_pres_t* p, hentity;
514         str contact;
515         struct to_body *pto = NULL, TO = {0}, *pfrom = NULL;
516         unsigned int hash_code;
517
518         if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
519         {
520                 LM_ERR("when parsing headers\n");
521                 return -1;
522         }
523
524         /* find the record */
525         if( msg->callid==NULL || msg->callid->body.s==NULL)
526         {
527                 LM_ERR("cannot parse callid header\n");
528                 return -1;
529         }
530
531         if (!msg->from || !msg->from->body.s)
532         {
533                 LM_ERR("cannot find 'from' header!\n");
534                 return -1;
535         }
536         if (msg->from->parsed == NULL)
537         {
538                 if ( parse_from_header( msg )<0 )
539                 {
540                         LM_ERR("cannot parse From header\n");
541                         return -1;
542                 }
543         }
544
545         pfrom = (struct to_body*)msg->from->parsed;
546
547         if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
548         {
549                 LM_ERR("no from tag value present\n");
550                 return -1;
551         }
552
553         if( msg->to==NULL || msg->to->body.s==NULL)
554         {
555                 LM_ERR("cannot parse TO header\n");
556                 return -1;
557         }
558
559         if(msg->to->parsed != NULL)
560         {
561                 pto = (struct to_body*)msg->to->parsed;
562                 LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",pto->uri.len,pto->uri.s);
563         }
564         else
565         {
566                 parse_to(msg->to->body.s,msg->to->body.s +
567                         msg->to->body.len + 1, &TO);
568                 if(TO.uri.len <= 0)
569                 {
570                         LM_DBG("'To' header NOT parsed\n");
571                         goto error;
572                 }
573                 pto = &TO;
574         }
575         if( pto->tag_value.s ==NULL || pto->tag_value.len == 0)
576         {
577                 LM_ERR("no from tag value present\n");
578                 goto error;
579         }
580         hentity.watcher_uri= &pto->uri;
581         hentity.pres_uri= &pfrom->uri;
582         hentity.call_id=  msg->callid->body;
583         hentity.to_tag= pto->tag_value;
584         hentity.from_tag= pfrom->tag_value;
585
586
587         /* extract the contact */
588         if(msg->contact== NULL || msg->contact->body.s== NULL)
589         {
590                 LM_ERR("no contact header found in 200 OK reply");
591                 goto error;
592         }
593         contact= msg->contact->body;
594
595         if (dbmode==PUA_DB_ONLY)
596         {
597                 update_contact_puadb(&hentity, &contact );
598                 free_to_params(&TO);
599                 return(1);
600         }
601
602         hash_code= core_hash(hentity.pres_uri,hentity.watcher_uri,
603                                 HASH_SIZE);
604
605         lock_get(&HashT->p_records[hash_code].lock);
606
607         p= get_dialog(&hentity, hash_code);
608         if(p== NULL)
609         {
610                 lock_release(&HashT->p_records[hash_code].lock);
611                 LM_ERR("no record for the dialog found in hash table\n");
612                 goto error;
613         }
614
615         shm_free(p->remote_contact.s);
616
617         if(!(p->remote_contact.len== contact.len &&
618                                 strncmp(p->remote_contact.s, contact.s, contact.len)==0))
619         {
620                 /* update remote contact */
621                 shm_free(p->remote_contact.s);
622                 p->remote_contact.s= (char*)shm_malloc(contact.len* sizeof(char));
623                 if(p->remote_contact.s== NULL)
624                 {
625                         SHM_MEM_ERROR;
626                         lock_release(&HashT->p_records[hash_code].lock);
627                         goto error;
628                 }
629                 memcpy(p->remote_contact.s, contact.s, contact.len);
630                 p->remote_contact.len= contact.len;
631         }
632
633         lock_release(&HashT->p_records[hash_code].lock);
634
635         free_to_params(&TO);
636         return 1;
637
638 error:
639         free_to_params(&TO);
640         return -1;
641 }
642
643 int w_pua_update_contact(struct sip_msg* msg, char* str1, char* str2)
644 {
645         return ki_pua_update_contact(msg);
646 }
647
648 list_entry_t *get_subs_list(str *did)
649 {
650         int i;
651         str *tmp_str;
652         list_entry_t *list = NULL;
653
654         if (dbmode==PUA_DB_ONLY)
655                 return get_subs_list_puadb(did);
656
657         for (i = 0; i < HASH_SIZE; i++)
658         {
659                 ua_pres_t *dialog;
660
661                 lock_get(&HashT->p_records[i].lock);
662                 dialog = HashT->p_records[i].entity;
663                 while (dialog != NULL)
664                 {
665                         if (dialog->id.s != NULL && dialog->id.len > 0 &&
666                                 strncmp(dialog->id.s, did->s, did->len) == 0 &&
667                                 dialog->pres_uri != NULL && dialog->pres_uri->s != NULL &&
668                                 dialog->pres_uri->len > 0)
669                         {
670                                 if ((tmp_str = (str *)pkg_malloc(sizeof(str))) == NULL)
671                                 {
672                                         PKG_MEM_ERROR;
673                                         lock_release(&HashT->p_records[i].lock);
674                                         goto done;
675                                 }
676                                 if ((tmp_str->s = (char *)pkg_malloc(sizeof(char) * dialog->pres_uri->len + 1)) == NULL)
677                                 {
678                                         pkg_free(tmp_str);
679                                         PKG_MEM_ERROR;
680                                         lock_release(&HashT->p_records[i].lock);
681                                         goto done;
682                                 }
683                                 memcpy(tmp_str->s, dialog->pres_uri->s, dialog->pres_uri->len);
684                                 tmp_str->len = dialog->pres_uri->len;
685                                 tmp_str->s[tmp_str->len] = '\0';
686
687                                 list = list_insert(tmp_str, list, NULL);
688                         }
689                         dialog = dialog->next;
690                 }
691                 lock_release(&HashT->p_records[i].lock);
692         }
693 done:
694         return list;
695 }