h_table.c

Go to the documentation of this file.
00001 /*
00002  * $Id: h_table.c 5666 2009-03-03 12:13:46Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio 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  * Kamailio 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  * 2007-01-25  DNS failover at transaction level added (bogdan)
00040  */
00041 
00042 /*! \file
00043  * \brief TM :: Hash tables
00044  *
00045  * \ingroup tm
00046  * - Module: \ref tm
00047  */
00048 
00049 
00050 #include <stdlib.h>
00051 
00052 
00053 #include "../../mem/shm_mem.h"
00054 #include "../../hash_func.h"
00055 #include "../../dprint.h"
00056 #include "../../md5utils.h"
00057 #include "../../ut.h"
00058 #include "../../error.h"
00059 #include "t_reply.h"
00060 #include "t_cancel.h"
00061 #include "t_stats.h"
00062 #include "h_table.h"
00063 #include "fix_lumps.h" /* free_via_clen_lump */
00064 #include "t_hooks.h"
00065 #include "t_fwd.h"
00066 
00067 static enum kill_reason kr;
00068 
00069 /*! \brief pointer to the big table where all the transaction data
00070    lives */
00071 static struct s_table*  tm_table;
00072 
00073 int syn_branch = 1;
00074 
00075 
00076 void reset_kr(void)
00077 {
00078    kr = 0;
00079 }
00080 
00081 void set_kr( enum kill_reason _kr )
00082 {
00083    kr|=_kr;
00084 }
00085 
00086 
00087 enum kill_reason get_kr(void) {
00088    return kr;
00089 }
00090 
00091 
00092 void lock_hash(int i) 
00093 {
00094    lock(&tm_table->entrys[i].mutex);
00095 }
00096 
00097 
00098 void unlock_hash(int i) 
00099 {
00100    unlock(&tm_table->entrys[i].mutex);
00101 }
00102 
00103 
00104 struct s_table* get_tm_table(void)
00105 {
00106    return tm_table;
00107 }
00108 
00109 
00110 unsigned int transaction_count( void )
00111 {
00112    unsigned int i;
00113    unsigned int count;
00114 
00115    count=0; 
00116    for (i=0; i<TM_TABLE_ENTRIES; i++) 
00117       count+=tm_table->entrys[i].cur_entries;
00118    return count;
00119 }
00120 
00121 
00122 
00123 void free_cell( struct cell* dead_cell )
00124 {
00125    char *b;
00126    int i;
00127    struct sip_msg *rpl;
00128    struct totag_elem *tt, *foo;
00129    struct proxy_l *p;
00130 
00131    if ( has_tran_tmcbs( dead_cell, TMCB_TRANS_DELETED) )
00132       run_trans_callbacks( TMCB_TRANS_DELETED, dead_cell, 0, 0, 0);
00133 
00134    empty_tmcb_list(&dead_cell->tmcb_hl);
00135 
00136    shm_lock();
00137 
00138    /* UA Server */
00139    if ( dead_cell->uas.request )
00140       sip_msg_free_unsafe( dead_cell->uas.request );
00141    if ( dead_cell->uas.response.buffer.s )
00142       shm_free_unsafe( dead_cell->uas.response.buffer.s );
00143 
00144    /* UA Clients */
00145    for ( i =0 ; i<dead_cell->nr_of_outgoings;  i++ )
00146    {
00147       /* retransmission buffer */
00148       if ( (b=dead_cell->uac[i].request.buffer.s) )
00149          shm_free_unsafe( b );
00150       b=dead_cell->uac[i].local_cancel.buffer.s;
00151       if (b!=0 && b!=BUSY_BUFFER)
00152          shm_free_unsafe( b );
00153       rpl=dead_cell->uac[i].reply;
00154       if (rpl && rpl!=FAKED_REPLY && rpl->msg_flags&FL_SHM_CLONE) {
00155          sip_msg_free_unsafe( rpl );
00156       }
00157       if ( (p=dead_cell->uac[i].proxy)!=NULL ) {
00158          if ( p->host.h_addr_list )
00159             shm_free_unsafe( p->host.h_addr_list );
00160          if ( p->dn ) {
00161             if ( p->dn->kids )
00162                shm_free_unsafe( p->dn->kids );
00163             shm_free_unsafe( p->dn );
00164          }
00165          shm_free_unsafe(p);
00166       }
00167       if (dead_cell->uac[i].path_vec.s) {
00168          shm_free_unsafe(dead_cell->uac[i].path_vec.s);
00169       }
00170    }
00171 
00172    /* collected to tags */
00173    tt=dead_cell->fwded_totags;
00174    while(tt) {
00175       foo=tt->next;
00176       shm_free_unsafe(tt->tag.s);
00177       shm_free_unsafe(tt);
00178       tt=foo;
00179    }
00180 
00181    /* free the avp list */
00182    if (dead_cell->user_avps)
00183       destroy_avp_list_unsafe( &dead_cell->user_avps );
00184 
00185    /* the cell's body */
00186    shm_free_unsafe( dead_cell );
00187 
00188    shm_unlock();
00189 }
00190 
00191 
00192 
00193 static inline void init_synonym_id( struct cell *t )
00194 {
00195    struct sip_msg *p_msg;
00196    int size;
00197    char *c;
00198    unsigned int myrand;
00199 
00200    if (!syn_branch) {
00201       p_msg=t->uas.request;
00202       if (p_msg) {
00203          /* char value of a proxied transaction is
00204             calculated out of header-fields forming
00205             transaction key
00206          */
00207          char_msg_val( p_msg, t->md5 );
00208       } else {
00209          /* char value for a UAC transaction is created
00210             randomly -- UAC is an originating stateful element 
00211             which cannot be refreshed, so the value can be
00212             anything
00213          */
00214          /* HACK : not long enough */
00215          myrand=rand();
00216          c=t->md5;
00217          size=MD5_LEN;
00218          memset(c, '0', size );
00219          int2reverse_hex( &c, &size, myrand );
00220       }
00221    }
00222 }
00223 
00224 static inline void init_branches(struct cell *t)
00225 {
00226    unsigned int i;
00227    struct ua_client *uac;
00228 
00229    for(i=0;i<MAX_BRANCHES;i++)
00230    {
00231       uac=&t->uac[i];
00232       uac->request.my_T = t;
00233       uac->request.branch = i;
00234 #ifdef EXTRA_DEBUG
00235       uac->request.fr_timer.tg = TG_FR;
00236       uac->request.retr_timer.tg = TG_RT;
00237 #endif
00238       uac->local_cancel=uac->request;
00239    }
00240 }
00241 
00242 
00243 struct cell*  build_cell( struct sip_msg* p_msg )
00244 {
00245    struct cell* new_cell;
00246    int          sip_msg_len;
00247    struct usr_avp **old;
00248    struct tm_callback *cbs, *cbs_tmp;
00249 
00250    /* allocs a new cell */
00251    new_cell = (struct cell*)shm_malloc( sizeof( struct cell ) );
00252    if  ( !new_cell ) {
00253       ser_error=E_OUT_OF_MEM;
00254       return NULL;
00255    }
00256 
00257    /* filling with 0 */
00258    memset( new_cell, 0, sizeof( struct cell ) );
00259 
00260    /* UAS */
00261 #ifdef EXTRA_DEBUG
00262    new_cell->uas.response.retr_timer.tg=TG_RT;
00263    new_cell->uas.response.fr_timer.tg=TG_FR;
00264 #endif
00265    new_cell->uas.response.my_T=new_cell;
00266 
00267    /* dcm: - local generation transactions should not inherit AVPs 
00268     * - commpletely new message */
00269    if(p_msg) {
00270       /* move the current avp list to transaction -bogdan */
00271       old = set_avp_list( &new_cell->user_avps );
00272       new_cell->user_avps = *old;
00273       *old = 0;
00274 
00275       /* move the pending callbacks to transaction -bogdan */
00276       if (p_msg->id==tmcb_pending_id) {
00277          new_cell->tmcb_hl = tmcb_pending_hl;
00278          tmcb_pending_hl.first = 0;
00279       }
00280 
00281       /* enter callback, which may potentially want to parse some stuff,
00282        * before the request is shmem-ized */
00283       if (has_reqin_tmcbs() )
00284          run_reqin_callbacks( new_cell, p_msg, p_msg->REQ_METHOD);
00285 
00286       /* clean possible previous added vias/clen header or else they would
00287        * get propagated in the failure routes */
00288       free_via_clen_lump(&p_msg->add_rm);
00289       new_cell->uas.request = sip_msg_cloner(p_msg,&sip_msg_len);
00290       if (!new_cell->uas.request)
00291          goto error;
00292       new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len;
00293    }
00294 
00295    /* UAC */
00296    init_branches(new_cell);
00297 
00298    new_cell->relayed_reply_branch   = -1;
00299    /* new_cell->T_canceled = T_UNDEFINED; */
00300 #ifdef EXTRA_DEBUG
00301    new_cell->wait_tl.tg=TG_WT;
00302    new_cell->dele_tl.tg=TG_DEL;
00303 #endif
00304 
00305    init_synonym_id(new_cell);
00306    init_cell_lock(  new_cell );
00307    return new_cell;
00308 
00309 error:
00310    if (new_cell->user_avps)
00311       destroy_avp_list( &new_cell->user_avps );
00312    if (new_cell->tmcb_hl.first) {
00313       for( cbs=new_cell->tmcb_hl.first ; cbs ; ) {
00314          cbs_tmp = cbs;
00315          cbs = cbs->next;
00316          shm_free( cbs_tmp );
00317       }
00318    }
00319    shm_free(new_cell);
00320    /* unlink transaction AVP list and link back the global AVP list (bogdan)*/
00321    reset_avps();
00322    return NULL;
00323 }
00324 
00325 
00326 
00327 /*! \brief Release all the data contained by the hash table. All the aux. structures
00328  *  as sems, lists, etc, are also released */
00329 void free_hash_table(void)
00330 {
00331    struct cell* p_cell;
00332    struct cell* tmp_cell;
00333    int    i;
00334 
00335    if (tm_table)
00336    {
00337       /* remove the data contained by each entry */
00338       for( i = 0 ; i<TM_TABLE_ENTRIES; i++)
00339       {
00340          /* delete all synonyms at hash-collision-slot i */
00341          p_cell=tm_table->entrys[i].first_cell;
00342          for( ; p_cell; p_cell = tmp_cell )
00343          {
00344             tmp_cell = p_cell->next_cell;
00345             free_cell( p_cell );
00346          }
00347       }
00348       shm_free(tm_table);
00349    }
00350 }
00351 
00352 
00353 /*
00354  */
00355 struct s_table* init_hash_table(void)
00356 {
00357    int              i;
00358 
00359    /*allocs the table*/
00360    tm_table= (struct s_table*)shm_malloc( sizeof( struct s_table ) );
00361    if ( !tm_table) {
00362       LM_ERR("no more share memory\n");
00363       goto error0;
00364    }
00365 
00366    memset( tm_table, 0, sizeof (struct s_table ) );
00367 
00368    /* try first allocating all the structures needed for syncing */
00369    if (lock_initialize()==-1)
00370       goto error1;
00371 
00372    /* inits the entrys */
00373    for(  i=0 ; i<TM_TABLE_ENTRIES; i++ )
00374    {
00375       init_entry_lock( tm_table, (tm_table->entrys)+i );
00376       tm_table->entrys[i].next_label = rand();
00377    }
00378 
00379    return  tm_table;
00380 
00381 error1:
00382    free_hash_table( );
00383 error0:
00384    return 0;
00385 }
00386 
00387 
00388 /*! \brief  Takes an already created cell and links it into hash table on the
00389  *  appropriate entry. */
00390 void insert_into_hash_table_unsafe( struct cell * p_cell, unsigned int _hash )
00391 {
00392    struct entry* p_entry;
00393 
00394    p_cell->hash_index=_hash;
00395 
00396    /* locates the appropriate entry */
00397    p_entry = &tm_table->entrys[ _hash ];
00398 
00399    p_cell->label = p_entry->next_label++;
00400    if ( p_entry->last_cell )
00401    {
00402       p_entry->last_cell->next_cell = p_cell;
00403       p_cell->prev_cell = p_entry->last_cell;
00404    } else p_entry->first_cell = p_cell;
00405 
00406    p_entry->last_cell = p_cell;
00407 
00408    /* update stats */
00409    p_entry->cur_entries++;
00410    p_entry->acc_entries++;
00411    stats_trans_new( is_local(p_cell) );
00412 }
00413 
00414 
00415 /*! \brief  Un-link a  cell from hash_table, but the cell itself is not released */
00416 void remove_from_hash_table_unsafe( struct cell * p_cell)
00417 {
00418    struct entry*  p_entry  = &(tm_table->entrys[p_cell->hash_index]);
00419 
00420    if ( p_cell->prev_cell )
00421       p_cell->prev_cell->next_cell = p_cell->next_cell;
00422    else
00423       p_entry->first_cell = p_cell->next_cell;
00424 
00425    if ( p_cell->next_cell )
00426       p_cell->next_cell->prev_cell = p_cell->prev_cell;
00427    else
00428       p_entry->last_cell = p_cell->prev_cell;
00429 # ifdef EXTRA_DEBUG
00430    if (p_entry->cur_entries==0) {
00431       LM_CRIT("bad things happened: cur_entries=0\n");
00432       abort();
00433    }
00434 # endif
00435    /* update stats */
00436    p_entry->cur_entries--;
00437    if_update_stat(tm_enable_stats, tm_trans_inuse , -1 );
00438 }

Generated on Wed May 23 06:00:45 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6