bugfix: Call-ID generation repaired, from_tags introduced,
[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
28 #include <stdlib.h>
29 #include "../../mem/shm_mem.h"
30 #include "../../hash_func.h"
31 #include "h_table.h"
32 #include "../../dprint.h"
33 #include "../../md5utils.h"
34 /* bogdan test */
35 #include "../../ut.h"
36 #include "../../globals.h"
37 #include "../../error.h"
38 #include "../../fifo_server.h"
39 #include "t_reply.h"
40 #include "t_cancel.h"
41 #include "t_stats.h"
42
43 /* pointer to the big table where all the transaction data
44    lives
45 */
46
47 static struct s_table*  tm_table;
48
49 void lock_hash(int i) 
50 {
51         lock(&tm_table->entrys[i].mutex);
52 }
53
54 void unlock_hash(int i) 
55 {
56         unlock(&tm_table->entrys[i].mutex);
57 }
58
59
60 struct s_table* get_tm_table()
61 {
62         return tm_table;
63 }
64
65
66 unsigned int transaction_count( void )
67 {
68         unsigned int i;
69         unsigned int count;
70
71         count=0;        
72         for (i=0; i<TABLE_ENTRIES; i++) 
73                 count+=tm_table->entrys[i].cur_entries;
74         return count;
75 }
76
77
78
79 void free_cell( struct cell* dead_cell )
80 {
81         char *b;
82         int i;
83         struct sip_msg *rpl;
84
85         release_cell_lock( dead_cell );
86         shm_lock();
87
88         /* UA Server */
89         if ( dead_cell->uas.request )
90                 sip_msg_free_unsafe( dead_cell->uas.request );
91         if ( dead_cell->uas.response.buffer )
92                 shm_free_unsafe( dead_cell->uas.response.buffer );
93 #ifdef TOTAG
94         if (dead_cell->uas.to_tag.s)
95                 shm_free_unsafe(dead_cell->uas.to_tag.s);
96 #endif
97
98         /* completion callback */
99         if (dead_cell->cbp) shm_free_unsafe(dead_cell->cbp);
100
101         /* UA Clients */
102         for ( i =0 ; i<dead_cell->nr_of_outgoings;  i++ )
103         {
104                 /* retransmission buffer */
105                 if ( (b=dead_cell->uac[i].request.buffer) )
106                         shm_free_unsafe( b );
107 #ifdef OLD_CANCEL
108                 if ( (b=dead_cell->uac[i].request.ack) )
109                         shm_free_unsafe( b );
110                 if ( (b=dead_cell->uac[i].request.cancel) )
111                         shm_free_unsafe( b );
112 #endif
113                 b=dead_cell->uac[i].local_cancel.buffer;
114                 if (b!=0 && b!=BUSY_BUFFER)
115                         shm_free_unsafe( b );
116                 rpl=dead_cell->uac[i].reply;
117                 if (rpl && rpl!=FAKED_REPLY) {
118                         sip_msg_free_unsafe( rpl );
119                 }
120 #ifdef _OBSOLETED
121                 if ( (b=dead_cell->uac[i].rpl_buffer.s) )
122                         shm_free_unsafe( b );
123 #endif
124         }
125
126         /* the cell's body */
127         shm_free_unsafe( dead_cell );
128
129         shm_unlock();
130 }
131
132
133
134
135 struct cell*  build_cell( struct sip_msg* p_msg )
136 {
137         struct cell* new_cell;
138         unsigned int i;
139         unsigned int myrand;
140         int size;
141         char *c;
142         struct ua_client *uac;
143
144         /* avoid 'unitialized var use' warning */
145         myrand=0;
146
147         /* allocs a new cell */
148         new_cell = (struct cell*)shm_malloc( sizeof( struct cell ) );
149         if  ( !new_cell ) {
150                 ser_error=E_OUT_OF_MEM;
151                 return NULL;
152         }
153
154         /* filling with 0 */
155         memset( new_cell, 0, sizeof( struct cell ) );
156
157         /* UAS */
158         new_cell->uas.response.retr_timer.tg=TG_RT;
159         new_cell->uas.response.fr_timer.tg=TG_FR;
160         new_cell->uas.response.fr_timer.payload =
161                 new_cell->uas.response.retr_timer.payload = &(new_cell->uas.response);
162         new_cell->uas.response.my_T=new_cell;
163
164         /* bogdan - debug */
165         /*fprintf(stderr,"before clone VIA |%.*s|\n",via_len(p_msg->via1),
166                 via_s(p_msg->via1,p_msg));*/
167
168         if (p_msg) {
169                 new_cell->uas.request = sip_msg_cloner(p_msg);
170                 if (!new_cell->uas.request)
171                         goto error;
172         }
173
174         /* new_cell->uas.to_tag = &( get_to(new_cell->uas.request)->tag_value ); */
175         new_cell->uas.response.my_T = new_cell;
176
177         /* UAC */
178         for(i=0;i<MAX_BRANCHES;i++)
179         {
180                 uac=&new_cell->uac[i];
181                 uac->request.my_T = new_cell;
182                 uac->request.branch = i;
183                 uac->request.fr_timer.tg = TG_FR;
184                 uac->request.retr_timer.tg = TG_RT;
185                 uac->request.retr_timer.payload = 
186                         uac->request.fr_timer.payload =
187                         &uac->request;
188                 uac->local_cancel=uac->request;
189         }
190
191         /* global data for transaction */
192         if (p_msg) {
193                 new_cell->hash_index = p_msg->hash_index;
194         } else {
195                 /* note: unsatisfactory if 
196                    RAND_MAX < TABLE_ENTRIES
197                 */
198                 myrand = rand();
199                 new_cell->hash_index = myrand % TABLE_ENTRIES ;
200         }
201         new_cell->wait_tl.payload = new_cell;
202         new_cell->dele_tl.payload = new_cell;
203         new_cell->relaied_reply_branch   = -1;
204         /* new_cell->T_canceled = T_UNDEFINED; */
205         new_cell->wait_tl.tg=TG_WT;
206         new_cell->dele_tl.tg=TG_DEL;
207
208         if (!syn_branch) {
209                 if (p_msg) {
210                         /* char value of a proxied transaction is
211                            calculated out of header-fileds forming
212                            transaction key
213                         */
214                         char_msg_val( p_msg, new_cell->md5 );
215                 } else {
216                         /* char value for a UAC transaction is created
217                            randomly -- UAC is an originating stateful element 
218                            which cannot be refreshed, so the value can be
219                            anything
220                         */
221                         /* HACK : not long enough */
222                         c=new_cell->md5;
223                         size=MD5_LEN;
224                         memset(c, '0', size );
225                         int2reverse_hex( &c, &size, myrand );
226                 }
227         }
228
229         init_cell_lock(  new_cell );
230         return new_cell;
231
232 error:
233         shm_free(new_cell);
234         return NULL;
235 }
236
237
238
239
240 /* Release all the data contained by the hash table. All the aux. structures
241  *  as sems, lists, etc, are also released */
242 void free_hash_table(  )
243 {
244         struct cell* p_cell;
245         struct cell* tmp_cell;
246         int    i;
247
248         if (tm_table)
249         {
250                 /* remove the data contained by each entry */
251                 for( i = 0 ; i<TABLE_ENTRIES; i++)
252                 {
253                         release_entry_lock( (tm_table->entrys)+i );
254                         /* delete all synonyms at hash-collision-slot i */
255                         p_cell=tm_table->entrys[i].first_cell;
256                         for( ; p_cell; p_cell = tmp_cell )
257                         {
258                                 tmp_cell = p_cell->next_cell;
259                                 free_cell( p_cell );
260                         }
261                 }
262                 shm_free(tm_table);
263         }
264 }
265
266
267
268
269 /*
270  */
271 struct s_table* init_hash_table()
272 {
273         int              i;
274
275         /*allocs the table*/
276         tm_table= (struct s_table*)shm_malloc( sizeof( struct s_table ) );
277         if ( !tm_table) {
278                 LOG(L_ERR, "ERROR: init_hash_table: no shmem for TM table\n");
279                 goto error0;
280         }
281
282         memset( tm_table, 0, sizeof (struct s_table ) );
283
284         /* try first allocating all the structures needed for syncing */
285         if (lock_initialize()==-1)
286                 goto error1;
287
288         /* inits the entrys */
289         for(  i=0 ; i<TABLE_ENTRIES; i++ )
290         {
291                 init_entry_lock( tm_table, (tm_table->entrys)+i );
292                 tm_table->entrys[i].next_label = rand();
293         }
294
295         return  tm_table;
296
297 #ifdef _OBSO
298 error2:
299         lock_cleanup();
300 #endif
301 error1:
302         free_hash_table( );
303 error0:
304         return 0;
305 }
306
307
308
309
310 /*  Takes an already created cell and links it into hash table on the
311  *  appropiate entry. */
312 void insert_into_hash_table_unsafe( struct cell * p_cell )
313 {
314         struct entry* p_entry;
315
316         /* locates the apropiate entry */
317         p_entry = &tm_table->entrys[ p_cell->hash_index ];
318
319         p_cell->label = p_entry->next_label++;
320         if ( p_entry->last_cell )
321         {
322                 p_entry->last_cell->next_cell = p_cell;
323                 p_cell->prev_cell = p_entry->last_cell;
324         } else p_entry->first_cell = p_cell;
325
326         p_entry->last_cell = p_cell;
327
328         /* update stats */
329         p_entry->cur_entries++;
330         p_entry->acc_entries++;
331         t_stats_new(p_cell->local);
332 }
333
334
335
336
337 void insert_into_hash_table( struct cell * p_cell)
338 {
339         LOCK_HASH(p_cell->hash_index);
340         insert_into_hash_table_unsafe(  p_cell );
341         UNLOCK_HASH(p_cell->hash_index);
342 }
343
344
345
346
347 /*  Un-link a  cell from hash_table, but the cell itself is not released */
348 void remove_from_hash_table_unsafe( struct cell * p_cell)
349 {
350         struct entry*  p_entry  = &(tm_table->entrys[p_cell->hash_index]);
351
352         /* unlink the cell from entry list */
353         /* lock( &(p_entry->mutex) ); */
354
355         if ( p_cell->prev_cell )
356                 p_cell->prev_cell->next_cell = p_cell->next_cell;
357         else
358                 p_entry->first_cell = p_cell->next_cell;
359
360         if ( p_cell->next_cell )
361                 p_cell->next_cell->prev_cell = p_cell->prev_cell;
362         else
363                 p_entry->last_cell = p_cell->prev_cell;
364         /* update stats */
365 #       ifdef EXTRA_DEBUG
366         if (p_entry->cur_entries==0) {
367                 LOG(L_CRIT, "BUG: bad things happened: cur_entries=0\n");
368                 abort();
369         }
370 #       endif
371         p_entry->cur_entries--;
372         t_stats_deleted(p_cell->local);
373
374         /* unlock( &(p_entry->mutex) ); */
375 }
376
377 /* print accumulated distribution of the hash table */
378 int fifo_hash( FILE *stream, char *response_file )
379 {
380         FILE *reply_file;
381         unsigned int i;
382
383         reply_file=open_reply_pipe(response_file);
384         if (reply_file==0) {
385                 LOG(L_ERR, "ERROR: fifo_hash: file '%s' not opened\n", 
386                         response_file);
387                 return -1;
388         }
389         fputs( "200 ok\n\tcurrent\ttotal\n", reply_file);
390         for (i=0; i<TABLE_ENTRIES; i++) {
391                 fprintf(reply_file, "%d.\t%lu\t%lu\n", 
392                         i, tm_table->entrys[i].cur_entries ,
393                         tm_table->entrys[i].acc_entries );
394         }
395         fclose(reply_file);
396         return 1;
397 }