ul_mod.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ul_mod.c 5193 2008-11-13 10:21:53Z henningw $
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 
00036 /*! \file
00037  *  \brief USRLOC - Usrloc module interface
00038  *  \ingroup usrloc
00039  *
00040  * - Module \ref usrloc
00041  */
00042 
00043 /*!
00044  * \defgroup usrloc Usrloc :: User location module
00045  * \brief User location module
00046  *
00047  * The module keeps a user location table and provides access
00048  * to the table to other modules. The module exports no functions
00049  * that could be used directly from scripts, all access is done
00050  * over a API. A main user of this API is the registrar module.
00051  * \see registrar
00052  */
00053 
00054 #include <stdio.h>
00055 #include "ul_mod.h"
00056 #include "../../sr_module.h"
00057 #include "../../dprint.h"
00058 #include "../../timer.h"     /* register_timer */
00059 #include "../../globals.h"   /* is_main */
00060 #include "../../ut.h"        /* str_init */
00061 #include "dlist.h"           /* register_udomain */
00062 #include "udomain.h"         /* {insert,delete,get,release}_urecord */
00063 #include "urecord.h"         /* {insert,delete,get}_ucontact */
00064 #include "ucontact.h"        /* update_ucontact */
00065 #include "ul_mi.h"
00066 #include "ul_callback.h"
00067 #include "usrloc.h"
00068 
00069 MODULE_VERSION
00070 
00071 #define USER_COL       "username"
00072 #define DOMAIN_COL     "domain"
00073 #define CONTACT_COL    "contact"
00074 #define EXPIRES_COL    "expires"
00075 #define Q_COL          "q"
00076 #define CALLID_COL     "callid"
00077 #define CSEQ_COL       "cseq"
00078 #define FLAGS_COL      "flags"
00079 #define CFLAGS_COL     "cflags"
00080 #define USER_AGENT_COL "user_agent"
00081 #define RECEIVED_COL   "received"
00082 #define PATH_COL       "path"
00083 #define SOCK_COL       "socket"
00084 #define METHODS_COL    "methods"
00085 #define LAST_MOD_COL   "last_modified"
00086 
00087 static int mod_init(void);                          /*!< Module initialization function */
00088 static void destroy(void);                          /*!< Module destroy function */
00089 static void timer(unsigned int ticks, void* param); /*!< Timer handler */
00090 static int child_init(int rank);                    /*!< Per-child init function */
00091 static int mi_child_init(void);
00092 
00093 extern int bind_usrloc(usrloc_api_t* api);
00094 extern int ul_locks_no;
00095 /*
00096  * Module parameters and their default values
00097  */
00098 
00099 str user_col        = str_init(USER_COL);       /*!< Name of column containing usernames */
00100 str domain_col      = str_init(DOMAIN_COL);     /*!< Name of column containing domains */
00101 str contact_col     = str_init(CONTACT_COL);    /*!< Name of column containing contact addresses */
00102 str expires_col     = str_init(EXPIRES_COL);    /*!< Name of column containing expires values */
00103 str q_col           = str_init(Q_COL);       /*!< Name of column containing q values */
00104 str callid_col      = str_init(CALLID_COL);     /*!< Name of column containing callid string */
00105 str cseq_col        = str_init(CSEQ_COL);    /*!< Name of column containing cseq values */
00106 str flags_col       = str_init(FLAGS_COL);      /*!< Name of column containing internal flags */
00107 str cflags_col      = str_init(CFLAGS_COL);     /*!< Name of column containing contact flags */
00108 str user_agent_col  = str_init(USER_AGENT_COL);    /*!< Name of column containing user agent string */
00109 str received_col    = str_init(RECEIVED_COL);      /*!< Name of column containing transport info of REGISTER */
00110 str path_col        = str_init(PATH_COL);    /*!< Name of column containing the Path header */
00111 str sock_col        = str_init(SOCK_COL);    /*!< Name of column containing the received socket */
00112 str methods_col     = str_init(METHODS_COL);    /*!< Name of column containing the supported methods */
00113 str last_mod_col     = str_init(LAST_MOD_COL);     /*!< Name of column containing the last modified date */
00114 str db_url          = str_init(DEFAULT_DB_URL);    /*!< Database URL */
00115 int timer_interval  = 60;           /*!< Timer interval in seconds */
00116 int db_mode         = 0;            /*!< Database sync scheme: 0-no db, 1-write through, 2-write back, 3-only db */
00117 int use_domain      = 0;            /*!< Whether usrloc should use domain part of aor */
00118 int desc_time_order = 0;            /*!< By default do not enable timestamp ordering */
00119 
00120 int ul_fetch_rows = 2000;           /*!< number of rows to fetch from result */
00121 int ul_hash_size = 9;
00122 
00123 /* flags */
00124 unsigned int nat_bflag = (unsigned int)-1;
00125 unsigned int init_flag = 0;
00126 
00127 db_con_t* ul_dbh = 0; /* Database connection handle */
00128 db_func_t ul_dbf;
00129 
00130 
00131 
00132 /*! \brief
00133  * Exported functions
00134  */
00135 static cmd_export_t cmds[] = {
00136    {"ul_bind_usrloc",        (cmd_function)bind_usrloc,        1, 0, 0, 0},
00137    {0, 0, 0, 0, 0, 0}
00138 };
00139 
00140 
00141 /*! \brief
00142  * Exported parameters 
00143  */
00144 static param_export_t params[] = {
00145    {"user_column",       STR_PARAM, &user_col.s      },
00146    {"domain_column",     STR_PARAM, &domain_col.s    },
00147    {"contact_column",    STR_PARAM, &contact_col.s   },
00148    {"expires_column",    STR_PARAM, &expires_col.s   },
00149    {"q_column",          STR_PARAM, &q_col.s         },
00150    {"callid_column",     STR_PARAM, &callid_col.s    },
00151    {"cseq_column",       STR_PARAM, &cseq_col.s      },
00152    {"flags_column",      STR_PARAM, &flags_col.s     },
00153    {"cflags_column",     STR_PARAM, &cflags_col.s    },
00154    {"db_url",            STR_PARAM, &db_url.s        },
00155    {"timer_interval",    INT_PARAM, &timer_interval  },
00156    {"db_mode",           INT_PARAM, &db_mode         },
00157    {"use_domain",        INT_PARAM, &use_domain      },
00158    {"desc_time_order",   INT_PARAM, &desc_time_order },
00159    {"user_agent_column", STR_PARAM, &user_agent_col.s},
00160    {"received_column",   STR_PARAM, &received_col.s  },
00161    {"path_column",       STR_PARAM, &path_col.s      },
00162    {"socket_column",     STR_PARAM, &sock_col.s      },
00163    {"methods_column",    STR_PARAM, &methods_col.s   },
00164    {"matching_mode",     INT_PARAM, &matching_mode   },
00165    {"cseq_delay",        INT_PARAM, &cseq_delay      },
00166    {"fetch_rows",        INT_PARAM, &ul_fetch_rows   },
00167    {"hash_size",         INT_PARAM, &ul_hash_size    },
00168    {"nat_bflag",         INT_PARAM, &nat_bflag       },
00169    {0, 0, 0}
00170 };
00171 
00172 
00173 stat_export_t mod_stats[] = {
00174    {"registered_users" ,  STAT_IS_FUNC, (stat_var**)get_number_of_users  },
00175    {0,0,0}
00176 };
00177 
00178 
00179 static mi_export_t mi_cmds[] = {
00180    { MI_USRLOC_RM,           mi_usrloc_rm_aor,       0,                 0,
00181             mi_child_init },
00182    { MI_USRLOC_RM_CONTACT,   mi_usrloc_rm_contact,   0,                 0,
00183             mi_child_init },
00184    { MI_USRLOC_DUMP,         mi_usrloc_dump,         0,                 0,
00185             0             },
00186    { MI_USRLOC_FLUSH,        mi_usrloc_flush,        MI_NO_INPUT_FLAG,  0,
00187             mi_child_init },
00188    { MI_USRLOC_ADD,          mi_usrloc_add,          0,                 0,
00189             mi_child_init },
00190    { MI_USRLOC_SHOW_CONTACT, mi_usrloc_show_contact, 0,                 0,
00191             mi_child_init },
00192    { 0, 0, 0, 0, 0}
00193 };
00194 
00195 
00196 struct module_exports exports = {
00197    "usrloc",
00198    DEFAULT_DLFLAGS, /*!< dlopen flags */
00199    cmds,       /*!< Exported functions */
00200    params,     /*!< Export parameters */
00201    mod_stats,  /*!< exported statistics */
00202    mi_cmds,    /*!< exported MI functions */
00203    0,          /*!< exported pseudo-variables */
00204    0,          /*!< extra processes */
00205    mod_init,   /*!< Module initialization function */
00206    0,          /*!< Response function */
00207    destroy,    /*!< Destroy function */
00208    child_init  /*!< Child initialization function */
00209 };
00210 
00211 
00212 /*! \brief
00213  * Module initialization function
00214  */
00215 static int mod_init(void)
00216 {
00217    /* Compute the lengths of string parameters */
00218    user_col.len = strlen(user_col.s);
00219    domain_col.len = strlen(domain_col.s);
00220    contact_col.len = strlen(contact_col.s);
00221    expires_col.len = strlen(expires_col.s);
00222    q_col.len = strlen(q_col.s);
00223    callid_col.len = strlen(callid_col.s);
00224    cseq_col.len = strlen(cseq_col.s);
00225    flags_col.len = strlen(flags_col.s);
00226    cflags_col.len = strlen(cflags_col.s);
00227    user_agent_col.len = strlen(user_agent_col.s);
00228    received_col.len = strlen(received_col.s);
00229    path_col.len = strlen(path_col.s);
00230    sock_col.len = strlen(sock_col.s);
00231    methods_col.len = strlen(methods_col.s);
00232    last_mod_col.len = strlen(last_mod_col.s);
00233    db_url.len = strlen(db_url.s);
00234 
00235    if(ul_hash_size<=1)
00236       ul_hash_size = 512;
00237    else
00238       ul_hash_size = 1<<ul_hash_size;
00239    ul_locks_no = ul_hash_size;
00240 
00241    /* check matching mode */
00242    switch (matching_mode) {
00243       case CONTACT_ONLY:
00244       case CONTACT_CALLID:
00245          break;
00246       default:
00247          LM_ERR("invalid matching mode %d\n", matching_mode);
00248    }
00249 
00250    if(ul_init_locks()!=0)
00251    {
00252       LM_ERR("locks array initialization failed\n");
00253       return -1;
00254    }
00255 
00256    /* Register cache timer */
00257    register_timer( timer, 0, timer_interval);
00258 
00259    /* init the callbacks list */
00260    if ( init_ulcb_list() < 0) {
00261       LM_ERR("usrloc/callbacks initialization failed\n");
00262       return -1;
00263    }
00264 
00265    /* Shall we use database ? */
00266    if (db_mode != NO_DB) { /* Yes */
00267       if (db_bind_mod(&db_url, &ul_dbf) < 0) { /* Find database module */
00268          LM_ERR("failed to bind database module\n");
00269          return -1;
00270       }
00271       if (!DB_CAPABILITY(ul_dbf, DB_CAP_ALL)) {
00272          LM_ERR("database module does not implement all functions"
00273                " needed by the module\n");
00274          return -1;
00275       }
00276       if(ul_fetch_rows<=0) {
00277          LM_ERR("invalid fetch_rows number '%d'\n", ul_fetch_rows);
00278          return -1;
00279       }
00280    }
00281 
00282    if (nat_bflag==(unsigned int)-1) {
00283       nat_bflag = 0;
00284    } else if ( nat_bflag>=8*sizeof(nat_bflag) ) {
00285       LM_ERR("bflag index (%d) too big!\n", nat_bflag);
00286       return -1;
00287    } else {
00288       nat_bflag = 1<<nat_bflag;
00289    }
00290 
00291    init_flag = 1;
00292 
00293    return 0;
00294 }
00295 
00296 
00297 static int child_init(int _rank)
00298 {
00299    dlist_t* ptr;
00300 
00301    /* connecting to DB ? */
00302    switch (db_mode) {
00303       case NO_DB:
00304          return 0;
00305       case DB_ONLY:
00306       case WRITE_THROUGH:
00307          /* we need connection from working SIP and TIMER and MAIN
00308           * processes only */
00309          if (_rank<=0 && _rank!=PROC_TIMER && _rank!=PROC_MAIN)
00310             return 0;
00311          break;
00312       case WRITE_BACK:
00313          /* connect only from TIMER (for flush), from MAIN (for
00314           * final flush() and from child 1 for preload */
00315          if (_rank!=PROC_TIMER && _rank!=PROC_MAIN && _rank!=1)
00316             return 0;
00317          break;
00318    }
00319 
00320    ul_dbh = ul_dbf.init(&db_url); /* Get a new database connection */
00321    if (!ul_dbh) {
00322       LM_ERR("child(%d): failed to connect to database\n", _rank);
00323       return -1;
00324    }
00325    /* _rank==1 is used even when fork is disabled */
00326    if (_rank==1 && db_mode!= DB_ONLY) {
00327       /* if cache is used, populate domains from DB */
00328       for( ptr=root ; ptr ; ptr=ptr->next) {
00329          if (preload_udomain(ul_dbh, ptr->d) < 0) {
00330             LM_ERR("child(%d): failed to preload domain '%.*s'\n",
00331                   _rank, ptr->name.len, ZSW(ptr->name.s));
00332             return -1;
00333          }
00334       }
00335    }
00336 
00337    return 0;
00338 }
00339 
00340 
00341 /* */
00342 static int mi_child_init(void)
00343 {
00344    static int done = 0;
00345 
00346    if (done)
00347       return 0;
00348 
00349    if (db_mode != NO_DB) {
00350       ul_dbh = ul_dbf.init(&db_url);
00351       if (!ul_dbh) {
00352          LM_ERR("failed to connect to database\n");
00353          return -1;
00354       }
00355    }
00356    done = 1;
00357 
00358    return 0;
00359 }
00360 
00361 
00362 /*! \brief
00363  * Module destroy function
00364  */
00365 static void destroy(void)
00366 {
00367    /* we need to sync DB in order to flush the cache */
00368    if (ul_dbh) {
00369       ul_unlock_locks();
00370       if (synchronize_all_udomains() != 0) {
00371          LM_ERR("flushing cache failed\n");
00372       }
00373       ul_dbf.close(ul_dbh);
00374    }
00375 
00376    free_all_udomains();
00377    ul_destroy_locks();
00378 
00379    /* free callbacks list */
00380    destroy_ulcb_list();
00381 }
00382 
00383 
00384 /*! \brief
00385  * Timer handler
00386  */
00387 static void timer(unsigned int ticks, void* param)
00388 {
00389    if (synchronize_all_udomains() != 0) {
00390       LM_ERR("synchronizing cache failed\n");
00391    }
00392 }
00393 

Generated on Thu May 24 22:00:35 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6