Browse code

*** empty log message ***

Bogdan-Andrei Iancu authored on 27/11/2001 18:49:24
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,640 @@
1
+#include "t_funcs.h"
2
+
3
+struct cell      *T;
4
+unsigned int  global_msg_id;
5
+struct s_table*  hash_table;
6
+
7
+struct cell* t_lookupOriginalT(  struct s_table* hash_table , struct sip_msg* p_msg );
8
+
9
+int t_reply_matching( struct s_table* , struct sip_msg* , struct cell** , unsigned int*  );
10
+int t_store_incoming_reply( struct cell* , unsigned int , struct sip_msg* );
11
+int t_relay_reply( struct cell* , unsigned int , struct sip_msg* );
12
+int t_check( struct s_table* , struct sip_msg*  );
13
+int t_all_final( struct cell * );
14
+int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg );
15
+int push_reply_from_uac_to_uas( struct sip_msg * , unsigned int );
16
+
17
+void del_Transaction( struct s_table *hash_table , struct cell * p_cell );
18
+void start_FR_timer( struct s_table* hash_table, struct cell* p_cell );
19
+void start_WT_timer( struct s_table* hash_table, struct cell* p_cell );
20
+
21
+
22
+
23
+
24
+/* function returns:
25
+ *       0 - a new transaction was created
26
+ *      -1 - retransmission
27
+ *      -2 - error
28
+ */
29
+int t_add_transaction( struct s_table* hash_table , struct sip_msg* p_msg )
30
+{
31
+   struct cell*    new_cell;
32
+
33
+   /* it's about the same transaction or not?*/
34
+   if ( global_msg_id != p_msg->id )
35
+   {
36
+      T = (struct cell*)-1;
37
+      global_msg_id = p_msg->id;
38
+   }
39
+
40
+    /* if the transaction is not found yet we are tring to look for it*/
41
+   if ( (int)T==-1 )
42
+      /* if the lookup's result is not 0 means that it's a retransmission */
43
+      if ( t_lookup_request( hash_table , p_msg ) )
44
+         return -1;
45
+
46
+   /* creates a new transaction */
47
+   new_cell = build_cell( hash_table , p_msg ) ;
48
+   if  ( !new_cell )
49
+      return -2;
50
+   insert_into_hash_table( hash_table , new_cell );
51
+
52
+   T = new_cell;
53
+   return 0;
54
+}
55
+
56
+
57
+/* function returns:
58
+ *       0 - transaction wasn't found
59
+ *       1 - transaction found
60
+ */
61
+int t_lookup_request(  struct s_table* hash_table , struct sip_msg* p_msg )
62
+{
63
+   struct cell      *p_cell;
64
+   struct cell      *tmp_cell;
65
+   unsigned int  hash_index=0;
66
+   unsigned int  isACK = 0;
67
+
68
+   /* it's about the same transaction or not?*/
69
+   if ( global_msg_id != p_msg->id )
70
+   {
71
+      T = (struct cell*)-1;
72
+      global_msg_id = p_msg->id;
73
+   }
74
+
75
+    /* if  T is previous found -> return found */
76
+   if ( (int)T !=-1 && T )
77
+      return 1;
78
+
79
+    /* if T was previous searched and not found -> return not found*/
80
+   if ( !T )
81
+      return 0;
82
+
83
+   /* start searching into the table */
84
+   hash_index = hash( p_msg->callid , get_cseq(p_msg)->number ) ;
85
+   if ( p_msg->first_line.u.request.method_value==METHOD_ACK  )
86
+      isACK = 1;
87
+
88
+   /* all the transactions from the entry are compared */
89
+   p_cell     = hash_table->entrys[hash_index].first_cell;
90
+   tmp_cell = 0;
91
+   while( p_cell )
92
+   {
93
+      /* the transaction is referenceted for reading */
94
+      ref_transaction( p_cell );
95
+
96
+      /* is it the wanted transaction ? */
97
+      if ( !isACK )
98
+      { /* is not an ACK request */
99
+         /* first only the length are checked */
100
+         if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len )
101
+            if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len )
102
+                //if ( /*tag length*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && p_cell->inbound_request->tag->body.len == p_msg->tag->body.len) )
103
+                  if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len )
104
+                     if ( /*cseq length*/ p_cell->inbound_request->cseq->body.len == p_msg->cseq->body.len )
105
+                            /* so far the lengths are the same -> let's check the contents */
106
+                            if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) )
107
+                               if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len)  )
108
+                                  //if ( /*tag*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && !memcmp( p_cell->inbound_request->tag->body.s , p_msg->tag->body.s , p_msg->tag->body.len )) )
109
+                                     if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) )
110
+                                        if ( /*cseq*/ !memcmp( p_cell->inbound_request->cseq->body.s , p_msg->cseq->body.s , p_msg->cseq->body.len ) )
111
+                                              { /* WE FOUND THE GOLDEN EGG !!!! */
112
+                                                 T = p_cell;
113
+                                                 unref_transaction ( p_cell );
114
+                                                 return 1;
115
+                                              }
116
+      }
117
+      else
118
+      { /* it's a ACK request*/
119
+         /* first only the length are checked */
120
+         if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len )
121
+            if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len )
122
+               if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len )
123
+                  if ( /*cseq_nr length*/ get_cseq(p_cell->inbound_request)->number.len == get_cseq(p_msg)->number.len )
124
+                      if ( /*cseq_method length*/ get_cseq(p_cell->inbound_request)->method.len == 6 /*INVITE*/ )
125
+                         //if ( /*tag length*/ p_cell->tag &&  p_cell->tag->len==p_msg->tag->body.len )
126
+                            /* so far the lengths are the same -> let's check the contents */
127
+                            if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) )
128
+                               if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len)  )
129
+                                  //if ( /*tag*/ !memcmp( p_cell->tag->s , p_msg->tag->body.s , p_msg->tag->body.len ) )
130
+                                     if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) )
131
+                                        if ( /*cseq_nr*/ !memcmp( get_cseq(p_cell->inbound_request)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len ) )
132
+                                           if ( /*cseq_method*/ !memcmp( get_cseq(p_cell->inbound_request)->method.s , "INVITE" , 6 ) )
133
+                                              { /* WE FOUND THE GOLDEN EGG !!!! */
134
+                                                 T = p_cell;
135
+                                                 unref_transaction ( p_cell );
136
+                                                 return 1;
137
+                                              }
138
+      } /* end if is ACK or not*/
139
+      /* next transaction */
140
+      tmp_cell = p_cell;
141
+      p_cell = p_cell->next_cell;
142
+
143
+      /* the transaction is dereferenceted */
144
+      unref_transaction ( tmp_cell );
145
+   }
146
+
147
+   /* no transaction found */
148
+   T = 0;
149
+   return 0;
150
+}
151
+
152
+
153
+
154
+/* function returns:
155
+ *       0 - transaction wasn't found
156
+ *       T - transaction found
157
+ */
158
+struct cell* t_lookupOriginalT(  struct s_table* hash_table , struct sip_msg* p_msg )
159
+{
160
+   struct cell      *p_cell;
161
+   struct cell      *tmp_cell;
162
+   unsigned int  hash_index=0;
163
+
164
+   /* it's a CANCEL request for sure */
165
+
166
+   /* start searching into the table */
167
+   hash_index = hash( p_msg->callid , get_cseq(p_msg)->number  ) ;
168
+
169
+   /* all the transactions from the entry are compared */
170
+   p_cell     = hash_table->entrys[hash_index].first_cell;
171
+   tmp_cell = 0;
172
+   while( p_cell )
173
+   {
174
+      /* the transaction is referenceted for reading */
175
+      ref_transaction( p_cell );
176
+
177
+      /* is it the wanted transaction ? */
178
+      /* first only the length are checked */
179
+      if ( /*from length*/ p_cell->inbound_request->from->body.len == p_msg->from->body.len )
180
+         if ( /*to length*/ p_cell->inbound_request->to->body.len == p_msg->to->body.len )
181
+            //if ( /*tag length*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && p_cell->inbound_request->tag->body.len == p_msg->tag->body.len) )
182
+               if ( /*callid length*/ p_cell->inbound_request->callid->body.len == p_msg->callid->body.len )
183
+                  if ( /*cseq_nr length*/ get_cseq(p_cell->inbound_request)->number.len == get_cseq(p_msg)->number.len )
184
+                      //if ( /*cseq_method length*/ p_cell->inbound_request->cseq_method->body.len != 6 /*CANCEL*/ )
185
+                         if ( /*req_uri length*/ p_cell->inbound_request->first_line.u.request.uri.len == p_msg->first_line.u.request.uri.len )
186
+                             /* so far the lengths are the same -> let's check the contents */
187
+                             if ( /*from*/ !memcmp( p_cell->inbound_request->from->body.s , p_msg->from->body.s , p_msg->from->body.len ) )
188
+                                if ( /*to*/ !memcmp( p_cell->inbound_request->to->body.s , p_msg->to->body.s , p_msg->to->body.len)  )
189
+                                   //if ( /*tag*/ (!p_cell->inbound_request->tag && !p_msg->tag) || (p_cell->inbound_request->tag && p_msg->tag && !memcmp( p_cell->inbound_request->tag->body.s , p_msg->tag->body.s , p_msg->tag->body.len )) )
190
+                                      if ( /*callid*/ !memcmp( p_cell->inbound_request->callid->body.s , p_msg->callid->body.s , p_msg->callid->body.len ) )
191
+                                          if ( /*cseq_nr*/ !memcmp( get_cseq(p_cell->inbound_request)->number.s , get_cseq(p_msg)->number.s , get_cseq(p_msg)->number.len ) )
192
+                                             if ( /*cseq_method*/ strcmp( get_cseq(p_cell->inbound_request)->method.s , "CANCEL" ) )
193
+                                                if ( /*req_uri*/ memcmp( p_cell->inbound_request->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.s , p_msg->first_line.u.request.uri.len ) )
194
+                                                { /* WE FOUND THE GOLDEN EGG !!!! */
195
+                                                   unref_transaction ( p_cell );
196
+                                                   return p_cell;
197
+                                                }
198
+      /* next transaction */
199
+      tmp_cell = p_cell;
200
+      p_cell = p_cell->next_cell;
201
+
202
+      /* the transaction is dereferenceted */
203
+      unref_transaction ( tmp_cell );
204
+   }
205
+
206
+   /* no transaction found */
207
+   T = 0;
208
+   return 0;
209
+
210
+
211
+   return 0;
212
+}
213
+
214
+
215
+/* function returns:
216
+ *       0 - forward successfull
217
+ *      -1 - error during forward
218
+ */
219
+int t_forward( struct s_table* hash_table , struct sip_msg* p_msg , unsigned int dest_ip_param , unsigned int dest_port_param )
220
+{
221
+   /* it's about the same transaction or not? */
222
+   if ( global_msg_id != p_msg->id )
223
+   {
224
+      T = (struct cell*)-1;
225
+      global_msg_id = p_msg->id;
226
+   }
227
+
228
+   /* if  T hasn't been previous searched -> search for it */
229
+   if ( (int)T !=-1 )
230
+      t_lookup_request( hash_table , p_msg );
231
+
232
+   /*if T hasn't been found after all -> return not found (error) */
233
+   if ( !T )
234
+      return -1;
235
+
236
+   /*if it's an ACK and the status is not final or is final, but error the ACK is not forwarded*/
237
+   if ( !memcmp(p_msg->first_line.u.request.method.s,"ACK",3) && (T->status/100)!=2 )
238
+      return 0;
239
+
240
+   /* if it's forwarded for the first time ; else the request is retransmited from the transaction buffer */
241
+   if ( T->outbound_request[0]==NULL )
242
+   {
243
+      unsigned int dest_ip     = dest_ip_param;
244
+      unsigned int dest_port  = dest_port_param;
245
+      unsigned int len;
246
+      char              *buf;
247
+
248
+      /* allocates a new retrans_buff for the outbound request */
249
+      T->outbound_request[0] = (struct retrans_buff*)sh_malloc( sizeof(struct retrans_buff) );
250
+      T->nr_of_outgoings = 1;
251
+
252
+      /* special case : CANCEL */
253
+      if ( p_msg->first_line.u.request.method_value==METHOD_CANCEL  )
254
+      {
255
+         struct cell  *T2;
256
+         /* find original cancelled transaction; if found, use its next-hops; otherwise use those passed by script */
257
+         T2 = t_lookupOriginalT( hash_table , p_msg );
258
+         /* if found */
259
+         if (T2)
260
+         {  /* if in 1xx status, send to the same destination */
261
+            if ( (T2->status/100)==1 )
262
+            {
263
+               dest_ip    = T2->outbound_request[0]->dest_ip;
264
+               dest_port = T2->outbound_request[0]->dest_port;
265
+            }
266
+            else
267
+               /* transaction exists, but nothing to cancel */
268
+             return 0;
269
+         }
270
+      }/* end special case CANCEL*/
271
+
272
+      /* store */
273
+      T->outbound_request[0]->dest_ip    = dest_ip;
274
+      T->outbound_request[0]->dest_port = dest_port;
275
+      // buf = build_message( p_mesg , &len );
276
+      // T->outbound_request[0]->bufflen     = len ;
277
+      // memcpy( T->outbound_request[0]->buffer , buf , len );
278
+   }/* end for the first time */
279
+
280
+   /* send the request */
281
+   // send ( T->outbound_request.buffer , T->outbound_request.dest_ip , T->outbound_request.dest_ip );
282
+
283
+}
284
+
285
+
286
+
287
+
288
+
289
+/*  This function is called whenever a reply for our module is received; we need to register
290
+  *  this function on module initialization;
291
+  *  Returns :   1 - core router stops
292
+  *                    0 - core router relay statelessly
293
+  */
294
+int t_on_reply_received( struct s_table  *hash_table , struct sip_msg  *p_msg )
295
+{
296
+   unsigned int  branch;
297
+
298
+   global_msg_id = p_msg->id;
299
+
300
+   /* we use label-matching to lookup for T */
301
+   t_reply_matching( hash_table , p_msg , &T , &branch  );
302
+
303
+   /* if no T found ->tell the core router to forward statelessly */
304
+   if ( !T )
305
+      return 0;
306
+
307
+   /* on a non-200 reply to INVITE, generate local ACK and stop retransmission of the INVITE */
308
+   if ( T->inbound_request->first_line.u.request.method_value==METHOD_INVITE && p_msg->first_line.u.reply.statusclass>2 )
309
+   {
310
+      // sendACK   TO DO !!!!!!!!!!
311
+      // remove_from_retransmission_list( T->outbound_request[branch] );     TO DO !!!!!
312
+      t_store_incoming_reply( T , branch , p_msg );
313
+   }
314
+
315
+   #ifdef FORKING
316
+   /* skipped for the moment*/
317
+   #endif
318
+
319
+   /*let's check the current inbound response status (is final or not) */
320
+   if ( T->inbound_response && (T->status/100)>1 )
321
+   {   /*a final reply was already sent upstream */
322
+       /* alway relay 2xx immediately ; drop anything else */
323
+      if ( p_msg->first_line.u.reply.statusclass==2 )
324
+          t_relay_reply( T , branch , p_msg );
325
+       /* nothing to do for the ser core */
326
+      return 1;
327
+   }
328
+   else
329
+   {  /* no reply sent yet or sent but not final*/
330
+
331
+      /* stops the request's retransmission*/
332
+      // remove_from_retransmission_list( T->outbound_request[branch] );     TO DO !!!!!
333
+      /* restart retransmission if provisional response came for a non_INVITE -> retrasmit at RT_T2*/
334
+      if ( p_msg->first_line.u.reply.statusclass==1 && T->inbound_request->first_line.u.request.method_value!=METHOD_INVITE )
335
+         /*put_in_retransmission_list( T->trasaction.outbound_request[branch] , RT_T2 ) TO DO !!!!!!!*/ ;
336
+
337
+
338
+      /* relay ringing and OK immediately */
339
+      if ( p_msg->first_line.u.reply.statusclass ==1 || p_msg->first_line.u.reply.statusclass ==2  )
340
+      {
341
+           if ( p_msg->first_line.u.reply.statuscode > T->status )
342
+              t_relay_reply( T , branch , p_msg );
343
+         return 1;
344
+      }
345
+
346
+      /* error final responses are only stored */
347
+      if ( p_msg->first_line.u.reply.statusclass>=3 && p_msg->first_line.u.reply.statusclass<=5 )
348
+      {
349
+         t_store_incoming_reply( T , branch , p_msg );
350
+         if ( t_all_final(T) )
351
+              relay_lowest_reply_upstream( T , p_msg );
352
+         /* nothing to do for the ser core */
353
+         return 1;
354
+      }
355
+
356
+      /* global failure responses relay immediately */
357
+     if ( p_msg->first_line.u.reply.statusclass==6 )
358
+      {
359
+         t_relay_reply( T , branch , p_msg );
360
+         /* nothing to do for the ser core */
361
+         return 1;
362
+      }
363
+   }
364
+}
365
+
366
+
367
+
368
+
369
+/* Retransmits the last sent inbound reply.
370
+  * Returns  -1 -error
371
+  *                0 - OK
372
+  */
373
+int t_retransmit_reply( struct s_table *hash_table , struct sip_msg* p_msg )
374
+{
375
+   t_check( hash_table, p_msg );
376
+
377
+   /* if no transaction exists or no reply to be resend -> out */
378
+   if ( T  && T->inbound_response )
379
+   {
380
+       //sendto(  );   TO DO !!!!!!
381
+      return 0;
382
+   }
383
+
384
+   return -1;
385
+}
386
+
387
+
388
+
389
+
390
+/* ----------------------------HELPER FUNCTIONS-------------------------------- */
391
+
392
+
393
+/* Returns 0 - nothing found
394
+  *              1  - T found
395
+  */
396
+int t_reply_matching( struct s_table *hash_table , struct sip_msg *p_msg , struct cell **p_Trans , unsigned int *p_branch )
397
+{
398
+   struct cell*  p_cell;
399
+   struct cell* tmp_cell;
400
+   unsigned int hash_index = 0;
401
+   unsigned int entry_label  = 0;
402
+   unsigned int branch_id    = 0;
403
+
404
+   /* getting the hash_index from the brach param , via header*/
405
+   // hash_index = get_hash_index( p_msg );   TO DO !!!!
406
+
407
+   /*if the hash index is corect */
408
+   if  ( hash_index>=0 && hash_index<TABLE_ENTRIES-1 )
409
+   {
410
+      /* getting the entry label value */
411
+      // entry_label =  get_entry_label( p_msg );   TO DO !!!!
412
+      /* if the entry label also is corect */
413
+      if  ( entry_label>=0 )
414
+      {
415
+         /* getting the branch_id value */
416
+         // entry_label =  get_branch_id( p_msg );   TO DO !!!!
417
+         /* if the entry label also is corect */
418
+          if  ( branch_id>=0 )
419
+          {
420
+             /*all the cells from the entry are scan to detect an entry_label matching */
421
+             p_cell     = hash_table->entrys[hash_index].first_cell;
422
+             tmp_cell = 0;
423
+            while( p_cell )
424
+             {
425
+                /* the transaction is referenceted for reading */
426
+                ref_transaction( p_cell );
427
+                /* is it the cell with the wanted entry_label? */
428
+                if ( p_cell->label = entry_label )
429
+                   /* has the transaction the wanted branch? */
430
+                   if ( p_cell->nr_of_outgoings>branch_id && p_cell->outbound_request[branch_id] )
431
+                    {/* WE FOUND THE GOLDEN EGG !!!! */
432
+                       p_Trans = &p_cell;
433
+                       *p_branch = branch_id;
434
+                       unref_transaction( p_cell );
435
+                       return 1;
436
+                    }
437
+
438
+               /* next cell */
439
+               tmp_cell = p_cell;
440
+               p_cell = p_cell->next_cell;
441
+
442
+               /* the transaction is dereferenceted */
443
+               unref_transaction( tmp_cell );
444
+             }
445
+          }
446
+      }
447
+   }
448
+
449
+   /* nothing found */
450
+   *p_branch = -1;
451
+   return 0;
452
+}
453
+
454
+
455
+
456
+
457
+/* We like this incoming reply, so, let's store it, we'll decide
458
+  * later what to d with that
459
+  */
460
+int t_store_incoming_reply( struct cell* Trans, unsigned int branch, struct sip_msg* p_msg )
461
+{
462
+   /* if there is a previous reply, replace it */
463
+   if ( Trans->outbound_response[branch] )
464
+      /*free_sip_msg( Trans->outbound_response[branch] ) TO DO*/ ;
465
+   Trans->outbound_response[branch] = sip_msg_cloner( p_msg );
466
+}
467
+
468
+
469
+
470
+
471
+/*  We like this incoming reply and we want ot store it and
472
+  *  to relay it upstream
473
+  */
474
+int t_relay_reply( struct cell* Trans, unsigned int branch, struct sip_msg* p_msg )
475
+{
476
+   t_store_incoming_reply( Trans , branch, p_msg );
477
+   push_reply_from_uac_to_uas( p_msg , branch );
478
+}
479
+
480
+
481
+
482
+
483
+/* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction
484
+  * for current message exists;
485
+  * Returns 1 if T was modified or 0 if not.
486
+  */
487
+int t_check( struct s_table *hash_table , struct sip_msg* p_msg )
488
+{
489
+   unsigned int branch;
490
+
491
+   /* is T still up-to-date ? */
492
+   if ( p_msg->id != global_msg_id || (int)T==-1 )
493
+   {
494
+      global_msg_id = p_msg->id;
495
+      /* transaction lookup */
496
+     if ( p_msg->first_line.type=SIP_REQUEST )
497
+         t_lookup_request(  hash_table , p_msg );
498
+      else
499
+         t_reply_matching( hash_table , p_msg , &T , &branch );
500
+
501
+      return 1;
502
+   }
503
+
504
+   return 0;
505
+}
506
+
507
+
508
+
509
+
510
+/*  Checks if all the transaction's outbound request has a final response.
511
+  *  Return   1 - all are final
512
+  *                0 - some waitting
513
+  */
514
+int t_all_final( struct cell *Trans )
515
+{
516
+   unsigned int i;
517
+
518
+   for( i=0 ; i<Trans->nr_of_outgoings ; i++  )
519
+      if (  !Trans->outbound_response[i] || (Trans->outbound_response[i]) && Trans->outbound_response[i]->first_line.u.reply.statuscode<200 )
520
+         return 0;
521
+
522
+   return 1;
523
+}
524
+
525
+
526
+
527
+
528
+/* Picks the lowest code reply and send it upstream.
529
+  *  Returns -1 if no lowest find reply found (all provisional)
530
+  */
531
+int relay_lowest_reply_upstream( struct cell *Trans , struct sip_msg *p_msg )
532
+{
533
+   unsigned int i            =0 ;
534
+   unsigned int lowest_i = -1;
535
+   int                 lowest_v = 999;
536
+
537
+   for(  ; i<T->nr_of_outgoings ; i++ )
538
+      if ( T->outbound_response[i] && T->outbound_response[i]->first_line.u.reply.statuscode>=200 && T->outbound_response[i]->first_line.u.reply.statuscode<lowest_v )
539
+      {
540
+         lowest_i =i;
541
+         lowest_v = T->outbound_response[i]->first_line.u.reply.statuscode;
542
+      }
543
+
544
+   if ( lowest_i != -1 )
545
+      push_reply_from_uac_to_uas( p_msg ,lowest_i );
546
+
547
+   return lowest_i;
548
+}
549
+
550
+
551
+
552
+
553
+/* Push a previously stored reply from UA Client to UA Server
554
+  * and send it out
555
+  */
556
+int push_reply_from_uac_to_uas( struct sip_msg *p_msg , unsigned int branch )
557
+{
558
+   /* if there is a reply, release the buffer (everything else stays same) */
559
+   if ( T->inbound_response )
560
+   {
561
+      sh_free( T->inbound_response->buffer );
562
+      //release_retransmision.... ????
563
+   }
564
+
565
+
566
+}
567
+
568
+
569
+
570
+
571
+
572
+
573
+
574
+
575
+
576
+
577
+
578
+
579
+/*
580
+*   The cell is inserted at the end of the FINAL RESPONSE timer list.
581
+*   The expire time is given by the current time plus the FINAL
582
+    RESPONSE timeout - FR_TIME_OUT
583
+*/
584
+void start_FR_timer( struct s_table* hash_table, struct cell* p_cell )
585
+{
586
+
587
+   /* adds the cell int FINAL RESPONSE timer list*/
588
+   add_to_tail_of_timer_list( hash_table, &(p_cell->tl[FR_TIMER_LIST]), FR_TIMER_LIST, FR_TIME_OUT);
589
+
590
+}
591
+
592
+
593
+/*
594
+*   The cell is inserted at the end of the WAIT timer list. Before adding to the WT list, it's verify if the cell is
595
+*   or not in the FR list (normally it should be there). If it is, it's first removed from FR list and after that
596
+*   added to the WT list.
597
+*   The expire time is given by the current time plus the WAIT timeout - WT_TIME_OUT
598
+*/
599
+
600
+void start_WT_timer( struct s_table* hash_table, struct cell* p_cell )
601
+{
602
+   	struct timer* timers= hash_table->timers;
603
+
604
+   	//if is in FR list -> first it must be removed from there
605
+	remove_from_timer_list( hash_table, &(p_cell->tl[FR_TIMER_LIST]), FR_TIMER_LIST );
606
+
607
+   	/* adds the cell int WAIT timer list*/
608
+   	add_to_tail_of_timer_list( hash_table, &(p_cell->tl[WT_TIMER_LIST]), WT_TIMER_LIST, WT_TIME_OUT );
609
+}
610
+
611
+
612
+
613
+
614
+/*
615
+*   prepare for del a transaction ; the transaction is first removed from the hash entry list (oniy the links from
616
+*   cell to list are deleted in order to make the cell unaccessible from the list and in the same time to keep the
617
+*   list accessible from the cell for process that are currently reading the cell). If no process is reading the cell
618
+*   (ref conter is 0) the cell is immediatly deleted. Otherwise it is put in a waitting list (del_hooker list) for
619
+*   future del. This list is veify by the the timer every sec and the cell that finaly have ref_counter 0 are del.
620
+*/
621
+void del_Transaction( struct s_table *hash_table , struct cell * p_cell )
622
+{
623
+    int      ref_counter         = 0;
624
+
625
+    /* the cell is removed from the list */
626
+    remove_from_hash_table( hash_table, p_cell );
627
+
628
+    /* gets the cell's ref counter*/
629
+    lock( p_cell->mutex );
630
+    ref_counter = p_cell->ref_counter;
631
+    unlock( p_cell->mutex );
632
+
633
+    /* if is not refenceted -> is deleted*/
634
+    if ( ref_counter==0 )
635
+       free_cell( p_cell );
636
+     /* else it's added to del hooker list for future del */
637
+    else add_to_tail_of_timer_list( hash_table, &(p_cell->tl[DELETE_LIST]), DELETE_LIST, 0 );
638
+}
639
+
640
+