memory access syncing protection added
authorJiri Kuthan <jiri@iptel.org>
Mon, 28 Jan 2002 23:30:56 +0000 (23:30 +0000)
committerJiri Kuthan <jiri@iptel.org>
Mon, 28 Jan 2002 23:30:56 +0000 (23:30 +0000)
16 files changed:
Makefile.defs
modules/tm/config.h
modules/tm/h_table.c
modules/tm/h_table.h
modules/tm/lock.c
modules/tm/lock.h
modules/tm/t_funcs.c
modules/tm/t_funcs.h
modules/tm/t_fwd.c [new file with mode: 0644]
modules/tm/t_lookup.c
modules/tm/timer.c
modules/tm/timer.h
modules/tm/tm.c
msg_parser.h
test/tx.cfg
udp_server.c

index d58777f..87d9913 100644 (file)
@@ -53,7 +53,7 @@ ARCH = $(shell uname -s)
 
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
         -DDNS_IP_HACK  -DPKG_MALLOC -DSHM_MEM  -DSHM_MMAP \
-        -DVQ_MALLOC 
+       -DVQ_MALLOC -DBRUT_HACK #-DEXTRA_DEBUG #-DSTATIC_TM #-DEXTRA_DEBUG
        #-DEXTRA_DEBUG -DBRUT_HACK \
        #-DVQ_MALLOC  -DDBG_LOCK  #-DSTATS
          #-DDBG_QM_MALLOC #-DVQ_MALLOC #-DNO_DEBUG
index a9792e1..8e8f8f9 100644 (file)
@@ -7,7 +7,7 @@
 #define _TM_CONFIG_H
 
 /* always use a power of 2 for hash table size */
-#define T_TABLE_POWER          10
+#define T_TABLE_POWER          12
 #define TABLE_ENTRIES                  (2 << (T_TABLE_POWER-1))
 
 /* maximum number of forks per transaction */
index 0f40c64..8f2f54c 100644 (file)
@@ -7,7 +7,6 @@
 #include "../../dprint.h"
 #include "sh_malloc.h"
 
-
 /*   Frees the all the containes of a cell and the cell's body itself
   */
 void free_cell( struct cell* dead_cell )
@@ -19,6 +18,7 @@ void free_cell( struct cell* dead_cell )
        DBG("DEBUG: free_cell: start\n");
        /* UA Server */
        DBG("DEBUG: free_cell: inbound request %p\n",dead_cell->inbound_request);
+       release_cell_lock( dead_cell );
        shm_lock();
        if ( dead_cell->inbound_request )
                sip_msg_free_unsafe( dead_cell->inbound_request );
@@ -36,6 +36,9 @@ void free_cell( struct cell* dead_cell )
                        dead_cell->outbound_request[i] = NULL;
                        shm_free_unsafe( rb );
                }
+               /* outbound ACKs, if any */
+               if (rb=dead_cell->outbound_ack[i] )
+                       shm_free_unsafe( rb );
                /* outbound requests*/
                DBG("DEBUG: free_cell: inbound_response[%d] %p\n",i,dead_cell->inbound_response[i]);
                if ( dead_cell -> inbound_response[i] )
@@ -141,8 +144,15 @@ struct cell*  build_cell( struct sip_msg* p_msg )
 
    /* filling with 0 */
    memset( new_cell, 0, sizeof( struct cell ) );
+
+       new_cell->outbound_response.retr_timer.tg=TG_RT;
+       new_cell->outbound_response.fr_timer.tg=TG_FR;
+       new_cell->wait_tl.tg=TG_WT;
+       new_cell->dele_tl.tg=TG_DEL;
+
    /* hash index of the entry */
-   new_cell->hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number );
+   /* new_cell->hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number ); */
+       new_cell->hash_index = p_msg->hash_index;
    /* mutex */
    /* ref counter is 0 */
    /* all pointers from timers list tl are NULL */
@@ -153,19 +163,10 @@ struct cell*  build_cell( struct sip_msg* p_msg )
    DBG("DEBUG: build_cell : clone done\n");
    if (!new_cell->inbound_request)
        goto error;
-   /* inbound response is NULL*/
-   /* status is 0 */
-   /* tag pointer is NULL */
-   //if ( p_msg->tag )      TO DO !!!!!!!!!!!!!!!!!!!!!!
-   //   new_cell->tag  =  &(new_cell->inbound_request->tag->body);
-   /* nr of outbound requests is 0 */
-   /* all pointers from outbound_request array are NULL */
-   /* all pointers from outbound_response array are NULL */
-   /*init the links with the canceled / canceler transaction */
    new_cell->relaied_reply_branch   = -1;
    new_cell->T_canceled = T_UNDEFINED;
 
-   /* init_cell_lock(  new_cell ); */
+    init_cell_lock(  new_cell ); 
 
    DBG("DEBUG: build_cell : done\n");
    return new_cell;
@@ -181,31 +182,28 @@ error:
 /*  Takes an already created cell and links it into hash table on the
   *  appropiate entry.
   */
-void    insert_into_hash_table( struct s_table *hash_table,  struct cell * p_cell )
+void    insert_into_hash_table_unsafe( struct s_table *hash_table,  struct cell * p_cell )
 {
-   struct entry* p_entry;
-
-   /* do we have or not something to insert? */
-   if (!p_cell)
-      return;
+       struct entry* p_entry;
 
-   /* locates the apropiate entry */
-   p_entry = &hash_table->entrys[ p_cell->hash_index ];
+       /* locates the apropiate entry */
+       p_entry = &hash_table->entrys[ p_cell->hash_index ];
 
-   /* critical region - inserting the cell at the end of the list */
-   lock( p_entry->mutex );
-
-   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;
+       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;
+}
 
-   unlock( p_entry->mutex );
+void insert_into_hash_table( struct s_table *hash_table,  struct cell * p_cell )
+{
+       lock( hash_table->entrys[ p_cell->hash_index ].mutex );
+       insert_into_hash_table_unsafe( hash_table,  p_cell );
+       unlock( hash_table->entrys[ p_cell->hash_index ].mutex );
 }
 
 
index 161a7d8..473f5c5 100644 (file)
@@ -34,20 +34,22 @@ struct timer;
 
 typedef struct retrans_buff
 {
-   char               *retr_buffer;
-   int                  bufflen;
+       char               *retr_buffer;
+       int                  bufflen;
 
-   struct sockaddr_in to;
-   size_t tolen;
+       struct sockaddr_in to;
+       size_t tolen;
 
-   /* a message can be linked just to retransmission and FR list */
-   struct timer_link retr_timer;
-   struct timer_link fr_timer;
+       /* a message can be linked just to retransmission and FR list */
+       struct timer_link retr_timer;
+       struct timer_link fr_timer;
 
-   /*the cell that containes this retrans_buff*/
-   struct cell* my_T;
+       /*the cell that containes this retrans_buff*/
+       struct cell* my_T;
 
        enum lists retr_list;
+       /* set to status code if the buffer is a reply, 0 if request */
+       int reply;
 
 }retrans_buff_type;
 
@@ -76,17 +78,28 @@ typedef struct cell
 
        /* useful data */
        /* UA Server */
-       struct sip_msg         *inbound_request;
-       struct retrans_buff   outbound_response;
-       unsigned int             status;
-       str*                             tag;
-       unsigned int             inbound_request_isACKed;
-       int                              relaied_reply_branch;
-       int                               nr_of_outgoings;
+       struct sip_msg          *inbound_request;
+       struct retrans_buff     outbound_response;
+       unsigned int            status;
+       str*                            tag;
+       unsigned int            inbound_request_isACKed;
+       int                                     relaied_reply_branch;
+       int                                     nr_of_outgoings;
        /* UA Clients */
-       struct retrans_buff   *outbound_request[ MAX_FORK ];
-       struct sip_msg          *inbound_response[ MAX_FORK ];
-       unsigned int             outbound_request_isACKed[MAX_FORK];
+       struct retrans_buff     *outbound_request[ MAX_FORK ];
+       struct sip_msg          *inbound_response[ MAX_FORK ];
+       /* unsigned int         outbound_request_isACKed[MAX_FORK]; */
+       struct retrans_buff     *outbound_ack[ MAX_FORK ];
+
+       /* protection against concurrent reply processing */
+       ser_lock_t      reply_mutex;
+       /* protection against concurrent ACK processing */
+       ser_lock_t      ack_mutex;
+
+       /* this is where destination is stored for picked branch;
+          good if a need to forward ACK later on
+       */
+       struct sockaddr_in ack_to;
 
 #ifdef EXTRA_DEBUG
        /* scheduled for deletion ? */
@@ -125,5 +138,6 @@ void free_cell( struct cell* dead_cell );
 struct cell*  build_cell( struct sip_msg* p_msg );
 void remove_from_hash_table( struct s_table *hash_table, struct cell * p_cell );
 void insert_into_hash_table( struct s_table *hash_table, struct cell * p_cell );
+void insert_into_hash_table_unsafe( struct s_table *hash_table, struct cell * p_cell );
 
 #endif
index e6d0894..0d50421 100644 (file)
 */
 
 /* keep the semaphore here */
-int entry_semaphore=0, transaction_timer_semaphore=0, retrasmission_timer_semaphore=0;
-/* and the number of semaphores in the entry_semaphore set */
-int sem_nr;
+static int
+       entry_semaphore=0, 
+       timer_semaphore=0, 
+       reply_semaphore=0,
+       ack_semaphore=0;
+/* and the maximum number of semaphores in the entry_semaphore set */
+static int sem_nr;
+/* timer group locks */
+
+ser_lock_t timer_group_lock[TG_NR];
+
 
 
 /* intitialize the locks; return 0 on success, -1 otherwise
@@ -57,16 +65,16 @@ int lock_initialize()
        DBG("DEBUG: lock_initialize: lock initialization started\n");
 
        /* transaction timers */
-       if ((transaction_timer_semaphore=init_semaphore_set( NR_OF_TIMER_LISTS) ) < 0) {
-                LOG(L_ERR, "ERROR: lock_initialize:  transaction timer semaphore initialization failure\n");
+       if ((timer_semaphore= init_semaphore_set( TG_NR ) ) < 0) {
+                LOG(L_ERR, "ERROR: lock_initialize:  "
+                       "transaction timer semaphore initialization failure\n");
                goto error;
        }
 
-       /* message retransmission timers
-        if ((retrasmission_timer_semaphore=init_semaphore_set( NR_OF_RT_LISTS) ) < 0) {
-                LOG(L_ERR, "ERROR: lock_initialize:  retransmission timer semaphore initialization failure\n");
-                goto error;
-        } */
+       for (i=0; i<TG_NR; i++) {
+               timer_group_lock[i].semaphore_set = timer_semaphore;
+               timer_group_lock[i].semaphore_index = timer_group[ i ]; 
+       }
 
 
        i=SEM_MIN;
@@ -106,10 +114,14 @@ int lock_initialize()
                        }
                }
        } while(1);
-
        sem_nr=i;       
+
+       reply_semaphore=init_semaphore_set( sem_nr );
+       ack_semaphore=init_semaphore_set(sem_nr);
+
+
        /* return success */
-       printf("INFO: %d entry semaphores allocated\n", sem_nr );
+       LOG(L_INFO, "INFO: semaphore arrays of size %d allocated\n", sem_nr );
        return 0;
 error:
        lock_cleanup();
@@ -117,7 +129,7 @@ error:
 }
 
 /* return -1 if semget failed, -2 if semctl failed */
-int init_semaphore_set( int size )
+static int init_semaphore_set( int size )
 {
        int new_semaphore, i;
 
@@ -160,14 +172,17 @@ void lock_cleanup()
        if (entry_semaphore > 0 && 
            semctl( entry_semaphore, 0 , IPC_RMID , 0 )==-1)
                LOG(L_ERR, "ERROR: lock_cleanup, entry_semaphore cleanup failed\n");
-       if (transaction_timer_semaphore > 0 && 
-           semctl( transaction_timer_semaphore, 0 , IPC_RMID , 0 )==-1)
-               LOG(L_ERR, "ERROR: lock_cleanup, transaction_timer_semaphore cleanup failed\n");
-       if (retrasmission_timer_semaphore > 0 &&
-           semctl( retrasmission_timer_semaphore, 0 , IPC_RMID , 0 )==-1)
-               LOG(L_ERR, "ERROR: lock_cleanup, retrasmission_timer_semaphore cleanup failed\n");
-
-       entry_semaphore = transaction_timer_semaphore = retrasmission_timer_semaphore = 0;
+       if (timer_semaphore > 0 && 
+           semctl( timer_semaphore, 0 , IPC_RMID , 0 )==-1)
+               LOG(L_ERR, "ERROR: lock_cleanup, timer_semaphore cleanup failed\n");
+       if (reply_semaphore > 0 &&
+           semctl( reply_semaphore, 0 , IPC_RMID , 0 )==-1)
+               LOG(L_ERR, "ERROR: lock_cleanup, reply_semaphore cleanup failed\n");
+       if (ack_semaphore > 0 &&
+           semctl( ack_semaphore, 0 , IPC_RMID , 0 )==-1)
+               LOG(L_ERR, "ERROR: lock_cleanup, ack_semaphore cleanup failed\n");
+
+       entry_semaphore = timer_semaphore = reply_semaphore = ack_semaphore = 0;
 
 }
 
