- updated to latest avp api
[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  */
45
46 #include <stdlib.h>
47
48
49 #include "../../mem/shm_mem.h"
50 #include "../../hash_func.h"
51 #include "../../dprint.h"
52 #include "../../md5utils.h"
53 #include "../../ut.h"
54 #include "../../globals.h"
55 #include "../../error.h"
56 #include "../../fifo_server.h"
57 #include "../../unixsock_server.h"
58 #include "defs.h"
59 #include "t_reply.h"
60 #include "t_cancel.h"
61 #include "t_stats.h"
62 #include "h_table.h"
63 #include "fix_lumps.h" /* free_via_clen_lump */
64
65 static enum kill_reason kr;
66
67 /* pointer to the big table where all the transaction data
68    lives */
69 static struct s_table*  tm_table;
70
71
72
73 void set_kr( enum kill_reason _kr )
74 {
75         kr|=_kr;
76 }
77
78
79 enum kill_reason get_kr() {
80         return kr;
81 }
82
83
84 void lock_hash(int i) 
85 {
86         lock(&tm_table->entrys[i].mutex);
87 }
88
89
90 void unlock_hash(int i) 
91 {
92         unlock(&tm_table->entrys[i].mutex);
93 }
94
95
96 struct s_table* get_tm_table()
97 {
98         return tm_table;
99 }
100
101
102 unsigned int transaction_count( void )
103 {
104         unsigned int i;
105         unsigned int count;
106
107         count=0;        
108         for (i=0; i<TABLE_ENTRIES; i++) 
109                 count+=tm_table->entrys[i].cur_entries;
110         return count;
111 }
112
113
114
115 void free_cell( struct cell* dead_cell )
116 {
117         char *b;
118         int i;
119         struct sip_msg *rpl;
120         struct totag_elem *tt, *foo;
121         struct tm_callback *cbs, *cbs_tmp;
122
123         release_cell_lock( dead_cell );
124         shm_lock();
125
126         /* UA Server */
127         if ( dead_cell->uas.request )
128                 sip_msg_free_unsafe( dead_cell->uas.request );
129         if ( dead_cell->uas.response.buffer )
130                 shm_free_unsafe( dead_cell->uas.response.buffer );
131
132         /* callbacks */
133         for( cbs=dead_cell->tmcb_hl.first ; cbs ; ) {
134                 cbs_tmp = cbs;
135                 cbs = cbs->next;
136                 shm_free_unsafe( cbs_tmp );
137         }
138
139         /* UA Clients */
140         for ( i =0 ; i<dead_cell->nr_of_outgoings;  i++ )
141         {
142                 /* retransmission buffer */
143                 if ( (b=dead_cell->uac[i].request.buffer) )
144                         shm_free_unsafe( b );
145                 b=dead_cell->uac[i].local_cancel.buffer;
146                 if (b!=0 && b!=BUSY_BUFFER)
147                         shm_free_unsafe( b );
148                 rpl=dead_cell->uac[i].reply;
149                 if (rpl && rpl!=FAKED_REPLY && rpl->msg_flags&FL_SHM_CLONE) {
150                         sip_msg_free_unsafe( rpl );
151                 }
152         }
153
154         /* collected to tags */
155         tt=dead_cell->fwded_totags;
156         while(tt) {
157                 foo=tt->next;
158                 shm_free_unsafe(tt->tag.s);
159                 shm_free_unsafe(tt);
160                 tt=foo;
161         }
162
163         /* free the avp list */
164         if (dead_cell->user_avps)
165                 destroy_avp_list_unsafe( &dead_cell->user_avps );
166
167         /* the cell's body */
168         shm_free_unsafe( dead_cell );
169
170         shm_unlock();
171 }
172
173
174
175 static inline void init_synonym_id( struct cell *t )
176 {
177         struct sip_msg *p_msg;
178         int size;
179         char *c;
180         unsigned int myrand;
181
182         if (!syn_branch) {
183                 p_msg=t->uas.request;
184                 if (p_msg) {
185                         /* char value of a proxied transaction is
186                            calculated out of header-fields forming
187                            transaction key
188                         */
189                         char_msg_val( p_msg, t->md5 );
190                 } else {
191                         /* char value for a UAC transaction is created
192                            randomly -- UAC is an originating stateful element 
193                            which cannot be refreshed, so the value can be
194                            anything
195                         */
196                         /* HACK : not long enough */
197                         myrand=rand();
198                         c=t->md5;
199                         size=MD5_LEN;
200                         memset(c, '0', size );
201                         int2reverse_hex( &c, &size, myrand );
202                 }
203         }
204 }
205
206 static void inline init_branches(struct cell *t)
207 {
208         unsigned int i;
209         struct ua_client *uac;
210
211         for(i=0;i<MAX_BRANCHES;i++)
212         {
213                 uac=&t->uac[i];
214                 uac->request.my_T = t;
215                 uac->request.branch = i;
216 #ifdef EXTRA_DEBUG
217                 uac->request.fr_timer.tg = TG_FR;
218                 uac->request.retr_timer.tg = TG_RT;
219 #endif
220                 uac->local_cancel=uac->request;
221         }
222 }
223
224
225 struct cell*  build_cell( struct sip_msg* p_msg )
226 {
227         struct cell* new_cell;
228         int          sip_msg_len;
229         avp_list_t* old;
230
231         /* allocs a new cell */
232         new_cell = (struct cell*)shm_malloc( sizeof( struct cell ) );
233         if  ( !new_cell ) {
234                 ser_error=E_OUT_OF_MEM;
235                 return NULL;
236         }
237
238         /* filling with 0 */
239         memset( new_cell, 0, sizeof( struct cell ) );
240
241         /* UAS */
242 #ifdef EXTRA_DEBUG
243         new_cell->uas.response.retr_timer.tg=TG_RT;
244         new_cell->uas.response.fr_timer.tg=TG_FR;
245 #endif
246         new_cell->uas.response.my_T=new_cell;
247
248         /* move the current avp list to transaction -bogdan */
249         old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER,  &new_cell->user_avps );
250         new_cell->user_avps = *old;
251         *old = 0;
252
253         /* enter callback, which may potentially want to parse some stuff,
254          * before the request is shmem-ized */
255         if ( p_msg && has_reqin_tmcbs() )
256                 run_reqin_callbacks( new_cell, p_msg, p_msg->REQ_METHOD);
257
258         if (p_msg) {
259                 /* clean possible previous added vias/clen header or else they would 
260                  * get propagated in the failure routes */
261                 free_via_clen_lump(&p_msg->add_rm);
262                 new_cell->uas.request = sip_msg_cloner(p_msg,&sip_msg_len);
263                 if (!new_cell->uas.request)
264                         goto error;
265                 new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len;
266         }
267
268         /* UAC */
269         init_branches(new_cell);
270
271         new_cell->relayed_reply_branch   = -1;
272         /* new_cell->T_canceled = T_UNDEFINED; */
273 #ifdef EXTRA_DEBUG
274         new_cell->wait_tl.tg=TG_WT;
275         new_cell->dele_tl.tg=TG_DEL;
276 #endif
277
278         init_synonym_id(new_cell);
279         init_cell_lock(  new_cell );
280         return new_cell;
281
282 error:
283         destroy_avp_list(&new_cell->user_avps);
284         shm_free(new_cell);
285         /* unlink transaction AVP list and link back the global AVP list (bogdan)*/
286         reset_avps();
287         return NULL;
288 }
289
290
291
292 /* Release all the data contained by the hash table. All the aux. structures
293  *  as sems, lists, etc, are also released */
294 void free_hash_table(  )
295 {
296         struct cell* p_cell;
297         struct cell* tmp_cell;
298         int    i;
299
300         if (tm_table)
301         {
302                 /* remove the data contained by each entry */
303                 for( i = 0 ; i<TABLE_ENTRIES; i++)
304                 {
305                         release_entry_lock( (tm_table->entrys)+i );
306                         /* delete all synonyms at hash-collision-slot i */
307                         p_cell=tm_table->entrys[i].first_cell;
308                         for( ; p_cell; p_cell = tmp_cell )
309                         {
310                                 tmp_cell = p_cell->next_cell;
311                                 free_cell( p_cell );
312                         }
313                 }
314                 shm_free(tm_table);
315         }
316 }
317
318
319
320
321 /*
322  */
323 struct s_table* init_hash_table()
324 {
325         int              i;
326
327         /*allocs the table*/
328         tm_table= (struct s_table*)shm_malloc( sizeof( struct s_table ) );
329         if ( !tm_table) {
330                 LOG(L_ERR, "ERROR: init_hash_table: no shmem for TM table\n");
331                 goto error0;
332         }
333
334         memset( tm_table, 0, sizeof (struct s_table ) );
335
336         /* try first allocating all the structures needed for syncing */
337         if (lock_initialize()==-1)
338                 goto error1;
339
340         /* inits the entrys */
341         for(  i=0 ; i<TABLE_ENTRIES; i++ )
342         {
343                 init_entry_lock( tm_table, (tm_table->entrys)+i );
344                 tm_table->entrys[i].next_label = rand();
345         }
346
347         return  tm_table;
348
349 error1:
350         free_hash_table( );
351 error0:
352         return 0;
353 }
354
355
356
357
358 /*  Takes an already created cell and links it into hash table on the
359  *  appropriate entry. */
360 void insert_into_hash_table_unsafe( struct cell * p_cell, unsigned int _hash )
361 {
362         struct entry* p_entry;
363
364         p_cell->hash_index=_hash;
365
366         /* locates the appropriate entry */
367         p_entry = &tm_table->entrys[ _hash ];
368
369         p_cell->label = p_entry->next_label++;
370         if ( p_entry->last_cell )
371         {
372                 p_entry->last_cell->next_cell = p_cell;
373                 p_cell->prev_cell = p_entry->last_cell;
374         } else p_entry->first_cell = p_cell;
375
376         p_entry->last_cell = p_cell;
377
378         /* update stats */
379         p_entry->cur_entries++;
380         p_entry->acc_entries++;
381         t_stats_new( is_local(p_cell) );
382 }
383
384
385 /*  Un-link a  cell from hash_table, but the cell itself is not released */
386 void remove_from_hash_table_unsafe( struct cell * p_cell)
387 {
388         struct entry*  p_entry  = &(tm_table->entrys[p_cell->hash_index]);
389
390         /* unlink the cell from entry list */
391         /* lock( &(p_entry->mutex) ); */
392
393         if ( p_cell->prev_cell )
394                 p_cell->prev_cell->next_cell = p_cell->next_cell;
395         else
396                 p_entry->first_cell = p_cell->next_cell;
397
398         if ( p_cell->next_cell )
399                 p_cell->next_cell->prev_cell = p_cell->prev_cell;
400         else
401                 p_entry->last_cell = p_cell->prev_cell;
402         /* update stats */
403 #       ifdef EXTRA_DEBUG
404         if (p_entry->cur_entries==0) {
405                 LOG(L_CRIT, "BUG: bad things happened: cur_entries=0\n");
406                 abort();
407         }
408 #       endif
409         p_entry->cur_entries--;
410         t_stats_deleted( is_local(p_cell) );
411
412         /* unlock( &(p_entry->mutex) ); */
413 }
414
415 /* print accumulated distribution of the hash table */
416 int fifo_hash( FILE *stream, char *response_file )
417 {
418         FILE *reply_file;
419         unsigned int i;
420
421         reply_file=open_reply_pipe(response_file);
422         if (reply_file==0) {
423                 LOG(L_ERR, "ERROR: fifo_hash: file '%s' not opened\n", 
424                         response_file);
425                 return -1;
426         }
427         fputs( "200 ok\n\tcurrent\ttotal\n", reply_file);
428         for (i=0; i<TABLE_ENTRIES; i++) {
429                 fprintf(reply_file, "%d.\t%lu\t%lu\n", 
430                         i, tm_table->entrys[i].cur_entries ,
431                         tm_table->entrys[i].acc_entries );
432         }
433         fclose(reply_file);
434         return 1;
435 }
436
437
438 int unixsock_hash(str* msg)
439 {
440         unsigned int i, ret;
441
442         ret = 0;
443         unixsock_reply_asciiz( "200 OK\n\tcurrent\ttotal\n");
444
445         for (i = 0; i < TABLE_ENTRIES; i++) {
446                 if (unixsock_reply_printf("%d.\t%lu\t%lu\n", 
447                                           i, tm_table->entrys[i].cur_entries,
448                                           tm_table->entrys[i].acc_entries
449                                           ) < 0) {
450                         unixsock_reply_reset();
451                         unixsock_reply_asciiz("500 Error while creating reply\n");
452                         ret = -1;
453                         break;
454                 }
455         }
456
457         if (unixsock_reply_send() < 0) {
458                 ret = -1;
459         }
460         return ret;
461 }