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 #include "../../mem/shm_mem.h"
00038 #include "../../hash_func.h"
00039 #include "../../dprint.h"
00040 #include "../../ut.h"
00041 #include "../../route.h"
00042 #include "../tm/tm_load.h"
00043 #include "dlg_hash.h"
00044 #include "dlg_profile.h"
00045
00046
00047
00048 #define PROFILE_HASH_SIZE 16
00049
00050
00051 extern struct tm_binds d_tmb;
00052
00053
00054 static unsigned int current_dlg_msg_id = 0 ;
00055
00056
00057 struct dlg_cell *current_dlg_pointer = NULL ;
00058
00059
00060 static struct dlg_profile_link *current_pending_linkers = NULL;
00061
00062
00063 static struct dlg_profile_table *profiles = NULL;
00064
00065
00066 static struct dlg_profile_table* new_dlg_profile( str *name,
00067 unsigned int size, unsigned int has_value);
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 int add_profile_definitions( char* profiles, unsigned int has_value)
00078 {
00079 char *p;
00080 char *d;
00081 str name;
00082 unsigned int i;
00083
00084 if (profiles==NULL || strlen(profiles)==0 )
00085 return 0;
00086
00087 p = profiles;
00088 do {
00089
00090 name.s = p;
00091 d = strchr( p, ';');
00092 if (d) {
00093 name.len = d-p;
00094 d++;
00095 } else {
00096 name.len = strlen(p);
00097 }
00098
00099
00100 trim_spaces_lr( name );
00101
00102
00103 if (name.len==0)
00104
00105 continue;
00106
00107
00108 for(i=0;i<name.len;i++) {
00109 if ( !isalnum(name.s[i]) ) {
00110 LM_ERR("bad profile name <%.*s>, char %c - use only "
00111 "alphanumerical characters\n", name.len,name.s,name.s[i]);
00112 return -1;
00113 }
00114 }
00115
00116
00117 LM_DBG("creating profile <%.*s>\n",name.len,name.s);
00118
00119 if (new_dlg_profile( &name, PROFILE_HASH_SIZE, has_value)==NULL) {
00120 LM_ERR("failed to create new profile <%.*s>\n",name.len,name.s);
00121 return -1;
00122 }
00123
00124 }while( (p=d)!=NULL );
00125
00126 return 0;
00127 }
00128
00129
00130
00131
00132
00133
00134
00135
00136 struct dlg_profile_table* search_dlg_profile(str *name)
00137 {
00138 struct dlg_profile_table *profile;
00139
00140 for( profile=profiles ; profile ; profile=profile->next ) {
00141 if (name->len==profile->name.len &&
00142 memcmp(name->s,profile->name.s,name->len)==0 )
00143 return profile;
00144 }
00145 return NULL;
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 static struct dlg_profile_table* new_dlg_profile( str *name, unsigned int size,
00158 unsigned int has_value)
00159 {
00160 struct dlg_profile_table *profile;
00161 struct dlg_profile_table *ptmp;
00162 unsigned int len;
00163 unsigned int i;
00164
00165 if ( name->s==NULL || name->len==0 || size==0 ) {
00166 LM_ERR("invalid parameters\n");
00167 return NULL;
00168 }
00169
00170 for( len=0,i=0 ; i<8*sizeof(size) ; i++ ) {
00171 if ( size & (1<<i) ) len++;
00172 }
00173 if (len!=1) {
00174 LM_ERR(" size %u is not power of 2!\n", size);
00175 return NULL;
00176 }
00177
00178 profile = search_dlg_profile(name);
00179 if (profile!=NULL) {
00180 LM_ERR("duplicate dialog profile registered <%.*s>\n",
00181 name->len, name->s);
00182 return NULL;
00183 }
00184
00185 len = sizeof(struct dlg_profile_table) +
00186 size*sizeof(struct dlg_profile_entry) +
00187 name->len + 1;
00188 profile = (struct dlg_profile_table *)shm_malloc(len);
00189 if (profile==NULL) {
00190 LM_ERR("no more shm mem\n");
00191 return NULL;
00192 }
00193
00194 memset( profile , 0 , len);
00195 profile->size = size;
00196 profile->has_value = (has_value==0)?0:1;
00197
00198
00199 if (lock_init( &profile->lock )==NULL) {
00200 LM_ERR("failed to init lock\n");
00201 shm_free(profile);
00202 return NULL;
00203 }
00204
00205
00206 profile->entries = (struct dlg_profile_entry*)(profile + 1);
00207 profile->name.s = ((char*)profile->entries) +
00208 size*sizeof(struct dlg_profile_entry);
00209
00210
00211 memcpy( profile->name.s, name->s, name->len );
00212 profile->name.len = name->len;
00213 profile->name.s[profile->name.len] = 0;
00214
00215
00216 for( ptmp=profiles ; ptmp && ptmp->next; ptmp=ptmp->next );
00217 if (ptmp==NULL)
00218 profiles = profile;
00219 else
00220 ptmp->next = profile;
00221
00222 return profile;
00223 }
00224
00225
00226
00227
00228
00229
00230 static void destroy_dlg_profile(struct dlg_profile_table *profile)
00231 {
00232 if (profile==NULL)
00233 return;
00234
00235 lock_destroy( &profile->lock );
00236 shm_free( profile );
00237 return;
00238 }
00239
00240
00241
00242
00243
00244 void destroy_dlg_profiles(void)
00245 {
00246 struct dlg_profile_table *profile;
00247
00248 while(profiles) {
00249 profile = profiles;
00250 profiles = profiles->next;
00251 destroy_dlg_profile( profile );
00252 }
00253 return;
00254 }
00255
00256
00257
00258
00259
00260
00261 void destroy_linkers(struct dlg_profile_link *linker)
00262 {
00263 struct dlg_profile_entry *p_entry;
00264 struct dlg_profile_link *l;
00265 struct dlg_profile_hash *lh;
00266
00267 while(linker) {
00268 l = linker;
00269 linker = linker->next;
00270
00271 if (l->hash_linker.next) {
00272 p_entry = &l->profile->entries[l->hash_linker.hash];
00273 get_lock( &l->profile->lock );
00274 lh = &l->hash_linker;
00275
00276 if (lh==lh->next) {
00277 p_entry->first = NULL;
00278 } else {
00279 if (p_entry->first==lh)
00280 p_entry->first = lh->next;
00281 lh->next->prev = lh->prev;
00282 lh->prev->next = lh->next;
00283 }
00284 lh->next = lh->prev = NULL;
00285 p_entry->content --;
00286 release_lock( &l->profile->lock );
00287 }
00288
00289 shm_free(l);
00290 }
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300 int profile_cleanup( struct sip_msg *msg, void *param )
00301 {
00302 current_dlg_msg_id = 0;
00303 if (current_dlg_pointer) {
00304 unref_dlg( current_dlg_pointer, 1);
00305 current_dlg_pointer = NULL;
00306 }
00307 if (current_pending_linkers) {
00308 destroy_linkers(current_pending_linkers);
00309 current_pending_linkers = NULL;
00310 }
00311
00312
00313 return 1;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322 static struct dlg_cell *get_current_dialog(struct sip_msg *msg)
00323 {
00324 struct cell *trans;
00325
00326 if (route_type==REQUEST_ROUTE) {
00327
00328 if (msg->id==current_dlg_msg_id)
00329 return current_dlg_pointer;
00330 current_dlg_pointer = NULL;
00331 current_dlg_msg_id = msg->id;
00332 destroy_linkers(current_pending_linkers);
00333 current_pending_linkers = NULL;
00334 return NULL;
00335 } else {
00336
00337 trans = d_tmb.t_gett();
00338 if (trans==NULL || trans==T_UNDEFINED)
00339 return NULL;
00340 return (struct dlg_cell*)trans->dialog_ctx;
00341 }
00342 }
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 inline static unsigned int calc_hash_profile(str *value, struct dlg_cell *dlg,
00354 struct dlg_profile_table *profile)
00355 {
00356 if (profile->has_value) {
00357
00358 return core_hash( value, NULL, profile->size);
00359 } else {
00360
00361 return ((unsigned long)dlg) % profile->size ;
00362 }
00363 }
00364
00365
00366
00367
00368
00369
00370
00371 static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *dlg)
00372 {
00373 unsigned int hash;
00374 struct dlg_profile_entry *p_entry;
00375 struct dlg_entry *d_entry;
00376
00377
00378
00379
00380 if (dlg->h_id) {
00381 d_entry = &d_table->entries[dlg->h_entry];
00382 dlg_lock( d_table, d_entry);
00383 linker->next = dlg->profile_links;
00384 dlg->profile_links =linker;
00385 linker->hash_linker.dlg = dlg;
00386 dlg_unlock( d_table, d_entry);
00387 } else {
00388 linker->next = dlg->profile_links;
00389 dlg->profile_links =linker;
00390 linker->hash_linker.dlg = dlg;
00391 }
00392
00393
00394 hash = calc_hash_profile(&linker->hash_linker.value, dlg, linker->profile);
00395 linker->hash_linker.hash = hash;
00396
00397
00398 p_entry = &linker->profile->entries[hash];
00399 get_lock( &linker->profile->lock );
00400 if (p_entry->first) {
00401 linker->hash_linker.prev = p_entry->first->prev;
00402 linker->hash_linker.next = p_entry->first;
00403 p_entry->first->prev->next = &linker->hash_linker;
00404 p_entry->first->prev = &linker->hash_linker;
00405 } else {
00406 p_entry->first = linker->hash_linker.next
00407 = linker->hash_linker.prev = &linker->hash_linker;
00408 }
00409 p_entry->content ++;
00410 release_lock( &linker->profile->lock );
00411 }
00412
00413
00414
00415
00416
00417
00418
00419 void set_current_dialog(struct sip_msg *msg, struct dlg_cell *dlg)
00420 {
00421 struct dlg_profile_link *linker;
00422 struct dlg_profile_link *tlinker;
00423
00424
00425 if (msg->id!=current_dlg_msg_id) {
00426 current_dlg_msg_id = msg->id;
00427 destroy_linkers(current_pending_linkers);
00428 } else {
00429
00430 linker = current_pending_linkers;
00431 while (linker) {
00432 tlinker = linker;
00433 linker = linker->next;
00434
00435 tlinker->next = NULL;
00436 link_dlg_profile( tlinker, dlg);
00437 }
00438 }
00439 current_pending_linkers = NULL;
00440 current_dlg_pointer = dlg;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *profile)
00452 {
00453 struct dlg_cell *dlg;
00454 struct dlg_profile_link *linker;
00455
00456
00457 dlg = get_current_dialog(msg);
00458
00459 if (dlg==NULL && route_type!=REQUEST_ROUTE) {
00460 LM_CRIT("BUG - dialog not found in a non REQUEST route (%d)\n",
00461 REQUEST_ROUTE);
00462 return -1;
00463 }
00464
00465
00466 linker = (struct dlg_profile_link*)shm_malloc(
00467 sizeof(struct dlg_profile_link) + (profile->has_value?value->len:0) );
00468 if (linker==NULL) {
00469 LM_ERR("no more shm memory\n");
00470 return -1;
00471 }
00472 memset(linker, 0, sizeof(struct dlg_profile_link));
00473
00474
00475 linker->profile = profile;
00476
00477
00478 if (profile->has_value) {
00479 linker->hash_linker.value.s = (char*)(linker+1);
00480 memcpy( linker->hash_linker.value.s, value->s, value->len);
00481 linker->hash_linker.value.len = value->len;
00482 }
00483
00484 if (dlg!=NULL) {
00485
00486 link_dlg_profile( linker, dlg);
00487 } else {
00488
00489 linker->next = current_pending_linkers;
00490 current_pending_linkers = linker;
00491 }
00492
00493 return 0;
00494 }
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504 int unset_dlg_profile(struct sip_msg *msg, str *value,
00505 struct dlg_profile_table *profile)
00506 {
00507 struct dlg_cell *dlg;
00508 struct dlg_profile_link *linker;
00509 struct dlg_profile_link *linker_prev;
00510 struct dlg_entry *d_entry;
00511
00512
00513 dlg = get_current_dialog(msg);
00514
00515 if (dlg==NULL || route_type==REQUEST_ROUTE) {
00516 LM_CRIT("BUG - dialog NULL or del_profile used in request route\n");
00517 return -1;
00518 }
00519
00520
00521 d_entry = &d_table->entries[dlg->h_entry];
00522 dlg_lock( d_table, d_entry);
00523 linker = dlg->profile_links;
00524 linker_prev = NULL;
00525 for( ; linker ; linker_prev=linker,linker=linker->next) {
00526 if (linker->profile==profile) {
00527 if (profile->has_value==0) {
00528 goto found;
00529 } else if (value && value->len==linker->hash_linker.value.len &&
00530 memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
00531 goto found;
00532 }
00533
00534
00535
00536 }
00537 }
00538 dlg_unlock( d_table, d_entry);
00539 return -1;
00540
00541 found:
00542
00543
00544 if (linker_prev==NULL) {
00545 dlg->profile_links = linker->next;
00546 } else {
00547 linker_prev->next = linker->next;
00548 }
00549 linker->next = NULL;
00550 dlg_unlock( d_table, d_entry);
00551
00552 destroy_linkers(linker);
00553 return 1;
00554 }
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
00565 str *value)
00566 {
00567 struct dlg_cell *dlg;
00568 struct dlg_profile_link *linker;
00569 struct dlg_entry *d_entry;
00570
00571
00572 dlg = get_current_dialog(msg);
00573
00574 if (dlg==NULL)
00575 return -1;
00576
00577
00578 d_entry = &d_table->entries[dlg->h_entry];
00579 dlg_lock( d_table, d_entry);
00580 for( linker=dlg->profile_links ; linker ; linker=linker->next) {
00581 if (linker->profile==profile) {
00582 if (profile->has_value==0) {
00583 dlg_unlock( d_table, d_entry);
00584 return 1;
00585 } else if (value && value->len==linker->hash_linker.value.len &&
00586 memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
00587 dlg_unlock( d_table, d_entry);
00588 return 1;
00589 }
00590
00591
00592
00593 }
00594 }
00595 dlg_unlock( d_table, d_entry);
00596 return -1;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606 unsigned int get_profile_size(struct dlg_profile_table *profile, str *value)
00607 {
00608 unsigned int n,i;
00609 struct dlg_profile_hash *ph;
00610
00611 if (profile->has_value==0 || value==NULL) {
00612
00613 get_lock( &profile->lock );
00614 for( i=0,n=0 ; i<profile->size ; i++ )
00615 n += profile->entries[i].content;
00616 release_lock( &profile->lock );
00617 return n;
00618 } else {
00619
00620
00621 i = calc_hash_profile( value, NULL, profile);
00622 n = 0;
00623 get_lock( &profile->lock );
00624 ph = profile->entries[i].first;
00625 if(ph) {
00626 do {
00627
00628 if ( value->len==ph->value.len &&
00629 memcmp(value->s,ph->value.s,value->len)==0 ) {
00630
00631 n++;
00632 }
00633
00634 ph=ph->next;
00635 }while( ph!=profile->entries[i].first );
00636 }
00637 release_lock( &profile->lock );
00638 return n;
00639 }
00640 }
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 struct mi_root * mi_get_profile(struct mi_root *cmd_tree, void *param)
00651 {
00652 struct mi_node* node;
00653 struct mi_root* rpl_tree= NULL;
00654 struct mi_node* rpl = NULL;
00655 struct mi_attr* attr;
00656 struct dlg_profile_table *profile;
00657 str *value;
00658 str *profile_name;
00659 unsigned int size;
00660 int len;
00661 char *p;
00662
00663 node = cmd_tree->node.kids;
00664 if (node==NULL || !node->value.s || !node->value.len)
00665 return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
00666 profile_name = &node->value;
00667
00668 if (node->next) {
00669 node = node->next;
00670 if (!node->value.s || !node->value.len)
00671 return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
00672 if (node->next)
00673 return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
00674 value = &node->value;
00675 } else {
00676 value = NULL;
00677 }
00678
00679
00680 profile = search_dlg_profile( profile_name );
00681 if (profile==NULL)
00682 return init_mi_tree( 404, MI_SSTR("Profile not found"));
00683
00684 size = get_profile_size( profile , value );
00685
00686 rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
00687 if (rpl_tree==0)
00688 return 0;
00689 rpl = &rpl_tree->node;
00690
00691 node = add_mi_node_child(rpl, MI_DUP_VALUE, "profile", 7, NULL, 0);
00692 if (node==0) {
00693 free_mi_tree(rpl_tree);
00694 return NULL;
00695 }
00696
00697 attr = add_mi_attr(node, MI_DUP_VALUE, "name", 4,
00698 profile->name.s, profile->name.len);
00699 if(attr == NULL) {
00700 goto error;
00701 }
00702
00703 if (value) {
00704 attr = add_mi_attr(node, MI_DUP_VALUE, "value", 5, value->s, value->len);
00705 } else {
00706 attr = add_mi_attr(node, MI_DUP_VALUE, "value", 5, NULL, 0);
00707 }
00708 if(attr == NULL) {
00709 goto error;
00710 }
00711
00712 p= int2str((unsigned long)size, &len);
00713 attr = add_mi_attr(node, MI_DUP_VALUE, "count", 5, p, len);
00714 if(attr == NULL) {
00715 goto error;
00716 }
00717
00718 return rpl_tree;
00719 error:
00720 free_mi_tree(rpl_tree);
00721 return NULL;
00722 }
00723
00724
00725
00726
00727
00728
00729
00730
00731 struct mi_root * mi_profile_list(struct mi_root *cmd_tree, void *param )
00732 {
00733 struct mi_node* node;
00734 struct mi_root* rpl_tree= NULL;
00735 struct mi_node* rpl = NULL;
00736 struct dlg_profile_table *profile;
00737 struct dlg_profile_hash *ph;
00738 str *profile_name;
00739 str *value;
00740 unsigned int i;
00741
00742 node = cmd_tree->node.kids;
00743 if (node==NULL || !node->value.s || !node->value.len)
00744 return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
00745 profile_name = &node->value;
00746
00747 if (node->next) {
00748 node = node->next;
00749 if (!node->value.s || !node->value.len)
00750 return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
00751 if (node->next)
00752 return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
00753 value = &node->value;
00754 } else {
00755 value = NULL;
00756 }
00757
00758
00759 profile = search_dlg_profile( profile_name );
00760 if (profile==NULL)
00761 return init_mi_tree( 404, MI_SSTR("Profile not found"));
00762
00763 rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
00764 if (rpl_tree==0)
00765 return 0;
00766 rpl = &rpl_tree->node;
00767
00768
00769 if (profile->has_value==0 || value==NULL) {
00770
00771 get_lock( &profile->lock );
00772 for ( i=0 ; i< profile->size ; i++ ) {
00773 ph = profile->entries[i].first;
00774 if(ph) {
00775 do {
00776
00777 if ( mi_print_dlg( rpl, ph->dlg, 0)!=0 )
00778 goto error;
00779
00780 ph=ph->next;
00781 }while( ph!=profile->entries[i].first );
00782 }
00783 release_lock( &profile->lock );
00784 }
00785 } else {
00786
00787 get_lock( &profile->lock );
00788 for ( i=0 ; i< profile->size ; i++ ) {
00789 ph = profile->entries[i].first;
00790 if(ph) {
00791 do {
00792 if ( value->len==ph->value.len &&
00793 memcmp(value->s,ph->value.s,value->len)==0 ) {
00794
00795 if ( mi_print_dlg( rpl, ph->dlg, 0)!=0 )
00796 goto error;
00797 }
00798
00799 ph=ph->next;
00800 }while( ph!=profile->entries[i].first );
00801 }
00802 release_lock( &profile->lock );
00803 }
00804 }
00805
00806 return rpl_tree;
00807 error:
00808 free_mi_tree(rpl_tree);
00809 return NULL;
00810 }