123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398 |
- /*
- * $Id$
- *
- * Copyright (C) 2001-2003 FhG Fokus
- *
- * 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:
- * ---------
- * 2003-03-11 changed to the new locking scheme: locking.h (andrei)
- * 2003-03-12 added replication mark and zombie state (nils)
- * 2004-06-07 updated to the new DB api (andrei)
- * 2004-08-23 hash function changed to process characters as unsigned
- * -> no negative results occur (jku)
- */
- /*! \file
- * \brief USRLOC - Userloc domain handling functions
- * \ingroup usrloc
- *
- * - Module: \ref usrloc
- */
- #include "udomain.h"
- #include <string.h>
- #include "../../parser/parse_methods.h"
- #include "../../mem/shm_mem.h"
- #include "../../dprint.h"
- #include "../../lib/srdb1/db.h"
- #include "../../socket_info.h"
- #include "../../ut.h"
- #include "../../hashes.h"
- #include "ul_mod.h" /* usrloc module parameters */
- #include "usrloc.h"
- #include "utime.h"
- #include "usrloc.h"
- #ifdef STATISTICS
- static char *build_stat_name( str* domain, char *var_name)
- {
- int n;
- char *s;
- char *p;
- n = domain->len + 1 + strlen(var_name) + 1;
- s = (char*)shm_malloc( n );
- if (s==0) {
- LM_ERR("no more shm mem\n");
- return 0;
- }
- memcpy( s, domain->s, domain->len);
- p = s + domain->len;
- *(p++) = '-';
- memcpy( p , var_name, strlen(var_name));
- p += strlen(var_name);
- *(p++) = 0;
- return s;
- }
- #endif
- /*!
- * \brief Create a new domain structure
- * \param _n is pointer to str representing name of the domain, the string is
- * not copied, it should point to str structure stored in domain list
- * \param _s is hash table size
- * \param _d new created domain
- * \return 0 on success, -1 on failure
- */
- int new_udomain(str* _n, int _s, udomain_t** _d)
- {
- int i;
- #ifdef STATISTICS
- char *name;
- #endif
-
- /* Must be always in shared memory, since
- * the cache is accessed from timer which
- * lives in a separate process
- */
- *_d = (udomain_t*)shm_malloc(sizeof(udomain_t));
- if (!(*_d)) {
- LM_ERR("new_udomain(): No memory left\n");
- goto error0;
- }
- memset(*_d, 0, sizeof(udomain_t));
-
- (*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s);
- if (!(*_d)->table) {
- LM_ERR("no memory left 2\n");
- goto error1;
- }
- (*_d)->name = _n;
-
- for(i = 0; i < _s; i++) {
- init_slot(*_d, &((*_d)->table[i]), i);
- }
- (*_d)->size = _s;
- #ifdef STATISTICS
- /* register the statistics */
- if ( (name=build_stat_name(_n,"users"))==0 || register_stat("usrloc",
- name, &(*_d)->users, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
- LM_ERR("failed to add stat variable\n");
- goto error2;
- }
- if ( (name=build_stat_name(_n,"contacts"))==0 || register_stat("usrloc",
- name, &(*_d)->contacts, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
- LM_ERR("failed to add stat variable\n");
- goto error2;
- }
- if ( (name=build_stat_name(_n,"expires"))==0 || register_stat("usrloc",
- name, &(*_d)->expires, STAT_SHM_NAME)!=0 ) {
- LM_ERR("failed to add stat variable\n");
- goto error2;
- }
- #endif
- return 0;
- #ifdef STATISTICS
- error2:
- shm_free((*_d)->table);
- #endif
- error1:
- shm_free(*_d);
- error0:
- return -1;
- }
- /*!
- * \brief Free all memory allocated for the domain
- * \param _d freed domain
- */
- void free_udomain(udomain_t* _d)
- {
- int i;
-
- if (_d->table) {
- for(i = 0; i < _d->size; i++) {
- lock_ulslot(_d, i);
- deinit_slot(_d->table + i);
- unlock_ulslot(_d, i);
- }
- shm_free(_d->table);
- }
- shm_free(_d);
- }
- /*!
- * \brief Returns a static dummy urecord for temporary usage
- * \param _d domain (needed for the name)
- * \param _aor address of record
- * \param _r new created urecord
- */
- static inline void get_static_urecord(udomain_t* _d, str* _aor,
- struct urecord** _r)
- {
- static struct urecord r;
- memset( &r, 0, sizeof(struct urecord) );
- r.aor = *_aor;
- r.aorhash = ul_get_aorhash(_aor);
- r.domain = _d->name;
- *_r = &r;
- }
- /*!
- * \brief Debugging helper function
- */
- void print_udomain(FILE* _f, udomain_t* _d)
- {
- int i;
- int max=0, slot=0, n=0;
- struct urecord* r;
- fprintf(_f, "---Domain---\n");
- fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
- fprintf(_f, "size : %d\n", _d->size);
- fprintf(_f, "table: %p\n", _d->table);
- /*fprintf(_f, "lock : %d\n", _d->lock); -- can be a structure --andrei*/
- fprintf(_f, "\n");
- for(i=0; i<_d->size; i++)
- {
- r = _d->table[i].first;
- n += _d->table[i].n;
- if(max<_d->table[i].n){
- max= _d->table[i].n;
- slot = i;
- }
- while(r) {
- print_urecord(_f, r);
- r = r->next;
- }
- }
- fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n);
- fprintf(_f, "\n---/Domain---\n");
- }
- /*!
- * \brief Convert database values into ucontact_info
- *
- * Convert database values into ucontact_info,
- * expects 12 rows (contact, expirs, q, callid, cseq, flags,
- * ua, received, path, socket, methods, last_modified)
- * \param vals database values
- * \param contact contact
- * \return pointer to the ucontact_info on success, 0 on failure
- */
- static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact)
- {
- static ucontact_info_t ci;
- static str callid, ua, received, host, path;
- int port, proto;
- char *p;
- memset( &ci, 0, sizeof(ucontact_info_t));
- contact->s = (char*)VAL_STRING(vals);
- if (VAL_NULL(vals) || contact->s==0 || contact->s[0]==0) {
- LM_CRIT("bad contact\n");
- return 0;
- }
- contact->len = strlen(contact->s);
- if (VAL_NULL(vals+1)) {
- LM_CRIT("empty expire\n");
- return 0;
- }
- ci.expires = UL_DB_EXPIRES_GET(vals+1);
- if (VAL_NULL(vals+2)) {
- LM_CRIT("empty q\n");
- return 0;
- }
- ci.q = double2q(VAL_DOUBLE(vals+2));
- if (VAL_NULL(vals+4)) {
- LM_CRIT("empty cseq_nr\n");
- return 0;
- }
- ci.cseq = VAL_INT(vals+4);
- callid.s = (char*)VAL_STRING(vals+3);
- if (VAL_NULL(vals+3) || !callid.s || !callid.s[0]) {
- LM_CRIT("bad callid\n");
- return 0;
- }
- callid.len = strlen(callid.s);
- ci.callid = &callid;
- if (VAL_NULL(vals+5)) {
- LM_CRIT("empty flag\n");
- return 0;
- }
- ci.flags = VAL_BITMAP(vals+5);
- if (VAL_NULL(vals+6)) {
- LM_CRIT("empty cflag\n");
- return 0;
- }
- ci.cflags = VAL_BITMAP(vals+6);
- ua.s = (char*)VAL_STRING(vals+7);
- if (VAL_NULL(vals+7) || !ua.s || !ua.s[0]) {
- ua.s = 0;
- ua.len = 0;
- } else {
- ua.len = strlen(ua.s);
- }
- ci.user_agent = &ua;
- received.s = (char*)VAL_STRING(vals+8);
- if (VAL_NULL(vals+8) || !received.s || !received.s[0]) {
- received.len = 0;
- received.s = 0;
- } else {
- received.len = strlen(received.s);
- }
- ci.received = received;
-
- path.s = (char*)VAL_STRING(vals+9);
- if (VAL_NULL(vals+9) || !path.s || !path.s[0]) {
- path.len = 0;
- path.s = 0;
- } else {
- path.len = strlen(path.s);
- }
- ci.path= &path;
- /* socket name */
- p = (char*)VAL_STRING(vals+10);
- if (VAL_NULL(vals+10) || p==0 || p[0]==0){
- ci.sock = 0;
- } else {
- if (parse_phostport( p, &host.s, &host.len,
- &port, &proto)!=0) {
- LM_ERR("bad socket <%s>\n", p);
- return 0;
- }
- ci.sock = grep_sock_info( &host, (unsigned short)port, proto);
- if (ci.sock==0) {
- LM_INFO("non-local socket <%s>...ignoring\n", p);
- }
- }
- /* supported methods */
- if (VAL_NULL(vals+11)) {
- ci.methods = ALL_METHODS;
- } else {
- ci.methods = VAL_BITMAP(vals+11);
- }
- /* last modified time */
- if (!VAL_NULL(vals+12)) {
- ci.last_modified = UL_DB_EXPIRES_GET(vals+12);
- }
- /* record internal uid */
- if (!VAL_NULL(vals+13)) {
- ci.ruid.s = (char*)VAL_STRING(vals+13);
- ci.ruid.len = strlen(ci.ruid.s);
- }
- /* sip instance */
- if (!VAL_NULL(vals+14)) {
- ci.instance.s = (char*)VAL_STRING(vals+14);
- ci.instance.len = strlen(ci.instance.s);
- }
- /* reg-id */
- if (!VAL_NULL(vals+15)) {
- ci.reg_id = VAL_UINT(vals+15);
- }
- /* tcp connection id */
- ci.tcpconn_id = -1;
- return &ci;
- }
- /*!
- * \brief Load all records from a udomain
- *
- * Load all records from a udomain, useful to populate the
- * memory cache on startup.
- * \param _c database connection
- * \param _d loaded domain
- * \return 0 on success, -1 on failure
- */
- int preload_udomain(db1_con_t* _c, udomain_t* _d)
- {
- char uri[MAX_URI_SIZE];
- ucontact_info_t *ci;
- db_row_t *row;
- db_key_t columns[18];
- db1_res_t* res = NULL;
- str user, contact;
- char* domain;
- int i;
- int n;
- urecord_t* r;
- ucontact_t* c;
- columns[0] = &user_col;
- columns[1] = &contact_col;
- columns[2] = &expires_col;
- columns[3] = &q_col;
- columns[4] = &callid_col;
- columns[5] = &cseq_col;
- columns[6] = &flags_col;
- columns[7] = &cflags_col;
- columns[8] = &user_agent_col;
- columns[9] = &received_col;
- columns[10] = &path_col;
- columns[11] = &sock_col;
- columns[12] = &methods_col;
- columns[13] = &last_mod_col;
- columns[14] = &ruid_col;
- columns[15] = &instance_col;
- columns[16] = ®_id_col;
- columns[17] = &domain_col;
- if (ul_dbf.use_table(_c, _d->name) < 0) {
- LM_ERR("sql use_table failed\n");
- return -1;
- }
- #ifdef EXTRA_DEBUG
- LM_NOTICE("load start time [%d]\n", (int)time(NULL));
- #endif
- if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
- if (ul_dbf.query(_c, 0, 0, 0, columns, 0, (use_domain)?(18):(17), 0,
- 0) < 0) {
- LM_ERR("db_query (1) failed\n");
- return -1;
- }
- if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
- LM_ERR("fetching rows failed\n");
- return -1;
- }
- } else {
- if (ul_dbf.query(_c, 0, 0, 0, columns, 0, (use_domain)?(18):(17), 0,
- &res) < 0) {
- LM_ERR("db_query failed\n");
- return -1;
- }
- }
- if (RES_ROW_N(res) == 0) {
- LM_DBG("table is empty\n");
- ul_dbf.free_result(_c, res);
- return 0;
- }
- n = 0;
- do {
- LM_DBG("loading records - cycle [%d]\n", ++n);
- for(i = 0; i < RES_ROW_N(res); i++) {
- row = RES_ROWS(res) + i;
- user.s = (char*)VAL_STRING(ROW_VALUES(row));
- if (VAL_NULL(ROW_VALUES(row)) || user.s==0 || user.s[0]==0) {
- LM_CRIT("empty username record in table %s...skipping\n",
- _d->name->s);
- continue;
- }
- user.len = strlen(user.s);
- ci = dbrow2info( ROW_VALUES(row)+1, &contact);
- if (ci==0) {
- LM_ERR("sipping record for %.*s in table %s\n",
- user.len, user.s, _d->name->s);
- continue;
- }
- if (use_domain) {
- domain = (char*)VAL_STRING(ROW_VALUES(row) + 17);
- if (VAL_NULL(ROW_VALUES(row)+17) || domain==0 || domain[0]==0){
- LM_CRIT("empty domain record for user %.*s...skipping\n",
- user.len, user.s);
- continue;
- }
- /* user.s cannot be NULL - checked previosly */
- user.len = snprintf(uri, MAX_URI_SIZE, "%.*s@%s",
- user.len, user.s, domain);
- user.s = uri;
- if (user.s[user.len]!=0) {
- LM_CRIT("URI '%.*s@%s' longer than %d\n", user.len, user.s,
- domain, MAX_URI_SIZE);
- continue;
- }
- }
-
- lock_udomain(_d, &user);
- if (get_urecord(_d, &user, &r) > 0) {
- if (mem_insert_urecord(_d, &user, &r) < 0) {
- LM_ERR("failed to create a record\n");
- unlock_udomain(_d, &user);
- goto error;
- }
- }
- if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
- LM_ERR("inserting contact failed\n");
- unlock_udomain(_d, &user);
- goto error1;
- }
- /* We have to do this, because insert_ucontact sets state to CS_NEW
- * and we have the contact in the database already */
- c->state = CS_SYNC;
- unlock_udomain(_d, &user);
- }
- if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
- if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
- LM_ERR("fetching rows (1) failed\n");
- ul_dbf.free_result(_c, res);
- return -1;
- }
- } else {
- break;
- }
- } while(RES_ROW_N(res)>0);
- ul_dbf.free_result(_c, res);
- #ifdef EXTRA_DEBUG
- LM_NOTICE("load end time [%d]\n", (int)time(NULL));
- #endif
- return 0;
- error1:
- free_ucontact(c);
- error:
- ul_dbf.free_result(_c, res);
- return -1;
- }
- /*!
- * \brief Loads from DB all contacts for an AOR
- * \param _c database connection
- * \param _d domain
- * \param _aor address of record
- * \return pointer to the record on success, 0 on errors or if nothing is found
- */
- urecord_t* db_load_urecord(db1_con_t* _c, udomain_t* _d, str *_aor)
- {
- char tname_buf[64];
- str tname;
- ucontact_info_t *ci;
- db_key_t columns[16];
- db_key_t keys[2];
- db_key_t order;
- db_val_t vals[2];
- db1_res_t* res = NULL;
- db_row_t *row;
- str aname;
- str avalue;
- sr_xval_t aval;
- str contact;
- char *domain;
- int i;
- urecord_t* r;
- ucontact_t* c;
- keys[0] = &user_col;
- vals[0].type = DB1_STR;
- vals[0].nul = 0;
- if (use_domain) {
- keys[1] = &domain_col;
- vals[1].type = DB1_STR;
- vals[1].nul = 0;
- domain = memchr(_aor->s, '@', _aor->len);
- vals[0].val.str_val.s = _aor->s;
- if (domain==0) {
- vals[0].val.str_val.len = 0;
- vals[1].val.str_val = *_aor;
- } else {
- vals[0].val.str_val.len = domain - _aor->s;
- vals[1].val.str_val.s = domain+1;
- vals[1].val.str_val.len = _aor->s + _aor->len - domain - 1;
- }
- } else {
- vals[0].val.str_val = *_aor;
- }
- columns[0] = &contact_col;
- columns[1] = &expires_col;
- columns[2] = &q_col;
- columns[3] = &callid_col;
- columns[4] = &cseq_col;
- columns[5] = &flags_col;
- columns[6] = &cflags_col;
- columns[7] = &user_agent_col;
- columns[8] = &received_col;
- columns[9] = &path_col;
- columns[10] = &sock_col;
- columns[11] = &methods_col;
- columns[12] = &last_mod_col;
- columns[13] = &ruid_col;
- columns[14] = &instance_col;
- columns[15] = ®_id_col;
- if (desc_time_order)
- order = &last_mod_col;
- else
- order = &q_col;
- if (ul_dbf.use_table(_c, _d->name) < 0) {
- LM_ERR("failed to use table %.*s\n", _d->name->len, _d->name->s);
- return 0;
- }
- if (ul_dbf.query(_c, keys, 0, vals, columns, (use_domain)?2:1, 16, order,
- &res) < 0) {
- LM_ERR("db_query failed\n");
- return 0;
- }
- if (RES_ROW_N(res) == 0) {
- LM_DBG("aor %.*s not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
- ul_dbf.free_result(_c, res);
- return 0;
- }
- r = 0;
- for(i = 0; i < RES_ROW_N(res); i++) {
- ci = dbrow2info( ROW_VALUES(RES_ROWS(res) + i), &contact);
- if (ci==0) {
- LM_ERR("skipping record for %.*s in table %s\n",
- _aor->len, _aor->s, _d->name->s);
- continue;
- }
-
- if ( r==0 )
- get_static_urecord( _d, _aor, &r);
- if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
- LM_ERR("mem_insert failed\n");
- free_urecord(r);
- ul_dbf.free_result(_c, res);
- return 0;
- }
- /* We have to do this, because insert_ucontact sets state to CS_NEW
- * and we have the contact in the database already */
- c->state = CS_SYNC;
- }
- ul_dbf.free_result(_c, res);
- /* Retrieve ul attributes */
- if(ul_xavp_contact_name.s==NULL) {
- /* feature disabled by mod param */
- goto done;
- }
- if(_d->name->len + 6>=64) {
- LM_ERR("attributes table name is too big\n");
- goto done;
- }
- strncpy(tname_buf, _d->name->s, _d->name->len);
- tname_buf[_d->name->len] = '\0';
- strcat(tname_buf, "_attrs");
- tname.s = tname_buf;
- tname.len = _d->name->len + 6;
- keys[0] = &ulattrs_ruid_col;
- vals[0].type = DB1_STR;
- vals[0].nul = 0;
- columns[0] = &ulattrs_aname_col;
- columns[1] = &ulattrs_atype_col;
- columns[2] = &ulattrs_avalue_col;
- if (ul_dbf.use_table(ul_dbh, &tname) < 0) {
- LM_ERR("sql use_table failed for %.*s\n", tname.len, tname.s);
- goto done;
- }
- for (c = r->contacts; c != NULL; c = c->next) {
- vals[0].val.str_val.s = c->ruid.s;
- vals[0].val.str_val.len = c->ruid.len;
- if (ul_dbf.query(ul_dbh, keys, 0, vals, columns, 1, 3, 0, &res) < 0) {
- LM_ERR("db_query failed\n");
- continue;
- }
- if (RES_ROW_N(res) == 0) {
- LM_DBG("location attrs table is empty\n");
- ul_dbf.free_result(ul_dbh, res);
- continue;
- }
- for(i = 0; i < RES_ROW_N(res); i++) {
- row = RES_ROWS(res) + i;
- aname.s = (char*)VAL_STRING(ROW_VALUES(row));
- aname.len = strlen(aname.s);
- avalue.s = (char*)VAL_STRING(ROW_VALUES(row) + 2);
- avalue.len = strlen(avalue.s);
- memset(&aval, 0, sizeof(sr_xval_t));
- if(VAL_INT(ROW_VALUES(row)+1)==0) {
- /* string value */
- aval.v.s = avalue;
- aval.type = SR_XTYPE_STR;
- } else if(VAL_INT(ROW_VALUES(row)+1)==1) {
- /* int value */
- str2sint(&avalue, &aval.v.i);
- aval.type = SR_XTYPE_INT;
- } else {
- /* unknown type - ignore */
- continue;
- }
- /* add xavp to contact */
- if(c->xavp==NULL) {
- if(xavp_add_xavp_value(&ul_xavp_contact_name, &aname,
- &aval, &c->xavp)==NULL)
- LM_INFO("cannot add first xavp to contact - ignoring\n");
- } else {
- if(c->xavp->val.type==SR_XTYPE_XAVP) {
- if(xavp_add_value(&aname, &aval, &c->xavp->val.v.xavp)==NULL)
- LM_INFO("cannot add values to contact xavp\n");
- }
- }
- }
- ul_dbf.free_result(ul_dbh, res);
- }
- done:
- return r;
- }
- /*!
- * \brief Loads from DB all contacts for a RUID
- * \param _c database connection
- * \param _d domain
- * \param _aor address of record
- * \return pointer to the record on success, 0 on errors or if nothing is found
- */
- urecord_t* db_load_urecord_by_ruid(db1_con_t* _c, udomain_t* _d, str *_ruid)
- {
- ucontact_info_t *ci;
- db_key_t columns[18];
- db_key_t keys[1];
- db_key_t order;
- db_val_t vals[1];
- db1_res_t* res = NULL;
- db_row_t *row;
- str contact;
- str aor;
- static char aorbuf[512];
- str domain;
- urecord_t* r;
- ucontact_t* c;
- keys[0] = &ruid_col;
- vals[0].type = DB1_STR;
- vals[0].nul = 0;
- vals[0].val.str_val = *_ruid;
- columns[0] = &contact_col;
- columns[1] = &expires_col;
- columns[2] = &q_col;
- columns[3] = &callid_col;
- columns[4] = &cseq_col;
- columns[5] = &flags_col;
- columns[6] = &cflags_col;
- columns[7] = &user_agent_col;
- columns[8] = &received_col;
- columns[9] = &path_col;
- columns[10] = &sock_col;
- columns[11] = &methods_col;
- columns[12] = &last_mod_col;
- columns[13] = &ruid_col;
- columns[14] = &instance_col;
- columns[15] = ®_id_col;
- columns[16] = &user_col;
- columns[17] = &domain_col;
- if (desc_time_order)
- order = &last_mod_col;
- else
- order = &q_col;
- if (ul_dbf.use_table(_c, _d->name) < 0) {
- LM_ERR("failed to use table %.*s\n", _d->name->len, _d->name->s);
- return 0;
- }
- if (ul_dbf.query(_c, keys, 0, vals, columns, 1, 18, order,
- &res) < 0) {
- LM_ERR("db_query failed\n");
- return 0;
- }
- if (RES_ROW_N(res) == 0) {
- LM_DBG("aor %.*s not found in table %.*s\n",_ruid->len, _ruid->s,
- _d->name->len, _d->name->s);
- ul_dbf.free_result(_c, res);
- return 0;
- }
- r = 0;
- /* use first row - shouldn't be more */
- row = RES_ROWS(res);
- ci = dbrow2info(ROW_VALUES(RES_ROWS(res)), &contact);
- if (ci==0) {
- LM_ERR("skipping record for %.*s in table %s\n",
- _ruid->len, _ruid->s, _d->name->s);
- goto done;
- }
- aor.s = (char*)VAL_STRING(ROW_VALUES(row) + 16);
- aor.len = strlen(aor.s);
- if (use_domain) {
- domain.s = (char*)VAL_STRING(ROW_VALUES(row) + 17);
- if (VAL_NULL(ROW_VALUES(row)+17) || domain.s==0 || domain.s[0]==0){
- LM_CRIT("empty domain record for user %.*s...skipping\n",
- aor.len, aor.s);
- goto done;
- }
- domain.len = strlen(domain.s);
- if(aor.len + domain.len + 2 >= 512) {
- LM_ERR("AoR is too big\n");
- goto done;
- }
- memcpy(aorbuf, aor.s, aor.len);
- aorbuf[aor.len] = '@';
- memcpy(aorbuf + aor.len + 1, domain.s, domain.len);
- aor.len += 1 + domain.len;
- aor.s = aorbuf;
- aor.s[aor.len] = '\0';
- }
- get_static_urecord( _d, &aor, &r);
- if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
- LM_ERR("mem_insert failed\n");
- free_urecord(r);
- ul_dbf.free_result(_c, res);
- return 0;
- }
- /* We have to do this, because insert_ucontact sets state to CS_NEW
- * and we have the contact in the database already */
- c->state = CS_SYNC;
- done:
- ul_dbf.free_result(_c, res);
- return r;
- }
- /*!
- * \brief Timer function to cleanup expired contacts, DB_ONLY db_mode
- * \param _d cleaned domain
- * \return 0 on success, -1 on failure
- */
- int db_timer_udomain(udomain_t* _d)
- {
- db_key_t keys[2];
- db_op_t ops[2];
- db_val_t vals[2];
- keys[0] = &expires_col;
- ops[0] = "<";
- vals[0].nul = 0;
- UL_DB_EXPIRES_SET(&vals[0], act_time + 1);
- keys[1] = &expires_col;
- ops[1] = "!=";
- vals[1].nul = 0;
- UL_DB_EXPIRES_SET(&vals[1], 0);
- if (ul_dbf.use_table(ul_dbh, _d->name) < 0) {
- LM_ERR("use_table failed\n");
- return -1;
- }
- if (ul_dbf.delete(ul_dbh, keys, ops, vals, 2) < 0) {
- LM_ERR("failed to delete from table %s\n",_d->name->s);
- return -1;
- }
- return 0;
- }
- /*!
- * \brief performs a dummy query just to see if DB is ok
- * \param con database connection
- * \param d domain
- */
- int testdb_udomain(db1_con_t* con, udomain_t* d)
- {
- db_key_t key[1], col[1];
- db_val_t val[1];
- db1_res_t* res = NULL;
- if (ul_dbf.use_table(con, d->name) < 0) {
- LM_ERR("failed to change table\n");
- return -1;
- }
- key[0] = &user_col;
- col[0] = &user_col;
- VAL_TYPE(val) = DB1_STRING;
- VAL_NULL(val) = 0;
- VAL_STRING(val) = "dummy_user";
-
- if (ul_dbf.query( con, key, 0, val, col, 1, 1, 0, &res) < 0) {
- LM_ERR("failure in db_query\n");
- return -1;
- }
- ul_dbf.free_result( con, res);
- return 0;
- }
- /*!
- * \brief Insert a new record into domain in memory
- * \param _d domain the record belongs to
- * \param _aor address of record
- * \param _r new created record
- * \return 0 on success, -1 on failure
- */
- int mem_insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
- {
- int sl;
-
- if (new_urecord(_d->name, _aor, _r) < 0) {
- LM_ERR("creating urecord failed\n");
- return -1;
- }
- sl = ((*_r)->aorhash)&(_d->size-1);
- slot_add(&_d->table[sl], *_r);
- update_stat( _d->users, 1);
- return 0;
- }
- /*!
- * \brief Remove a record from domain in memory
- * \param _d domain the record belongs to
- * \param _r deleted record
- */
- void mem_delete_urecord(udomain_t* _d, struct urecord* _r)
- {
- slot_rem(_r->slot, _r);
- free_urecord(_r);
- update_stat( _d->users, -1);
- }
- /*!
- * \brief Run timer handler for given domain
- * \param _d domain
- */
- void mem_timer_udomain(udomain_t* _d, int istart, int istep)
- {
- struct urecord* ptr, *t;
- int i;
- for(i=istart; i<_d->size; i+=istep)
- {
- lock_ulslot(_d, i);
- ptr = _d->table[i].first;
- while(ptr) {
- timer_urecord(ptr);
- /* Remove the entire record if it is empty */
- if (ptr->contacts == 0) {
- t = ptr;
- ptr = ptr->next;
- mem_delete_urecord(_d, t);
- } else {
- ptr = ptr->next;
- }
- }
- unlock_ulslot(_d, i);
- }
- }
- /*!
- * \brief Get lock for a domain
- * \param _d domain
- * \param _aor adress of record, used as hash source for the lock slot
- */
- void lock_udomain(udomain_t* _d, str* _aor)
- {
- unsigned int sl;
- if (db_mode!=DB_ONLY)
- {
- sl = ul_get_aorhash(_aor) & (_d->size - 1);
- #ifdef GEN_LOCK_T_PREFERED
- lock_get(_d->table[sl].lock);
- #else
- ul_lock_idx(_d->table[sl].lockidx);
- #endif
- }
- }
- /*!
- * \brief Release lock for a domain
- * \param _d domain
- * \param _aor address of record, uses as hash source for the lock slot
- */
- void unlock_udomain(udomain_t* _d, str* _aor)
- {
- unsigned int sl;
- if (db_mode!=DB_ONLY)
- {
- sl = ul_get_aorhash(_aor) & (_d->size - 1);
- #ifdef GEN_LOCK_T_PREFERED
- lock_release(_d->table[sl].lock);
- #else
- ul_release_idx(_d->table[sl].lockidx);
- #endif
- }
- }
- /*!
- * \brief Get lock for a slot
- * \param _d domain
- * \param i slot number
- */
- void lock_ulslot(udomain_t* _d, int i)
- {
- if (db_mode!=DB_ONLY)
- #ifdef GEN_LOCK_T_PREFERED
- lock_get(_d->table[i].lock);
- #else
- ul_lock_idx(_d->table[i].lockidx);
- #endif
- }
- /*!
- * \brief Release lock for a slot
- * \param _d domain
- * \param i slot number
- */
- void unlock_ulslot(udomain_t* _d, int i)
- {
- if (db_mode!=DB_ONLY)
- #ifdef GEN_LOCK_T_PREFERED
- lock_release(_d->table[i].lock);
- #else
- ul_release_idx(_d->table[i].lockidx);
- #endif
- }
- /*!
- * \brief Create and insert a new record
- * \param _d domain to insert the new record
- * \param _aor address of the record
- * \param _r new created record
- * \return return 0 on success, -1 on failure
- */
- int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
- {
- if (db_mode!=DB_ONLY) {
- if (mem_insert_urecord(_d, _aor, _r) < 0) {
- LM_ERR("inserting record failed\n");
- return -1;
- }
- } else {
- get_static_urecord( _d, _aor, _r);
- }
- return 0;
- }
- /*!
- * \brief Obtain a urecord pointer if the urecord exists in domain
- * \param _d domain to search the record
- * \param _aor address of record
- * \param _r new created record
- * \return 0 if a record was found, 1 if nothing could be found
- */
- int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
- {
- unsigned int sl, i, aorhash;
- urecord_t* r;
- if (db_mode!=DB_ONLY) {
- /* search in cache */
- aorhash = ul_get_aorhash(_aor);
- sl = aorhash&(_d->size-1);
- r = _d->table[sl].first;
- for(i = 0; r!=NULL && i < _d->table[sl].n; i++) {
- if((r->aorhash==aorhash) && (r->aor.len==_aor->len)
- && !memcmp(r->aor.s,_aor->s,_aor->len)){
- *_r = r;
- return 0;
- }
- r = r->next;
- }
- } else {
- /* search in DB */
- r = db_load_urecord( ul_dbh, _d, _aor);
- if (r) {
- *_r = r;
- return 0;
- }
- }
- return 1; /* Nothing found */
- }
- /*!
- * \brief Obtain a urecord pointer if the urecord exists in domain (lock slot)
- * \param _d domain to search the record
- * \param _aorhash hash id for address of record
- * \param _ruid record internal unique id
- * \param _r store pointer to location record
- * \param _c store pointer to contact structure
- * \return 0 if a record was found, -1 if nothing could be found
- */
- int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
- str *_ruid, struct urecord** _r, struct ucontact** _c)
- {
- unsigned int sl, i;
- urecord_t* r;
- ucontact_t* c;
- sl = _aorhash&(_d->size-1);
- lock_ulslot(_d, sl);
- if (db_mode!=DB_ONLY) {
- /* search in cache */
- r = _d->table[sl].first;
- for(i = 0; i < _d->table[sl].n; i++) {
- if(r->aorhash==_aorhash) {
- c = r->contacts;
- while(c) {
- if(c->ruid.len==_ruid->len
- && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) {
- *_r = r;
- *_c = c;
- return 0;
- }
- c = c->next;
- }
- }
- r = r->next;
- }
- } else {
- /* search in DB */
- r = db_load_urecord_by_ruid(ul_dbh, _d, _ruid);
- if (r) {
- if(r->aorhash==_aorhash) {
- c = r->contacts;
- while(c) {
- if(c->ruid.len==_ruid->len
- && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) {
- *_r = r;
- *_c = c;
- return 0;
- }
- c = c->next;
- }
- }
- }
- }
- unlock_ulslot(_d, (_aorhash & (_d->size - 1)));
- return -1; /* Nothing found */
- }
- /*!
- * \brief Delete a urecord from domain
- * \param _d domain where the record should be deleted
- * \param _aor address of record
- * \param _r deleted record
- * \return 0 on success, -1 if the record could not be deleted
- */
- int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r)
- {
- struct ucontact* c, *t;
- if (db_mode==DB_ONLY) {
- if (_r==0)
- get_static_urecord( _d, _aor, &_r);
- if (db_delete_urecord(_r)<0) {
- LM_ERR("DB delete failed\n");
- return -1;
- }
- free_urecord(_r);
- return 0;
- }
- if (_r==0) {
- if (get_urecord(_d, _aor, &_r) > 0) {
- return 0;
- }
- }
- c = _r->contacts;
- while(c) {
- t = c;
- c = c->next;
- if (delete_ucontact(_r, t) < 0) {
- LM_ERR("deleting contact failed\n");
- return -1;
- }
- }
- release_urecord(_r);
- return 0;
- }
- /*!
- * \brief Load all location attributes from an udomain
- *
- * Load all location attributes from a udomain, useful to populate the
- * memory cache on startup.
- * \param _d loaded domain
- * \return 0 on success, -1 on failure
- */
- int uldb_preload_attrs(udomain_t *_d)
- {
- char uri[MAX_URI_SIZE];
- str suri;
- char tname_buf[64];
- str tname;
- db_row_t *row;
- db_key_t columns[6];
- db1_res_t* res = NULL;
- str user = {0};
- str domain = {0};
- str ruid;
- str aname;
- str avalue;
- sr_xval_t aval;
- int i;
- int n;
- urecord_t* r;
- ucontact_t* c;
- if(ul_xavp_contact_name.s==NULL) {
- /* feature disabled by mod param */
- return 0;
- }
- if(_d->name->len + 6>=64) {
- LM_ERR("attributes table name is too big\n");
- return -1;
- }
- strncpy(tname_buf, _d->name->s, _d->name->len);
- tname_buf[_d->name->len] = '\0';
- strcat(tname_buf, "_attrs");
- tname.s = tname_buf;
- tname.len = _d->name->len + 6;
- columns[0] = &ulattrs_user_col;
- columns[1] = &ulattrs_ruid_col;
- columns[2] = &ulattrs_aname_col;
- columns[3] = &ulattrs_atype_col;
- columns[4] = &ulattrs_avalue_col;
- columns[5] = &ulattrs_domain_col;
- if (ul_dbf.use_table(ul_dbh, &tname) < 0) {
- LM_ERR("sql use_table failed for %.*s\n", tname.len, tname.s);
- return -1;
- }
- #ifdef EXTRA_DEBUG
- LM_NOTICE("load start time [%d]\n", (int)time(NULL));
- #endif
- if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
- if (ul_dbf.query(ul_dbh, 0, 0, 0, columns, 0, (use_domain)?(6):(5), 0,
- 0) < 0) {
- LM_ERR("db_query (1) failed\n");
- return -1;
- }
- if(ul_dbf.fetch_result(ul_dbh, &res, ul_fetch_rows)<0) {
- LM_ERR("fetching rows failed\n");
- return -1;
- }
- } else {
- if (ul_dbf.query(ul_dbh, 0, 0, 0, columns, 0, (use_domain)?(6):(5), 0,
- &res) < 0) {
- LM_ERR("db_query failed\n");
- return -1;
- }
- }
- if (RES_ROW_N(res) == 0) {
- LM_DBG("location attrs table is empty\n");
- ul_dbf.free_result(ul_dbh, res);
- return 0;
- }
- n = 0;
- do {
- LM_DBG("loading records - cycle [%d]\n", ++n);
- for(i = 0; i < RES_ROW_N(res); i++) {
- row = RES_ROWS(res) + i;
- user.s = (char*)VAL_STRING(ROW_VALUES(row));
- if (VAL_NULL(ROW_VALUES(row)) || user.s==0 || user.s[0]==0) {
- LM_CRIT("empty username record in table %s...skipping\n",
- _d->name->s);
- continue;
- }
- user.len = strlen(user.s);
- ruid.s = (char*)VAL_STRING(ROW_VALUES(row) + 1);
- ruid.len = strlen(ruid.s);
- aname.s = (char*)VAL_STRING(ROW_VALUES(row) + 2);
- aname.len = strlen(aname.s);
- avalue.s = (char*)VAL_STRING(ROW_VALUES(row) + 4);
- avalue.len = strlen(avalue.s);
- memset(&aval, 0, sizeof(sr_xval_t));
- if(VAL_INT(ROW_VALUES(row)+3)==0) {
- /* string value */
- aval.v.s = avalue;
- aval.type = SR_XTYPE_STR;
- } else if(VAL_INT(ROW_VALUES(row)+3)==1) {
- /* int value */
- str2sint(&avalue, &aval.v.i);
- aval.type = SR_XTYPE_INT;
- } else {
- /* unknown type - ignore */
- continue;
- }
- if (use_domain) {
- domain.s = (char*)VAL_STRING(ROW_VALUES(row) + 5);
- if (VAL_NULL(ROW_VALUES(row)+5) || domain.s==0 || domain.s[0]==0){
- LM_CRIT("empty domain record for user %.*s...skipping\n",
- user.len, user.s);
- continue;
- }
- domain.len = strlen(domain.s);
- /* user.s cannot be NULL - checked previosly */
- suri.len = snprintf(uri, MAX_URI_SIZE, "%.*s@%s",
- user.len, user.s, domain.s);
- suri.s = uri;
- if (suri.s[suri.len]!=0) {
- LM_CRIT("URI '%.*s@%s' longer than %d\n", user.len, user.s,
- domain.s, MAX_URI_SIZE);
- continue;
- }
- } else {
- suri = user;
- }
- if (get_urecord_by_ruid(_d, ul_get_aorhash(&suri), &ruid, &r, &c) < 0) {
- /* delete attrs records from db table */
- LM_INFO("no contact record for this ruid\n");
- uldb_delete_attrs(_d->name, &user, &domain, &ruid);
- } else {
- /* add xavp to contact */
- if(c->xavp==NULL) {
- if(xavp_add_xavp_value(&ul_xavp_contact_name, &aname,
- &aval, &c->xavp)==NULL)
- LM_INFO("cannot add first xavp to contact - ignoring\n");
- } else {
- if(c->xavp->val.type==SR_XTYPE_XAVP) {
- if(xavp_add_value(&aname, &aval, &c->xavp->val.v.xavp)==NULL)
- LM_INFO("cannot add values to contact xavp\n");
- }
- }
- /* get_urecord_by_ruid() locks the slot */
- unlock_udomain(_d, &suri);
- }
- }
- if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
- if(ul_dbf.fetch_result(ul_dbh, &res, ul_fetch_rows)<0) {
- LM_ERR("fetching rows (1) failed\n");
- ul_dbf.free_result(ul_dbh, res);
- return -1;
- }
- } else {
- break;
- }
- } while(RES_ROW_N(res)>0);
- ul_dbf.free_result(ul_dbh, res);
- #ifdef EXTRA_DEBUG
- LM_NOTICE("load end time [%d]\n", (int)time(NULL));
- #endif
- return 0;
- }
|