00001
00062 #include <values.h>
00063
00064 #include "../../mem/shm_mem.h"
00065
00066 #include "../../dset.h"
00067 #include "../tm/tm_load.h"
00068
00069 #include "scscf_list.h"
00070 #include "db.h"
00071 #include "sip.h"
00072
00073
00074 extern struct tm_binds tmb;
00076 scscf_capabilities *SCSCF_Capabilities=0;
00077 int SCSCF_Capabilities_cnt=0;
00079 int i_hash_size;
00080 i_hash_slot *i_hash_table=0;
00090 int I_get_capabilities()
00091 {
00092 int i,j,r;
00093
00094 if (SCSCF_Capabilities!=0){
00095 for(i=0;i<SCSCF_Capabilities_cnt;i++){
00096 if (SCSCF_Capabilities[i].capabilities)
00097 shm_free(SCSCF_Capabilities[i].capabilities);
00098 }
00099 shm_free(SCSCF_Capabilities);
00100 }
00101
00102 SCSCF_Capabilities_cnt = icscf_db_get_scscf(&SCSCF_Capabilities);
00103
00104 r = icscf_db_get_capabilities(&SCSCF_Capabilities,SCSCF_Capabilities_cnt);
00105
00106 LOG(L_DBG,"DBG:"M_NAME":------ S-CSCF Map with Capabilities begin ------\n");
00107 if (SCSCF_Capabilities!=0){
00108 for(i=0;i<SCSCF_Capabilities_cnt;i++){
00109 LOG(L_DBG,"DBG:"M_NAME":S-CSCF [%d] <%.*s>\n",
00110 SCSCF_Capabilities[i].id_s_cscf,
00111 SCSCF_Capabilities[i].scscf_name.len,
00112 SCSCF_Capabilities[i].scscf_name.s);
00113 for(j=0;j<SCSCF_Capabilities[i].cnt;j++)
00114 LOG(L_DBG,"DBG:"M_NAME": \t [%d]\n",
00115 SCSCF_Capabilities[i].capabilities[j]);
00116 }
00117 }
00118 LOG(L_DBG,"DBG:"M_NAME":------ S-CSCF Map with Capabilities end ------\n");
00119
00120 return r;
00121 }
00122
00133 int I_get_capab_match(scscf_capabilities *c,int *m,int mcnt,int *o,int ocnt)
00134 {
00135 int r=0,i,j,t=0;
00136 for(i=0;i<mcnt;i++){
00137 t=0;
00138 for(j=0;j<c->cnt;j++)
00139 if (m[i]==c->capabilities[j]) {
00140 t=1;
00141 break;
00142 }
00143 if (!t) return -1;
00144 }
00145 for(i=0;i<ocnt;i++){
00146 for(j=0;j<c->cnt;j++)
00147 if (o[i]==c->capabilities[j]) r++;
00148 }
00149 return r;
00150 }
00151
00156 static inline scscf_entry* I_add_to_scscf_list(scscf_entry *root,str name,int score, int originating)
00157 {
00158 scscf_entry *x,*i;
00159
00160
00161 for(i=root;i;i=i->next)
00162 if (name.len == i->scscf_name.len &&
00163 strncasecmp(name.s,i->scscf_name.s,name.len)==0)
00164 return root;
00165
00166 x = new_scscf_entry(name,score, originating);
00167 if (!x) return root;
00168
00169 if (!root){
00170 return x;
00171 }
00172 if (root->score < x->score){
00173 x->next = root;
00174 return x;
00175 }
00176 i = root;
00177 while(i->next && i->next->score > x->score)
00178 i = i->next;
00179 x->next = i->next;
00180 i->next = x;
00181 return root;
00182 }
00183
00196 scscf_entry* I_get_capab_ordered(str scscf_name,int *m,int mcnt,int *o,int ocnt, str *p, int pcnt,int orig)
00197 {
00198 scscf_entry *list=0;
00199 int i,r;
00200
00201 if (scscf_name.len) list = I_add_to_scscf_list(list,scscf_name,MAXINT, orig);
00202
00203 for(i=0;i<pcnt;i++)
00204 list = I_add_to_scscf_list(list,p[i],MAXINT-i,orig);
00205
00206 for(i=0;i<SCSCF_Capabilities_cnt;i++){
00207 r = I_get_capab_match(SCSCF_Capabilities+i,m,mcnt,o,ocnt);
00208 if (r!=-1){
00209 list = I_add_to_scscf_list(list,SCSCF_Capabilities[i].scscf_name,r, orig);
00210 LOG(L_DBG,"DBG:"M_NAME":I_get_capab_ordered: <%.*s> Added to the list, orig=%d\n",
00211 SCSCF_Capabilities[i].scscf_name.len,SCSCF_Capabilities[i].scscf_name.s, orig);
00212 }
00213 }
00214 return list;
00215 }
00216
00217
00221 inline unsigned int get_call_id_hash(str callid,int hash_size)
00222 {
00223 #define h_inc h+=v^(v>>3)
00224 char* p;
00225 register unsigned v;
00226 register unsigned h;
00227
00228 h=0;
00229 for (p=callid.s; p<=(callid.s+callid.len-4); p+=4){
00230 v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
00231 h_inc;
00232 }
00233 v=0;
00234 for (;p<(callid.s+callid.len); p++) {
00235 v<<=8;
00236 v+=*p;
00237 }
00238 h_inc;
00239
00240 h=((h)+(h>>11))+((h>>13)+(h>>23));
00241 return (h)%hash_size;
00242 #undef h_inc
00243 }
00244
00248 int i_hash_table_init(int hash_size)
00249 {
00250 int i;
00251
00252 i_hash_size = hash_size;
00253 i_hash_table = shm_malloc(sizeof(i_hash_slot)*i_hash_size);
00254
00255 if (!i_hash_table) return 0;
00256
00257 memset(i_hash_table,0,sizeof(i_hash_slot)*i_hash_size);
00258
00259 for(i=0;i<i_hash_size;i++){
00260 i_hash_table[i].lock = lock_alloc();
00261 if (!i_hash_table[i].lock){
00262 LOG(L_ERR,"ERR:"M_NAME":i_hash_table_init(): Error creating lock\n");
00263 return 0;
00264 }
00265 i_hash_table[i].lock = lock_init(i_hash_table[i].lock);
00266 }
00267
00268 return 1;
00269 }
00270
00274 void i_hash_table_destroy()
00275 {
00276 int i;
00277 scscf_list *sl,*nsl;
00278 for(i=0;i<i_hash_size;i++){
00279 i_lock(i);
00280 sl = i_hash_table[i].head;
00281 while(sl){
00282 nsl = sl->next;
00283 free_scscf_list(sl);
00284 sl = nsl;
00285 }
00286 i_unlock(i);
00287 lock_dealloc(i_hash_table[i].lock);
00288 }
00289 shm_free(i_hash_table);
00290 }
00291
00295 inline void i_lock(unsigned int hash)
00296 {
00297
00298 lock_get(i_hash_table[(hash)].lock);
00299
00300 }
00301
00305 inline void i_unlock(unsigned int hash)
00306 {
00307 lock_release(i_hash_table[(hash)].lock);
00308
00309 }
00310
00311 scscf_entry* new_scscf_entry(str name, int score, int orig)
00312 {
00313 scscf_entry *x=0;
00314 x = shm_malloc(sizeof(scscf_entry));
00315 if (!x) {
00316 LOG(L_ERR,"ERR:"M_NAME":new_scscf_entry: Error allocating %d bytes\n",
00317 sizeof(scscf_entry));
00318 return 0;
00319 }
00320
00321 if (orig) x->scscf_name.s = shm_malloc(name.len+5);
00322 else x->scscf_name.s = shm_malloc(name.len);
00323 if (!x->scscf_name.s){
00324 LOG(L_ERR,"ERR:"M_NAME":new_scscf_entry: Error allocating %d bytes\n",
00325 orig?name.len+5:name.len);
00326 shm_free(x);
00327 return 0;
00328 }
00329 memcpy(x->scscf_name.s,name.s,name.len);
00330 x->scscf_name.len = name.len;
00331 if (orig) {
00332 memcpy(x->scscf_name.s+name.len, ";orig", 5);
00333 x->scscf_name.len += 5;
00334 }
00335
00336 LOG(L_INFO,"INFO:"M_NAME":new_scscf_entry: <%.*s>\n",x->scscf_name.len,x->scscf_name.s);
00337
00338 x->score = score;
00339 x->next = 0;
00340 return x;
00341 }
00342
00343
00344 scscf_list* new_scscf_list(str call_id,scscf_entry *sl)
00345 {
00346 scscf_list *l;
00347
00348 l = shm_malloc(sizeof(scscf_list));
00349 if (!l) {
00350 LOG(L_ERR,"ERR:"M_NAME":new_scscf_list(): Unable to alloc %d bytes\n",
00351 sizeof(scscf_list));
00352 goto error;
00353 }
00354 memset(l,0,sizeof(scscf_list));
00355
00356 STR_SHM_DUP(l->call_id,call_id,"shm");
00357 l->list = sl;
00358
00359 return l;
00360 error:
00361 out_of_memory:
00362 if (l){
00363 shm_free(l);
00364 }
00365 return 0;
00366 }
00367
00368 int add_scscf_list(str call_id,scscf_entry *sl)
00369 {
00370 scscf_list *l;
00371 unsigned int hash = get_call_id_hash(call_id,i_hash_size);
00372
00373 l = new_scscf_list(call_id,sl);
00374 if (!l) return 0;
00375
00376 i_lock(hash);
00377 l->prev = 0;
00378 l->next = i_hash_table[hash].head;
00379 if (l->next) l->next->prev = l;
00380 i_hash_table[hash].head = l;
00381 if (!i_hash_table[hash].tail) i_hash_table[hash].tail = l;
00382 i_unlock(hash);
00383
00384 return 1;
00385 }
00386
00387 int is_scscf_list(str call_id)
00388 {
00389 scscf_list *l=0;
00390 unsigned int hash = get_call_id_hash(call_id,i_hash_size);
00391
00392 i_lock(hash);
00393 l = i_hash_table[hash].head;
00394 while(l){
00395 if (l->call_id.len == call_id.len &&
00396 strncasecmp(l->call_id.s,call_id.s,call_id.len)==0) {
00397 i_unlock(hash);
00398 return 1;
00399 }
00400 l = l->next;
00401 }
00402 i_unlock(hash);
00403 return 0;
00404 }
00405
00412 str take_scscf_entry(str call_id)
00413 {
00414 str scscf={0,0};
00415 scscf_list *l=0;
00416 scscf_entry *sl;
00417 unsigned int hash = get_call_id_hash(call_id,i_hash_size);
00418
00419 i_lock(hash);
00420 l = i_hash_table[hash].head;
00421 while(l){
00422 if (l->call_id.len == call_id.len &&
00423 strncasecmp(l->call_id.s,call_id.s,call_id.len)==0) {
00424 if (l->list){
00425 scscf = l->list->scscf_name;
00426 sl = l->list->next;
00427 shm_free(l->list);
00428 l->list = sl;
00429 }
00430 break;
00431 }
00432 l = l->next;
00433 }
00434 i_unlock(hash);
00435 return scscf;
00436 }
00437
00438 void del_scscf_list(str call_id)
00439 {
00440 scscf_list *l=0;
00441 unsigned int hash = get_call_id_hash(call_id,i_hash_size);
00442
00443 i_lock(hash);
00444 l = i_hash_table[hash].head;
00445 while(l){
00446 if (l->call_id.len == call_id.len &&
00447 strncasecmp(l->call_id.s,call_id.s,call_id.len)==0) {
00448 if (l->prev) l->prev->next = l->next;
00449 else i_hash_table[hash].head = l->next;
00450 if (l->next) l->next->prev = l->prev;
00451 else i_hash_table[hash].tail = l->prev;
00452 i_unlock(hash);
00453 free_scscf_list(l);
00454 return;
00455 }
00456 l = l->next;
00457 }
00458 i_unlock(hash);
00459 }
00460
00461 void free_scscf_list(scscf_list *sl)
00462 {
00463 scscf_entry *i;
00464 if (!sl) return;
00465 if (sl->call_id.s) shm_free(sl->call_id.s);
00466 while (sl->list) {
00467 i = sl->list->next;
00468 if (sl->list->scscf_name.s) shm_free(sl->list->scscf_name.s);
00469 shm_free(sl->list);
00470 sl->list = i;
00471 }
00472 shm_free(sl);
00473 }
00474
00475 void print_scscf_list(int log_level)
00476 {
00477 scscf_list *l;
00478 int i;
00479 scscf_entry *sl;
00480 LOG(log_level,"INF:"M_NAME":---------- S-CSCF Lists begin --------------\n");
00481 for(i=0;i<i_hash_size;i++){
00482 i_lock(i);
00483 l = i_hash_table[i].head;
00484 while(l){
00485 LOG(log_level,"INF:"M_NAME":[%4d] Call-ID: <%.*s> \n",i,
00486 l->call_id.len,l->call_id.s);
00487 sl = l->list;
00488 while(sl){
00489 LOG(log_level,"INF:"M_NAME": Score:[%4d] S-CSCF: <%.*s> \n",
00490 sl->score,
00491 sl->scscf_name.len,sl->scscf_name.s);
00492 sl = sl->next;
00493 }
00494 l = l->next;
00495 }
00496 i_unlock(i);
00497 }
00498 LOG(log_level,"INF:"M_NAME":---------- S-CSCF Lists end --------------\n");
00499
00500 }
00501
00502 int I_trans_in_processing(struct sip_msg* msg, char* str1, char* str2)
00503 {
00504 unsigned int hash, label;
00505 if (tmb.t_get_trans_ident(msg,&hash,&label)<0)
00506 return CSCF_RETURN_FALSE;
00507 return CSCF_RETURN_TRUE;
00508 }
00509
00510 static str route_hdr_s={"Route: <",8};
00511 static str route_hdr_e={">\r\n",3};
00512
00513 int I_scscf_select(struct sip_msg* msg, char* str1, char* str2)
00514 {
00515 str call_id,scscf_name={0,0};
00516 struct sip_msg *req;
00517 int result;
00518 str hdr={0,0};
00519
00520
00521
00522 call_id = cscf_get_call_id(msg,0);
00523 LOG(L_DBG,"DBG:"M_NAME":I_scscf_select(): <%.*s>\n",call_id.len,call_id.s);
00524 if (!call_id.len)
00525 return CSCF_RETURN_FALSE;
00526
00527 scscf_name = take_scscf_entry(call_id);
00528 if (!scscf_name.len){
00529 I_scscf_drop(msg,str1,str2);
00530 cscf_reply_transactional(msg,600,MSG_600_FORWARDING_FAILED);
00531 return CSCF_RETURN_BREAK;
00532 }
00533
00534 if (msg->first_line.u.request.method.len==8 &&
00535 strncasecmp(msg->first_line.u.request.method.s,"REGISTER",8)==0) {
00536
00537 if (str1&&str1[0]=='0'){
00538
00539
00540 if (rewrite_uri(msg, &(scscf_name)) < 0) {
00541 LOG(L_ERR,"ERR:"M_NAME":I_UAR_forward: Unable to Rewrite URI\n");
00542 result = CSCF_RETURN_FALSE;
00543 }else
00544 result = CSCF_RETURN_TRUE;
00545 }else{
00546
00547
00548 req = msg;
00549 append_branch(req,scscf_name.s,scscf_name.len,0,0,0,0);
00550 result = CSCF_RETURN_TRUE;
00551 }
00552 }else{
00553
00554 result = CSCF_RETURN_TRUE;
00555
00556 hdr.len = route_hdr_s.len+scscf_name.len+route_hdr_e.len;
00557 hdr.s = pkg_malloc(hdr.len);
00558 if (!hdr.s){
00559 LOG(L_ERR,"ERR:"M_NAME":Mw_REQUEST_forward: Error allocating %d bytes\n",
00560 hdr.len);
00561 result = CSCF_RETURN_TRUE;
00562 }
00563 hdr.len=0;
00564 STR_APPEND(hdr,route_hdr_s);
00565 STR_APPEND(hdr,scscf_name);
00566 STR_APPEND(hdr,route_hdr_e);
00567
00568 if (!cscf_add_header_first(msg,&hdr,HDR_ROUTE_T)){
00569 pkg_free(hdr.s);
00570 result = CSCF_RETURN_TRUE;
00571 }
00572
00573 if (msg->dst_uri.s) pkg_free(msg->dst_uri.s);
00574 STR_PKG_DUP(msg->dst_uri,scscf_name,"pkg");
00575 }
00576
00577 if (scscf_name.s) shm_free(scscf_name.s);
00578 return result;
00579 out_of_memory:
00580 if (scscf_name.s) shm_free(scscf_name.s);
00581 return CSCF_RETURN_ERROR;
00582 }
00583
00584 int I_scscf_drop(struct sip_msg* msg, char* str1, char* str2)
00585 {
00586 str call_id;
00587
00588 call_id = cscf_get_call_id(msg,0);
00589 LOG(L_DBG,"DBG:"M_NAME":I_scscf_drop(): <%.*s>\n",call_id.len,call_id.s);
00590 if (!call_id.len)
00591 return CSCF_RETURN_FALSE;
00592
00593 del_scscf_list(call_id);
00594 return CSCF_RETURN_TRUE;
00595 }
00596