modules_k/usrloc/ul_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  */
00035 
00054 #include <stdio.h>
00055 #include "ul_mod.h"
00056 #include "../../sr_module.h"
00057 #include "../../dprint.h"
00058 #include "../../rpc_lookup.h"
00059 #include "../../timer.h"     /* register_timer */
00060 #include "../../timer_proc.h" /* register_sync_timer */
00061 #include "../../globals.h"   /* is_main */
00062 #include "../../ut.h"        /* str_init */
00063 #include "../../lib/srutils/sruid.h"
00064 #include "dlist.h"           /* register_udomain */
00065 #include "udomain.h"         /* {insert,delete,get,release}_urecord */
00066 #include "urecord.h"         /* {insert,delete,get}_ucontact */
00067 #include "ucontact.h"        /* update_ucontact */
00068 #include "ul_mi.h"
00069 #include "ul_rpc.h"
00070 #include "ul_callback.h"
00071 #include "usrloc.h"
00072 
00073 MODULE_VERSION
00074 
00075 #define RUID_COL       "ruid"
00076 #define USER_COL       "username"
00077 #define DOMAIN_COL     "domain"
00078 #define CONTACT_COL    "contact"
00079 #define EXPIRES_COL    "expires"
00080 #define Q_COL          "q"
00081 #define CALLID_COL     "callid"
00082 #define CSEQ_COL       "cseq"
00083 #define FLAGS_COL      "flags"
00084 #define CFLAGS_COL     "cflags"
00085 #define USER_AGENT_COL "user_agent"
00086 #define RECEIVED_COL   "received"
00087 #define PATH_COL       "path"
00088 #define SOCK_COL       "socket"
00089 #define METHODS_COL    "methods"
00090 #define INSTANCE_COL   "instance"
00091 #define REG_ID_COL     "reg_id"
00092 #define LAST_MOD_COL   "last_modified"
00093 
00094 static int mod_init(void);                          
00095 static void destroy(void);                          
00096 static void ul_core_timer(unsigned int ticks, void* param);  
00097 static void ul_local_timer(unsigned int ticks, void* param); 
00098 static int child_init(int rank);                    
00099 static int mi_child_init(void);
00100 
00101 #define UL_PRELOAD_SIZE 8
00102 static char* ul_preload_list[UL_PRELOAD_SIZE];
00103 static int ul_preload_index = 0;
00104 static int ul_preload_param(modparam_t type, void* val);
00105 
00106 extern int bind_usrloc(usrloc_api_t* api);
00107 extern int ul_locks_no;
00108 int ul_db_update_as_insert = 0;
00109 int ul_timer_procs = 0;
00110 
00111 /* sruid to get internal uid for mi/rpc commands */
00112 sruid_t _ul_sruid;
00113 
00114 /*
00115  * Module parameters and their default values
00116  */
00117 
00118 str ruid_col        = str_init(RUID_COL);               
00119 str user_col        = str_init(USER_COL);               
00120 str domain_col      = str_init(DOMAIN_COL);     
00121 str contact_col     = str_init(CONTACT_COL);    
00122 str expires_col     = str_init(EXPIRES_COL);    
00123 str q_col           = str_init(Q_COL);                  
00124 str callid_col      = str_init(CALLID_COL);             
00125 str cseq_col        = str_init(CSEQ_COL);               
00126 str flags_col       = str_init(FLAGS_COL);              
00127 str cflags_col      = str_init(CFLAGS_COL);             
00128 str user_agent_col  = str_init(USER_AGENT_COL); 
00129 str received_col    = str_init(RECEIVED_COL);   
00130 str path_col        = str_init(PATH_COL);               
00131 str sock_col        = str_init(SOCK_COL);               
00132 str methods_col     = str_init(METHODS_COL);    
00133 str instance_col    = str_init(INSTANCE_COL);   
00134 str reg_id_col      = str_init(REG_ID_COL);             
00135 str last_mod_col    = str_init(LAST_MOD_COL);   
00136 str db_url          = str_init(DEFAULT_DB_URL); 
00137 int timer_interval  = 60;                               
00138 int db_mode         = 0;                                
00139 int use_domain      = 0;                                
00140 int desc_time_order = 0;                                
00142 int ul_fetch_rows = 2000;                               
00143 int ul_hash_size = 9;
00144 
00145 /* flags */
00146 unsigned int nat_bflag = (unsigned int)-1;
00147 unsigned int init_flag = 0;
00148 
00149 db1_con_t* ul_dbh = 0; /* Database connection handle */
00150 db_func_t ul_dbf;
00151 
00152 
00153 
00157 static cmd_export_t cmds[] = {
00158         {"ul_bind_usrloc",        (cmd_function)bind_usrloc,        1, 0, 0, 0},
00159         {0, 0, 0, 0, 0, 0}
00160 };
00161 
00162 
00166 static param_export_t params[] = {
00167         {"ruid_column",         STR_PARAM, &ruid_col.s      },
00168         {"user_column",         STR_PARAM, &user_col.s      },
00169         {"domain_column",       STR_PARAM, &domain_col.s    },
00170         {"contact_column",      STR_PARAM, &contact_col.s   },
00171         {"expires_column",      STR_PARAM, &expires_col.s   },
00172         {"q_column",            STR_PARAM, &q_col.s         },
00173         {"callid_column",       STR_PARAM, &callid_col.s    },
00174         {"cseq_column",         STR_PARAM, &cseq_col.s      },
00175         {"flags_column",        STR_PARAM, &flags_col.s     },
00176         {"cflags_column",       STR_PARAM, &cflags_col.s    },
00177         {"db_url",              STR_PARAM, &db_url.s        },
00178         {"timer_interval",      INT_PARAM, &timer_interval  },
00179         {"db_mode",             INT_PARAM, &db_mode         },
00180         {"use_domain",          INT_PARAM, &use_domain      },
00181         {"desc_time_order",     INT_PARAM, &desc_time_order },
00182         {"user_agent_column",   STR_PARAM, &user_agent_col.s},
00183         {"received_column",     STR_PARAM, &received_col.s  },
00184         {"path_column",         STR_PARAM, &path_col.s      },
00185         {"socket_column",       STR_PARAM, &sock_col.s      },
00186         {"methods_column",      STR_PARAM, &methods_col.s   },
00187         {"instance_column",     STR_PARAM, &instance_col.s  },
00188         {"reg_id_column",       STR_PARAM, &reg_id_col.s    },
00189         {"matching_mode",       INT_PARAM, &matching_mode   },
00190         {"cseq_delay",          INT_PARAM, &cseq_delay      },
00191         {"fetch_rows",          INT_PARAM, &ul_fetch_rows   },
00192         {"hash_size",           INT_PARAM, &ul_hash_size    },
00193         {"nat_bflag",           INT_PARAM, &nat_bflag       },
00194         {"preload",             STR_PARAM|USE_FUNC_PARAM, (void*)ul_preload_param},
00195         {"db_update_as_insert", INT_PARAM, &ul_db_update_as_insert},
00196         {"timer_procs",         INT_PARAM, &ul_timer_procs},
00197         {0, 0, 0}
00198 };
00199 
00200 
00201 stat_export_t mod_stats[] = {
00202         {"registered_users" ,  STAT_IS_FUNC, (stat_var**)get_number_of_users  },
00203         {0,0,0}
00204 };
00205 
00206 
00207 static mi_export_t mi_cmds[] = {
00208         { MI_USRLOC_RM,           mi_usrloc_rm_aor,       0,                 0,
00209                                 mi_child_init },
00210         { MI_USRLOC_RM_CONTACT,   mi_usrloc_rm_contact,   0,                 0,
00211                                 mi_child_init },
00212         { MI_USRLOC_DUMP,         mi_usrloc_dump,         0,                 0,
00213                                 0             },
00214         { MI_USRLOC_FLUSH,        mi_usrloc_flush,        MI_NO_INPUT_FLAG,  0,
00215                                 mi_child_init },
00216         { MI_USRLOC_ADD,          mi_usrloc_add,          0,                 0,
00217                                 mi_child_init },
00218         { MI_USRLOC_SHOW_CONTACT, mi_usrloc_show_contact, 0,                 0,
00219                                 mi_child_init },
00220         { 0, 0, 0, 0, 0}
00221 };
00222 
00223 
00224 struct module_exports exports = {
00225         "usrloc",
00226         DEFAULT_DLFLAGS, 
00227         cmds,       
00228         params,     
00229         mod_stats,  
00230         mi_cmds,    
00231         0,          
00232         0,          
00233         mod_init,   
00234         0,          
00235         destroy,    
00236         child_init  
00237 };
00238 
00239 
00243 static int mod_init(void)
00244 {
00245         int i;
00246         udomain_t* d;
00247 
00248         if(sruid_init(&_ul_sruid, '-', "ulcx", SRUID_INC)<0)
00249                 return -1;
00250 
00251 #ifdef STATISTICS
00252         /* register statistics */
00253         if (register_module_stats( exports.name, mod_stats)!=0 ) {
00254                 LM_ERR("failed to register core statistics\n");
00255                 return -1;
00256         }
00257 #endif
00258         
00259         if(register_mi_mod(exports.name, mi_cmds)!=0)
00260         {
00261                 LM_ERR("failed to register MI commands\n");
00262                 return -1;
00263         }
00264 
00265         if (rpc_register_array(ul_rpc)!=0)
00266         {
00267                 LM_ERR("failed to register RPC commands\n");
00268                 return -1;
00269         }
00270 
00271         /* Compute the lengths of string parameters */
00272         ruid_col.len = strlen(ruid_col.s);
00273         user_col.len = strlen(user_col.s);
00274         domain_col.len = strlen(domain_col.s);
00275         contact_col.len = strlen(contact_col.s);
00276         expires_col.len = strlen(expires_col.s);
00277         q_col.len = strlen(q_col.s);
00278         callid_col.len = strlen(callid_col.s);
00279         cseq_col.len = strlen(cseq_col.s);
00280         flags_col.len = strlen(flags_col.s);
00281         cflags_col.len = strlen(cflags_col.s);
00282         user_agent_col.len = strlen(user_agent_col.s);
00283         received_col.len = strlen(received_col.s);
00284         path_col.len = strlen(path_col.s);
00285         sock_col.len = strlen(sock_col.s);
00286         methods_col.len = strlen(methods_col.s);
00287         instance_col.len = strlen(instance_col.s);
00288         reg_id_col.len = strlen(reg_id_col.s);
00289         last_mod_col.len = strlen(last_mod_col.s);
00290         db_url.len = strlen(db_url.s);
00291 
00292         if(ul_hash_size<=1)
00293                 ul_hash_size = 512;
00294         else
00295                 ul_hash_size = 1<<ul_hash_size;
00296         ul_locks_no = ul_hash_size;
00297 
00298         /* check matching mode */
00299         switch (matching_mode) {
00300                 case CONTACT_ONLY:
00301                 case CONTACT_CALLID:
00302                 case CONTACT_PATH:
00303                         break;
00304                 default:
00305                         LM_ERR("invalid matching mode %d\n", matching_mode);
00306         }
00307 
00308         if(ul_init_locks()!=0)
00309         {
00310                 LM_ERR("locks array initialization failed\n");
00311                 return -1;
00312         }
00313 
00314         /* Register cache timer */
00315         if(ul_timer_procs<=0)
00316                 register_timer(ul_core_timer, 0, timer_interval);
00317         else
00318                 register_sync_timers(ul_timer_procs);
00319 
00320         /* init the callbacks list */
00321         if ( init_ulcb_list() < 0) {
00322                 LM_ERR("usrloc/callbacks initialization failed\n");
00323                 return -1;
00324         }
00325 
00326         /* Shall we use database ? */
00327         if (db_mode != NO_DB) { /* Yes */
00328                 if (db_bind_mod(&db_url, &ul_dbf) < 0) { /* Find database module */
00329                         LM_ERR("failed to bind database module\n");
00330                         return -1;
00331                 }
00332                 if (!DB_CAPABILITY(ul_dbf, DB_CAP_ALL)) {
00333                         LM_ERR("database module does not implement all functions"
00334                                         " needed by the module\n");
00335                         return -1;
00336                 }
00337                 if(ul_fetch_rows<=0) {
00338                         LM_ERR("invalid fetch_rows number '%d'\n", ul_fetch_rows);
00339                         return -1;
00340                 }
00341         }
00342 
00343         if (nat_bflag==(unsigned int)-1) {
00344                 nat_bflag = 0;
00345         } else if ( nat_bflag>=8*sizeof(nat_bflag) ) {
00346                 LM_ERR("bflag index (%d) too big!\n", nat_bflag);
00347                 return -1;
00348         } else {
00349                 nat_bflag = 1<<nat_bflag;
00350         }
00351 
00352         for(i=0; i<ul_preload_index; i++) {
00353                 if(register_udomain((const char*)ul_preload_list[i], &d)<0) {
00354                         LM_ERR("cannot register preloaded table %s\n", ul_preload_list[i]);
00355                         return -1;
00356                 }
00357         }
00358         init_flag = 1;
00359 
00360         return 0;
00361 }
00362 
00363 
00364 static int child_init(int _rank)
00365 {
00366         dlist_t* ptr;
00367         int i;
00368 
00369         if(_rank==PROC_MAIN && ul_timer_procs>0)
00370         {
00371                 for(i=0; i<ul_timer_procs; i++)
00372                 {
00373                         if(fork_sync_timer(PROC_TIMER, "USRLOC Timer", 1 /*socks flag*/,
00374                                         ul_local_timer, (void*)(long)i, timer_interval /*sec*/)<0) {
00375                                 LM_ERR("failed to start timer routine as process\n");
00376                                 return -1; /* error */
00377                         }
00378                 }
00379         }
00380 
00381         /* connecting to DB ? */
00382         switch (db_mode) {
00383                 case NO_DB:
00384                         return 0;
00385                 case DB_ONLY:
00386                 case WRITE_THROUGH:
00387                         /* we need connection from working SIP and TIMER and MAIN
00388                          * processes only */
00389                         if (_rank<=0 && _rank!=PROC_TIMER && _rank!=PROC_MAIN)
00390                                 return 0;
00391                         break;
00392                 case WRITE_BACK:
00393                         /* connect only from TIMER (for flush), from MAIN (for
00394                          * final flush() and from child 1 for preload */
00395                         if (_rank!=PROC_TIMER && _rank!=PROC_MAIN && _rank!=1)
00396                                 return 0;
00397                         break;
00398         }
00399 
00400         ul_dbh = ul_dbf.init(&db_url); /* Get a database connection per child */
00401         if (!ul_dbh) {
00402                 LM_ERR("child(%d): failed to connect to database\n", _rank);
00403                 return -1;
00404         }
00405         /* _rank==PROC_SIPINIT is used even when fork is disabled */
00406         if (_rank==PROC_SIPINIT && db_mode!= DB_ONLY) {
00407                 /* if cache is used, populate domains from DB */
00408                 for( ptr=root ; ptr ; ptr=ptr->next) {
00409                         if (preload_udomain(ul_dbh, ptr->d) < 0) {
00410                                 LM_ERR("child(%d): failed to preload domain '%.*s'\n",
00411                                                 _rank, ptr->name.len, ZSW(ptr->name.s));
00412                                 return -1;
00413                         }
00414                 }
00415         }
00416 
00417         return 0;
00418 }
00419 
00420 
00421 /* */
00422 static int mi_child_init(void)
00423 {
00424         static int done = 0;
00425 
00426         if (done)
00427                 return 0;
00428 
00429         if (db_mode != NO_DB) {
00430                 ul_dbh = ul_dbf.init(&db_url);
00431                 if (!ul_dbh) {
00432                         LM_ERR("failed to connect to database\n");
00433                         return -1;
00434                 }
00435         }
00436         done = 1;
00437 
00438         return 0;
00439 }
00440 
00441 
00445 static void destroy(void)
00446 {
00447         /* we need to sync DB in order to flush the cache */
00448         if (ul_dbh) {
00449                 ul_unlock_locks();
00450                 if (synchronize_all_udomains(0, 1) != 0) {
00451                         LM_ERR("flushing cache failed\n");
00452                 }
00453                 ul_dbf.close(ul_dbh);
00454         }
00455 
00456         free_all_udomains();
00457         ul_destroy_locks();
00458 
00459         /* free callbacks list */
00460         destroy_ulcb_list();
00461 }
00462 
00463 
00467 static void ul_core_timer(unsigned int ticks, void* param)
00468 {
00469         if (synchronize_all_udomains(0, 1) != 0) {
00470                 LM_ERR("synchronizing cache failed\n");
00471         }
00472 }
00473 
00477 static void ul_local_timer(unsigned int ticks, void* param)
00478 {
00479         if (synchronize_all_udomains((int)(long)param, ul_timer_procs) != 0) {
00480                 LM_ERR("synchronizing cache failed\n");
00481         }
00482 }
00483 
00487 static int ul_preload_param(modparam_t type, void* val)
00488 {
00489         if(val==NULL)
00490         {
00491                 LM_ERR("invalid parameter\n");
00492                 goto error;
00493         }
00494         if(ul_preload_index>=UL_PRELOAD_SIZE)
00495         {
00496                 LM_ERR("too many preloaded tables\n");
00497                 goto error;
00498         }
00499         ul_preload_list[ul_preload_index] = (char*)val;
00500         ul_preload_index++;
00501         return 0;
00502 error:
00503         return -1;
00504 }