modules_k/p_usrloc/ucontact.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ucontact.c 5272 2008-11-27 12:32:26Z henningw $ 
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * ---------
00024  * 2003-03-12 added replication mark and three zombie states (nils)
00025  * 2004-03-17 generic callbacks added (bogdan)
00026  * 2004-06-07 updated to the new DB api (andrei)
00027  */
00028 
00036 #include "ucontact.h"
00037 #include <string.h>             /* memcpy */
00038 #include "../../mem/shm_mem.h"
00039 #include "../../ut.h"
00040 #include "../../ip_addr.h"
00041 #include "../../socket_info.h"
00042 #include "../../dprint.h"
00043 #include "../../lib/srdb1/db.h"
00044 #include "p_usrloc_mod.h"
00045 #include "../usrloc/ul_callback.h"
00046 #include "urecord.h"
00047 #include "ucontact.h"
00048 #include "ul_db_layer.h"
00049 #include "dlist.h"
00050 
00059 ucontact_t* new_ucontact(str* _dom, str* _aor, str* _contact, ucontact_info_t* _ci)
00060 {
00061         ucontact_t *c;
00062 
00063         c = (ucontact_t*)shm_malloc(sizeof(ucontact_t));
00064         if (!c) {
00065                 LM_ERR("no more shm memory\n");
00066                 return 0;
00067         }
00068         memset(c, 0, sizeof(ucontact_t));
00069 
00070         if (shm_str_dup( &c->c, _contact) < 0) goto error;
00071         if (shm_str_dup( &c->callid, _ci->callid) < 0) goto error;
00072         if (shm_str_dup( &c->user_agent, _ci->user_agent) < 0) goto error;
00073 
00074         if (_ci->received.s && _ci->received.len) {
00075                 if (shm_str_dup( &c->received, &_ci->received) < 0) goto error;
00076         }
00077         if (_ci->path && _ci->path->len) {
00078                 if (shm_str_dup( &c->path, _ci->path) < 0) goto error;
00079         }
00080 
00081         c->domain = _dom;
00082         c->aor = _aor;
00083         c->expires = _ci->expires;
00084         c->q = _ci->q;
00085         c->sock = _ci->sock;
00086         c->cseq = _ci->cseq;
00087         c->state = CS_NEW;
00088         c->flags = _ci->flags;
00089         c->cflags = _ci->cflags;
00090         c->methods = _ci->methods;
00091         c->last_modified = _ci->last_modified;
00092 
00093         return c;
00094 error:
00095         LM_ERR("no more shm memory\n");
00096         if (c->path.s) shm_free(c->path.s);
00097         if (c->received.s) shm_free(c->received.s);
00098         if (c->user_agent.s) shm_free(c->user_agent.s);
00099         if (c->callid.s) shm_free(c->callid.s);
00100         if (c->c.s) shm_free(c->c.s);
00101         shm_free(c);
00102         return 0;
00103 }
00104 
00105 
00106 
00111 void free_ucontact(ucontact_t* _c)
00112 {
00113         if (!_c) return;
00114         if (_c->path.s) shm_free(_c->path.s);
00115         if (_c->received.s) shm_free(_c->received.s);
00116         if (_c->user_agent.s) shm_free(_c->user_agent.s);
00117         if (_c->callid.s) shm_free(_c->callid.s);
00118         if (_c->c.s) shm_free(_c->c.s);
00119         shm_free( _c );
00120 }
00121 
00122 
00128 void print_ucontact(FILE* _f, ucontact_t* _c)
00129 {
00130         time_t t = time(0);
00131         char* st;
00132 
00133         switch(_c->state) {
00134         case CS_NEW:   st = "CS_NEW";     break;
00135         case CS_SYNC:  st = "CS_SYNC";    break;
00136         case CS_DIRTY: st = "CS_DIRTY";   break;
00137         default:       st = "CS_UNKNOWN"; break;
00138         }
00139 
00140         fprintf(_f, "~~~Contact(%p)~~~\n", _c);
00141         fprintf(_f, "domain    : '%.*s'\n", _c->domain->len, ZSW(_c->domain->s));
00142         fprintf(_f, "aor       : '%.*s'\n", _c->aor->len, ZSW(_c->aor->s));
00143         fprintf(_f, "Contact   : '%.*s'\n", _c->c.len, ZSW(_c->c.s));
00144         fprintf(_f, "Expires   : ");
00145         if (_c->expires == 0) {
00146                 fprintf(_f, "Permanent\n");
00147         } else if (_c->expires == UL_EXPIRED_TIME) {
00148                 fprintf(_f, "Deleted\n");
00149         } else if (t > _c->expires) {
00150                 fprintf(_f, "Expired\n");
00151         } else {
00152                 fprintf(_f, "%u\n", (unsigned int)(_c->expires - t));
00153         }
00154         fprintf(_f, "q         : %s\n", q2str(_c->q, 0));
00155         fprintf(_f, "Call-ID   : '%.*s'\n", _c->callid.len, ZSW(_c->callid.s));
00156         fprintf(_f, "CSeq      : %d\n", _c->cseq);
00157         fprintf(_f, "User-Agent: '%.*s'\n",
00158                 _c->user_agent.len, ZSW(_c->user_agent.s));
00159         fprintf(_f, "received  : '%.*s'\n",
00160                 _c->received.len, ZSW(_c->received.s));
00161         fprintf(_f, "Path      : '%.*s'\n",
00162                 _c->path.len, ZSW(_c->path.s));
00163         fprintf(_f, "State     : %s\n", st);
00164         fprintf(_f, "Flags     : %u\n", _c->flags);
00165         if (_c->sock) {
00166                 fprintf(_f, "Sock      : %.*s (%p)\n",
00167                                 _c->sock->sock_str.len,_c->sock->sock_str.s,_c->sock);
00168         } else {
00169                 fprintf(_f, "Sock      : none (null)\n");
00170         }
00171         fprintf(_f, "Methods   : %u\n", _c->methods);
00172         fprintf(_f, "next      : %p\n", _c->next);
00173         fprintf(_f, "prev      : %p\n", _c->prev);
00174         fprintf(_f, "~~~/Contact~~~~\n");
00175 }
00176 
00177 
00184 int mem_update_ucontact(ucontact_t* _c, ucontact_info_t* _ci)
00185 {
00186 #define update_str(_old,_new) \
00187         do{\
00188                 if ((_old)->len < (_new)->len) { \
00189                         ptr = (char*)shm_malloc((_new)->len); \
00190                         if (ptr == 0) { \
00191                                 LM_ERR("no more shm memory\n"); \
00192                                 return -1; \
00193                         }\
00194                         memcpy(ptr, (_new)->s, (_new)->len);\
00195                         if ((_old)->s) shm_free((_old)->s);\
00196                         (_old)->s = ptr;\
00197                 } else {\
00198                         memcpy((_old)->s, (_new)->s, (_new)->len);\
00199                 }\
00200                 (_old)->len = (_new)->len;\
00201         } while(0)
00202 
00203         char* ptr;
00204 
00205         /* No need to update Callid as it is constant 
00206          * per ucontact (set at insert time)  -bogdan */
00207 
00208         update_str( &_c->user_agent, _ci->user_agent);
00209 
00210         if (_ci->received.s && _ci->received.len) {
00211                 update_str( &_c->received, &_ci->received);
00212         } else {
00213                 if (_c->received.s) shm_free(_c->received.s);
00214                 _c->received.s = 0;
00215                 _c->received.len = 0;
00216         }
00217         
00218         if (_ci->path) {
00219                 update_str( &_c->path, _ci->path);
00220         } else {
00221                 if (_c->path.s) shm_free(_c->path.s);
00222                 _c->path.s = 0;
00223                 _c->path.len = 0;
00224         }
00225 
00226         _c->sock = _ci->sock;
00227         _c->expires = _ci->expires;
00228         _c->q = _ci->q;
00229         _c->cseq = _ci->cseq;
00230         _c->methods = _ci->methods;
00231         _c->last_modified = _ci->last_modified;
00232         _c->flags = _ci->flags;
00233         _c->cflags = _ci->cflags;
00234 
00235         return 0;
00236 }
00237 
00238 
00239 /* ================ State related functions =============== */
00240 
00245 void st_update_ucontact(ucontact_t* _c)
00246 {
00247         switch(_c->state) {
00248         case CS_NEW:
00249                          /* Contact is new and is not in the database yet,
00250                           * we remain in the same state here because the
00251                           * contact must be inserted later in the timer
00252                           */
00253                 break;
00254 
00255         case CS_SYNC:
00256                          /* For db mode 1 & 2 a modified contact needs to be 
00257                           * updated also in the database, so transit into 
00258                           * CS_DIRTY and let the timer to do the update 
00259                           * again. For db mode 1 we try to update right
00260                           * now and if fails, let the timer to do the job
00261                           */
00262                 if (db_mode == WRITE_BACK || db_mode == WRITE_THROUGH) {
00263                         _c->state = CS_DIRTY;
00264                 }
00265                 break;
00266 
00267         case CS_DIRTY:
00268                          /* Modification of dirty contact results in
00269                           * dirty contact again, don't change anything
00270                           */
00271                 break;
00272         }
00273 }
00274 
00275 
00281 int st_delete_ucontact(ucontact_t* _c)
00282 {
00283         switch(_c->state) {
00284         case CS_NEW:
00285                      /* Contact is new and isn't in the database
00286                       * yet, we can delete it from the memory
00287                       * safely.
00288                       */
00289                 return 1;
00290 
00291         case CS_SYNC:
00292         case CS_DIRTY:
00293                      /* Contact is in the database,
00294                       * we cannot remove it from the memory 
00295                       * directly, but we can set expires to zero
00296                       * and the timer will take care of deleting 
00297                       * the contact from the memory as well as 
00298                       * from the database
00299                       */
00300                 if (db_mode == WRITE_BACK) {
00301                         _c->expires = UL_EXPIRED_TIME;
00302                         return 0;
00303                 } else {
00304                              /* WRITE_THROUGH or NO_DB -- we can
00305                               * remove it from memory immediately and
00306                               * the calling function would also remove
00307                               * it from the database if needed
00308                               */
00309                         return 1;
00310                 }
00311         }
00312 
00313         return 0; /* Makes gcc happy */
00314 }
00315 
00316 
00322 int st_expired_ucontact(ucontact_t* _c)
00323 {
00324              /* There is no need to change contact
00325               * state, because the contact will
00326               * be deleted anyway
00327               */
00328 
00329         switch(_c->state) {
00330         case CS_NEW:
00331                      /* Contact is not in the database
00332                       * yet, remove it from memory only
00333                       */
00334                 return 0;
00335 
00336         case CS_SYNC:
00337         case CS_DIRTY:
00338                      /* Remove from database here */
00339                 return 1;
00340         }
00341 
00342         return 0; /* Makes gcc happy */
00343 }
00344 
00345 
00351 int st_flush_ucontact(ucontact_t* _c)
00352 {
00353         switch(_c->state) {
00354         case CS_NEW:
00355                      /* Contact is new and is not in
00356                       * the database yet so we have
00357                       * to insert it
00358                       */
00359                 _c->state = CS_SYNC;
00360                 return 1;
00361 
00362         case CS_SYNC:
00363                      /* Contact is synchronized, do
00364                       * nothing
00365                       */
00366                 return 0;
00367 
00368         case CS_DIRTY:
00369                      /* Contact has been modified and
00370                       * is in the db already so we
00371                       * have to update it
00372                       */
00373                 _c->state = CS_SYNC;
00374                 return 2;
00375         }
00376 
00377         return 0; /* Makes gcc happy */
00378 }
00379 
00380 
00381 /* ============== Database related functions ================ */
00382 
00388 int db_insert_ucontact(ucontact_t* _c)
00389 {
00390         char* dom;
00391         db_key_t keys[15];
00392         db_val_t vals[15];
00393         int nr_cols  = 0;
00394         int nr_cols_key = 0;
00395         struct udomain * _d;
00396         str user={0, 0};
00397         str domain={0, 0};
00398 
00399         if (_c->flags & FL_MEM) {
00400                 return 0;
00401         }
00402 
00403         if(register_udomain(_c->domain->s, &_d) < 0){
00404                 return -1;
00405         }
00406         LM_INFO("Domain set for contact %.*s\n", _c->domain->len, _c->domain->s);
00407 
00408         keys[nr_cols] = &user_col;
00409         vals[nr_cols].type = DB1_STR;
00410         vals[nr_cols].nul = 0;
00411         vals[nr_cols].val.str_val = *_c->aor;
00412         nr_cols++;
00413 
00414         keys[nr_cols] = &contact_col;
00415         vals[nr_cols].type = DB1_STR;
00416         vals[nr_cols].nul = 0;
00417         vals[nr_cols].val.str_val = _c->c;
00418         nr_cols++;
00419 
00420         if(use_domain) {
00421                 keys[nr_cols] = &domain_col;
00422                 vals[nr_cols].type = DB1_STR;
00423                 vals[nr_cols].nul = 0;
00424 
00425                 dom = memchr(_c->aor->s, '@', _c->aor->len);
00426                 if (dom==0) {
00427                         LM_INFO("*** use domain and AOR does not contain @\n");
00428                         vals[nr_cols].val.str_val.len = 0;
00429                         vals[nr_cols].val.str_val.s = 0;
00430                 } else {
00431                         vals[0].val.str_val.len = dom - _c->aor->s;
00432                         vals[nr_cols].val.str_val.s = dom + 1;
00433                         vals[nr_cols].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1;
00434                 }
00435                 domain = vals[nr_cols].val.str_val;
00436                 LM_DBG("** Username=%.*s  Domain=%.*s\n", vals[0].val.str_val.len, vals[0].val.str_val.s,
00437                                 vals[nr_cols].val.str_val.len, vals[nr_cols].val.str_val.s);
00438                 nr_cols++;
00439         }
00440         nr_cols_key  = nr_cols;
00441         user = vals[0].val.str_val;
00442 
00443         keys[nr_cols] = &expires_col;
00444         vals[nr_cols].type = DB1_DATETIME;
00445         vals[nr_cols].nul = 0;
00446         vals[nr_cols].val.time_val = _c->expires;
00447         nr_cols++;
00448 
00449         keys[nr_cols] = &q_col;
00450         vals[nr_cols].type = DB1_DOUBLE;
00451         vals[nr_cols].nul = 0;
00452         vals[nr_cols].val.double_val = q2double(_c->q);
00453         nr_cols++;
00454 
00455         keys[nr_cols] = &callid_col;
00456         vals[nr_cols].type = DB1_STR;
00457         vals[nr_cols].nul = 0;
00458         vals[nr_cols].val.str_val = _c->callid;
00459         nr_cols++;
00460 
00461         keys[nr_cols] = &cseq_col;
00462         vals[nr_cols].type = DB1_INT;
00463         vals[nr_cols].nul = 0;
00464         vals[nr_cols].val.int_val = _c->cseq;
00465         nr_cols++;
00466 
00467         keys[nr_cols] = &flags_col;
00468         vals[nr_cols].type = DB1_INT;
00469         vals[nr_cols].nul = 0;
00470         vals[nr_cols].val.bitmap_val = _c->flags;
00471         nr_cols++;
00472 
00473         keys[nr_cols] = &cflags_col;
00474         vals[nr_cols].type = DB1_INT;
00475         vals[nr_cols].nul = 0;
00476         vals[nr_cols].val.bitmap_val = _c->cflags;
00477         nr_cols++;
00478 
00479         keys[nr_cols] = &user_agent_col;
00480         vals[nr_cols].type = DB1_STR;
00481         vals[nr_cols].nul = 0;
00482         vals[nr_cols].val.str_val = _c->user_agent;
00483         nr_cols++;
00484 
00485         keys[nr_cols] = &received_col;
00486         vals[nr_cols].type = DB1_STR;
00487         if (_c->received.s == 0) {
00488                 vals[nr_cols].nul = 1;
00489         } else {
00490                 vals[nr_cols].nul = 0;
00491                 vals[nr_cols].val.str_val = _c->received;
00492         }
00493         nr_cols++;
00494 
00495         keys[nr_cols] = &path_col;
00496         vals[nr_cols].type = DB1_STR;
00497         if (_c->path.s == 0) {
00498                 vals[nr_cols].nul = 1;
00499         } else {
00500                 vals[nr_cols].nul = 0;
00501                 vals[nr_cols].val.str_val = _c->path;
00502         }
00503         nr_cols++;
00504 
00505         keys[nr_cols] = &sock_col;
00506         vals[nr_cols].type = DB1_STR;
00507         if (_c->sock) {
00508                 vals[nr_cols].val.str_val = _c->sock->sock_str;
00509                 vals[nr_cols].nul = 0;
00510         } else {
00511                 vals[nr_cols].nul = 1;
00512         }
00513         nr_cols++;
00514 
00515         keys[nr_cols] = &methods_col;
00516         vals[nr_cols].type = DB1_BITMAP;
00517         if (_c->methods == 0xFFFFFFFF) {
00518                 vals[nr_cols].nul = 1;
00519         } else {
00520                 vals[nr_cols].val.bitmap_val = _c->methods;
00521                 vals[nr_cols].nul = 0;
00522         }
00523         nr_cols++;
00524 
00525         keys[nr_cols] = &last_mod_col;
00526         vals[nr_cols].type = DB1_DATETIME;
00527         vals[nr_cols].nul = 0;
00528         vals[nr_cols].val.time_val = _c->last_modified;
00529 
00530 
00531         /* to prevent errors from the DB because of duplicated entries */
00532         if (ul_db_layer_replace(_d, &user, &domain, keys, vals, nr_cols, nr_cols_key) <0) {
00533                 LM_ERR("inserting contact in db failed\n");
00534                 return -1;
00535         }
00536 
00537         return 0;
00538 }
00539 
00540 
00546 int db_update_ucontact(ucontact_t* _c)
00547 {
00548         char* dom;
00549         db_key_t keys1[4];
00550         db_val_t vals1[4];
00551 
00552         db_key_t keys2[11];
00553         db_val_t vals2[11];
00554 
00555         if (_c->flags & FL_MEM) {
00556                 return 0;
00557         }
00558         struct udomain * _d;
00559         if(register_udomain(_c->domain->s, &_d) < 0){
00560                 return -1;
00561         }
00562 
00563         keys1[0] = &user_col;
00564         keys1[1] = &contact_col;
00565         keys1[2] = &callid_col;
00566         keys1[3] = &domain_col;
00567         keys2[0] = &expires_col;
00568         keys2[1] = &q_col;
00569         keys2[2] = &cseq_col;
00570         keys2[3] = &flags_col;
00571         keys2[4] = &cflags_col;
00572         keys2[5] = &user_agent_col;
00573         keys2[6] = &received_col;
00574         keys2[7] = &path_col;
00575         keys2[8] = &sock_col;
00576         keys2[9] = &methods_col;
00577         keys2[10] = &last_mod_col;
00578 
00579         vals1[0].type = DB1_STR;
00580         vals1[0].nul = 0;
00581         vals1[0].val.str_val = *_c->aor;
00582 
00583         vals1[1].type = DB1_STR;
00584         vals1[1].nul = 0;
00585         vals1[1].val.str_val = _c->c;
00586 
00587         vals1[2].type = DB1_STR;
00588         vals1[2].nul = 0;
00589         vals1[2].val.str_val = _c->callid;
00590 
00591         vals2[0].type = DB1_DATETIME;
00592         vals2[0].nul = 0;
00593         vals2[0].val.time_val = _c->expires;
00594 
00595         vals2[1].type = DB1_DOUBLE;
00596         vals2[1].nul = 0;
00597         vals2[1].val.double_val = q2double(_c->q);
00598 
00599         vals2[2].type = DB1_INT;
00600         vals2[2].nul = 0;
00601         vals2[2].val.int_val = _c->cseq;
00602 
00603         vals2[3].type = DB1_INT;
00604         vals2[3].nul = 0;
00605         vals2[3].val.bitmap_val = _c->flags;
00606 
00607         vals2[4].type = DB1_INT;
00608         vals2[4].nul = 0;
00609         vals2[4].val.bitmap_val = _c->cflags;
00610 
00611         vals2[5].type = DB1_STR;
00612         vals2[5].nul = 0;
00613         vals2[5].val.str_val = _c->user_agent;
00614 
00615         vals2[6].type = DB1_STR;
00616         if (_c->received.s == 0) {
00617                 vals2[6].nul = 1;
00618         } else {
00619                 vals2[6].nul = 0;
00620                 vals2[6].val.str_val = _c->received;
00621         }
00622         
00623         vals2[7].type = DB1_STR;
00624         if (_c->path.s == 0) {
00625                 vals2[7].nul = 1;
00626         } else {
00627                 vals2[7].nul = 0;
00628                 vals2[7].val.str_val = _c->path;
00629         }
00630 
00631         vals2[8].type = DB1_STR;
00632         if (_c->sock) {
00633                 vals2[8].val.str_val = _c->sock->sock_str;
00634                 vals2[8].nul = 0;
00635         } else {
00636                 vals2[8].nul = 1;
00637         }
00638 
00639         vals2[9].type = DB1_BITMAP;
00640         if (_c->methods == 0xFFFFFFFF) {
00641                 vals2[9].nul = 1;
00642         } else {
00643                 vals2[9].val.bitmap_val = _c->methods;
00644                 vals2[9].nul = 0;
00645         }
00646 
00647         vals2[10].type = DB1_DATETIME;
00648         vals2[10].nul = 0;
00649         vals2[10].val.time_val = _c->last_modified;
00650 
00651         if (use_domain) {
00652                 vals1[3].type = DB1_STR;
00653                 vals1[3].nul = 0;
00654                 dom = memchr(_c->aor->s, '@', _c->aor->len);
00655                 if (dom==0) {
00656                         vals1[0].val.str_val.len = 0;
00657                         vals1[3].val.str_val = *_c->aor;
00658                 } else {
00659                         vals1[0].val.str_val.len = dom - _c->aor->s;
00660                         vals1[3].val.str_val.s = dom + 1;
00661                         vals1[3].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1;
00662                 }
00663         }
00664 
00665         if (ul_db_layer_update(_d, &vals1[0].val.str_val, &vals1[3].val.str_val, keys1, 0, vals1, keys2, vals2, 
00666         (use_domain) ? (4) : (3), 11) < 0) {
00667                 LM_ERR("updating database failed\n");
00668                 return -1;
00669         }
00670 
00671         return 0;
00672 }
00673 
00674 
00680 int db_delete_ucontact(ucontact_t* _c)
00681 {
00682         char* dom;
00683         db_key_t keys[4];
00684         db_val_t vals[4];
00685 
00686         if (_c->flags & FL_MEM) {
00687                 return 0;
00688         }
00689         struct udomain * _d;
00690         if(register_udomain(_c->domain->s, &_d) < 0){
00691                 return -1;
00692         }
00693 
00694         keys[0] = &user_col;
00695         keys[1] = &contact_col;
00696         keys[2] = &callid_col;
00697         keys[3] = &domain_col;
00698 
00699         vals[0].type = DB1_STR;
00700         vals[0].nul = 0;
00701         vals[0].val.str_val = *_c->aor;
00702 
00703         vals[1].type = DB1_STR;
00704         vals[1].nul = 0;
00705         vals[1].val.str_val = _c->c;
00706 
00707         vals[2].type = DB1_STR;
00708         vals[2].nul = 0;
00709         vals[2].val.str_val = _c->callid;
00710 
00711         if (use_domain) {
00712                 vals[3].type = DB1_STR;
00713                 vals[3].nul = 0;
00714                 dom = memchr(_c->aor->s, '@', _c->aor->len);
00715                 if (dom==0) {
00716                         vals[0].val.str_val.len = 0;
00717                         vals[3].val.str_val = *_c->aor;
00718                 } else {
00719                         vals[0].val.str_val.len = dom - _c->aor->s;
00720                         vals[3].val.str_val.s = dom + 1;
00721                         vals[3].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1;
00722                 }
00723         }
00724 
00725         if (ul_db_layer_delete(_d, &vals[0].val.str_val, &vals[3].val.str_val, keys, 0, vals, (use_domain) ? (4) : (3)) < 0) {
00726                 LM_ERR("deleting from database failed\n");
00727                 return -1;
00728         }
00729 
00730         return 0;
00731 }
00732 
00733 
00739 static inline void unlink_contact(struct urecord* _r, ucontact_t* _c)
00740 {
00741         if (_c->prev) {
00742                 _c->prev->next = _c->next;
00743                 if (_c->next) {
00744                         _c->next->prev = _c->prev;
00745                 }
00746         } else {
00747                 _r->contacts = _c->next;
00748                 if (_c->next) {
00749                         _c->next->prev = 0;
00750                 }
00751         }
00752 }
00753 
00754 
00760 static inline void update_contact_pos(struct urecord* _r, ucontact_t* _c)
00761 {
00762         ucontact_t *pos, *ppos;
00763 
00764         if (desc_time_order) {
00765                 /* order by time - first the newest */
00766                 if (_c->prev==0)
00767                         return;
00768                 unlink_contact(_r, _c);
00769                 /* insert it at the beginning */
00770                 _c->next = _r->contacts;
00771                 _c->prev = 0;
00772                 _r->contacts->prev = _c;
00773                 _r->contacts = _c;
00774         } else {
00775                 /* order by q - first the smaller q */
00776                 if ( (_c->prev==0 || _c->q<=_c->prev->q)
00777                 && (_c->next==0 || _c->q>=_c->next->q)  )
00778                         return;
00779                 /* need to move , but where? */
00780                 unlink_contact(_r, _c);
00781                 _c->next = _c->prev = 0;
00782                 for(pos=_r->contacts,ppos=0;pos&&pos->q<_c->q;ppos=pos,pos=pos->next);
00783                 if (pos) {
00784                         if (!pos->prev) {
00785                                 pos->prev = _c;
00786                                 _c->next = pos;
00787                                 _r->contacts = _c;
00788                         } else {
00789                                 _c->next = pos;
00790                                 _c->prev = pos->prev;
00791                                 pos->prev->next = _c;
00792                                 pos->prev = _c;
00793                         }
00794                 } else if (ppos) {
00795                         ppos->next = _c;
00796                         _c->prev = ppos;
00797                 } else {
00798                         _r->contacts = _c;
00799                 }
00800         }
00801 }
00802 
00803 
00811 int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci)
00812 {
00813         /* we have to update memory in any case, but database directly
00814          * only in db_mode 1 */
00815         if (mem_update_ucontact( _c, _ci) < 0) {
00816                 LM_ERR("failed to update memory\n");
00817                 return -1;
00818         }
00819 
00820         /* run callbacks for UPDATE event */
00821         if (exists_ulcb_type(UL_CONTACT_UPDATE))
00822         {
00823                 LM_DBG("exists callback for type= UL_CONTACT_UPDATE\n");
00824                 run_ul_callbacks( UL_CONTACT_UPDATE, _c);
00825         }
00826 
00827         if (_r && db_mode!=DB_ONLY)
00828                 update_contact_pos( _r, _c);
00829 
00830         st_update_ucontact(_c);
00831 
00832         if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) {
00833                 /*
00834                  * prevent problems when we're in a failover situation: the first DB contains
00835                  * the complete location entries, the other misses some of them. Before the
00836                  * update it checks for a entry in the first DB, this is ok. But the update
00837                  * in the second DB will not work. Thus the expire mechanism don't work, it
00838                  * takes too long until both DBs have the same number of entries again.
00839                  */
00840                 if (db_insert_ucontact(_c) < 0) {
00841                         LM_ERR("failed to insert_update database\n");
00842                         return -1;
00843                 } else {
00844                         _c->state = CS_SYNC;
00845                 }
00846         }
00847         return 0;
00848 }