@@ -199,8 +214,7 @@ inline int _unlock( ser_lock_t s )
        return change_semaphore( s, +1 );
 }
 
-
-int change_semaphore( ser_lock_t s  , int val )
+static int change_semaphore( ser_lock_t s  , int val )
 {
        struct sembuf pbuf;
        int r;
@@ -217,27 +231,18 @@ tryagain:
                        DBG("signal received in a semaphore\n");
                        goto tryagain;
                } else LOG(L_ERR, "ERROR: change_semaphore: %s\n", strerror(errno));
-    }
-   return r;
+       }
+       return r;
 }
 
 
-/*
 int init_cell_lock( struct cell *cell )
 {
-*/
-       /* just advice which of the available semaphores to use;
-               shared with the lock belonging to the next hash entry lock
-            (so that there are no collisions if one wants to try to
-             lock on a cell as well as its list)
-
-        */
-/*
-       cell->mutex.semaphore_set=entry_semaphore,
-       cell->mutex.semaphore_index=(cell->hash_index % sem_nr + 1)%sem_nr;
-
+       cell->reply_mutex.semaphore_set=reply_semaphore;
+       cell->reply_mutex.semaphore_index = cell->hash_index % sem_nr;
+       cell->ack_mutex.semaphore_set=ack_semaphore;
+       cell->ack_mutex.semaphore_index = cell->hash_index % sem_nr;
 }
-*/
 
 int init_entry_lock( struct s_table* hash_table, struct entry *entry )
 {
@@ -254,28 +259,21 @@ int init_entry_lock( struct s_table* hash_table, struct entry *entry )
 int init_timerlist_lock( struct s_table* hash_table, enum lists timerlist_id)
 {
        /* each timer list has its own semaphore */
-       hash_table->timers[timerlist_id].mutex.semaphore_set=transaction_timer_semaphore;
-       hash_table->timers[timerlist_id].mutex.semaphore_index=timerlist_id;
-}
-/*
-int init_retr_timer_lock( struct s_table* hash_table, enum retransmission_lists list_id )
-{
-       hash_table->retr_timers[list_id].mutex.semaphore_set=retrasmission_timer_semaphore;
-       hash_table->retr_timers[list_id].mutex.semaphore_index=list_id;
+       /*
+       hash_table->timers[timerlist_id].mutex.semaphore_set=timer_semaphore;
+       hash_table->timers[timerlist_id].mutex.semaphore_index=timer_group[timerlist_id];
+       */
+
+       hash_table->timers[timerlist_id].mutex=timer_group_lock[ timer_group[timerlist_id] ];
 }
-*/
 
-/*
 int release_cell_lock( struct cell *cell )
 {
-*/
        /* don't do anything here -- the init_*_lock procedures
           just advised on usage of shared semaphores but did not
           generate them
        */
