| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- /*
- * $Id$
- *
- * Copyright (C) 2001-2003 FhG Fokus
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * History
- * -------
- * 2003-03-06 200/INV to-tag list deallocation added;
- * setting "kill_reason" moved in here -- it is moved
- * from transaction state to a static var(jiri)
- * 2003-03-16 removed _TOTAG (jiri)
- * 2003-03-30 set_kr for requests only (jiri)
- * 2003-04-04 bug_fix: REQ_IN callback not called for local
- * UAC transactions (jiri)
- * 2003-09-12 timer_link->tg will be set only if EXTRA_DEBUG (andrei)
- * 2003-12-04 global callbacks replaceed with callbacks per transaction;
- * completion callback merged into them as LOCAL_COMPETED (bogdan)
- * 2004-02-11 FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
- * 2004-02-13 t->is_invite and t->local replaced with flags;
- * timer_link.payload removed (bogdan)
- * 2004-08-23 avp support added - move and remove avp list to/from
- * transactions (bogdan)
- */
- #include <stdlib.h>
- #include "../../mem/shm_mem.h"
- #include "../../hash_func.h"
- #include "../../dprint.h"
- #include "../../md5utils.h"
- #include "../../ut.h"
- #include "../../globals.h"
- #include "../../error.h"
- #include "../../fifo_server.h"
- #include "../../unixsock_server.h"
- #include "defs.h"
- #include "t_reply.h"
- #include "t_cancel.h"
- #include "t_stats.h"
- #include "h_table.h"
- #include "fix_lumps.h" /* free_via_clen_lump */
- static enum kill_reason kr;
- /* pointer to the big table where all the transaction data
- lives */
- static struct s_table* tm_table;
- void set_kr( enum kill_reason _kr )
- {
- kr|=_kr;
- }
- enum kill_reason get_kr() {
- return kr;
- }
- void lock_hash(int i)
- {
- lock(&tm_table->entrys[i].mutex);
- }
- void unlock_hash(int i)
- {
- unlock(&tm_table->entrys[i].mutex);
- }
- struct s_table* get_tm_table()
- {
- return tm_table;
- }
- unsigned int transaction_count( void )
- {
- unsigned int i;
- unsigned int count;
- count=0;
- for (i=0; i<TABLE_ENTRIES; i++)
- count+=tm_table->entrys[i].cur_entries;
- return count;
- }
- void free_cell( struct cell* dead_cell )
- {
- char *b;
- int i;
- struct sip_msg *rpl;
- struct totag_elem *tt, *foo;
- struct tm_callback *cbs, *cbs_tmp;
- release_cell_lock( dead_cell );
- shm_lock();
- /* UA Server */
- if ( dead_cell->uas.request )
- sip_msg_free_unsafe( dead_cell->uas.request );
- if ( dead_cell->uas.response.buffer )
- shm_free_unsafe( dead_cell->uas.response.buffer );
- /* callbacks */
- for( cbs=dead_cell->tmcb_hl.first ; cbs ; ) {
- cbs_tmp = cbs;
- cbs = cbs->next;
- shm_free_unsafe( cbs_tmp );
- }
- /* UA Clients */
- for ( i =0 ; i<dead_cell->nr_of_outgoings; i++ )
- {
- /* retransmission buffer */
- if ( (b=dead_cell->uac[i].request.buffer) )
- shm_free_unsafe( b );
- b=dead_cell->uac[i].local_cancel.buffer;
- if (b!=0 && b!=BUSY_BUFFER)
- shm_free_unsafe( b );
- rpl=dead_cell->uac[i].reply;
- if (rpl && rpl!=FAKED_REPLY && rpl->msg_flags&FL_SHM_CLONE) {
- sip_msg_free_unsafe( rpl );
- }
- }
- /* collected to tags */
- tt=dead_cell->fwded_totags;
- while(tt) {
- foo=tt->next;
- shm_free_unsafe(tt->tag.s);
- shm_free_unsafe(tt);
- tt=foo;
- }
- /* free the avp list */
- if (dead_cell->user_avps)
- destroy_avp_list_unsafe( &dead_cell->user_avps );
- /* the cell's body */
- shm_free_unsafe( dead_cell );
- shm_unlock();
- }
- static inline void init_synonym_id( struct cell *t )
- {
- struct sip_msg *p_msg;
- int size;
- char *c;
- unsigned int myrand;
- if (!syn_branch) {
- p_msg=t->uas.request;
- if (p_msg) {
- /* char value of a proxied transaction is
- calculated out of header-fields forming
- transaction key
- */
- char_msg_val( p_msg, t->md5 );
- } else {
- /* char value for a UAC transaction is created
- randomly -- UAC is an originating stateful element
- which cannot be refreshed, so the value can be
- anything
- */
- /* HACK : not long enough */
- myrand=rand();
- c=t->md5;
- size=MD5_LEN;
- memset(c, '0', size );
- int2reverse_hex( &c, &size, myrand );
- }
- }
- }
- static void inline init_branches(struct cell *t)
- {
- unsigned int i;
- struct ua_client *uac;
- for(i=0;i<MAX_BRANCHES;i++)
- {
- uac=&t->uac[i];
- uac->request.my_T = t;
- uac->request.branch = i;
- #ifdef EXTRA_DEBUG
- uac->request.fr_timer.tg = TG_FR;
- uac->request.retr_timer.tg = TG_RT;
- #endif
- uac->local_cancel=uac->request;
- }
- }
- struct cell* build_cell( struct sip_msg* p_msg )
- {
- struct cell* new_cell;
- int sip_msg_len;
- struct usr_avp **old;
- /* allocs a new cell */
- new_cell = (struct cell*)shm_malloc( sizeof( struct cell ) );
- if ( !new_cell ) {
- ser_error=E_OUT_OF_MEM;
- return NULL;
- }
- /* filling with 0 */
- memset( new_cell, 0, sizeof( struct cell ) );
- /* UAS */
- #ifdef EXTRA_DEBUG
- new_cell->uas.response.retr_timer.tg=TG_RT;
- new_cell->uas.response.fr_timer.tg=TG_FR;
- #endif
- new_cell->uas.response.my_T=new_cell;
- /* move the current avp list to transaction -bogdan */
- old = set_avp_list( &new_cell->user_avps );
- new_cell->user_avps = *old;
- *old = 0;
- /* enter callback, which may potentially want to parse some stuff,
- * before the request is shmem-ized */
- if ( p_msg && has_reqin_tmcbs() )
- run_reqin_callbacks( new_cell, p_msg, p_msg->REQ_METHOD);
- if (p_msg) {
- /* clean possible previous added vias/clen header or else they would
- * get propagated in the failure routes */
- free_via_clen_lump(&p_msg->add_rm);
- new_cell->uas.request = sip_msg_cloner(p_msg,&sip_msg_len);
- if (!new_cell->uas.request)
- goto error;
- new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len;
- }
- /* UAC */
- init_branches(new_cell);
- new_cell->relaied_reply_branch = -1;
- /* new_cell->T_canceled = T_UNDEFINED; */
- #ifdef EXTRA_DEBUG
- new_cell->wait_tl.tg=TG_WT;
- new_cell->dele_tl.tg=TG_DEL;
- #endif
- init_synonym_id(new_cell);
- init_cell_lock( new_cell );
- return new_cell;
- error:
- shm_free(new_cell);
- /* unlink transaction AVP list and link back the global AVP list (bogdan)*/
- reset_avps();
- return NULL;
- }
- /* Release all the data contained by the hash table. All the aux. structures
- * as sems, lists, etc, are also released */
- void free_hash_table( )
- {
- struct cell* p_cell;
- struct cell* tmp_cell;
- int i;
- if (tm_table)
- {
- /* remove the data contained by each entry */
- for( i = 0 ; i<TABLE_ENTRIES; i++)
- {
- release_entry_lock( (tm_table->entrys)+i );
- /* delete all synonyms at hash-collision-slot i */
- p_cell=tm_table->entrys[i].first_cell;
- for( ; p_cell; p_cell = tmp_cell )
- {
- tmp_cell = p_cell->next_cell;
- free_cell( p_cell );
- }
- }
- shm_free(tm_table);
- }
- }
- /*
- */
- struct s_table* init_hash_table()
- {
- int i;
- /*allocs the table*/
- tm_table= (struct s_table*)shm_malloc( sizeof( struct s_table ) );
- if ( !tm_table) {
- LOG(L_ERR, "ERROR: init_hash_table: no shmem for TM table\n");
- goto error0;
- }
- memset( tm_table, 0, sizeof (struct s_table ) );
- /* try first allocating all the structures needed for syncing */
- if (lock_initialize()==-1)
- goto error1;
- /* inits the entrys */
- for( i=0 ; i<TABLE_ENTRIES; i++ )
- {
- init_entry_lock( tm_table, (tm_table->entrys)+i );
- tm_table->entrys[i].next_label = rand();
- }
- return tm_table;
- error1:
- free_hash_table( );
- error0:
- return 0;
- }
- /* Takes an already created cell and links it into hash table on the
- * appropriate entry. */
- void insert_into_hash_table_unsafe( struct cell * p_cell, unsigned int _hash )
- {
- struct entry* p_entry;
- p_cell->hash_index=_hash;
- /* locates the appropriate entry */
- p_entry = &tm_table->entrys[ _hash ];
- p_cell->label = p_entry->next_label++;
- if ( p_entry->last_cell )
- {
- p_entry->last_cell->next_cell = p_cell;
- p_cell->prev_cell = p_entry->last_cell;
- } else p_entry->first_cell = p_cell;
- p_entry->last_cell = p_cell;
- /* update stats */
- p_entry->cur_entries++;
- p_entry->acc_entries++;
- t_stats_new( is_local(p_cell) );
- }
- #ifdef _OBSOLETED
- void insert_into_hash_table( struct cell * p_cell)
- {
- LOCK_HASH(p_cell->hash_index);
- insert_into_hash_table_unsafe( p_cell );
- UNLOCK_HASH(p_cell->hash_index);
- }
- #endif
- /* Un-link a cell from hash_table, but the cell itself is not released */
- void remove_from_hash_table_unsafe( struct cell * p_cell)
- {
- struct entry* p_entry = &(tm_table->entrys[p_cell->hash_index]);
- /* unlink the cell from entry list */
- /* lock( &(p_entry->mutex) ); */
- if ( p_cell->prev_cell )
- p_cell->prev_cell->next_cell = p_cell->next_cell;
- else
- p_entry->first_cell = p_cell->next_cell;
- if ( p_cell->next_cell )
- p_cell->next_cell->prev_cell = p_cell->prev_cell;
- else
- p_entry->last_cell = p_cell->prev_cell;
- /* update stats */
- # ifdef EXTRA_DEBUG
- if (p_entry->cur_entries==0) {
- LOG(L_CRIT, "BUG: bad things happened: cur_entries=0\n");
- abort();
- }
- # endif
- p_entry->cur_entries--;
- t_stats_deleted( is_local(p_cell) );
- /* unlock( &(p_entry->mutex) ); */
- }
- /* print accumulated distribution of the hash table */
- int fifo_hash( FILE *stream, char *response_file )
- {
- FILE *reply_file;
- unsigned int i;
- reply_file=open_reply_pipe(response_file);
- if (reply_file==0) {
- LOG(L_ERR, "ERROR: fifo_hash: file '%s' not opened\n",
- response_file);
- return -1;
- }
- fputs( "200 ok\n\tcurrent\ttotal\n", reply_file);
- for (i=0; i<TABLE_ENTRIES; i++) {
- fprintf(reply_file, "%d.\t%lu\t%lu\n",
- i, tm_table->entrys[i].cur_entries ,
- tm_table->entrys[i].acc_entries );
- }
- fclose(reply_file);
- return 1;
- }
- int unixsock_hash(str* msg)
- {
- unsigned int i, ret;
- ret = 0;
- unixsock_reply_asciiz( "200 OK\n\tcurrent\ttotal\n");
- for (i = 0; i < TABLE_ENTRIES; i++) {
- if (unixsock_reply_printf("%d.\t%lu\t%lu\n",
- i, tm_table->entrys[i].cur_entries,
- tm_table->entrys[i].acc_entries
- ) < 0) {
- unixsock_reply_reset();
- unixsock_reply_asciiz("500 Error while creating reply\n");
- ret = -1;
- break;
- }
- }
- if (unixsock_reply_send() < 0) {
- ret = -1;
- }
- return ret;
- }
|