modules_k/usrloc/urecord.c

Go to the documentation of this file.
00001 /*
00002  * $Id$ 
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 
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 "ul_mod.h"
00044 #include "usrloc.h"
00045 #include "utime.h"
00046 #include "ul_callback.h"
00047 #include "usrloc.h"
00048 
00050 int matching_mode = CONTACT_ONLY;
00052 int cseq_delay = 20;
00053 
00061 int new_urecord(str* _dom, str* _aor, urecord_t** _r)
00062 {
00063         *_r = (urecord_t*)shm_malloc(sizeof(urecord_t));
00064         if (*_r == 0) {
00065                 LM_ERR("no more share memory\n");
00066                 return -1;
00067         }
00068         memset(*_r, 0, sizeof(urecord_t));
00069 
00070         (*_r)->aor.s = (char*)shm_malloc(_aor->len);
00071         if ((*_r)->aor.s == 0) {
00072                 LM_ERR("no more share memory\n");
00073                 shm_free(*_r);
00074                 *_r = 0;
00075                 return -2;
00076         }
00077         memcpy((*_r)->aor.s, _aor->s, _aor->len);
00078         (*_r)->aor.len = _aor->len;
00079         (*_r)->domain = _dom;
00080         (*_r)->aorhash = ul_get_aorhash(_aor);
00081         return 0;
00082 }
00083 
00084 
00093 void free_urecord(urecord_t* _r)
00094 {
00095         ucontact_t* ptr;
00096 
00097         while(_r->contacts) {
00098                 ptr = _r->contacts;
00099                 _r->contacts = _r->contacts->next;
00100                 free_ucontact(ptr);
00101         }
00102         
00103         /* if mem cache is not used, the urecord struct is static*/
00104         if (db_mode!=DB_ONLY) {
00105                 if (_r->aor.s) shm_free(_r->aor.s);
00106                 shm_free(_r);
00107         }
00108 }
00109 
00110 
00116 void print_urecord(FILE* _f, urecord_t* _r)
00117 {
00118         ucontact_t* ptr;
00119 
00120         fprintf(_f, "...Record(%p)...\n", _r);
00121         fprintf(_f, "domain : '%.*s'\n", _r->domain->len, ZSW(_r->domain->s));
00122         fprintf(_f, "aor    : '%.*s'\n", _r->aor.len, ZSW(_r->aor.s));
00123         fprintf(_f, "aorhash: '%u'\n", (unsigned)_r->aorhash);
00124         fprintf(_f, "slot:    '%d'\n", _r->aorhash&(_r->slot->d->size-1));
00125         
00126         if (_r->contacts) {
00127                 ptr = _r->contacts;
00128                 while(ptr) {
00129                         print_ucontact(_f, ptr);
00130                         ptr = ptr->next;
00131                 }
00132         }
00133 
00134         fprintf(_f, ".../Record...\n");
00135 }
00136 
00137 
00148 ucontact_t* mem_insert_ucontact(urecord_t* _r, str* _c, ucontact_info_t* _ci)
00149 {
00150         ucontact_t* ptr, *prev = 0;
00151         ucontact_t* c;
00152 
00153         if ( (c=new_ucontact(_r->domain, &_r->aor, _c, _ci)) == 0) {
00154                 LM_ERR("failed to create new contact\n");
00155                 return 0;
00156         }
00157         if_update_stat( _r->slot, _r->slot->d->contacts, 1);
00158 
00159         ptr = _r->contacts;
00160 
00161         if (!desc_time_order) {
00162                 while(ptr) {
00163                         if (ptr->q < c->q) break;
00164                         prev = ptr;
00165                         ptr = ptr->next;
00166                 }
00167         }
00168 
00169         if (ptr) {
00170                 if (!ptr->prev) {
00171                         ptr->prev = c;
00172                         c->next = ptr;
00173                         _r->contacts = c;
00174                 } else {
00175                         c->next = ptr;
00176                         c->prev = ptr->prev;
00177                         ptr->prev->next = c;
00178                         ptr->prev = c;
00179                 }
00180         } else if (prev) {
00181                 prev->next = c;
00182                 c->prev = prev;
00183         } else {
00184                 _r->contacts = c;
00185         }
00186 
00187         return c;
00188 }
00189 
00190 
00196 void mem_remove_ucontact(urecord_t* _r, ucontact_t* _c)
00197 {
00198         if (_c->prev) {
00199                 _c->prev->next = _c->next;
00200                 if (_c->next) {
00201                         _c->next->prev = _c->prev;
00202                 }
00203         } else {
00204                 _r->contacts = _c->next;
00205                 if (_c->next) {
00206                         _c->next->prev = 0;
00207                 }
00208         }
00209 }       
00210 
00211 
00217 void mem_delete_ucontact(urecord_t* _r, ucontact_t* _c)
00218 {
00219         mem_remove_ucontact(_r, _c);
00220         if_update_stat( _r->slot, _r->slot->d->contacts, -1);
00221         free_ucontact(_c);
00222 }
00223 
00224 
00232 static inline void nodb_timer(urecord_t* _r)
00233 {
00234         ucontact_t* ptr, *t;
00235 
00236         ptr = _r->contacts;
00237 
00238         while(ptr) {
00239                 if (!VALID_CONTACT(ptr, act_time)) {
00240                         /* run callbacks for EXPIRE event */
00241                         if (exists_ulcb_type(UL_CONTACT_EXPIRE))
00242                                 run_ul_callbacks( UL_CONTACT_EXPIRE, ptr);
00243 
00244                         LM_DBG("Binding '%.*s','%.*s' has expired\n",
00245                                 ptr->aor->len, ZSW(ptr->aor->s),
00246                                 ptr->c.len, ZSW(ptr->c.s));
00247 
00248                         t = ptr;
00249                         ptr = ptr->next;
00250 
00251                         mem_delete_ucontact(_r, t);
00252                         update_stat( _r->slot->d->expires, 1);
00253                 } else {
00254                         ptr = ptr->next;
00255                 }
00256         }
00257 }
00258 
00259 
00268 static inline void wt_timer(urecord_t* _r)
00269 {
00270         ucontact_t* ptr, *t;
00271 
00272         ptr = _r->contacts;
00273 
00274         while(ptr) {
00275                 if (!VALID_CONTACT(ptr, act_time)) {
00276                         /* run callbacks for EXPIRE event */
00277                         if (exists_ulcb_type(UL_CONTACT_EXPIRE)) {
00278                                 run_ul_callbacks( UL_CONTACT_EXPIRE, ptr);
00279                         }
00280 
00281                         LM_DBG("Binding '%.*s','%.*s' has expired\n",
00282                                 ptr->aor->len, ZSW(ptr->aor->s),
00283                                 ptr->c.len, ZSW(ptr->c.s));
00284 
00285                         t = ptr;
00286                         ptr = ptr->next;
00287 
00288                         if (db_delete_ucontact(t) < 0) {
00289                                 LM_ERR("deleting contact from database failed\n");
00290                         }
00291                         mem_delete_ucontact(_r, t);
00292                         update_stat( _r->slot->d->expires, 1);
00293                 } else {
00294                         ptr = ptr->next;
00295                 }
00296         }
00297 }
00298 
00299 
00309 static inline void wb_timer(urecord_t* _r)
00310 {
00311         ucontact_t* ptr, *t;
00312         cstate_t old_state;
00313         int op;
00314         int res;
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 (ul_db_update_as_insert)
00359                                         res = db_insert_ucontact(ptr);
00360                                 else
00361                                         res = db_update_ucontact(ptr);
00362                                 if (res < 0) {
00363                                         LM_ERR("updating contact in db failed\n");
00364                                         ptr->state = old_state;
00365                                 }
00366                                 break;
00367                         }
00368 
00369                         ptr = ptr->next;
00370                 }
00371         }
00372 }
00373 
00374 
00382 void timer_urecord(urecord_t* _r)
00383 {
00384         switch(db_mode) {
00385         case NO_DB:         nodb_timer(_r);
00386                                                 break;
00387         /* use also the write_back timer routine to handle the failed
00388          * realtime inserts/updates */
00389         case WRITE_THROUGH: wb_timer(_r); /*wt_timer(_r);*/
00390                                                 break;
00391         case WRITE_BACK:    wb_timer(_r);
00392                                                 break;
00393         }
00394 }
00395 
00396 
00402 int db_delete_urecord(urecord_t* _r)
00403 {
00404         db_key_t keys[2];
00405         db_val_t vals[2];
00406         char* dom;
00407 
00408         keys[0] = &user_col;
00409         keys[1] = &domain_col;
00410         vals[0].type = DB1_STR;
00411         vals[0].nul = 0;
00412         vals[0].val.str_val.s = _r->aor.s;
00413         vals[0].val.str_val.len = _r->aor.len;
00414 
00415         if (use_domain) {
00416                 dom = memchr(_r->aor.s, '@', _r->aor.len);
00417                 vals[0].val.str_val.len = dom - _r->aor.s;
00418 
00419                 vals[1].type = DB1_STR;
00420                 vals[1].nul = 0;
00421                 vals[1].val.str_val.s = dom + 1;
00422                 vals[1].val.str_val.len = _r->aor.s + _r->aor.len - dom - 1;
00423         }
00424 
00425         if (ul_dbf.use_table(ul_dbh, _r->domain) < 0) {
00426                 LM_ERR("use_table failed\n");
00427                 return -1;
00428         }
00429 
00430         if (ul_dbf.delete(ul_dbh, keys, 0, vals, (use_domain) ? (2) : (1)) < 0) {
00431                 LM_ERR("failed to delete from database\n");
00432                 return -1;
00433         }
00434 
00435         return 0;
00436 }
00437 
00438 
00447 void release_urecord(urecord_t* _r)
00448 {
00449         if (db_mode==DB_ONLY) {
00450                 free_urecord(_r);
00451         } else if (_r->contacts == 0) {
00452                 mem_delete_urecord(_r->slot->d, _r);
00453         }
00454 }
00455 
00456 
00465 int insert_ucontact(urecord_t* _r, str* _contact, ucontact_info_t* _ci,
00466                                                                                                                         ucontact_t** _c)
00467 {
00468         if ( ((*_c)=mem_insert_ucontact(_r, _contact, _ci)) == 0) {
00469                 LM_ERR("failed to insert contact\n");
00470                 return -1;
00471         }
00472 
00473         if (exists_ulcb_type(UL_CONTACT_INSERT)) {
00474                 run_ul_callbacks( UL_CONTACT_INSERT, *_c);
00475         }
00476 
00477         if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) {
00478                 if (db_insert_ucontact(*_c) < 0) {
00479                         LM_ERR("failed to insert in database\n");
00480                         return -1;
00481                 } else {
00482                         (*_c)->state = CS_SYNC;
00483                 }
00484         }
00485 
00486         return 0;
00487 }
00488 
00489 
00496 int delete_ucontact(urecord_t* _r, struct ucontact* _c)
00497 {
00498         int ret = 0;
00499 
00500         if (exists_ulcb_type(UL_CONTACT_DELETE)) {
00501                 run_ul_callbacks( UL_CONTACT_DELETE, _c);
00502         }
00503 
00504         if (st_delete_ucontact(_c) > 0) {
00505                 if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) {
00506                         if (db_delete_ucontact(_c) < 0) {
00507                                 LM_ERR("failed to remove contact from database\n");
00508                                 ret = -1;
00509                         }
00510                 }
00511 
00512                 mem_delete_ucontact(_r, _c);
00513         }
00514 
00515         return ret;
00516 }
00517 
00518 
00525 static inline struct ucontact* contact_match( ucontact_t* ptr, str* _c)
00526 {
00527         while(ptr) {
00528                 if ((_c->len == ptr->c.len) && !memcmp(_c->s, ptr->c.s, _c->len)) {
00529                         return ptr;
00530                 }
00531                 
00532                 ptr = ptr->next;
00533         }
00534         return 0;
00535 }
00536 
00537 
00545 static inline struct ucontact* contact_callid_match( ucontact_t* ptr,
00546                                                                                                                 str* _c, str *_callid)
00547 {
00548         while(ptr) {
00549                 if ( (_c->len==ptr->c.len) && (_callid->len==ptr->callid.len)
00550                 && !memcmp(_c->s, ptr->c.s, _c->len)
00551                 && !memcmp(_callid->s, ptr->callid.s, _callid->len)
00552                 ) {
00553                         return ptr;
00554                 }
00555                 
00556                 ptr = ptr->next;
00557         }
00558         return 0;
00559 }
00560 
00568 static inline struct ucontact* contact_path_match( ucontact_t* ptr, str* _c, str *_path)
00569 {
00570         /* if no path is preset (in REGISTER request) or use_path is not configured
00571            in registrar module, default to contact_match() */
00572         if( _path == NULL) return contact_match(ptr, _c);
00573 
00574         while(ptr) {
00575                 if ( (_c->len==ptr->c.len) && (_path->len==ptr->path.len)
00576                 && !memcmp(_c->s, ptr->c.s, _c->len)
00577                 && !memcmp(_path->s, ptr->path.s, _path->len)
00578                 ) {
00579                         return ptr;
00580                 }
00581 
00582                 ptr = ptr->next;
00583         }
00584         return 0;
00585 }
00586 
00598 int get_ucontact(urecord_t* _r, str* _c, str* _callid, str* _path, int _cseq,
00599                                                                                                                 struct ucontact** _co)
00600 {
00601         ucontact_t* ptr;
00602         int no_callid;
00603 
00604         ptr = 0;
00605         no_callid = 0;
00606         *_co = 0;
00607 
00608         switch (matching_mode) {
00609                 case CONTACT_ONLY:
00610                         ptr = contact_match( _r->contacts, _c);
00611                         break;
00612                 case CONTACT_CALLID:
00613                         ptr = contact_callid_match( _r->contacts, _c, _callid);
00614                         no_callid = 1;
00615                         break;
00616                 case CONTACT_PATH:
00617                         ptr = contact_path_match( _r->contacts, _c, _path);
00618                         break;
00619                 default:
00620                         LM_CRIT("unknown matching_mode %d\n", matching_mode);
00621                         return -1;
00622         }
00623 
00624         if (ptr) {
00625                 /* found -> check callid and cseq */
00626                 if ( no_callid || (ptr->callid.len==_callid->len
00627                 && memcmp(_callid->s, ptr->callid.s, _callid->len)==0 ) ) {
00628                         if (_cseq<ptr->cseq)
00629                                 return -1;
00630                         if (_cseq==ptr->cseq) {
00631                                 get_act_time();
00632                                 return (ptr->last_modified+cseq_delay>act_time)?-2:-1;
00633                         }
00634                 }
00635                 *_co = ptr;
00636                 return 0;
00637         }
00638 
00639         return 1;
00640 }
00641 
00642 /*
00643  * Get pointer to ucontact with given info (by address or sip.instance)
00644  */
00645 int get_ucontact_by_instance(urecord_t* _r, str* _c, ucontact_info_t* _ci,
00646                 ucontact_t** _co)
00647 {
00648         ucontact_t* ptr;
00649         str i1;
00650         str i2;
00651         
00652         if (_ci->instance.s == NULL || _ci->instance.len <= 0) {
00653                 return get_ucontact(_r, _c, _ci->callid, _ci->path, _ci->cseq, _co);
00654         }
00655 
00656         /* find by instance */
00657         ptr = _r->contacts;
00658         while(ptr) {
00659                 if (ptr->instance.len>0 && _ci->reg_id==ptr->reg_id)
00660                 {
00661                         i1 = _ci->instance;
00662                         i2 = ptr->instance;
00663                         if(i1.s[0]=='<' && i1.s[i1.len-1]=='>') {
00664                                 i1.s++;
00665                                 i1.len-=2;
00666                         }
00667                         if(i2.s[0]=='<' && i2.s[i2.len-1]=='>') {
00668                                 i2.s++;
00669                                 i2.len-=2;
00670                         }
00671                         if(i1.len==i2.len && memcmp(i1.s, i2.s, i2.len)==0) {
00672                                 *_co = ptr;
00673                                 return 0;
00674                         }
00675                 }
00676                 
00677                 ptr = ptr->next;
00678         }
00679         return 1;
00680 }
00681 
00682 unsigned int ul_get_aorhash(str *_aor)
00683 {
00684         return core_hash(_aor, 0, 0);
00685 }