k/presence/hash.c

Go to the documentation of this file.
00001 /*
00002  * $Id: hash.c 2583 2007-08-08 11:33:25Z anca_vamanu $
00003  *
00004  * presence module - presence server implementation
00005  *
00006  * Copyright (C) 2007 Voice Sistem S.R.L.
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  *  2007-08-20  initial version (Anca Vamanu)
00027  */
00028 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include "../../mem/shm_mem.h"
00037 #include "../../hashes.h"
00038 #include "../../dprint.h"
00039 #include "../../str.h"
00040 #include "../pua/hash.h"
00041 #include "presence.h"
00042 #include "hash.h"
00043 #include "notify.h"
00044 
00045 shtable_t new_shtable(int hash_size)
00046 {
00047         shtable_t htable= NULL;
00048         int i, j;
00049 
00050         i = 0;
00051         htable= (subs_entry_t*)shm_malloc(hash_size* sizeof(subs_entry_t));
00052         if(htable== NULL)
00053         {
00054                 ERR_MEM(SHARE_MEM);
00055         }
00056         memset(htable, 0, hash_size* sizeof(subs_entry_t));
00057         for(i= 0; i< hash_size; i++)
00058         {
00059                 if(lock_init(&htable[i].lock)== 0)
00060                 {
00061                         LM_ERR("initializing lock [%d]\n", i);
00062                         goto error;
00063                 }
00064                 htable[i].entries= (subs_t*)shm_malloc(sizeof(subs_t));
00065                 if(htable[i].entries== NULL)
00066                 {
00067                         lock_destroy(&htable[i].lock);
00068                         ERR_MEM(SHARE_MEM);
00069                 }
00070                 memset(htable[i].entries, 0, sizeof(subs_t));
00071                 htable[i].entries->next= NULL;
00072         }
00073 
00074         return htable;
00075 
00076 error:
00077         if(htable)
00078         {
00079                 for(j=0; j< i; j++)
00080                 {
00081                         lock_destroy(&htable[j].lock);
00082                         shm_free(htable[j].entries);
00083                 }
00084                 shm_free(htable);
00085         }
00086         return NULL;
00087 
00088 }
00089 
00090 void destroy_shtable(shtable_t htable, int hash_size)
00091 {
00092         int i;
00093 
00094         if(htable== NULL)
00095                 return;
00096 
00097         for(i= 0; i< hash_size; i++)
00098         {
00099                 lock_destroy(&htable[i].lock);
00100                 free_subs_list(htable[i].entries->next, SHM_MEM_TYPE, 1);
00101                 shm_free(htable[i].entries);
00102         }
00103         shm_free(htable);
00104         htable= NULL;
00105 }
00106 
00107 subs_t* search_shtable(shtable_t htable,str callid,str to_tag,
00108                 str from_tag,unsigned int hash_code)
00109 {
00110         subs_t* s;
00111 
00112         s= htable[hash_code].entries->next;
00113 
00114         while(s)
00115         {
00116                 if(s->callid.len==callid.len &&
00117                                 strncmp(s->callid.s, callid.s, callid.len)==0 &&
00118                         s->to_tag.len== to_tag.len &&
00119                                 strncmp(s->to_tag.s, to_tag.s, to_tag.len)==0 &&
00120                         s->from_tag.len== from_tag.len &&
00121                                 strncmp(s->from_tag.s, from_tag.s, from_tag.len)== 0)
00122                         return s;
00123                 s= s->next;
00124         }
00125 
00126         return NULL;
00127 }
00128 
00129 subs_t* mem_copy_subs(subs_t* s, int mem_type)
00130 {
00131         int size;
00132         subs_t* dest;
00133 
00134         size= sizeof(subs_t)+ (s->pres_uri.len+ s->to_user.len
00135                 + s->to_domain.len+ s->from_user.len+ s->from_domain.len+ s->callid.len
00136                 + s->to_tag.len+ s->from_tag.len+s->sockinfo_str.len+s->event_id.len
00137                 + s->local_contact.len+ s->contact.len+ s->record_route.len
00138                 + s->reason.len+ s->watcher_user.len+ s->watcher_domain.len
00139                 + 1)*sizeof(char);
00140 
00141         if(mem_type & PKG_MEM_TYPE)
00142                 dest= (subs_t*)pkg_malloc(size);
00143         else
00144                 dest= (subs_t*)shm_malloc(size);
00145 
00146         if(dest== NULL)
00147         {
00148                 ERR_MEM((mem_type==PKG_MEM_TYPE)?PKG_MEM_STR:SHARE_MEM);
00149         }
00150         memset(dest, 0, size);
00151         size= sizeof(subs_t);
00152 
00153         CONT_COPY(dest, dest->pres_uri, s->pres_uri)
00154         CONT_COPY(dest, dest->to_user, s->to_user)
00155         CONT_COPY(dest, dest->to_domain, s->to_domain)
00156         CONT_COPY(dest, dest->from_user, s->from_user)
00157         CONT_COPY(dest, dest->from_domain, s->from_domain)
00158         CONT_COPY(dest, dest->watcher_user, s->watcher_user)
00159         CONT_COPY(dest, dest->watcher_domain, s->watcher_domain)
00160         CONT_COPY(dest, dest->to_tag, s->to_tag)
00161         CONT_COPY(dest, dest->from_tag, s->from_tag)
00162         CONT_COPY(dest, dest->callid, s->callid)
00163         CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str)
00164         CONT_COPY(dest, dest->local_contact, s->local_contact)
00165         CONT_COPY(dest, dest->contact, s->contact)
00166         CONT_COPY(dest, dest->record_route, s->record_route)
00167         if(s->event_id.s)
00168                 CONT_COPY(dest, dest->event_id, s->event_id)
00169         if(s->reason.s)
00170                 CONT_COPY(dest, dest->reason, s->reason)
00171 
00172         dest->event= s->event;
00173         dest->local_cseq= s->local_cseq;
00174         dest->remote_cseq= s->remote_cseq;
00175         dest->status= s->status;
00176         dest->version= s->version;
00177         dest->send_on_cback= s->send_on_cback;
00178         dest->expires= s->expires;
00179         dest->db_flag= s->db_flag;
00180 
00181         return dest;
00182 
00183 error:
00184         if(dest)
00185         {
00186                 if(mem_type & PKG_MEM_TYPE)
00187                         pkg_free(dest);
00188                 else
00189                         shm_free(dest);
00190         }
00191         return NULL;
00192 }
00193 
00194 
00195 subs_t* mem_copy_subs_noc(subs_t* s)
00196 {
00197         int size;
00198         subs_t* dest;
00199 
00200         size= sizeof(subs_t)+ (s->pres_uri.len+ s->to_user.len
00201                 + s->to_domain.len+ s->from_user.len+ s->from_domain.len+ s->callid.len
00202                 + s->to_tag.len+ s->from_tag.len+s->sockinfo_str.len+s->event_id.len
00203                 + s->local_contact.len + s->record_route.len+
00204                 + s->reason.len+ s->watcher_user.len+ s->watcher_domain.len
00205                 + 1)*sizeof(char);
00206 
00207         dest= (subs_t*)shm_malloc(size);
00208         if(dest== NULL)
00209         {
00210                 ERR_MEM(SHARE_MEM);
00211         }
00212         memset(dest, 0, size);
00213         size= sizeof(subs_t);
00214 
00215         CONT_COPY(dest, dest->pres_uri, s->pres_uri)
00216         CONT_COPY(dest, dest->to_user, s->to_user)
00217         CONT_COPY(dest, dest->to_domain, s->to_domain)
00218         CONT_COPY(dest, dest->from_user, s->from_user)
00219         CONT_COPY(dest, dest->from_domain, s->from_domain)
00220         CONT_COPY(dest, dest->watcher_user, s->watcher_user)
00221         CONT_COPY(dest, dest->watcher_domain, s->watcher_domain)
00222         CONT_COPY(dest, dest->to_tag, s->to_tag)
00223         CONT_COPY(dest, dest->from_tag, s->from_tag)
00224         CONT_COPY(dest, dest->callid, s->callid)
00225         CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str)
00226         CONT_COPY(dest, dest->local_contact, s->local_contact)
00227         CONT_COPY(dest, dest->record_route, s->record_route)
00228         if(s->event_id.s)
00229                 CONT_COPY(dest, dest->event_id, s->event_id)
00230         if(s->reason.s)
00231                 CONT_COPY(dest, dest->reason, s->reason)
00232 
00233         dest->event= s->event;
00234         dest->local_cseq= s->local_cseq;
00235         dest->remote_cseq= s->remote_cseq;
00236         dest->status= s->status;
00237         dest->version= s->version;
00238         dest->send_on_cback= s->send_on_cback;
00239         dest->expires= s->expires;
00240         dest->db_flag= s->db_flag;
00241 
00242         dest->contact.s= (char*)shm_malloc(s->contact.len* sizeof(char));
00243         if(dest->contact.s== NULL)
00244         {
00245                 ERR_MEM(SHARE_MEM);
00246         }
00247         memcpy(dest->contact.s, s->contact.s, s->contact.len);
00248         dest->contact.len= s->contact.len;
00249 
00250         return dest;
00251 
00252 error:
00253         if(dest)
00254                         shm_free(dest);
00255         return NULL;
00256 }
00257 
00258 int insert_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs)
00259 {
00260         subs_t* new_rec= NULL;
00261 
00262         new_rec= mem_copy_subs_noc(subs);
00263         if(new_rec== NULL)
00264         {
00265                 LM_ERR("copying in share memory a subs_t structure\n");
00266                 return -1;
00267         }
00268         new_rec->expires+= (int)time(NULL);
00269 
00270         lock_get(&htable[hash_code].lock);
00271         new_rec->next= htable[hash_code].entries->next;
00272         htable[hash_code].entries->next= new_rec;
00273         lock_release(&htable[hash_code].lock);
00274 
00275         return 0;
00276 }
00277 
00278 int delete_shtable(shtable_t htable,unsigned int hash_code,str to_tag)
00279 {
00280         subs_t* s= NULL, *ps= NULL;
00281         int found= -1;
00282 
00283         lock_get(&htable[hash_code].lock);
00284         
00285         ps= htable[hash_code].entries;
00286         s= ps->next;
00287                 
00288         while(s)
00289         {
00290                 if(s->to_tag.len== to_tag.len &&
00291                                 strncmp(s->to_tag.s, to_tag.s, to_tag.len)== 0)
00292                 {
00293                         found= s->local_cseq +1;
00294                         ps->next= s->next;
00295                         if(s->contact.s!=NULL)
00296                                 shm_free(s->contact.s);
00297                         shm_free(s);
00298                         break;
00299                 }
00300                 ps= s;
00301                 s= s->next;
00302         }
00303         lock_release(&htable[hash_code].lock);
00304         return found;
00305 }
00306 
00307 void free_subs_list(subs_t* s_array, int mem_type, int ic)
00308 {
00309         subs_t* s;
00310 
00311         while(s_array)
00312         {
00313                 s= s_array;
00314                 s_array= s_array->next;
00315                 if(mem_type & PKG_MEM_TYPE)
00316                 {
00317                         if(ic)
00318                                 pkg_free(s->contact.s);
00319                         pkg_free(s);
00320                 }
00321                 else
00322                 {
00323                         if(ic)
00324                                 shm_free(s->contact.s);
00325                         shm_free(s);
00326                 }
00327         }
00328         
00329 }
00330 
00331 int update_shtable(shtable_t htable,unsigned int hash_code, 
00332                 subs_t* subs, int type)
00333 {
00334         subs_t* s;
00335 
00336         lock_get(&htable[hash_code].lock);
00337 
00338         s= search_shtable(htable,subs->callid, subs->to_tag, subs->from_tag,
00339                         hash_code);
00340         if(s== NULL)
00341         {
00342                 LM_DBG("record not found in hash table\n");
00343                 lock_release(&htable[hash_code].lock);
00344                 return -1;
00345         }
00346 
00347         if(type & REMOTE_TYPE)
00348         {
00349                 s->expires= subs->expires+ (int)time(NULL);
00350                 s->remote_cseq= subs->remote_cseq;
00351         }
00352         else
00353         {
00354                 subs->local_cseq = ++s->local_cseq;
00355                 subs->version = ++s->version;
00356         }
00357         
00358         if(strncmp(s->contact.s, subs->contact.s, subs->contact.len))
00359         {
00360                 shm_free(s->contact.s);
00361                 s->contact.s= (char*)shm_malloc(subs->contact.len* sizeof(char));
00362                 if(s->contact.s== NULL)
00363                 {
00364                         lock_release(&htable[hash_code].lock);
00365                         LM_ERR("no more shared memory\n");
00366                         return -1;
00367                 }
00368                 memcpy(s->contact.s, subs->contact.s, subs->contact.len);
00369                 s->contact.len= subs->contact.len;
00370         }
00371 
00372         s->status= subs->status;
00373         s->event= subs->event;
00374         subs->db_flag= s->db_flag;
00375 
00376         if(s->db_flag & NO_UPDATEDB_FLAG)
00377                 s->db_flag= UPDATEDB_FLAG;
00378 
00379         lock_release(&htable[hash_code].lock);
00380         
00381         return 0;
00382 }
00383 
00384 phtable_t* new_phtable(void)
00385 {
00386         phtable_t* htable= NULL;
00387         int i, j;
00388 
00389         i = 0;
00390         htable= (phtable_t*)shm_malloc(phtable_size* sizeof(phtable_t));
00391         if(htable== NULL)
00392         {
00393                 ERR_MEM(SHARE_MEM);
00394         }
00395         memset(htable, 0, phtable_size* sizeof(phtable_t));
00396 
00397         for(i= 0; i< phtable_size; i++)
00398         {
00399                 if(lock_init(&htable[i].lock)== 0)
00400                 {
00401                         LM_ERR("initializing lock [%d]\n", i);
00402                         goto error;
00403                 }
00404                 htable[i].entries= (pres_entry_t*)shm_malloc(sizeof(pres_entry_t));
00405                 if(htable[i].entries== NULL)
00406                 {
00407                         ERR_MEM(SHARE_MEM);
00408                 }
00409                 memset(htable[i].entries, 0, sizeof(pres_entry_t));
00410                 htable[i].entries->next= NULL;
00411         }
00412 
00413         return htable;
00414 
00415 error:
00416         if(htable)
00417         {
00418                 for(j=0; j< i; j++)
00419                 {
00420                         if(htable[i].entries)
00421                                 shm_free(htable[i].entries);
00422                         else 
00423                                 break;
00424                         lock_destroy(&htable[i].lock);
00425                 }
00426                 shm_free(htable);
00427         }
00428         return NULL;
00429 
00430 }
00431 
00432 void destroy_phtable(void)
00433 {
00434         int i;
00435         pres_entry_t* p, *prev_p;
00436 
00437         if(pres_htable== NULL)
00438                 return;
00439 
00440         for(i= 0; i< phtable_size; i++)
00441         {
00442                 lock_destroy(&pres_htable[i].lock);
00443                 p= pres_htable[i].entries;
00444                 while(p)
00445                 {
00446                         prev_p= p;
00447                         p= p->next;
00448                         if(prev_p->sphere)
00449                                 shm_free(prev_p->sphere);
00450                         shm_free(prev_p);
00451                 }
00452         }
00453         shm_free(pres_htable);
00454 }
00455 /* entry must be locked before calling this function */
00456 
00457 pres_entry_t* search_phtable(str* pres_uri,int event, unsigned int hash_code)
00458 {
00459         pres_entry_t* p;
00460 
00461         LM_DBG("pres_uri= %.*s\n", pres_uri->len,  pres_uri->s);
00462         p= pres_htable[hash_code].entries->next;
00463         while(p)
00464         {
00465                 if(p->event== event && p->pres_uri.len== pres_uri->len &&
00466                                 strncmp(p->pres_uri.s, pres_uri->s, pres_uri->len)== 0 )
00467                         return p;
00468                 p= p->next;
00469         }
00470         return NULL;
00471 }
00472 
00473 int insert_phtable(str* pres_uri, int event, char* sphere)
00474 {
00475         unsigned int hash_code;
00476         pres_entry_t* p= NULL;
00477         int size;
00478 
00479         hash_code= core_hash(pres_uri, NULL, phtable_size);
00480 
00481         lock_get(&pres_htable[hash_code].lock);
00482         
00483         p= search_phtable(pres_uri, event, hash_code);
00484         if(p)
00485         {
00486                 p->publ_count++;
00487                 lock_release(&pres_htable[hash_code].lock);
00488                 return 0;
00489         }
00490         size= sizeof(pres_entry_t)+ pres_uri->len* sizeof(char);
00491 
00492         p= (pres_entry_t*)shm_malloc(size);
00493         if(p== NULL)
00494         {
00495                 lock_release(&pres_htable[hash_code].lock);
00496                 ERR_MEM(SHARE_MEM);
00497         }
00498         memset(p, 0, size);
00499 
00500         size= sizeof(pres_entry_t);
00501         p->pres_uri.s= (char*)p+ size;
00502         memcpy(p->pres_uri.s, pres_uri->s, pres_uri->len);
00503         p->pres_uri.len= pres_uri->len;
00504         
00505         if(sphere)
00506         {
00507                 p->sphere= (char*)shm_malloc((strlen(sphere)+ 1)*sizeof(char));
00508                 if(p->sphere== NULL)
00509                 {
00510                         lock_release(&pres_htable[hash_code].lock);
00511                         ERR_MEM(SHARE_MEM);
00512                 }
00513                 strcpy(p->sphere, sphere);
00514         }
00515 
00516         p->event= event;
00517         
00518 
00519         p->next= pres_htable[hash_code].entries->next;
00520         pres_htable[hash_code].entries->next= p;
00521 
00522         lock_release(&pres_htable[hash_code].lock);
00523         
00524         return 0;
00525 
00526 error:
00527         return -1;
00528 }
00529 
00530 int delete_phtable(str* pres_uri, int event)
00531 {
00532         unsigned int hash_code;
00533         pres_entry_t* p= NULL, *prev_p= NULL;
00534 
00535         hash_code= core_hash(pres_uri, NULL, phtable_size);
00536 
00537         lock_get(&pres_htable[hash_code].lock);
00538         
00539         p= search_phtable(pres_uri, event, hash_code);
00540         if(p== NULL)
00541         {
00542                 LM_DBG("record not found\n");
00543                 lock_release(&pres_htable[hash_code].lock);
00544                 return 0;
00545         }
00546         
00547         p->publ_count--;
00548         if(p->publ_count== 0)
00549         {
00550                 /* delete record */     
00551                 prev_p= pres_htable[hash_code].entries;
00552                 while(prev_p->next)
00553                 {
00554                         if(prev_p->next== p)
00555                                 break;
00556                         prev_p= prev_p->next;
00557                 }
00558                 if(prev_p->next== NULL)
00559                 {
00560                         LM_ERR("record not found\n");
00561                         lock_release(&pres_htable[hash_code].lock);
00562                         return -1;
00563                 }
00564                 prev_p->next= p->next;
00565                 if(p->sphere)
00566                         shm_free(p->sphere);
00567 
00568                 shm_free(p);
00569         }
00570         lock_release(&pres_htable[hash_code].lock);
00571 
00572         return 0;       
00573 }
00574 
00575 int update_phtable(presentity_t* presentity, str pres_uri, str body)
00576 {
00577         char* sphere= NULL;
00578         unsigned int hash_code;
00579         pres_entry_t* p;
00580         int ret= 0;
00581         str* xcap_doc= NULL;
00582 
00583         /* get new sphere */
00584         sphere= extract_sphere(body);
00585         if(sphere==NULL)
00586         {
00587                 LM_DBG("no sphere defined in new body\n");
00588                 return 0;
00589         }
00590 
00591         /* search for record in hash table */
00592         hash_code= core_hash(&pres_uri, NULL, phtable_size);
00593         
00594         lock_get(&pres_htable[hash_code].lock);
00595 
00596         p= search_phtable(&pres_uri, presentity->event->evp->type, hash_code);
00597         if(p== NULL)
00598         {
00599                 lock_release(&pres_htable[hash_code].lock);
00600                 goto done;
00601         }
00602         
00603         if(p->sphere)
00604         {
00605                 if(strcmp(p->sphere, sphere)!= 0)
00606                 {
00607                         /* new sphere definition */
00608                         shm_free(p->sphere);
00609                 }
00610                 else
00611                 {
00612                         /* no change in sphere definition */
00613                         lock_release(&pres_htable[hash_code].lock);
00614                         pkg_free(sphere);
00615                         return 0;
00616                 }
00617         
00618         }
00619 
00620 
00621         p->sphere= (char*)shm_malloc((strlen(sphere)+ 1)*sizeof(char));
00622         if(p->sphere== NULL)
00623         {
00624                 lock_release(&pres_htable[hash_code].lock);
00625                 ret= -1;
00626                 goto done;
00627         }
00628         strcpy(p->sphere, sphere);
00629                 
00630         lock_release(&pres_htable[hash_code].lock);
00631 
00632         /* call for watchers status update */
00633 
00634         if(presentity->event->get_rules_doc(&presentity->user, &presentity->domain,
00635                                 &xcap_doc)< 0)
00636         {
00637                 LM_ERR("failed to retreive xcap document\n");
00638                 ret= -1;
00639                 goto done;
00640         }
00641 
00642         update_watchers_status(pres_uri, presentity->event, xcap_doc);
00643 
00644 
00645 done:
00646 
00647         if(xcap_doc)
00648         {
00649                 if(xcap_doc->s)
00650                         pkg_free(xcap_doc->s);
00651                 pkg_free(xcap_doc);
00652         }
00653 
00654         if(sphere)
00655                 pkg_free(sphere);
00656         return ret;
00657 }