modules_k/p_usrloc/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 
00036 #include "../usrloc/usrloc.h"
00037 #include "urecord.h"
00038 #include <string.h>
00039 #include "../../mem/shm_mem.h"
00040 #include "../../dprint.h"
00041 #include "../../ut.h"
00042 #include "../../hashes.h"
00043 #include "p_usrloc_mod.h"
00044 #include "utime.h"
00045 #include "../usrloc/ul_callback.h"
00046 
00047 #include "ul_db_layer.h"
00048 
00049 
00051 int matching_mode = CONTACT_ONLY;
00053 int cseq_delay = 20;
00054 
00062 int new_urecord(str* _dom, str* _aor, urecord_t** _r)
00063 {
00064         *_r = (urecord_t*)shm_malloc(sizeof(urecord_t));
00065         if (*_r == 0) {
00066                 LM_ERR("no more share memory\n");
00067                 return -1;
00068         }
00069         memset(*_r, 0, sizeof(urecord_t));
00070 
00071         (*_r)->aor.s = (char*)shm_malloc(_aor->len);
00072         if ((*_r)->aor.s == 0) {
00073                 LM_ERR("no more share memory\n");
00074                 shm_free(*_r);
00075                 *_r = 0;
00076                 return -2;
00077         }
00078         memcpy((*_r)->aor.s, _aor->s, _aor->len);
00079         (*_r)->aor.len = _aor->len;
00080         (*_r)->domain = _dom;
00081         (*_r)->aorhash = core_hash(_aor, 0, 0);
00082         return 0;
00083 }
00084 
00085 
00094 void free_urecord(urecord_t* _r)
00095 {
00096         ucontact_t* ptr;
00097 
00098         while(_r->contacts) {
00099                 ptr = _r->contacts;
00100                 _r->contacts = _r->contacts->next;
00101                 free_ucontact(ptr);
00102         }
00103         
00104         /* if mem cache is not used, the urecord struct is static*/
00105         if (db_mode!=DB_ONLY) {
00106                 if (_r->aor.s) shm_free(_r->aor.s);
00107                 shm_free(_r);
00108         }
00109 }
00110 
00111 
00117 void print_urecord(FILE* _f, urecord_t* _r)
00118 {
00119         ucontact_t* ptr;
00120 
00121         fprintf(_f, "...Record(%p)...\n", _r);
00122         fprintf(_f, "domain : '%.*s'\n", _r->domain->len, ZSW(_r->domain->s));
00123         fprintf(_f, "aor    : '%.*s'\n", _r->aor.len, ZSW(_r->aor.s));
00124         fprintf(_f, "aorhash: '%u'\n", (unsigned)_r->aorhash);
00125         fprintf(_f, "slot:    '%d'\n", _r->aorhash&(_r->slot->d->size-1));
00126         
00127         if (_r->contacts) {
00128                 ptr = _r->contacts;
00129                 while(ptr) {
00130                         print_ucontact(_f, ptr);
00131                         ptr = ptr->next;
00132                 }
00133         }
00134 
00135         fprintf(_f, ".../Record...\n");
00136 }
00137 
00138 
00149 ucontact_t* mem_insert_ucontact(urecord_t* _r, str* _c, ucontact_info_t* _ci)
00150 {
00151         ucontact_t* ptr, *prev = 0;
00152         ucontact_t* c;
00153 
00154         if ( (c=new_ucontact(_r->domain, &_r->aor, _c, _ci)) == 0) {
00155                 LM_ERR("failed to create new contact\n");
00156                 return 0;
00157         }
00158         if_update_stat( _r->slot, _r->slot->d->contacts, 1);
00159 
00160         ptr = _r->contacts;
00161 
00162         if (!desc_time_order) {
00163                 while(ptr) {
00164                         if (ptr->q < c->q) break;
00165                         prev = ptr;
00166                         ptr = ptr->next;
00167                 }
00168         }
00169 
00170         if (ptr) {
00171                 if (!ptr->prev) {
00172                         ptr->prev = c;
00173                         c->next = ptr;
00174                         _r->contacts = c;
00175                 } else {
00176                         c->next = ptr;
00177                         c->prev = ptr->prev;
00178                         ptr->prev->next = c;
00179                         ptr->prev = c;
00180                 }
00181         } else if (prev) {
00182                 prev->next = c;
00183                 c->prev = prev;
00184         } else {
00185                 _r->contacts = c;
00186         }
00187 
00188         return c;
00189 }
00190 
00191 
00197 void mem_remove_ucontact(urecord_t* _r, ucontact_t* _c)
00198 {
00199         if (_c->prev) {
00200                 _c->prev->next = _c->next;
00201                 if (_c->next) {
00202                         _c->next->prev = _c->prev;
00203                 }
00204         } else {
00205                 _r->contacts = _c->next;
00206                 if (_c->next) {
00207                         _c->next->prev = 0;
00208                 }
00209         }
00210 }       
00211 
00212 
00218 void mem_delete_ucontact(urecord_t* _r, ucontact_t* _c)
00219 {
00220         mem_remove_ucontact(_r, _c);
00221         if_update_stat( _r->slot, _r->slot->d->contacts, -1);
00222         free_ucontact(_c);
00223 }
00224 
00225 
00233 static inline void nodb_timer(urecord_t* _r)
00234 {
00235         ucontact_t* ptr, *t;
00236 
00237         ptr = _r->contacts;
00238 
00239         while(ptr) {
00240                 if (!VALID_CONTACT(ptr, act_time)) {
00241                         /* run callbacks for EXPIRE event */
00242                         if (exists_ulcb_type(UL_CONTACT_EXPIRE))
00243                                 run_ul_callbacks( UL_CONTACT_EXPIRE, ptr);
00244 
00245                         LM_DBG("Binding '%.*s','%.*s' has expired\n",
00246                                 ptr->aor->len, ZSW(ptr->aor->s),
00247                                 ptr->c.len, ZSW(ptr->c.s));
00248 
00249                         t = ptr;
00250                         ptr = ptr->next;
00251 
00252                         mem_delete_ucontact(_r, t);
00253                         update_stat( _r->slot->d->expires, 1);
00254                 } else {
00255                         ptr = ptr->next;
00256                 }
00257         }
00258 }
00259 
00260 
00269 static inline void wt_timer(urecord_t* _r)
00270 {
00271         ucontact_t* ptr, *t;
00272 
00273         ptr = _r->contacts;
00274 
00275         while(ptr) {
00276                 if (!VALID_CONTACT(ptr, act_time)) {
00277                         /* run callbacks for EXPIRE event */
00278                         if (exists_ulcb_type(UL_CONTACT_EXPIRE)) {
00279                                 run_ul_callbacks( UL_CONTACT_EXPIRE, ptr);
00280                         }
00281 
00282                         LM_DBG("Binding '%.*s','%.*s' has expired\n",
00283                                 ptr->aor->len, ZSW(ptr->aor->s),
00284                                 ptr->c.len, ZSW(ptr->c.s));
00285 
00286                         t = ptr;
00287                         ptr = ptr->next;
00288 
00289                         if (db_delete_ucontact(t) < 0) {
00290                                 LM_ERR("deleting contact from database failed\n");
00291                         }
00292                         mem_delete_ucontact(_r, t);
00293                         update_stat( _r->slot->d->expires, 1);
00294                 } else {
00295                         ptr = ptr->next;
00296                 }
00297         }
00298 }
00299 
00300 
00310 static inline void wb_timer(urecord_t* _r)
00311 {
00312         ucontact_t* ptr, *t;
00313         cstate_t old_state;
00314         int op;
00315 
00316         ptr = _r->contacts;
00317 
00318         while(ptr) {
00319                 if (!VALID_CONTACT(ptr, act_time)) {
00320                         /* run callbacks for EXPIRE event */
00321                         if (exists_ulcb_type(UL_CONTACT_EXPIRE)) {
00322                                 run_ul_callbacks( UL_CONTACT_EXPIRE, ptr);
00323                         }
00324 
00325                         LM_DBG("Binding '%.*s','%.*s' has expired\n",
00326                                 ptr->aor->len, ZSW(ptr->aor->s),
00327                                 ptr->c.len, ZSW(ptr->c.s));
00328                         update_stat( _r->slot->d->expires, 1);
00329 
00330                         t = ptr;
00331                         ptr = ptr->next;
00332 
00333                         /* Should we remove the contact from the database ? */
00334                         if (st_expired_ucontact(t) == 1) {
00335                                 if (db_delete_ucontact(t) < 0) {
00336                                         LM_ERR("failed to delete contact from the database\n");
00337                                 }
00338                         }
00339 
00340                         mem_delete_ucontact(_r, t);
00341                 } else {
00342                         /* Determine the operation we have to do */
00343                         old_state = ptr->state;
00344                         op = st_flush_ucontact(ptr);
00345 
00346                         switch(op) {
00347                         case 0: /* do nothing, contact is synchronized */
00348                                 break;
00349 
00350                         case 1: /* insert */
00351                                 if (db_insert_ucontact(ptr) < 0) {
00352                                         LM_ERR("inserting contact into database failed\n");
00353                                         ptr->state = old_state;
00354                                 }
00355                                 break;
00356 
00357                         case 2: /* update */
00358                                 if (db_update_ucontact(ptr) < 0) {
00359                                         LM_ERR("updating contact in db failed\n");
00360                                         ptr->state = old_state;
00361                                 }
00362                                 break;
00363                         }
00364 
00365                         ptr = ptr->next;
00366                 }
00367         }
00368 }
00369 
00370 
00378 void timer_urecord(urecord_t* _r)
00379 {
00380         switch(db_mode) {
00381         case NO_DB:         nodb_timer(_r);
00382                                                 break;
00383         /* use also the write_back timer routine to handle the failed
00384          * realtime inserts/updates */
00385         case WRITE_THROUGH: wb_timer(_r); /*wt_timer(_r);*/
00386                                                 break;
00387         case WRITE_BACK:    wb_timer(_r);
00388                                                 break;
00389         }
00390 }
00391 
00392 
00398 int db_delete_urecord(udomain_t* _d, urecord_t* _r)
00399 {
00400         db_key_t keys[2];
00401         db_val_t vals[2];
00402         char* dom;
00403 
00404         keys[0] = &user_col;
00405         keys[1] = &domain_col;
00406         vals[0].type = DB1_STR;
00407         vals[0].nul = 0;
00408         vals[0].val.str_val.s = _r->aor.s;
00409         vals[0].val.str_val.len = _r->aor.len;
00410 
00411         if (use_domain) {
00412                 dom = memchr(_r->aor.s, '@', _r->aor.len);
00413                 vals[0].val.str_val.len = dom - _r->aor.s;
00414 
00415                 vals[1].type = DB1_STR;
00416                 vals[1].nul = 0;
00417                 vals[1].val.str_val.s = dom + 1;
00418                 vals[1].val.str_val.len = _r->aor.s + _r->aor.len - dom - 1;
00419         }
00420 
00421         if (ul_db_layer_delete(_d, &vals[0].val.str_val, &vals[1].val.str_val, keys, 0, vals, (use_domain) ? (2) : (1)) < 0) {
00422                 return -1;
00423         }
00424 
00425         return 0;
00426 }
00427 
00428 
00437 void release_urecord(urecord_t* _r)
00438 {
00439         if (db_mode==DB_ONLY) {
00440                 free_urecord(_r);
00441         } else if (_r->contacts == 0) {
00442                 mem_delete_urecord(_r->slot->d, _r);
00443         }
00444 }
00445 
00446 
00455 int insert_ucontact(urecord_t* _r, str* _contact, ucontact_info_t* _ci,
00456                                                                                                                         ucontact_t** _c)
00457 {
00458         if ( ((*_c)=mem_insert_ucontact(_r, _contact, _ci)) == 0) {
00459                 LM_ERR("failed to insert contact\n");
00460                 return -1;
00461         }
00462 
00463         if (exists_ulcb_type(UL_CONTACT_INSERT)) {
00464                 run_ul_callbacks( UL_CONTACT_INSERT, *_c);
00465         }
00466 
00467         if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) {
00468                 if (db_insert_ucontact(*_c) < 0) {
00469                         LM_ERR("failed to insert in database\n");
00470                         return -1;
00471                 } else {
00472                         (*_c)->state = CS_SYNC;
00473                 }
00474         }
00475 
00476         return 0;
00477 }
00478 
00479 
00486 int delete_ucontact(urecord_t* _r, struct ucontact* _c)
00487 {
00488         int ret = 0;
00489 
00490         if (exists_ulcb_type(UL_CONTACT_DELETE)) {
00491                 run_ul_callbacks( UL_CONTACT_DELETE, _c);
00492         }
00493 
00494         if (st_delete_ucontact(_c) > 0) {
00495                 if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) {
00496                         if (db_delete_ucontact(_c) < 0) {
00497                                 LM_ERR("failed to remove contact from database\n");
00498                                 ret = -1;
00499                         }
00500                 }
00501 
00502                 mem_delete_ucontact(_r, _c);
00503         }
00504 
00505         return ret;
00506 }
00507 
00508 
00515 static inline struct ucontact* contact_match( ucontact_t* ptr, str* _c)
00516 {
00517         while(ptr) {
00518                 if ((_c->len == ptr->c.len) && !memcmp(_c->s, ptr->c.s, _c->len)) {
00519                         return ptr;
00520                 }
00521                 
00522                 ptr = ptr->next;
00523         }
00524         return 0;
00525 }
00526 
00527 
00535 static inline struct ucontact* contact_callid_match( ucontact_t* ptr,
00536                                                                                                                 str* _c, str *_callid)
00537 {
00538         while(ptr) {
00539                 if ( (_c->len==ptr->c.len) && (_callid->len==ptr->callid.len)
00540                 && !memcmp(_c->s, ptr->c.s, _c->len)
00541                 && !memcmp(_callid->s, ptr->callid.s, _callid->len)
00542                 ) {
00543                         return ptr;
00544                 }
00545                 
00546                 ptr = ptr->next;
00547         }
00548         return 0;
00549 }
00550 
00551 
00559 static inline struct ucontact* contact_path_match( ucontact_t* ptr, str* _c, str *_path)
00560 {
00561         /* if no path is preset (in REGISTER request) or use_path is not configured
00562            in registrar module, default to contact_match() */
00563         if( _path == NULL) return contact_match(ptr, _c);
00564 
00565         while(ptr) {
00566                 if ( (_c->len==ptr->c.len) && (_path->len==ptr->path.len)
00567                 && !memcmp(_c->s, ptr->c.s, _c->len)
00568                 && !memcmp(_path->s, ptr->path.s, _path->len)
00569                 ) {
00570                         return ptr;
00571                 }
00572 
00573                 ptr = ptr->next;
00574         }
00575         return 0;
00576 }
00577 
00588 int get_ucontact(urecord_t* _r, str* _c, str* _callid, str* _path, int _cseq,
00589                                         struct ucontact** _co)
00590 {
00591         ucontact_t* ptr;
00592         int no_callid;
00593 
00594         ptr = 0;
00595         no_callid = 0;
00596         *_co = 0;
00597 
00598         switch (matching_mode) {
00599                 case CONTACT_ONLY:
00600                         ptr = contact_match( _r->contacts, _c);
00601                         break;
00602                 case CONTACT_CALLID:
00603                         ptr = contact_callid_match( _r->contacts, _c, _callid);
00604                         no_callid = 1;
00605                         break;
00606                 case CONTACT_PATH:
00607                         ptr = contact_path_match( _r->contacts, _c, _path);
00608                         break;
00609                 default:
00610                         LM_CRIT("unknown matching_mode %d\n", matching_mode);
00611                         return -1;
00612         }
00613 
00614         if (ptr) {
00615                 /* found -> check callid and cseq */
00616                 if ( no_callid || (ptr->callid.len==_callid->len
00617                 && memcmp(_callid->s, ptr->callid.s, _callid->len)==0 ) ) {
00618                         if (_cseq<ptr->cseq)
00619                                 return -1;
00620                         if (_cseq==ptr->cseq) {
00621                                 get_act_time();
00622                                 return (ptr->last_modified+cseq_delay>act_time)?-2:-1;
00623                         }
00624                 }
00625                 *_co = ptr;
00626                 return 0;
00627         }
00628 
00629         return 1;
00630 }