-/*
 }
-*/
 
 int release_entry_lock( struct entry *entry )
 {
@@ -286,8 +284,3 @@ release_timerlist_lock( struct timer *timerlist )
 {
        /* the same as above */
 }
-/*
-int release_retr_timer_lock( struct timer *timerlist )
-{
-
-} */
index 722d1f9..05ade95 100644 (file)
@@ -18,6 +18,16 @@ typedef struct {
        int semaphore_index;
 } ser_lock_t;
 
+enum timer_groups {
+       TG_FR,
+       TG_WT,
+       TG_DEL,
+       TG_RT,
+       TG_NR
+};
+
+extern ser_lock_t timer_group_lock[TG_NR];
+
 
 #include "h_table.h"
 #include "timer.h"
@@ -27,7 +37,7 @@ typedef struct {
 
 
 int lock_initialize();
-int init_semaphore_set( int size );
+static int init_semaphore_set( int size );
 void lock_cleanup();
 
 
@@ -43,12 +53,10 @@ int _unlock( ser_lock_t s );
 #      define unlock(_s) _unlock( (_s) )
 #endif
 
-int change_semaphore( ser_lock_t s  , int val );
+static int change_semaphore( ser_lock_t s  , int val );
 
 int init_cell_lock( struct cell *cell );
 int init_entry_lock( struct s_table* hash_table, struct entry *entry );
-// int init_timerlist_lock( struct s_table* hash_table, enum lists timerlist_id);
-//int init_retr_timer_lock( struct s_table* hash_table, enum retransmission_lists list_id );
 
 int release_cell_lock( struct cell *cell );
 int release_entry_lock( struct entry *entry );
index a4e7141..70c4ac5 100644 (file)
@@ -11,7 +11,6 @@
 #include "../../ut.h"
 #include "../../timer.h"
 
-
 struct cell         *T;
 unsigned int     global_msg_id;
 struct s_table*  hash_table;
@@ -20,10 +19,11 @@ struct s_table*  hash_table;
 
 
 /* determine timer length and put on a correct timer list */
-static inline void set_timer( struct s_table *hash_table,
+inline void set_timer( struct s_table *hash_table,
        struct timer_link *new_tl, enum lists list_id )
 {
        unsigned int timeout;
+       struct timer* list;
        static enum lists to_table[NR_OF_TIMER_LISTS] =
                {       FR_TIME_OUT, INV_FR_TIME_OUT, WT_TIME_OUT, DEL_TIME_OUT,
                        RETR_T1, RETR_T1 << 1,  RETR_T1 << 2, RETR_T2 };
@@ -36,15 +36,25 @@ static inline void set_timer( struct s_table *hash_table,
                return;
        }
        timeout = to_table[ list_id ];
+       list= &(hash_table->timers[ list_id ]);
+/*
        add_to_tail_of_timer_list( &(hash_table->timers[ list_id ]),
                new_tl,get_ticks()+timeout);
+*/
+       lock(  list->mutex );
+       /* make sure I'm not already on a list */
+       remove_timer_unsafe( new_tl );
+       add_timer_unsafe( list, new_tl, get_ticks()+timeout);
+       unlock( list->mutex );
 }
 
 /* remove from timer list */
-static inline void reset_timer( struct s_table *hash_table,
+inline void reset_timer( struct s_table *hash_table,
        struct timer_link* tl )
 {
-       remove_from_timer_list( tl );
+       lock( timer_group_lock[ tl->tg ] );
+       remove_timer_unsafe( tl );
+       unlock( timer_group_lock[ tl->tg ] );
 }
 
 static inline void reset_retr_timers( struct s_table *h_table,
@@ -54,15 +64,29 @@ static inline void reset_retr_timers( struct s_table *h_table,
        struct retrans_buff *rb;
 
        DBG("DEBUG:stop_RETR_and_FR_timers : start \n");
-       reset_timer( h_table, &(p_cell->outbound_response.retr_timer));
-       reset_timer( h_table, &(p_cell->outbound_response.fr_timer));
-
+       /* lock the first timer list of the FR group -- all other
+          lists share the same lock
+       */
+       lock(  hash_table->timers[FR_TIMER_LIST].mutex );
+       /* reset_timer( h_table, &(p_cell->outbound_response.retr_timer)); */
+       remove_timer_unsafe( & p_cell->outbound_response.retr_timer );
        for( ijk=0 ; ijk<(p_cell)->nr_of_outgoings ; ijk++ )  { 
                        if ( rb = p_cell->outbound_request[ijk] ) {
-                               reset_timer(h_table, &(rb->retr_timer));
-                               reset_timer(h_table, &(rb->fr_timer));
+                               /* reset_timer(h_table, &(rb->retr_timer)); */
+                               remove_timer_unsafe( & rb->retr_timer );
                        }
                } 
+       unlock(  hash_table->timers[FR_TIMER_LIST].mutex );
+       lock(  hash_table->timers[RT_T1_TO_1].mutex );
+       /* reset_timer( h_table, &(p_cell->outbound_response.fr_timer)); */
+       remove_timer_unsafe( & p_cell->outbound_response.fr_timer );
+       for( ijk=0 ; ijk<(p_cell)->nr_of_outgoings ; ijk++ )  { 
+                       if ( rb = p_cell->outbound_request[ijk] ) {
+                               /* reset_timer(h_table, &(rb->fr_timer)); */
+                               remove_timer_unsafe( & rb->fr_timer );
+                       }
+               } 
+       unlock(  hash_table->timers[RT_T1_TO_1].mutex );
        DBG("DEBUG:stop_RETR_and_FR_timers : stop\n");
 }
 
@@ -139,7 +163,7 @@ void tm_shutdown()
  *       1 - a new transaction was created
  *      -1 - error, including retransmission
  */
-int t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar )
+int t_add_transaction( struct sip_msg* p_msg )
 {
    struct cell*    new_cell;
 
@@ -153,14 +177,14 @@ int t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar )
    }
 
    /* it's about the same transaction or not?*/
-       if (t_check( p_msg , 0 )==-1) return -1;
+       /* if (t_check( p_msg , 0 )==-1) return -1; */
 
    /* if the lookup's result is not 0 means that it's a retransmission */
-   if ( T )
+   /* if ( T )
    {
       LOG(L_ERR,"ERROR: t_add_transaction: won't add a retransmission\n");
       return -1;
-   }
+   } */
 
    /* creates a new transaction */
    new_cell = build_cell( p_msg ) ;
@@ -181,7 +205,7 @@ int t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar )
 
 
 
-
+#ifdef _OBSOLETED_TM
 /* function returns:
  *       1 - forward successfull
  *      -1 - error during forward
@@ -200,14 +224,16 @@ int t_forward( struct sip_msg* p_msg , unsigned int dest_ip_param , unsigned int
        branch = 0;     /* we don't do any forking right now */
 
        /* it's about the same transaction or not? */
-       if (t_check( p_msg , 0 )==-1) return -1;
+       /* if (t_check( p_msg , 0 )==-1) return -1; */
 
        /*if T hasn't been found after all -> return not found (error) */
+       /*
        if ( !T )
        {
                DBG("DEBUG: t_forward: no transaction found for request forwarding\n");
                return -1;
        }
+       */
 
        /*if it's an ACK and the status is not final or is final, but error the
        ACK is not forwarded*/
@@ -281,6 +307,8 @@ int t_forward( struct sip_msg* p_msg , unsigned int dest_ip_param , unsigned int
                }
                shm_unlock();
                memset( rb , 0 , sizeof (struct retrans_buff) );
+               rb->retr_timer.tg=TG_RT;
+               rb->fr_timer.tg=TG_FR;
                rb->retr_buffer = shbuf;
                rb->retr_timer.payload =  rb;
                rb->fr_timer.payload =  rb;
@@ -351,7 +379,7 @@ error:
  *       1 - forward successfull
  *      -1 - error during forward
  */
-int t_forward_uri( struct sip_msg* p_msg, char* foo, char* bar  )
+int t_forward_uri( struct sip_msg* p_msg  )
 {
    unsigned int     ip, port;
 
@@ -363,186 +391,170 @@ int t_forward_uri( struct sip_msg* p_msg, char* foo, char* bar  )
 
    return t_forward( p_msg , ip , port );
 }
+#endif
 
 
-
-
-/*  This function is called whenever a reply for our module is received; we need to register
-  *  this function on module initialization;
+/*  This function is called whenever a reply for our module is received; 
+  * we need to register  this function on module initialization;
   *  Returns :   0 - core router stops
-  *                    1 - core router relay statelessly
+  *              1 - core router relay statelessly
   */
 int t_on_reply_received( struct sip_msg  *p_msg )
 {
-       unsigned int  branch,len, msg_status, msg_class;
-       struct sip_msg *clone;
+       unsigned int  branch,len, msg_status, msg_class, save_clone;
+       struct sip_msg *clone, *backup;
        int relay;
+       int start_fr;
+       int is_invite;
        struct retrans_buff *rb;
 
-       clone=NULL;
 
-       /* if a reply received which has not all fields we might want to
-          have for stateul forwarding, give the stateless router
-          a chance for minimum routing; parse only what's needed
-          for MPLS-ize reply matching
-       */
+       /* make sure we know the assosociated tranaction ... */
        if (t_check( p_msg  , &branch )==-1) return 1;
+       /* ... if there is no such, tell the core router to forward statelessly */
+       if ( T<=0 ) return 1;
 
-       /* if no T found ->tell the core router to forward statelessly */
-       if ( T<=0 )
-               return 1;
        DBG("DEBUG: t_on_reply_received: Original status =%d\n",T->status);
 
-       /* we were not able to process the response due to memory
-          shortage; simply drop it; hopefuly, we will have more
-       memory on the next try */
+       /* it can take quite long -- better do it now than later 
+          inside a reply_lock */
+       if (!(clone=sip_msg_cloner( p_msg ))) {
+               goto error;
+       }
        msg_status=p_msg->REPLY_STATUS;
        msg_class=REPLY_CLASS(p_msg);
-       relay = t_should_relay_response( T , msg_status );
-
-       if (relay && !(clone=sip_msg_cloner( p_msg ))) {
-               T_UNREF( T );
-               return 0;
-       }
+       is_invite= T->inbound_request->REQ_METHOD==METHOD_INVITE;
 
+       /* *** stop timers *** */
        rb=T->outbound_request[branch];
-
        /* stop retransmission */
        reset_timer( hash_table, &(rb->retr_timer));
-
        /* stop final response timer only if I got a final response */
        if ( msg_class>1 )
                reset_timer( hash_table, &(rb->fr_timer));
-       /* if a got the first prov. response for an INVITE ->
+
+       LOCK_REPLIES( T );
+       /* if a got the first prov. response for an INVITE ->
           change FR_TIME_OUT to INV_FR_TIME_UT */
-       if (!T->inbound_response[branch] && msg_class==1
-        && T->inbound_request->REQ_METHOD==METHOD_INVITE )
-               set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
-       /* get response for INVITE */
-       if ( T->inbound_request->REQ_METHOD==METHOD_INVITE )
-       {
-               if ( T->outbound_request_isACKed[branch] )
-               {       /*retransmit the last ACK*/
-                       DBG("DEBUG: t_on_reply_received: retransmitting ACK!!!!!!!!!!!!!!!!!!+!+!+!!\n");
-                       SEND_BUFFER( T->outbound_request[branch] );
-               } else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
-                       DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
-                       if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
-                       {
-                               LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
-                               if (clone ) sip_msg_free( clone );
-                               T_UNREF( T );
-                               return 0;
-                       }
-               }
-       }
+       start_fr = !T->inbound_response[branch] && msg_class==1 && is_invite;
 
-#      ifdef FORKING
-       /* skipped for the moment*/
-#      endif
+       /* *** store and relay message as needed *** */
+       relay = t_should_relay_response( T , msg_status, branch, &save_clone );
 
-       /* if the incoming response code is not reliable->drop it*/
-       if (!relay) {
-               T_UNREF( T );
-               return 0;
+       if (save_clone) {
+               /* release previously hold message */
+               backup = T->inbound_response[branch];
+               T->inbound_response[branch] = clone;
+       } else {
+               backup = NULL;
+               sip_msg_free( clone );
        }
 
-       /* restart retransmission if provisional response came for a non_INVITE ->
-               retrasmit at RT_T2*/
-       if ( msg_class==1 && T->inbound_request->REQ_METHOD!=METHOD_INVITE )
-       {
-               rb->retr_list = RT_T2;
-               set_timer( hash_table, &(rb->retr_timer), RT_T2 );
+       if (relay>=0 &&  push_reply_from_uac_to_uas( T, relay)==-1 ) {
+               /* restore original state first */
+               if (save_clone) T->inbound_response[branch] = backup;
+               /* restart FR */
+               start_fr=1;
+               goto cleanup;
        }
 
-       /*store the inbound reply - if there is a previous reply, replace it */
-       if ( T->inbound_response[branch] ) {
-               sip_msg_free( T->inbound_response[branch] ) ;
-               DBG("DEBUG: t_store_incoming_reply: previous inbound reply freed....\n");
-       }
-       T->inbound_response[branch] = clone;
 
-       if ( msg_class>=3 && msg_class<=5 )
+       /* *** ACK handling *** */
+       if ( is_invite )
        {
-               if ( t_all_final(T) && relay_lowest_reply_upstream( T , p_msg )==-1 && clone )
-                       goto error;
-       } else {
-               if (push_reply_from_uac_to_uas( T , branch )==-1 && clone )
-                       goto error;
+               if ( T->outbound_ack[branch] )
+               {   /*retransmit*/
+                       SEND_BUFFER( T->outbound_ack[branch] );
+               } else if (msg_class>2 ) {   /*on a non-200 reply to INVITE*/
+                       DBG("DEBUG: t_on_reply_received: >=3xx reply to INVITE: send ACK\n");
+                       if ( t_build_and_send_ACK( T , branch , p_msg )==-1)
+                       {
+                               LOG( L_ERR , "ERROR: t_on_reply_received: unable to send ACK\n" );
+                                       /* restart FR */
+                                       start_fr=1;
+                       }
+                       }
+       }
+cleanup:
+       UNLOCK_REPLIES( T );
+       if (backup) sip_msg_free(backup);
+       if (start_fr) set_timer( hash_table, &(rb->fr_timer), FR_INV_TIMER_LIST );
+       /* restart retransmission if a provisional response came for 
+          a non_INVITE -> retrasmit at RT_T2*/
+       if ( msg_class==1 && !is_invite )
+       {
+               rb->retr_list = RT_T2;
+               set_timer( hash_table, &(rb->retr_timer), RT_T2 );
        }
-
-       /* nothing to do for the ser core */
-       T_UNREF( T );
-       return 0;
-
 error:
        T_UNREF( T );
-       T->inbound_response[branch]=NULL;
-       sip_msg_free( clone );
-       /* don't try to relay statelessly on error */
+       /* don't try to relay statelessly on error; on troubles, simply do nothing;
+           that will make the other party to retransmit; hopefuly, we'll then 
+           be better off */
        return 0;
 }
 
-
-int t_on_request_received( struct sip_msg  *p_msg , unsigned int ip , unsigned int port)
+#ifdef _OBSOLETED_TM
+int t_on_request_received( struct sip_msg  *p_msg , 
+       unsigned int ip , unsigned int port)
 {
        if ( t_check( p_msg , 0 ) )
        {
                if ( p_msg->first_line.u.request.method_value==METHOD_ACK )
                {
-                       LOG( L_INFO , "SER: ACK received -> t_release\n");
+                       DBG( "SER: ACK received -> t_release\n");
                        if ( !t_forward( p_msg , ip , port ) )
                        {
-                               LOG( L_WARN, "SER: WARNING: bad forward\n");
+                               DBG( "SER: WARNING: bad forward\n");
                        }
                        if ( !t_release_transaction( p_msg ) )
                        {
-                               LOG( L_WARN ,"SER: WARNING: bad t_release\n");
+                               DBG( "SER: WARNING: bad t_release\n");
                        }
                }
                else
                {
-                       if ( !t_retransmit_reply( p_msg , 0, 0) )
+                       if ( !t_retransmit_reply( p_msg ) )
                        {
-                               LOG( L_WARN, "SER: WARNING: bad t_retransmit_reply\n");
+                               DBG( "SER: WARNING: bad t_retransmit_reply\n");
                        }
-                       LOG( L_INFO, "SER: yet another annoying retranmission\n");
+                       DBG( "SER: yet another annoying retranmission\n");
                }
-               t_unref( p_msg,0,0 );
+               t_unref( /* p_msg */ );
        } else {
                if ( p_msg->first_line.u.request.method_value==METHOD_ACK )
                {
-                       LOG( L_INFO , "SER: forwarding ACK  statelessly\n");
+                       DBG( "SER: forwarding ACK  statelessly\n");
                        /* no established transaction ... forward ACK just statelessly*/
                        forward_request( p_msg , mk_proxy_from_ip(ip,port) );
                }
                else
                {
                        /* establish transaction*/
-                       if ( !t_add_transaction(p_msg,0,0) )
+                       if ( !t_add_transaction(p_msg) )
                        {
-                               LOG( L_ERR , "ERROR in ser: t_add_transaction\n");
+                               DBG( "SER: ERROR in ser: t_add_transaction\n");
                        }
                        /* reply */
                        if ( p_msg->first_line.u.request.method_value==METHOD_CANCEL)
                        {
-                               LOG( L_INFO, "SER: new CANCEL\n");
+                               DBG( "SER: new CANCEL\n");
                                if ( !t_send_reply( p_msg , 200, "glad to cancel") )
                                {
-                                       LOG( L_ERR ,"SER:ERROR: t_send_reply\n");
+                                       DBG( "SER:ERROR: t_send_reply\n");
                                }
                        } else {
-                               LOG( L_INFO, "SER: new transaction\n");
+                               DBG( "SER: new transaction\n");
                                if ( !t_send_reply( p_msg , 100 , "trying -- your call is important to us") )
                                {
-                                       LOG( L_ERR, "SER: ERROR: t_send_reply (100)\n");
+                                       DBG( "SER: ERROR: t_send_reply (100)\n");
                                }
                        }
                        if ( !t_forward( p_msg, ip, port ) )
                        {
-                               LOG( L_ERR , "SER:ERROR: t_forward \n");
+                               DBG( "SER:ERROR: t_forward \n");
                        }
-                       t_unref( p_msg , 0 , 0);
+                       t_unref( /* p_msg */ );
                }
        }
 
@@ -565,19 +577,21 @@ int t_on_request_received_uri( struct sip_msg  *p_msg )
        return t_on_request_received( p_msg , ip , port );
 }
 
-
+#endif
 
 
 /*   returns 1 if everything was OK or -1 for error
   */
 int t_release_transaction( struct sip_msg* p_msg)
 {
+/*
        if (t_check( p_msg  , 0 )==-1) return 1;
 
    if ( T && T!=T_UNDEFINED )
+*/
       return t_put_on_wait( T );
 
-   return 1;
+/*   return 1; */
 }
 
 
@@ -590,28 +604,32 @@ int t_release_transaction( struct sip_msg* p_msg)
   * Returns  -1 -error
   *                1 - OK
   */
-int t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar  )
+int t_retransmit_reply( struct sip_msg* p_msg   )
 {
-       if (t_check( p_msg  , 0 )==-1) return 1;
+/*     if (t_check( p_msg  , 0 )==-1) return 1; */
 
    /* if no transaction exists or no reply to be resend -> out */
-   if ( T )
+/*   if ( T ) */
    {
+       LOCK_REPLIES( T );
        SEND_BUFFER( & T->outbound_response );
+       UNLOCK_REPLIES( T );
        return 1;
    }
 
   /* no transaction found */
-   return -1;
+/*   return -1; */
 }
 
 
 
 
-int t_unref( struct sip_msg* p_msg, char* foo, char* bar )
+int t_unref( /* struct sip_msg* p_msg */ )
 {
+/*
        if (T==T_UNDEFINED || T==T_NULL)
                return -1;
+*/
        T_UNREF( T );
        T=T_UNDEFINED;
        return 1;
@@ -626,11 +644,11 @@ int t_unref( struct sip_msg* p_msg, char* foo, char* bar )
 int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
 {
        unsigned int len, buf_len;
-       char * buf;
+       char * buf, *shbuf;
        struct retrans_buff *rb;
 
        DBG("DEBUG: t_send_reply: entered\n");
-       if (t_check( p_msg , 0 )==-1) return -1;
+       /* if (t_check( p_msg , 0 )==-1) return -1;
 
        if (!T)
        {
@@ -638,6 +656,17 @@ int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
                        "for which no T-state has been established\n");
                return -1;
        }
+       */
+
+       buf = build_res_buf_from_sip_req( code , text , T->inbound_request , &len );
+       DBG("DEBUG: t_send_reply: buffer computed\n");
+       if (!buf)
+       {
+               DBG("DEBUG: t_send_reply: response building failed\n");
+               goto error;
+       }
+
+       LOCK_REPLIES( T );
 
        rb = & T->outbound_response;
        if (!rb->retr_buffer) {
@@ -650,23 +679,18 @@ int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
                        goto error;
                }
 
+               rb->retr_timer.tg=TG_RT;
+               rb->fr_timer.tg=TG_FR;
                rb->retr_timer.payload = rb;
                rb->fr_timer.payload = rb;
                rb->to.sin_family = AF_INET;
                rb->my_T = T;
+               rb->reply = code;
        }
 
-       buf = build_res_buf_from_sip_req( code , text , T->inbound_request , &len );
-       DBG("DEBUG: t_send_reply: buffer computed\n");
-       if (!buf)
-       {
-               DBG("DEBUG: t_send_reply: response building failed\n");
-               goto error;
-       }
 
        /* if this is a first reply (?100), longer replies will probably follow;
-       try avoiding shm_resize by higher buffer size
-    */
+          try avoiding shm_resize by higher buffer size */
        buf_len = rb->retr_buffer ? len : len + REPLY_OVERBUFFER_LEN;
 
        if (! (rb->retr_buffer = (char*)shm_resize( rb->retr_buffer, buf_len )))
@@ -676,16 +700,18 @@ int t_send_reply(  struct sip_msg* p_msg , unsigned int code , char * text )
        }
        rb->bufflen = len ;
        memcpy( rb->retr_buffer , buf , len );
-       free( buf ) ;
        T->status = code;
+       SEND_BUFFER( rb );
+       /* needs to be protected too because what timers are set depends
+          on current transactions status
+       */
+       t_update_timers_after_sending_reply( rb );
+       UNLOCK_REPLIES( T );
 
+       free( buf ) ;
        /* start/stops the proper timers*/
-       DBG("DEBUG: t_send_reply: update timers\n");
-       t_update_timers_after_sending_reply( rb );
 
-       DBG("DEBUG: t_send_reply: send reply\n");
-       /* t_retransmit_reply( p_msg, 0 , 0); */
-       SEND_BUFFER( rb );
+       DBG("DEBUG: t_send_reply: finished\n");
 
        return 1;
 
@@ -700,7 +726,7 @@ error:
 /* Push a previously stored reply from UA Client to UA Server
   * and send it out
   */
-int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
+static int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
 {
        char *buf;
        unsigned int len, buf_len;
@@ -719,10 +745,13 @@ int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
                                trans->inbound_response[branch]->via2->host.s );
                                goto error;
                }
+               rb->retr_timer.tg=TG_RT;
+               rb->fr_timer.tg=TG_FR;
                rb->retr_timer.payload = rb;
                rb->fr_timer.payload =  rb;
                rb->to.sin_family = AF_INET;
                rb->my_T = trans;
+               rb->reply = trans->inbound_response[branch]->REPLY_STATUS;
 
        } else {
                reset_timer( hash_table, &(rb->retr_timer));
@@ -752,14 +781,17 @@ int push_reply_from_uac_to_uas( struct cell* trans , unsigned int branch )
        /* update the status*/
        trans->status = trans->inbound_response[branch]->REPLY_STATUS;
        if ( trans->inbound_response[branch]->REPLY_STATUS>=200 &&
-       trans->relaied_reply_branch==-1 )
+               trans->relaied_reply_branch==-1 ) {
+
+               memcpy( & trans->ack_to, & trans->outbound_request[ branch ]->to,
+                       sizeof( struct sockaddr_in ) );
                trans->relaied_reply_branch = branch;
+       }
 
        /* start/stops the proper timers*/
        t_update_timers_after_sending_reply( rb );
 
        /*send the reply*/
