00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00052 #include <stdlib.h>
00053
00054
00055 #include "../../mem/shm_mem.h"
00056 #include "../../hash_func.h"
00057 #include "../../dprint.h"
00058 #include "../../md5utils.h"
00059 #include "../../ut.h"
00060 #include "../../globals.h"
00061 #include "../../error.h"
00062 #include "../../char_msg_val.h"
00063 #include "defs.h"
00064 #include "t_reply.h"
00065 #include "t_cancel.h"
00066 #include "t_stats.h"
00067 #include "h_table.h"
00068 #include "../../fix_lumps.h"
00069 #include "timer.h"
00070 #include "uac.h"
00071
00072
00073 static enum kill_reason kr;
00074
00075
00076
00077 struct s_table* _tm_table;
00078
00079 struct s_table* tm_get_table(void) {
00080 return _tm_table;
00081 }
00082
00083 void reset_kr(void) {
00084 kr=0;
00085 }
00086
00087 void set_kr( enum kill_reason _kr )
00088 {
00089 kr|=_kr;
00090 }
00091
00092
00093 enum kill_reason get_kr() {
00094 return kr;
00095 }
00096
00097
00098 void lock_hash(int i)
00099 {
00100
00101 int mypid;
00102
00103 mypid = my_pid();
00104 if (likely(atomic_get(&_tm_table->entries[i].locker_pid) != mypid)) {
00105 lock(&_tm_table->entries[i].mutex);
00106 atomic_set(&_tm_table->entries[i].locker_pid, mypid);
00107 } else {
00108
00109 _tm_table->entries[i].rec_lock_level++;
00110 }
00111 }
00112
00113
00114 void unlock_hash(int i)
00115 {
00116 if (likely(_tm_table->entries[i].rec_lock_level == 0)) {
00117 atomic_set(&_tm_table->entries[i].locker_pid, 0);
00118 unlock(&_tm_table->entries[i].mutex);
00119 } else {
00120
00121 _tm_table->entries[i].rec_lock_level--;
00122 }
00123 }
00124
00125
00126
00127 #ifdef TM_HASH_STATS
00128 unsigned int transaction_count( void )
00129 {
00130 unsigned int i;
00131 unsigned int count;
00132
00133 count=0;
00134 for (i=0; i<TABLE_ENTRIES; i++)
00135 count+=_tm_table->entries[i].cur_entries;
00136 return count;
00137 }
00138 #endif
00139
00140
00141
00142 void free_cell( struct cell* dead_cell )
00143 {
00144 char *b;
00145 int i;
00146 struct sip_msg *rpl;
00147 struct totag_elem *tt, *foo;
00148 struct tm_callback *cbs, *cbs_tmp;
00149
00150 release_cell_lock( dead_cell );
00151 if (unlikely(has_tran_tmcbs(dead_cell, TMCB_DESTROY)))
00152 run_trans_callbacks(TMCB_DESTROY, dead_cell, 0, 0, 0);
00153
00154 shm_lock();
00155
00156 if ( dead_cell->uas.request )
00157 sip_msg_free_unsafe( dead_cell->uas.request );
00158 if ( dead_cell->uas.response.buffer )
00159 shm_free_unsafe( dead_cell->uas.response.buffer );
00160 #ifdef CANCEL_REASON_SUPPORT
00161 if (unlikely(dead_cell->uas.cancel_reas))
00162 shm_free_unsafe(dead_cell->uas.cancel_reas);
00163 #endif
00164
00165
00166 for( cbs=(struct tm_callback*)dead_cell->tmcb_hl.first ; cbs ; ) {
00167 cbs_tmp = cbs;
00168 cbs = cbs->next;
00169 if (cbs_tmp->release) {
00170
00171
00172
00173
00174 shm_unlock();
00175 cbs_tmp->release(cbs_tmp->param);
00176 shm_lock();
00177 }
00178 shm_free_unsafe( cbs_tmp );
00179 }
00180
00181
00182 for ( i =0 ; i<dead_cell->nr_of_outgoings; i++ )
00183 {
00184
00185 if ( (b=dead_cell->uac[i].request.buffer) )
00186 shm_free_unsafe( b );
00187 b=dead_cell->uac[i].local_cancel.buffer;
00188 if (b!=0 && b!=BUSY_BUFFER)
00189 shm_free_unsafe( b );
00190 rpl=dead_cell->uac[i].reply;
00191 if (rpl && rpl!=FAKED_REPLY && rpl->msg_flags&FL_SHM_CLONE) {
00192 sip_msg_free_unsafe( rpl );
00193 }
00194 #ifdef USE_DNS_FAILOVER
00195 if (dead_cell->uac[i].dns_h.a){
00196 DBG("branch %d -> dns_h.srv (%.*s) ref=%d,"
00197 " dns_h.a (%.*s) ref=%d\n", i,
00198 dead_cell->uac[i].dns_h.srv?
00199 dead_cell->uac[i].dns_h.srv->name_len:0,
00200 dead_cell->uac[i].dns_h.srv?
00201 dead_cell->uac[i].dns_h.srv->name:"",
00202 dead_cell->uac[i].dns_h.srv?
00203 dead_cell->uac[i].dns_h.srv->refcnt.val:0,
00204 dead_cell->uac[i].dns_h.a->name_len,
00205 dead_cell->uac[i].dns_h.a->name,
00206 dead_cell->uac[i].dns_h.a->refcnt.val);
00207 }
00208 dns_srv_handle_put_shm_unsafe(&dead_cell->uac[i].dns_h);
00209 #endif
00210 if (unlikely(dead_cell->uac[i].path.s)) {
00211 shm_free_unsafe(dead_cell->uac[i].path.s);
00212 }
00213 }
00214
00215 #ifdef WITH_AS_SUPPORT
00216 if (dead_cell->uac[0].local_ack)
00217 free_local_ack_unsafe(dead_cell->uac[0].local_ack);
00218 #endif
00219
00220
00221 tt=dead_cell->fwded_totags;
00222 while(tt) {
00223 foo=tt->next;
00224 shm_free_unsafe(tt->tag.s);
00225 shm_free_unsafe(tt);
00226 tt=foo;
00227 }
00228
00229
00230 if (dead_cell->user_avps_from)
00231 destroy_avp_list_unsafe( &dead_cell->user_avps_from );
00232 if (dead_cell->user_avps_to)
00233 destroy_avp_list_unsafe( &dead_cell->user_avps_to );
00234 if (dead_cell->uri_avps_from)
00235 destroy_avp_list_unsafe( &dead_cell->uri_avps_from );
00236 if (dead_cell->uri_avps_to)
00237 destroy_avp_list_unsafe( &dead_cell->uri_avps_to );
00238 #ifdef WITH_XAVP
00239 if (dead_cell->xavps_list)
00240 xavp_destroy_list_unsafe( &dead_cell->xavps_list );
00241 #endif
00242
00243
00244 shm_free_unsafe( dead_cell );
00245
00246 shm_unlock();
00247 t_stats_freed();
00248 }
00249
00250
00251
00252 static inline void init_synonym_id( struct cell *t )
00253 {
00254 struct sip_msg *p_msg;
00255 int size;
00256 char *c;
00257 unsigned int myrand;
00258
00259 if (!syn_branch) {
00260 p_msg=t->uas.request;
00261 if (p_msg) {
00262
00263
00264
00265
00266 char_msg_val( p_msg, t->md5 );
00267 } else {
00268
00269
00270
00271
00272
00273
00274 myrand=rand();
00275 c=t->md5;
00276 size=MD5_LEN;
00277 memset(c, '0', size );
00278 int2reverse_hex( &c, &size, myrand );
00279 }
00280 }
00281 }
00282
00283 static void inline init_branches(struct cell *t)
00284 {
00285 unsigned int i;
00286 struct ua_client *uac;
00287
00288 for(i=0;i<MAX_BRANCHES;i++)
00289 {
00290 uac=&t->uac[i];
00291 uac->request.my_T = t;
00292 uac->request.branch = i;
00293 init_rb_timers(&uac->request);
00294 uac->local_cancel=uac->request;
00295 #ifdef USE_DNS_FAILOVER
00296 dns_srv_handle_init(&uac->dns_h);
00297 #endif
00298 }
00299 }
00300
00301
00302 struct cell* build_cell( struct sip_msg* p_msg )
00303 {
00304 struct cell* new_cell;
00305 int sip_msg_len;
00306 avp_list_t* old;
00307 struct tm_callback *cbs, *cbs_tmp;
00308 #ifdef WITH_XAVP
00309 sr_xavp_t** xold;
00310 #endif
00311
00312
00313
00314 new_cell = (struct cell*)shm_malloc( sizeof( struct cell )+
00315 ((MD5_LEN-sizeof(((struct cell*)0)->md5))&((syn_branch!=0)-1)) );
00316 if ( !new_cell ) {
00317 ser_error=E_OUT_OF_MEM;
00318 return NULL;
00319 }
00320
00321
00322 memset( new_cell, 0, sizeof( struct cell ) );
00323
00324
00325 new_cell->uas.response.my_T=new_cell;
00326 init_rb_timers(&new_cell->uas.response);
00327
00328 init_cell_timers(new_cell);
00329
00330 old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI,
00331 &new_cell->uri_avps_from );
00332 new_cell->uri_avps_from = *old;
00333 *old = 0;
00334
00335 old = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI,
00336 &new_cell->uri_avps_to );
00337 new_cell->uri_avps_to = *old;
00338 *old = 0;
00339
00340 old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER,
00341 &new_cell->user_avps_from );
00342 new_cell->user_avps_from = *old;
00343 *old = 0;
00344
00345 old = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER,
00346 &new_cell->user_avps_to );
00347 new_cell->user_avps_to = *old;
00348 *old = 0;
00349
00350 #ifdef WITH_XAVP
00351 xold = xavp_set_list(&new_cell->xavps_list );
00352 new_cell->xavps_list = *xold;
00353 *xold = 0;
00354 #endif
00355
00356
00357
00358
00359 new_cell->domain_avps_from = get_avp_list(AVP_TRACK_FROM |
00360 AVP_CLASS_DOMAIN);
00361 new_cell->domain_avps_to = get_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN);
00362
00363
00364
00365 if (p_msg) {
00366 set_early_tmcb_list(p_msg, new_cell);
00367 if(has_reqin_tmcbs())
00368 run_reqin_callbacks( new_cell, p_msg, p_msg->REQ_METHOD);
00369 }
00370
00371 if (p_msg) {
00372 new_cell->uas.request = sip_msg_cloner(p_msg,&sip_msg_len);
00373 if (!new_cell->uas.request)
00374 goto error;
00375 new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len;
00376 }
00377
00378
00379 init_branches(new_cell);
00380
00381 new_cell->relayed_reply_branch = -1;
00382
00383
00384 init_synonym_id(new_cell);
00385 init_cell_lock( new_cell );
00386 t_stats_created();
00387 return new_cell;
00388
00389 error:
00390
00391
00392
00393
00394
00395 if (unlikely(has_tran_tmcbs(new_cell, TMCB_DESTROY)))
00396 run_trans_callbacks(TMCB_DESTROY, new_cell, 0, 0, 0);
00397
00398
00399 for( cbs=(struct tm_callback*)new_cell->tmcb_hl.first ; cbs ; ) {
00400 cbs_tmp = cbs;
00401 cbs = cbs->next;
00402 if (cbs_tmp->release) {
00403 cbs_tmp->release(cbs_tmp->param);
00404 }
00405 shm_free( cbs_tmp );
00406 }
00407
00408 destroy_avp_list(&new_cell->user_avps_from);
00409 destroy_avp_list(&new_cell->user_avps_to);
00410 destroy_avp_list(&new_cell->uri_avps_from);
00411 destroy_avp_list(&new_cell->uri_avps_to);
00412 #ifdef WITH_XAVP
00413 xavp_destroy_list(&new_cell->xavps_list);
00414 #endif
00415 shm_free(new_cell);
00416
00417 reset_avps();
00418 #ifdef WITH_XAVP
00419 xavp_reset_list();
00420 #endif
00421 return NULL;
00422 }
00423
00424
00425
00426
00427
00428 void free_hash_table( )
00429 {
00430 struct cell* p_cell;
00431 struct cell* tmp_cell;
00432 int i;
00433
00434 if (_tm_table)
00435 {
00436
00437 for( i = 0 ; i<TABLE_ENTRIES; i++)
00438 {
00439 release_entry_lock( (_tm_table->entries)+i );
00440
00441 clist_foreach_safe(&_tm_table->entries[i], p_cell, tmp_cell,
00442 next_c){
00443 free_cell(p_cell);
00444 }
00445 }
00446 shm_free(_tm_table);
00447 _tm_table = 0;
00448 }
00449 }
00450
00451
00452
00453
00454
00455
00456 struct s_table* init_hash_table()
00457 {
00458 int i;
00459
00460
00461 _tm_table= (struct s_table*)shm_malloc( sizeof( struct s_table ) );
00462 if ( !_tm_table) {
00463 LOG(L_ERR, "ERROR: init_hash_table: no shmem for TM table\n");
00464 goto error0;
00465 }
00466
00467 memset( _tm_table, 0, sizeof (struct s_table ) );
00468
00469
00470 if (lock_initialize()==-1)
00471 goto error1;
00472
00473
00474 for( i=0 ; i<TABLE_ENTRIES; i++ )
00475 {
00476 init_entry_lock( _tm_table, (_tm_table->entries)+i );
00477 _tm_table->entries[i].next_label = rand();
00478
00479 clist_init(&_tm_table->entries[i], next_c, prev_c);
00480 }
00481
00482 return _tm_table;
00483
00484 error1:
00485 free_hash_table( );
00486 error0:
00487 return 0;
00488 }
00489
00490
00496 void tm_xdata_swap(tm_cell_t *t, tm_xlinks_t *xd, int mode)
00497 {
00498 static tm_xlinks_t _txdata;
00499 tm_xlinks_t *x;
00500
00501 if(xd==NULL)
00502 x = &_txdata;
00503 else
00504 x = xd;
00505
00506 if(mode==0) {
00507 if(t==NULL)
00508 return;
00509 x->uri_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from );
00510 x->uri_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to );
00511 x->user_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from );
00512 x->user_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to );
00513 x->domain_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from );
00514 x->domain_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to );
00515 #ifdef WITH_XAVP
00516 x->xavps_list = xavp_set_list(&t->xavps_list);
00517 #endif
00518 } else if(mode==1) {
00519
00520 set_avp_list( AVP_TRACK_FROM | AVP_CLASS_URI, x->uri_avps_from );
00521 set_avp_list( AVP_TRACK_TO | AVP_CLASS_URI, x->uri_avps_to );
00522 set_avp_list( AVP_TRACK_FROM | AVP_CLASS_USER, x->user_avps_from );
00523 set_avp_list( AVP_TRACK_TO | AVP_CLASS_USER, x->user_avps_to );
00524 set_avp_list( AVP_TRACK_FROM | AVP_CLASS_DOMAIN, x->domain_avps_from );
00525 set_avp_list( AVP_TRACK_TO | AVP_CLASS_DOMAIN, x->domain_avps_to );
00526 #ifdef WITH_XAVP
00527 xavp_set_list(x->xavps_list);
00528 #endif
00529 }
00530
00531 }
00532
00536 void tm_xdata_replace(tm_xdata_t *newxd, tm_xlinks_t *bakxd)
00537 {
00538 if(newxd==NULL && bakxd!=NULL) {
00539 set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, bakxd->uri_avps_from);
00540 set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, bakxd->uri_avps_to);
00541 set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, bakxd->user_avps_from);
00542 set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, bakxd->user_avps_to);
00543 set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, bakxd->domain_avps_from);
00544 set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, bakxd->domain_avps_to);
00545 #ifdef WITH_XAVP
00546 xavp_set_list(bakxd->xavps_list);
00547 #endif
00548 return;
00549 }
00550
00551 if(newxd!=NULL && bakxd!=NULL) {
00552 bakxd->uri_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI,
00553 &newxd->uri_avps_from);
00554 bakxd->uri_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI,
00555 &newxd->uri_avps_to);
00556 bakxd->user_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER,
00557 &newxd->user_avps_from);
00558 bakxd->user_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER,
00559 &newxd->user_avps_to);
00560 bakxd->domain_avps_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN,
00561 &newxd->domain_avps_from);
00562 bakxd->domain_avps_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN,
00563 &newxd->domain_avps_to);
00564 #ifdef WITH_XAVP
00565 bakxd->xavps_list = xavp_set_list(&newxd->xavps_list);
00566 #endif
00567 return;
00568 }
00569 }