ser_error processing, ipv6-ization of TM, new TM callbacks;
[sip-router] / modules / tm / t_funcs.c
1 /*
2  * $Id$
3  *
4  * transaction maintenance functions
5  */
6
7 #include "../../dprint.h"
8 #include "../../config.h"
9 #include "../../parser/parser_f.h"
10 #include "../../ut.h"
11 #include "hash_func.h"
12 #include "t_funcs.h"
13 #include "t_fork.h"
14
15
16 struct cell      *T;
17 unsigned int     global_msg_id;
18 struct s_table*  hash_table;
19
20
21 int tm_startup()
22 {
23         /* building the hash table*/
24         hash_table = init_hash_table();
25         if (!hash_table)
26                 return -1;
27
28         /* init. timer lists */
29         hash_table->timers[RT_T1_TO_1].id = RT_T1_TO_1;
30         hash_table->timers[RT_T1_TO_2].id = RT_T1_TO_2;
31         hash_table->timers[RT_T1_TO_3].id = RT_T1_TO_3;
32         hash_table->timers[RT_T2].id      = RT_T2;
33         hash_table->timers[FR_TIMER_LIST].id     = FR_TIMER_LIST;
34         hash_table->timers[FR_INV_TIMER_LIST].id = FR_INV_TIMER_LIST;
35         hash_table->timers[WT_TIMER_LIST].id     = WT_TIMER_LIST;
36         hash_table->timers[DELETE_LIST].id       = DELETE_LIST;
37
38         /* register the timer function */
39         register_timer( timer_routine , hash_table , 1 );
40
41         /* fork table */
42         nr_forks = 0;
43
44         /*first msg id*/
45         global_msg_id = 0;
46         T = T_UNDEFINED;
47
48         return 0;
49 }
50
51
52
53
54 void tm_shutdown()
55 {
56         struct timer_link  *tl, *end, *tmp;
57         int i;
58
59         DBG("DEBUG: tm_shutdown : start\n");
60         /* remember the DELETE LIST */
61         tl = hash_table->timers[DELETE_LIST].first_tl.next_tl;
62         end = & hash_table->timers[DELETE_LIST].last_tl;
63         /* unlink the timer lists */
64         for( i=0; i<NR_OF_TIMER_LISTS ; i++ )
65                 reset_timer_list( hash_table, i );
66
67         DBG("DEBUG: tm_shutdown : empting DELETE list\n");
68         /* deletes all cells from DELETE_LIST list
69         (they are no more accessible from enrys) */
70         while (tl!=end) {
71                 tmp=tl->next_tl;
72                 free_cell((struct cell*)tl->payload);
73                 tl=tmp;
74         }
75
76         /* destroy the hash table */
77         DBG("DEBUG: tm_shutdown : empting hash table\n");
78         free_hash_table( hash_table );
79         DBG("DEBUG: tm_shutdown : removing semaphores\n");
80         lock_cleanup();
81         DBG("DEBUG: tm_shutdown : done\n");
82 }
83
84
85
86
87 /* function returns:
88  *       1 - a new transaction was created
89  *      -1 - error, including retransmission
90  */
91 int t_add_transaction( struct sip_msg* p_msg )
92 {
93         struct cell*    new_cell;
94
95         DBG("DEBUG: t_add_transaction: adding......\n");
96         /* sanity check: ACKs can never establish a transaction */
97         if ( p_msg->REQ_METHOD==METHOD_ACK )
98         {
99                 LOG(L_ERR, "ERROR: add_transaction: ACK can't be used to add"
100                         " transaction\n");
101                 return -1;
102         }
103
104         /* creates a new transaction */
105         new_cell = build_cell( p_msg ) ;
106         DBG("DEBUG: t_add_transaction: new transaction created %p\n", new_cell);
107         if  ( !new_cell ){
108                 LOG(L_ERR, "ERROR: add_transaction: out of mem:\n");
109                 sh_status();
110                 return -1;
111         }
112         /*insert the transaction into hash table*/
113         insert_into_hash_table( hash_table , new_cell );
114         DBG("DEBUG: t_add_transaction: new transaction inserted, hash: %d\n",
115                 new_cell->hash_index );
116
117         T = new_cell;
118         T_REF(T);
119         return 1;
120 }
121
122
123
124
125 /*   returns 1 if everything was OK or -1 for error
126 */
127 int t_release_transaction( struct sip_msg* p_msg)
128 {
129       return t_put_on_wait( T );
130 }
131
132
133
134 int t_unref( /* struct sip_msg* p_msg */ )
135 {
136         if (T==T_UNDEFINED || T==T_NULL)
137                 return -1;
138         T_UNREF( T );
139         T=T_UNDEFINED;
140         return 1;
141 }
142
143
144
145
146
147 /* ----------------------------HELPER FUNCTIONS-------------------------------- */
148
149
150 int t_update_timers_after_sending_reply( struct retr_buf *rb )
151 {
152         struct cell *Trans = rb->my_T;
153
154         /* make sure that if we send something final upstream, everything else
155            will be cancelled */
156         if (Trans->uas.status>=300&&Trans->uas.request->REQ_METHOD==METHOD_INVITE)
157         {
158                 rb->retr_list = RT_T1_TO_1;
159                 set_timer( hash_table, &(rb->retr_timer), RT_T1_TO_1 );
160                 set_timer( hash_table, &(rb->fr_timer), FR_TIMER_LIST );
161         } else if ( Trans->uas.request->REQ_METHOD==METHOD_CANCEL ) {
162                 if ( Trans->T_canceled==T_UNDEFINED )
163                         Trans->T_canceled = t_lookupOriginalT( hash_table ,
164                                 Trans->uas.request );
165                 if ( Trans->T_canceled==T_NULL )
166                         return 1;
167                 /* put CANCEL transaction on wait only if canceled transaction already
168                     is in final status and there is nothing to cancel; */
169                 if ( Trans->T_canceled->uas.status>=200)
170                         t_put_on_wait( Trans );
171         } else if (Trans->uas.status>=200)
172                 t_put_on_wait( Trans );
173    return 1;
174 }
175
176
177
178
179 /*
180   */
181 int t_put_on_wait(  struct cell  *Trans  )
182 {
183         unsigned int i;
184         //struct retrans_buff* rb;
185
186 #ifndef WAIT
187         if (is_in_timer_list2( &(Trans->wait_tl)))
188         {
189                 DBG("DEBUG: t_put_on_wait: already on wait\n");
190                 return 1;
191         }
192 #else
193         /* have some race conditons occured and we already
194           entered/passed the wait status previously?
195           if so, exit now
196         */
197
198         LOCK_WAIT(Trans);
199         if (Trans->on_wait)
200         {
201                 DBG("DEBUG: t_put_on_wait: already on wait\n");
202                 UNLOCK_WAIT(Trans);
203                 return 1;
204         } else {
205                 Trans->on_wait=1;
206                 UNLOCK_WAIT(Trans);
207         }
208 #endif
209
210         /* remove from  retranssmision  and  final response   list */
211         DBG("DEBUG: t_put_on_wait: stopping timers (FR and RETR)\n");
212         reset_retr_timers(hash_table,Trans) ;
213
214 #ifdef SILENT_FR
215         if (Trans->nr_of_outgoings>1)
216 #endif
217         {
218         /* cancel pending client transactions, if any */
219         for( i=0 ; i<Trans->nr_of_outgoings ; i++ )
220                 if ( Trans->uac[i].rpl_received && Trans->uac[i].status<200 )
221                         t_build_and_send_CANCEL(Trans , i);
222         }
223
224         /* adds to Wait list*/
225         set_timer( hash_table, &(Trans->wait_tl), WT_TIMER_LIST );
226         return 1;
227 }
228
229
230
231
232
233 void delete_cell( struct cell *p_cell )
234 {
235 #ifdef EXTRA_DEBUG
236         int i;
237
238         if (is_in_timer_list2(& p_cell->wait_tl )) {
239                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
240                         " still on WAIT\n", p_cell);
241                 abort();
242         }
243         /*
244         if (is_in_timer_list2(& p_cell->outbound_response.retr_timer )) {
245                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
246                         " still on RETR (rep)\n",
247                         p_cell);
248                 abort();
249         }
250         if (is_in_timer_list2(& p_cell->outbound_response.fr_timer )) {
251                 LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
252                         " still on FR (rep)\n", p_cell);
253                 abort();
254         }
255         for (i=0; i<p_cell->nr_of_outgoings; i++) {
256                 if (is_in_timer_list2(& p_cell->outbound_request[i]->retr_timer)) {
257                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
258                                 " still on RETR (req %d)\n", p_cell, i);
259                         abort();
260                 }
261                 if (is_in_timer_list2(& p_cell->outbound_request[i]->fr_timer)) {
262                         LOG( L_ERR, "ERROR: transaction %p scheduled for deletion and"
263                                 " still on FR (req %d)\n", p_cell, i);
264                         abort();
265                 }
266         }
267         */
268         reset_retr_timers( hash_table, p_cell );
269 #endif
270         /* still in use ... don't delete */
271         if ( T_IS_REFED(p_cell) ) {
272 #ifdef  EXTRA_DEBUG
273                 if (T_REFCOUNTER(p_cell)>1) {
274                         DBG("DEBUG: while debugging with a single process, ref_count>1\n");
275                         DBG("DEBUG: transaction =%p\n", p_cell );
276                         abort();
277                 }
278 #endif
279                 DBG("DEBUG: delete_cell: t=%p post for delete (refbitmap %x,"
280                         " refcount %d)\n",p_cell,p_cell->ref_bitmap,T_REFCOUNTER(p_cell));
281                 /* it's added to del list for future del */
282                 set_timer( hash_table, &(p_cell->dele_tl), DELETE_LIST );
283         } else {
284                 DBG("DEBUG: delete transaction %p\n", p_cell );
285                 free_cell( p_cell );
286         }
287 }
288
289