-       /* t_retransmit_reply( trans->inbound_response[branch], 0 , 0 ); */
        SEND_BUFFER( rb );
        return 1;
 
@@ -778,54 +810,6 @@ error:
 
 
 
-/*  Checks if all the transaction's outbound request has a final response.
-  *  Return   1 - all are final
-  *                0 - some waitting
-  */
-int t_all_final( struct cell *Trans )
-{
-   unsigned int i;
-
-       for( i=0 ; i<Trans->nr_of_outgoings ; i++  )
-               if (  !Trans->inbound_response[i] ||
-               Trans->inbound_response[i]->REPLY_STATUS<=200 )
-                       return 0;
-
-       DBG("DEBUG: t_all_final: final state!!!!:)) \n");
-       return 1;
-}
-
-
-
-
-/* Picks the lowest code reply and send it upstream.
-  *  Returns -1 if no lowest find reply found (all provisional)
-  */
-int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg )
-{
-   unsigned int i            =0 ;
-   unsigned int lowest_i = -1;
-   int                 lowest_v = 999;
-
-   for(  ; i<T->nr_of_outgoings ; i++ )
-      if ( T->inbound_response[i] &&
-          T->inbound_response[i]->REPLY_STATUS>=200 &&
-          T->inbound_response[i]->REPLY_STATUS<lowest_v )
-      {
-         lowest_i =i;
-         lowest_v = T->inbound_response[i]->REPLY_STATUS;
-      }
-
-   DBG("DEBUG: relay_lowest_reply_upstream: lowest reply [%d]=%d\n",lowest_i,lowest_v);
-
-   if ( lowest_i != -1 && push_reply_from_uac_to_uas( T ,lowest_i ) == -1 )
-       return -1;
-
-   return lowest_i;
-}
-
-
-
 
 /*
   */
@@ -861,32 +845,79 @@ int t_update_timers_after_sending_reply( struct retrans_buff *rb )
 /* Checks if the new reply (with new_code status) should be sent or not
  *  based on the current
   * transactin status.
-  * Returns 1 - the response can be sent
-  *         0 - is not indicated to sent
+  * Returns    - branch number (0,1,...) which should be relayed
+               - -1 if nothing to be relayed
   */
-int t_should_relay_response( struct cell *Trans , int new_code )
+int t_should_relay_response( struct cell *Trans , int new_code, 
+       int branch , int *should_store )
 {
        int T_code;
+       int b, lowest_b, lowest_s;
 
        T_code = Trans->status;
 
-       if ( T_code >= 200 ) { /* if final response sent out ... */
-               if (new_code>=200 && new_code < 300  && /* relay only 2xx */
+       /* note: this code never lets replies to CANCEL go through;
+          we generate always a local 200 for CANCEL; 200s are
+          not relayed because it's not an INVITE transaction;
+          >= 300 are not relayed because 200 was already sent
+          out
+       */
+
+       /* if final response sent out, allow only INVITE 2xx  */
+       if ( T_code >= 200 ) { 
+               if (new_code>=200 && new_code < 300  && 
                        Trans->inbound_request->REQ_METHOD==METHOD_INVITE) {
                        DBG("DBG: t_should_relay: 200 INV after final sent\n");
-                       return 1;
+                       *should_store=1;
+                       return branch;
+               } else {
+                       *should_store=0;
+                       return -1;
                }
        } else { /* no final response sent yet */
-               if (new_code!=100) { /* all but "100 trying" */
-                       DBG("DBG: t_should_relay: !=100 -> relay\n");
-                       return 1;
+
+               /* negative replies subject to fork picking */
+               if (new_code >=300 ) {
+                       *should_store=1;
+                       /* if all_final return lowest */
+                       lowest_b=-1; lowest_s=999;
+                       for ( b=0; b<Trans->nr_of_outgoings ; b++ ) {
+                               /* "fake" for the currently processed branch */
+                               if (b==branch) {
+                                       if (new_code<lowest_s) {
+                                               lowest_b=b;
+                                               lowest_s=new_code;
+                                       }
+                                       continue;
+                               }
+                               /* there is still an unfinished UAC transaction; wait now! */
+                               if ( !Trans->inbound_response[b] ||
+                                       Trans->inbound_response[b]->REPLY_STATUS<200 )
+                                       return -1;
+                               if ( Trans->inbound_response[b]->REPLY_STATUS<lowest_s )
+                               {
+                                       lowest_b =b;
+                                       lowest_s = T->inbound_response[b]->REPLY_STATUS;
+                               }
+                       }
+                       return lowest_b;
+
+               /* 1xx except 100 and 2xx will be relayed */
+               } else if (new_code>100) {
+                       *should_store=1;
+                       return branch;
+               }
+               /* 100 won't be relayed */
+               else {
+                       if (!T->inbound_response[branch]) *should_store=1; 
+                       else *should_store=0;
+                       return -1;
                }
        }
-       DBG("DBG: t_should_relay: not to be relayed\n");
-       return 0;
-}
-
 
+       LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay\n");
+       abort();
+}
 
 
 /*
@@ -895,22 +926,42 @@ int t_put_on_wait(  struct cell  *Trans  )
 {
        struct timer_link *tl;
        unsigned int i;
+       struct retrans_buff* rb;
+
        if (is_in_timer_list2( &(Trans->wait_tl)))
        {
                DBG("DEBUG: t_put_on_wait: already on wait\n");
                return 1;
        }
 
+       /* remove from  retranssmision  and  final response   list */
        DBG("DEBUG: t_put_on_wait: stopping timers (FR and RETR)\n");
-       /**/
+       reset_retr_timers(hash_table,Trans) ;
+
+       /* cancel pending client transactions, if any */
        for( i=0 ; i<Trans->nr_of_outgoings ; i++ )
                if ( Trans->inbound_response[i] && 
                REPLY_CLASS(Trans->inbound_response[i])==1)
                t_cancel_branch(i);
 
-       /* make double-sure we have finished everything */
-       /* remove from  retranssmision  and  final response   list */
-       reset_retr_timers(hash_table,Trans) ;
+
+       /* we don't need outbound requests anymore -- let's save
+          memory and junk them right now!
+       */
+/*
+       shm_lock();
+       for ( i =0 ; i<Trans->nr_of_outgoings;  i++ )
+       {
+               if ( rb=Trans->outbound_request[i] )
+               {
+                       if (rb->retr_buffer) shm_free_unsafe( rb->retr_buffer );
+                       Trans->outbound_request[i] = NULL;
+                       shm_free_unsafe( rb );
+               }
+       }
+       shm_unlock();
+*/
+
        /* adds to Wait list*/
        set_timer( hash_table, &(Trans->wait_tl), WT_TIMER_LIST );
        return 1;
@@ -939,6 +990,7 @@ int t_build_and_send_ACK( struct cell *Trans, unsigned int branch, struct sip_ms
    char *ack_buf, *p, *via;
    unsigned int len, via_len;
    int n;
+       struct retrans_buff *srb;
 
    ack_buf = 0;
    via =0;
@@ -948,13 +1000,15 @@ int t_build_and_send_ACK( struct cell *Trans, unsigned int branch, struct sip_ms
 
    if ( parse_headers(rpl,HDR_TO)==-1 || !rpl->to )
    {
-       LOG(L_ERR, "ERROR: t_build_and_send_ACK: cannot generate a HBH ACK if key HFs in INVITE missing\n");
+       LOG(L_ERR, "ERROR: t_build_and_send_ACK: "
+               "cannot generate a HBH ACK if key HFs in reply missing\n");
        goto error;
    }
 
     len = 0;
     /*first line's len */
-    len += 4+p_msg->first_line.u.request.uri.len+1+p_msg->first_line.u.request.version.len+CRLF_LEN;
+    len += 4+p_msg->first_line.u.request.uri.len+1+
+               p_msg->first_line.u.request.version.len+CRLF_LEN;
     /*via*/
     via = via_builder( p_msg , &via_len );
     if (!via)
@@ -976,12 +1030,13 @@ int t_build_and_send_ACK( struct cell *Trans, unsigned int branch, struct sip_ms
    /* end of message */
    len += CRLF_LEN; /*new line*/
 
-   ack_buf = (char *)pkg_malloc( len +1);
-   if (!ack_buf)
-   {
-       LOG(L_ERR, "ERROR: t_build_and_send_ACK: cannot allocate memory\n");
-       goto error;
-   }
+   /* ack_buf = (char *)pkg_malloc( len +1); */
+       srb = (struct retrans_buff *) sh_malloc( sizeof(struct retrans_buff) + len + 1 );
+       if (!srb) {
+               LOG(L_ERR, "ERROR: t_build_and_send_ACK: cannot allocate memory\n");
+               goto error1;
+       }
+       ack_buf = (char *) srb + sizeof(struct retrans_buff);
 
    p = ack_buf;
    DBG("DEBUG: t_build_and_send_ACK: len = %d \n",len);
@@ -1037,31 +1092,14 @@ int t_build_and_send_ACK( struct cell *Trans, unsigned int branch, struct sip_ms
     memcpy( p , CRLF , CRLF_LEN );
     p += CRLF_LEN;
 
-   /* sends the ACK message to the same destination as the INVITE */
-   udp_send( ack_buf, p-ack_buf, (struct sockaddr*)&(Trans->outbound_request[branch]->to) , sizeof(struct sockaddr_in) );
-
-   /* registering the ACK as received, processed and send */
-   Trans->outbound_request_isACKed[branch] = 1;
-   if ( (Trans->outbound_request[branch]->retr_buffer =
-      (char*)shm_resize( Trans->outbound_request[branch]->retr_buffer, p-ack_buf) ))
-   {
-       memcpy ( Trans->outbound_request[branch]->retr_buffer , ack_buf , p-ack_buf);
-       Trans->outbound_request[branch]->bufflen = p-ack_buf;
-   }
-   else
-       Trans->outbound_request[branch]->bufflen = 0;
-
-
-   DBG("DEBUG: t_build_and_send_ACK: ACK sent\n");
-
-   /* free mem*/
-   if (ack_buf) pkg_free( ack_buf );
-   if (via) pkg_free(via );
-   return 0;
-
+       send_ack( T, branch, srb, p-ack_buf );
+       pkg_free( via );
+       DBG("DEBUG: t_build_and_send_ACK: ACK sent\n");
+       return 0;
+               
+error1:
+   pkg_free(via );
 error:
-   if (ack_buf) free( ack_buf );
-   if (via) pkg_free(via );
    return -1;
 }
 
@@ -1076,6 +1114,7 @@ void delete_cell( struct cell *p_cell )
                        p_cell);
                abort();
        }
+       /*
        if (is_in_timer_list2(& p_cell->outbound_response.retr_timer )) {
                LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and still on RETR (rep)\n",
                        p_cell);
@@ -1098,6 +1137,8 @@ void delete_cell( struct cell *p_cell )
                        abort();
                }
        }
+       */
+       reset_retr_timers( hash_table, p_cell );
 #endif
        /* still in use ... don't delete */
        if ( T_IS_REFED(p_cell) ) {
@@ -1113,7 +1154,7 @@ void delete_cell( struct cell *p_cell )
                /* it's added to del list for future del */
                set_timer( hash_table, &(p_cell->dele_tl), DELETE_LIST );
        } else {
-               DBG("DEBUG: delete_handler : delete transaction %p\n", p_cell );
+               DBG("DEBUG: delete transaction %p\n", p_cell );
                free_cell( p_cell );
        }
 }
@@ -1216,7 +1257,13 @@ void retransmission_handler( void *attr)
 
        /* retransmision */
        DBG("DEBUG: retransmission_handler : resending (t=%p)\n", r_buf->my_T);
-       SEND_BUFFER( r_buf );
+       if (r_buf->reply) {
+               LOCK_REPLIES( r_buf->my_T );
+               SEND_BUFFER( r_buf );
+               UNLOCK_REPLIES( r_buf->my_T );
+       } else {
+               SEND_BUFFER( r_buf );
+       }
 
        id = r_buf->retr_list;
        r_buf->retr_list = id < RT_T2 ? id + 1 : RT_T2;
@@ -1286,8 +1333,9 @@ void wait_handler( void *attr)
        /* the cell is removed from the hash table */
        DBG("DEBUG: wait_handler : removing %p from table \n", p_cell );
        remove_from_hash_table( hash_table, p_cell );
+       /* jku: no more here -- we do it when we put a transaction on wait */
        DBG("DEBUG: wait_handler : stopping all timers\n");
-       reset_retr_timers(hash_table,p_cell) ;
+       reset_retr_timers(hash_table,p_cell) ; 
        /* put it on DEL_LIST - sch for del */
 #ifdef EXTRA_DEBUG
        p_cell->damocles = 1;
index 49af62e..8fb3dec 100644 (file)
@@ -33,6 +33,11 @@ extern struct s_table*  hash_table;
 #include "sip_msg.h"
 
 
+#define LOCK_REPLIES(_t) lock((_t)->reply_mutex )
+#define UNLOCK_REPLIES(_t) unlock((_t)->reply_mutex )
+#define LOCK_ACK(_t) lock((_t)->ack_mutex )
+#define UNLOCK_ACK(_t) unlock((_t)->ack_mutex )
+
 
 /* convenience short-cut macros */
 #define REQ_METHOD first_line.u.request.method_value
@@ -112,6 +117,8 @@ extern struct s_table*  hash_table;
                DBG_REF("ref", (_T_cell));      })
 #endif
 
