urecord.c

Go to the documentation of this file.
00001 /*
00002  * $Id: urecord.c 5241 2008-11-21 12:52:25Z 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-12 added replication mark and zombie state support (nils)
00025  * 2004-03-17 generic callbacks added (bogdan)
00026  * 2004-06-07 updated to the new DB api (andrei)
00027  */
00028 
00029 /*! \file
00030  *  \brief USRLOC - Usrloc record structure
00031  *  \ingroup usrloc
00032  *
00033  * - Module \ref usrloc
00034  */
00035 
00036 
00037 #include "urecord.h"
00038 #include <string.h>
00039 #include "../../mem/shm_mem.h"
00040 #include "../../dprint.h"
00041 #include "../../ut.h"
00042 #include "../../hash_func.h"
00043 #include "ul_mod.h"
00044 #include "utime.h"
00045 #include "ul_callback.h"
00046 
00047 
00048 /*! contact matching mode */
00049 int matching_mode = CONTACT_ONLY;
00050 /*! retransmission detection interval in seconds */
00051 int cseq_delay = 20;
00052 
00053 /*!
00054  * \brief Create and initialize new record structure
00055  * \param _dom domain name
00056  * \param _aor address of record
00057  * \param _r pointer to the new record
00058  * \return 0 on success, negative on failure
00059  */
00060 int new_urecord(str* _dom, str* _aor, urecord_t** _r)
00061 {
00062    *_r = (urecord_t*)shm_malloc(sizeof(urecord_t));
00063    if (*_r == 0) {
00064       LM_ERR("no more share memory\n");
00065       return -1;
00066    }
00067    memset(*_r, 0, sizeof(urecord_t));
00068 
00069    (*_r)->aor.s = (char*)shm_malloc(_aor->len);
00070    if ((*_r)->aor.s == 0) {
00071       LM_ERR("no more share memory\n");
00072       shm_free(*_r);
00073       *_r = 0;
00074       return -2;
00075    }
00076    memcpy((*_r)->aor.s, _aor->s, _aor->len);
00077    (*_r)->aor.len = _aor->len;
00078    (*_r)->domain = _dom;
00079    (*_r)->aorhash = core_hash(_aor, 0, 0);
00080    return 0;
00081 }
00082 
00083 
00084 /*!
00085  * \brief Free all memory used by the given structure
00086  *
00087  * Free all memory used by the given structure.
00088  * The structure must be removed from all linked
00089  * lists first
00090  * \param _r freed record list
00091  */
00092 void free_urecord(urecord_t* _r)
00093 {
00094    ucontact_t* ptr;
00095 
00096    while(_r->contacts) {
00097       ptr = _r->contacts;
00098       _r->contacts = _r->contacts->next;
00099       free_ucontact(ptr);
00100    }
00101    
00102    /* if mem cache is not used, the urecord struct is static*/
00103    if (db_mode!=DB_ONLY) {
00104       if (_r->aor.s) shm_free(_r->aor.s);
00105       shm_free(_r);
00106    }
00107 }
00108 
00109 
00110 /*!
00111  * \brief Print a record, useful for debugging
00112  * \param _f print output
00113  * \param _r printed record
00114  */
00115 void print_urecord(FILE* _f, urecord_t* _r)
00116 {
00117    ucontact_t* ptr;
00118 
00119    fprintf(_f, "...Record(%p)...\n", _r);
00120    fprintf(_f, "domain : '%.*s'\n", _r->domain->len, ZSW(_r->domain->s));
00121    fprintf(_f, "aor    : '%.*s'\n", _r->aor.len, ZSW(_r->aor.s));
00122    fprintf(_f, "aorhash: '%u'\n", (unsigned)_r->aorhash);
00123    fprintf(_f, "slot:    '%d'\n", _r->aorhash&(_r->slot->d->size-1));
00124    
00125    if (_r->contacts) {
00126       ptr = _r->contacts;
00127       while(ptr) {
00128          print_ucontact(_f, ptr);
00129          ptr = ptr->next;
00130       }
00131    }
00132 
00133    fprintf(_f, ".../Record...\n");
00134 }
00135 
00136 
00137 /*!
00138  * \brief Add a new contact in memory
00139  *
00140  * Add a new contact in memory, contacts are ordered by:
00141  * 1) q value, 2) descending modification time
00142  * \param _r record this contact belongs to
00143  * \param _c contact
00144  * \param _ci contact information
00145  * \return pointer to new created contact on success, 0 on failure
00146  */
00147 ucontact_t* mem_insert_ucontact(urecord_t* _r, str* _c, ucontact_info_t* _ci)
00148 {
00149    ucontact_t* ptr, *prev = 0;
00150    ucontact_t* c;
00151 
00152    if ( (c=new_ucontact(_r->domain, &_r->aor, _c, _ci)) == 0) {
00153       LM_ERR("failed to create new contact\n");
00154       return 0;
00155    }
00156    if_update_stat( _r->slot, _r->slot->d->contacts, 1);
00157 
00158    ptr = _r->contacts;
00159 
00160    if (!desc_time_order) {
00161       while(ptr) {
00162          if (ptr->q < c->q) break;
00163          prev = ptr;
00164          ptr = ptr->next;
00165       }
00166    }
00167 
00168    if (ptr) {
00169       if (!ptr->prev) {
00170          ptr->prev = c;
00171          c->next = ptr;
00172          _r->contacts = c;
00173       } else {
00174          c->next = ptr;
00175          c->prev = ptr->prev;
00176          ptr->prev->next = c;
00177          ptr->prev = c;
00178       }
00179    } else if (prev) {
00180       prev->next = c;
00181       c->prev = prev;
00182    } else {
00183       _r->contacts = c;
00184    }
00185 
00186    return c;
00187 }
00188 
00189 
00190 /*!
00191  * \brief Remove the contact from lists in memory
00192  * \param _r record this contact belongs to
00193  * \param _c removed contact
00194  */
00195 void mem_remove_ucontact(urecord_t* _r, ucontact_t* _c)
00196 {
00197    if (_c->prev) {
00198       _c->prev->next = _c->next;
00199       if (_c->next) {
00200          _c->next->prev = _c->prev;
00201       }
00202    } else {
00203       _r->contacts = _c->next;
00204       if (_c->next) {
00205          _c->next->prev = 0;
00206       }
00207    }
00208 }  
00209 
00210 
00211 /*!
00212  * \brief Remove contact in memory from the list and delete it
00213  * \param _r record this contact belongs to
00214  * \param _c deleted contact
00215  */
00216 void mem_delete_ucontact(urecord_t* _r, ucontact_t* _c)
00217 {
00218    mem_remove_ucontact(_r, _c);
00219    if_update_stat( _r->slot, _r->slot->d->contacts, -1);
00220    free_ucontact(_c);
00221 }
00222 
00223 
00224 /*!
00225  * \brief Expires timer for NO_DB db_mode
00226  *
00227  * Expires timer for NO_DB db_mode, process all contacts from
00228  * the record, delete the expired ones from memory.
00229  * \param _r processed record
00230  */
00231 static inline void nodb_timer(urecord_t* _r)
00232 {
00233    ucontact_t* ptr, *t;
00234 
00235    ptr = _r->contacts;
00236 
00237    while(ptr) {
00238       if (!VALID_CONTACT(ptr, act_time)) {
00239          /* run callbacks for EXPIRE event */
00240          if (exists_ulcb_type(UL_CONTACT_EXPIRE))
00241             run_ul_callbacks( UL_CONTACT_EXPIRE, ptr);
00242 
00243          LM_DBG("Binding '%.*s','%.*s' has expired\n",
00244             ptr->aor->len, ZSW(ptr->aor->s),
00245             ptr->c.len, ZSW(ptr->c.s));
00246 
00247          t = ptr;
00248          ptr = ptr->next;
00249 
00250          mem_delete_ucontact(_r, t);
00251          update_stat( _r->slot->d->expires, 1);
00252       } else {
00253          ptr = ptr->next;
00254       }
00255    }
00256 }
00257 
00258 
00259 /*!
00260  * \brief Write through timer, used for WRITE_THROUGH db_mode
00261  *
00262  * Write through timer, used for WRITE_THROUGH db_mode. Process all
00263  * contacts from the record, delete all expired ones from the DB.
00264  * \param _r processed record
00265  * \note currently unused, this mode is also handled by the wb_timer
00266  */
00267 static inline void wt_timer(urecord_t* _r)
00268 {
00269    ucontact_t* ptr, *t;
00270 
00271    ptr = _r->contacts;
00272 
00273    while(ptr) {
00274       if (!VALID_CONTACT(ptr, act_time)) {
00275          /* run callbacks for EXPIRE event */
00276          if (exists_ulcb_type(UL_CONTACT_EXPIRE)) {
00277             run_ul_callbacks( UL_CONTACT_EXPIRE, ptr);
00278          }
00279 
00280          LM_DBG("Binding '%.*s','%.*s' has expired\n",
00281             ptr->aor->len, ZSW(ptr->aor->s),
00282             ptr->c.len, ZSW(ptr->c.s));
00283 
00284          t = ptr;
00285          ptr = ptr->next;
00286 
00287          if (db_delete_ucontact(t) < 0) {
00288             LM_ERR("deleting contact from database failed\n");
00289          }
00290          mem_delete_ucontact(_r, t);
00291          update_stat( _r->slot->d->expires, 1);
00292       } else {
00293          ptr = ptr->next;
00294       }
00295    }
00296 }
00297 
00298 
00299 /*!
00300  * \brief Write-back timer, used for WRITE_BACK db_mode
00301  *
00302  * Write-back timer, used for WRITE_BACK db_mode. Process
00303  * all contacts from the record, delete expired ones from the DB.
00304  * Furthermore it updates changed contacts, and also insert new
00305  * ones in the DB.
00306  * \param _r processed record
00307  */
00308 static inline void wb_timer(urecord_t* _r)
00309 {
00310    ucontact_t* ptr, *t;
00311    cstate_t old_state;
00312    int op;
00313 
00314    ptr = _r->contacts;
00315 
00316    while(ptr) {
00317       if (!VALID_CONTACT(ptr, act_time)) {
00318          /* run callbacks for EXPIRE event */
00319          if (exists_ulcb_type(UL_CONTACT_EXPIRE)) {
00320             run_ul_callbacks( UL_CONTACT_EXPIRE, ptr);
00321          }
00322 
00323          LM_DBG("Binding '%.*s','%.*s' has expired\n",
00324             ptr->aor->len, ZSW(ptr->aor->s),
00325             ptr->c.len, ZSW(ptr->c.s));
00326          update_stat( _r->slot->d->expires, 1);
00327 
00328          t = ptr;
00329          ptr = ptr->next;
00330 
00331          /* Should we remove the contact from the database ? */
00332          if (st_expired_ucontact(t) == 1) {
00333             if (db_delete_ucontact(t) < 0) {
00334                LM_ERR("failed to delete contact from the database\n");
00335             }
00336          }
00337 
00338          mem_delete_ucontact(_r, t);
00339       } else {
00340          /* Determine the operation we have to do */
00341          old_state = ptr->state;
00342          op = st_flush_ucontact(ptr);
00343 
00344          switch(op) {
00345          case 0: /* do nothing, contact is synchronized */
00346             break;
00347 
00348          case 1: /* insert */
00349             if (db_insert_ucontact(ptr) < 0) {
00350                LM_ERR("inserting contact into database failed\n");
00351                ptr->state = old_state;
00352             }
00353             break;
00354 
00355          case 2: /* update */
00356             if (db_update_ucontact(ptr) < 0) {
00357                LM_ERR("updating contact in db failed\n");
00358                ptr->state = old_state;
00359             }
00360             break;
00361          }
00362 
00363          ptr = ptr->next;
00364       }
00365    }
00366 }
00367 
00368 
00369 /*!
00370  * \brief Run timer functions depending on the db_mode setting.
00371  *
00372  * Helper function that run the appropriate timer function, depending
00373  * on the db_mode setting.
00374  * \param _r processed record
00375  */
00376 void timer_urecord(urecord_t* _r)
00377 {
00378    switch(db_mode) {
00379    case NO_DB:         nodb_timer(_r);
00380                   break;
00381    /* use also the write_back timer routine to handle the failed
00382     * realtime inserts/updates */
00383    case WRITE_THROUGH: wb_timer(_r); /*wt_timer(_r);*/
00384                   break;
00385    case WRITE_BACK:    wb_timer(_r);
00386                   break;
00387    }
00388 }
00389 
00390 
00391 /*!
00392  * \brief Delete a record from the database
00393  * \param _r deleted record
00394  * \return 0 on success, -1 on failure
00395  */
00396 int db_delete_urecord(urecord_t* _r)
00397 {
00398    db_key_t keys[2];
00399    db_val_t vals[2];
00400    char* dom;
00401 
00402    keys[0] = &user_col;
00403    keys[1] = &domain_col;
00404    vals[0].type = DB_STR;
00405    vals[0].nul = 0;
00406    vals[0].val.str_val.s = _r->aor.s;
00407    vals[0].val.str_val.len = _r->aor.len;
00408 
00409    if (use_domain) {
00410       dom = memchr(_r->aor.s, '@', _r->aor.len);
00411       vals[0].val.str_val.len = dom - _r->aor.s;
00412 
00413       vals[1].type = DB_STR;
00414       vals[1].nul = 0;
00415       vals[1].val.str_val.s = dom + 1;
00416       vals[1].val.str_val.len = _r->aor.s + _r->aor.len - dom - 1;
00417    }
00418 
00419    if (ul_dbf.use_table(ul_dbh, _r->domain) < 0) {
00420       LM_ERR("use_table failed\n");
00421       return -1;
00422    }
00423 
00424    if (ul_dbf.delete(ul_dbh, keys, 0, vals, (use_domain) ? (2) : (1)) < 0) {
00425       LM_ERR("failed to delete from database\n");
00426       return -1;
00427    }
00428 
00429    return 0;
00430 }
00431 
00432 
00433 /*!
00434  * \brief Release urecord previously obtained through get_urecord
00435  * \warning Failing to calls this function after get_urecord will
00436  * result in a memory leak when the DB_ONLY mode is used. When
00437  * the records is later deleted, e.g. with delete_urecord, then
00438  * its not necessary, as this function already releases the record.
00439  * \param _r released record
00440  */
00441 void release_urecord(urecord_t* _r)
00442 {
00443    if (db_mode==DB_ONLY) {
00444       free_urecord(_r);
00445    } else if (_r->contacts == 0) {
00446       mem_delete_urecord(_r->slot->d, _r);
00447    }
00448 }
00449 
00450 
00451 /*!
00452  * \brief Create and insert new contact into urecord
00453  * \param _r record into the new contact should be inserted
00454  * \param _contact contact string
00455  * \param _ci contact information
00456  * \param _c new created contact
00457  * \return 0 on success, -1 on failure
00458  */
00459 int insert_ucontact(urecord_t* _r, str* _contact, ucontact_info_t* _ci,
00460                                              ucontact_t** _c)
00461 {
00462    if ( ((*_c)=mem_insert_ucontact(_r, _contact, _ci)) == 0) {
00463       LM_ERR("failed to insert contact\n");
00464       return -1;
00465    }
00466 
00467    if (exists_ulcb_type(UL_CONTACT_INSERT)) {
00468       run_ul_callbacks( UL_CONTACT_INSERT, *_c);
00469    }
00470 
00471    if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) {
00472       if (db_insert_ucontact(*_c) < 0) {
00473          LM_ERR("failed to insert in database\n");
00474          return -1;
00475       } else {
00476          (*_c)->state = CS_SYNC;
00477       }
00478    }
00479 
00480    return 0;
00481 }
00482 
00483 
00484 /*!
00485  * \brief Delete ucontact from urecord
00486  * \param _r record where the contact belongs to
00487  * \param _c deleted contact
00488  * \return 0 on success, -1 on failure
00489  */
00490 int delete_ucontact(urecord_t* _r, struct ucontact* _c)
00491 {
00492    int ret = 0;
00493 
00494    if (exists_ulcb_type(UL_CONTACT_DELETE)) {
00495       run_ul_callbacks( UL_CONTACT_DELETE, _c);
00496    }
00497 
00498    if (st_delete_ucontact(_c) > 0) {
00499       if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) {
00500          if (db_delete_ucontact(_c) < 0) {
00501             LM_ERR("failed to remove contact from database\n");
00502             ret = -1;
00503          }
00504       }
00505 
00506       mem_delete_ucontact(_r, _c);
00507    }
00508 
00509    return ret;
00510 }
00511 
00512 
00513 /*!
00514  * \brief Match a contact record to a contact string
00515  * \param ptr contact record
00516  * \param _c contact string
00517  * \return ptr on successfull match, 0 when they not match
00518  */
00519 static inline struct ucontact* contact_match( ucontact_t* ptr, str* _c)
00520 {
00521    while(ptr) {
00522       if ((_c->len == ptr->c.len) && !memcmp(_c->s, ptr->c.s, _c->len)) {
00523          return ptr;
00524       }
00525       
00526       ptr = ptr->next;
00527    }
00528    return 0;
00529 }
00530 
00531 
00532 /*!
00533  * \brief Match a contact record to a contact string and callid
00534  * \param ptr contact record
00535  * \param _c contact string
00536  * \param _callid callid
00537  * \return ptr on successfull match, 0 when they not match
00538  */
00539 static inline struct ucontact* contact_callid_match( ucontact_t* ptr,
00540                                           str* _c, str *_callid)
00541 {
00542    while(ptr) {
00543       if ( (_c->len==ptr->c.len) && (_callid->len==ptr->callid.len)
00544       && !memcmp(_c->s, ptr->c.s, _c->len)
00545       && !memcmp(_callid->s, ptr->callid.s, _callid->len)
00546       ) {
00547          return ptr;
00548       }
00549       
00550       ptr = ptr->next;
00551    }
00552    return 0;
00553 }
00554 
00555 
00556 /*!
00557  * \brief Get pointer to ucontact with given contact
00558  * \param _r record where to search the contacts
00559  * \param _c contact string
00560  * \param _callid callid
00561  * \param _cseq CSEQ number
00562  * \param _co found contact
00563  * \return 0 - found, 1 - not found, -1 - invalid found, 
00564  * -2 - found, but to be skipped (same cseq)
00565  */
00566 int get_ucontact(urecord_t* _r, str* _c, str* _callid, int _cseq,
00567                                           struct ucontact** _co)
00568 {
00569    ucontact_t* ptr;
00570    int no_callid;
00571 
00572    ptr = 0;
00573    no_callid = 0;
00574    *_co = 0;
00575 
00576    switch (matching_mode) {
00577       case CONTACT_ONLY:
00578          ptr = contact_match( _r->contacts, _c);
00579          break;
00580       case CONTACT_CALLID:
00581          ptr = contact_callid_match( _r->contacts, _c, _callid);
00582          no_callid = 1;
00583          break;
00584       default:
00585          LM_CRIT("unknown matching_mode %d\n", matching_mode);
00586          return -1;
00587    }
00588 
00589    if (ptr) {
00590       /* found -> check callid and cseq */
00591       if ( no_callid || (ptr->callid.len==_callid->len
00592       && memcmp(_callid->s, ptr->callid.s, _callid->len)==0 ) ) {
00593          if (_cseq<ptr->cseq)
00594             return -1;
00595          if (_cseq==ptr->cseq) {
00596             get_act_time();
00597             return (ptr->last_modified+cseq_delay>act_time)?-2:-1;
00598          }
00599       }
00600       *_co = ptr;
00601       return 0;
00602    }
00603 
00604    return 1;
00605 }

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