udomain.c

Go to the documentation of this file.
00001 /*
00002  * $Id: udomain.c 5272 2008-11-27 12:32:26Z henningw $ 
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * ---------
00024  * 2003-03-11 changed to the new locking scheme: locking.h (andrei)
00025  * 2003-03-12 added replication mark and zombie state (nils)
00026  * 2004-06-07 updated to the new DB api (andrei)
00027  * 2004-08-23  hash function changed to process characters as unsigned
00028  *             -> no negative results occur (jku)
00029  */
00030 
00031 /*! \file
00032  *  \brief USRLOC - Userloc domain handling functions
00033  *  \ingroup usrloc
00034  *
00035  * - Module: \ref usrloc
00036  */
00037 
00038 #include "udomain.h"
00039 #include <string.h>
00040 #include "../../parser/parse_methods.h"
00041 #include "../../mem/shm_mem.h"
00042 #include "../../dprint.h"
00043 #include "../../db/db.h"
00044 #include "../../socket_info.h"
00045 #include "../../ut.h"
00046 #include "../../hash_func.h"
00047 #include "ul_mod.h"            /* usrloc module parameters */
00048 #include "utime.h"
00049 
00050 
00051 #ifdef STATISTICS
00052 static char *build_stat_name( str* domain, char *var_name)
00053 {
00054    int n;
00055    char *s;
00056    char *p;
00057 
00058    n = domain->len + 1 + strlen(var_name) + 1;
00059    s = (char*)shm_malloc( n );
00060    if (s==0) {
00061       LM_ERR("no more shm mem\n");
00062       return 0;
00063    }
00064    memcpy( s, domain->s, domain->len);
00065    p = s + domain->len;
00066    *(p++) = '-';
00067    memcpy( p , var_name, strlen(var_name));
00068    p += strlen(var_name);
00069    *(p++) = 0;
00070    return s;
00071 }
00072 #endif
00073 
00074 
00075 /*!
00076  * \brief Create a new domain structure
00077  * \param  _n is pointer to str representing name of the domain, the string is
00078  * not copied, it should point to str structure stored in domain list
00079  * \param _s is hash table size
00080  * \param _d new created domain
00081  * \return 0 on success, -1 on failure
00082  */
00083 int new_udomain(str* _n, int _s, udomain_t** _d)
00084 {
00085    int i;
00086 #ifdef STATISTICS
00087    char *name;
00088 #endif
00089    
00090    /* Must be always in shared memory, since
00091     * the cache is accessed from timer which
00092     * lives in a separate process
00093     */
00094    *_d = (udomain_t*)shm_malloc(sizeof(udomain_t));
00095    if (!(*_d)) {
00096       LM_ERR("new_udomain(): No memory left\n");
00097       goto error0;
00098    }
00099    memset(*_d, 0, sizeof(udomain_t));
00100    
00101    (*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s);
00102    if (!(*_d)->table) {
00103       LM_ERR("no memory left 2\n");
00104       goto error1;
00105    }
00106 
00107    (*_d)->name = _n;
00108    
00109    for(i = 0; i < _s; i++) {
00110       init_slot(*_d, &((*_d)->table[i]), i);
00111    }
00112 
00113    (*_d)->size = _s;
00114 
00115 #ifdef STATISTICS
00116    /* register the statistics */
00117    if ( (name=build_stat_name(_n,"users"))==0 || register_stat("usrloc",
00118    name, &(*_d)->users, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
00119       LM_ERR("failed to add stat variable\n");
00120       goto error2;
00121    }
00122    if ( (name=build_stat_name(_n,"contacts"))==0 || register_stat("usrloc",
00123    name, &(*_d)->contacts, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
00124       LM_ERR("failed to add stat variable\n");
00125       goto error2;
00126    }
00127    if ( (name=build_stat_name(_n,"expires"))==0 || register_stat("usrloc",
00128    name, &(*_d)->expires, STAT_SHM_NAME)!=0 ) {
00129       LM_ERR("failed to add stat variable\n");
00130       goto error2;
00131    }
00132 #endif
00133 
00134    return 0;
00135 error2:
00136    shm_free((*_d)->table);
00137 error1:
00138    shm_free(*_d);
00139 error0:
00140    return -1;
00141 }
00142 
00143 
00144 /*!
00145  * \brief Free all memory allocated for the domain
00146  * \param _d freed domain
00147  */
00148 void free_udomain(udomain_t* _d)
00149 {
00150    int i;
00151    
00152    if (_d->table) {
00153       for(i = 0; i < _d->size; i++) {
00154          lock_ulslot(_d, i);
00155          deinit_slot(_d->table + i);
00156          unlock_ulslot(_d, i);
00157       }
00158       shm_free(_d->table);
00159    }
00160    shm_free(_d);
00161 }
00162 
00163 
00164 /*!
00165  * \brief Returns a static dummy urecord for temporary usage
00166  * \param _d domain (needed for the name)
00167  * \param _aor address of record
00168  * \param _r new created urecord
00169  */
00170 static inline void get_static_urecord(udomain_t* _d, str* _aor,
00171                                           struct urecord** _r)
00172 {
00173    static struct urecord r;
00174 
00175    memset( &r, 0, sizeof(struct urecord) );
00176    r.aor = *_aor;
00177    r.domain = _d->name;
00178    *_r = &r;
00179 }
00180 
00181 
00182 /*!
00183  * \brief Debugging helper function
00184  */
00185 void print_udomain(FILE* _f, udomain_t* _d)
00186 {
00187    int i;
00188    int max=0, slot=0, n=0;
00189    struct urecord* r;
00190    fprintf(_f, "---Domain---\n");
00191    fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
00192    fprintf(_f, "size : %d\n", _d->size);
00193    fprintf(_f, "table: %p\n", _d->table);
00194    /*fprintf(_f, "lock : %d\n", _d->lock); -- can be a structure --andrei*/
00195    fprintf(_f, "\n");
00196    for(i=0; i<_d->size; i++)
00197    {
00198       r = _d->table[i].first;
00199       n += _d->table[i].n;
00200       if(max<_d->table[i].n){
00201          max= _d->table[i].n;
00202          slot = i;
00203       }
00204       while(r) {
00205          print_urecord(_f, r);
00206          r = r->next;
00207       }
00208    }
00209    fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n);
00210    fprintf(_f, "\n---/Domain---\n");
00211 }
00212 
00213 
00214 /*!
00215  * \brief Convert database values into ucontact_info
00216  *
00217  * Convert database values into ucontact_info, 
00218  * expects 12 rows (contact, expirs, q, callid, cseq, flags,
00219  * ua, received, path, socket, methods, last_modified)
00220  * \param vals database values
00221  * \param contact contact
00222  * \return pointer to the ucontact_info on success, 0 on failure
00223  */
00224 static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact)
00225 {
00226    static ucontact_info_t ci;
00227    static str callid, ua, received, host, path;
00228    int port, proto;
00229    char *p;
00230 
00231    memset( &ci, 0, sizeof(ucontact_info_t));
00232 
00233    contact->s = (char*)VAL_STRING(vals);
00234    if (VAL_NULL(vals) || contact->s==0 || contact->s[0]==0) {
00235       LM_CRIT("bad contact\n");
00236       return 0;
00237    }
00238    contact->len = strlen(contact->s);
00239 
00240    if (VAL_NULL(vals+1)) {
00241       LM_CRIT("empty expire\n");
00242       return 0;
00243    }
00244    ci.expires = VAL_TIME(vals+1);
00245 
00246    if (VAL_NULL(vals+2)) {
00247       LM_CRIT("empty q\n");
00248       return 0;
00249    }
00250    ci.q = double2q(VAL_DOUBLE(vals+2));
00251 
00252    if (VAL_NULL(vals+4)) {
00253       LM_CRIT("empty cseq_nr\n");
00254       return 0;
00255    }
00256    ci.cseq = VAL_INT(vals+4);
00257 
00258    callid.s = (char*)VAL_STRING(vals+3);
00259    if (VAL_NULL(vals+3) || !callid.s || !callid.s[0]) {
00260       LM_CRIT("bad callid\n");
00261       return 0;
00262    }
00263    callid.len  = strlen(callid.s);
00264    ci.callid = &callid;
00265 
00266    if (VAL_NULL(vals+5)) {
00267       LM_CRIT("empty flag\n");
00268       return 0;
00269    }
00270    ci.flags  = VAL_BITMAP(vals+5);
00271 
00272    if (VAL_NULL(vals+6)) {
00273       LM_CRIT("empty cflag\n");
00274       return 0;
00275    }
00276    ci.cflags  = VAL_BITMAP(vals+6);
00277 
00278    ua.s  = (char*)VAL_STRING(vals+7);
00279    if (VAL_NULL(vals+7) || !ua.s || !ua.s[0]) {
00280       ua.s = 0;
00281       ua.len = 0;
00282    } else {
00283       ua.len = strlen(ua.s);
00284    }
00285    ci.user_agent = &ua;
00286 
00287    received.s  = (char*)VAL_STRING(vals+8);
00288    if (VAL_NULL(vals+8) || !received.s || !received.s[0]) {
00289       received.len = 0;
00290       received.s = 0;
00291    } else {
00292       received.len = strlen(received.s);
00293    }
00294    ci.received = received;
00295    
00296    path.s  = (char*)VAL_STRING(vals+9);
00297       if (VAL_NULL(vals+9) || !path.s || !path.s[0]) {
00298          path.len = 0;
00299          path.s = 0;
00300       } else {
00301          path.len = strlen(path.s);
00302       }
00303    ci.path= &path;
00304 
00305    /* socket name */
00306    p  = (char*)VAL_STRING(vals+10);
00307    if (VAL_NULL(vals+10) || p==0 || p[0]==0){
00308       ci.sock = 0;
00309    } else {
00310       if (parse_phostport( p, strlen(p), &host.s, &host.len, 
00311       &port, &proto)!=0) {
00312          LM_ERR("bad socket <%s>\n", p);
00313          return 0;
00314       }
00315       ci.sock = grep_sock_info( &host, (unsigned short)port, proto);
00316       if (ci.sock==0) {
00317          LM_WARN("non-local socket <%s>...ignoring\n", p);
00318       }
00319    }
00320 
00321    /* supported methods */
00322    if (VAL_NULL(vals+11)) {
00323       ci.methods = ALL_METHODS;
00324    } else {
00325       ci.methods = VAL_BITMAP(vals+11);
00326    }
00327 
00328    /* last modified time */
00329    if (!VAL_NULL(vals+12)) {
00330       ci.last_modified = VAL_TIME(vals+12);
00331    }
00332 
00333    return &ci;
00334 }
00335 
00336 
00337 /*!
00338  * \brief Load all records from a udomain
00339  *
00340  * Load all records from a udomain, useful to populate the
00341  * memory cache on startup.
00342  * \param _c database connection
00343  * \param _d loaded domain
00344  * \return 0 on success, -1 on failure
00345  */
00346 int preload_udomain(db_con_t* _c, udomain_t* _d)
00347 {
00348    char uri[MAX_URI_SIZE];
00349    ucontact_info_t *ci;
00350    db_row_t *row;
00351    db_key_t columns[15];
00352    db_res_t* res = NULL;
00353    str user, contact;
00354    char* domain;
00355    int i;
00356    int n;
00357 
00358    urecord_t* r;
00359    ucontact_t* c;
00360 
00361    columns[0] = &user_col;
00362    columns[1] = &contact_col;
00363    columns[2] = &expires_col;
00364    columns[3] = &q_col;
00365    columns[4] = &callid_col;
00366    columns[5] = &cseq_col;
00367    columns[6] = &flags_col;
00368    columns[7] = &cflags_col;
00369    columns[8] = &user_agent_col;
00370    columns[9] = &received_col;
00371    columns[10] = &path_col;
00372    columns[11] = &sock_col;
00373    columns[12] = &methods_col;
00374    columns[13] = &last_mod_col;
00375    columns[14] = &domain_col;
00376 
00377    if (ul_dbf.use_table(_c, _d->name) < 0) {
00378       LM_ERR("sql use_table failed\n");
00379       return -1;
00380    }
00381 
00382 #ifdef EXTRA_DEBUG
00383    LM_NOTICE("load start time [%d]\n", (int)time(NULL));
00384 #endif
00385 
00386    if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
00387       if (ul_dbf.query(_c, 0, 0, 0, columns, 0, (use_domain)?(15):(14), 0,
00388       0) < 0) {
00389          LM_ERR("db_query (1) failed\n");
00390          return -1;
00391       }
00392       if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
00393          LM_ERR("fetching rows failed\n");
00394          return -1;
00395       }
00396    } else {
00397       if (ul_dbf.query(_c, 0, 0, 0, columns, 0, (use_domain)?(15):(14), 0,
00398       &res) < 0) {
00399          LM_ERR("db_query failed\n");
00400          return -1;
00401       }
00402    }
00403 
00404    if (RES_ROW_N(res) == 0) {
00405       LM_DBG("table is empty\n");
00406       ul_dbf.free_result(_c, res);
00407       return 0;
00408    }
00409 
00410 
00411    n = 0;
00412    do {
00413       LM_DBG("loading records - cycle [%d]\n", ++n);
00414       for(i = 0; i < RES_ROW_N(res); i++) {
00415          row = RES_ROWS(res) + i;
00416 
00417          user.s = (char*)VAL_STRING(ROW_VALUES(row));
00418          if (VAL_NULL(ROW_VALUES(row)) || user.s==0 || user.s[0]==0) {
00419             LM_CRIT("empty username record in table %s...skipping\n",
00420                   _d->name->s);
00421             continue;
00422          }
00423          user.len = strlen(user.s);
00424 
00425          ci = dbrow2info( ROW_VALUES(row)+1, &contact);
00426          if (ci==0) {
00427             LM_ERR("sipping record for %.*s in table %s\n",
00428                   user.len, user.s, _d->name->s);
00429             continue;
00430          }
00431 
00432          if (use_domain) {
00433             domain = (char*)VAL_STRING(ROW_VALUES(row) + 14);
00434             if (VAL_NULL(ROW_VALUES(row)+13) || domain==0 || domain[0]==0){
00435                LM_CRIT("empty domain record for user %.*s...skipping\n",
00436                      user.len, user.s);
00437                continue;
00438             }
00439             /* user.s cannot be NULL - checked previosly */
00440             user.len = snprintf(uri, MAX_URI_SIZE, "%.*s@%s",
00441                user.len, user.s, domain);
00442             user.s = uri;
00443             if (user.s[user.len]!=0) {
00444                LM_CRIT("URI '%.*s@%s' longer than %d\n", user.len, user.s,
00445                      domain,  MAX_URI_SIZE);
00446                continue;
00447             }
00448          }
00449 
00450       
00451          lock_udomain(_d, &user);
00452          if (get_urecord(_d, &user, &r) > 0) {
00453             if (mem_insert_urecord(_d, &user, &r) < 0) {
00454                LM_ERR("failed to create a record\n");
00455                unlock_udomain(_d, &user);
00456                goto error;
00457             }
00458          }
00459 
00460          if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
00461             LM_ERR("inserting contact failed\n");
00462             unlock_udomain(_d, &user);
00463             goto error1;
00464          }
00465 
00466          /* We have to do this, because insert_ucontact sets state to CS_NEW
00467           * and we have the contact in the database already */
00468          c->state = CS_SYNC;
00469          unlock_udomain(_d, &user);
00470       }
00471 
00472       if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
00473          if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
00474             LM_ERR("fetching rows (1) failed\n");
00475             ul_dbf.free_result(_c, res);
00476             return -1;
00477          }
00478       } else {
00479          break;
00480       }
00481    } while(RES_ROW_N(res)>0);
00482 
00483    ul_dbf.free_result(_c, res);
00484 
00485 #ifdef EXTRA_DEBUG
00486    LM_NOTICE("load end time [%d]\n", (int)time(NULL));
00487 #endif
00488 
00489    return 0;
00490 error1:
00491    free_ucontact(c);
00492 error:
00493    ul_dbf.free_result(_c, res);
00494    return -1;
00495 }
00496 
00497 
00498 /*!
00499  * \brief Loads from DB all contacts for an AOR
00500  * \param _c database connection
00501  * \param _d domain
00502  * \param _aor address of record
00503  * \return pointer to the record on success, 0 on errors or if nothing is found
00504  */
00505 urecord_t* db_load_urecord(db_con_t* _c, udomain_t* _d, str *_aor)
00506 {
00507    ucontact_info_t *ci;
00508    db_key_t columns[13];
00509    db_key_t keys[2];
00510    db_key_t order;
00511    db_val_t vals[2];
00512    db_res_t* res = NULL;
00513    str contact;
00514    char *domain;
00515    int i;
00516 
00517    urecord_t* r;
00518    ucontact_t* c;
00519 
00520    keys[0] = &user_col;
00521    vals[0].type = DB_STR;
00522    vals[0].nul = 0;
00523    if (use_domain) {
00524       keys[1] = &domain_col;
00525       vals[1].type = DB_STR;
00526       vals[1].nul = 0;
00527       domain = memchr(_aor->s, '@', _aor->len);
00528       vals[0].val.str_val.s   = _aor->s;
00529       if (domain==0) {
00530          vals[0].val.str_val.len = 0;
00531          vals[1].val.str_val = *_aor;
00532       } else {
00533          vals[0].val.str_val.len = domain - _aor->s;
00534          vals[1].val.str_val.s   = domain+1;
00535          vals[1].val.str_val.len = _aor->s + _aor->len - domain - 1;
00536       }
00537    } else {
00538       vals[0].val.str_val = *_aor;
00539    }
00540 
00541    columns[0] = &contact_col;
00542    columns[1] = &expires_col;
00543    columns[2] = &q_col;
00544    columns[3] = &callid_col;
00545    columns[4] = &cseq_col;
00546    columns[5] = &flags_col;
00547    columns[6] = &cflags_col;
00548    columns[7] = &user_agent_col;
00549    columns[8] = &received_col;
00550    columns[9] = &path_col;
00551    columns[10] = &sock_col;
00552    columns[11] = &methods_col;
00553    columns[12] = &last_mod_col;
00554 
00555    if (desc_time_order)
00556       order = &last_mod_col;
00557    else
00558       order = &q_col;
00559 
00560    if (ul_dbf.use_table(_c, _d->name) < 0) {
00561       LM_ERR("failed to use table %.*s\n", _d->name->len, _d->name->s);
00562       return 0;
00563    }
00564 
00565    if (ul_dbf.query(_c, keys, 0, vals, columns, (use_domain)?2:1, 13, order,
00566             &res) < 0) {
00567       LM_ERR("db_query failed\n");
00568       return 0;
00569    }
00570 
00571    if (RES_ROW_N(res) == 0) {
00572       LM_DBG("aor %.*s not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
00573       ul_dbf.free_result(_c, res);
00574       return 0;
00575    }
00576 
00577    r = 0;
00578 
00579    for(i = 0; i < RES_ROW_N(res); i++) {
00580       ci = dbrow2info(  ROW_VALUES(RES_ROWS(res) + i), &contact);
00581       if (ci==0) {
00582          LM_ERR("skipping record for %.*s in table %s\n",
00583                _aor->len, _aor->s, _d->name->s);
00584          continue;
00585       }
00586       
00587       if ( r==0 )
00588          get_static_urecord( _d, _aor, &r);
00589 
00590       if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
00591          LM_ERR("mem_insert failed\n");
00592          free_urecord(r);
00593          ul_dbf.free_result(_c, res);
00594          return 0;
00595       }
00596 
00597       /* We have to do this, because insert_ucontact sets state to CS_NEW
00598        * and we have the contact in the database already */
00599       c->state = CS_SYNC;
00600    }
00601 
00602    ul_dbf.free_result(_c, res);
00603    return r;
00604 }
00605 
00606 
00607 /*!
00608  * \brief Timer function to cleanup expired contacts, DB_ONLY db_mode
00609  * \param _d cleaned domain
00610  * \return 0 on success, -1 on failure
00611  */
00612 int db_timer_udomain(udomain_t* _d)
00613 {
00614    db_key_t keys[2];
00615    db_op_t  ops[2];
00616    db_val_t vals[2];
00617 
00618    keys[0] = &expires_col;
00619    ops[0] = "<";
00620    vals[0].type = DB_DATETIME;
00621    vals[0].nul = 0;
00622    vals[0].val.time_val = act_time + 1;
00623 
00624    keys[1] = &expires_col;
00625    ops[1] = "!=";
00626    vals[1].type = DB_DATETIME;
00627    vals[1].nul = 0;
00628    vals[1].val.time_val = 0;
00629 
00630    if (ul_dbf.use_table(ul_dbh, _d->name) < 0) {
00631       LM_ERR("use_table failed\n");
00632       return -1;
00633    }
00634 
00635    if (ul_dbf.delete(ul_dbh, keys, ops, vals, 2) < 0) {
00636       LM_ERR("failed to delete from table %s\n",_d->name->s);
00637       return -1;
00638    }
00639 
00640    return 0;
00641 }
00642 
00643 
00644 /*!
00645  * \brief performs a dummy query just to see if DB is ok
00646  * \param con database connection
00647  * \param d domain
00648  */
00649 int testdb_udomain(db_con_t* con, udomain_t* d)
00650 {
00651    db_key_t key[1], col[1];
00652    db_val_t val[1];
00653    db_res_t* res = NULL;
00654 
00655    if (ul_dbf.use_table(con, d->name) < 0) {
00656       LM_ERR("failed to change table\n");
00657       return -1;
00658    }
00659 
00660    key[0] = &user_col;
00661 
00662    col[0] = &user_col;
00663    VAL_TYPE(val) = DB_STRING;
00664    VAL_NULL(val) = 0;
00665    VAL_STRING(val) = "dummy_user";
00666    
00667    if (ul_dbf.query( con, key, 0, val, col, 1, 1, 0, &res) < 0) {
00668       LM_ERR("failure in db_query\n");
00669       return -1;
00670    }
00671 
00672    ul_dbf.free_result( con, res);
00673    return 0;
00674 }
00675 
00676 
00677 /*!
00678  * \brief Insert a new record into domain in memory
00679  * \param _d domain the record belongs to
00680  * \param _aor address of record
00681  * \param _r new created record
00682  * \return 0 on success, -1 on failure
00683  */
00684 int mem_insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
00685 {
00686    int sl;
00687    
00688    if (new_urecord(_d->name, _aor, _r) < 0) {
00689       LM_ERR("creating urecord failed\n");
00690       return -1;
00691    }
00692 
00693    sl = ((*_r)->aorhash)&(_d->size-1);
00694    slot_add(&_d->table[sl], *_r);
00695    update_stat( _d->users, 1);
00696    return 0;
00697 }
00698 
00699 
00700 /*!
00701  * \brief Remove a record from domain in memory
00702  * \param _d domain the record belongs to
00703  * \param _r deleted record
00704  */
00705 void mem_delete_urecord(udomain_t* _d, struct urecord* _r)
00706 {
00707    slot_rem(_r->slot, _r);
00708    free_urecord(_r);
00709    update_stat( _d->users, -1);
00710 }
00711 
00712 
00713 /*!
00714  * \brief Run timer handler for given domain
00715  * \param _d domain
00716  */
00717 void mem_timer_udomain(udomain_t* _d)
00718 {
00719    struct urecord* ptr, *t;
00720    int i;
00721 
00722    for(i=0; i<_d->size; i++)
00723    {
00724       lock_ulslot(_d, i);
00725 
00726       ptr = _d->table[i].first;
00727 
00728       while(ptr) {
00729          timer_urecord(ptr);
00730          /* Remove the entire record if it is empty */
00731          if (ptr->contacts == 0) {
00732             t = ptr;
00733             ptr = ptr->next;
00734             mem_delete_urecord(_d, t);
00735          } else {
00736             ptr = ptr->next;
00737          }
00738       }
00739       unlock_ulslot(_d, i);
00740    }
00741 }
00742 
00743 
00744 /*!
00745  * \brief Get lock for a domain
00746  * \param _d domain
00747  * \param _aor adress of record, used as hash source for the lock slot
00748  */
00749 void lock_udomain(udomain_t* _d, str* _aor)
00750 {
00751    unsigned int sl;
00752    if (db_mode!=DB_ONLY)
00753    {
00754       sl = core_hash(_aor, 0, _d->size);
00755 
00756 #ifdef GEN_LOCK_T_PREFERED
00757       lock_get(_d->table[sl].lock);
00758 #else
00759       ul_lock_idx(_d->table[sl].lockidx);
00760 #endif
00761    }
00762 }
00763 
00764 
00765 /*!
00766  * \brief Release lock for a domain
00767  * \param _d domain
00768  * \param _aor address of record, uses as hash source for the lock slot
00769  */
00770 void unlock_udomain(udomain_t* _d, str* _aor)
00771 {
00772    unsigned int sl;
00773    if (db_mode!=DB_ONLY)
00774    {
00775       sl = core_hash(_aor, 0, _d->size);
00776 #ifdef GEN_LOCK_T_PREFERED
00777       lock_release(_d->table[sl].lock);
00778 #else
00779       ul_release_idx(_d->table[sl].lockidx);
00780 #endif
00781    }
00782 }
00783 
00784 /*!
00785  * \brief  Get lock for a slot
00786  * \param _d domain
00787  * \param i slot number
00788  */
00789 void lock_ulslot(udomain_t* _d, int i)
00790 {
00791    if (db_mode!=DB_ONLY)
00792 #ifdef GEN_LOCK_T_PREFERED
00793       lock_get(_d->table[i].lock);
00794 #else
00795       ul_lock_idx(_d->table[i].lockidx);
00796 #endif
00797 }
00798 
00799 
00800 /*!
00801  * \brief Release lock for a slot
00802  * \param _d domain
00803  * \param i slot number
00804  */
00805 void unlock_ulslot(udomain_t* _d, int i)
00806 {
00807    if (db_mode!=DB_ONLY)
00808 #ifdef GEN_LOCK_T_PREFERED
00809       lock_release(_d->table[i].lock);
00810 #else
00811       ul_release_idx(_d->table[i].lockidx);
00812 #endif
00813 }
00814 
00815 
00816 
00817 /*!
00818  * \brief Create and insert a new record
00819  * \param _d domain to insert the new record
00820  * \param _aor address of the record
00821  * \param _r new created record
00822  * \return return 0 on success, -1 on failure
00823  */
00824 int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
00825 {
00826    if (db_mode!=DB_ONLY) {
00827       if (mem_insert_urecord(_d, _aor, _r) < 0) {
00828          LM_ERR("inserting record failed\n");
00829          return -1;
00830       }
00831    } else {
00832       get_static_urecord( _d, _aor, _r);
00833    }
00834    return 0;
00835 }
00836 
00837 
00838 /*!
00839  * \brief Obtain a urecord pointer if the urecord exists in domain
00840  * \param _d domain to search the record
00841  * \param _aor address of record
00842  * \param _r new created record
00843  * \return 0 if a record was found, 1 if nothing could be found
00844  */
00845 int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
00846 {
00847    unsigned int sl, i, aorhash;
00848    urecord_t* r;
00849 
00850    if (db_mode!=DB_ONLY) {
00851       /* search in cache */
00852       aorhash = core_hash(_aor, 0, 0);
00853       sl = aorhash&(_d->size-1);
00854       r = _d->table[sl].first;
00855 
00856       for(i = 0; i < _d->table[sl].n; i++) {
00857          if((r->aorhash==aorhash) && (r->aor.len==_aor->len)
00858                   && !memcmp(r->aor.s,_aor->s,_aor->len)){
00859             *_r = r;
00860             return 0;
00861          }
00862 
00863          r = r->next;
00864       }
00865    } else {
00866       /* search in DB */
00867       r = db_load_urecord( ul_dbh, _d, _aor);
00868       if (r) {
00869          *_r = r;
00870          return 0;
00871       }
00872    }
00873 
00874    return 1;   /* Nothing found */
00875 }
00876 
00877 
00878 /*!
00879  * \brief Delete a urecord from domain
00880  * \param _d domain where the record should be deleted
00881  * \param _aor address of record
00882  * \param _r deleted record
00883  * \return 0 on success, -1 if the record could not be deleted
00884  */
00885 int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r)
00886 {
00887    struct ucontact* c, *t;
00888 
00889    if (db_mode==DB_ONLY) {
00890       if (_r==0)
00891          get_static_urecord( _d, _aor, &_r);
00892       if (db_delete_urecord(_r)<0) {
00893          LM_ERR("DB delete failed\n");
00894          return -1;
00895       }
00896       free_urecord(_r);
00897       return 0;
00898    }
00899 
00900    if (_r==0) {
00901       if (get_urecord(_d, _aor, &_r) > 0) {
00902          return 0;
00903       }
00904    }
00905 
00906    c = _r->contacts;
00907    while(c) {
00908       t = c;
00909       c = c->next;
00910       if (delete_ucontact(_r, t) < 0) {
00911          LM_ERR("deleting contact failed\n");
00912          return -1;
00913       }
00914    }
00915    release_urecord(_r);
00916    return 0;
00917 }

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