+enum addifnew_status { AIN_ERROR, AIN_RETR, AIN_NEW, AIN_NEWACK, AIN_OLDACK } ;
+
 
 int   tm_startup();
 void tm_shutdown();
@@ -121,7 +128,7 @@ void tm_shutdown();
  *       1 - a new transaction was created
  *      -1 - error, including retransmission
  */
-int  t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar  );
+int  t_add_transaction( struct sip_msg* p_msg  );
 
 
 
@@ -149,7 +156,7 @@ int t_forward( struct sip_msg* p_msg , unsigned int dst_ip ,
  *       1 - forward successfull
  *      -1 - error during forward
  */
-int t_forward_uri( struct sip_msg* p_msg , char* foo, char* bar );
+int t_forward_uri( struct sip_msg* p_msg  );
 
 
 
@@ -194,7 +201,7 @@ int t_release_transaction( struct sip_msg* );
   * Returns  -1 -error
   *                1 - OK
   */
-int t_retransmit_reply( struct sip_msg *, char* , char* );
+int t_retransmit_reply( struct sip_msg *  );
 
 
 
@@ -206,31 +213,59 @@ int t_send_reply( struct sip_msg * , unsigned int , char *  );
 
 
 /* releases T-context */
-int t_unref( struct sip_msg* p_msg, char* foo, char* bar );
+int t_unref( /* struct sip_msg* p_msg */ );
+
+int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
+    unsigned int dest_port_param );
+int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
+    unsigned int dest_port_param );
+
 
 
 
 struct cell* t_lookupOriginalT(  struct s_table* hash_table , struct sip_msg* p_msg );
 int t_reply_matching( struct sip_msg* , unsigned int*  );
 int t_store_incoming_reply( struct cell* , unsigned int , struct sip_msg* );
-int  t_lookup_request( struct sip_msg* p_msg );
+int  t_lookup_request( struct sip_msg* p_msg , int leave_new_locked );
 int t_all_final( struct cell * );
 int t_build_and_send_ACK( struct cell *Trans , unsigned int brach , struct sip_msg* rpl);
 int t_cancel_branch(unsigned int branch); //TO DO
-int t_should_relay_response( struct cell *Trans, int new_code );
+int t_should_relay_response( struct cell *Trans, int new_code, int branch, int *should_store );
 int t_update_timers_after_sending_reply( struct retrans_buff *rb );
 int t_put_on_wait(  struct cell  *Trans  );
 int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg );
-int push_reply_from_uac_to_uas( struct cell* Trans , unsigned int );
+static int push_reply_from_uac_to_uas( struct cell* Trans , unsigned int );
 int add_branch_label( struct cell *Trans, struct sip_msg *p_msg , int branch );
 int get_ip_and_port_from_uri( struct sip_msg* p_msg , unsigned int *param_ip, unsigned int *param_port);
 
+enum addifnew_status t_addifnew( struct sip_msg* p_msg );
+
 void retransmission_handler( void *);
 void final_response_handler( void *);
 void wait_handler( void *);
 void delete_handler( void *);
 
-
+inline int static send_ack( struct cell *t, int branch, 
+       struct retrans_buff *srb, int len )
+{
+       memset( srb, 0, sizeof( struct retrans_buff ) );
+       memcpy( & srb->to, & t->ack_to, sizeof (struct sockaddr_in));
+       srb->tolen = sizeof (struct sockaddr_in);
+       srb->my_T = t;
+       srb->retr_buffer = (char *) srb + sizeof( struct retrans_buff );
+       srb->bufflen = len;
+       LOCK_ACK( t );
+       if (t->outbound_ack[branch]) {
+               UNLOCK_ACK(t);
+               shm_free( srb );        
+               LOG(L_WARN, "send_ack: Warning: ACK already sent out\n");
+               return 0;
+       }
+       t->outbound_ack[branch] = srb;
+       SEND_BUFFER( srb );
+       UNLOCK_ACK( t );
+       return 1;
+}
 
 
 #endif
diff --git a/modules/tm/t_fwd.c b/modules/tm/t_fwd.c
new file mode 100644 (file)
index 0000000..f094a73
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * $Id$
+ *
+ */
+
+#include "hash_func.h"
+#include "t_funcs.h"
+#include "../../dprint.h"
+#include "../../config.h"
+#include "../../parser_f.h"
+#include "../../ut.h"
+#include "../../timer.h"
+
+/* function returns:
+ *       1 - forward successfull
+ *      -1 - error during forward
+ */
+int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param , 
+       unsigned int dest_port_param )
+{
+       unsigned int dest_ip     = dest_ip_param;
+       unsigned int dest_port  = dest_port_param;
+       int     branch;
+       unsigned int len;
+       char               *buf, *shbuf;
+       struct retrans_buff *rb;
+       
+
+       buf=NULL;
+       shbuf = NULL;
+       branch = 0;     /* we don't do any forking right now */
+
+       if ( T->outbound_request[branch]==NULL )
+       {
+               DBG("DEBUG: t_forward: first time forwarding\n");
+
+               /* special case : CANCEL */
+               if ( p_msg->REQ_METHOD==METHOD_CANCEL  )
+               {
+                       DBG("DEBUG: t_forward: it's CANCEL\n");
+                       /* find original cancelled transaction; if found, use its
+                          next-hops; otherwise use those passed by script */
+                       if ( T->T_canceled==T_UNDEFINED )
+                               T->T_canceled = t_lookupOriginalT( hash_table , p_msg );
+                       /* if found */
+                       if ( T->T_canceled!=T_NULL )
+                       {
+               
+                               /* if in 1xx status, send to the same destination */
+                               if ( (T->T_canceled->status/100)==1 )
+                               {
+                                       DBG("DEBUG: t_forward: it's CANCEL and I will send "
+                                               "to the same place where INVITE went\n");
+                                       dest_ip=T->T_canceled->outbound_request[branch]->
+                                               to.sin_addr.s_addr;
+                                       dest_port = T->T_canceled->outbound_request[branch]->
+                                               to.sin_port;
+                               } else { /* transaction exists, but nothing to cancel */
+                                               DBG("DEBUG: t_forward: it's CANCEL but "
+                                               "I have nothing to cancel here\n");
+                                       /* forward CANCEL as a stand-alone transaction */
+                                       /*      return 1; */
+                               }
+                       } else { /* transaction doesnot exists  */
+                               DBG("DEBUG: t_forward: canceled request not found! "
+                               "nothing to CANCEL\n");
+                               return 1;
+                       }
+       }/* end special case CANCEL*/
+
+               if ( add_branch_label( T, T->inbound_request , branch )==-1) 
+                       goto error;
+               if ( add_branch_label( T, p_msg , branch )==-1) 
+                       goto error;
+               if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len))) 
+                       goto error;
+
+               /* allocates a new retrans_buff for the outbound request */
+               DBG("DEBUG: t_forward: building outbound request\n");
+               shm_lock();
+               rb = (struct retrans_buff*) shm_malloc_unsafe( sizeof(struct retrans_buff)  );
+               if (!rb)
+               {
+                       LOG(L_ERR, "ERROR: t_forward: out of shmem\n");
+                       shm_unlock();
+                       goto error;
+               }
+               shbuf = (char *) shm_malloc_unsafe( len );
+               if (!shbuf)
+               {
+                       LOG(L_ERR, "ERROR: t_forward: out of shmem buffer\n");
+                       shm_unlock();
+                       goto error;
+               }
+               shm_unlock();
+               memset( rb , 0 , sizeof (struct retrans_buff) );
+               rb->retr_timer.tg=TG_RT;
+               rb->fr_timer.tg=TG_FR;
+               rb->retr_buffer = shbuf;
+               rb->retr_timer.payload =  rb;
+               rb->fr_timer.payload =  rb;
+               rb->my_T =  T;
+               T->nr_of_outgoings = 1;
+               rb->bufflen = len ;
+               memcpy( rb->retr_buffer , buf , len );
+               /* send the request */
+               /* known to be in network order */
+               rb->to.sin_port     =  dest_port;
+               rb->to.sin_addr.s_addr =  dest_ip;
+               rb->to.sin_family = AF_INET;
+               T->outbound_request[branch] = rb;
+               SEND_BUFFER( rb );
+               /* link the retransmission buffer to our structures when the job is done */
+               free( buf ) ; buf=NULL;
+
+               DBG("DEBUG: t_forward: starting timers (retrans and FR) %d\n",get_ticks() );
+               /*sets and starts the FINAL RESPONSE timer */
+               set_timer( hash_table, &(rb->fr_timer), FR_TIMER_LIST );
+
+               /* sets and starts the RETRANS timer */
+               rb->retr_list = RT_T1_TO_1;
+               set_timer( hash_table, &(rb->retr_timer), RT_T1_TO_1 );
+       }/* end for the first time */ else {
+               /* rewriting a request should really not happen -- retransmission
+              does not rewrite, whereas a new request should be written
+                  somewhere else
+               */
+               LOG( L_CRIT, "ERROR: t_forward_nonack: attempt to rewrite request structures\n");
+               return 0;
+       }
+
+       if (  p_msg->REQ_METHOD==METHOD_CANCEL )
+       {
+               DBG("DEBUG: t_forward: forwarding CANCEL\n");
+               /* if no transaction to CANCEL */
+      /* or if the canceled transaction has a final status -> drop the CANCEL*/
+               if ( T->T_canceled==T_NULL || T->T_canceled->status>=200)
+               {
+                       reset_timer( hash_table, &(rb->fr_timer ));
+                       reset_timer( hash_table, &(rb->retr_timer ));
+                       return 1;
+                       }
+       }
+
+
+   return 1;
+
+error:
+       if (shbuf) shm_free(shbuf);
+       if (rb) {
+               shm_free(rb);
+               T->outbound_request[branch]=NULL;
+       }
+       if (buf) free( buf );
+
+       return -1;
+
+}
+
+int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param , 
+       unsigned int dest_port_param )
+{
+
+       int branch;
+       int len;
+       char *buf;
+       struct sockaddr_in to_sock;
+       struct retrans_buff *rb;
+       struct retrans_buff *srb;
+
+
+       /* drop local ACKs */
+       if (T->status/100!=2 ) {
+               DBG("DEBUG: local ACK dropped\n");
+               return 1;
+       }
+
+       branch=T->relaied_reply_branch;
+       /* double-check for odd relaying */
+       if ( branch <0 || branch>=T->nr_of_outgoings ) {
+               DBG("DEBUG: t_forward_ack: strange relaied_reply_branch: %d out of %d\n", 
+                       branch, T->nr_of_outgoings );
+               return -1;
+       }
+       
+       DBG("DEBUG: t_forward: forwarding ACK [%d]\n",branch);
+       /* not able to build branch -- then better give up */
+       if ( add_branch_label( T, p_msg , branch )==-1) {
+               LOG( L_ERR, "ERROR: t_forward_ack failed to add branch label\n" );
+               return 0;
+       }
+       /* not able to build outbound request -- then better give up */
+       if ( !(buf = build_req_buf_from_sip_req  ( p_msg, &len)))  {
+               LOG( L_ERR, "ERROR: t_forward_ack failed to generate outbound message\n" );
+               return 0;
+       };
+
+#ifdef _DONT_USE
+       /* strange conditions -- no INVITE before me ?!?! */
+       if ( (rb=T->outbound_request[branch])==NULL ) {
+               /* better stateless than nothing */
+               goto fwd_sl;
+       }
+#endif
+
+       shm_lock();
+       /* check for bizzar race condition if two processes receive
+          two ACKs concurrently; use shmem semaphore for protection
+          -- we have to enter it here anyway (the trick with inACKed
+          inside the protection region)
+    */
+       if  (T->inbound_request_isACKed ) {
+               shm_unlock();
+               LOG(L_WARN, "Warning: ACK received when there's one; check upstream\n");
+               return 1;
+       }
+       srb = (struct retrans_buff *) shm_malloc_unsafe( sizeof( struct retrans_buff ) + len );
+       T->inbound_request_isACKed = 1;
+       shm_unlock();
+
+       memcpy( (char *) srb + sizeof ( struct retrans_buff ), buf, len );
+       free( buf );
+
+       send_ack( T, branch, srb, len );
+       return 1;
+
+fwd_sl: /* some strange conditions occured; try statelessly */
+       LOG(L_ERR, "ERROR: fwd-ing a 2xx ACK with T-state failed; "
+               "trying statelessly\n");
+       memset( &to_sock, sizeof to_sock, 0 );
+       to_sock.sin_family = AF_INET;
+       to_sock.sin_port =  dest_port_param;
+       to_sock.sin_addr.s_addr = dest_ip_param;
+       udp_send( buf, len, (struct sockaddr*)(&to_sock), 
+               sizeof(struct sockaddr_in) );
+       free( buf );
+       return 1;
+}
index 64352c5..71ab6ce 100644 (file)
@@ -77,11 +77,11 @@ inline static int int2reverse_hex( char **c, int *size, int nr )
  *      -1 - transaction wasn't found
  *       1  - transaction found
  */
