modules/utils/utils.c

Go to the documentation of this file.
00001 /*
00002  * utils Module
00003  *
00004  * Copyright (C) 2008 Juha Heinanen
00005  * Copyright (C) 2009 1&1 Internet AG
00006  *
00007  * This file is part of Kamailio, a free SIP server.
00008  *
00009  * Kamailio is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * Kamailio is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License 
00020  * along with this program; if not, write to the Free Software 
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  * History:
00024  * -------
00025  * 2008-11-24: Introduced utils module and its first function: http_query.
00026  *
00027  */
00028 
00041 #include <curl/curl.h>
00042 
00043 #include "../../mod_fix.h"
00044 #include "../../sr_module.h"
00045 #include "../../ut.h"
00046 #include "../../forward.h"
00047 #include "../../resolve.h"
00048 #include "../../locking.h"
00049 #include "../../script_cb.h"
00050 #include "../../mem/shm_mem.h"
00051 #include "../../lib/srdb1/db.h"
00052 
00053 #include "functions.h"
00054 #include "conf.h"
00055 #include "xcap_auth.h"
00056 
00057 
00058 MODULE_VERSION
00059 
00060 #define XCAP_TABLE_VERSION 4
00061 
00062 /* Module parameter variables */
00063 int http_query_timeout = 4;
00064 static int forward_active = 0;
00065 static int   mp_max_id = 0;
00066 static char* mp_switch = "";
00067 static char* mp_filter = "";
00068 static char* mp_proxy  = "";
00069 str xcap_table= str_init("xcap");
00070 str pres_db_url = {0, 0};
00071 
00072 /* lock for configuration access */
00073 static gen_lock_t *conf_lock = NULL;
00074 
00075 /* FIFO interface functions */
00076 static struct mi_root* forward_fifo_list(struct mi_root* cmd_tree, void *param);
00077 static struct mi_root* forward_fifo_switch(struct mi_root* cmd_tree, void* param);
00078 static struct mi_root* forward_fifo_filter(struct mi_root* cmd_tree, void* param);
00079 static struct mi_root* forward_fifo_proxy(struct mi_root* cmd_tree, void* param);
00080 
00081 /* Database connection */
00082 db1_con_t *pres_dbh = NULL;
00083 db_func_t pres_dbf;
00084 
00085 /* Module management function prototypes */
00086 static int mod_init(void);
00087 static int child_init(int);
00088 static void destroy(void);
00089 
00090 /* Fixup functions to be defined later */
00091 static int fixup_http_query(void** param, int param_no);
00092 static int fixup_free_http_query(void** param, int param_no);
00093 
00094 /* forward function */
00095 int utils_forward(struct sip_msg *msg, int id, int proto);
00096 
00097 /* Exported functions */
00098 static cmd_export_t cmds[] = {
00099     {"http_query", (cmd_function)http_query, 2, fixup_http_query,
00100      fixup_free_http_query,
00101      REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00102     {"xcap_auth_status", (cmd_function)xcap_auth_status, 2, fixup_pvar_pvar,
00103      fixup_free_pvar_pvar, REQUEST_ROUTE},
00104     {0, 0, 0, 0, 0, 0}
00105 };
00106 
00107 
00108 /* Exported parameters */
00109 static param_export_t params[] = {
00110     {"pres_db_url", STR_PARAM, &pres_db_url.s},
00111     {"xcap_table", STR_PARAM, &xcap_table.s},
00112     {"http_query_timeout", INT_PARAM, &http_query_timeout},
00113     {"forward_active", INT_PARAM, &forward_active},
00114     {0, 0, 0}
00115 };
00116 
00117 static mi_export_t mi_cmds[] = {
00118         { "forward_list",   forward_fifo_list,   MI_NO_INPUT_FLAG, 0,  0 },
00119         { "forward_switch", forward_fifo_switch, 0, 0,  0 },
00120         { "forward_filter", forward_fifo_filter, 0, 0,  0 },
00121         { "forward_proxy",  forward_fifo_proxy,  0, 0,  0 },
00122         { 0, 0, 0, 0, 0}
00123 };
00124 
00125 /* Module interface */
00126 struct module_exports exports = {
00127     "utils",
00128     DEFAULT_DLFLAGS, /* dlopen flags */
00129     cmds,      /* Exported functions */
00130     params,    /* Exported parameters */
00131     0,         /* exported statistics */
00132     mi_cmds,   /* exported MI functions */
00133     0,         /* exported pseudo-variables */
00134     0,         /* extra processes */
00135     mod_init,  /* module initialization function */
00136     0,         /* response function*/
00137     destroy,   /* destroy function */
00138     child_init /* per-child init function */
00139 };
00140 
00141 
00142 static int init_shmlock(void)
00143 {
00144         conf_lock = lock_alloc();
00145         if (conf_lock == NULL) {
00146                 LM_CRIT("cannot allocate memory for lock.\n");
00147                 return -1;
00148         }
00149         if (lock_init(conf_lock) == 0) {
00150                 LM_CRIT("cannot initialize lock.\n");
00151                 return -1;
00152         }
00153 
00154         return 0;
00155 }
00156 
00157 
00158 static int pre_script_filter(struct sip_msg *msg, unsigned int flags, void *unused)
00159 {
00160         /* use id 0 for pre script callback */
00161         utils_forward(msg, 0, PROTO_UDP);
00162 
00163         /* always return 1 so that routing skript is called for msg */
00164         return 1;
00165 }
00166 
00167 
00168 static void destroy_shmlock(void)
00169 {
00170         if (conf_lock) {
00171                 lock_destroy(conf_lock);
00172                 lock_dealloc((void *)conf_lock);
00173                 conf_lock = NULL;
00174         }
00175 }
00176 
00177 
00178 static void pres_db_close(void) {
00179     if (pres_dbh) {
00180         pres_dbf.close(pres_dbh);
00181         pres_dbh = NULL;
00182     }
00183 }
00184 
00185 static int pres_db_init(void) {
00186     if (!pres_db_url.s || !pres_db_url.len) {
00187         LM_INFO("xcap_auth_status function is disabled\n");
00188         return 0;
00189     }
00190     if (db_bind_mod(&pres_db_url, &pres_dbf) < 0) {
00191         LM_ERR("can't bind database module\n");
00192         return -1;
00193     }
00194     if ((pres_dbh = pres_dbf.init(&pres_db_url)) == NULL) {
00195         LM_ERR("can't connect to database\n");
00196         return -1;
00197     }
00198     if (db_check_table_version(&pres_dbf, pres_dbh, &xcap_table,
00199                                XCAP_TABLE_VERSION) < 0) {
00200         LM_ERR("during table version check\n");
00201         pres_db_close();
00202         return -1;
00203     }
00204     pres_db_close();
00205     return 0;
00206 }
00207 
00208 static int pres_db_open(void) {
00209     if (!pres_db_url.s || !pres_db_url.len) {
00210         return 0;
00211     }
00212     if (pres_dbh) {
00213         pres_dbf.close(pres_dbh);
00214     }
00215     if ((pres_dbh = pres_dbf.init(&pres_db_url)) == NULL) {
00216         LM_ERR("can't connect to database\n");
00217         return -1;
00218     }
00219     if (pres_dbf.use_table(pres_dbh, &xcap_table) < 0) {
00220         LM_ERR("in use_table: %.*s\n", xcap_table.len, xcap_table.s);
00221         return -1;
00222     }
00223     return 0;
00224 }
00225 
00226 
00227 /* Module initialization function */
00228 static int mod_init(void)
00229 {
00230         if(register_mi_mod(exports.name, mi_cmds)!=0)
00231         {
00232                 LM_ERR("failed to register MI commands\n");
00233                 return -1;
00234         }
00235 
00236         /* Initialize curl */
00237         if (curl_global_init(CURL_GLOBAL_ALL)) {
00238                 LM_ERR("curl_global_init failed\n");
00239                 return -1;
00240         }
00241 
00242 
00243         if (init_shmlock() != 0) {
00244                 LM_CRIT("cannot initialize shmlock.\n");
00245                 return -1;
00246         }
00247 
00248         if (conf_init(mp_max_id) < 0) {
00249                 LM_CRIT("cannot initialize configuration.\n");
00250                 return -1;
00251         }
00252 
00253         /* read module parameters and update configuration structure */
00254         if (conf_parse_proxy(mp_proxy) < 0) {
00255                 LM_CRIT("cannot parse proxy module parameter.\n");
00256                 return -1;
00257         }
00258         if (conf_parse_filter(mp_filter) < 0) {
00259                 LM_CRIT("cannot parse filter module parameter.\n");
00260                 return -1;
00261         }
00262         if (conf_parse_switch(mp_switch) < 0) {
00263                 LM_CRIT("cannot parse switch module parameter.\n");
00264                 return -1;
00265         }
00266 
00267         if (forward_active == 1) {
00268                 /* register callback for id 0 */
00269                 if (register_script_cb(pre_script_filter, PRE_SCRIPT_CB|ONREPLY_CB, 0) < 0) {
00270                         LM_CRIT("cannot register script callback for requests.\n");
00271                         return -1;
00272                 }
00273                 if (register_script_cb(pre_script_filter, PRE_SCRIPT_CB|ONREPLY_CB, 0) < 0) {
00274                         LM_CRIT("cannot register script callback for replies.\n");
00275                         return -1;
00276                 }
00277         } else {
00278                 LM_INFO("forward functionality disabled");
00279         }
00280 
00281         /* presence database */
00282         pres_db_url.len = pres_db_url.s ? strlen(pres_db_url.s) : 0;
00283         LM_DBG("pres_db_url=%s/%d/%p\n", ZSW(pres_db_url.s), pres_db_url.len,
00284                pres_db_url.s);
00285         xcap_table.len = xcap_table.s ? strlen(xcap_table.s) : 0;
00286 
00287         if(pres_db_init() < 0) {
00288             return -1;
00289         }
00290 
00291         return 0;
00292 }
00293 
00294 
00295 /* Child initialization function */
00296 static int child_init(int rank)
00297 {       
00298         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00299                 return 0; /* do nothing for the main process */
00300 
00301     return pres_db_open();
00302 }
00303 
00304 static void destroy(void)
00305 {
00306         /* Cleanup curl */
00307         curl_global_cleanup();
00308         /* Cleanup forward */
00309         conf_destroy();
00310         destroy_shmlock();
00311         /* Close pres db */
00312         pres_db_close();
00313 }
00314 
00315 
00316 /* Fixup functions */
00317 
00318 /*
00319  * Fix http_query params: url (string that may contain pvars) and
00320  * result (writable pvar).
00321  */
00322 static int fixup_http_query(void** param, int param_no)
00323 {
00324     if (param_no == 1) {
00325         return fixup_spve_null(param, 1);
00326     }
00327 
00328     if (param_no == 2) {
00329         if (fixup_pvar_null(param, 1) != 0) {
00330             LM_ERR("failed to fixup result pvar\n");
00331             return -1;
00332         }
00333         if (((pv_spec_t *)(*param))->setf == NULL) {
00334             LM_ERR("result pvar is not writeble\n");
00335             return -1;
00336         }
00337         return 0;
00338     }
00339 
00340     LM_ERR("invalid parameter number <%d>\n", param_no);
00341     return -1;
00342 }
00343 
00344 /*
00345  * Free http_query params.
00346  */
00347 static int fixup_free_http_query(void** param, int param_no)
00348 {
00349     if (param_no == 1) {
00350         LM_WARN("free function has not been defined for spve\n");
00351         return 0;
00352     }
00353 
00354     if (param_no == 2) {
00355         return fixup_free_pvar_null(param, 1);
00356     }
00357     
00358     LM_ERR("invalid parameter number <%d>\n", param_no);
00359     return -1;
00360 }
00361 
00362 
00370 int utils_forward(struct sip_msg *msg, int id, int proto)
00371 {
00372         int ret = -1;
00373         struct dest_info dst;
00374 
00375         init_dest_info(&dst);
00376         dst.proto = proto;
00377 
00378         // critical section start:
00379         // avoids dirty reads when updating configuration.
00380         lock_get(conf_lock);
00381 
00382         struct proxy_l *proxy = conf_needs_forward(msg, id);
00383 
00384         if (proxy != NULL) {
00385                 proxy2su(&dst.to, proxy);
00386                 if (forward_request(msg, NULL, 0, &dst) < 0){
00387                         LM_ERR("could not forward message\n");
00388                 }
00389                 ret = 0;
00390         }
00391 
00392         // critical section end
00393         lock_release(conf_lock);
00394 
00395         return ret;
00396 }
00397 
00398 
00399 /* FIFO functions */
00400 
00405 static struct mi_root* forward_fifo_list(struct mi_root* cmd_tree, void *param)
00406 {
00407         struct mi_node *node = NULL;
00408         struct mi_root * ret = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00409         if(ret == NULL)
00410                 return 0;
00411 
00412         node = addf_mi_node_child( &ret->node, 0, 0, 0, "Printing forwarding information:");
00413         if(node == NULL)
00414                 goto error;
00415 
00416         // critical section start:
00417         // avoids dirty reads when updating configuration.
00418         lock_get(conf_lock);
00419 
00420         conf_show(ret);
00421 
00422         // critical section end
00423         lock_release(conf_lock);
00424 
00425         return ret;
00426 
00427 error:
00428         free_mi_tree(ret);
00429         return 0;
00430 }
00431 
00432 
00437 static struct mi_root* forward_fifo_switch(struct mi_root* cmd_tree, void* param)
00438 {
00439         struct mi_node *node = NULL;
00440         int result;
00441 
00442         node = cmd_tree->node.kids;
00443         if (node==NULL || node->next!=NULL || node->value.s==NULL)
00444                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00445 
00446         // critical section start:
00447         // avoids dirty reads when updating configuration.
00448         lock_get(conf_lock);
00449 
00450         result = conf_parse_switch(node->value.s);
00451 
00452         // critical section end
00453         lock_release(conf_lock);
00454 
00455         if (result < 0) {
00456                 LM_ERR("cannot parse parameter\n");
00457                 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00458         }
00459         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00460 }
00461 
00462 
00467 static struct mi_root* forward_fifo_filter(struct mi_root* cmd_tree, void* param)
00468 {
00469         struct mi_node *node = NULL;
00470         int result;
00471 
00472         node = cmd_tree->node.kids;
00473         if (node==NULL || node->next!=NULL || node->value.s==NULL)
00474                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00475 
00476         // critical section start:
00477         //   avoids dirty reads when updating configuration.
00478         lock_get(conf_lock);
00479 
00480         result = conf_parse_filter(node->value.s);
00481 
00482         // critical section end
00483         lock_release(conf_lock);
00484 
00485         if (result < 0) {
00486                 LM_ERR("cannot parse parameter\n");
00487                 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00488         }
00489         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00490 }
00491 
00492 
00497 static struct mi_root* forward_fifo_proxy(struct mi_root* cmd_tree, void* param)
00498 {
00499         struct mi_node *node = NULL;
00500         int result;
00501 
00502         node = cmd_tree->node.kids;
00503         if (node==NULL || node->next!=NULL || node->value.s==NULL)
00504                 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00505 
00506         // critical section start:
00507         //   avoids dirty reads when updating configuration.
00508         lock_get(conf_lock);
00509 
00510         result = conf_parse_proxy(node->value.s);
00511 
00512         // critical section end
00513         lock_release(conf_lock);
00514 
00515         if (result < 0) {
00516                 LM_ERR("cannot parse parameter\n");
00517                 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00518         }
00519         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00520 }