perl.c

Go to the documentation of this file.
00001 /*
00002  * $Id: perl.c 5515 2009-01-26 12:39:40Z henningw $
00003  *
00004  * Perl module for OpenSER
00005  *
00006  * Copyright (C) 2006 Collax GmbH
00007  *                    (Bastian Friedrich <bastian.friedrich@collax.com>)
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  */
00026 
00027 #define DEFAULTMODULE "OpenSER"
00028 #define MAX_LIB_PATHS 10
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <dlfcn.h>
00034 
00035 #include "../../sr_module.h"
00036 #include "../../mem/mem.h"
00037 #include "../../mi/mi.h"
00038 #include "../rr/api.h"
00039 #include "../sl/sl_api.h"
00040 
00041 /* lock_ops.h defines union semun, perl does not need to redefine it */
00042 #ifdef USE_SYSV_SEM
00043 # define HAS_UNION_SEMUN
00044 #endif
00045 
00046 #include "perlfunc.h"
00047 #include "perl.h"
00048 
00049 /* #include "perlxsi.h" function is in here... */
00050 
00051 MODULE_VERSION
00052 
00053 /* Full path to the script including executed functions */
00054 char *filename = NULL;
00055 
00056 /* Path to an arbitrary directory where the OpenSER Perl modules are
00057  * installed */
00058 char *modpath = NULL;
00059 
00060 /* Allow unsafe module functions - functions with fixups. This will create
00061  * memory leaks, the variable thus is not documented! */
00062 int unsafemodfnc = 0;
00063 
00064 /* Reference to the running Perl interpreter instance */
00065 PerlInterpreter *my_perl = NULL;
00066 
00067 /** SL binds */
00068 struct sl_binds slb;
00069 
00070 /*
00071  * Module destroy function prototype
00072  */
00073 static void destroy(void);
00074 
00075 
00076 /*
00077  * Module initialization function prototype
00078  */
00079 static int mod_init(void);
00080 
00081 
00082 /*
00083  * Reload perl interpreter - reload perl script. Forward declaration.
00084  */
00085 struct mi_root* perl_mi_reload(struct mi_root *cmd_tree, void *param);
00086 
00087 
00088 
00089 /*
00090  * Exported functions
00091  */
00092 static cmd_export_t cmds[] = {
00093    { "perl_exec_simple", (cmd_function)perl_exec_simple1, 1,  NULL, 0,
00094                           REQUEST_ROUTE | FAILURE_ROUTE
00095                         | ONREPLY_ROUTE | BRANCH_ROUTE },
00096    { "perl_exec_simple", (cmd_function)perl_exec_simple2, 2,  NULL, 0,
00097                           REQUEST_ROUTE | FAILURE_ROUTE
00098                         | ONREPLY_ROUTE | BRANCH_ROUTE },
00099    { "perl_exec", (cmd_function)perl_exec1, 1,  NULL, 0, 
00100                           REQUEST_ROUTE | FAILURE_ROUTE
00101                         | ONREPLY_ROUTE | BRANCH_ROUTE },
00102    { "perl_exec", (cmd_function)perl_exec2, 2, NULL, 0,
00103                           REQUEST_ROUTE | FAILURE_ROUTE
00104                         | ONREPLY_ROUTE | BRANCH_ROUTE },
00105    { 0, 0, 0, 0, 0, 0 }
00106 };
00107 
00108 
00109 /*
00110  * Exported parameters
00111  */
00112 static param_export_t params[] = {
00113    {"filename", STR_PARAM, &filename},
00114    {"modpath", STR_PARAM, &modpath},
00115    {"unsafemodfnc", INT_PARAM, &unsafemodfnc},
00116    { 0, 0, 0 }
00117 };
00118 
00119 
00120 /*
00121  * Exported MI functions
00122  */
00123 static mi_export_t mi_cmds[] = {
00124    /* FIXME This does not yet work... 
00125    { "perl_reload",  perl_mi_reload, MI_NO_INPUT_FLAG,  0,  0  },*/
00126    { 0, 0, 0, 0, 0}
00127 
00128 };
00129 
00130 
00131 
00132 
00133 /*
00134  * Module info
00135  */
00136 
00137 #ifndef RTLD_NOW
00138 /* for openbsd */
00139 #define RTLD_NOW DL_LAZY
00140 #endif
00141 
00142 #ifndef RTLD_GLOBAL
00143 /* Unsupported! */
00144 #define RTLD_GLOBAL 0
00145 #endif
00146 
00147 /*
00148  * Module interface
00149  */
00150 struct module_exports exports = {
00151    "perl", 
00152    RTLD_NOW | RTLD_GLOBAL,
00153    cmds,       /* Exported functions */
00154    params,     /* Exported parameters */
00155    0,          /* exported statistics */
00156    mi_cmds,    /* exported MI functions */
00157    0,          /* exported pseudo-variables */
00158    0,          /* extra processes */
00159    mod_init,   /* module initialization function */
00160    0,          /* response function */
00161    destroy,    /* destroy function */
00162    0           /* child initialization function */
00163 };
00164 
00165 
00166 
00167 EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
00168 EXTERN_C void boot_OpenSER(pTHX_ CV* cv);
00169 
00170 
00171 /*
00172  * This is output by perl -MExtUtils::Embed -e xsinit
00173  * and complemented by the OpenSER bootstrapping
00174  */
00175 EXTERN_C void xs_init(pTHX) {
00176         char *file = __FILE__;
00177         dXSUB_SYS;
00178 
00179         newXS("OpenSER::bootstrap", boot_OpenSER, file);
00180 
00181         newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
00182 }
00183 
00184 
00185 /*
00186  * Initialize the perl interpreter.
00187  * This might later be used to reinit the module.
00188  */
00189 PerlInterpreter *parser_init(void) {
00190    int argc = 0;
00191    char *argv[MAX_LIB_PATHS + 3];
00192    PerlInterpreter *new_perl = NULL;
00193    char *entry, *stop, *end;
00194    int modpathset_start = 0;
00195    int modpathset_end = 0;
00196    int i;
00197 
00198    new_perl = perl_alloc();
00199 
00200    if (!new_perl) {
00201       LM_ERR("could not allocate perl.\n");
00202       return NULL;
00203    }
00204 
00205    perl_construct(new_perl);
00206 
00207    argv[0] = ""; argc++; /* First param _needs_ to be empty */
00208    
00209     /* Possible Include path extension by modparam */
00210    if (modpath && (strlen(modpath) > 0)) {
00211       modpathset_start = argc;
00212 
00213       entry = modpath;
00214       stop = modpath + strlen(modpath);
00215       for (end = modpath; end <= stop; end++) {
00216          if ( (end[0] == ':') || (end[0] == '\0') ) {
00217             end[0] = '\0';
00218             if (argc > MAX_LIB_PATHS) {
00219                LM_ERR("too many lib paths, skipping lib path: '%s'\n", entry);
00220             } else {
00221                LM_INFO("setting lib path: '%s'\n", entry);
00222                argv[argc] = pkg_malloc(strlen(entry)+20);
00223                sprintf(argv[argc], "-I%s", entry);
00224                modpathset_end = argc;
00225                argc++;
00226             }
00227             entry = end + 1;
00228          }
00229       }
00230    }
00231 
00232    argv[argc] = "-M"DEFAULTMODULE; argc++; /* Always "use" Openser.pm */
00233 
00234    argv[argc] = filename; /* The script itself */
00235    argc++;
00236 
00237    if (perl_parse(new_perl, xs_init, argc, argv, NULL)) {
00238       LM_ERR("failed to load perl file \"%s\".\n", argv[argc-1]);
00239       if (modpathset_start) {
00240          for (i = modpathset_start; i <= modpathset_end; i++) {
00241             pkg_free(argv[i]);
00242          }
00243       }
00244       return NULL;
00245    } else {
00246       LM_INFO("successfully loaded perl file \"%s\"\n", argv[argc-1]);
00247    }
00248 
00249    if (modpathset_start) {
00250       for (i = modpathset_start; i <= modpathset_end; i++) {
00251          pkg_free(argv[i]);
00252       }
00253    }
00254    perl_run(new_perl);
00255 
00256    return new_perl;
00257 
00258 }
00259 
00260 /*
00261  *
00262  */
00263 int unload_perl(PerlInterpreter *p) {
00264    perl_destruct(p);
00265    perl_free(p);
00266 
00267    return 0;
00268 }
00269 
00270 
00271 /*
00272  * reload function.
00273  * Reinitializes the interpreter. Works, but execution for _all_
00274  * children is difficult.
00275  */
00276 int perl_reload(struct sip_msg *m, char *a, char *b) {
00277 
00278    PerlInterpreter *new_perl;
00279 
00280    new_perl = parser_init();
00281 
00282    if (new_perl) {
00283       unload_perl(my_perl);
00284       my_perl = new_perl;
00285 #ifdef PERL_EXIT_DESTRUCT_END
00286       PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
00287 #else
00288 #warning Perl 5.8.x should be used. Please upgrade.
00289 #warning This binary will be unsupported.
00290       PL_exit_flags |= PERL_EXIT_EXPECTED;
00291 #endif
00292       return 1;
00293    } else {
00294       return 0;
00295    }
00296 
00297 }
00298 
00299 
00300 /*
00301  * Reinit through fifo.
00302  * Currently does not seem to work :((
00303  */
00304 struct mi_root* perl_mi_reload(struct mi_root *cmd_tree, void *param)
00305 {
00306    if (perl_reload(NULL, NULL, NULL)) {
00307       return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00308    } else {
00309       return init_mi_tree( 500, "Perl reload failed", 18);
00310    }
00311 
00312 }
00313 
00314 
00315 /*
00316  * mod_init
00317  * Called by openser at init time
00318  */
00319 static int mod_init(void) {
00320 
00321    int ret = 0;
00322 
00323    if (!filename) {
00324       LM_ERR("insufficient module parameters. Module not loaded.\n");
00325       return -1;
00326    }
00327 
00328    /**
00329     * We will need sl_send_reply from stateless
00330     * module for sending replies
00331     */
00332 
00333 
00334    /* load the SL API */
00335    if (load_sl_api(&slb)!=0) {
00336       LM_ERR("can't load SL API\n");
00337       return -1;
00338    }
00339 
00340    PERL_SYS_INIT3(NULL, NULL, &environ);
00341 
00342    if ((my_perl = parser_init())) {
00343       ret = 0;
00344 #ifdef PERL_EXIT_DESTRUCT_END
00345       PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
00346 #else
00347       PL_exit_flags |= PERL_EXIT_EXPECTED;
00348 #endif
00349 
00350    } else {
00351       ret = -1;
00352    }
00353 
00354    return ret;
00355 }
00356 
00357 /*
00358  * destroy
00359  * called by openser at exit time
00360  */
00361 static void destroy(void)
00362 {
00363    if(my_perl==NULL)
00364       return;
00365    unload_perl(my_perl);
00366    PERL_SYS_TERM();
00367    my_perl = NULL;
00368 }

Generated on Thu May 24 02:00:29 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6