-int t_lookup_request( struct sip_msg* p_msg )
+int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 {
    struct cell      *p_cell;
    struct cell      *tmp_cell;
-   unsigned int  hash_index=0;
+   /* unsigned int  hash_index=0; */
    unsigned int  isACK;
    struct sip_msg      *t_msg;
 
@@ -94,15 +94,15 @@ int t_lookup_request( struct sip_msg* p_msg )
       return 0;
    }
    /* start searching into the table */
-   hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;
+   p_msg->hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;
    isACK = p_msg->REQ_METHOD==METHOD_ACK;
-   DBG("t_lookup_request: start searching:  hash=%d, isACK=%d\n",hash_index,isACK);
+   DBG("t_lookup_request: start searching:  hash=%d, isACK=%d\n",p_msg->hash_index,isACK);
 
    /* lock the hole entry*/
-   lock( hash_table->entrys[hash_index].mutex );
+   lock( hash_table->entrys[p_msg->hash_index].mutex );
 
    /* all the transactions from the entry are compared */
-   p_cell     = hash_table->entrys[hash_index].first_cell;
+   p_cell     = hash_table->entrys[p_msg->hash_index].first_cell;
    tmp_cell = 0;
    while( p_cell )
    {
@@ -155,7 +155,7 @@ int t_lookup_request( struct sip_msg* p_msg )
 
    /* no transaction found */
    T = 0;
-   unlock( hash_table->entrys[hash_index].mutex );
+   if (!leave_new_locked) unlock( hash_table->entrys[p_msg->hash_index].mutex );
    DBG("DEBUG: t_lookup_request: no transaction found\n");
    return -1;
 
@@ -164,7 +164,7 @@ found:
    T_REF( T );
    DBG("DEBUG:XXXXXXXXXXXXXXXXXXXXX t_lookup_request: "
                    "transaction found ( T=%p , ref=%x)\n",T,T->ref_bitmap);
-   unlock( hash_table->entrys[hash_index].mutex );
+   unlock( hash_table->entrys[p_msg->hash_index].mutex );
    return 1;
 }
 
@@ -185,7 +185,8 @@ struct cell* t_lookupOriginalT(  struct s_table* hash_table , struct sip_msg* p_
    /* it's a CANCEL request for sure */
 
    /* start searching into the table */
-   hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number  ) ;
+   /* hash_index = hash( p_msg->callid->body , get_cseq(p_msg)->number  ) ; */
+       hash_index = p_msg->hash_index;
    DBG("DEBUG: t_lookupOriginalT: searching on hash entry %d\n",hash_index );
 
    /* all the transactions from the entry are compared */
@@ -359,12 +360,12 @@ int t_check( struct sip_msg* p_msg , int *param_branch)
                        /* force parsing all the needed headers*/
                        if (parse_headers(p_msg, HDR_EOH )==-1)
                                return -1;
-               t_lookup_request( p_msg );
+               t_lookup_request( p_msg , 0 /* unlock before returning */ );
                } else {
                        if ( parse_headers(p_msg, HDR_VIA1|HDR_VIA2|HDR_TO|HDR_CSEQ )==-1 ||
                        !p_msg->via1 || !p_msg->via2 || !p_msg->to || !p_msg->cseq )
-                       return -1;
-               t_reply_matching( p_msg , ((param_branch!=0)?(param_branch):(&local_branch)) );
+                               return -1;
+                       t_reply_matching( p_msg , ((param_branch!=0)?(param_branch):(&local_branch)) );
                }
 #              ifdef EXTRA_DEBUG
                if ( T && T!=T_UNDEFINED && T->damocles) {
@@ -414,3 +415,66 @@ int add_branch_label( struct cell *trans, struct sip_msg *p_msg, int branch )
 
 }
 
+/* atomic "add_if_new" construct; it returns:
+       AIN_ERROR       if a fatal error (e.g, parsing) occured
+       AIN_RETR        it's a retransmission
+       AIN_NEW         it's a new request
+       AIN_NEWACK      it's an ACK for which no transaction exists
+       AIN_OLDACK      it's an ACK for an existing transaction
+*/
+enum addifnew_status t_addifnew( struct sip_msg* p_msg )
+{
+
+       int ret, lret;
+       struct cell *new_cell;
+
+       /* is T still up-to-date ? */
+       DBG("DEBUG: t_check_new_request: msg id=%d , global msg id=%d , T on entrance=%p\n", 
+               p_msg->id,global_msg_id,T);
+       if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
+       {
+               global_msg_id = p_msg->id;
+               T = T_UNDEFINED;
+               /* transaction lookup */
+               /* force parsing all the needed headers*/
+               if (parse_headers(p_msg, HDR_EOH )==-1)
+                       return AIN_ERROR;
+               lret = t_lookup_request( p_msg, 1 /* leave locked */ );
+               if (lret==0) return AIN_ERROR;  
+               if (lret==-1) {
+                       /* transaction not found, it's a new request */
+                       if ( p_msg->REQ_METHOD==METHOD_ACK ) {
+                               ret=AIN_NEWACK;
+                       } else {
+                               /* add new transaction */
+                               new_cell = build_cell( p_msg ) ;
+                               if  ( !new_cell ){
+                                               LOG(L_ERR, "ERROR: t_addifnew: out of mem:\n");
+                                       ret = AIN_ERROR;
+                               } else {
+                                       insert_into_hash_table_unsafe( hash_table , new_cell );
+                                       ret = AIN_NEW;
+                                       T=new_cell;
+                                       T_REF(T);
+                               }
+                       }
+                       unlock( hash_table->entrys[p_msg->hash_index].mutex );
+                       return ret;
+               } else {
+                       /* tramsaction found, it's a retransmission  or ACK */
+                       return p_msg->REQ_METHOD==METHOD_ACK ? AIN_OLDACK : AIN_RETR;
+               }
+       } else {
+               if (T)
+                       LOG(L_ERR, "ERROR: t_check_new_request: already "
+                       "processing this message, T found!\n");
+               else
+                       LOG(L_ERR, "ERROR: t_check_new_request: already "
+                       "processing this message, T not found!\n");
+               return AIN_ERROR;
+       }
+
+}
+
+
+
index bd7ebf2..a09de36 100644 (file)
@@ -8,6 +8,13 @@
 #include "timer.h"
 #include "../../dprint.h"
 
+int timer_group[NR_OF_TIMER_LISTS] = { 
+       TG_FR, TG_FR,
+       TG_WT,
+       TG_DEL,
+       TG_RT, TG_RT, TG_RT, TG_RT
+};
+
 void reset_timer_list( struct s_table* hash_table, enum lists list_id)
 {
        hash_table->timers[ list_id ].first_tl.next_tl = & (hash_table->timers[ list_id ].last_tl );
@@ -36,61 +43,44 @@ void print_timer_list(struct s_table* hash_table, enum lists list_id)
    }
 }
 
-static void remove_from_timer_list_dummy(  struct timer_link* tl )
+/* static void remove_from_timer_list_dummy(  struct timer_link* tl ) */
+void remove_timer_unsafe(  struct timer_link* tl )
 {
-       DBG("DEBUG: remove_from_timer[%d]: %p \n",tl->list->id,tl);
-       tl->prev_tl->next_tl = tl->next_tl;
-       tl->next_tl->prev_tl = tl->prev_tl;
-    tl->next_tl = 0;
-    tl->prev_tl = 0;
-       tl->list = NULL;
+       if (is_in_timer_list2( tl )) {
+               tl->prev_tl->next_tl = tl->next_tl;
+               tl->next_tl->prev_tl = tl->prev_tl;
+               tl->next_tl = 0;
+               tl->prev_tl = 0;
+               tl->timer_list = NULL;
+       }
 }
 
 /* put a new cell into a list nr. list_id within a hash_table;
   * set initial timeout
   */
