h_table.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of SIP-router, a free SIP server.
00007  *
00008  * SIP-router is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * SIP-router is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History
00023  * -------
00024  * 2003-03-06  200/INV to-tag list deallocation added;
00025  *             setting "kill_reason" moved in here -- it is moved
00026  *             from transaction state to a static var(jiri)
00027  * 2003-03-16  removed _TOTAG (jiri)
00028  * 2003-03-30  set_kr for requests only (jiri)
00029  * 2003-04-04  bug_fix: REQ_IN callback not called for local 
00030  *             UAC transactions (jiri)
00031  * 2003-09-12  timer_link->tg will be set only if EXTRA_DEBUG (andrei)
00032  * 2003-12-04  global callbacks replaceed with callbacks per transaction;
00033  *             completion callback merged into them as LOCAL_COMPETED (bogdan)
00034  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
00035  * 2004-02-13  t->is_invite and t->local replaced with flags;
00036  *             timer_link.payload removed (bogdan)
00037  * 2004-08-23  avp support added - move and remove avp list to/from
00038  *             transactions (bogdan)
00039  * 2006-08-11  dns failover support (andrei)
00040  * 2007-05-16  callbacks called on destroy (andrei)
00041  * 2007-06-06  don't allocate extra space for md5 if not used: syn_branch==1 
00042  *              (andrei)
00043  * 2007-06-06  switched tm bucket list to a simpler and faster clist (andrei)
00044  */
00045 
00052 #include <stdlib.h>
00053 
00054 
00055 #include "../../mem/shm_mem.h"
00056 #include "../../hash_func.h"
00057 #include "../../dprint.h"
00058 #include "../../md5utils.h"
00059 #include "../../ut.h"
00060 #include "../../globals.h"
00061 #include "../../error.h"
00062 #include "../../char_msg_val.h"
00063 #include "defs.h"
00064 #include "t_reply.h"
00065 #include "t_cancel.h"
00066 #include "t_stats.h"
00067 #include "h_table.h"
00068 #include "../../fix_lumps.h" /* free_via_clen_lump */
00069 #include "timer.h"
00070 #include "uac.h" /* free_local_ack */
00071 
00072 
00073 static enum kill_reason kr;
00074 
00075 /* pointer to the big table where all the transaction data
00076    lives */
00077 struct s_table*  _tm_table;
00078 
00079 struct s_table* tm_get_table(void) {
00080         return _tm_table;
00081 }
00082 
00083 void reset_kr(void) {
00084         kr=0;
00085 }
00086 
00087 void set_kr( enum kill_reason _kr )
00088 {
00089         kr|=_kr;
00090 }
00091 
00092 
00093 enum kill_reason get_kr() {
00094         return kr;
00095 }
00096 
00097 
00098 void lock_hash(int i) 
00099 {
00100 
00101         int mypid;
00102 
00103         mypid = my_pid();
00104         if (likely(atomic_get(&_tm_table->entries[i].locker_pid) != mypid)) {
00105                 lock(&_tm_table->entries[i].mutex);
00106                 atomic_set(&_tm_table->entries[i].locker_pid, mypid);
00107         } else {
00108                 /* locked within the same process that called us*/
00109                 _tm_table->entries[i].rec_lock_level++;
00110         }
00111 }
00112 
00113 
00114 void unlock_hash(int i) 
00115 {
00116         if (likely(_tm_table->entries[i].rec_lock_level == 0)) {
00117                 atomic_set(&_tm_table->entries[i].locker_pid, 0);
00118                 unlock(&_tm_table->entries[i].mutex);
00119         } else  {
00120                 /* recursive locked => decrease rec. lock count */
00121                 _tm_table->entries[i].rec_lock_level--;
00122         }
00123 }
00124 
00125 
00126 
00127 #ifdef TM_HASH_STATS
00128 unsigned int transaction_count( void )
00129 {
00130         unsigned int i;
00131         unsigned int count;
00132 
00133         count=0;        
00134         for (i=0; i<TABLE_ENTRIES; i++) 
00135                 count+=_tm_table->entries[i].cur_entries;
00136         return count;
00137 }
00138 #endif
00139 
00140 
00141 
00142 void free_cell( struct cell* dead_cell )
00143 {
00144         char *b;
00145         int i;
00146         struct sip_msg *rpl;
00147         struct totag_elem *tt, *foo;
00148         struct tm_callback *cbs, *cbs_tmp;
00149 
00150         release_cell_lock( dead_cell );
00151         if (unlikely(has_tran_tmcbs(dead_cell, TMCB_DESTROY)))
00152                 run_trans_callbacks(TMCB_DESTROY, dead_cell, 0, 0, 0);
00153 
00154         shm_lock();
00155         /* UA Server */
00156         if ( dead_cell->uas.request )
00157                 sip_msg_free_unsafe( dead_cell->uas.request );
00158         if ( dead_cell->uas.response.buffer )
00159                 shm_free_unsafe( dead_cell->uas.response.buffer );
00160 #ifdef CANCEL_REASON_SUPPORT
00161         if (unlikely(dead_cell->uas.cancel_reas))
00162                 shm_free_unsafe(dead_cell->uas.cancel_reas);
00163 #endif /* CANCEL_REASON_SUPPORT */
00164 
00165         /* callbacks */
00166         for( cbs=(struct tm_callback*)dead_cell->tmcb_hl.first ; cbs ; ) {
00167                 cbs_tmp = cbs;
00168                 cbs = cbs->next;
00169                 if (cbs_tmp->release) {
00170                         /* It is safer to release the shm memory lock
00171                          * otherwise the release function must to be aware of
00172                          * the lock state (Miklos)
00173                          */
00174                         shm_unlock();
00175                         cbs_tmp->release(cbs_tmp->param);
00176                         shm_lock();
00177                 }
00178                 shm_free_unsafe( cbs_tmp );
00179         }
00180 
00181         /* UA Clients */
00182         for ( i =0 ; i<dead_cell->nr_of_outgoings;  i++ )
00183         {
00184                 /* retransmission buffer */
00185                 if ( (b=dead_cell->uac[i].request.buffer) )
00186                         shm_free_unsafe( b );
00187                 b=dead_cell->uac[i].local_cancel.buffer;
00188                 if (b!=0 && b!=BUSY_BUFFER)
00189                         shm_free_unsafe( b );
00190                 rpl=dead_cell->uac[i].reply;
00191                 if (rpl && rpl!=FAKED_REPLY && rpl->msg_flags&FL_SHM_CLONE) {
00192                         sip_msg_free_unsafe( rpl );
00193                 }
00194 #ifdef USE_DNS_FAILOVER
00195                 if (dead_cell->uac[i].dns_h.a){
00196                         DBG("branch %d -> dns_h.srv (%.*s) ref=%d,"
00197                                                         " dns_h.a (%.*s) ref=%d\n", i,
00198                                         dead_cell->uac[i].dns_h.srv?
00199                                                                 dead_cell->uac[i].dns_h.srv->name_len:0,
00200                                         dead_cell->uac[i].dns_h.srv?
00201                                                                 dead_cell->uac[i].dns_h.srv->name:"",
00202                                         dead_cell->uac[i].dns_h.srv?
00203                                                                 dead_cell->uac[i].dns_h.srv->refcnt.val:0,
00204                                         dead_cell->uac[i].dns_h.a->name_len,
00205                                         dead_cell->uac[i].dns_h.a->name,
00206                                         dead_cell->uac[i].dns_h.a->refcnt.val);
00207                 }
00208                 dns_srv_handle_put_shm_unsafe(&dead_cell->uac[i].dns_h);
00209 #endif
00210                 if (unlikely(dead_cell->uac[i].path.s)) {
00211                         shm_free_unsafe(dead_cell->uac[i].path.s);
00212                 }
00213         }
00214 
00215 #ifdef WITH_AS_SUPPORT
00216         if (dead_cell->uac[0].local_ack)
00217                 free_local_ack_unsafe(dead_cell->uac[0].local_ack);
00218 #endif
00219 
00220         /* collected to tags */
00221         tt=dead_cell->fwded_totags;
00222         while(tt) {
00223                 foo=tt->next;
00224                 shm_free_unsafe(tt->tag.s);
00225                 shm_free_unsafe(tt);
00226                 tt=foo;
00227         }
00228 
00229         /* free the avp list */
00230         if (dead_cell->user_avps_from)
00231                 destroy_avp_list_unsafe( &dead_cell->user_avps_from );
00232         if (dead_cell->user_avps_to)
00233                 destroy_avp_list_unsafe( &dead_cell->user_avps_to );
00234         if (dead_cell->uri_avps_from)
00235                 destroy_avp_list_unsafe( &dead_cell->uri_avps_from );
00236         if (dead_cell->uri_avps_to)
00237                 destroy_avp_list_unsafe( &dead_cell->uri_avps_to );
00238 #ifdef WITH_XAVP
00239         if (dead_cell->xavps_list)
00240                 xavp_destroy_list_unsafe( &dead_cell->xavps_list );
00241 #endif
00242 
00243         /* the cell's body */
00244         shm_free_unsafe( dead_cell );
00245 
00246         shm_unlock();
00247         t_stats_freed();
00248 }
00249 
00250 
00251 
00252 static inline void init_synonym_id( struct cell *t )
00253 {
00254         struct sip_msg *p_msg;
00255         int size;
00256         char *c;
00257         unsigned int myrand;
00258 
00259         if (!syn_branch) {
00260                 p_msg=t->uas.request;
00261                 if (p_msg) {
00262                         /* char value of a proxied transaction is
00263                            calculated out of header-fields forming
00264                            transaction key
00265                         */
00266                         char_msg_val( p_msg, t->md5 );
00267                 } else {
00268                         /* char value for a UAC transaction is created
00269                            randomly -- UAC is an originating stateful element 
00270                            which cannot be refreshed, so the value can be
00271                            anything
00272                         */
00273                         /* HACK : not long enough */
00274                         myrand=rand();
00275                         c=t->md5;
00276                         size=MD5_LEN;
00277                         memset(c, '0', size );
00278                         int2reverse_hex( &c, &size, myrand );
00279                 }
00280         }
00281 }
00282 
00283 static void inline init_branches(struct cell *t)
00284 {
00285         unsigned int i;
00286         struct ua_client *uac;
00287 
00288         for(i=0;i<MAX_BRANCHES;i++)
00289         {
00290                 uac=&t->uac[i];
00291                 uac->request.my_T = t;
00292                 uac->request.branch = i;
00293                 init_rb_timers(&uac->request);
00294                 uac->local_cancel=uac->request;
00295 #ifdef USE_DNS_FAILOVER
00296                 dns_srv_handle_init(&uac->dns_h);
00297 #endif
00298         }
00299 }
00300 
00301 
00302 struct cell*  build_cell( struct sip_msg* p_msg )
00303 {
00304         struct cell* new_cell;
00305         int          sip_msg_len;
00306         avp_list_t* old;
00307         struct tm_callback *cbs, *cbs_tmp;
00308 #ifdef WITH_XAVP
00309         sr_xavp_t** xold;
00310 #endif
00311 
00312         /* allocs a new cell */
00313         /* if syn_branch==0 add space for md5 (MD5_LEN -sizeof(struct cell.md5)) */
00314         new_cell = (struct cell*)shm_malloc( sizeof( struct cell )+
00315                         ((MD5_LEN-sizeof(((struct cell*)0)->md5))&((syn_branch!=0)-1)) );
00316         if  ( !new_cell ) {
00317                 ser_error=E_OUT_OF_MEM;
00318                 return NULL;
00319         }
00320 
00321         /* filling with 0 */
00322         memset( new_cell, 0, sizeof( struct cell ) );
00323 
00324         /* UAS */
00325         new_cell->uas.response.my_T=new_cell;
00326         init_rb_timers(&new_cell->uas.response);
00327         /* timers */
00328         init_cell_timers(new_cell);
00329 
00330         old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, 
00331                         &new_cell->uri_avps_from );
00332         new_cell->uri_avps_from = *old;
00333         *old = 0;
00334 
00335         old = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, 
00336                         &new_cell->uri_avps_to );
00337         new_cell->uri_avps_to = *old;
00338         *old = 0;
00339 
00340         old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, 
00341                         &new_cell->user_avps_from );
00342         new_cell->user_avps_from = *old;
00343         *old = 0;
00344 
00345         old = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, 
00346                         &new_cell->user_avps_to );
00347         new_cell->user_avps_to = *old;
00348         *old = 0;
00349 
00350 #ifdef WITH_XAVP
00351         xold = xavp_set_list(&new_cell->xavps_list );
00352         new_cell->xavps_list = *xold;
00353         *xold = 0;
00354 #endif
00355 
00356              /* We can just store pointer to domain avps in the transaction context,
00357               * because they are read-only
00358               */
00359         new_cell->domain_avps_from = get_avp_list(AVP_TRACK_FROM | 
00360                                                                 AVP_CLASS_DOMAIN);
00361         new_cell->domain_avps_to = get_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN);
00362 
00363         /* enter callback, which may potentially want to parse some stuff,
00364          * before the request is shmem-ized */
00365         if (p_msg) {
00366                 set_early_tmcb_list(p_msg, new_cell);
00367                 if(has_reqin_tmcbs())
00368                         run_reqin_callbacks( new_cell, p_msg, p_msg->REQ_METHOD);
00369         }
00370 
00371         if (p_msg) {
00372                 new_cell->uas.request = sip_msg_cloner(p_msg,&sip_msg_len);
00373                 if (!new_cell->uas.request)
00374                         goto error;
00375                 new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len;
00376         }
00377 
00378         /* UAC */
00379         init_branches(new_cell);
00380 
00381         new_cell->relayed_reply_branch   = -1;
00382         /* new_cell->T_canceled = T_UNDEFINED; */
00383 
00384         init_synonym_id(new_cell);
00385         init_cell_lock(  new_cell );
00386         t_stats_created();
00387         return new_cell;
00388 
00389 error:
00390         /* Other modules may have already registered some
00391          * transaction callbacks and may also allocated
00392          * additional memory for their parameters,
00393          * hence TMCB_DESTROY needs to be called. (Miklos)
00394          */
00395         if (unlikely(has_tran_tmcbs(new_cell, TMCB_DESTROY)))
00396                 run_trans_callbacks(TMCB_DESTROY, new_cell, 0, 0, 0);
00397 
00398         /* free the callback list */
00399         for( cbs=(struct tm_callback*)new_cell->tmcb_hl.first ; cbs ; ) {
00400                 cbs_tmp = cbs;
00401                 cbs = cbs->next;
00402                 if (cbs_tmp->release) {
00403                         cbs_tmp->release(cbs_tmp->param);
00404                 }
00405                 shm_free( cbs_tmp );
00406         }
00407         
00408         destroy_avp_list(&new_cell->user_avps_from);
00409         destroy_avp_list(&new_cell->user_avps_to);
00410         destroy_avp_list(&new_cell->uri_avps_from);
00411         destroy_avp_list(&new_cell->uri_avps_to);
00412 #ifdef WITH_XAVP
00413         xavp_destroy_list(&new_cell->xavps_list);
00414 #endif
00415         shm_free(new_cell);
00416         /* unlink transaction AVP list and link back the global AVP list (bogdan)*/
00417         reset_avps();
00418 #ifdef WITH_XAVP
00419         xavp_reset_list();
00420 #endif
00421         return NULL;
00422 }
00423 
00424 
00425 
00426 /* Release all the data contained by the hash table. All the aux. structures
00427  *  as sems, lists, etc, are also released */
00428 void free_hash_table(  )
00429 {
00430         struct cell* p_cell;
00431         struct cell* tmp_cell;
00432         int    i;
00433 
00434         if (_tm_table)
00435         {
00436                 /* remove the data contained by each entry */
00437                 for( i = 0 ; i<TABLE_ENTRIES; i++)
00438                 {
00439                         release_entry_lock( (_tm_table->entries)+i );
00440                         /* delete all synonyms at hash-collision-slot i */
00441                         clist_foreach_safe(&_tm_table->entries[i], p_cell, tmp_cell,
00442                                                                         next_c){
00443                                 free_cell(p_cell);
00444                         }
00445                 }
00446                 shm_free(_tm_table);
00447                 _tm_table = 0;
00448         }
00449 }
00450 
00451 
00452 
00453 
00454 /*
00455  */
00456 struct s_table* init_hash_table()
00457 {
00458         int              i;
00459 
00460         /*allocs the table*/
00461         _tm_table= (struct s_table*)shm_malloc( sizeof( struct s_table ) );
00462         if ( !_tm_table) {
00463                 LOG(L_ERR, "ERROR: init_hash_table: no shmem for TM table\n");
00464                 goto error0;
00465         }
00466 
00467         memset( _tm_table, 0, sizeof (struct s_table ) );
00468 
00469         /* try first allocating all the structures needed for syncing */
00470         if (lock_initialize()==-1)
00471                 goto error1;
00472 
00473         /* inits the entriess */
00474         for(  i=0 ; i<TABLE_ENTRIES; i++ )
00475         {
00476                 init_entry_lock( _tm_table, (_tm_table->entries)+i );
00477                 _tm_table->entries[i].next_label = rand();
00478                 /* init cell list */
00479                 clist_init(&_tm_table->entries[i], next_c, prev_c);
00480         }
00481 
00482         return  _tm_table;
00483 
00484 error1:
00485         free_hash_table( );
00486 error0:
00487         return 0;
00488 }
00489 
00490 
00496 void tm_xdata_swap(tm_cell_t *t, tm_xlinks_t *xd, int mode)
00497 {
00498         static tm_xlinks_t _txdata;
00499         tm_xlinks_t *x;
00500 
00501         if(xd==NULL)
00502                 x = &_txdata;
00503         else
00504                 x = xd;
00505 
00506         if(mode==0) {
00507                 if(t==NULL)
00508                         return;
00509                 x->uri_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from );
00510                 x->uri_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to );
00511                 x->user_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from );
00512                 x->user_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to );
00513                 x->domain_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from );
00514                 x->domain_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to );
00515 #ifdef WITH_XAVP
00516                 x->xavps_list = xavp_set_list(&t->xavps_list);
00517 #endif
00518         } else if(mode==1) {
00519                 /* restore original avp list */
00520                 set_avp_list( AVP_TRACK_FROM | AVP_CLASS_URI, x->uri_avps_from );
00521                 set_avp_list( AVP_TRACK_TO | AVP_CLASS_URI, x->uri_avps_to );
00522                 set_avp_list( AVP_TRACK_FROM | AVP_CLASS_USER, x->user_avps_from );
00523                 set_avp_list( AVP_TRACK_TO | AVP_CLASS_USER, x->user_avps_to );
00524                 set_avp_list( AVP_TRACK_FROM | AVP_CLASS_DOMAIN, x->domain_avps_from );
00525                 set_avp_list( AVP_TRACK_TO | AVP_CLASS_DOMAIN, x->domain_avps_to );
00526 #ifdef WITH_XAVP
00527                 xavp_set_list(x->xavps_list);
00528 #endif
00529         }
00530 
00531 }
00532 
00536 void tm_xdata_replace(tm_xdata_t *newxd, tm_xlinks_t *bakxd)
00537 {
00538         if(newxd==NULL && bakxd!=NULL) {
00539                 set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, bakxd->uri_avps_from);
00540                 set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, bakxd->uri_avps_to);
00541                 set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, bakxd->user_avps_from);
00542                 set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, bakxd->user_avps_to);
00543                 set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, bakxd->domain_avps_from);
00544                 set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, bakxd->domain_avps_to);
00545 #ifdef WITH_XAVP
00546                 xavp_set_list(bakxd->xavps_list);
00547 #endif
00548                 return;
00549         }
00550 
00551         if(newxd!=NULL && bakxd!=NULL) {
00552                 bakxd->uri_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI,
00553                                 &newxd->uri_avps_from);
00554                 bakxd->uri_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI,
00555                                 &newxd->uri_avps_to);
00556                 bakxd->user_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER,
00557                                 &newxd->user_avps_from);
00558                 bakxd->user_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER,
00559                                 &newxd->user_avps_to);
00560                 bakxd->domain_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN,
00561                                 &newxd->domain_avps_from);
00562                 bakxd->domain_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN,
00563                                 &newxd->domain_avps_to);
00564 #ifdef WITH_XAVP
00565                 bakxd->xavps_list = xavp_set_list(&newxd->xavps_list);
00566 #endif
00567                 return;
00568         }
00569 }