p_usrloc_mod.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Usrloc module interface
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * ---------
00026  * 2003-01-27 timer activity printing #ifdef-ed to EXTRA_DEBUG (jiri)
00027  * 2003-03-11 New module interface (janakj)
00028  * 2003-03-12 added replication and state columns (nils)
00029  * 2003-03-16 flags export parameter added (janakj)
00030  * 2003-04-05: default_uri #define used (jiri)
00031  * 2003-04-21 failed fifo init stops init process (jiri)
00032  * 2004-03-17 generic callbacks added (bogdan)
00033  * 2004-06-07 updated to the new DB api (andrei)
00034  * 2011-01-03 extended module definition for partitioned userlocking (marius)
00035  */
00036 
00055 #include <stdio.h>
00056 #include "p_usrloc_mod.h"
00057 #include "../../sr_module.h"
00058 #include "../../dprint.h"
00059 #include "../../rpc_lookup.h"
00060 #include "../../timer_proc.h"
00061 #include "../../globals.h"   /* is_main */
00062 #include "../../ut.h"        /* str_init */
00063 #include "udomain.h"         /* {insert,delete,get,release}_urecord */
00064 #include "urecord.h"         /* {insert,delete,get}_ucontact */
00065 #include "ucontact.h"        /* update_ucontact */
00066 #include "ul_mi.h"
00067 #include "../usrloc/ul_callback.h"
00068 #include "ul_db_api.h"
00069 #include "ul_db_watch.h"
00070 #include "ul_check.h"
00071 #include "ul_db.h"
00072 #include "ul_db_layer.h"
00073 #include "dlist.h"
00074 
00075 MODULE_VERSION
00076 
00077 #define USER_COL       "username"
00078 #define DOMAIN_COL     "domain"
00079 #define CONTACT_COL    "contact"
00080 #define EXPIRES_COL    "expires"
00081 #define Q_COL          "q"
00082 #define CALLID_COL     "callid"
00083 #define CSEQ_COL       "cseq"
00084 #define FLAGS_COL      "flags"
00085 #define CFLAGS_COL      "cflags"
00086 #define USER_AGENT_COL "user_agent"
00087 #define RECEIVED_COL   "received"
00088 #define PATH_COL       "path"
00089 #define SOCK_COL       "socket"
00090 #define METHODS_COL    "methods"
00091 #define LAST_MOD_COL   "last_modified"
00092 
00093 static int mod_init(void);                          
00094 static void destroy(void);                          
00095 static int child_init(int rank);                    
00096 static int mi_child_init(void);
00097 static int mi_child_loc_nr_init(void);
00098 extern int bind_usrloc(usrloc_api_t* api);
00099 extern int ul_locks_no;
00100 /*
00101  * Module parameters and their default values
00102  */
00103 
00138 str user_col        = str_init(USER_COL);               
00139 str domain_col      = str_init(DOMAIN_COL);             
00140 str contact_col     = str_init(CONTACT_COL);            
00141 str expires_col     = str_init(EXPIRES_COL);            
00142 str q_col           = str_init(Q_COL);                  
00143 str callid_col      = str_init(CALLID_COL);             
00144 str cseq_col        = str_init(CSEQ_COL);               
00145 str flags_col       = str_init(FLAGS_COL);              
00146 str cflags_col       = str_init(CFLAGS_COL);
00147 str user_agent_col  = str_init(USER_AGENT_COL);         
00148 str received_col    = str_init(RECEIVED_COL);           
00149 str path_col        = str_init(PATH_COL);               
00150 str sock_col        = str_init(SOCK_COL);               
00151 str methods_col     = str_init(METHODS_COL);            
00152 str last_mod_col     = str_init(LAST_MOD_COL);          
00153 int db_mode         = 3;                                
00154 int use_domain      = 0;                                
00155 int desc_time_order = 0;                                
00157 int ul_fetch_rows = 2000;                               
00158 int ul_hash_size = 9;
00159 str write_db_url         = {DEFAULT_DB_URL, DEFAULT_DB_URL_LEN};
00160 str read_db_url          = {DEFAULT_DB_URL, DEFAULT_DB_URL_LEN};
00161 str reg_table            = {REG_TABLE, sizeof(REG_TABLE) -1};
00162 str id_col               = {ID_COL, sizeof(ID_COL) - 1};
00163 str url_col              = {URL_COL, sizeof(URL_COL) - 1};
00164 str num_col              = {NUM_COL, sizeof(NUM_COL) - 1};
00165 str status_col           = {STATUS_COL, sizeof(STATUS_COL) - 1};
00166 str failover_time_col    = {FAILOVER_T_COL, sizeof(FAILOVER_T_COL) - 1};
00167 str spare_col            = {SPARE_COL, sizeof(SPARE_COL) - 1};
00168 str error_col            = {ERROR_COL, sizeof(ERROR_COL) - 1};
00169 str risk_group_col       = {RISK_GROUP_COL, sizeof(RISK_GROUP_COL) - 1};
00170 int expire_time          = DEFAULT_EXPIRE;
00171 int db_error_threshold   = DEFAULT_ERR_THRESHOLD;
00172 int failover_level       = DEFAULT_FAILOVER_LEVEL;
00173 int retry_interval       = DB_RETRY;
00174 int policy               = DB_DEFAULT_POLICY;
00175 int db_write             = 0;
00176 int db_master_write      = 0;
00177 int alg_location         = 0;
00178 
00179 int db_use_transactions  = 0;
00180 str db_transaction_level = {DB_DEFAULT_TRANSACTION_LEVEL, sizeof(DB_DEFAULT_TRANSACTION_LEVEL) -1};
00181 char * isolation_level;
00182 int connection_expires   = DB_DEFAULT_CONNECTION_EXPIRES;
00183 int max_loc_nr  = 0 ;
00184 
00185 
00186 /* flags */
00187 unsigned int nat_bflag = (unsigned int)-1;
00188 unsigned int init_flag = 0;
00189 
00190 str default_db_url    = str_init(DEFAULT_DB_URL);
00191 str default_db_type   = str_init(DEFAULT_DB_TYPE);
00192 str domain_db         = str_init(DEFAULT_DOMAIN_DB);
00193 int default_dbt       = 0;
00194 int expire            = 0;
00195 
00196 
00200 static cmd_export_t cmds[] = {
00201         {"ul_bind_usrloc",        (cmd_function)bind_usrloc,        1, 0, 0, 0},
00202         {0, 0, 0, 0, 0, 0}
00203 };
00204 
00205 
00209 static param_export_t params[] = {
00210         {"user_column",       STR_PARAM, &user_col.s      },
00211         {"domain_column",     STR_PARAM, &domain_col.s    },
00212         {"contact_column",    STR_PARAM, &contact_col.s   },
00213         {"expires_column",    STR_PARAM, &expires_col.s   },
00214         {"q_column",          STR_PARAM, &q_col.s         },
00215         {"callid_column",     STR_PARAM, &callid_col.s    },
00216         {"cseq_column",       STR_PARAM, &cseq_col.s      },
00217         {"flags_column",      STR_PARAM, &flags_col.s     },
00218         {"cflags_column",     STR_PARAM, &cflags_col.s    },
00219         {"db_mode",           INT_PARAM, &db_mode         },
00220         {"use_domain",        INT_PARAM, &use_domain      },
00221         {"desc_time_order",   INT_PARAM, &desc_time_order },
00222         {"user_agent_column", STR_PARAM, &user_agent_col.s},
00223         {"received_column",   STR_PARAM, &received_col.s  },
00224         {"path_column",       STR_PARAM, &path_col.s      },
00225         {"socket_column",     STR_PARAM, &sock_col.s      },
00226         {"methods_column",    STR_PARAM, &methods_col.s   },
00227         {"matching_mode",     INT_PARAM, &matching_mode   },
00228         {"cseq_delay",        INT_PARAM, &cseq_delay      },
00229         {"fetch_rows",        INT_PARAM, &ul_fetch_rows   },
00230         {"hash_size",         INT_PARAM, &ul_hash_size    },
00231         {"nat_bflag",         INT_PARAM, &nat_bflag       },
00232         {"default_db_url",    STR_PARAM, &default_db_url.s    },
00233         {"default_db_type",   STR_PARAM, &default_db_type.s   },
00234         {"domain_db",         STR_PARAM, &domain_db.s         },
00235         {"write_db_url",         STR_PARAM, &write_db_url.s      },
00236         {"read_db_url",          STR_PARAM, &read_db_url.s       },
00237         {"reg_db_table",         STR_PARAM, &reg_table.s         },
00238         {"id_column",            STR_PARAM, &id_col.s            },
00239         {"num_column",           STR_PARAM, &num_col.s           },
00240         {"url_column",           STR_PARAM, &url_col.s           },
00241         {"status_column",        STR_PARAM, &status_col.s        },
00242         {"failover_time_column", STR_PARAM, &failover_time_col.s },
00243         {"spare_flag_column",    STR_PARAM, &spare_col.s         },
00244         {"error_column",         STR_PARAM, &error_col.s         },
00245         {"risk_group_column",    STR_PARAM, &risk_group_col.s    },
00246         {"expire_time",          INT_PARAM, &expire_time         },
00247         {"db_err_threshold",     INT_PARAM, &db_error_threshold  },
00248         {"failover_level",       INT_PARAM, &failover_level      },
00249         {"db_retry_interval",    INT_PARAM, &retry_interval      },
00250         {"db_use_transactions",  INT_PARAM, &db_use_transactions },
00251         {"db_transaction_level", INT_PARAM, &db_transaction_level},
00252         {"write_on_db",          INT_PARAM, &db_write            },
00253         {"write_on_master_db",   INT_PARAM, &db_master_write     },
00254         {"connection_expires",   INT_PARAM, &connection_expires  },
00255         {"alg_location",         INT_PARAM, &alg_location },
00256         {0, 0, 0}
00257 };
00258 
00259 
00260 stat_export_t mod_stats[] = {
00261         {"registered_users" ,  STAT_IS_FUNC, (stat_var**)get_number_of_users  },
00262         {0,0,0}
00263 };
00264 
00265 
00266 static mi_export_t mi_cmds[] = {
00267         { MI_USRLOC_RM,           mi_usrloc_rm_aor,       0,                 0,
00268                                 mi_child_init },
00269         { MI_USRLOC_RM_CONTACT,   mi_usrloc_rm_contact,   0,                 0,
00270                                 mi_child_init },
00271         { MI_USRLOC_DUMP,         mi_usrloc_dump,         0,                 0,
00272                                 0             },
00273         { MI_USRLOC_FLUSH,        mi_usrloc_flush,        MI_NO_INPUT_FLAG,  0,
00274                                 mi_child_init },
00275         { MI_USRLOC_ADD,          mi_usrloc_add,          0,                 0,
00276                                 mi_child_init },
00277         { MI_USRLOC_SHOW_CONTACT, mi_usrloc_show_contact, 0,                 0,
00278                                 mi_child_init },
00279         { "loc_refresh", mi_ul_db_refresh, MI_NO_INPUT_FLAG,  0, mi_child_init },
00280         { "loc_nr_refresh", mi_loc_nr_refresh, MI_NO_INPUT_FLAG,  0, mi_child_loc_nr_init },
00281         { 0, 0, 0, 0, 0}
00282 };
00283 
00284 
00285 struct module_exports exports = {
00286         "p_usrloc",
00287         DEFAULT_DLFLAGS, 
00288         cmds,       
00289         params,     
00290         mod_stats,  
00291         mi_cmds,    
00292         0,          
00293         0,          
00294         mod_init,   
00295         0,          
00296         destroy,    
00297         child_init  
00298 };
00299 
00300 
00304 static int mod_init(void)
00305 {
00306 #ifdef STATISTICS
00307         /* register statistics */
00308         if (register_module_stats( exports.name, mod_stats)!=0 ) {
00309                 LM_ERR("failed to register core statistics\n");
00310                 return -1;
00311         }
00312 #endif
00313         
00314         if(register_mi_mod(exports.name, mi_cmds)!=0)
00315         {
00316                 LM_ERR("failed to register MI commands\n");
00317                 return -1;
00318         }
00319 
00320 
00321         /* Compute the lengths of string parameters */
00322         user_col.len = strlen(user_col.s);
00323         domain_col.len = strlen(domain_col.s);
00324         contact_col.len = strlen(contact_col.s);
00325         expires_col.len = strlen(expires_col.s);
00326         q_col.len = strlen(q_col.s);
00327         callid_col.len = strlen(callid_col.s);
00328         cseq_col.len = strlen(cseq_col.s);
00329         flags_col.len = strlen(flags_col.s);
00330         cflags_col.len = strlen(cflags_col.s);
00331         user_agent_col.len = strlen(user_agent_col.s);
00332         received_col.len = strlen(received_col.s);
00333         path_col.len = strlen(path_col.s);
00334         sock_col.len = strlen(sock_col.s);
00335         methods_col.len = strlen(methods_col.s);
00336         last_mod_col.len = strlen(last_mod_col.s);
00337         
00338         write_db_url.len = strlen (write_db_url.s);
00339         read_db_url.len = strlen (read_db_url.s);
00340         reg_table.len = strlen(reg_table.s);
00341         id_col.len = strlen(id_col.s);
00342         url_col.len = strlen(url_col.s);
00343         num_col.len = strlen(num_col.s);
00344         status_col.len = strlen(status_col.s);
00345         failover_time_col.len = strlen(failover_time_col.s);
00346         spare_col.len = strlen(spare_col.s);
00347         error_col.len = strlen(error_col.s);
00348         risk_group_col.len = strlen(risk_group_col.s);
00349         db_transaction_level.len = strlen(db_transaction_level.s);
00350 
00351         
00352         if(ul_hash_size<=1)
00353                 ul_hash_size = 512;
00354         else
00355                 ul_hash_size = 1<<ul_hash_size;
00356         ul_locks_no = ul_hash_size;
00357 
00358         /* check matching mode */
00359         switch (matching_mode) {
00360                 case CONTACT_ONLY:
00361                 case CONTACT_CALLID:
00362                 case CONTACT_PATH:
00363                         break;
00364                 default:
00365                         LM_ERR("invalid matching mode %d\n", matching_mode);
00366         }
00367 
00368         if(ul_init_locks()!=0)
00369         {
00370                 LM_ERR("locks array initialization failed\n");
00371                 return -1;
00372         }
00373 
00374         /* init the callbacks list */
00375         if ( init_ulcb_list() < 0) {
00376                 LM_ERR("usrloc/callbacks initialization failed\n");
00377                 return -1;
00378         }
00379 
00380         if (db_mode != DB_ONLY) {
00381                 LM_ERR("DB_ONLY is the only mode possible for partitioned usrloc. Please set db_mode to 3");
00382                 return  -1;
00383         }
00384 
00385         /* Shall we use database ? */
00386         if (db_mode != NO_DB) { /* Yes */
00387                 if(!default_db_url.s || !strlen(default_db_url.s)){
00388                         LM_ERR("must set default_db_url parameter\n");
00389                         return -1;
00390                 }
00391                 default_db_url.len = strlen (default_db_url.s);
00392 
00393                 domain_db.len = strlen(domain_db.s);
00394                 default_db_type.len = strlen(default_db_type.s);
00395                 if(strcmp(DB_TYPE_CLUSTER_STR, default_db_type.s) == 0){
00396                         default_dbt = DB_TYPE_CLUSTER;
00397                 } else {
00398                         default_dbt = DB_TYPE_SINGLE;
00399                 }
00400 
00401                 if (ul_db_layer_init() < 0) {
00402                         return -1;
00403                 }
00404 
00405                 if(ul_fetch_rows<=0) {
00406                         LM_ERR("invalid fetch_rows number '%d'\n", ul_fetch_rows);
00407                         return -1;
00408                 }
00409         }
00410 
00411         if (nat_bflag==(unsigned int)-1) {
00412                 nat_bflag = 0;
00413         } else if ( nat_bflag>=8*sizeof(nat_bflag) ) {
00414                 LM_ERR("bflag index (%d) too big!\n", nat_bflag);
00415                 return -1;
00416         } else {
00417                 nat_bflag = 1<<nat_bflag;
00418         }
00419 
00420         init_flag = 1;
00421         
00422         if((isolation_level = pkg_malloc(strlen("SET TRANSACTION ISOLATION LEVEL ") + db_transaction_level.len + 1)) == NULL){
00423                 LM_ERR("couldn't allocate private memory.\n");
00424                 return -1;
00425         }
00426         sprintf(isolation_level, "SET TRANSACTION ISOLATION LEVEL %s", db_transaction_level.s);
00427         if(init_list() < 0) {
00428                 LM_ERR("could not init check list.\n");
00429                 return -1;
00430         }
00431         if(ul_db_init() < 0){
00432                 LM_ERR("could not initialise databases.\n");
00433                 return -1;
00434         }
00435         if(ul_db_watch_init() < 0){
00436                 LM_ERR("could not init database watch environment.\n");
00437                 return -1;
00438         }
00439         if(db_master_write){
00440                 /* register extra dummy timer to be created in init_db_check() */
00441                 register_dummy_timers(1);
00442         }
00443         return 0;
00444 }
00445 
00446 
00447 static int child_init(int _rank)
00448 {
00449         if(_rank==PROC_INIT) {
00450                 if(init_db_check() < 0){
00451                                 LM_ERR("could not initialise database check.\n");
00452                         return -1;
00453                 }
00454                 return 0;
00455         }
00456         if(ul_db_child_init() < 0){
00457                 LM_ERR("could not initialise databases.\n");
00458                 return -1;
00459         }
00460         
00461 
00462         return 0;
00463 }
00464 
00465 
00466 /* */
00467 static int mi_child_init(void)
00468 {
00469 
00470         return ul_db_child_init();
00471 }
00472 
00473 
00477 static void destroy(void)
00478 {
00479         /* we need to sync DB in order to flush the cache */
00480         ul_unlock_locks();
00481 
00482         free_all_udomains();
00483         ul_destroy_locks();
00484         /* free callbacks list */
00485         destroy_ulcb_list();
00486         
00487         ul_db_shutdown();
00488         destroy_list();
00489         ul_db_watch_destroy();
00490         
00491 }
00492 
00493 
00494 static int mi_child_loc_nr_init(void)
00495 {
00496         if(ul_db_child_locnr_init() < 0){
00497                 LM_ERR("could not retrive location number from database. Try to reinitialize the db handles\n");
00498                 return -1;
00499         }
00500         return 0;
00501 }
00502 
00503 
00504 struct mi_root*  mi_ul_db_refresh(struct mi_root* cmd_tree, void* param) {
00505         int ret;
00506         ret = set_must_refresh();
00507         
00508         LM_INFO("sp-ul_db location databases were refreshed (%i elements).\n", ret);
00509 
00510         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00511 }
00512 
00513 
00514 struct mi_root*  mi_loc_nr_refresh(struct mi_root* cmd_tree, void* param) {
00515         /* this function does nothing, all work is done per each child in the mi_child_loc_nr_init function */
00516         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00517 }