-void add_to_tail_of_timer_list( struct timer *timer_list, 
+void add_timer_unsafe( struct timer *timer_list,
        struct timer_link *tl, unsigned int time_out )
 {
-       remove_from_timer_list( tl );
+       /*      remove_from_timer_list( tl ); */
        /* the entire timer list is locked now -- noone else can manipulate it */
-       lock( timer_list->mutex );
+       /* lock( timer_list->mutex ); */
        tl->time_out = time_out;
        tl->prev_tl = timer_list->last_tl.prev_tl;
        tl->next_tl = & timer_list->last_tl;
        timer_list->last_tl.prev_tl = tl;
        tl->prev_tl->next_tl = tl;
-       tl->list = timer_list;
-       //print_timer_list(hash_table, list_id);
+       tl->timer_list = timer_list;
+#      ifdef EXTRA_DEBUG
+               if ( tl->tg != timer_group[ timer_list->id ] ) {
+                       LOG( L_CRIT, "CRITICAL error: changing timer group\n");
+                       abort();
+               }
+#      endif
        /* give the list lock away */
-       unlock( timer_list->mutex );
+       /* unlock( timer_list->mutex ); */
        DBG("DEBUG: add_to_tail_of_timer[%d]: %p\n",timer_list->id,tl);
 }
 
-
-
-
-
-/* remove a cell from a list nr. list_id within a hash_table;
-*/
-void remove_from_timer_list( struct timer_link* tl)
-{
-       ser_lock_t      m;
-
-       if (is_in_timer_list2( tl )) {
-               m=tl->list->mutex;
-               /* the entire timer list is locked now -- noone else can manipulate it */
-               lock( m );
-               if ( is_in_timer_list2( tl )  ) remove_from_timer_list_dummy( tl );
-               //print_timer_list(hash_table, list_id);
-               /* give the list lock away */
-               unlock( m );
-       }
-}
-
-
-
-
 /*
        detach items passed by the time from timer list
 */
@@ -99,8 +89,6 @@ struct timer_link  *check_and_split_time_list( struct timer *timer_list, int tim
 {
        struct timer_link *tl , *tmp , *end, *ret;
 
-       //DBG("DEBUG : check_and_split_time_list: start\n");
-
        /* quick check whether it is worth entering the lock */
        if (timer_list->first_tl.next_tl==&timer_list->last_tl ||
                timer_list->first_tl.next_tl->time_out > time )
@@ -111,7 +99,10 @@ struct timer_link  *check_and_split_time_list( struct timer *timer_list, int tim
 
        end = &timer_list->last_tl;
        tl = timer_list->first_tl.next_tl;
-       while( tl!=end && tl->time_out <= time) tl=tl->next_tl;
+       while( tl!=end && tl->time_out <= time) {
+               tl->timer_list = NULL;
+               tl=tl->next_tl;
+       }
 
        /* nothing to delete found */
        if (tl->prev_tl==&(timer_list->first_tl)) {
@@ -129,8 +120,6 @@ struct timer_link  *check_and_split_time_list( struct timer *timer_list, int tim
    /* give the list lock away */
    unlock( timer_list->mutex );
 
-   //DBG("DEBUG : check_and_split_time_list: done, returns %p\n",tl);
-   //print_timer_list(hash_table, list_id);
    return ret;
 }
 
@@ -160,7 +149,6 @@ void timer_routine(unsigned int ticks , void * attr)
                        /* reset the timer list linkage */
                        tmp_tl = tl->next_tl;
                        tl->next_tl = tl->prev_tl =0 ; 
-                       tl->list = NULL;
                        DBG("DEBUG: timer routine: timer[%d] , tl=%p next=%p\n",id,tl,tmp_tl);
                        timers[id].timeout_handler( tl->payload );
                        tl = tmp_tl;
@@ -170,50 +158,3 @@ void timer_routine(unsigned int ticks , void * attr)
 
 
 
-/* deprecated -- too CPU expensive 
-  */
-/*
-void insert_into_timer_list( struct s_table* hash_table , 
-       struct timer_link* new_tl, enum lists list_id , unsigned int time_out )
-{
-   struct timer          *timer_list = &(hash_table->timers[ list_id ]);
-   struct timer_link  *tl;
-
-   // the entire timer list is locked now -- noone else can manipulate it 
-   lock( timer_list->mutex );
-
-   // if the element is already in list->first remove it 
-   if ( is_in_timer_list( new_tl,list_id)  )
-      remove_from_timer_list_dummy( hash_table , new_tl , list_id);
-
-   new_tl->time_out = time_out ;
-   DBG("DEBUG: insert_into_timer[%d]:%d, %p\n",list_id,new_tl->time_out,new_tl);
-    // seeks the position for insertion 
-   for( tl=timer_list->first_tl ; tl && tl->time_out<new_tl->time_out ; tl=tl->next_tl );
-
-   // link it into list
-    if ( tl )
-    {  // insert before tl
-       new_tl->prev_tl = tl->prev_tl;
-       tl->prev_tl = new_tl;
-    }
-   else
-    {  // at the end or empty list 
-       new_tl->prev_tl = timer_list->last_tl;
-       timer_list->last_tl = new_tl;
-    }
-    if (new_tl->prev_tl )
-       new_tl->prev_tl->next_tl = new_tl;
-    else
-       timer_list->first_tl = new_tl;
-    new_tl->next_tl = tl;
-       tl->list_id = list_id;
-
-   //print_timer_list(hash_table, list_id);
-    // give the list lock away 
-
-    unlock( timer_list->mutex );
-}
-
-
-*/
index e0ccfb0..904748b 100644 (file)
@@ -9,15 +9,20 @@
 
 /* identifiers of timer lists; 
 */
-enum lists {   FR_TIMER_LIST, FR_INV_TIMER_LIST,
-                               WT_TIMER_LIST, DELETE_LIST, 
-                               /* fixed-timer retransmission lists (benefit: fixed timer
-                                  length allows for appending new items to the list as
-                                       opposed to inserting them which is costly */
-                               RT_T1_TO_1, RT_T1_TO_2, RT_T1_TO_3, RT_T2, 
-                               NR_OF_TIMER_LISTS };
+enum lists {
+       FR_TIMER_LIST, FR_INV_TIMER_LIST,
+       WT_TIMER_LIST, 
+       DELETE_LIST, 
+       /* fixed-timer retransmission lists (benefit: fixed timer
+          length allows for appending new items to the list as
+               opposed to inserting them which is costly */
+       RT_T1_TO_1, RT_T1_TO_2, RT_T1_TO_3, RT_T2, 
+       NR_OF_TIMER_LISTS };
 
-#define is_in_timer_list2(_tl) ( (_tl)->list )
+
+extern int timer_group[NR_OF_TIMER_LISTS];
+
+#define is_in_timer_list2(_tl) ( (_tl)->timer_list )
 
 
 struct timer;
@@ -30,7 +35,9 @@ typedef struct timer_link
        struct timer_link       *prev_tl;
        unsigned int            time_out;
        void                            *payload;
-       struct timer            *list;
+       struct timer            *timer_list;
+       /* ser_lock_t                   *mutex; */
+       enum timer_groups       tg;
 }timer_link_type ;
 
 
@@ -47,11 +54,18 @@ typedef struct  timer
 void init_timer_list( struct s_table* hash_table, enum lists list_id);
 void reset_timer_list( struct s_table* hash_table, enum lists list_id);
 
+/*
 void add_to_tail_of_timer_list( struct timer *timer_list, 
        struct timer_link *tl, unsigned int time_out );
 void remove_from_timer_list( struct timer_link *tl);
+*/
 void timer_routine(unsigned int, void *);
 
+void remove_timer_unsafe(  struct timer_link* tl ) ;
+void add_timer_unsafe( struct timer *timer_list,
+       struct timer_link *tl, unsigned int time_out );
+
+
 
 /* deprecated -- too expensive -- use appending instead 
 void insert_into_timer_list( struct s_table* hash_table , 
index 9884118..b615a3d 100644 (file)
 /*static int test_f(struct sip_msg*, char*,char*);*/
 static int w_t_check(struct sip_msg* msg, char* str, char* str2);
 static int w_t_send_reply(struct sip_msg* msg, char* str, char* str2);
+#ifdef _OBSOLETED_TM
 static int w_t_forward(struct sip_msg* msg, char* str, char* str2);
-static int w_t_forward_def(struct sip_msg* msg, char* str, char* str2);
-static int w_t_release(struct sip_msg* msg, char* str, char* str2);
 static int w_t_on_request_received(struct sip_msg* msg, char* str, char* str2);
 static int w_t_on_request_received_uri(struct sip_msg* msg, char* str, char* str2);
+int w_t_forward_uri( struct sip_msg* p_msg, char* foo, char* bar  );
+//static int fixup_t_on_request_received(void** param, int param_no);
+static int w_t_forward_def(struct sip_msg* msg, char* str, char* str2);
+#endif
+static int w_t_release(struct sip_msg* msg, char* str, char* str2);
 static int fixup_t_forward(void** param, int param_no);
 static int fixup_t_forward_def(void** param, int param_no);
 static int fixup_t_send_reply(void** param, int param_no);
-static void w_onbreak(struct sip_msg* msg) { t_unref(msg, NULL, NULL); }
+static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar );
+static w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar  );
+static int w_t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar );
 
+static int t_relay_to( struct sip_msg  *p_msg ,  char *str_ip , char *str_port  );
+static int t_relay( struct sip_msg  *p_msg ,  char* foo, char* bar  );
+static int w_t_forward_ack(struct sip_msg* msg, char* str, char* str2);
+static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* str2);
+static void w_onbreak(struct sip_msg* msg) { t_unref(); }
 
 static struct module_exports nm_exports= {
        "tm_module",
-       (char*[]){                      "t_add_transaction",
-                               "t_lookup_request",
+       (char*[]){                      
+#ifdef _OBSOLETED_TM
                                "t_forward",
                                "t_forward_def",
                                "t_forward_uri",
+                               "t_on_request_receive_uri",
+                               "t_on_request_receive_to",
+#endif
+                               "t_add_transaction",
+                               "t_lookup_request",
                                "t_send_reply",
                                "t_retransmit_reply",
                                "t_release",
                                "t_unref",
-                               "t_on_request_receive_uri",
-                               "t_on_request_receive_to"
+                               "t_relay_to",
+                               "t_relay",
+                               "t_forward_nonack",
+                               "t_forward_ack"
                        },
        (cmd_function[]){
-                                       t_add_transaction,
-                                       w_t_check,
+#ifdef _OBSOLETED_TM
                                        w_t_forward,
                                        w_t_forward_def,
-                                       t_forward_uri,
+                                       w_t_forward_uri,
+                                       w_t_on_request_received_uri,
+                                       w_t_on_request_received,
+#endif
+
+                                       w_t_add_transaction,
+                                       w_t_check,
                                        w_t_send_reply,
-                                       t_retransmit_reply,
+                                       w_t_retransmit_reply,
                                        w_t_release,
-                                       t_unref,
-                                       w_t_on_request_received_uri,
-                                       w_t_on_request_received
+                                       w_t_unref,
+                                       t_relay_to,
+                                       t_relay,
+                                       w_t_forward_nonack,
+                                       w_t_forward_ack
                                        },
        (int[]){
-                               0,
-                               0,
-                               2,
-                               1,
-                               0,
-                               2,
-                               0,
-                               0,
-                               0,
-                               0,
-                               2
+#ifdef _OBSOLETED_TM
+                               2, /* t_forward */
+                               1, /* t_forward_def */
+                               0, /* t_forward_uri */
+                               0, /* t_on_request_receive_uri */
+                               2, /* t_on_request_receive_to */
+#endif
+                               0, /* t_add_transaction */
+                               0, /* t_lookup_request */
+                               2, /* t_send_reply */
+                               0, /* t_retransmit_reply */
+                               0, /* t_release */
+                               0, /* t_unref */
+                               2, /* t_relay_to */
+                               0, /* t_relay */
+                               2, /* t_forward_nonack */
+                               2  /* t_forward_ack */
                        },
        (fixup_function[]){
-                               0,
-                               0,
-                               fixup_t_forward,
-                               fixup_t_forward_def,
-                               0,
-                               fixup_t_send_reply,
-                               0,
-                               0,
-                               0,
-                               0,
-                               fixup_t_forward
+#ifdef _OBSOLETED_TM
+                               fixup_t_forward,                /* t_forward */ 
+                               fixup_t_forward_def,    /* t_forward_def */
+                               0,                                              /* t_forward_uri */
+                               0,                                              /* t_on_request_receive_uri */
+                               fixup_t_forward,                /* t_on_request_receive_to */
+#endif
+                               0,                                              /* t_add_transaction */
+                               0,                                              /* t_lookup_request */
+                               fixup_t_send_reply,             /* t_send_reply */
+                               0,                                              /* t_retransmit_reply */
+                               0,                                              /* t_release */
+                               0,                                              /* t_unref */
+                               fixup_t_forward,                /* t_relay_to */
+                               0,                                              /* t_relay */
+                               fixup_t_forward,                /* t_forward_nonack */
+                               fixup_t_forward                 /* t_forward_ack */
                },
-       11,
+#ifdef _OBSOLETED_TM
+       15,
+#else
+       10,
+#endif
        (response_function) t_on_reply_received,
        (destroy_function) tm_shutdown,
        w_onbreak
@@ -225,34 +266,198 @@ static int w_t_check(struct sip_msg* msg, char* str, char* str2)
        return t_check( msg , 0 ) ? 1 : -1;
 }
 
+#ifdef _OBSOLETED_TM
 static int w_t_forward(struct sip_msg* msg, char* str, char* str2)
 {
+       if (t_check( msg , 0 )==-1) return -1;
+       if (!T) {
+               DBG("DEBUG: t_forward: no transaction found for request forwarding\n");
+               return -1;
+       }
        return t_forward(msg, (unsigned int) str, (unsigned int) str2);
 }
-
-
 static int w_t_forward_def(struct sip_msg* msg, char* str, char* str2)
 {
+       if (t_check( msg , 0 )==-1) return -1;
+       if (!T) {
+               DBG("DEBUG: t_forward: no transaction found for request forwarding\n");
+               return -1;
+       }
        return t_forward(msg, (unsigned int) str, 5060 );
 }
 
+int w_t_forward_uri( struct sip_msg* p_msg, char* foo, char* bar  ) {
+       if (t_check( p_msg , 0 )==-1) return -1;
+       if (!T) {
+               DBG("DEBUG: t_forward: no transaction found for request forwarding\n");
+               return -1;
+       }
+       return t_forward_uri(p_msg  );
+}
+static int w_t_on_request_received(struct sip_msg* msg, char* str, char* str2)
+{
+       return t_on_request_received(msg, (unsigned int) str, (unsigned int) str2);
+}
+
+static int w_t_on_request_received_uri(struct sip_msg* msg, char* str, char* str2)
+{
+       return t_on_request_received_uri(msg);
+}
+
+
+#endif
+
+static int w_t_forward_ack(struct sip_msg* msg, char* str, char* str2)
+{
+       if (t_check( msg , 0 )==-1) return -1;
+       if (!T) {
+               DBG("DEBUG: t_forward_ack: no transaction found for request forwarding\n");
+               return -1;
+       }
+       return t_forward_ack(msg, (unsigned int) str, (unsigned int) str2);
+}
+static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* str2)
+{
+       if (t_check( msg , 0 )==-1) return -1;
+       if (!T) {
+               DBG("DEBUG: t_forward_nonack: no transaction found for request forwarding\n");
+               return -1;
+       }
+       return t_forward_nonack(msg, (unsigned int) str, (unsigned int) str2);
+}
+
+
 
 static int w_t_send_reply(struct sip_msg* msg, char* str, char* str2)
 {
+       if (t_check( msg , 0 )==-1) return -1;
+       if (!T) {
+               LOG(L_ERR, "ERROR: t_send_reply: cannot send a t_reply to a message "
+                       "for which no T-state has been established\n");
+               return -1;
+       }
        return t_send_reply(msg, (unsigned int) str, str2);
 }
 
 static int w_t_release(struct sip_msg* msg, char* str, char* str2)
 {
-       return t_release_transaction(msg);
+       if (t_check( msg  , 0 )==-1) return 1;
+       if ( T && T!=T_UNDEFINED ) 
+               return t_put_on_wait( T );
+       return 1;
 }
 
