00001
00055 #include <stdio.h>
00056 #include <string.h>
00057 #include <sys/stat.h>
00058 #include <unistd.h>
00059 #include <fcntl.h>
00060 #include <signal.h>
00061
00062 #include "mod.h"
00063 #include "../tm/tm_load.h"
00064 #include "../scscf/scscf_load.h"
00065
00066 #include "sip.h"
00067 #include "checker.h"
00068 #include "mark.h"
00069 #include "isc.h"
00070 #include "third_party_reg.h"
00071 #include "ims_pm.h"
00072 #include "../../dset.h"
00073
00074 MODULE_VERSION
00075
00076 static int isc_init( void );
00077 static int isc_child_init( int rank );
00078 static int isc_destroy( void );
00079
00080 int isc_appserver_forward(struct sip_msg *msg,char *str1,char *str2 );
00081
00082 int ISC_match_filter(struct sip_msg *msg,char *str1,char *str2);
00083 int ISC_match_filter_reg(struct sip_msg *msg,char *str1,char *str2);
00084 int ISC_from_AS(struct sip_msg *msg,char *str1,char *str2);
00085 int ISC_is_session_continued(struct sip_msg *msg,char *str1,char *str2);
00086
00091 char *isc_my_uri_c = "scscf.open-ims.test:6060";
00092 str isc_my_uri={0,0};
00093 str isc_my_uri_sip={0,0};
00094 int isc_fr_timeout=5000;
00095 int isc_fr_inv_timeout=20000;
00096 int isc_expires_grace=120;
00099 #ifdef WITH_IMS_PM
00100
00101 char* ims_pm_node_type="S-CSCF.ISC";
00102 char* ims_pm_logfile="/opt/OpenIMSCore/default_ims_pm.log";
00103 #endif
00104
00105
00110 struct tm_binds isc_tmb;
00111 struct scscf_binds isc_scscfb;
00125 static cmd_export_t isc_cmds[] = {
00126 {"isc_appserver_forward", isc_appserver_forward, 2, 0, REQUEST_ROUTE},
00127
00128 {"ISC_match_filter", ISC_match_filter, 1, 0, REQUEST_ROUTE|FAILURE_ROUTE},
00129 {"ISC_match_filter_reg", ISC_match_filter_reg, 1, 0, REQUEST_ROUTE},
00130 {"ISC_from_AS", ISC_from_AS, 1, 0, REQUEST_ROUTE|FAILURE_ROUTE},
00131 {"ISC_is_session_continued",ISC_is_session_continued, 0, 0, FAILURE_ROUTE},
00132
00133 { 0, 0, 0, 0, 0 }
00134 };
00135
00136
00144 static param_export_t isc_params[] = {
00145 {"my_uri", STR_PARAM, &isc_my_uri_c},
00147 {"isc_fr_timeout", INT_PARAM, &isc_fr_timeout},
00151 {"isc_fr_inv_timeout", INT_PARAM, &isc_fr_timeout},
00155 {"expires_grace", INT_PARAM, & isc_expires_grace},
00157 #ifdef WITH_IMS_PM
00158 {"ims_pm_node_type", STR_PARAM, &ims_pm_node_type},
00159 {"ims_pm_logfile", STR_PARAM, &ims_pm_logfile},
00160 #endif
00161
00162 { 0, 0, 0 }
00163 };
00164
00165
00169 struct module_exports exports = {
00170 "isc",
00171 isc_cmds,
00172 0,
00173 isc_params,
00174 isc_init,
00175 (response_function) 0,
00176 (destroy_function) isc_destroy,
00177 0,
00178 (child_init_function) isc_child_init
00179 };
00180
00181
00182
00183
00188 static int isc_init( void )
00189 {
00190 load_tm_f load_tm;
00191 load_scscf_f load_scscf;
00192 LOG( L_INFO, "INFO:"M_NAME": - init\n" );
00193
00194
00195 if (!(load_tm = (load_tm_f)find_export("load_tm",NO_SCRIPT,0))) {
00196 LOG(L_ERR,"ERROR:"M_NAME":isc_init: cannot import load_tm\n");
00197 goto error;
00198 }
00199
00200 if (load_tm(&isc_tmb) == -1)
00201 goto error;
00202
00203
00204 if (!(load_scscf = (load_scscf_f)find_export("load_scscf",NO_SCRIPT,0))) {
00205 LOG(L_ERR,"ERROR:"M_NAME":isc_init: cannot import load_scscf\n");
00206 goto error;
00207 }
00208
00209 if (load_scscf(&isc_scscfb) == -1)
00210 goto error;
00211
00212
00213 if (!isc_my_uri_c) {
00214 LOG( L_CRIT, "ERROR:"M_NAME":isc_init: mandatory parameter \"isc_my_uri\" found empty\n" );
00215 goto error;
00216 }
00217 isc_my_uri.s = isc_my_uri_c;
00218 isc_my_uri.len = strlen(isc_my_uri_c);
00219 isc_my_uri_sip.len = 4+isc_my_uri.len;
00220 isc_my_uri_sip.s = shm_malloc(isc_my_uri_sip.len+1);
00221 memcpy(isc_my_uri_sip.s,"sip:",4);
00222 memcpy(isc_my_uri_sip.s+4,isc_my_uri.s,isc_my_uri.len);
00223 isc_my_uri_sip.s[isc_my_uri_sip.len]=0;
00224
00225 #ifdef WITH_IMS_PM
00226 ims_pm_init(isc_my_uri_sip,ims_pm_node_type, ims_pm_logfile);
00227 #endif
00228
00229 return 0;
00230 error:
00231 return -1;
00232 }
00233
00234
00239 static int isc_child_init( int rank )
00240 {
00241 LOG( L_INFO, "INFO:"M_NAME": - child init [%d]\n", rank );
00242
00243
00244 if ( rank == PROC_MAIN || rank == PROC_TCP_MAIN )
00245 return 0;
00246
00247
00248 return 0;
00249 }
00250
00251
00256 static int isc_destroy( void )
00257 {
00258 LOG( L_INFO, "INFO:"M_NAME": - child exit\n" );
00259
00260 #ifdef WITH_IMS_PM
00261 ims_pm_destroy();
00262 #endif
00263 return 0;
00264 }
00265
00266
00267
00268
00269
00270
00281 int isc_appserver_forward(struct sip_msg *msg,char *str1,char *str2 )
00282 {
00283 struct hdr_field *last,*hdr;
00284 struct lump* anchor;
00285 str header_mark;
00286 rr_t *rr;
00287
00288 LOG(L_DBG,"DEBUG:"M_NAME":isc_appserver_forward: Forward-back request reached\n");
00289 parse_headers(msg,HDR_EOH_F,0);
00290 last = msg->headers;
00291 while(last->next)
00292 last = last->next;
00293
00294 LOG(L_INFO,"INFO:"M_NAME":isc_appserver_forward: New header: [%s]\n%.*s",str2,msg->len,msg->buf);
00295
00296
00297
00298 if (strlen(str2)){
00299
00300 header_mark.s = pkg_malloc(256);
00301 sprintf(header_mark.s,"%.*s\n",strlen(str2),str2);
00302 header_mark.len =strlen(header_mark.s);
00303
00304 anchor = anchor_lump(msg, last->name.s + last->len - msg->buf, 0 , 0);
00305 if (anchor == NULL) {
00306 LOG(L_ERR, "ERROR:"M_NAME":isc_appserver_forward: anchor_lump failed\n");
00307 }
00308
00309 if (!insert_new_lump_before(anchor, header_mark.s,header_mark.len,0)){
00310 LOG( L_ERR, "ERROR:"M_NAME":isc_appserver_forward: error creting lump for header_mark\n" );
00311 }
00312
00313 }
00314 LOG(L_ERR, "INFO:"M_NAME":isc_appserver_forward: Searching Route header to rewrite\n");
00315
00316 hdr = msg->headers;
00317 while(hdr){
00318 if (hdr->type == HDR_ROUTE_T){
00319 if (!hdr->parsed){
00320 if (parse_rr(hdr) < 0) {
00321 LOG(L_ERR, "ERROR:"M_NAME":isc_appserver_forward: Error while parsing Route HF\n");
00322 continue;
00323 }
00324 }
00325 rr = (rr_t*)hdr->parsed;
00326 while(rr){
00327 if (rr->nameaddr.uri.len >= ISC_MARK_USERNAME_LEN &&
00328 strncasecmp(rr->nameaddr.uri.s,ISC_MARK_USERNAME,ISC_MARK_USERNAME_LEN)==0) {
00329 LOG(L_INFO,"DEBUG:"M_NAME":isc_appserver_forward: Found S-CSCF marking <%.*s> \n",rr->nameaddr.uri.len,rr->nameaddr.uri.s);
00330
00331 if (!del_lump(msg, hdr->name.s - msg->buf, hdr->len, 0)) {
00332 LOG(L_ERR, "ERROR:"M_NAME":isc_appserver_forward: Can't remove Route HF\n");
00333 }
00334
00335
00336 anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0 , 0);
00337 header_mark.s = pkg_malloc(256);
00338 sprintf(header_mark.s,"Route: <%.*s>\n",rr->nameaddr.uri.len,rr->nameaddr.uri.s);
00339 header_mark.len =strlen(header_mark.s);
00340 if (!insert_new_lump_before(anchor, header_mark.s,header_mark.len,0)){
00341 LOG( L_ERR, "ERROR:"M_NAME":isc_appserver_forward: error creting lump for route header\n" );
00342 }
00343
00344 msg->dst_uri.s = pkg_malloc(rr->nameaddr.uri.len);
00345 memcpy(msg->dst_uri.s,rr->nameaddr.uri.s,rr->nameaddr.uri.len);
00346 msg->dst_uri.len=rr->nameaddr.uri.len;
00347 isc_tmb.t_relay(msg,0,0);
00348 return 0;
00349 }
00350 rr = rr->next;
00351 }
00352 }
00353 hdr = hdr->next;
00354 }
00355
00356
00357 msg->dst_uri.len = strlen(str1);
00358 msg->dst_uri.s = str1;
00359 isc_tmb.t_relay(msg,0,0);
00360 LOG(L_DBG,"DEBUG:"M_NAME":isc_appserver_forward: Mirror request finished\n");
00361 return 0;
00362 }
00363
00364
00371 static inline enum dialog_direction get_dialog_direction(char *direction)
00372 {
00373 switch(direction[0]){
00374 case 'o':
00375 case 'O':
00376 case '0':
00377 return DLG_MOBILE_ORIGINATING;
00378 case 't':
00379 case 'T':
00380 case '1':
00381 return DLG_MOBILE_TERMINATING;
00382 default:
00383 LOG(L_ERR,"ERR:"M_NAME":get_dialog_direction(): Unknown direction %s",direction);
00384 return DLG_MOBILE_UNKNOWN;
00385 }
00386 }
00387
00388
00397 int ISC_match_filter(struct sip_msg *msg,char *str1,char *str2)
00398 {
00399 int k = 0;
00400 isc_match *m = NULL;
00401 str s={0,0};
00402 int ret = ISC_RETURN_FALSE;
00403 isc_mark new_mark,old_mark;
00404
00405 enum dialog_direction dir = get_dialog_direction(str1);
00406
00407 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Checking triggers\n",str1);
00408
00409 if (dir==DLG_MOBILE_UNKNOWN)
00410 return ISC_RETURN_BREAK;
00411
00412 if (!isc_is_initial_request(msg)) return ISC_RETURN_FALSE;
00413
00414
00415 memset(&old_mark,0,sizeof(isc_mark));
00416 memset(&new_mark,0,sizeof(isc_mark));
00417 if (isc_mark_get_from_msg(msg,&old_mark)){
00418 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Message returned s=%d;h=%d;d=%d;a=%.*s\n",
00419 str1,old_mark.skip,old_mark.handling,old_mark.direction,old_mark.aor.len,old_mark.aor.s);
00420 }
00421 else {
00422 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Starting triggering\n",str1);
00423 }
00424
00425
00426 if (*isc_tmb.route_mode==MODE_ONFAILURE) {
00427 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): failure\n",str1);
00428
00429
00430 if (dir==DLG_MOBILE_ORIGINATING){
00431 k = isc_get_originating_user(msg,&old_mark,&s);
00432 if (k){
00433 k = isc_is_registered(&s);
00434 if (k==NOT_REGISTERED) {
00435 ret = ISC_MSG_NOT_FORWARDED;
00436 goto done;
00437 }
00438 new_mark.direction = IFC_ORIGINATING_SESSION;
00439 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Orig User <%.*s> [%d]\n",str1,
00440 s.len,s.s,k);
00441 } else goto done;
00442 }
00443 if (dir==DLG_MOBILE_TERMINATING){
00444 k = isc_get_terminating_user(msg,&old_mark,&s);
00445 if (k){
00446 k = isc_is_registered(&s);
00447
00448 if (k==REGISTERED) {
00449 new_mark.direction = IFC_TERMINATING_SESSION;
00450 } else {
00451 new_mark.direction = IFC_TERMINATING_UNREGISTERED;
00452 }
00453 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Term User <%.*s> [%d]\n",str1,
00454 s.len,s.s,k);
00455 } else {
00456 goto done;
00457 }
00458 }
00459 struct cell * t = isc_tmb.t_gett();
00460 LOG(L_CRIT,"SKIP: %d\n",old_mark.skip);
00461 int index = old_mark.skip;
00462 for (k=0;k<t->nr_of_outgoings;k++) {
00463 m = isc_checker_find(s,new_mark.direction,index,msg,isc_is_registered(&s));
00464 if (m) {
00465 index = m->index;
00466 if (k < t->nr_of_outgoings - 1) isc_free_match(m);
00467 } else {
00468 LOG(L_ERR,"ERR:"M_NAME":ISC_match_filter(%s): On failure, previously matched trigger no longer matches?!\n", str1);
00469 ret = ISC_RETURN_BREAK;
00470 goto done;
00471 }
00472 }
00473 if (m->default_handling==IFC_SESSION_TERMINATED) {
00474
00475 DBG("DEBUG:"M_NAME":ISC_match_filter(%s): Terminating session.\n", str1);
00476 isc_tmb.t_reply(msg,IFC_AS_UNAVAILABLE_STATUS_CODE,
00477 "AS Contacting Failed - iFC terminated dialog");
00478 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Responding with %d "
00479 "to URI: %.*s\n",str1, IFC_AS_UNAVAILABLE_STATUS_CODE,
00480 msg->first_line.u.request.uri.len,
00481 msg->first_line.u.request.uri.s);
00482 isc_free_match(m);
00483 ret = ISC_RETURN_BREAK;
00484 goto done;
00485 }
00486
00487
00488 old_mark.skip = index + 1;
00489
00490 isc_free_match(m);
00491 isc_mark_drop_route(msg);
00492 }
00493
00494
00495 if (dir==DLG_MOBILE_ORIGINATING){
00496 k = isc_get_originating_user(msg,&old_mark,&s);
00497 if (k){
00498 k = isc_is_registered(&s);
00499 if (k==NOT_REGISTERED) return ISC_MSG_NOT_FORWARDED;
00500
00501 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Orig User <%.*s> [%d]\n",str1,
00502 s.len,s.s,k);
00503 m = isc_checker_find(s,old_mark.direction,old_mark.skip,msg,isc_is_registered(&s));
00504 if (m){
00505 new_mark.direction = IFC_ORIGINATING_SESSION;
00506 new_mark.skip = m->index+1;
00507 new_mark.handling = m->default_handling;
00508 new_mark.aor = s;
00509 ret = isc_forward(msg,m,&new_mark);
00510 isc_free_match(m);
00511 goto done;
00512 }
00513 }
00514 goto done;
00515 }
00516
00517
00518 if (dir==DLG_MOBILE_TERMINATING){
00519 k = isc_get_terminating_user(msg,&old_mark,&s);
00520 if (k){
00521 k = isc_is_registered(&s);
00522 if (k==REGISTERED) {
00523 new_mark.direction = IFC_TERMINATING_SESSION;
00524 } else {
00525 new_mark.direction = IFC_TERMINATING_UNREGISTERED;
00526 }
00527 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter(%s): Term User <%.*s> [%d]\n",str1,
00528 s.len,s.s,k);
00529
00530 m = isc_checker_find(s,new_mark.direction,old_mark.skip,msg,isc_is_registered(&s));
00531 if (m){
00532 new_mark.skip = m->index+1;
00533 new_mark.handling = m->default_handling;
00534 new_mark.aor = s;
00535 ret = isc_forward(msg,m,&new_mark);
00536 isc_free_match(m);
00537 goto done;
00538 }
00539 }
00540 goto done;
00541 }
00542
00543 done:
00544 if (old_mark.aor.s) pkg_free(old_mark.aor.s);
00545 return ret;
00546 }
00547
00556 int ISC_match_filter_reg(struct sip_msg *msg,char *str1,char *str2)
00557 {
00558 int k;
00559 isc_match *m;
00560 str s={0,0};
00561 int ret = ISC_RETURN_FALSE;
00562 isc_mark old_mark;
00563
00564 enum dialog_direction dir = DLG_MOBILE_ORIGINATING;
00565
00566 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter_reg(): Checking triggers\n");
00567
00568 if (!isc_is_register(msg)) return ISC_RETURN_FALSE;
00569
00570
00571 memset(&old_mark,0,sizeof(isc_mark));
00572 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter_reg(): Starting triggering\n");
00573
00574
00575
00576 if (dir==DLG_MOBILE_ORIGINATING){
00577 k = isc_get_originating_user(msg,&old_mark,&s);
00578 if (k){
00579 if (str1==0||strlen(str1)!=1){
00580 LOG(L_ERR,"ERR:"M_NAME":ISC_match_filter_reg(): wrong parameter - must be \"0\" (initial registration) or \"1\"(previously registered) \n");
00581 return ret;
00582 }else
00583 if (str1[0]=='0') k = 0;
00584 else k=1;
00585
00586 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter_reg(): Orig User <%.*s> [%d]\n",s.len,s.s,k);
00587 m = isc_checker_find(s,old_mark.direction,old_mark.skip,msg,k);
00588 while (m){
00589 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter_reg(): REGISTER match found in filter criteria\n");
00590 ret = isc_third_party_reg(msg,m,&old_mark);
00591 old_mark.skip = m->index+1;
00592 isc_free_match(m);
00593 m = isc_checker_find(s,old_mark.direction,old_mark.skip,msg,k);
00594 }
00595
00596 if(ret == ISC_RETURN_FALSE)
00597 LOG(L_INFO,"INFO:"M_NAME":ISC_match_filter_reg(): No REGISTER match found in filter criteria\n");
00598 }
00599 }
00600 return ret;
00601 }
00602
00611 int ISC_from_AS(struct sip_msg *msg,char *str1,char *str2)
00612 {
00613 int ret = ISC_RETURN_FALSE;
00614 isc_mark old_mark;
00615
00616 enum dialog_direction dir = get_dialog_direction(str1);
00617
00618 if (dir==DLG_MOBILE_UNKNOWN)
00619 return ISC_RETURN_BREAK;
00620
00621 if (!isc_is_initial_request(msg)) return ISC_RETURN_FALSE;
00622
00623
00624 if (isc_mark_get_from_msg(msg,&old_mark)){
00625 LOG(L_INFO,"INFO:"M_NAME":ISC_from_AS(%s): Message returned s=%d;h=%d;d=%d\n",
00626 str1,old_mark.skip,old_mark.handling,old_mark.direction);
00627 if (old_mark.direction==IFC_ORIGINATING_SESSION && dir!=DLG_MOBILE_ORIGINATING)
00628 ret = ISC_RETURN_FALSE;
00629 else
00630 if ((old_mark.direction==IFC_TERMINATING_SESSION||old_mark.direction==IFC_TERMINATING_UNREGISTERED)
00631 && dir!=DLG_MOBILE_TERMINATING)
00632 ret = ISC_RETURN_FALSE;
00633 else
00634 ret = ISC_RETURN_TRUE;
00635 } else {
00636 ret = ISC_RETURN_FALSE;
00637 }
00638 return ret;
00639 }
00640
00649 int ISC_is_session_continued(struct sip_msg *msg,char *str1,char *str2)
00650 {
00651 int ret = ISC_RETURN_FALSE;
00652 isc_mark old_mark;
00653 struct sip_msg *req;
00654
00655 req = cscf_get_request_from_reply(msg);
00656
00657 if (!req) {
00658 LOG(L_ERR,"ERR:"M_NAME":ISC_is_session_continued(): There is no transaction \n");
00659 return ISC_RETURN_FALSE;
00660 }
00661
00662 if (!isc_is_initial_request(req)) {
00663 LOG(L_ERR,"ERR:"M_NAME":ISC_is_session_continued(): This is no initial request \n");
00664 return ISC_RETURN_FALSE;
00665 }
00666
00667
00668 if (isc_mark_get_from_lump(req,&old_mark)){
00669 LOG(L_INFO,"INFO:"M_NAME":ISC_is_session_continued(): Message returned handling [%d] \n",old_mark.handling);
00670 if (old_mark.handling == IFC_SESSION_CONTINUED)
00671 ret = ISC_RETURN_TRUE;
00672 else
00673 ret = ISC_RETURN_FALSE;
00674 } else {
00675 LOG(L_ERR,"ERR:"M_NAME":ISC_is_session_continued(): mark not found in lump \n");
00676 ret = ISC_RETURN_ERROR;
00677 }
00678 return ret;
00679 }
00680