فهرست منبع

initial CVS checkin of t-management

Jiri Kuthan 24 سال پیش
والد
کامیت
7298c786d4
6فایلهای تغییر یافته به همراه1089 افزوده شده و 0 حذف شده
  1. 26 0
      modules/tm/Makefile
  2. 499 0
      modules/tm/table/h_table.c
  3. 15 0
      modules/tm/table/hash_func.c
  4. 42 0
      modules/tm/table/semaphore.c
  5. 243 0
      modules/tm/table/timer.c
  6. 264 0
      modules/tm/tm.c

+ 26 - 0
modules/tm/Makefile

@@ -0,0 +1,26 @@
+CC		= g++
+cc		= gcc
+CCFLAGS 	= -c
+TABLE_DIR          = table
+INCLUDE 	= -include $(TABLE_DIR)/h_table.h
+LIBS		= -lpthread
+
+all: build link
+
+build:  $(TABLE_DIR)/table.o  tm.o
+
+link:  tm
+
+$(TABLE_DIR)/table.o: Makefile $(TABLE_DIR)/hash_func.c $(TABLE_DIR)/h_table.c $(TABLE_DIR)/h_table.h $(TABLE_DIR)/semaphore.c $(TABLE_DIR)/timer.c
+	$(cc)  $(CCFLAGS)  $(TABLE_DIR)/h_table.c -o $@
+
+tm.o: Makefile tm.c
+	$(cc)  $(CCFLAGS)  $(INCLUDE) tm.c -o $@
+
+tm: Makefile tm.o $(TABLE_DIR)/table.o
+	$(cc)  tm.o $(TABLE_DIR)/table.o $(LIBS)  -o $@
+
+clean:
+	rm -f  $(TABLE_DIR)/*.o || return 0
+	rm -f  *.o || return 0
+	rm -f tm  || return 0

+ 499 - 0
modules/tm/table/h_table.c

@@ -0,0 +1,499 @@
+#include "h_table.h"
+
+#include "hash_func.c"
+#include "semaphore.c"
+#include "timer.c"
+
+
+void free_cell( struct cell* dead_cell )
+{
+   sh_free( dead_cell->from );
+   sh_free( dead_cell->to );
+   sh_free( dead_cell->req_tag );
+   sh_free( dead_cell->res_tag );
+   sh_free( dead_cell->call_id );
+   sh_free( dead_cell->cseq_nr );
+   sh_free( dead_cell->cseq_method );
+   sh_free( dead_cell->incoming_req_uri );
+   sh_free( dead_cell->outgoing_req_uri );
+   remove_sem( dead_cell->sem );
+   sh_free( dead_cell );
+}
+
+
+void free_hash_table( table hash_table )
+{
+   struct cell* p_cell;
+   int   i;
+
+   if (hash_table)
+   {
+      if ( hash_table->entrys )
+      {
+         for( i = 0 ; i<TABLE_ENTRYS ; i++)
+          {
+             remove_sem( hash_table->entrys[i].sem );
+             p_cell = hash_table->entrys[i].first_cell;
+             while( p_cell )
+              {
+                 /* free the cell*/
+                 free_cell( p_cell );
+                 p_cell = p_cell->next_cell;
+              }
+          }
+          sh_free( hash_table->entrys );
+      }
+      if ( hash_table->first_del_hooker )
+      {
+         p_cell = hash_table->first_del_hooker;
+         while (p_cell)
+         {
+            /*free the cell */
+            free_cell( p_cell );
+            p_cell = p_cell->timer_next_cell;
+         }
+      }
+      if ( hash_table->timers)
+      {
+         sh_free( hash_table->timers );
+      }
+      sh_free( hash_table );
+   }
+}
+
+
+
+table  init_hash_table()
+{
+   struct s_table*  hash_table;
+   int       i;
+
+   /*allocs the table*/
+   hash_table = sh_malloc(  sizeof( struct s_table ) );
+   if ( !hash_table )
+   {
+       free_hash_table( hash_table );
+      return 0;
+   }
+
+   /*inits the time*/
+   hash_table->time = 0;
+
+   /* allocs the entry's table */
+    hash_table->entrys  = sh_malloc( TABLE_ENTRYS * sizeof( struct entry )  );
+    if ( !hash_table->entrys )
+    {
+        free_hash_table( hash_table );
+       return 0;
+    }
+
+   /* allocs the timer's table */
+    hash_table->timers  = sh_malloc( 2 * sizeof( struct timer )  );
+    if ( !hash_table->timers )
+    {
+        free_hash_table( hash_table );
+       return 0;
+    }
+
+    /* inits the deleted cells list*/
+    hash_table->first_del_hooker = 0;
+    hash_table->last_del_hooker = 0;
+
+    /* inits the entrys */
+    for(  i=0 ; i<TABLE_ENTRYS ; i++ )
+    {
+       hash_table->entrys[i].first_cell = 0;
+       hash_table->entrys[i].last_cell = 0;
+       hash_table->entrys[i].next_label = 1;
+       hash_table->entrys[i].sem = create_sem( SEM_KEY , 1 ) ;
+    }
+
+   /* inits the timers*/
+    for(  i=0 ; i<2 ; i++ )
+    {
+       hash_table->timers[i].first_cell = 0;
+       hash_table->timers[i].last_cell = 0;
+       hash_table->timers[i].sem = create_sem( SEM_KEY , 1 ) ;
+    }
+
+   /* starts the timer thread/ process */
+   pthread_create( &(hash_table->timer_thread_id), NULL, timer_routine, hash_table );
+
+   return  hash_table;
+}
+
+
+
+
+struct cell* add_Transaction( table hash_table, char* incoming_req_uri, char* from, char* to, char* tag, char* call_id, char* cseq_nr ,char* cseq_method )
+{
+   struct cell*    new_cell;
+   struct entry* match_entry;
+   char*              via_label;
+   int                  hash_index;
+
+   hash_index   = hash( call_id , cseq_nr ) % TABLE_ENTRYS;
+   /*will it be faster to repolace  x % 256   with   x - (x>>8)<<8  ?  */
+   match_entry = &hash_table->entrys[hash_index];
+
+   new_cell = sh_malloc( sizeof( struct cell ) );
+   if  ( !new_cell )
+      return 0;
+
+   //incoming_req_uri
+   new_cell->incoming_req_uri_length = strlen( incoming_req_uri );
+   new_cell->incoming_req_uri = sh_malloc( new_cell->incoming_req_uri_length+1 );
+   strcpy( new_cell->incoming_req_uri , incoming_req_uri );
+   //from
+   new_cell->from_length = strlen( from );
+   new_cell->from = sh_malloc( new_cell->from_length+1 );
+   strcpy( new_cell->from , from );
+   //to
+   new_cell->to_length = strlen( to );
+   new_cell->to = sh_malloc( new_cell->to_length+1 );
+   strcpy( new_cell->to , to );
+   //req_tag
+   if (tag)
+   {
+      new_cell->req_tag_length = strlen( tag );
+      new_cell->req_tag = sh_malloc( new_cell->req_tag_length+1 );
+      strcpy( new_cell->req_tag , tag );
+   }
+   else
+   {
+      new_cell->req_tag_length = 0;
+      new_cell->req_tag             = 0;
+   }
+   //cseq_nr
+   new_cell->cseq_nr_length = strlen( cseq_nr );
+   new_cell->cseq_nr = sh_malloc( new_cell->cseq_nr_length+1 );
+   strcpy( new_cell->cseq_nr , cseq_nr );
+   //cseq_method
+   new_cell->cseq_method_length = strlen( cseq_method );
+   new_cell->cseq_method = sh_malloc( new_cell->cseq_method_length+1 );
+   strcpy( new_cell->cseq_method , cseq_method );
+   //call_id
+   new_cell->call_id_length = strlen( call_id );
+   new_cell->call_id = sh_malloc( new_cell->call_id_length+1 );
+   strcpy( new_cell->call_id , call_id );
+   //outgoing_req_uri
+   new_cell->outgoing_req_uri = 0;
+   //res_tag
+   new_cell->res_tag_length = 0;
+   new_cell->res_tag             = 0;
+   //status
+   new_cell->status = 100;
+   //ref_counter
+   new_cell->ref_counter =  0;
+   //cell semaphore
+   new_cell->sem = create_sem( SEM_KEY , 1 ) ;
+   //time_out
+   new_cell ->time_out          = 0;
+   new_cell->timer_prev_cell = 0;
+   new_cell->timer_next_cell = 0;
+   //next cell
+   new_cell -> next_cell = 0;
+   new_cell -> prev_cell = 0;
+
+   // critical region - inserting the cell at the end of the list
+   change_sem( match_entry->sem , -1  );
+   new_cell->label = match_entry->next_label++;
+   if ( match_entry->last_cell )
+   {
+      match_entry->last_cell->next_cell = new_cell;
+      new_cell->prev_cell = match_entry->last_cell;
+   }
+   else
+      match_entry->first_cell = new_cell;
+   match_entry->last_cell = new_cell;
+   change_sem( match_entry->sem , +1 );
+
+   //via label
+   via_label = sh_malloc( 512 );
+   sprintf( via_label , "%da%d", hash_index , new_cell->label );
+   new_cell->via_label = sh_malloc( strlen(via_label)+1 );
+   strcpy( new_cell->via_label , via_label );
+   sh_free( via_label );
+
+   return new_cell;
+}
+
+
+
+
+void ref_Cell( struct cell* p_cell)
+{
+   change_sem( p_cell->sem , -1 );
+   p_cell->ref_counter++;
+   change_sem( p_cell->sem , +1 );
+}
+
+
+void unref_Cell( struct cell* p_cell)
+{
+   change_sem( p_cell->sem , -1 );
+   p_cell ->ref_counter--;
+   change_sem( p_cell->sem , +1 );
+}
+
+
+
+/*
+ *  the method looks for a perfect transaction matche for a request. The request cannot be an ACK because the ACK
+ *  request are treated before (and ACK req don't have transactions :-) ). Requests don't have labels for search - the label
+ *  matching tech. is nor used, only standard search. No special matching for the tag attr from To header - the request are
+ *  different than ACK -> perfect To matche is performed.
+ *  WARNING : in case of a returned transaction, this transaction is NOT  unref !!!
+ */
+struct cell* lookup_for_Transaction_by_req( table hash_table, char* from, char* to, char* tag, char* call_id , char* cseq_nr ,char* cseq_method )
+{
+   struct cell*  p_cell;
+   struct cell* tmp_cell;
+   int                hash_index=0;
+   int                call_id_len, from_len, to_len, tag_len, cseq_nr_len, cseq_method_len;
+
+   /* The lenght of the fields that will be comp */
+   hash_index         = hash( call_id , cseq_nr ) % TABLE_ENTRYS;
+   call_id_len           = strlen(call_id);
+   from_len              = strlen(from);
+   to_len                   = strlen(to);
+   tag_len                 = (tag)?strlen(tag):0;
+   cseq_nr_len         = strlen(cseq_nr);
+   cseq_method_len = strlen(cseq_method);
+
+   //all the cells from the entry are compared
+   p_cell     = hash_table->entrys[hash_index].first_cell;
+   tmp_cell = 0;
+   while( p_cell )
+   {
+      // the cell is referenceted for reading
+      ref_Cell( p_cell );
+
+      //is the wanted cell ?
+      if ( p_cell->from_length == from_len && p_cell->to_length == to_len && p_cell->req_tag_length == tag_len && p_cell->call_id_length == call_id_len && p_cell->cseq_nr_length == cseq_nr_len && p_cell->cseq_method_length == cseq_method_len  )
+         if ( !strcmp(p_cell->from,from) && !strcmp(p_cell->to,to) && !strncmp(p_cell->req_tag,tag,tag_len) && !strcmp(p_cell->call_id,call_id) && !strcmp(p_cell->cseq_nr,cseq_nr) && !strcmp(p_cell->cseq_method,cseq_method)  )
+              return p_cell;
+      //next cell
+      tmp_cell = p_cell;
+      p_cell = p_cell->next_cell;
+
+      //the cell is dereferenceted
+      unref_Cell ( tmp_cell );
+   }
+
+   return 0;
+
+}
+
+
+
+
+
+/*
+ *  the method looks for a pair transaction for an ACK request. Requests don't have labels for search - the label matching tech.
+ *  is nor used, only standard search. Being a ACK, a special matching for the tag attr from To header is performed.
+ *  WARNING : in case of a returned transaction, this transaction is NOT  unref !!!
+ */
+struct cell* lookup_for_Transaction_by_ACK( table hash_table, char* from, char* to, char* tag, char* call_id, char* cseq_nr )
+{
+   struct cell*  p_cell;
+   struct cell*  tmp_cell;
+   char*            trans_tag;
+   int                hash_index=0;
+   int                call_id_len, from_len, to_len, tag_len, cseq_nr_len;
+   int                trans_tag_len;
+
+   /* The lenght of the fields that will be comp */
+   hash_index         = hash( call_id , cseq_nr ) % TABLE_ENTRYS;
+   call_id_len           = strlen(call_id);
+   from_len              = strlen(from);
+   to_len                   = strlen(to);
+   tag_len                 = (tag)?strlen(tag):0;
+   cseq_nr_len         = strlen(cseq_nr);
+
+   //all the cells from the entry are compared
+   p_cell     = hash_table->entrys[hash_index].first_cell;
+   tmp_cell = 0;
+   while( p_cell )
+   {
+      // the cell is referenceted for reading
+      ref_Cell( p_cell );
+
+      //is the wanted cell ?
+      if ( p_cell->from_length == from_len && p_cell->to_length == to_len &&p_cell->call_id_length == call_id_len && p_cell->cseq_nr_length == cseq_nr_len && p_cell->cseq_method_length == 3  )
+         if ( !strcmp(p_cell->from,from) && !strcmp(p_cell->to,to) && !strcmp(p_cell->call_id,call_id) && !strcmp(p_cell->cseq_nr,cseq_nr) && !strcmp(p_cell->cseq_method,"ACK")  )
+            {
+             trans_tag        = p_cell->res_tag;
+             trans_tag_len = p_cell->res_tag_length;
+             if ( !p_cell->res_tag )
+                {
+                   trans_tag        = p_cell->req_tag;
+                   trans_tag_len = p_cell->req_tag_length;
+                }
+
+                if ( trans_tag_len == tag_len && !strncmp(trans_tag,tag,tag_len) )
+                  return p_cell;
+            }
+      //next cell
+      tmp_cell = p_cell;
+      p_cell = p_cell->next_cell;
+
+      //the cell is dereferenceted
+      unref_Cell ( tmp_cell );
+   }
+
+   return 0;
+
+}
+
+
+
+/*
+ *  the method looks for a pair transaction for a CANCEL request. Requests don't have labels for search - the label
+ *  matching tech. is nor used, only standard search. No special matching for the tag attr from To header - the request are
+ *  different than ACK -> perfect To match is performed.
+ *  WARNING : in case of a returned transaction, this transaction is NOT  unref !!!
+ */
+struct cell* lookup_for_Transaction_by_CANCEL( table hash_table,char *req_uri, char* from, char* to, char* tag, char* call_id, char* cseq_nr )
+{
+   struct cell*  p_cell;
+   struct cell* tmp_cell;
+   int                hash_index=0;
+   int                req_uri_len, call_id_len, from_len, to_len, tag_len, cseq_nr_len;
+
+   /* The lenght of the fields that will be comp */
+   hash_index         = hash( call_id , cseq_nr ) % TABLE_ENTRYS;
+   req_uri_len          = strlen(req_uri);
+   call_id_len           = strlen(call_id);
+   from_len              = strlen(from);
+   to_len                   = strlen(to);
+   tag_len                 = (tag)?strlen(tag):0;
+   cseq_nr_len         = strlen(cseq_nr);
+
+   //all the cells from the entry are compared
+   p_cell     = hash_table->entrys[hash_index].first_cell;
+   tmp_cell = 0;
+   while( p_cell )
+   {
+      // the cell is referenceted for reading
+      ref_Cell( p_cell );
+
+      //is the wanted cell ?
+      if ( p_cell->incoming_req_uri_length == req_uri_len && p_cell->from_length == from_len && p_cell->to_length == to_len && p_cell->req_tag_length == tag_len && p_cell->call_id_length == call_id_len && p_cell->cseq_nr_length == cseq_nr_len && p_cell->cseq_method_length == 6  )
+         if ( !strcmp(p_cell->incoming_req_uri,req_uri) && !strcmp(p_cell->from,from) && !strcmp(p_cell->to,to) && !strcmp(p_cell->req_tag,tag) && !strcmp(p_cell->call_id,call_id) && !strcmp(p_cell->cseq_nr,cseq_nr) && !strcmp(p_cell->cseq_method,"CANCEL")  )
+              return p_cell;
+      //next cell
+      tmp_cell = p_cell;
+      p_cell = p_cell->next_cell;
+
+      //the cell is dereferenceted
+      unref_Cell ( tmp_cell );
+   }
+
+   return 0;
+
+}
+
+
+
+
+/*
+ *  the method looks for a perfect transaction match for a response. The label matching tech. is  used, but also
+ *  standard search if no label is present or the label is corupted. A tag matching is performed only if the original
+ *  request had a tag.
+ *  WARNING : in case of a returned transaction, this transaction is NOT  unref !!!
+ */
+struct cell* lookup_for_Transaction_by_res( table hash_table, char* label, char* from, char* to, char* tag, char* call_id, char* cseq_nr ,char* cseq_method )
+{
+   struct cell*  p_cell;
+   struct cell* tmp_cell;
+   int                hash_index=0;
+   int                call_id_len, from_len, to_len, tag_len, cseq_nr_len, cseq_method_len;
+
+   if ( label )
+   {
+      //the mesasge has a label -> search using label matching
+      int      entry_label  = 0;
+      char*  p = label;
+      char*  tmp;
+
+      //looking for the hash index  value
+      for(  ; p && *p>='0' && *p<='9' ; p++ )
+         hash_index = hash_index * 10 + (*p - '0')  ;
+
+      //if the hash index is corect
+      if  ( p && p!=label && hash_index<TABLE_ENTRYS-1 )
+      {
+         //looking for the entry label value
+         for( tmp=++p ; p && *p>='0' && *p<='9' ; p++ )
+             entry_label = entry_label * 10 + (*p - '0')  ;
+
+         //if the entry label also is corect
+         if  ( tmp!=p )
+         {
+             //all the cells from the entry are scan to detect an entry_label matching
+             p_cell     = hash_table->entrys[hash_index].first_cell;
+             tmp_cell = 0;
+             while( p_cell )
+             {
+                // the cell is referenceted for reading
+                ref_Cell( p_cell );
+                //is the cell with the wanted entry_label
+                if ( p_cell->label = entry_label )
+                   return p_cell;
+                //next cell
+                tmp_cell = p_cell;
+                p_cell = p_cell->next_cell;
+
+                //the cell is dereferenceted
+                unref_Cell ( tmp_cell );
+             }
+          }
+      }
+   }
+
+   //the message doesnot containe a label  or  the label is incorect-> normal seq. search.
+   hash_index         = hash( call_id , cseq_nr ) % TABLE_ENTRYS;
+   call_id_len           = strlen(call_id);
+   from_len              = strlen(from);
+   to_len                   = strlen(to);
+   tag_len                 = (tag)?strlen(tag):0;
+   cseq_nr_len         = strlen(cseq_nr);
+   cseq_method_len = strlen(cseq_method);
+
+   //all the cells from the entry are compared
+   p_cell     = hash_table->entrys[hash_index].first_cell;
+   tmp_cell = 0;
+   while( p_cell )
+   {
+      // the cell is referenceted for reading
+      ref_Cell( p_cell );
+      //is the wanted cell ?
+      if ( p_cell->from_length == from_len && p_cell->to_length == to_len && p_cell->req_tag_length == tag_len && p_cell->call_id_length == call_id_len && p_cell->cseq_nr_length == cseq_nr_len && p_cell->cseq_method_length == cseq_method_len  )
+         if ( !strcmp(p_cell->from,from) && !strcmp(p_cell->to,to) && !strncmp(p_cell->req_tag,tag,tag_len) && !strcmp(p_cell->call_id,call_id) && !strcmp(p_cell->cseq_nr,cseq_nr) && !strcmp(p_cell->cseq_method,cseq_method) )
+            return p_cell;
+      //next cell
+      tmp_cell = p_cell;
+      p_cell = p_cell->next_cell;
+
+      //the cell is dereferenceted
+      unref_Cell ( tmp_cell );
+   }
+
+   return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 15 - 0
modules/tm/table/hash_func.c

@@ -0,0 +1,15 @@
+
+
+int hash( char* call_id , char* cseq_nr )
+{
+   int     hash_code = 0;
+   char* p;
+
+    if ( call_id )
+      for( p=call_id ; (*p)!=0 ; hash_code+=(*p) , p++ );
+    if ( cseq_nr )
+      for( p=cseq_nr ; *p!=0 ; hash_code+=*p , p++ );
+
+   return hash_code ;
+}
+

+ 42 - 0
modules/tm/table/semaphore.c

@@ -0,0 +1,42 @@
+
+
+int create_sem( key_t key , int val)
+{
+   int id;
+   union semun
+   {
+      int val;
+      struct semid_ds *buf;
+      ushort *array;
+   } argument;
+
+   id = semget( key , 1,  0666|IPC_CREAT );
+   argument.val = val;
+   if  (id!=-1)
+      if ( semctl( id , 0 , SETVAL , argument )==-1 )
+         id = -1;
+   return id;
+}
+
+
+int change_sem( int id , int val )
+{
+   struct sembuf pbuf;
+
+   pbuf.sem_num = 0;
+   pbuf.sem_op =val;
+   pbuf.sem_flg = 0;
+
+   return semop( id , &pbuf , 1);
+}
+
+
+
+int remove_sem( int id )
+{
+   return  semctl( id , 0 , IPC_RMID , 0 ) ;
+}
+
+
+
+

+ 243 - 0
modules/tm/table/timer.c

@@ -0,0 +1,243 @@
+void free_cell( struct cell* dead_cell );
+
+
+/*
+*   The cell is inserted at the end of the FINAL RESPONSE timer list.
+*   The expire time is given by the current time plus the FINAL RESPONSE timeout - FR_TIME_OUT
+*/
+void start_FR_timer( table hash_table, struct cell* p_cell )
+{
+   struct timer* timers= hash_table->timers;
+
+   /* adds the cell int FINAL RESPONSE timer list*/
+   change_sem( timers[0].sem , -1  );
+   p_cell -> time_out    = FR_TIME_OUT + hash_table->time;
+   if ( timers[0].last_cell )
+   {
+      p_cell -> timer_next_cell = 0;
+      p_cell->timer_prev_cell = timers[0].last_cell;
+      timers[0].last_cell->timer_next_cell = p_cell;
+      timers[0].last_cell = p_cell;
+   }
+   else
+   {
+      p_cell->timer_prev_cell = 0;
+      p_cell->timer_next_cell = 0;
+      timers[0].first_cell = p_cell;
+      timers[0].last_cell = p_cell;
+   }
+
+   change_sem( timers[0].sem , +1  );
+}
+
+
+
+/*
+*   The cell is inserted at the end of the WAIT timer list. Before adding to the WT list, it's verify if the cell is
+*   or not in the FR list (normally it should be there). If it is, it's first removed from FR list and after that
+*   added to the WT list.
+*   The expire time is given by the current time plus the WAIT timeout - WT_TIME_OUT
+*/
+
+void start_WT_timer( table hash_table, struct cell* p_cell )
+{
+   struct timer* timers= hash_table->timers;
+
+   //if is in FR list -> first it must be removed from there
+   if ( p_cell->timer_next_cell || p_cell->timer_prev_cell || (!p_cell->timer_next_cell && !p_cell->timer_prev_cell && p_cell==timers[0].first_cell)  )
+   {
+      change_sem( timers[0].sem , -1  );
+      if ( p_cell->timer_prev_cell )
+         p_cell->timer_prev_cell->timer_next_cell = p_cell->timer_next_cell;
+      else
+         timers[0].first_cell = p_cell->timer_next_cell;
+      if ( p_cell->timer_next_cell )
+         p_cell->timer_next_cell->timer_prev_cell = p_cell->timer_prev_cell;
+      else
+         timers[0].last_cell = p_cell->timer_prev_cell;
+      change_sem( timers[0].sem , +1  );
+   }
+
+   /* adds the cell int WAIT timer list*/
+   change_sem( timers[1].sem , -1  );
+   p_cell -> time_out = WT_TIME_OUT + hash_table->time;
+   if ( timers[1].last_cell )
+   {
+      p_cell -> timer_next_cell = 0;
+      p_cell ->timer_prev_cell = timers[1].last_cell;
+      timers[1].last_cell->timer_next_cell = p_cell;
+      timers[1].last_cell = p_cell;
+   }
+   else
+   {
+      p_cell->timer_prev_cell = 0;
+      p_cell->timer_next_cell = 0;
+      timers[1].first_cell = p_cell;
+      timers[1].last_cell = p_cell;
+   }
+
+   change_sem( timers[1].sem , +1  );
+}
+
+
+
+
+/*
+*   prepare for del a transaction ; the transaction is first removed from the hash entry list (oniy the links from
+*   cell to list are deleted in order to make the cell unaccessible from the list and in the same time to keep the
+*   list accessible from the cell for process that are currently reading the cell). If no process is reading the cell
+*   (ref conter is 0) the cell is immediatly deleted. Otherwise it is put in a waitting list (del_hooker list) for
+*   future del. This list is veify by the the timer every sec and the cell that finaly have ref_counter 0 are del.
+*/
+void del_Transaction( table hash_table , struct cell * p_cell )
+{
+   int      ref_counter         = 0;
+   int      hash_index         = 0;
+   char*  p                         = p_cell->via_label;
+   struct entry*  p_entry  = 0 ;
+
+    /* gets the entry number from the label */
+   for(  ; p && *p>='0' && *p<='9' ; p++ )
+      hash_index = hash_index * 10 + (*p - '0')  ;
+    p_entry = &(hash_table->entrys[hash_index]);
+
+    /* the cell is removed from the list */
+    change_sem( p_entry->sem , -1  );
+    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;
+    change_sem( p_entry->sem , +1  );
+
+    /* gets the cell's ref counter*/
+    change_sem( p_cell->sem , -1  );
+    ref_counter = p_cell->ref_counter;
+    change_sem( p_cell->sem , +1  );
+
+    /* if is not refenceted -> is deleted*/
+    if ( ref_counter==0 )
+       free_cell( p_cell );
+     /* else it's added to del hooker list for future del */
+    else
+        if ( hash_table->last_del_hooker )
+         {
+            p_cell -> timer_next_cell = 0;
+            p_cell ->timer_prev_cell = hash_table->last_del_hooker;
+            hash_table->last_del_hooker->timer_next_cell = p_cell;
+            hash_table->last_del_hooker = p_cell;
+         }
+        else
+         {
+            p_cell->timer_prev_cell = 0;
+            p_cell->timer_next_cell = 0;
+            hash_table->first_del_hooker = p_cell;
+            hash_table->last_del_hooker = p_cell;
+         }
+}
+
+
+
+
+
+void * timer_routine(void * attr)
+{
+   table                  hash_table = (table)attr;
+   struct timer*    timers= hash_table->timers;
+   struct timeval  a_sec;
+   struct cell*       p_cell;
+   struct cell*       tmp_cell;
+   int unsigned*    time =  &(hash_table->time);
+
+
+   while (1)
+   {
+      a_sec.tv_sec   = 1;
+      a_sec.tv_usec = 0;
+      select( 0 , 0 , 0 ,0 , &a_sec );
+      (*time)++;
+      printf("%d\n", *time);
+
+
+      /* del hooker list */
+      for( p_cell = hash_table->first_del_hooker ; p_cell ;  p_cell = tmp_cell )
+      {
+         int ref_counter;
+         /*gets the cell's ref counter*/
+         change_sem( p_cell->sem , -1  );
+         ref_counter = p_cell->ref_counter;
+         change_sem( p_cell->sem , +1  );
+         /*if the ref counter is 0 (nobody is reading the cell any more) -> remove from list and del*/
+        if (ref_counter==0)
+         {
+             tmp_cell = p_cell->timer_next_cell;
+             /*remove from the list*/
+           if ( p_cell->timer_prev_cell )
+                 p_cell->timer_prev_cell->timer_next_cell = p_cell->timer_next_cell;
+            else
+                 hash_table->first_del_hooker = p_cell->timer_next_cell;
+            if ( p_cell->timer_next_cell )
+                 p_cell->timer_next_cell->timer_prev_cell = p_cell->timer_prev_cell;
+            else
+                 hash_table->last_del_hooker = p_cell->timer_prev_cell;
+             /* del the cell*/
+             free_cell( p_cell );
+         }
+         else
+            tmp_cell = p_cell->timer_next_cell;
+
+       }
+
+
+       /* final response timer list*/
+      for( p_cell = timers[0].first_cell ; p_cell ;  p_cell=tmp_cell )
+           /* if the time out expired -> send a 408 and move the trans in the WAIT timer queue */
+           if ( (p_cell->time_out == *time) )
+           {
+              // TO DO - send r0 = 408
+              printf("FR timeout !!!\n");
+              /* next cell in FR list */
+              tmp_cell = p_cell->timer_next_cell;
+              /* and added to WT timer list */
+              start_WT_timer( hash_table, p_cell );
+           }
+           /* the search stops - no further matched found*/
+         else
+           {
+              tmp_cell = 0;
+           }
+
+
+       /* wait timer list */
+       for( p_cell = timers[1].first_cell ; p_cell ;  p_cell = tmp_cell )
+          /* if the timeout expired - > release the tranzactin*/
+        if ( p_cell->time_out == *time)
+          {
+              printf("WT timeout !!!\n");
+              /* next cell in WT list */
+              tmp_cell = p_cell->timer_next_cell;
+              /* the cell is removed from the WT timer list */
+              change_sem( timers[1].sem , -1  );
+              timers[1].first_cell = p_cell->timer_next_cell;
+              if ( !timers[1].first_cell ) timers[1].last_cell = 0;
+              change_sem( timers[1].sem , +1  );
+              /* release the trasaction*/
+              del_Transaction( hash_table , p_cell );
+          }
+           /* the search stops - no further matched found*/
+          else
+          {
+             tmp_cell = 0;
+          }
+
+    }
+}
+
+
+
+
+
+

+ 264 - 0
modules/tm/tm.c

@@ -0,0 +1,264 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int request_received(  table hash_table, char* incoming_req_uri, char *from, char* to, char* tag, char* call_id, char* cseq_nr ,char* cseq_method, char* outgoing_req_uri)
+{
+   struct cell*  matched_trans = 0;
+   struct cell*  new_trans         = 0;
+   int status;
+
+   /* looking for transaction
+    * IMPORTANT NOTE : the lookup_for_Transaction_by_XXXX returns the found trans referenceted -> when finidh you
+    * have to unreference manually, otherwise the cell wann't be ever deleted!!!!
+    */
+
+   if ( !strcmp( cseq_method , "ACK") )
+   {
+      /* we got an ACK -> do we have a transaction pair for it?*/
+      matched_trans =  lookup_for_Transaction_by_ACK( hash_table, from , to , tag , call_id , cseq_nr );
+      if ( matched_trans )
+      {
+         /* the trans pair was found -> let's check the trans's status  */
+         status = matched_trans->status;
+         /* done with reading the transaction -> unref it*/
+         unref_Cell( matched_trans );
+         if ( status>=200 && status<300 )
+         {
+            /* response for PROXY -> route the ACK */
+          return 1;
+         }
+         else
+         {
+            /* response for PROXY->DROP the request!! */
+            return 0;
+         }
+      }
+      else
+      {
+         /* response for PROXY -> route the ACK */
+         return 1;
+      }
+   }
+
+
+   /* looks up for a perfect mache transaction */
+   matched_trans =  lookup_for_Transaction_by_req( hash_table, from , to , tag , call_id , cseq_nr , cseq_method );
+
+   if ( matched_trans )
+   {
+      /* the trans already exists -> the last response is retransmited  */
+      status = matched_trans->status;
+      /* done with reading the transaction -> unref it*/
+      unref_Cell( matched_trans );
+      // TO DO -> replay with <status> response
+      /* response for PROXY->DROP the request!! */
+      return 0 ;
+   }
+
+
+    /* if is not a request -> route it further */
+   if ( strcmp( cseq_method , "CANCEL") )
+   {
+      /* we got a CANCEL -> do we have a transaction pair for it?*/
+      matched_trans = lookup_for_Transaction_by_CANCEL( hash_table, incoming_req_uri , from , to , tag , call_id , cseq_nr );
+      if ( matched_trans )
+      {
+         /* the trans pair was found -> let's check the trans's status  */
+         status = matched_trans->status;
+         /* done with reading the transaction -> unref it*/
+         unref_Cell( matched_trans );
+        if ( status>=200 )
+         {
+            /* the trasaction has a final response -> send a 200 reply for the CANCEL */
+            // TO DO send 200 reply
+            /*response for PROXY -> DROP the request!!! */
+            return 0;
+         }
+      }
+   }
+
+   /* a new trans is created based on the received request */
+   new_trans = add_Transaction( hash_table , incoming_req_uri , from , to , tag , call_id , cseq_nr , cseq_method );
+   if ( !new_trans )
+   {
+      /* response for PROXY -> error:cannot alloc memory */
+      return -1;
+   }
+   /* a 100 replay is sent */
+   //TO DO ->send a 100 reply
+
+   /* the FINAL RESPONSE timer is engaged */
+   start_FR_timer( hash_table, new_trans );
+   /* sets the outgoing req URI */
+   new_trans->outgoing_req_uri = sh_malloc( strlen(outgoing_req_uri) + 1 );
+   strcpy( new_trans->outgoing_req_uri , outgoing_req_uri );
+
+   /* response for PROXY -> route the request */
+   return 1;
+}
+
+
+
+
+
+
+int response_received(  table hash_table, char* reply_code, char* incoming_url , char* via, char* label , char* from , char* to , char* tag , char* call_id , char* cseq_nr ,char* cseq_method )
+{
+   struct cell*  matched_trans = 0;
+   char* p;
+   int  res_status, trans_status;
+
+   /* looking for a transaction match
+    * IMPORTANT NOTE : the lookup_fir_Transaction returns the found trans referenceted -> when finidh you
+    * have to unreference manually, otherwise the cell wann't be ever deleted!!!!
+    */
+   matched_trans =  lookup_for_Transaction_by_res( hash_table, label , from , to , tag , call_id , cseq_nr , cseq_method );
+
+   if ( !matched_trans )
+   {
+      /* the trans wasn't found ->  the response is forwarded to next Via hop  */
+      return 1;
+   }
+
+   /* getting the matched trasaction  status */
+   trans_status = matched_trans->status;
+
+   /* getting the response status from reply as int form string */
+   p = reply_code;
+   res_status = strtol( reply_code , &p , 10 );
+   if ( *p!=0 )
+   {
+      /* done with the transaction -> unref it*/
+      unref_Cell( matched_trans );
+      /* response for PROXY -> error:cannot convert string to number */
+      return -1;
+   }
+
+   if ( res_status==100)
+   {
+      /* done with the transaction -> unref it*/
+      unref_Cell( matched_trans );
+      /* response for PROXY -> DROP the response!!! */
+      return 0;
+   }
+
+   if ( res_status >100 && res_status<200 )
+      if ( res_status > trans_status )
+      {
+         /* updating the transaction status */
+         matched_trans->status = res_status;
+         /* store the reply's tag (if no response tag has been set)*/
+         if ( !matched_trans->res_tag )
+         {
+            matched_trans->res_tag_length = strlen( tag );
+            matched_trans->res_tag = sh_malloc( matched_trans->res_tag_length+1 );
+            strcpy( matched_trans->res_tag , tag );
+         }
+         /* done with the transaction -> unref it*/
+         unref_Cell( matched_trans );
+         /* response to PROXY ->forward upstream the response */
+         return 1;
+      }
+      else
+      {
+         /* done with the transaction -> unref it*/
+         unref_Cell( matched_trans );
+         /* response to PROXY -> DROP the response !!! */
+         return 0;
+      }
+
+   /* if is the response for a local CANCEL*/
+   if ( via==0 && !strcmp( cseq_method,"CANCEL" ) )
+   {
+      /* done with the transaction -> unref it*/
+      unref_Cell( matched_trans );
+      /* response to PROXY -> DROP the response !!! */
+      return 0;
+   }
+
+   if ( res_status<200 || res_status>=300 )
+      if ( !strcmp( cseq_method,"INVITE" ) )
+      {
+         char   ack_req[500];
+         char* tag = 0;
+         /* send ACK for an error INVITE response */
+         strcpy( ack_req , "ACK " );
+         strcat( ack_req , matched_trans->incoming_req_uri ); strcat( ack_req , "\n" );
+         // via TO DO ?!!?!?!
+         strcat( ack_req , "From: " ); strcat( ack_req , matched_trans->from ); strcat( ack_req , "\n" );
+         strcat( ack_req , "To: " ); strcat( ack_req , matched_trans->to );
+         if ( matched_trans->req_tag )
+            tag = matched_trans->req_tag;
+         if ( !tag && matched_trans->res_tag )
+            tag = matched_trans->res_tag;
+         if (tag)
+            {strcat(ack_req," ;tag=");strcat(ack_req,tag);}
+         strcat( ack_req , "\n" );
+         strcat( ack_req , "Call-ID: " ); strcat( ack_req , matched_trans->call_id ); strcat( ack_req , "\n" );
+         strcat( ack_req , "CSeq: " ); strcat( ack_req , matched_trans->cseq_nr ); strcat( ack_req , " ACK\n\n" );
+         //TO DO - send the request
+      }
+   else
+      if ( strcmp( cseq_method,"INVITE" ) && trans_status>=200 )
+      {
+         /* done with the transaction -> unref it*/
+         unref_Cell( matched_trans );
+         /* response to PROXY -> DROP the response !!! */
+         return 0;
+      }
+
+
+   /* Final clean up */
+
+   /* updating the transaction status */
+   matched_trans->status = res_status;
+   /* store the reply's tag (if it's unset)*/
+   if ( !matched_trans->res_tag )
+   {
+      matched_trans->res_tag_length = strlen( tag );
+      matched_trans->res_tag = sh_malloc( matched_trans->res_tag_length+1 );
+      strcpy( matched_trans->res_tag , tag );
+   }
+   /* starts the WAIT timer */
+   start_WT_timer( hash_table, matched_trans );
+   /* done with the transaction -> unref it*/
+   unref_Cell( matched_trans );
+
+   /* response to PROXY ->forward upstream the response */
+   return 1;
+}
+
+
+
+
+
+int main()
+{
+   table  hash_table;
+    struct cell* cell1,*cell2 , *cell3 ,*cell4;
+
+   hash_table = init_hash_table();
+
+   cell1 = add_Transaction( hash_table , "iptel.org" , "[email protected]", "[email protected]", 0 , "[email protected]" , "100" , "INVITE"  );
+   cell2 = add_Transaction( hash_table , "iptel.org" , "[email protected]", "[email protected]", 0 , "[email protected]" , "200" ,"REGISTER" );
+
+   start_FR_timer( hash_table, cell1 ) ;
+   start_FR_timer( hash_table, cell2 ) ;
+
+   cell3 = lookup_for_Transaction_by_req( hash_table, "[email protected]", "[email protected]", 0 , "[email protected]" , "100" ,"INVITE");
+
+    if (cell3)
+    {
+       printf(" From %s to %s a %s request\n",cell3->from,cell3->to,cell3->cseq_method);
+        unref_Cell ( cell3 );
+    }
+
+   while(1)
+   {
+      cell3 = lookup_for_Transaction_by_req( hash_table, "[email protected]", "[email protected]", 0 , "[email protected]" , "100" ,"INVITE");
+      if (cell3)  unref_Cell(cell3);
+      cell4 = lookup_for_Transaction_by_req( hash_table, "[email protected]" , "[email protected]", 0 , "[email protected]" , "200" ,"REGISTER" );
+      if (cell4)  unref_Cell(cell4);
+   }
+
+}