de818e5a15a17cb28ed642e21cbb7754002ced31
[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                 LM_ERR("No more memory\n");
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                 LM_ERR("No more share memory\n");
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                         LM_ERR("No more share memory\n");
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                 memcpy(p->etag.s, etag->s, etag->len);
205                 p->etag.len= etag->len;
206         }
207
208         p->expires= expires+ (int)time(NULL);
209         p->desired_expires= desired_expires;
210                 
211         if(p->db_flag & NO_UPDATEDB_FLAG)
212                 p->db_flag= UPDATEDB_FLAG;
213
214         if(p->watcher_uri)
215                 p->cseq++;
216
217         if(contact)
218         {
219                 if(!(p->remote_contact.len== contact->len && 
220                                 strncmp(p->remote_contact.s, contact->s, contact->len)==0))
221                 {
222                         /* update remote contact */
223                         shm_free(p->remote_contact.s);
224                         p->remote_contact.s= (char*)shm_malloc(contact->len* sizeof(char));
225                         if(p->remote_contact.s== NULL)
226                         {
227                                 LM_ERR("no more shared memory\n");
228                                 return;
229                         }
230                         memcpy(p->remote_contact.s, contact->s, contact->len);
231                         p->remote_contact.len= contact->len;
232                 }
233         }
234 }
235 /* insert in front; so when searching the most recent result is returned*/
236 void insert_htable(ua_pres_t* presentity, unsigned int hash_code)
237 {
238         ua_pres_t* p= NULL;
239
240         if (dbmode==PUA_DB_ONLY)
241         {
242                 LM_ERR( "insert_htable shouldn't be called in PUA_DB_ONLY mode\n" );
243                 return;
244         }
245
246         p= HashT->p_records[hash_code].entity;
247
248         presentity->db_flag= INSERTDB_FLAG;
249         presentity->next= p->next;
250         
251         p->next= presentity;
252 }
253
254 /* This function used to perform a search to find the hash table
255    entry that matches the presentity it is passed.  However,
256    everywhere it is used it is passed a pointer to the correct
257    hash table entry already...  so let's just delete that */
258 void delete_htable(ua_pres_t* presentity, unsigned int hash_code)
259
260         ua_pres_t *q = NULL;
261
262         if (dbmode==PUA_DB_ONLY)
263         {
264                 LM_ERR( "delete_htable shouldn't be called in PUA_DB_ONLY mode\n" );
265                 return;
266         }
267
268         if (presentity == NULL)
269                 return;
270
271         q = HashT->p_records[hash_code].entity;
272
273         while (q->next != presentity)
274                 q = q->next;
275         q->next = presentity->next;
276         
277         if(presentity->etag.s)
278                 shm_free(presentity->etag.s);
279         else
280                 if(presentity->remote_contact.s)
281                         shm_free(presentity->remote_contact.s);
282
283         shm_free(presentity);
284         presentity = NULL;
285
286 }
287         
288 void destroy_htable(void)
289 {
290         ua_pres_t* p= NULL,*q= NULL;
291         int i;
292
293         if (dbmode==PUA_DB_ONLY)
294         {
295                 LM_ERR( "destroy_htable shouldn't be called in PUA_DB_ONLY mode\n" );
296                 return;
297         }
298
299         for(i=0; i<HASH_SIZE; i++)
300         {       
301                 lock_destroy(&HashT->p_records[i].lock);
302                 p=HashT->p_records[i].entity;
303                 while(p->next)
304                 {
305                         q=p->next;
306                         p->next=q->next;
307                         if(q->etag.s)
308                                 shm_free(q->etag.s);
309                         else
310                                 if(q->remote_contact.s)
311                                         shm_free(q->remote_contact.s);
312
313                         shm_free(q);
314                         q= NULL;
315                 }
316                 shm_free(p);
317         }
318     shm_free(HashT->p_records);
319         shm_free(HashT);
320   
321   return;
322 }
323
324 int convert_temporary_dialog(ua_pres_t *dialog)
325 {
326         ua_pres_t *temp_dialog;
327         unsigned int hash_code;
328
329         hash_code= core_hash(dialog->pres_uri,dialog->watcher_uri, HASH_SIZE); 
330         lock_get(&HashT->p_records[hash_code].lock);
331
332         temp_dialog = get_temporary_dialog(dialog, hash_code);
333         if (temp_dialog)
334                 delete_htable(temp_dialog, hash_code);
335         else {
336                 lock_release(&HashT->p_records[hash_code].lock);
337                 return -1;
338         }
339
340         insert_htable(dialog, hash_code);
341
342         lock_release(&HashT->p_records[hash_code].lock);
343
344         return 1;
345 }
346
347 /* must lock the record line before calling this function*/
348 ua_pres_t* get_dialog(ua_pres_t* dialog, unsigned int hash_code)
349 {
350         ua_pres_t* p= NULL, *L;
351
352         if (dbmode==PUA_DB_ONLY)
353         {
354                 LM_ERR( "get_dialog shouldn't be called in PUA_DB_ONLY mode\n" );
355                 return(NULL);
356         }
357
358         if (dialog->to_tag.len == 0 || dialog->to_tag.s == NULL)
359                 return(NULL);
360
361         LM_DBG("core_hash= %u\n", hash_code);
362
363         L= HashT->p_records[hash_code].entity;
364         for(p= L->next; p; p=p->next)
365         {
366
367                 if(p->flag& dialog->flag)
368                 {
369                         LM_DBG("pres_uri= %.*s\twatcher_uri=%.*s\n\t"
370                                         "callid= %.*s\tto_tag= %.*s\tfrom_tag= %.*s\n",
371                                 p->pres_uri->len, p->pres_uri->s, p->watcher_uri->len,
372                                 p->watcher_uri->s,p->call_id.len, p->call_id.s,
373                                 p->to_tag.len, p->to_tag.s, p->from_tag.len, p->from_tag.s);
374
375                         LM_DBG("searched to_tag= %.*s\tfrom_tag= %.*s\n",
376                                  p->to_tag.len, p->to_tag.s, p->from_tag.len, p->from_tag.s);
377             
378                         if( (strncmp(p->call_id.s, dialog->call_id.s, p->call_id.len)== 0) &&
379                                 p->to_tag.len > 0 &&
380                                 (strncmp(p->to_tag.s, dialog->to_tag.s, p->to_tag.len)== 0) &&
381                                 (strncmp(p->from_tag.s, dialog->from_tag.s, p->from_tag.len)== 0) )
382                                 {       
383                                         LM_DBG("FOUND dialog\n");
384                                         break;
385                                 }
386                 }       
387         
388         }
389                 
390         return p;
391 }
392
393 /* must lock the record line before calling this function*/
394 ua_pres_t* get_temporary_dialog(ua_pres_t* dialog, unsigned int hash_code)
395 {
396         ua_pres_t* p= NULL, *L;
397         LM_DBG("core_hash= %u\n", hash_code);
398
399         L= HashT->p_records[hash_code].entity;
400         for(p= L->next; p; p=p->next)
401         {
402                 LM_DBG("pres_uri= %.*s\twatcher_uri=%.*s\n\t"
403                                 "callid= %.*s\tfrom_tag= %.*s\n",
404                         p->pres_uri->len, p->pres_uri->s, p->watcher_uri->len,
405                         p->watcher_uri->s,p->call_id.len, p->call_id.s,
406                         p->from_tag.len, p->from_tag.s);
407
408                 if((p->call_id.len == dialog->call_id.len) &&
409                         (strncmp(p->call_id.s, dialog->call_id.s, p->call_id.len)== 0) &&
410                         (p->from_tag.len == dialog->from_tag.len) &&
411                         (strncmp(p->from_tag.s, dialog->from_tag.s, p->from_tag.len)== 0))
412                 {
413                         LM_DBG("FOUND temporary dialog\n");
414                         break;
415                 }
416         }
417
418         return p;
419 }
420
421 int get_record_id(ua_pres_t* dialog, str** rec_id)
422 {
423         unsigned int hash_code;
424         ua_pres_t* rec;
425         str* id;
426
427         if (dbmode==PUA_DB_ONLY)
428         {
429                 return( get_record_id_puadb( dialog, rec_id ) );
430         }
431
432         *rec_id= NULL;
433
434         hash_code= core_hash(dialog->pres_uri, dialog->watcher_uri, HASH_SIZE);
435         lock_get(&HashT->p_records[hash_code].lock);
436
437         rec= get_dialog(dialog, hash_code);
438         if(rec== NULL)
439         {
440                 LM_DBG("Record not found - looking for temporary\n");
441                 rec = get_temporary_dialog(dialog, hash_code);
442                 if (rec == NULL)
443                 {
444                         LM_DBG("Temporary record not found\n");
445                         lock_release(&HashT->p_records[hash_code].lock);
446                         return 0;
447                 }
448         }
449         id= (str*)pkg_malloc(sizeof(str));
450         if(id== NULL)
451         {
452                 LM_ERR("No more memory\n");
453                 lock_release(&HashT->p_records[hash_code].lock);
454                 return -1;
455         }
456         id->s= (char*)pkg_malloc(rec->id.len* sizeof(char));
457         if(id->s== NULL)
458         {
459                 LM_ERR("No more memory\n");
460                 pkg_free(id);
461                 lock_release(&HashT->p_records[hash_code].lock);
462                 return -1;
463         }
464         memcpy(id->s, rec->id.s, rec->id.len);
465         id->len= rec->id.len;
466
467         lock_release(&HashT->p_records[hash_code].lock);
468
469         LM_DBG("rec did= %.*s\n", id->len, id->s);
470
471         *rec_id= id;
472
473         return 0;
474 }
475
476 /**
477  * return -1 on not found, 0 on established dialog, 1 on temporary dialog
478  */
479 int is_dialog(ua_pres_t* dialog)
480 {
481         int ret_code= 0;
482         unsigned int hash_code;
483
484         if (dbmode==PUA_DB_ONLY)
485         {
486                 return( is_dialog_puadb(dialog) );
487         }       
488
489         hash_code= core_hash(dialog->pres_uri, dialog->watcher_uri, HASH_SIZE);
490         lock_get(&HashT->p_records[hash_code].lock);
491
492         if(get_dialog(dialog, hash_code)==NULL)
493         {
494                 if(get_temporary_dialog(dialog, hash_code)==NULL)
495                         ret_code= -1;
496                 else
497                         ret_code= 1;
498         } else {
499                 ret_code= 0;
500         }
501         lock_release(&HashT->p_records[hash_code].lock);
502         
503         return ret_code;
504
505 }
506
507 int ki_pua_update_contact(struct sip_msg* msg)
508 {
509         ua_pres_t* p, hentity;
510         str contact;
511         struct to_body *pto = NULL, TO = {0}, *pfrom = NULL;
512         unsigned int hash_code;
513
514         if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
515         {
516                 LM_ERR("when parsing headers\n");
517                 return -1;
518         }
519
520         /* find the record */
521         if( msg->callid==NULL || msg->callid->body.s==NULL)
522         {
523                 LM_ERR("cannot parse callid header\n");
524                 return -1;
525         }               
526         
527         if (!msg->from || !msg->from->body.s)
528         {
529                 LM_ERR("cannot find 'from' header!\n");
530                 return -1;
531         }
532         if (msg->from->parsed == NULL)
533         {
534                 if ( parse_from_header( msg )<0 ) 
535                 {
536                         LM_ERR("cannot parse From header\n");
537                         return -1;
538                 }
539         }
540         
541         pfrom = (struct to_body*)msg->from->parsed;
542         
543         if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
544         {
545                 LM_ERR("no from tag value present\n");
546                 return -1;
547         }               
548         
549         if( msg->to==NULL || msg->to->body.s==NULL)
550         {
551                 LM_ERR("cannot parse TO header\n");
552                 return -1;
553         }                       
554         
555         if(msg->to->parsed != NULL)
556         {
557                 pto = (struct to_body*)msg->to->parsed;
558                 LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",pto->uri.len,pto->uri.s);
559         }
560         else
561         {
562                 parse_to(msg->to->body.s,msg->to->body.s +
563                         msg->to->body.len + 1, &TO);
564                 if(TO.uri.len <= 0) 
565                 {
566                         LM_DBG("'To' header NOT parsed\n");
567                         goto error;
568                 }
569                 pto = &TO;
570         }                       
571         if( pto->tag_value.s ==NULL || pto->tag_value.len == 0)
572         {
573                 LM_ERR("no from tag value present\n");
574                 goto error;
575         }
576         hentity.watcher_uri= &pto->uri;
577         hentity.pres_uri= &pfrom->uri; 
578         hentity.call_id=  msg->callid->body;
579         hentity.to_tag= pto->tag_value;
580         hentity.from_tag= pfrom->tag_value;
581         
582
583         /* extract the contact */
584         if(msg->contact== NULL || msg->contact->body.s== NULL)
585         {
586                 LM_ERR("no contact header found in 200 OK reply");
587                 goto error;
588         }
589         contact= msg->contact->body;
590
591         if (dbmode==PUA_DB_ONLY)
592         {
593                 update_contact_puadb(&hentity, &contact );
594                 free_to_params(&TO);
595                 return(1);
596         }
597
598         hash_code= core_hash(hentity.pres_uri,hentity.watcher_uri,
599                                 HASH_SIZE);
600
601         lock_get(&HashT->p_records[hash_code].lock);
602
603         p= get_dialog(&hentity, hash_code);
604         if(p== NULL)
605         {
606                 lock_release(&HashT->p_records[hash_code].lock);
607                 LM_ERR("no record for the dialog found in hash table\n");
608                 goto error;
609         }
610
611         shm_free(p->remote_contact.s);
612
613         if(!(p->remote_contact.len== contact.len && 
614                                 strncmp(p->remote_contact.s, contact.s, contact.len)==0))
615         {
616                 /* update remote contact */
617                 shm_free(p->remote_contact.s);
618                 p->remote_contact.s= (char*)shm_malloc(contact.len* sizeof(char));
619                 if(p->remote_contact.s== NULL)
620                 {
621                         LM_ERR("no more shared memory\n");
622                         lock_release(&HashT->p_records[hash_code].lock);
623                         goto error;
624                 }
625                 memcpy(p->remote_contact.s, contact.s, contact.len);
626                 p->remote_contact.len= contact.len;
627         }
628
629         lock_release(&HashT->p_records[hash_code].lock);
630
631         free_to_params(&TO);
632         return 1;
633
634 error:
635         free_to_params(&TO);
636         return -1;
637 }
638
639 int w_pua_update_contact(struct sip_msg* msg, char* str1, char* str2)
640 {
641         return ki_pua_update_contact(msg);
642 }
643
644 list_entry_t *get_subs_list(str *did)
645 {
646         int i;
647         str *tmp_str;
648         list_entry_t *list = NULL;
649
650         if (dbmode==PUA_DB_ONLY)
651                 return get_subs_list_puadb(did);
652
653         for (i = 0; i < HASH_SIZE; i++)
654         {
655                 ua_pres_t *dialog;
656
657                 lock_get(&HashT->p_records[i].lock);
658                 dialog = HashT->p_records[i].entity;
659                 while (dialog != NULL)
660                 {
661                         if (dialog->id.s != NULL && dialog->id.len > 0 &&
662                                 strncmp(dialog->id.s, did->s, did->len) == 0 &&
663                                 dialog->pres_uri != NULL && dialog->pres_uri->s != NULL &&
664                                 dialog->pres_uri->len > 0)
665                         {
666                                 if ((tmp_str = (str *)pkg_malloc(sizeof(str))) == NULL)
667                                 {
668                                         LM_ERR("out of private memory\n");
669                                         lock_release(&HashT->p_records[i].lock);
670                                         goto done;
671                                 }
672                                 if ((tmp_str->s = (char *)pkg_malloc(sizeof(char) * dialog->pres_uri->len + 1)) == NULL)
673                                 {
674                                         pkg_free(tmp_str);
675                                         LM_ERR("out of private memory\n");
676                                         lock_release(&HashT->p_records[i].lock);
677                                         goto done;
678                                 }
679                                 memcpy(tmp_str->s, dialog->pres_uri->s, dialog->pres_uri->len);
680                                 tmp_str->len = dialog->pres_uri->len;
681                                 tmp_str->s[tmp_str->len] = '\0';
682
683                                 list = list_insert(tmp_str, list, NULL);
684                         }
685                         dialog = dialog->next;
686                 }
687                 lock_release(&HashT->p_records[i].lock);
688         }
689 done:
690         return list;
691 }