2 * pua module - presence user agent module
4 * Copyright (C) 2006 Voice Sistem S.R.L.
6 * This file is part of Kamailio, a free SIP server.
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
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.
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
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"
37 #include "send_publish.h"
39 void print_ua_pres(ua_pres_t* p)
41 LM_DBG("\tpres_uri= %.*s len= %d\n", p->pres_uri->len, p->pres_uri->s, p->pres_uri->len);
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);
53 LM_DBG("\tetag= %.*s - len= %d\n", p->etag.len, p->etag.s, p->etag.len);
55 LM_DBG("\tid= %.*s\n", p->id.len, p->id.s);
57 LM_DBG("\texpires= %d\n", p->expires- (int)time(NULL));
60 htable_t* new_htable(void)
64 H= (htable_t*)shm_malloc(sizeof(htable_t));
66 if (dbmode==PUA_DB_ONLY)
68 LM_ERR( "new_htable shouldn't be called in PUA_DB_ONLY mode\n" );
77 memset(H, 0, sizeof(htable_t));
79 H->p_records= (hash_entry_t*)shm_malloc(HASH_SIZE* sizeof(hash_entry_t));
80 if(H->p_records== NULL)
86 for(i=0; i<HASH_SIZE; i++)
88 if(lock_init(&H->p_records[i].lock)== 0)
90 LM_CRIT("initializing lock [%d]\n", i);
93 H->p_records[i].entity= (ua_pres_t*)shm_malloc(sizeof(ua_pres_t));
94 if(H->p_records[i].entity== NULL)
99 H->p_records[i].entity->next= NULL;
109 if(H->p_records[j].entity)
110 shm_free(H->p_records[j].entity);
111 lock_destroy(&H->p_records[j].lock);
114 shm_free(H->p_records);
121 ua_pres_t* search_htable(ua_pres_t* pres, unsigned int hash_code)
123 ua_pres_t* p= NULL,* L= NULL;
124 L= HashT->p_records[hash_code].entity;
126 if (dbmode==PUA_DB_ONLY)
128 LM_ERR( "search_htable shouldn't be called in PUA_DB_ONLY mode\n" );
132 LM_DBG("core_hash= %u\n", hash_code);
134 for(p= L->next; p; p=p->next)
136 if((p->flag & pres->flag) && (p->event & pres->event))
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))
141 if(pres->id.s && pres->id.len)
143 if(!(pres->id.len== p->id.len &&
144 strncmp(p->id.s, pres->id.s,pres->id.len)==0))
148 if(pres->watcher_uri)
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))
154 if (check_remote_contact == 0)
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)
168 if(pres->etag.len== p->etag.len &&
169 strncmp(p->etag.s, pres->etag.s,pres->etag.len)==0)
174 LM_DBG("no etag restriction\n");
183 LM_DBG("found record\n");
185 LM_DBG("record not found\n");
190 void update_htable(ua_pres_t* p, time_t desired_expires, int expires,
191 str* etag, unsigned int hash_code, str* contact)
194 if (dbmode==PUA_DB_ONLY)
196 LM_ERR( "update_htable shouldn't be called in PUA_DB_ONLY mode\n" );
203 p->etag.s= (char*)shm_malloc(etag->len);
204 if(p->etag.s == NULL) {
208 memcpy(p->etag.s, etag->s, etag->len);
209 p->etag.len= etag->len;
212 p->expires= expires+ (int)time(NULL);
213 p->desired_expires= desired_expires;
215 if(p->db_flag & NO_UPDATEDB_FLAG)
216 p->db_flag= UPDATEDB_FLAG;
223 if(!(p->remote_contact.len== contact->len &&
224 strncmp(p->remote_contact.s, contact->s, contact->len)==0))
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)
234 memcpy(p->remote_contact.s, contact->s, contact->len);
235 p->remote_contact.len= contact->len;
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)
244 if (dbmode==PUA_DB_ONLY)
246 LM_ERR( "insert_htable shouldn't be called in PUA_DB_ONLY mode\n" );
250 p= HashT->p_records[hash_code].entity;
252 presentity->db_flag= INSERTDB_FLAG;
253 presentity->next= p->next;
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)
266 if (dbmode==PUA_DB_ONLY)
268 LM_ERR( "delete_htable shouldn't be called in PUA_DB_ONLY mode\n" );
272 if (presentity == NULL)
275 q = HashT->p_records[hash_code].entity;
277 while (q->next != presentity)
279 q->next = presentity->next;
281 if(presentity->etag.s)
282 shm_free(presentity->etag.s);
284 if(presentity->remote_contact.s)
285 shm_free(presentity->remote_contact.s);
287 shm_free(presentity);
292 void destroy_htable(void)
294 ua_pres_t* p= NULL,*q= NULL;
297 if (dbmode==PUA_DB_ONLY)
299 LM_ERR( "destroy_htable shouldn't be called in PUA_DB_ONLY mode\n" );
303 for(i=0; i<HASH_SIZE; i++)
305 lock_destroy(&HashT->p_records[i].lock);
306 p=HashT->p_records[i].entity;
314 if(q->remote_contact.s)
315 shm_free(q->remote_contact.s);
322 shm_free(HashT->p_records);
328 int convert_temporary_dialog(ua_pres_t *dialog)
330 ua_pres_t *temp_dialog;
331 unsigned int hash_code;
333 hash_code= core_hash(dialog->pres_uri,dialog->watcher_uri, HASH_SIZE);
334 lock_get(&HashT->p_records[hash_code].lock);
336 temp_dialog = get_temporary_dialog(dialog, hash_code);
338 delete_htable(temp_dialog, hash_code);
340 lock_release(&HashT->p_records[hash_code].lock);
344 insert_htable(dialog, hash_code);
346 lock_release(&HashT->p_records[hash_code].lock);
351 /* must lock the record line before calling this function*/
352 ua_pres_t* get_dialog(ua_pres_t* dialog, unsigned int hash_code)
354 ua_pres_t* p= NULL, *L;
356 if (dbmode==PUA_DB_ONLY)
358 LM_ERR( "get_dialog shouldn't be called in PUA_DB_ONLY mode\n" );
362 if (dialog->to_tag.len == 0 || dialog->to_tag.s == NULL)
365 LM_DBG("core_hash= %u\n", hash_code);
367 L= HashT->p_records[hash_code].entity;
368 for(p= L->next; p; p=p->next)
371 if(p->flag& dialog->flag)
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);
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);
382 if( (strncmp(p->call_id.s, dialog->call_id.s, p->call_id.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) )
387 LM_DBG("FOUND dialog\n");
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)
400 ua_pres_t* p= NULL, *L;
401 LM_DBG("core_hash= %u\n", hash_code);
403 L= HashT->p_records[hash_code].entity;
404 for(p= L->next; p; p=p->next)
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);
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))
417 LM_DBG("FOUND temporary dialog\n");
425 int get_record_id(ua_pres_t* dialog, str** rec_id)
427 unsigned int hash_code;
431 if (dbmode==PUA_DB_ONLY)
433 return( get_record_id_puadb( dialog, rec_id ) );
438 hash_code= core_hash(dialog->pres_uri, dialog->watcher_uri, HASH_SIZE);
439 lock_get(&HashT->p_records[hash_code].lock);
441 rec= get_dialog(dialog, hash_code);
444 LM_DBG("Record not found - looking for temporary\n");
445 rec = get_temporary_dialog(dialog, hash_code);
448 LM_DBG("Temporary record not found\n");
449 lock_release(&HashT->p_records[hash_code].lock);
453 id= (str*)pkg_malloc(sizeof(str));
457 lock_release(&HashT->p_records[hash_code].lock);
460 id->s= (char*)pkg_malloc(rec->id.len* sizeof(char));
465 lock_release(&HashT->p_records[hash_code].lock);
468 memcpy(id->s, rec->id.s, rec->id.len);
469 id->len= rec->id.len;
471 lock_release(&HashT->p_records[hash_code].lock);
473 LM_DBG("rec did= %.*s\n", id->len, id->s);
481 * return -1 on not found, 0 on established dialog, 1 on temporary dialog
483 int is_dialog(ua_pres_t* dialog)
486 unsigned int hash_code;
488 if (dbmode==PUA_DB_ONLY)
490 return( is_dialog_puadb(dialog) );
493 hash_code= core_hash(dialog->pres_uri, dialog->watcher_uri, HASH_SIZE);
494 lock_get(&HashT->p_records[hash_code].lock);
496 if(get_dialog(dialog, hash_code)==NULL)
498 if(get_temporary_dialog(dialog, hash_code)==NULL)
505 lock_release(&HashT->p_records[hash_code].lock);
511 int ki_pua_update_contact(struct sip_msg* msg)
513 ua_pres_t* p, hentity;
515 struct to_body *pto = NULL, TO = {0}, *pfrom = NULL;
516 unsigned int hash_code;
518 if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
520 LM_ERR("when parsing headers\n");
524 /* find the record */
525 if( msg->callid==NULL || msg->callid->body.s==NULL)
527 LM_ERR("cannot parse callid header\n");
531 if (!msg->from || !msg->from->body.s)
533 LM_ERR("cannot find 'from' header!\n");
536 if (msg->from->parsed == NULL)
538 if ( parse_from_header( msg )<0 )
540 LM_ERR("cannot parse From header\n");
545 pfrom = (struct to_body*)msg->from->parsed;
547 if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
549 LM_ERR("no from tag value present\n");
553 if( msg->to==NULL || msg->to->body.s==NULL)
555 LM_ERR("cannot parse TO header\n");
559 if(msg->to->parsed != NULL)
561 pto = (struct to_body*)msg->to->parsed;
562 LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",pto->uri.len,pto->uri.s);
566 parse_to(msg->to->body.s,msg->to->body.s +
567 msg->to->body.len + 1, &TO);
570 LM_DBG("'To' header NOT parsed\n");
575 if( pto->tag_value.s ==NULL || pto->tag_value.len == 0)
577 LM_ERR("no from tag value present\n");
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;
587 /* extract the contact */
588 if(msg->contact== NULL || msg->contact->body.s== NULL)
590 LM_ERR("no contact header found in 200 OK reply");
593 contact= msg->contact->body;
595 if (dbmode==PUA_DB_ONLY)
597 update_contact_puadb(&hentity, &contact );
602 hash_code= core_hash(hentity.pres_uri,hentity.watcher_uri,
605 lock_get(&HashT->p_records[hash_code].lock);
607 p= get_dialog(&hentity, hash_code);
610 lock_release(&HashT->p_records[hash_code].lock);
611 LM_ERR("no record for the dialog found in hash table\n");
615 shm_free(p->remote_contact.s);
617 if(!(p->remote_contact.len== contact.len &&
618 strncmp(p->remote_contact.s, contact.s, contact.len)==0))
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)
626 lock_release(&HashT->p_records[hash_code].lock);
629 memcpy(p->remote_contact.s, contact.s, contact.len);
630 p->remote_contact.len= contact.len;
633 lock_release(&HashT->p_records[hash_code].lock);
643 int w_pua_update_contact(struct sip_msg* msg, char* str1, char* str2)
645 return ki_pua_update_contact(msg);
648 list_entry_t *get_subs_list(str *did)
652 list_entry_t *list = NULL;
654 if (dbmode==PUA_DB_ONLY)
655 return get_subs_list_puadb(did);
657 for (i = 0; i < HASH_SIZE; i++)
661 lock_get(&HashT->p_records[i].lock);
662 dialog = HashT->p_records[i].entity;
663 while (dialog != NULL)
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)
670 if ((tmp_str = (str *)pkg_malloc(sizeof(str))) == NULL)
673 lock_release(&HashT->p_records[i].lock);
676 if ((tmp_str->s = (char *)pkg_malloc(sizeof(char) * dialog->pres_uri->len + 1)) == NULL)
680 lock_release(&HashT->p_records[i].lock);
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';
687 list = list_insert(tmp_str, list, NULL);
689 dialog = dialog->next;
691 lock_release(&HashT->p_records[i].lock);