Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

cpl.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cpl.c,v 1.66 2009/09/03 09:56:18 tirpi Exp $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  *
00027  * History:
00028  * -------
00029  * 2003-03-11: New module interface (janakj)
00030  * 2003-03-16: flags export parameter added (janakj)
00031  * 2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan)
00032  * 2004-06-06  updated to the new DB api (andrei)
00033  * 2004-06-14: all global variables merged into cpl_env and cpl_fct;
00034  *             case_sensitive and realm_prefix added for building AORs - see
00035  *             build_userhost (bogdan)
00036  * 2004-10-09: added process_register_norpl to allow register processing
00037  *             without sending the reply(bogdan) - based on a patch sent by
00038  *             Christopher Crawford
00039  */
00040 
00041 
00042 #include <stdio.h>
00043 #include <string.h>
00044 #include <sys/types.h>
00045 #include <sys/stat.h>
00046 #include <unistd.h>
00047 #include <fcntl.h>
00048 #include <signal.h>
00049 
00050 #include "../../mem/shm_mem.h"
00051 #include "../../mem/mem.h"
00052 #include "../../sr_module.h"
00053 #include "../../str.h"
00054 #include "../../ut.h"
00055 #include "../../dprint.h"
00056 #include "../../data_lump_rpl.h"
00057 #include "../../usr_avp.h"
00058 #include "../../parser/parse_uri.h"
00059 #include "../../parser/parse_from.h"
00060 #include "../../parser/parse_content.h"
00061 #include "../../parser/parse_disposition.h"
00062 #include "../../db/db.h"
00063 #include "../../cfg/cfg_struct.h"
00064 #include "cpl_run.h"
00065 #include "cpl_env.h"
00066 #include "cpl_db.h"
00067 #include "cpl_loader.h"
00068 #include "cpl_parser.h"
00069 #include "cpl_nonsig.h"
00070 #include "cpl_rpc.h"
00071 #include "loc_set.h"
00072 
00073 
00074 #define MAX_PROXY_RECURSE  10
00075 #define MAX_USERHOST_LEN    256
00076 
00077 
00078 /* modules param variables */
00079 static char *DB_URL        = 0;  /* database url */
00080 static char *DB_TABLE      = 0;  /* */
00081 static char *dtd_file      = 0;  /* name of the DTD file for CPL parser */
00082 static char *lookup_domain = 0;
00083 static pid_t aux_process   = 0;  /* pid of the private aux. process */
00084 static char *timer_avp     = 0;  /* name of variable timer AVP */
00085 
00086 
00087 struct cpl_enviroment    cpl_env = {
00088                 0, /* no cpl logging */
00089                 0, /* recurse proxy level is 0 */
00090                 0, /* no script route to be run before proxy */
00091                 6, /* nat flag */
00092                 0, /* user part is not case sensitive */
00093                 {0,0},   /* no domain prefix to be ignored */
00094                 {-1,-1}, /* communication pipe to aux_process */
00095                 {0,0},   /* original TZ \0 terminated "TZ=value" format */
00096                 0, /* udomain */
00097                 0, /* no branches on lookup */
00098                 0, /* timer avp type */
00099                 /*(int_str)*/{ 0 } /* timer avp name/ID */
00100 };
00101 
00102 struct cpl_functions  cpl_fct;
00103 
00104 
00105 MODULE_VERSION
00106 
00107 
00108 static int cpl_invoke_script (struct sip_msg* msg, char* str, char* str2);
00109 static int w_process_register(struct sip_msg* msg, char* str, char* str2);
00110 static int w_process_register_norpl(struct sip_msg* msg, char* str,char* str2);
00111 static int cpl_process_register(struct sip_msg* msg, int no_rpl);
00112 static int fixup_cpl_run_script(void** param, int param_no);
00113 static int cpl_init(void);
00114 static int cpl_child_init(int rank);
00115 static int cpl_exit(void);
00116 
00117 
00118 /*
00119  * Exported functions
00120  */
00121 static cmd_export_t cmds[] = {
00122         {"cpl_run_script",cpl_invoke_script,2,fixup_cpl_run_script,REQUEST_ROUTE},
00123         {"cpl_process_register",w_process_register,0,0,REQUEST_ROUTE},
00124         {"cpl_process_register_norpl",w_process_register_norpl,0,0,REQUEST_ROUTE},
00125         {0, 0, 0, 0, 0}
00126 };
00127 
00128 
00129 /*
00130  * Exported parameters
00131  */
00132 static param_export_t params[] = {
00133         {"cpl_db",         PARAM_STRING, &DB_URL      },
00134         {"cpl_table",      PARAM_STRING, &DB_TABLE    },
00135         {"cpl_dtd_file",   PARAM_STRING, &dtd_file    },
00136         {"proxy_recurse",  PARAM_INT,    &cpl_env.proxy_recurse  },
00137         {"proxy_route",    PARAM_INT,    &cpl_env.proxy_route    },
00138         {"nat_flag",       PARAM_INT,    &cpl_env.nat_flag       },
00139         {"log_dir",        PARAM_STRING, &cpl_env.log_dir        },
00140         {"case_sensitive", PARAM_INT,    &cpl_env.case_sensitive },
00141         {"realm_prefix",   PARAM_STR,    &cpl_env.realm_prefix   },
00142         {"lookup_domain",  PARAM_STRING, &lookup_domain          },
00143         {"lookup_append_branches", PARAM_INT, &cpl_env.lu_append_branches},
00144         {"timer_avp",      PARAM_STRING, &timer_avp   },
00145         {0, 0, 0}
00146 };
00147 
00148 
00149 struct module_exports exports = {
00150         "cpl-c",
00151         cmds,             /* Exported functions */
00152         cpl_rpc_methods,  /* RPC methods */
00153         params,           /* Exported parameters */
00154         cpl_init,         /* Module initialization function */
00155         (response_function) 0,
00156         (destroy_function) cpl_exit,
00157         0,
00158         (child_init_function) cpl_child_init /* per-child init function */
00159 };
00160 
00161 
00162 
00163 static int fixup_cpl_run_script(void** param, int param_no)
00164 {
00165         long flag;
00166 
00167         if (param_no==1) {
00168                 if (!strcasecmp( "incoming", *param))
00169                         flag = CPL_RUN_INCOMING;
00170                 else if (!strcasecmp( "outgoing", *param))
00171                         flag = CPL_RUN_OUTGOING;
00172                 else {
00173                         LOG(L_ERR,"ERROR:fixup_cpl_run_script: script directive \"%s\""
00174                                 " unknown!\n",(char*)*param);
00175                         return E_UNSPEC;
00176                 }
00177                 pkg_free(*param);
00178                 *param=(void*)flag;
00179                 return 0;
00180         } else if (param_no==2) {
00181                 if ( !strcasecmp("is_stateless", *param) ) {
00182                         flag = 0;
00183                 } else if ( !strcasecmp("is_stateful", *param) ) {
00184                         flag = CPL_IS_STATEFUL;
00185                 } else if ( !strcasecmp("force_stateful", *param) ) {
00186                         flag = CPL_FORCE_STATEFUL;
00187                 } else {
00188                         LOG(L_ERR,"ERROR:fixup_cpl_run_script: flag \"%s\" (second param)"
00189                                 " unknown!\n",(char*)*param);
00190                         return E_UNSPEC;
00191                 }
00192                 pkg_free(*param);
00193                 *param=(void*)flag;
00194         }
00195         return 0;
00196 }
00197 
00198 
00199 
00200 static int cpl_init(void)
00201 {
00202         bind_usrloc_t bind_usrloc;
00203         bind_sl_t     bind_sl;
00204         load_tm_f     load_tm;
00205         struct stat   stat_t;
00206         char *ptr;
00207         int val;
00208         str foo;
00209 
00210         LOG(L_INFO,"CPL - initializing\n");
00211 
00212         /* check the module params */
00213         if (DB_URL==0) {
00214                 LOG(L_CRIT,"ERROR:cpl_init: mandatory parameter \"cpl_db\" "
00215                         "found empty\n");
00216                 goto error;
00217         }
00218 
00219         if (DB_TABLE==0) {
00220                 LOG(L_CRIT,"ERROR:cpl_init: mandatory parameter \"cpl_table\" "
00221                         "found empty\n");
00222                 goto error;
00223         }
00224 
00225         if (cpl_env.proxy_recurse>MAX_PROXY_RECURSE) {
00226                 LOG(L_CRIT,"ERROR:cpl_init: value of proxy_recurse param (%d) exceeds "
00227                         "the maximum safety value (%d)\n",
00228                         cpl_env.proxy_recurse,MAX_PROXY_RECURSE);
00229                 goto error;
00230         }
00231 
00232         /* fix the timer_avp name */
00233         if (timer_avp) {
00234                 foo.s = timer_avp;
00235                 foo.len = strlen(foo.s);
00236                 if (parse_avp_spec(&foo,&cpl_env.timer_avp_type,&cpl_env.timer_avp,0)<0){
00237                         LOG(L_CRIT,"ERROR:cpl_init: invalid timer AVP specs \"%s\"\n",
00238                                 timer_avp);
00239                         goto error;
00240                 }
00241                 if (cpl_env.timer_avp_type&AVP_NAME_STR && cpl_env.timer_avp.s.s==foo.s) {
00242                         cpl_env.timer_avp.s = foo;
00243                 }
00244         }
00245 
00246         if (dtd_file==0) {
00247                 LOG(L_CRIT,"ERROR:cpl_init: mandatory parameter \"cpl_dtd_file\" "
00248                         "found empty\n");
00249                 goto error;
00250         } else {
00251                 /* check if the dtd file exists */
00252                 if (stat( dtd_file, &stat_t)==-1) {
00253                         LOG(L_ERR,"ERROR:cpl_init: checking file \"%s\" status failed;"
00254                                 " stat returned %s\n",dtd_file,strerror(errno));
00255                         goto error;
00256                 }
00257                 if ( !S_ISREG( stat_t.st_mode ) ) {
00258                         LOG(L_ERR,"ERROR:cpl_init: dir \"%s\" is not a regular file!\n",
00259                                 dtd_file);
00260                         goto error;
00261                 }
00262                 if (access( dtd_file, R_OK )==-1) {
00263                         LOG(L_ERR,"ERROR:cpl_init: checking file \"%s\" for permissions "
00264                                 "failed; access returned %s\n",dtd_file,strerror(errno));
00265                         goto error;
00266                 }
00267         }
00268 
00269         if (cpl_env.log_dir==0) {
00270                 LOG(L_INFO,"INFO:cpl_init: log_dir param found void -> logging "
00271                         " disabled!\n");
00272         } else {
00273                 if ( strlen(cpl_env.log_dir)>MAX_LOG_DIR_SIZE ) {
00274                         LOG(L_ERR,"ERROR:cpl_init: dir \"%s\" has a too long name :-(!\n",
00275                                 cpl_env.log_dir);
00276                         goto error;
00277                 }
00278                 /* check if the dir exists */
00279                 if (stat( cpl_env.log_dir, &stat_t)==-1) {
00280                         LOG(L_ERR,"ERROR:cpl_init: checking dir \"%s\" status failed;"
00281                                 " stat returned %s\n",cpl_env.log_dir,strerror(errno));
00282                         goto error;
00283                 }
00284                 if ( !S_ISDIR( stat_t.st_mode ) ) {
00285                         LOG(L_ERR,"ERROR:cpl_init: dir \"%s\" is not a directory!\n",
00286                                 cpl_env.log_dir);
00287                         goto error;
00288                 }
00289                 if (access( cpl_env.log_dir, R_OK|W_OK )==-1) {
00290                         LOG(L_ERR,"ERROR:cpl_init: checking dir \"%s\" for permissions "
00291                                 "failed; access returned %s\n",
00292                                 cpl_env.log_dir, strerror(errno));
00293                         goto error;
00294                 }
00295         }
00296 
00297         /* import the TM auto-loading function */
00298         if ( !(load_tm=(load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) {
00299                 LOG(L_ERR, "ERROR:cpl_c:cpl_init: cannot import load_tm\n");
00300                 goto error;
00301         }
00302         /* let the auto-loading function load all TM stuff */
00303         if (load_tm( &(cpl_fct.tmb) )==-1)
00304                 goto error;
00305 
00306         bind_sl = (bind_sl_t)find_export("bind_sl", 0, 0);
00307         if (!bind_sl) {
00308                 ERR("This module requires sl module\n");
00309                 return -1;
00310         }
00311         if (bind_sl(&cpl_fct.sl) < 0) return -1;
00312 
00313         /* bind to usrloc module if requested */
00314         if (lookup_domain) {
00315                 /* import all usrloc functions */
00316                 bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
00317                 if (!bind_usrloc) {
00318                         LOG(L_ERR, "ERROR:cpl_c:cpl_init: Can't bind usrloc\n");
00319                         goto error;
00320                 }
00321                 if (bind_usrloc( &(cpl_fct.ulb) ) < 0) {
00322                         LOG(L_ERR, "ERROR:cpl_c:cpl_init: importing usrloc failed\n");
00323                         goto error;
00324                 }
00325                 /* convert lookup_domain from char* to udomain_t* pointer */
00326                 if (cpl_fct.ulb.register_udomain( lookup_domain, &cpl_env.lu_domain)
00327                 < 0) {
00328                         LOG(L_ERR, "ERROR:cpl_c:cpl_init: Error while registering domain "
00329                                 "<%s>\n",lookup_domain);
00330                         goto error;
00331                 }
00332         } else {
00333                 LOG(L_NOTICE,"NOTICE:cpl_init: no lookup_domain given -> disable "
00334                         " lookup node\n");
00335         }
00336 
00337         /* build a pipe for sending commands to aux process */
00338         if ( pipe( cpl_env.cmd_pipe )==-1 ) {
00339                 LOG(L_CRIT,"ERROR:cpl_init: cannot create command pipe: %s!\n",
00340                         strerror(errno) );
00341                 goto error;
00342         }
00343         /* set the writing non blocking */
00344         if ( (val=fcntl(cpl_env.cmd_pipe[1], F_GETFL, 0))<0 ) {
00345                 LOG(L_ERR,"ERROR:cpl_init: getting flags from pipe[1] failed: fcntl "
00346                         "said %s!\n",strerror(errno));
00347                 goto error;
00348         }
00349         if ( fcntl(cpl_env.cmd_pipe[1], F_SETFL, val|O_NONBLOCK) ) {
00350                 LOG(L_ERR,"ERROR:cpl_init: setting flags to pipe[1] failed: fcntl "
00351                         "said %s!\n",strerror(errno));
00352                 goto error;
00353         }
00354 
00355         /* init the CPL parser */
00356         if (init_CPL_parser( dtd_file )!=1 ) {
00357                 LOG(L_ERR,"ERROR:cpl_init: init_CPL_parser failed!\n");
00358                 goto error;
00359         }
00360 
00361         /* make a copy of the original TZ env. variable */
00362         ptr = getenv("TZ");
00363         cpl_env.orig_tz.len = 3/*"TZ="*/ + (ptr?(strlen(ptr)+1):0);
00364         if ( (cpl_env.orig_tz.s=shm_malloc( cpl_env.orig_tz.len ))==0 ) {
00365                 LOG(L_ERR,"ERROR:cpl_init: no more shm mem. for saving TZ!\n");
00366                 goto error;
00367         }
00368         memcpy(cpl_env.orig_tz.s,"TZ=",3);
00369         if (ptr)
00370                 strcpy(cpl_env.orig_tz.s+3,ptr);
00371 
00372         /* convert realm_prefix from string null terminated to str */
00373         if (cpl_env.realm_prefix.s) {
00374                 /* convert the realm_prefix to lower cases */
00375                 strlower( &cpl_env.realm_prefix );
00376         }
00377 
00378         /* Register a child process that will keep updating
00379          * its local configuration */
00380         cfg_register_child(1);
00381 
00382         return 0;
00383 error:
00384         return -1;
00385 }
00386 
00387 
00388 
00389 static int cpl_child_init(int rank)
00390 {
00391         pid_t pid;
00392 
00393         /* don't do anything for main process and TCP manager process */
00394         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00395                 return 0;
00396 
00397         /* only child 1 will fork the aux process */
00398         if (rank==1) {
00399                 pid = fork();
00400                 if (pid==-1) {
00401                         LOG(L_CRIT,"ERROR:cpl_child_init(%d): cannot fork: %s!\n",
00402                                 rank, strerror(errno));
00403                         goto error;
00404                 } else if (pid==0) {
00405                         /* I'm the child */
00406 
00407                         /* initialize the config framework */
00408                         if (cfg_child_init()) goto error;
00409 
00410                         cpl_aux_process( cpl_env.cmd_pipe[0], cpl_env.log_dir);
00411                 } else {
00412                         LOG(L_INFO,"INFO:cpl_child_init(%d): I just gave birth to a child!"
00413                                 " I'm a PARENT!!\n",rank);
00414                         /* I'm the parent -> remember the pid */
00415                         aux_process = pid;
00416                 }
00417         }
00418 
00419         return cpl_db_init(DB_URL, DB_TABLE);
00420 error:
00421         return -1;
00422 }
00423 
00424 
00425 
00426 static int cpl_exit(void)
00427 {
00428         /* free the TZ orig */
00429         if (cpl_env.orig_tz.s)
00430                 shm_free(cpl_env.orig_tz.s);
00431 
00432         /* if still running, stop the aux process */
00433         if (!aux_process) {
00434                 LOG(L_INFO,"INFO:cpl_c:cpl_exit: aux process hasn't been created -> "
00435                         "nothing to kill :-(\n");
00436         } else {
00437                 /* kill the auxiliary process */
00438                 if (kill( aux_process, SIGKILL)!=0) {
00439                         if (errno==ESRCH) {
00440                                 LOG(L_INFO,"INFO:cpl_c:cpl_exit: seems that my child is "
00441                                         "already dead! :-((\n");
00442                         } else {
00443                                 LOG(L_ERR,"ERROR:cpl_c:cpl_exit: killing the aux. process "
00444                                         "failed! kill said: %s\n",strerror(errno));
00445                                 return -1;
00446                         }
00447                 } else {
00448                         LOG(L_INFO,"INFO:cl_c:cpl_exit: I have blood on my hands!! I just"
00449                                 " killed my own child!");
00450                 }
00451         }
00452         return 0;
00453 }
00454 
00455 
00456 
00457 #define BUILD_UH_SHM      (1<<0)
00458 #define BUILD_UH_ADDSIP   (1<<1)
00459 
00460 static inline int build_userhost(struct sip_uri *uri, str *uh, int flg)
00461 {
00462         static char buf[MAX_USERHOST_LEN];
00463         unsigned char do_strip;
00464         char *p;
00465         int i;
00466 
00467         /* do we need to strip realm prefix? */
00468         do_strip = 0;
00469         if (cpl_env.realm_prefix.len && cpl_env.realm_prefix.len<uri->host.len) {
00470                 for( i=cpl_env.realm_prefix.len-1 ; i>=0 ; i-- )
00471                         if ( cpl_env.realm_prefix.s[i]!=((uri->host.s[i])|(0x20)) )
00472                                 break;
00473                 if (i==-1)
00474                         do_strip = 1;
00475         }
00476 
00477         /* calculate the len (without terminating \0) */
00478         uh->len = 4*((flg&BUILD_UH_ADDSIP)!=0) + uri->user.len + 1 +
00479                 uri->host.len - do_strip*cpl_env.realm_prefix.len;
00480         if (flg&BUILD_UH_SHM) {
00481                 uh->s = (char*)shm_malloc( uh->len + 1 );
00482                 if (!uh->s) {
00483                         LOG(L_ERR,"ERROR:cpl-c:build_userhost: no more shm memory.\n");
00484                         return -1;
00485                 }
00486         } else {
00487                 uh->s = buf;
00488                 if ( uh->len > MAX_USERHOST_LEN ) {
00489                         LOG(L_ERR,"ERROR:cpl-c:build_userhost: user+host longer than %d\n",
00490                                 MAX_USERHOST_LEN);
00491                         return -1;
00492                 }
00493         }
00494 
00495         /* build user@host */
00496         p = uh->s;
00497         if (flg&BUILD_UH_ADDSIP) {
00498                 memcpy( uh->s, "sip:", 4);
00499                 p += 4;
00500         }
00501         /* user part */
00502         if (cpl_env.case_sensitive) {
00503                 memcpy( p, uri->user.s, uri->user.len);
00504                 p += uri->user.len;
00505         } else {
00506                 for(i=0;i<uri->user.len;i++)
00507                         *(p++) = (0x20)|(uri->user.s[i]);
00508         }
00509         *(p++) = '@';
00510         /* host part in lower cases */
00511         for( i=do_strip*cpl_env.realm_prefix.len ; i< uri->host.len ; i++ )
00512                 *(p++) = (0x20)|(uri->host.s[i]);
00513         *(p++) = 0;
00514 
00515         /* sanity check */
00516         if (p-uh->s!=uh->len+1) {
00517                 LOG(L_CRIT,"BUG:cpl-c:build_userhost: buffer overflow l=%d,w=%ld\n",
00518                         uh->len,(long)(p-uh->s));
00519                 return -1;
00520         }
00521         return 0;
00522 }
00523 
00524 
00525 
00526 static inline int get_dest_user(struct sip_msg *msg, str *uh, int flg)
00527 {
00528         struct sip_uri uri;
00529 
00530         /*  get the user_name from new_uri/RURI/To */
00531         DBG("DEBUG:cpl-c:get_dest_user: trying to get user from new_uri\n");
00532         if ( !msg->new_uri.s || parse_uri( msg->new_uri.s,msg->new_uri.len,&uri)==-1
00533         || !uri.user.len )
00534         {
00535                 DBG("DEBUG:cpl-c:get_dest_user: trying to get user from R_uri\n");
00536                 if ( parse_uri( msg->first_line.u.request.uri.s,
00537                 msg->first_line.u.request.uri.len ,&uri)==-1 || !uri.user.len )
00538                 {
00539                         DBG("DEBUG:cpl-c:get_dest_user: trying to get user from To\n");
00540                         if ( (!msg->to&&( (parse_headers(msg,HDR_TO_F,0)==-1) ||
00541                                         !msg->to)) ||
00542                                 parse_uri( get_to(msg)->uri.s, get_to(msg)->uri.len, &uri)==-1
00543                                 || !uri.user.len)
00544                         {
00545                                 LOG(L_ERR,"ERROR:cpl-c:get_dest_user: unable to extract user"
00546                                         " name from RURI or To header!\n");
00547                                 return -1;
00548                         }
00549                 }
00550         }
00551         return build_userhost( &uri, uh, flg);
00552 }
00553 
00554 
00555 
00556 static inline int get_orig_user(struct sip_msg *msg, str *uh, int flg)
00557 {
00558         struct to_body *from;
00559         struct sip_uri uri;
00560 
00561         /* if it's outgoing -> get the user_name from From */
00562         /* parsing from header */
00563         DBG("DEBUG:cpl-c:get_orig_user: trying to get user from From\n");
00564         if ( parse_from_header( msg )==-1 ) {
00565                 LOG(L_ERR,"ERROR:cpl-c:get_orig_user: unable to extract URI "
00566                         "from FROM header\n");
00567                 return -1;
00568         }
00569         from = (struct to_body*)msg->from->parsed;
00570         /* parse the extracted uri from From */
00571         if (parse_uri( from->uri.s, from->uri.len, &uri)||!uri.user.len) {
00572                 LOG(L_ERR,"ERROR:cpl-c:get_orig_user: unable to extract user name "
00573                         "from URI (From header)\n");
00574                 return -1;
00575         }
00576         return build_userhost( &uri, uh, flg);
00577 }
00578 
00579 
00580 
00581 /* Params:
00582  *   str1 - as unsigned int - can be CPL_RUN_INCOMING or CPL_RUN_OUTGOING
00583  *   str2 - as unsigned int - flags regarding state(less)|(ful)
00584  */
00585 static int cpl_invoke_script(struct sip_msg* msg, char* str1, char* str2)
00586 {
00587         struct cpl_interpreter  *cpl_intr;
00588         str  user;
00589         str  loc;
00590         str  script;
00591 
00592         /* get the user_name */
00593         if ( ((unsigned long)str1)&CPL_RUN_INCOMING ) {
00594                 /* if it's incoming -> get the destination user name */
00595                 if (get_dest_user( msg, &user, BUILD_UH_SHM)==-1)
00596                         goto error0;
00597         } else {
00598                 /* if it's outgoing -> get the origin user name */
00599                 if (get_orig_user( msg, &user, BUILD_UH_SHM)==-1)
00600                         goto error0;
00601         }
00602 
00603         /* get the script for this user */
00604         if (get_user_script(&user, &script, 1)==-1)
00605                 goto error1;
00606 
00607         /* has the user a non-empty script? if not, return normally, allowing ser to
00608          * continue its script */
00609         if ( !script.s || !script.len ) {
00610                 shm_free(user.s);
00611                 return 1;
00612         }
00613 
00614         /* build a new script interpreter */
00615         if ( (cpl_intr=new_cpl_interpreter(msg,&script))==0 )
00616                 goto error2;
00617         /* set the flags */
00618         cpl_intr->flags =(unsigned int)((unsigned long)str1)|((unsigned long)str2);
00619         /* attache the user */
00620         cpl_intr->user = user;
00621         /* for OUTGOING we need also the destination user for init. with him
00622          * the location set */
00623         if ( ((unsigned long)str1)&CPL_RUN_OUTGOING ) {
00624                 if (get_dest_user( msg, &loc,BUILD_UH_ADDSIP)==-1)
00625                         goto error3;
00626                 if (add_location( &(cpl_intr->loc_set), &loc,10,CPL_LOC_DUPL)==-1)
00627                         goto error3;
00628         }
00629 
00630         /* since the script interpretation can take some time, it will be better to
00631          * send a 100 back to prevent the UAC to retransmit
00632         if ( cpl_tmb.t_reply( msg, (int)100, "Running cpl script" )!=1 ) {
00633                 LOG(L_ERR,"ERROR:cpl_invoke_script: unable to send 100 reply!\n");
00634                 goto error3;
00635         }
00636         * this should be done from script - it's much sooner ;-) */
00637 
00638         /* run the script */
00639         switch (cpl_run_script( cpl_intr )) {
00640                 case SCRIPT_DEFAULT:
00641                         free_cpl_interpreter( cpl_intr );
00642                         return 1; /* execution of ser's script will continue */
00643                 case SCRIPT_END:
00644                         free_cpl_interpreter( cpl_intr );
00645                 case SCRIPT_TO_BE_CONTINUED:
00646                         return 0; /* break the SER script */
00647                 case SCRIPT_RUN_ERROR:
00648                 case SCRIPT_FORMAT_ERROR:
00649                         goto error3;
00650         }
00651 
00652         return 1;
00653 error3:
00654         free_cpl_interpreter( cpl_intr );
00655         return -1;
00656 error2:
00657         shm_free(script.s);
00658 error1:
00659         shm_free(user.s);
00660 error0:
00661         return -1;
00662 }
00663 
00664 
00665 
00666 #define CPL_SCRIPT          "script"
00667 #define CPL_SCRIPT_LEN      (sizeof(CPL_SCRIPT)-1)
00668 #define ACTION_PARAM        "action"
00669 #define ACTION_PARAM_LEN    (sizeof(ACTION_PARAM)-1)
00670 #define STORE_ACTION        "store"
00671 #define STORE_ACTION_LEN    (sizeof(STORE_ACTION)-1)
00672 #define REMOVE_ACTION       "remove"
00673 #define REMOVE_ACTION_LEN   (sizeof(REMOVE_ACTION)-1)
00674 
00675 #define REMOVE_SCRIPT       0xcaca
00676 #define STORE_SCRIPT        0xbebe
00677 
00678 #define CONTENT_TYPE_HDR      ("Content-Type: application/cpl-xml"CRLF)
00679 #define CONTENT_TYPE_HDR_LEN  (sizeof(CONTENT_TYPE_HDR)-1)
00680 
00681 struct cpl_error {
00682         int   err_code;
00683         char *err_msg;
00684 };
00685 
00686 static struct cpl_error bad_req = {400,"Bad request"};
00687 static struct cpl_error intern_err = {500,"Internal server error"};
00688 static struct cpl_error bad_cpl = {400,"Bad CPL script"};
00689 
00690 static struct cpl_error *cpl_err = &bad_req;
00691 
00692 
00693 static inline int do_script_action(struct sip_msg *msg, int action)
00694 {
00695         str  body = STR_NULL;
00696         str  user = STR_NULL;
00697         str  bin  = STR_NULL;
00698         str  log  = STR_NULL;
00699 
00700         /* content-length (if present) */
00701         if ( !msg->content_length &&
00702                         ((parse_headers(msg, HDR_CONTENTLENGTH_F, 0)==-1)
00703                          || !msg->content_length) )
00704         {
00705                 LOG(L_ERR,"ERROR:cpl-c:do_script_action: no Content-Length "
00706                         "hdr found!\n");
00707                 goto error;
00708         }
00709         body.len = get_content_length( msg );
00710 
00711         /* get the user name */
00712         if (get_dest_user( msg, &user, 0)==-1)
00713                 goto error;
00714 
00715         /* we have the script and the user */
00716         switch (action) {
00717                 case STORE_SCRIPT :
00718                         /* check the len -> it must not be 0 */
00719                         if (body.len==0) {
00720                                 LOG(L_ERR,"ERROR:cpl-c:do_script_action: 0 content-len found "
00721                                         "for store\n");
00722                                 goto error_1;
00723                         }
00724                         /* get the message's body */
00725                         body.s = get_body( msg );
00726                         if (body.s==0) {
00727                                 LOG(L_ERR,"ERROR:cpl-c:do_script_action: cannot extract "
00728                                         "body from msg!\n");
00729                                 goto error_1;
00730                         }
00731                         /* now compile the script and place it into database */
00732                         /* get the binary coding for the XML file */
00733                         if ( encodeCPL( &body, &bin, &log)!=1) {
00734                                 cpl_err = &bad_cpl;
00735                                 goto error_1;
00736                         }
00737 
00738                         /* write both the XML and binary formats into database */
00739                         if (write_to_db(user.s, &body, &bin)!=1) {
00740                                 cpl_err = &intern_err;
00741                                 goto error_1;
00742                         }
00743                         break;
00744                 case REMOVE_SCRIPT:
00745                         /* check the len -> it must be 0 */
00746                         if (body.len!=0) {
00747                                 LOG(L_ERR,"ERROR:cpl-c:do_script_action: non-0 content-len "
00748                                         "found for remove\n");
00749                                 goto error_1;
00750                         }
00751                         /* remove the script for the user */
00752                         if (rmv_from_db(user.s)!=1) {
00753                                 cpl_err = &intern_err;
00754                                 goto error_1;
00755                         }
00756                         break;
00757         }
00758 
00759         if (log.s) pkg_free( log.s );
00760         return 0;
00761 error_1:
00762         if (log.s) pkg_free( log.s );
00763 error:
00764         return -1;
00765 }
00766 
00767 
00768 
00769 static inline int do_script_download(struct sip_msg *msg)
00770 {
00771         str  user  = STR_NULL;
00772         str script = STR_NULL;
00773 
00774         /* get the destination user name */
00775         if (get_dest_user( msg, &user, 0)==-1)
00776                 goto error;
00777 
00778         /* get the user's xml script from the database */
00779         if (get_user_script(&user, &script, 0)==-1)
00780                 goto error;
00781 
00782         /* add a lump with content-type hdr */
00783         if (add_lump_rpl( msg, CONTENT_TYPE_HDR, CONTENT_TYPE_HDR_LEN,
00784         LUMP_RPL_HDR)==0) {
00785                 LOG(L_ERR,"ERROR:cpl-c:do_script_download: cannot build hdr lump\n");
00786                 cpl_err = &intern_err;
00787                 goto error;
00788         }
00789 
00790         if (script.s!=0) {
00791                 /*DBG("script len=%d\n--------\n%.*s\n--------\n",
00792                         script.len, script.len, script.s);*/
00793                 /* user has a script -> add a body lump */
00794                 if ( add_lump_rpl( msg, script.s, script.len, LUMP_RPL_BODY)==0) {
00795                         LOG(L_ERR,"ERROR:cpl-c:do_script_download: cannot build "
00796                                 "body lump\n");
00797                         cpl_err = &intern_err;
00798                         goto error;
00799                 }
00800                 /* build_lump_rpl duplicates the added text, so free the original */
00801                 shm_free( script.s );
00802         }
00803 
00804         return 0;
00805 error:
00806         if (script.s)
00807                 shm_free(script.s);
00808         return -1;
00809 }
00810 
00811 
00812 
00813 static int w_process_register(struct sip_msg* msg, char* str, char* str2)
00814 {
00815         return cpl_process_register( msg, 0);
00816 }
00817 
00818 
00819 
00820 static int w_process_register_norpl(struct sip_msg* msg, char* str,char* str2)
00821 {
00822         return cpl_process_register( msg, 1);
00823 }
00824 
00825 
00826 
00827 static int cpl_process_register(struct sip_msg* msg, int no_rpl)
00828 {
00829         struct disposition *disp;
00830         struct disposition_param *param;
00831         int  ret;
00832         int  mime;
00833         int  *mimes;
00834 
00835         /* make sure that is a REGISTER ??? */
00836 
00837         /* here should be the CONTACT- hack */
00838 
00839         /* is there a CONTENT-TYPE hdr ? */
00840         mime = parse_content_type_hdr( msg );
00841         if (mime==-1)
00842                 goto error;
00843 
00844         /* check the mime type */
00845         DBG("DEBUG:cpl_process_register: Content-Type mime found %u, %u\n",
00846                 mime>>16,mime&0x00ff);
00847         if ( mime && mime==(TYPE_APPLICATION<<16)+SUBTYPE_CPLXML ) {
00848                 /* can be an upload or remove -> check for the content-purpose and
00849                  * content-action headers */
00850                 DBG("DEBUG:cpl_process_register: carrying CPL -> look at "
00851                         "Content-Disposition\n");
00852                 if (parse_content_disposition( msg )!=0) {
00853                         LOG(L_ERR,"ERROR:cpl_process_register: Content-Disposition missing "
00854                                 "or corrupted\n");
00855                         goto error;
00856                 }
00857                 disp = get_content_disposition(msg);
00858                 print_disposition( disp ); /* just for DEBUG */
00859                 /* check if the type of disposition is SCRIPT */
00860                 if (disp->type.len!=CPL_SCRIPT_LEN ||
00861                 strncasecmp(disp->type.s,CPL_SCRIPT,CPL_SCRIPT_LEN) ) {
00862                         LOG(L_ERR,"ERROR:cpl_process_register: bogus message - Content-Type"
00863                                 "says CPL_SCRIPT, but Content-Disposition something else\n");
00864                         goto error;
00865                 }
00866                 /* disposition type is OK -> look for action parameter */
00867                 for(param=disp->params;param;param=param->next) {
00868                         if (param->name.len==ACTION_PARAM_LEN &&
00869                         !strncasecmp(param->name.s,ACTION_PARAM,ACTION_PARAM_LEN))
00870                                 break;
00871                 }
00872                 if (param==0) {
00873                         LOG(L_ERR,"ERROR:cpl_process_register: bogus message - "
00874                                 "Content-Disposition has no action param\n");
00875                         goto error;
00876                 }
00877                 /* action param found -> check its value: store or remove */
00878                 if (param->body.len==STORE_ACTION_LEN &&
00879                 !strncasecmp( param->body.s, STORE_ACTION, STORE_ACTION_LEN)) {
00880                         /* it's a store action -> get the script from body message and store
00881                          * it into database (CPL and BINARY format) */
00882                         if (do_script_action( msg, STORE_SCRIPT)==-1)
00883                                 goto error;
00884                 } else
00885                 if (param->body.len==REMOVE_ACTION_LEN &&
00886                 !strncasecmp( param->body.s, REMOVE_ACTION, REMOVE_ACTION_LEN)) {
00887                         /* it's a remove action -> remove the script from database */
00888                         if (do_script_action( msg, REMOVE_SCRIPT)==-1)
00889                                 goto error;
00890                 } else {
00891                         LOG(L_ERR,"ERROR:cpl_process_register: unknown action <%.*s>\n",
00892                                 param->body.len,param->body.s);
00893                         goto error;
00894                 }
00895 
00896                 /* do I have to send to reply? */
00897                 if (no_rpl)
00898                         goto resume_script;
00899 
00900                 /* send a 200 OK reply back */
00901                 cpl_fct.sl.reply( msg, 200, "OK");
00902                 /* I send the reply and I don't want to return to script execution, so
00903                  * I return 0 to do break */
00904                 goto stop_script;
00905         }
00906 
00907         /* is there an ACCEPT hdr ? */
00908         if ( (ret=parse_accept_hdr(msg))==-1)
00909                 goto error;
00910         if (ret==0 || (mimes=get_accept(msg))==0 )
00911                 /* accept header not present or no mimes found */
00912                 goto resume_script;
00913 
00914         /* looks if the REGISTER accepts cpl-xml or * */
00915         while (*mimes) {
00916                 DBG("DEBUG: accept mime found %u, %u\n",
00917                         (*mimes)>>16,(*mimes)&0x00ff);
00918                 if (*mimes==(TYPE_ALL<<16)+SUBTYPE_ALL ||
00919                 *mimes==(TYPE_APPLICATION<<16)+SUBTYPE_CPLXML )
00920                         break;
00921                 mimes++;
00922         }
00923         if (*mimes==0)
00924                 /* no accept mime that matched cpl */
00925                 goto resume_script;
00926 
00927         /* get the user name from msg, retrieve the script from db
00928          * and appended to reply */
00929         if (do_script_download( msg )==-1)
00930                 goto error;
00931 
00932         /* do I have to send to reply? */
00933         if (no_rpl)
00934                 goto resume_script;
00935 
00936         /* send a 200 OK reply back */
00937         cpl_fct.sl.reply( msg, 200, "OK");
00938 
00939 stop_script:
00940         return 0;
00941 resume_script:
00942         return 1;
00943 error:
00944         /* send a error reply back */
00945         cpl_fct.sl.reply( msg, cpl_err->err_code, cpl_err->err_msg);
00946         /* I don't want to return to script execution, so I return 0 to do break */
00947         return 0;
00948 }
00949 
00950 
00951 

Generated on Thu Sep 9 04:15:47 2010 for SIPExpressRouter by  doxygen 1.3.9.1