c666f61ee8a19df034b50ca20ed6eca0848f9f64
[sip-router] / modules / tm / h_table.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * History
28  * -------
29  * 2003-03-06  200/INV to-tag list deallocation added;
30  *             setting "kill_reason" moved in here -- it is moved
31  *             from transaction state to a static var(jiri)
32  * 2003-03-16  removed _TOTAG (jiri)
33  * 2003-03-30  set_kr for requests only (jiri)
34  * 2003-04-04  bug_fix: REQ_IN callback not called for local 
35  *             UAC transactions (jiri)
36  * 2003-09-12  timer_link->tg will be set only if EXTRA_DEBUG (andrei)
37  * 2003-12-04  global callbacks replaceed with callbacks per transaction;
38  *             completion callback merged into them as LOCAL_COMPETED (bogdan)
39  * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
40  * 2004-02-13  t->is_invite and t->local replaced with flags;
41  *             timer_link.payload removed (bogdan)
42  * 2004-08-23  avp support added - move and remove avp list to/from
43  *             transactions (bogdan)
44  * 2006-08-11  dns failover support (andrei)
45  * 2007-05-16  callbacks called on destroy (andrei)
46  * 2007-06-06  don't allocate extra space for md5 if not used: syn_branch==1 
47  *              (andrei)
48  * 2007-06-06  switched tm bucket list to a simpler and faster clist (andrei)
49  */
50
51 #include <stdlib.h>
52
53
54 #include "../../mem/shm_mem.h"
55 #include "../../hash_func.h"
56 #include "../../dprint.h"
57 #include "../../md5utils.h"
58 #include "../../ut.h"
59 #include "../../globals.h"
60 #include "../../error.h"
61 #include "defs.h"
62 #include "t_reply.h"
63 #include "t_cancel.h"
64 #include "t_stats.h"
65 #include "h_table.h"
66 #include "fix_lumps.h" /* free_via_clen_lump */
67 #include "timer.h"
68
69
70 static enum kill_reason kr;
71
72 /* pointer to the big table where all the transaction data
73    lives */
74 struct s_table*  _tm_table;
75
76
77 void reset_kr() {
78         kr=0;
79 }
80
81 void set_kr( enum kill_reason _kr )
82 {
83         kr|=_kr;
84 }
85
86
87 enum kill_reason get_kr() {
88         return kr;
89 }
90
91
92 void lock_hash(int i) 
93 {
94         lock(&_tm_table->entries[i].mutex);
95 }
96
97
98 void unlock_hash(int i) 
99 {
100         unlock(&_tm_table->entries[i].mutex);
101 }
102
103
104
105 #ifdef TM_HASH_STATS
106 unsigned int transaction_count( void )
107 {
108         unsigned int i;
109         unsigned int count;
110
111         count=0;        
112         for (i=0; i<TABLE_ENTRIES; i++) 
113                 count+=_tm_table->entries[i].cur_entries;
114         return count;
115 }
116 #endif
117
118
119
120 void free_cell( struct cell* dead_cell )
121 {
122         char *b;
123         int i;
124         struct sip_msg *rpl;
125         struct totag_elem *tt, *foo;
126         struct tm_callback *cbs, *cbs_tmp;
127
128         release_cell_lock( dead_cell );
129         if (unlikely(has_tran_tmcbs(dead_cell, TMCB_DESTROY)))
130                 run_trans_callbacks(TMCB_DESTROY, dead_cell, 0, 0, 0);
131
132         shm_lock();
133         /* UA Server */
134         if ( dead_cell->uas.request )
135                 sip_msg_free_unsafe( dead_cell->uas.request );
136         if ( dead_cell->uas.response.buffer )
137                 shm_free_unsafe( dead_cell->uas.response.buffer );
138
139         /* callbacks */
140         for( cbs=(struct tm_callback*)dead_cell->tmcb_hl.first ; cbs ; ) {
141                 cbs_tmp = cbs;
142                 cbs = cbs->next;
143                 shm_free_unsafe( cbs_tmp );
144         }
145
146         /* UA Clients */
147         for ( i =0 ; i<dead_cell->nr_of_outgoings;  i++ )
148         {
149                 /* retransmission buffer */
150                 if ( (b=dead_cell->uac[i].request.buffer) )
151                         shm_free_unsafe( b );
152                 b=dead_cell->uac[i].local_cancel.buffer;
153                 if (b!=0 && b!=BUSY_BUFFER)
154                         shm_free_unsafe( b );
155                 rpl=dead_cell->uac[i].reply;
156                 if (rpl && rpl!=FAKED_REPLY && rpl->msg_flags&FL_SHM_CLONE) {
157                         sip_msg_free_unsafe( rpl );
158                 }
159 #ifdef USE_DNS_FAILOVER
160                 if (dead_cell->uac[i].dns_h.a){
161                         DBG("branch %d -> dns_h.srv (%.*s) ref=%d,"
162                                                         " dns_h.a (%.*s) ref=%d\n", i,
163                                         dead_cell->uac[i].dns_h.srv?
164                                                                 dead_cell->uac[i].dns_h.srv->name_len:0,
165                                         dead_cell->uac[i].dns_h.srv?
166                                                                 dead_cell->uac[i].dns_h.srv->name:"",
167                                         dead_cell->uac[i].dns_h.srv?
168                                                                 dead_cell->uac[i].dns_h.srv->refcnt.val:0,
169                                         dead_cell->uac[i].dns_h.a->name_len,
170                                         dead_cell->uac[i].dns_h.a->name,
171                                         dead_cell->uac[i].dns_h.a->refcnt.val);
172                 }
173                 dns_srv_handle_put_shm_unsafe(&dead_cell->uac[i].dns_h);
174 #endif
175         }
176
177         /* collected to tags */
178         tt=dead_cell->fwded_totags;
179         while(tt) {
180                 foo=tt->next;
181                 shm_free_unsafe(tt->tag.s);
182                 shm_free_unsafe(tt);
183                 tt=foo;
184         }
185
186         /* free the avp list */
187         if (dead_cell->user_avps_from)
188                 destroy_avp_list_unsafe( &dead_cell->user_avps_from );
189         if (dead_cell->user_avps_to)
190                 destroy_avp_list_unsafe( &dead_cell->user_avps_to );
191         if (dead_cell->uri_avps_from)
192                 destroy_avp_list_unsafe( &dead_cell->uri_avps_from );
193         if (dead_cell->uri_avps_to)
194                 destroy_avp_list_unsafe( &dead_cell->uri_avps_to );
195
196         /* the cell's body */
197         shm_free_unsafe( dead_cell );
198
199         shm_unlock();
200         t_stats_freed();
201 }
202
203
204
205 static inline void init_synonym_id( struct cell *t )
206 {
207         struct sip_msg *p_msg;
208         int size;
209         char *c;
210         unsigned int myrand;
211
212         if (!syn_branch) {
213                 p_msg=t->uas.request;
214                 if (p_msg) {
215                         /* char value of a proxied transaction is
216                            calculated out of header-fields forming
217                            transaction key
218                         */
219                         char_msg_val( p_msg, t->md5 );
220                 } else {
221                         /* char value for a UAC transaction is created
222                            randomly -- UAC is an originating stateful element 
223                            which cannot be refreshed, so the value can be
224                            anything
225                         */
226                         /* HACK : not long enough */
227                         myrand=rand();
228                         c=t->md5;
229                         size=MD5_LEN;
230                         memset(c, '0', size );
231                         int2reverse_hex( &c, &size, myrand );
232                 }
233         }
234 }
235
236 static void inline init_branches(struct cell *t)
237 {
238         unsigned int i;
239         struct ua_client *uac;
240
241         for(i=0;i<MAX_BRANCHES;i++)
242         {
243                 uac=&t->uac[i];
244                 uac->request.my_T = t;
245                 uac->request.branch = i;
246                 init_rb_timers(&uac->request);
247                 uac->local_cancel=uac->request;
248 #ifdef USE_DNS_FAILOVER
249                 dns_srv_handle_init(&uac->dns_h);
250 #endif
251         }
252 }
253
254
255 struct cell*  build_cell( struct sip_msg* p_msg )
256 {
257         struct cell* new_cell;
258         int          sip_msg_len;
259         avp_list_t* old;
260
261         /* allocs a new cell */
262         /* if syn_branch==0 add space for md5 (MD5_LEN -sizeof(struct cell.md5)) */
263         new_cell = (struct cell*)shm_malloc( sizeof( struct cell )+
264                         ((MD5_LEN-sizeof(((struct cell*)0)->md5))&((syn_branch!=0)-1)) );
265         if  ( !new_cell ) {
266                 ser_error=E_OUT_OF_MEM;
267                 return NULL;
268         }
269
270         /* filling with 0 */
271         memset( new_cell, 0, sizeof( struct cell ) );
272
273         /* UAS */
274         new_cell->uas.response.my_T=new_cell;
275         init_rb_timers(&new_cell->uas.response);
276         /* timers */
277         init_cell_timers(new_cell);
278
279         old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, 
280                         &new_cell->uri_avps_from );
281         new_cell->uri_avps_from = *old;
282         *old = 0;
283
284         old = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, 
285                         &new_cell->uri_avps_to );
286         new_cell->uri_avps_to = *old;
287         *old = 0;
288
289         old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, 
290                         &new_cell->user_avps_from );
291         new_cell->user_avps_from = *old;
292         *old = 0;
293
294         old = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, 
295                         &new_cell->user_avps_to );
296         new_cell->user_avps_to = *old;
297         *old = 0;
298
299              /* We can just store pointer to domain avps in the transaction context,
300               * because they are read-only
301               */
302         new_cell->domain_avps_from = get_avp_list(AVP_TRACK_FROM | 
303                                                                 AVP_CLASS_DOMAIN);
304         new_cell->domain_avps_to = get_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN);
305
306         /* enter callback, which may potentially want to parse some stuff,
307          * before the request is shmem-ized */
308         if (p_msg && has_reqin_tmcbs())
309                         run_reqin_callbacks( new_cell, p_msg, p_msg->REQ_METHOD);
310
311         if (p_msg) {
312                 /* clean possible previous added vias/clen header or else they would 
313                  * get propagated in the failure routes */
314                 free_via_clen_lump(&p_msg->add_rm);
315                 new_cell->uas.request = sip_msg_cloner(p_msg,&sip_msg_len);
316                 if (!new_cell->uas.request)
317                         goto error;
318                 new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len;
319         }
320
321         /* UAC */
322         init_branches(new_cell);
323
324         new_cell->relayed_reply_branch   = -1;
325         /* new_cell->T_canceled = T_UNDEFINED; */
326
327         init_synonym_id(new_cell);
328         init_cell_lock(  new_cell );
329         t_stats_created();
330         return new_cell;
331
332 error:
333         destroy_avp_list(&new_cell->user_avps_from);
334         destroy_avp_list(&new_cell->user_avps_to);
335         destroy_avp_list(&new_cell->uri_avps_from);
336         destroy_avp_list(&new_cell->uri_avps_to);
337         shm_free(new_cell);
338         /* unlink transaction AVP list and link back the global AVP list (bogdan)*/
339         reset_avps();
340         return NULL;
341 }
342
343
344
345 /* Release all the data contained by the hash table. All the aux. structures
346  *  as sems, lists, etc, are also released */
347 void free_hash_table(  )
348 {
349         struct cell* p_cell;
350         struct cell* tmp_cell;
351         int    i;
352
353         if (_tm_table)
354         {
355                 /* remove the data contained by each entry */
356                 for( i = 0 ; i<TABLE_ENTRIES; i++)
357                 {
358                         release_entry_lock( (_tm_table->entries)+i );
359                         /* delete all synonyms at hash-collision-slot i */
360                         clist_foreach_safe(&_tm_table->entries[i], p_cell, tmp_cell,
361                                                                         next_c){
362                                 free_cell(p_cell);
363                         }
364                 }
365                 shm_free(_tm_table);
366         }
367 }
368
369
370
371
372 /*
373  */
374 struct s_table* init_hash_table()
375 {
376         int              i;
377
378         /*allocs the table*/
379         _tm_table= (struct s_table*)shm_malloc( sizeof( struct s_table ) );
380         if ( !_tm_table) {
381                 LOG(L_ERR, "ERROR: init_hash_table: no shmem for TM table\n");
382                 goto error0;
383         }
384
385         memset( _tm_table, 0, sizeof (struct s_table ) );
386
387         /* try first allocating all the structures needed for syncing */
388         if (lock_initialize()==-1)
389                 goto error1;
390
391         /* inits the entriess */
392         for(  i=0 ; i<TABLE_ENTRIES; i++ )
393         {
394                 init_entry_lock( _tm_table, (_tm_table->entries)+i );
395                 _tm_table->entries[i].next_label = rand();
396                 /* init cell list */
397                 clist_init(&_tm_table->entries[i], next_c, prev_c);
398         }
399
400         return  _tm_table;
401
402 error1:
403         free_hash_table( );
404 error0:
405         return 0;
406 }
407
408
409