123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- /*
- * $Id: matrix.c 4978 2008-09-23 14:25:02Z henningw $
- *
- * Copyright (C) 2007 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #include <string.h>
- #include "../../mem/shm_mem.h"
- #include "../../sr_module.h"
- #include "../../lib/kmi/mi.h"
- #include "../../mem/mem.h"
- #include "../../usr_avp.h"
- #include "../../locking.h"
- #include "../../error.h"
- #include "../../ut.h"
- #include "../../mod_fix.h"
- #include "db_matrix.h"
- MODULE_VERSION
- #define MAXCOLS 1000
- str matrix_db_url = str_init(DEFAULT_RODB_URL);
- /**
- * Generic parameter that holds a string, an int or an pseudo-variable
- * @todo replace this with gparam_t
- */
- struct multiparam_t {
- enum {
- MP_INT,
- MP_STR,
- MP_AVP,
- MP_PVE,
- } type;
- union {
- int n;
- str s;
- struct {
- unsigned short flags;
- int_str name;
- } a;
- pv_elem_t *p;
- } u;
- };
- /* ---- fixup functions: */
- static int matrix_fixup(void** param, int param_no);
- /* ---- exported commands: */
- static int lookup_matrix(struct sip_msg *msg, struct multiparam_t *_first, struct multiparam_t *_second, struct multiparam_t *_dstavp);
- /* ---- module init functions: */
- static int mod_init(void);
- static int child_init(int rank);
- static int mi_child_init(void);
- static void mod_destroy(void);
- /* --- fifo functions */
- struct mi_root * mi_reload_matrix(struct mi_root* cmd, void* param); /* usage: kamctl fifo reload_matrix */
- static cmd_export_t cmds[]={
- { "matrix", (cmd_function)lookup_matrix, 3, matrix_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
- { 0, 0, 0, 0, 0, 0}
- };
- static param_export_t params[] = {
- matrix_DB_URL
- matrix_DB_TABLE
- matrix_DB_COLS
- { 0, 0, 0}
- };
- /* Exported MI functions */
- static mi_export_t mi_cmds[] = {
- { "reload_matrix", mi_reload_matrix, MI_NO_INPUT_FLAG, 0, mi_child_init },
- { 0, 0, 0, 0, 0}
- };
- struct module_exports exports= {
- "matrix",
- DEFAULT_DLFLAGS,
- cmds,
- params,
- 0,
- mi_cmds,
- 0,
- 0,
- mod_init,
- 0,
- mod_destroy,
- child_init
- };
- struct first_t {
- struct first_t *next;
- int id;
- short int second_list[MAXCOLS+1];
- };
- struct matrix_t {
- struct first_t *head;
- };
- static gen_lock_t *lock = NULL;
- static struct matrix_t *matrix = NULL;
- /**
- * fixes the module functions' parameters if it is a phone number.
- * supports string, pseudo-variables and AVPs.
- *
- * @param param the parameter
- *
- * @return 0 on success, -1 on failure
- */
- static int mp_fixup(void ** param) {
- pv_spec_t avp_spec;
- struct multiparam_t *mp;
- str s;
- mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
- if (mp == NULL) {
- LM_ERR("out of pkg memory\n");
- return -1;
- }
- memset(mp, 0, sizeof(struct multiparam_t));
-
- s.s = (char *)(*param);
- s.len = strlen(s.s);
- if (s.s[0]!='$') {
- /* This is string */
- mp->type=MP_STR;
- mp->u.s=s;
- }
- else {
- /* This is a pseudo-variable */
- if (pv_parse_spec(&s, &avp_spec)==0) {
- LM_ERR("pv_parse_spec failed for '%s'\n", (char *)(*param));
- pkg_free(mp);
- return -1;
- }
- if (avp_spec.type==PVT_AVP) {
- /* This is an AVP - could be an id or name */
- mp->type=MP_AVP;
- if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
- LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
- pkg_free(mp);
- return -1;
- }
- } else {
- mp->type=MP_PVE;
- if(pv_parse_format(&s, &(mp->u.p))<0) {
- LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
- pkg_free(mp);
- return -1;
- }
- }
- }
- *param = (void*)mp;
- return 0;
- }
- /**
- * fixes the module functions' parameters in case of AVP names.
- *
- * @param param the parameter
- *
- * @return 0 on success, -1 on failure
- */
- static int avp_name_fixup(void ** param) {
- pv_spec_t avp_spec;
- struct multiparam_t *mp;
- str s;
- s.s = (char *)(*param);
- s.len = strlen(s.s);
- if (s.len <= 0) return -1;
- if (pv_parse_spec(&s, &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
- LM_ERR("Malformed or non AVP definition <%s>\n", (char *)(*param));
- return -1;
- }
-
- mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
- if (mp == NULL) {
- LM_ERR("out of pkg memory\n");
- return -1;
- }
- memset(mp, 0, sizeof(struct multiparam_t));
-
- mp->type=MP_AVP;
- if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
- LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
- pkg_free(mp);
- return -1;
- }
- *param = (void*)mp;
-
- return 0;
- }
- static int matrix_fixup(void** param, int param_no)
- {
- if (param_no == 1) {
- /* source id */
- if (mp_fixup(param) < 0) {
- LM_ERR("cannot fixup parameter %d\n", param_no);
- return -1;
- }
- }
- else if (param_no == 2) {
- /* destination id */
- if (mp_fixup(param) < 0) {
- LM_ERR("cannot fixup parameter %d\n", param_no);
- return -1;
- }
- }
- else if (param_no == 3) {
- /* destination avp name */
- if (avp_name_fixup(param) < 0) {
- LM_ERR("cannot fixup parameter %d\n", param_no);
- return -1;
- }
- }
- return 0;
- }
- static void matrix_clear(void)
- {
- struct first_t *srcitem;
- if (matrix) {
- while (matrix->head) {
- srcitem = matrix->head;
- matrix->head = srcitem->next;
- shm_free(srcitem);
- }
- }
- }
- static int matrix_insert(int first, short int second, int res)
- {
- struct first_t *srcitem;
- int i;
- if ((second<0) || (second>MAXCOLS)) {
- LM_ERR("invalid second value %d\n", second);
- return -1;
- }
- LM_DBG("searching for %d, %d\n", first, second);
- if (matrix) {
- srcitem = matrix->head;
- while (srcitem) {
- if (srcitem->id == first) {
- srcitem->second_list[second] = res;
- LM_DBG("inserted (%d, %d, %d)", first, second, res);
- return 0;
- }
- srcitem = srcitem->next;
- }
- /* not found */
- srcitem = shm_malloc(sizeof(struct first_t));
- if (srcitem == NULL) {
- LM_ERR("out of shared memory.");
- return -1;
- }
- memset(srcitem, 0, sizeof(struct first_t));
- /* Mark all new cells as empty */
- for (i=0; i<=MAXCOLS; i++) srcitem->second_list[i] = -1;
- srcitem->next = matrix->head;
- srcitem->id = first;
- srcitem->second_list[second] = res;
- matrix->head = srcitem;
- }
- LM_DBG("inserted new row for (%d, %d, %d)", first, second, res);
- return 0;
- }
- /* Returns the res id if the matrix contains an entry for the given indices, -1 otherwise.
- */
- static int internal_lookup(int first, short int second)
- {
- struct first_t *item;
- if ((second<0) || (second>MAXCOLS)) {
- LM_ERR("invalid second value %d\n", second);
- return -1;
- }
- if (matrix) {
- item = matrix->head;
- while (item) {
- if (item->id == first) {
- return item->second_list[second];
- }
- item = item->next;
- }
- }
- return -1;
- }
- static int lookup_matrix(struct sip_msg *msg, struct multiparam_t *_srctree, struct multiparam_t *_second, struct multiparam_t *_dstavp)
- {
- int first;
- int second;
- struct usr_avp *avp;
- int_str avp_val;
- switch (_srctree->type) {
- case MP_INT:
- first = _srctree->u.n;
- break;
- case MP_AVP:
- avp = search_first_avp(_srctree->u.a.flags, _srctree->u.a.name, &avp_val, 0);
- if (!avp) {
- LM_ERR("cannot find srctree AVP\n");
- return -1;
- }
- if ((avp->flags&AVP_VAL_STR)) {
- LM_ERR("cannot process string value in srctree AVP\n");
- return -1;
- }
- else first = avp_val.n;
- break;
- default:
- LM_ERR("invalid srctree type\n");
- return -1;
- }
- switch (_second->type) {
- case MP_INT:
- second = _second->u.n;
- break;
- case MP_AVP:
- avp = search_first_avp(_second->u.a.flags, _second->u.a.name, &avp_val, 0);
- if (!avp) {
- LM_ERR("cannot find second_value AVP\n");
- return -1;
- }
- if ((avp->flags&AVP_VAL_STR)) {
- LM_ERR("cannot process string value in second_value AVP\n");
- return -1;
- }
- else second = avp_val.n;
- break;
- default:
- LM_ERR("invalid second_value type\n");
- return -1;
- }
-
- /* critical section start: avoids dirty reads when updating d-tree */
- lock_get(lock);
- avp_val.n=internal_lookup(first, second);
- /* critical section end */
- lock_release(lock);
- if (avp_val.n<0) {
- LM_INFO("lookup failed\n");
- return -1;
- }
- /* set avp ! */
- if (add_avp(_dstavp->u.a.flags, _dstavp->u.a.name, avp_val)<0) {
- LM_ERR("add AVP failed\n");
- return -1;
- }
- LM_INFO("result from lookup: %d\n", avp_val.n);
- return 1;
- }
- /**
- * Rebuild matrix using database entries
- * \return negative on failure, positive on success, indicating the number of matrix entries
- */
- static int db_reload_matrix(void)
- {
- db_key_t columns[3] = { &matrix_first_col, &matrix_second_col, &matrix_res_col };
- db1_res_t *res;
- int i;
- int n = 0;
-
- if (matrix_dbf.use_table(matrix_dbh, &matrix_table) < 0) {
- LM_ERR("cannot use table '%.*s'.\n", matrix_table.len, matrix_table.s);
- return -1;
- }
- if (matrix_dbf.query(matrix_dbh, NULL, NULL, NULL, columns, 0, 3, NULL, &res) < 0) {
- LM_ERR("error while executing query.\n");
- return -1;
- }
- /* critical section start: avoids dirty reads when updating d-tree */
- lock_get(lock);
- matrix_clear();
- if (RES_COL_N(res) > 2) {
- for(i = 0; i < RES_ROW_N(res); i++) {
- if ((!RES_ROWS(res)[i].values[0].nul) && (!RES_ROWS(res)[i].values[1].nul)) {
- if ((RES_ROWS(res)[i].values[0].type == DB1_INT) &&
- (RES_ROWS(res)[i].values[1].type == DB1_INT) &&
- (RES_ROWS(res)[i].values[2].type == DB1_INT)) {
- matrix_insert(RES_ROWS(res)[i].values[0].val.int_val, RES_ROWS(res)[i].values[1].val.int_val, RES_ROWS(res)[i].values[2].val.int_val);
- n++;
- }
- else {
- LM_ERR("got invalid result type from query.\n");
- }
- }
- }
- }
- /* critical section end */
- lock_release(lock);
- matrix_dbf.free_result(matrix_dbh, res);
- LM_INFO("loaded %d matrix entries.", n);
- return n;
- }
- static int init_shmlock(void)
- {
- lock = lock_alloc();
- if (!lock) {
- LM_CRIT("cannot allocate memory for lock.\n");
- return -1;
- }
- if (lock_init(lock) == 0) {
- LM_CRIT("cannot initialize lock.\n");
- return -1;
- }
- return 0;
- }
- static void destroy_shmlock(void)
- {
- if (lock) {
- lock_destroy(lock);
- lock_dealloc((void *)lock);
- lock = NULL;
- }
- }
- struct mi_root * mi_reload_matrix(struct mi_root* cmd, void* param)
- {
- struct mi_root * tmp = NULL;
- if(db_reload_matrix() >= 0) {
- tmp = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
- } else {
- tmp = init_mi_tree( 500, "cannot reload matrix", 24);
- }
- return tmp;
- }
- static int init_matrix(void)
- {
- matrix = shm_malloc(sizeof(struct matrix_t));
- if (!matrix) {
- LM_ERR("out of shared memory\n");
- return -1;
- }
- memset(matrix, 0, sizeof(struct matrix_t));
- if (db_reload_matrix() < 0) {
- LM_ERR("cannot populate matrix\n");
- return -1;
- }
- return 0;
- }
- static void destroy_matrix(void)
- {
- if (matrix) {
- matrix_clear();
- shm_free(matrix);
- }
- }
- static int mod_init(void)
- {
- if(register_mi_mod(exports.name, mi_cmds)!=0)
- {
- LM_ERR("failed to register MI commands\n");
- return -1;
- }
- if (init_shmlock() != 0) return -1;
- if (matrix_db_init() != 0) return -1;
- if (matrix_db_open() != 0) return -1;
- if (init_matrix() != 0) return -1;
- matrix_db_close();
- return 0;
- }
- static int child_init(int rank)
- {
- if(rank==PROC_INIT || rank==PROC_TCP_MAIN)
- return 0;
- if (matrix_db_open() != 0) return -1;
- return 0;
- }
- static int mi_child_init(void)
- {
- if (matrix_db_open() != 0) return -1;
- return 0;
- }
- static void mod_destroy(void)
- {
- destroy_matrix();
- destroy_shmlock();
- matrix_db_close();
- }
|