-static int w_t_on_request_received(struct sip_msg* msg, char* str, char* str2)
+
+static int w_t_unref( struct sip_msg* p_msg, char* foo, char* bar )
 {
-       return t_on_request_received(msg, (unsigned int) str, (unsigned int) str2);
+       if (T==T_UNDEFINED || T==T_NULL)
+               return -1;
+    return t_unref( /* p_msg */ );
 }
 
-static int w_t_on_request_received_uri(struct sip_msg* msg, char* str, char* str2)
+static w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar  )
 {
-       return t_on_request_received_uri(msg);
+       if (t_check( p_msg  , 0 )==-1) return 1;
+       if (T) return t_retransmit_reply( p_msg );
+       else return -1;
 }
+
+static int w_t_add_transaction( struct sip_msg* p_msg, char* foo, char* bar ) {
+       if (t_check( p_msg , 0 )==-1) return -1;
+       if (T) {
+               LOG(L_ERR,"ERROR: t_add_transaction: won't add a retransmission\n");
+               return -1;
+       }
+       return t_add_transaction( p_msg );
+}
+
+
+
+static int t_relay_to( struct sip_msg  *p_msg , char *str_ip , char *str_port)
+{
+
+       enum addifnew_status status;
+       int ret;
+
+       status = t_addifnew( p_msg );   
+
+       switch( status ) {
+               case AIN_ERROR:         /*  fatal error (e.g, parsing) occured */
+                       ret = 0;
+                       break;
+                       
+               case AIN_RETR:          /* it's a retransmission */
+                       if ( !t_retransmit_reply( p_msg ) )
+                       {
+                               DBG( "SER: WARNING: bad t_retransmit_reply\n");
+                       }
+                       ret = 1;
+                       break;
+
+               case AIN_NEW:           /* it's a new request */
+                       if ( !t_forward_nonack( p_msg, (unsigned int) str_ip, (unsigned int) str_port )) 
+                       {
+                               DBG( "SER:ERROR: t_forward \n");
+                               ret = 0;
+                       } else { /* let upstream know, I forwarded downstream */
+                               if ( p_msg->REQ_METHOD==METHOD_CANCEL)
+                               {
+                                       DBG( "SER: new CANCEL\n");
+                                       if ( !t_send_reply( p_msg , 200, "glad to cancel") )
+                                               DBG( "SER:ERROR: t_send_reply\n");
+                               } else {
+                                       DBG( "SER: new transaction\n");
+                                       if (!t_send_reply( p_msg , 100 , "trying -- your call is important to us"))
+                                       {
+                                               DBG( "SER: ERROR: t_send_reply (100)\n");
+                                       }
+                               }
+                               ret = 1;
+                       }
+                       break;
+
+               case AIN_NEWACK:        /* it's an ACK for which no transaction exists */
+                       DBG( "SER: forwarding ACK  statelessly\n");
+                       forward_request( p_msg , mk_proxy_from_ip( 
+                               (unsigned int )str_ip, (unsigned int)str_port) ) ;
+                       ret=1;
+                       break;
+
+               case AIN_OLDACK:        /* it's an ACK for an existing transaction */
+                       DBG( "SER: ACK received -> t_release\n");
+                       if ( !t_release_transaction( p_msg ) )
+                       {
+                               DBG( "SER: WARNING: bad t_release\n");
+                       }
+                       /* t_forward decides whether to forward (2xx) or not (anything else) */
+                       if ( !t_forward_ack( p_msg , (unsigned int) str_ip , (unsigned int) str_port ) )
+                       {
+                               DBG( "SER: WARNING: bad ACK forward\n");
+                       }
+                       ret = 1;
+                       break;
+
+               default:
+                       LOG(L_CRIT, "ERROR: unexpected addifnew return value: %d\n", ret);
+                       abort();
+       };
+       T_UNREF( T );
+       return ret;
+}
+
+       
+
+
+static int t_relay( struct sip_msg  *p_msg , char* foo, char* bar)
+{
+   unsigned int     ip, port;
+
+   if ( get_ip_and_port_from_uri( p_msg , &ip, &port)<0 )
+   {
+      LOG( L_ERR , "ERROR: t_on_request_received_uri: unable to extract ip and port from uri!\n" );
+      return -1;
+   }
+
+   return t_relay_to( p_msg , ( char *) ip , (char *) port );
+}
+
index 5c5b055..4295cda 100644 (file)
@@ -183,6 +183,9 @@ struct sip_msg{
        char add_to_branch_s[MAX_BRANCH_PARAM_LEN];
        int add_to_branch_len;
 
+       /* index to TM hash table; stored in core to avoid unnecessary calcs */
+       unsigned int  hash_index;
+
        
 };
 
index 4cd2b55..d349c41 100644 (file)
@@ -4,91 +4,42 @@
 # $ID: $
 #
 
-debug=9          # debug level (cmd line: -dddddddddd)
-#fork=yes          # (cmd. line: -D)
-fork=no
+debug=3          # debug level (cmd line: -dddddddddd)
+fork=yes          # (cmd. line: -D)
+#fork=no
 #log_stderror=yes # (cmd line: -E)
 log_stderror=yes       # (cmd line: -E)
 
 
-#children=8
+children=8
 check_via=no     # (cmd. line: -v)
 #dns=on           # (cmd. line: -r)
 #rev_dns=yes      # (cmd. line: -R)
-#port=5080
+port=5080
 #listen=127.0.0.1
-#listen=195.37.77.101
+listen=195.37.77.101
 loop_checks=0
 # for more info: sip_router -h
 
 #modules
-#loadmodule "modules/print/print.so"
-#loadmodule "modules/tm/tm.so"
+loadmodule "modules/print/print.so"
+loadmodule "modules/tm/tm.so"
 
 #route[0]{
 #      if (method=="BYE") { forward("bat.iptel.org", 5000); }
 #      else forward("bat.iptel.org", 5090);
+#      else t_forward("bat.iptel.org", "9" );
 #      break;
 #}
 
 route[0]{
        log("SER: new request reveived\n");
-       if ( t_lookup_request()) {
-               if ( method=="ACK" )    {
-                       log("SER: ACK for an existing transaction received\n");
-                       if (! t_forward("bat.iptel.org", "5090" )) {
-                               log("SER: WARNING: bad forward\n");
-                       } else log("SER: t_forward ok\n");
-                       if (! t_release()) {
-                               log("SER: WARNING: bad t_release\n");
-                       } else log("SER: t_release ok\n");
-               } else {
-                       if (method=="INVITE" ) { log("SER: it's an INVITE retranmission\n"); }
-                       else if (method=="BYE") log( "SER: it's a BYE retransmission\n")
-                       else log("SER: it's a retransmission (neither INVITE nor BYE\n");
-                       if (! t_retransmit_reply()) {
-                               log("SER: WARNING: bad t_retransmit_reply\n");
-                       } else log("SER: t_retransmit ok\n");
-               };
-               t_unref();
-       } else {
-               log("SER: transaction not found\n");
-               if (method=="ACK") {
-                       # no established transaction ... forward ACK just statelessly
-                       log("SER: ACK received\n");
-                       forward("bat.iptel.org", 5090);
-               } else {
-                       # establish transaction
-                       log("SER: adding new transaction\n");
-                       if (method=="INVITE" ) { log("SER: it's a new INVITE \n"); }
-                       else if (method=="BYE") log( "SER: it's a new BYE \n")
-                       else log("SER: it is a new transaction (neither INVITE nor BYE)\n");
-                       if (! t_add_transaction()){
-                               log("SER t_add_transaction failed\n");
-                       } else log("SER: t_add_Transactio ok\n");
-                       # reply
-                       if (method=="CANCEL") {
-                               log("SER: new CANCEL\n");
-                               if (! t_send_reply( "200", "glad to cancel")){
-                                       log("SER:ERROR: t_send_reply\n");
-                               };
-                       } else {
-                               log("SER: replying\n");
-                               if (! t_send_reply("100", "Trying")
-                                       ){
-                                       log("SER: ERROR: t_send_reply (100)\n");
-                               } else log("SER: t_send_reply ok\n");
-                       };
-                       if (method=="INVITE") {
-                               if (! t_forward("bat.iptel.org", "5090")){
-                                       log("SER:ERROR: t_forward (..., 5555)\n");
-                               } else log("SER: t_forward ok\n");
-                       } else if (method=="BYE") {
-                               if (! t_forward("bat.iptel.org", "5000")){
-                                       log("SER:ERROR: t_forward (..., 5555)\n");
-                               } else log("SER: t_forward ok\n");
-                       } else log("SER: ERROR unknwon request\n");
-                       t_unref();
-               };
+       if (method=="BYE") {
+               t_relay_to( "bat.iptel.org", "5000" );
+       }
+       else {
+               t_relay_to( "bat.iptel.org", "5090" );
        };
+#      break;
 }
+
index 9fe2662..6b6fe9b 100644 (file)
@@ -232,6 +232,17 @@ int udp_send(char *buf, unsigned len, struct sockaddr*  to, unsigned tolen)
        if (a->sin_port == 0)
                DBG("DEBUG: no port\n");
 
+#ifdef EXTRA_DEBUG
+       if ( tolen < sizeof(struct sockaddr_in) || a->sin_family && a->sin_family != AF_INET
+               || a->sin_port == 0 )
+               abort();
+       /* every message must be terminated by CRLF */
+       if (memcmp(buf+len-CRLF_LEN, CRLF, CRLF_LEN)!=0) {
+               LOG(L_CRIT, "ERROR: this is ugly -- we are sending a packet not terminated by CRLF\n");
+               abort();
+       }
+#endif
+
        DBG(" destination: IP=%s, port=%u; packet:\n", ip_txt, p);
        DBG(" destination (hex): IP=%x, port=%x;\n", a->sin_addr.s_addr, a->sin_port );
        /* DBG(" packet: {%*s...}\n", 24, buf ); */
@@ -252,9 +263,14 @@ again:
                                buf,len,to,tolen,
                                strerror(errno),errno);
                if (errno==EINTR) goto again;
-               if (errno==EINVAL) LOG(L_CRIT,"CRITICAL: invalid sendtoparameters\n"
+               if (errno==EINVAL) {
+                       LOG(L_CRIT,"CRITICAL: invalid sendtoparameters\n"
                        "one possible reason is the server is bound to localhost and\n"
                        "attempts to send to the net\n");
+#                      ifdef EXTRA_DEBUG
+                       abort();
+#                      endif
+               }
        }
        return n;
 }