123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- /*
- * $Id$
- *
- * Copyright (C) 2005-2009 Voice Sistem SRL
- *
- * 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.
- *
- * History:
- * ---------
- * 2005-02-20 first version (cristian)
- * 2005-02-27 ported to 0.9.0 (bogdan)
- */
- #include <string.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <limits.h>
- #include "../../dprint.h"
- #include "../../route.h"
- //#include "../../db/db.h"
- #include "../../mem/shm_mem.h"
- #include "dr_load.h"
- #include "routing.h"
- #include "prefix_tree.h"
- #include "dr_time.h"
- #include "parse.h"
- #define DST_ID_DRD_COL "gwid"
- #define ADDRESS_DRD_COL "address"
- #define STRIP_DRD_COL "strip"
- #define PREFIX_DRD_COL "pri_prefix"
- #define TYPE_DRD_COL "type"
- #define ATTRS_DRD_COL "attrs"
- static str dst_id_drd_col = str_init(DST_ID_DRD_COL);
- static str address_drd_col = str_init(ADDRESS_DRD_COL);
- static str strip_drd_col = str_init(STRIP_DRD_COL);
- static str prefix_drd_col = str_init(PREFIX_DRD_COL);
- static str type_drd_col = str_init(TYPE_DRD_COL);
- static str attrs_drd_col = str_init(ATTRS_DRD_COL);
- #define RULE_ID_DRR_COL "ruleid"
- #define GROUP_DRR_COL "groupid"
- #define PREFIX_DRR_COL "prefix"
- #define TIME_DRR_COL "timerec"
- #define PRIORITY_DRR_COL "priority"
- #define ROUTEID_DRR_COL "routeid"
- #define DSTLIST_DRR_COL "gwlist"
- static str rule_id_drr_col = str_init(RULE_ID_DRR_COL);
- static str group_drr_col = str_init(GROUP_DRR_COL);
- static str prefix_drr_col = str_init(PREFIX_DRR_COL);
- static str time_drr_col = str_init(TIME_DRR_COL);
- static str priority_drr_col = str_init(PRIORITY_DRR_COL);
- static str routeid_drr_col = str_init(ROUTEID_DRR_COL);
- static str dstlist_drr_col = str_init(DSTLIST_DRR_COL);
- #define ID_DRL_COL "id"
- #define GWLIST_DRL_CAL "gwlist"
- static str id_drl_col = str_init(ID_DRL_COL);
- static str gwlist_drl_col = str_init(GWLIST_DRL_CAL);
- struct dr_gwl_tmp {
- unsigned int id;
- char *gwlist;
- struct dr_gwl_tmp *next;
- };
- static struct dr_gwl_tmp* dr_gw_lists = NULL;
- #define check_val( _val, _type, _not_null, _is_empty_str) \
- do{\
- if ((_val)->type!=_type) { \
- LM_ERR("bad colum type\n");\
- goto error;\
- } \
- if (_not_null && (_val)->nul) { \
- LM_ERR("nul column\n");\
- goto error;\
- } \
- if (_is_empty_str && VAL_STRING(_val)==0) { \
- LM_ERR("empty str column\n");\
- goto error;\
- } \
- }while(0)
- #define TR_SEPARATOR '|'
- #define load_TR_value( _p,_s, _tr, _func, _err, _done) \
- do{ \
- _s = strchr(_p, (int)TR_SEPARATOR); \
- if (_s) \
- *_s = 0; \
- /*DBG("----parsing tr param <%s>\n",_p);*/\
- if(_s != _p) {\
- if( _func( _tr, _p)) {\
- if (_s) *_s = TR_SEPARATOR; \
- goto _err; \
- } \
- } \
- if (_s) { \
- *_s = TR_SEPARATOR; \
- _p = _s+1;\
- if ( *(_p)==0 ) \
- goto _done; \
- } else {\
- goto _done; \
- }\
- } while(0)
- extern int dr_fetch_rows;
- static int add_tmp_gw_list(unsigned int id, char *list)
- {
- struct dr_gwl_tmp *tmp;
- unsigned int list_len;
- list_len = strlen(list) + 1;
- tmp = (struct dr_gwl_tmp*)pkg_malloc(sizeof(struct dr_gwl_tmp) + list_len);
- if (tmp==NULL) {
- LM_ERR("no more pkg mem\n");
- return -1;
- }
- tmp->id = id;
- tmp->gwlist = (char*)(tmp+1);
- memcpy(tmp->gwlist, list, list_len);
- tmp->next = dr_gw_lists;
- dr_gw_lists = tmp;
- return 0;
- }
- static char* get_tmp_gw_list(unsigned int id)
- {
- struct dr_gwl_tmp *tmp;
- for( tmp=dr_gw_lists ; tmp ; tmp=tmp->next )
- if (tmp->id == id) return tmp->gwlist;
- return NULL;
- }
- static void free_tmp_gw_list(void)
- {
- struct dr_gwl_tmp *tmp, *tmp1;
- for( tmp=dr_gw_lists ; tmp ; ) {
- tmp1 = tmp;
- tmp = tmp->next;
- pkg_free(tmp1);
- }
- dr_gw_lists = NULL;
- }
- static inline tmrec_t* parse_time_def(char *time_str)
- {
- tmrec_t *time_rec;
- char *p,*s;
- p = time_str;
- time_rec = 0;
- time_rec = (tmrec_t*)shm_malloc(sizeof(tmrec_t));
- if (time_rec==0) {
- LM_ERR("no more pkg mem\n");
- goto error;
- }
- memset( time_rec, 0, sizeof(tmrec_t));
- /* empty definition? */
- if ( time_str==0 || *time_str==0 )
- goto done;
- load_TR_value( p, s, time_rec, tr_parse_dtstart, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_duration, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_freq, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_until, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_interval, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_byday, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_bymday, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_byyday, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_byweekno, parse_error, done);
- load_TR_value( p, s, time_rec, tr_parse_bymonth, parse_error, done);
- /* success */
- done:
- return time_rec;
- parse_error:
- LM_ERR("parse error in <%s> around position %i\n",
- time_str, (int)(long)(p-time_str));
- error:
- if (time_rec)
- tmrec_free( time_rec );
- return 0;
- }
- static int add_rule(rt_data_t *rdata, char *grplst, str *prefix, rt_info_t *rule)
- {
- long int t;
- char *tmp;
- char *ep;
- int n;
- tmp=grplst;
- n=0;
- /* parse the grplst */
- while(tmp && (*tmp!=0)) {
- errno = 0;
- t = strtol(tmp, &ep, 10);
- if (ep == tmp) {
- LM_ERR("bad grp id '%c' (%d)[%s]\n",
- *ep, (int)(ep-grplst), grplst);
- goto error;
- }
- if ((!IS_SPACE(*ep)) && (*ep != SEP) && (*ep != SEP1) && (*ep!=0)) {
- LM_ERR("bad char %c (%d) [%s]\n",
- *ep, (int)(ep-grplst), grplst);
- goto error;
- }
- if (errno == ERANGE && (t== LONG_MAX || t== LONG_MIN)) {
- LM_ERR("out of bounds\n");
- goto error;
- }
- n++;
- /* add rule -> has prefix? */
- if (prefix->len) {
- /* add the routing rule */
- if ( add_prefix(rdata->pt, prefix, rule, (unsigned int)t)!=0 ) {
- LM_ERR("failed to add prefix route\n");
- goto error;
- }
- } else {
- if ( add_rt_info( &rdata->noprefix, rule, (unsigned int)t)!=0 ) {
- LM_ERR("failed to add prefixless route\n");
- goto error;
- }
- }
- /* keep parsing */
- if(IS_SPACE(*ep))
- EAT_SPACE(ep);
- if(ep && (*ep == SEP || *ep == SEP1))
- ep++;
- tmp = ep;
- }
- if(n==0) {
- LM_ERR("no id in grp list [%s]\n",
- grplst);
- goto error;
- }
- return 0;
- error:
- return -1;
- }
- rt_data_t* dr_load_routing_info( db_func_t *dr_dbf, db1_con_t* db_hdl,
- str *drd_table, str *drl_table, str* drr_table )
- {
- int int_vals[4];
- char * str_vals[5];
- str tmp;
- db_key_t columns[7];
- db1_res_t* res;
- db_row_t* row;
- rt_info_t *ri;
- rt_data_t *rdata;
- tmrec_t *time_rec;
- unsigned int id;
- str s_id;
- int i,n;
- res = 0;
- ri = 0;
- rdata = 0;
- /* init new data structure */
- if ( (rdata=build_rt_data())==0 ) {
- LM_ERR("failed to build rdata\n");
- goto error;
- }
- /* read the destinations */
- if (dr_dbf->use_table( db_hdl, drd_table) < 0) {
- LM_ERR("cannot select table \"%.*s\"\n", drd_table->len,drd_table->s);
- goto error;
- }
- columns[0] = &dst_id_drd_col;
- columns[1] = &address_drd_col;
- columns[2] = &strip_drd_col;
- columns[3] = &prefix_drd_col;
- columns[4] = &type_drd_col;
- columns[5] = &attrs_drd_col;
- if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) {
- if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 6, 0, 0 ) < 0) {
- LM_ERR("DB query failed\n");
- goto error;
- }
- if(dr_dbf->fetch_result(db_hdl, &res, dr_fetch_rows)<0) {
- LM_ERR("Error fetching rows\n");
- goto error;
- }
- } else {
- if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 6, 0, &res) < 0) {
- LM_ERR("DB query failed\n");
- goto error;
- }
- }
- if (RES_ROW_N(res) == 0) {
- LM_WARN("table \"%.*s\" empty\n", drd_table->len,drd_table->s );
- }
- LM_DBG("%d records found in %.*s\n",
- RES_ROW_N(res), drd_table->len,drd_table->s);
- n = 0;
- do {
- for(i=0; i < RES_ROW_N(res); i++) {
- row = RES_ROWS(res) + i;
- /* DST_ID column */
- check_val( ROW_VALUES(row), DB1_INT, 1, 0);
- int_vals[0] = VAL_INT (ROW_VALUES(row));
- /* ADDRESS column */
- check_val( ROW_VALUES(row)+1, DB1_STRING, 1, 1);
- str_vals[0] = (char*)VAL_STRING(ROW_VALUES(row)+1);
- /* STRIP column */
- check_val( ROW_VALUES(row)+2, DB1_INT, 1, 0);
- int_vals[1] = VAL_INT (ROW_VALUES(row)+2);
- /* PREFIX column */
- check_val( ROW_VALUES(row)+3, DB1_STRING, 0, 0);
- str_vals[1] = (char*)VAL_STRING(ROW_VALUES(row)+3);
- /* TYPE column */
- check_val( ROW_VALUES(row)+4, DB1_INT, 1, 0);
- int_vals[2] = VAL_INT(ROW_VALUES(row)+4);
- /* ATTRS column */
- check_val( ROW_VALUES(row)+5, DB1_STRING, 0, 0);
- str_vals[2] = (char*)VAL_STRING(ROW_VALUES(row)+5);
- /* add the destinaton definition in */
- if ( add_dst( rdata, int_vals[0], str_vals[0], int_vals[1],
- str_vals[1], int_vals[2], str_vals[2])<0 ) {
- LM_ERR("failed to add destination id %d -> skipping\n",
- int_vals[0]);
- continue;
- }
- n++;
- }
- if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) {
- if(dr_dbf->fetch_result(db_hdl, &res, dr_fetch_rows)<0) {
- LM_ERR( "fetching rows (1)\n");
- goto error;
- }
- } else {
- break;
- }
- } while(RES_ROW_N(res)>0);
- dr_dbf->free_result(db_hdl, res);
- res = 0;
- if (n==0) {
- LM_WARN("no valid "
- "destinations set -> ignoring the routing rules\n");
- return rdata;
- }
- /* read the gw lists, if any */
- if (dr_dbf->use_table( db_hdl, drl_table) < 0) {
- LM_ERR("cannot select table \"%.*s\"\n", drl_table->len,drl_table->s);
- goto error;
- }
- columns[0] = &id_drl_col;
- columns[1] = &gwlist_drl_col;
- if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) {
- if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 2, 0, 0 ) < 0) {
- LM_ERR("DB query failed\n");
- goto error;
- }
- if(dr_dbf->fetch_result(db_hdl, &res, dr_fetch_rows)<0) {
- LM_ERR("Error fetching rows\n");
- goto error;
- }
- } else {
- if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 2, 0, &res) < 0) {
- LM_ERR("DB query failed\n");
- goto error;
- }
- }
- if (RES_ROW_N(res) == 0) {
- LM_DBG("table \"%.*s\" empty\n", drl_table->len,drl_table->s );
- } else {
- LM_DBG("%d records found in %.*s\n",
- RES_ROW_N(res), drl_table->len,drl_table->s);
- do {
- for(i=0; i < RES_ROW_N(res); i++) {
- row = RES_ROWS(res) + i;
- /* ID column */
- check_val( ROW_VALUES(row), DB1_INT, 1, 0);
- int_vals[0] = VAL_INT (ROW_VALUES(row));
- /* GWLIST column */
- check_val( ROW_VALUES(row)+1, DB1_STRING, 1, 1);
- str_vals[0] = (char*)VAL_STRING(ROW_VALUES(row)+1);
- if (add_tmp_gw_list(int_vals[0], str_vals[0])!=0) {
- LM_ERR("failed to add temporary GW list\n");
- goto error;
- }
- }
- if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) {
- if(dr_dbf->fetch_result(db_hdl, &res, dr_fetch_rows)<0) {
- LM_ERR( "fetching rows (1)\n");
- goto error;
- }
- } else {
- break;
- }
- } while(RES_ROW_N(res)>0);
- }
- dr_dbf->free_result(db_hdl, res);
- res = 0;
- /* read the routing rules */
- if (dr_dbf->use_table( db_hdl, drr_table) < 0) {
- LM_ERR("cannot select table \"%.*s\"\n", drr_table->len, drr_table->s);
- goto error;
- }
- columns[0] = &rule_id_drr_col;
- columns[1] = &group_drr_col;
- columns[2] = &prefix_drr_col;
- columns[3] = &time_drr_col;
- columns[4] = &priority_drr_col;
- columns[5] = &routeid_drr_col;
- columns[6] = &dstlist_drr_col;
- if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) {
- if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 7, 0, 0) < 0) {
- LM_ERR("DB query failed\n");
- goto error;
- }
- if(dr_dbf->fetch_result(db_hdl, &res, dr_fetch_rows)<0) {
- LM_ERR("Error fetching rows\n");
- goto error;
- }
- } else {
- if ( dr_dbf->query( db_hdl, 0, 0, 0, columns, 0, 7, 0, &res) < 0) {
- LM_ERR("DB query failed\n");
- goto error;
- }
- }
- if (RES_ROW_N(res) == 0) {
- LM_WARN("table \"%.*s\" is empty\n", drr_table->len, drr_table->s);
- }
- LM_DBG("%d records found in %.*s\n", RES_ROW_N(res),
- drr_table->len, drr_table->s);
- n = 0;
- do {
- for(i=0; i < RES_ROW_N(res); i++) {
- row = RES_ROWS(res) + i;
- /* RULE_ID column */
- check_val( ROW_VALUES(row), DB1_INT, 1, 0);
- int_vals[0] = VAL_INT (ROW_VALUES(row));
- /* GROUP column */
- check_val( ROW_VALUES(row)+1, DB1_STRING, 1, 1);
- str_vals[0] = (char*)VAL_STRING(ROW_VALUES(row)+1);
- /* PREFIX column - it may be null or empty */
- check_val( ROW_VALUES(row)+2, DB1_STRING, 0, 0);
- if ((ROW_VALUES(row)+2)->nul || VAL_STRING(ROW_VALUES(row)+2)==0){
- tmp.s = NULL;
- tmp.len = 0;
- } else {
- str_vals[1] = (char*)VAL_STRING(ROW_VALUES(row)+2);
- tmp.s = str_vals[1];
- tmp.len = strlen(str_vals[1]);
- }
- /* TIME column */
- check_val( ROW_VALUES(row)+3, DB1_STRING, 1, 1);
- str_vals[2] = (char*)VAL_STRING(ROW_VALUES(row)+3);
- /* PRIORITY column */
- check_val( ROW_VALUES(row)+4, DB1_INT, 1, 0);
- int_vals[2] = VAL_INT (ROW_VALUES(row)+4);
- /* ROUTE_ID column */
- check_val( ROW_VALUES(row)+5, DB1_STRING, 1, 0);
- str_vals[3] = (char*)VAL_STRING(ROW_VALUES(row)+5);
- /* DSTLIST column */
- check_val( ROW_VALUES(row)+6, DB1_STRING, 1, 1);
- str_vals[4] = (char*)VAL_STRING(ROW_VALUES(row)+6);
- /* parse the time definition */
- if ((time_rec=parse_time_def(str_vals[2]))==0) {
- LM_ERR("bad time definition <%s> for rule id %d -> skipping\n",
- str_vals[2], int_vals[0]);
- continue;
- }
- /* lookup for the script route ID */
- if (str_vals[3][0] && str_vals[3][0]!='0') {
- int_vals[3] = route_lookup(&main_rt, str_vals[3]);
- if (int_vals[3]==-1) {
- LM_WARN("route <%s> does not exist\n",str_vals[3]);
- int_vals[3] = 0;
- }
- } else {
- int_vals[3] = 0;
- }
- /* is gw_list a list or a list id? */
- if (str_vals[4][0]=='#') {
- s_id.s = str_vals[4]+1;
- s_id.len = strlen(s_id.s);
- if ( str2int( &s_id, &id)!=0 ||
- (str_vals[4]=get_tmp_gw_list(id))==NULL ) {
- LM_ERR("invalid reference to a GW list <%s> -> skipping\n",
- str_vals[4]);
- continue;
- }
- }
- /* build the routing rule */
- if ((ri = build_rt_info( int_vals[2], time_rec, int_vals[3],
- str_vals[4], rdata->pgw_l))== 0 ) {
- LM_ERR("failed to add routing info for rule id %d -> "
- "skipping\n", int_vals[0]);
- tmrec_free( time_rec );
- continue;
- }
- /* add the rule */
- if (add_rule( rdata, str_vals[0], &tmp, ri)!=0) {
- LM_ERR("failed to add rule id %d -> skipping\n", int_vals[0]);
- free_rt_info( ri );
- continue;
- }
- n++;
- }
- if (DB_CAPABILITY(*dr_dbf, DB_CAP_FETCH)) {
- if(dr_dbf->fetch_result(db_hdl, &res, dr_fetch_rows)<0) {
- LM_ERR( "fetching rows (1)\n");
- goto error;
- }
- } else {
- break;
- }
- } while(RES_ROW_N(res)>0);
- dr_dbf->free_result(db_hdl, res);
- res = 0;
- free_tmp_gw_list();
- if (n==0) {
- LM_WARN("no valid routing rules -> discarding all destinations\n");
- free_rt_data( rdata, 0 );
- }
- return rdata;
- error:
- if (res)
- dr_dbf->free_result(db_hdl, res);
- if (rdata)
- free_rt_data( rdata, 1 );
- rdata = NULL;
- return 0;
- }
|