modules_k/usrloc/ucontact.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 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 "ul_mod.h"
00045 #include "ul_callback.h"
00046 #include "usrloc.h"
00047 #include "urecord.h"
00048 #include "ucontact.h"
00049 #include "usrloc.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         if (_ci->ruid.s && _ci->ruid.len) {
00081                 if (shm_str_dup( &c->ruid, &_ci->ruid) < 0) goto error;
00082         }
00083         if (_ci->instance.s && _ci->instance.len) {
00084                 if (shm_str_dup( &c->instance, &_ci->instance) < 0) goto error;
00085         }
00086 
00087         c->domain = _dom;
00088         c->aor = _aor;
00089         c->expires = _ci->expires;
00090         c->q = _ci->q;
00091         c->sock = _ci->sock;
00092         c->cseq = _ci->cseq;
00093         c->state = CS_NEW;
00094         c->flags = _ci->flags;
00095         c->cflags = _ci->cflags;
00096         c->methods = _ci->methods;
00097         c->reg_id = _ci->reg_id;
00098         c->last_modified = _ci->last_modified;
00099 
00100         return c;
00101 error:
00102         LM_ERR("no more shm memory\n");
00103         if (c->path.s) shm_free(c->path.s);
00104         if (c->received.s) shm_free(c->received.s);
00105         if (c->user_agent.s) shm_free(c->user_agent.s);
00106         if (c->callid.s) shm_free(c->callid.s);
00107         if (c->c.s) shm_free(c->c.s);
00108         if (c->ruid.s) shm_free(c->ruid.s);
00109         if (c->instance.s) shm_free(c->instance.s);
00110         shm_free(c);
00111         return 0;
00112 }
00113 
00114 
00115 
00120 void free_ucontact(ucontact_t* _c)
00121 {
00122         if (!_c) return;
00123         if (_c->path.s) shm_free(_c->path.s);
00124         if (_c->received.s) shm_free(_c->received.s);
00125         if (_c->user_agent.s) shm_free(_c->user_agent.s);
00126         if (_c->callid.s) shm_free(_c->callid.s);
00127         if (_c->c.s) shm_free(_c->c.s);
00128         if (_c->ruid.s) shm_free(_c->ruid.s);
00129         if (_c->instance.s) shm_free(_c->instance.s);
00130         shm_free( _c );
00131 }
00132 
00133 
00139 void print_ucontact(FILE* _f, ucontact_t* _c)
00140 {
00141         time_t t = time(0);
00142         char* st;
00143 
00144         switch(_c->state) {
00145         case CS_NEW:   st = "CS_NEW";     break;
00146         case CS_SYNC:  st = "CS_SYNC";    break;
00147         case CS_DIRTY: st = "CS_DIRTY";   break;
00148         default:       st = "CS_UNKNOWN"; break;
00149         }
00150 
00151         fprintf(_f, "~~~Contact(%p)~~~\n", _c);
00152         fprintf(_f, "domain    : '%.*s'\n", _c->domain->len, ZSW(_c->domain->s));
00153         fprintf(_f, "aor       : '%.*s'\n", _c->aor->len, ZSW(_c->aor->s));
00154         fprintf(_f, "Contact   : '%.*s'\n", _c->c.len, ZSW(_c->c.s));
00155         fprintf(_f, "Expires   : ");
00156         if (_c->expires == 0) {
00157                 fprintf(_f, "Permanent\n");
00158         } else if (_c->expires == UL_EXPIRED_TIME) {
00159                 fprintf(_f, "Deleted\n");
00160         } else if (t > _c->expires) {
00161                 fprintf(_f, "Expired\n");
00162         } else {
00163                 fprintf(_f, "%u\n", (unsigned int)(_c->expires - t));
00164         }
00165         fprintf(_f, "q         : %s\n", q2str(_c->q, 0));
00166         fprintf(_f, "Call-ID   : '%.*s'\n", _c->callid.len, ZSW(_c->callid.s));
00167         fprintf(_f, "CSeq      : %d\n", _c->cseq);
00168         fprintf(_f, "User-Agent: '%.*s'\n",
00169                 _c->user_agent.len, ZSW(_c->user_agent.s));
00170         fprintf(_f, "received  : '%.*s'\n",
00171                 _c->received.len, ZSW(_c->received.s));
00172         fprintf(_f, "Path      : '%.*s'\n",
00173                 _c->path.len, ZSW(_c->path.s));
00174         fprintf(_f, "State     : %s\n", st);
00175         fprintf(_f, "Flags     : %u\n", _c->flags);
00176         if (_c->sock) {
00177                 fprintf(_f, "Sock      : %.*s (%p)\n",
00178                                 _c->sock->sock_str.len,_c->sock->sock_str.s,_c->sock);
00179         } else {
00180                 fprintf(_f, "Sock      : none (null)\n");
00181         }
00182         fprintf(_f, "Methods   : %u\n", _c->methods);
00183         fprintf(_f, "ruid      : '%.*s'\n",
00184                 _c->ruid.len, ZSW(_c->ruid.s));
00185         fprintf(_f, "instance  : '%.*s'\n",
00186                 _c->instance.len, ZSW(_c->instance.s));
00187         fprintf(_f, "reg-id    : %u\n", _c->reg_id);
00188         fprintf(_f, "next      : %p\n", _c->next);
00189         fprintf(_f, "prev      : %p\n", _c->prev);
00190         fprintf(_f, "~~~/Contact~~~~\n");
00191 }
00192 
00193 
00200 int mem_update_ucontact(ucontact_t* _c, ucontact_info_t* _ci)
00201 {
00202 #define update_str(_old,_new) \
00203         do{\
00204                 if ((_old)->len < (_new)->len) { \
00205                         ptr = (char*)shm_malloc((_new)->len); \
00206                         if (ptr == 0) { \
00207                                 LM_ERR("no more shm memory\n"); \
00208                                 return -1; \
00209                         }\
00210                         memcpy(ptr, (_new)->s, (_new)->len);\
00211                         if ((_old)->s) shm_free((_old)->s);\
00212                         (_old)->s = ptr;\
00213                 } else {\
00214                         memcpy((_old)->s, (_new)->s, (_new)->len);\
00215                 }\
00216                 (_old)->len = (_new)->len;\
00217         } while(0)
00218 
00219         char* ptr;
00220 
00221         /* No need to update Callid as it is constant 
00222          * per ucontact (set at insert time)  -bogdan */
00223 
00224         update_str( &_c->user_agent, _ci->user_agent);
00225 
00226         if (_ci->received.s && _ci->received.len) {
00227                 update_str( &_c->received, &_ci->received);
00228         } else {
00229                 if (_c->received.s) shm_free(_c->received.s);
00230                 _c->received.s = 0;
00231                 _c->received.len = 0;
00232         }
00233         
00234         if (_ci->path) {
00235                 update_str( &_c->path, _ci->path);
00236         } else {
00237                 if (_c->path.s) shm_free(_c->path.s);
00238                 _c->path.s = 0;
00239                 _c->path.len = 0;
00240         }
00241 
00242         _c->sock = _ci->sock;
00243         _c->expires = _ci->expires;
00244         _c->q = _ci->q;
00245         _c->cseq = _ci->cseq;
00246         _c->methods = _ci->methods;
00247         _c->last_modified = _ci->last_modified;
00248         _c->flags = _ci->flags;
00249         _c->cflags = _ci->cflags;
00250 
00251         return 0;
00252 }
00253 
00254 
00255 /* ================ State related functions =============== */
00256 
00261 void st_update_ucontact(ucontact_t* _c)
00262 {
00263         switch(_c->state) {
00264         case CS_NEW:
00265                          /* Contact is new and is not in the database yet,
00266                           * we remain in the same state here because the
00267                           * contact must be inserted later in the timer
00268                           */
00269                 break;
00270 
00271         case CS_SYNC:
00272                          /* For db mode 1 & 2 a modified contact needs to be 
00273                           * updated also in the database, so transit into 
00274                           * CS_DIRTY and let the timer to do the update 
00275                           * again. For db mode 1 we try to update right
00276                           * now and if fails, let the timer to do the job
00277                           */
00278                 if (db_mode == WRITE_BACK || db_mode == WRITE_THROUGH) {
00279                         _c->state = CS_DIRTY;
00280                 }
00281                 break;
00282 
00283         case CS_DIRTY:
00284                          /* Modification of dirty contact results in
00285                           * dirty contact again, don't change anything
00286                           */
00287                 break;
00288         }
00289 }
00290 
00291 
00297 int st_delete_ucontact(ucontact_t* _c)
00298 {
00299         switch(_c->state) {
00300         case CS_NEW:
00301                      /* Contact is new and isn't in the database
00302                       * yet, we can delete it from the memory
00303                       * safely.
00304                       */
00305                 return 1;
00306 
00307         case CS_SYNC:
00308         case CS_DIRTY:
00309                      /* Contact is in the database,
00310                       * we cannot remove it from the memory 
00311                       * directly, but we can set expires to zero
00312                       * and the timer will take care of deleting 
00313                       * the contact from the memory as well as 
00314                       * from the database
00315                       */
00316                 if (db_mode == WRITE_BACK) {
00317                         _c->expires = UL_EXPIRED_TIME;
00318                         return 0;
00319                 } else {
00320                              /* WRITE_THROUGH or NO_DB -- we can
00321                               * remove it from memory immediately and
00322                               * the calling function would also remove
00323                               * it from the database if needed
00324                               */
00325                         return 1;
00326                 }
00327         }
00328 
00329         return 0; /* Makes gcc happy */
00330 }
00331 
00332 
00338 int st_expired_ucontact(ucontact_t* _c)
00339 {
00340              /* There is no need to change contact
00341               * state, because the contact will
00342               * be deleted anyway
00343               */
00344 
00345         switch(_c->state) {
00346         case CS_NEW:
00347                      /* Contact is not in the database
00348                       * yet, remove it from memory only
00349                       */
00350                 return 0;
00351 
00352         case CS_SYNC:
00353         case CS_DIRTY:
00354                      /* Remove from database here */
00355                 return 1;
00356         }
00357 
00358         return 0; /* Makes gcc happy */
00359 }
00360 
00361 
00367 int st_flush_ucontact(ucontact_t* _c)
00368 {
00369         switch(_c->state) {
00370         case CS_NEW:
00371                      /* Contact is new and is not in
00372                       * the database yet so we have
00373                       * to insert it
00374                       */
00375                 _c->state = CS_SYNC;
00376                 return 1;
00377 
00378         case CS_SYNC:
00379                      /* Contact is synchronized, do
00380                       * nothing
00381                       */
00382                 return 0;
00383 
00384         case CS_DIRTY:
00385                      /* Contact has been modified and
00386                       * is in the db already so we
00387                       * have to update it
00388                       */
00389                 _c->state = CS_SYNC;
00390                 return 2;
00391         }
00392 
00393         return 0; /* Makes gcc happy */
00394 }
00395 
00396 
00397 /* ============== Database related functions ================ */
00398 
00404 int db_insert_ucontact(ucontact_t* _c)
00405 {
00406         char* dom;
00407         db_key_t keys[18];
00408         db_val_t vals[18];
00409         int nr_cols;
00410         
00411         if (_c->flags & FL_MEM) {
00412                 return 0;
00413         }
00414 
00415         keys[0] = &user_col;
00416         keys[1] = &contact_col;
00417         keys[2] = &expires_col;
00418         keys[3] = &q_col;
00419         keys[4] = &callid_col;
00420         keys[5] = &cseq_col;
00421         keys[6] = &flags_col;
00422         keys[7] = &cflags_col;
00423         keys[8] = &user_agent_col;
00424         keys[9] = &received_col;
00425         keys[10] = &path_col;
00426         keys[11] = &sock_col;
00427         keys[12] = &methods_col;
00428         keys[13] = &last_mod_col;
00429         keys[14] = &ruid_col;
00430         keys[15] = &instance_col;
00431         keys[16] = &reg_id_col;
00432         keys[17] = &domain_col;
00433 
00434         vals[0].type = DB1_STR;
00435         vals[0].nul = 0;
00436         vals[0].val.str_val.s = _c->aor->s;
00437         vals[0].val.str_val.len = _c->aor->len;
00438 
00439         vals[1].type = DB1_STR;
00440         vals[1].nul = 0;
00441         vals[1].val.str_val.s = _c->c.s; 
00442         vals[1].val.str_val.len = _c->c.len;
00443 
00444         vals[2].type = DB1_DATETIME;
00445         vals[2].nul = 0;
00446         vals[2].val.time_val = _c->expires;
00447 
00448         vals[3].type = DB1_DOUBLE;
00449         vals[3].nul = 0;
00450         vals[3].val.double_val = q2double(_c->q);
00451 
00452         vals[4].type = DB1_STR;
00453         vals[4].nul = 0;
00454         vals[4].val.str_val.s = _c->callid.s;
00455         vals[4].val.str_val.len = _c->callid.len;
00456 
00457         vals[5].type = DB1_INT;
00458         vals[5].nul = 0;
00459         vals[5].val.int_val = _c->cseq;
00460 
00461         vals[6].type = DB1_INT;
00462         vals[6].nul = 0;
00463         vals[6].val.bitmap_val = _c->flags;
00464 
00465         vals[7].type = DB1_INT;
00466         vals[7].nul = 0;
00467         vals[7].val.bitmap_val = _c->cflags;
00468 
00469         vals[8].type = DB1_STR;
00470         vals[8].nul = 0;
00471         vals[8].val.str_val.s = _c->user_agent.s;
00472         vals[8].val.str_val.len = _c->user_agent.len;
00473 
00474         vals[9].type = DB1_STR;
00475         if (_c->received.s == 0) {
00476                 vals[9].nul = 1;
00477         } else {
00478                 vals[9].nul = 0;
00479                 vals[9].val.str_val.s = _c->received.s;
00480                 vals[9].val.str_val.len = _c->received.len;
00481         }
00482         
00483         vals[10].type = DB1_STR;
00484         if (_c->path.s == 0) {
00485                 vals[10].nul = 1;
00486         } else {
00487                 vals[10].nul = 0;
00488                 vals[10].val.str_val.s = _c->path.s;
00489                 vals[10].val.str_val.len = _c->path.len;
00490         }
00491 
00492         vals[11].type = DB1_STR;
00493         if (_c->sock) {
00494                 vals[11].val.str_val = _c->sock->sock_str;
00495                 vals[11].nul = 0;
00496         } else {
00497                 vals[11].nul = 1;
00498         }
00499 
00500         vals[12].type = DB1_BITMAP;
00501         if (_c->methods == 0xFFFFFFFF) {
00502                 vals[12].nul = 1;
00503         } else {
00504                 vals[12].val.bitmap_val = _c->methods;
00505                 vals[12].nul = 0;
00506         }
00507 
00508         vals[13].type = DB1_DATETIME;
00509         vals[13].nul = 0;
00510         vals[13].val.time_val = _c->last_modified;
00511 
00512         nr_cols = 14;
00513 
00514         if(_c->ruid.len>0)
00515         {
00516                 vals[nr_cols].type = DB1_STR;
00517                 vals[nr_cols].nul = 0;
00518                 vals[nr_cols].val.str_val = _c->ruid;
00519         } else {
00520                 vals[nr_cols].nul = 1;
00521         }
00522         nr_cols++;
00523 
00524         if(_c->instance.len>0)
00525         {
00526                 vals[nr_cols].type = DB1_STR;
00527                 vals[nr_cols].nul = 0;
00528                 vals[nr_cols].val.str_val = _c->instance;
00529         } else {
00530                 vals[nr_cols].nul = 1;
00531         }
00532         nr_cols++;
00533 
00534         vals[nr_cols].type = DB1_INT;
00535         vals[nr_cols].nul = 0;
00536         vals[nr_cols].val.int_val = (int)_c->reg_id;
00537         nr_cols++;
00538 
00539         if (use_domain) {
00540                 vals[nr_cols].type = DB1_STR;
00541                 vals[nr_cols].nul = 0;
00542 
00543                 dom = memchr(_c->aor->s, '@', _c->aor->len);
00544                 if (dom==0) {
00545                         vals[0].val.str_val.len = 0;
00546                         vals[nr_cols].val.str_val = *_c->aor;
00547                 } else {
00548                         vals[0].val.str_val.len = dom - _c->aor->s;
00549                         vals[nr_cols].val.str_val.s = dom + 1;
00550                         vals[nr_cols].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1;
00551                 }
00552                 nr_cols++;
00553         }
00554 
00555         if (ul_dbf.use_table(ul_dbh, _c->domain) < 0) {
00556                 LM_ERR("sql use_table failed\n");
00557                 return -1;
00558         }
00559 
00560         if (ul_dbf.insert(ul_dbh, keys, vals, nr_cols) < 0) {
00561                 LM_ERR("inserting contact in db failed\n");
00562                 return -1;
00563         }
00564 
00565         return 0;
00566 }
00567 
00568 
00574 int db_update_ucontact(ucontact_t* _c)
00575 {
00576         char* dom;
00577         db_key_t keys1[4];
00578         db_val_t vals1[4];
00579 
00580         db_key_t keys2[14];
00581         db_val_t vals2[14];
00582         int nr_cols2;
00583 
00584 
00585         if (_c->flags & FL_MEM) {
00586                 return 0;
00587         }
00588 
00589         keys1[0] = &user_col;
00590         keys1[1] = &contact_col;
00591         keys1[2] = &callid_col;
00592         keys1[3] = &domain_col;
00593         keys2[0] = &expires_col;
00594         keys2[1] = &q_col;
00595         keys2[2] = &cseq_col;
00596         keys2[3] = &flags_col;
00597         keys2[4] = &cflags_col;
00598         keys2[5] = &user_agent_col;
00599         keys2[6] = &received_col;
00600         keys2[7] = &path_col;
00601         keys2[8] = &sock_col;
00602         keys2[9] = &methods_col;
00603         keys2[10] = &last_mod_col;
00604         keys2[11] = &ruid_col;
00605         keys2[12] = &instance_col;
00606         keys2[13] = &reg_id_col;
00607 
00608         vals1[0].type = DB1_STR;
00609         vals1[0].nul = 0;
00610         vals1[0].val.str_val = *_c->aor;
00611 
00612         vals1[1].type = DB1_STR;
00613         vals1[1].nul = 0;
00614         vals1[1].val.str_val = _c->c;
00615 
00616         vals1[2].type = DB1_STR;
00617         vals1[2].nul = 0;
00618         vals1[2].val.str_val = _c->callid;
00619 
00620         vals2[0].type = DB1_DATETIME;
00621         vals2[0].nul = 0;
00622         vals2[0].val.time_val = _c->expires;
00623 
00624         vals2[1].type = DB1_DOUBLE;
00625         vals2[1].nul = 0;
00626         vals2[1].val.double_val = q2double(_c->q);
00627 
00628         vals2[2].type = DB1_INT;
00629         vals2[2].nul = 0;
00630         vals2[2].val.int_val = _c->cseq;
00631 
00632         vals2[3].type = DB1_INT;
00633         vals2[3].nul = 0;
00634         vals2[3].val.bitmap_val = _c->flags;
00635 
00636         vals2[4].type = DB1_INT;
00637         vals2[4].nul = 0;
00638         vals2[4].val.bitmap_val = _c->cflags;
00639 
00640         vals2[5].type = DB1_STR;
00641         vals2[5].nul = 0;
00642         vals2[5].val.str_val = _c->user_agent;
00643 
00644         vals2[6].type = DB1_STR;
00645         if (_c->received.s == 0) {
00646                 vals2[6].nul = 1;
00647         } else {
00648                 vals2[6].nul = 0;
00649                 vals2[6].val.str_val = _c->received;
00650         }
00651         
00652         vals2[7].type = DB1_STR;
00653         if (_c->path.s == 0) {
00654                 vals2[7].nul = 1;
00655         } else {
00656                 vals2[7].nul = 0;
00657                 vals2[7].val.str_val = _c->path;
00658         }
00659 
00660         vals2[8].type = DB1_STR;
00661         if (_c->sock) {
00662                 vals2[8].val.str_val = _c->sock->sock_str;
00663                 vals2[8].nul = 0;
00664         } else {
00665                 vals2[8].nul = 1;
00666         }
00667 
00668         vals2[9].type = DB1_BITMAP;
00669         if (_c->methods == 0xFFFFFFFF) {
00670                 vals2[9].nul = 1;
00671         } else {
00672                 vals2[9].val.bitmap_val = _c->methods;
00673                 vals2[9].nul = 0;
00674         }
00675 
00676         vals2[10].type = DB1_DATETIME;
00677         vals2[10].nul = 0;
00678         vals2[10].val.time_val = _c->last_modified;
00679 
00680         nr_cols2 = 11;
00681         if(_c->ruid.len>0)
00682         {
00683                 vals2[nr_cols2].type = DB1_STR;
00684                 vals2[nr_cols2].nul = 0;
00685                 vals2[nr_cols2].val.str_val = _c->ruid;
00686         } else {
00687                 vals2[nr_cols2].nul = 1;
00688         }
00689         nr_cols2++;
00690 
00691         if(_c->instance.len>0)
00692         {
00693                 vals2[nr_cols2].type = DB1_STR;
00694                 vals2[nr_cols2].nul = 0;
00695                 vals2[nr_cols2].val.str_val = _c->instance;
00696         } else {
00697                 vals2[nr_cols2].nul = 1;
00698         }
00699         nr_cols2++;
00700 
00701         vals2[nr_cols2].type = DB1_INT;
00702         vals2[nr_cols2].nul = 0;
00703         vals2[nr_cols2].val.int_val = (int)_c->reg_id;
00704         nr_cols2++;
00705 
00706         if (use_domain) {
00707                 vals1[3].type = DB1_STR;
00708                 vals1[3].nul = 0;
00709                 dom = memchr(_c->aor->s, '@', _c->aor->len);
00710                 if (dom==0) {
00711                         vals1[0].val.str_val.len = 0;
00712                         vals1[3].val.str_val = *_c->aor;
00713                 } else {
00714                         vals1[0].val.str_val.len = dom - _c->aor->s;
00715                         vals1[3].val.str_val.s = dom + 1;
00716                         vals1[3].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1;
00717                 }
00718         }
00719 
00720         if (ul_dbf.use_table(ul_dbh, _c->domain) < 0) {
00721                 LM_ERR("sql use_table failed\n");
00722                 return -1;
00723         }
00724 
00725         if (ul_dbf.update(ul_dbh, keys1, 0, vals1, keys2, vals2, 
00726         (use_domain) ? (4) : (3), nr_cols2) < 0) {
00727                 LM_ERR("updating database failed\n");
00728                 return -1;
00729         }
00730 
00731         return 0;
00732 }
00733 
00734 
00740 int db_delete_ucontact(ucontact_t* _c)
00741 {
00742         char* dom;
00743         db_key_t keys[4];
00744         db_val_t vals[4];
00745 
00746         if (_c->flags & FL_MEM) {
00747                 return 0;
00748         }
00749 
00750         keys[0] = &user_col;
00751         keys[1] = &contact_col;
00752         keys[2] = &callid_col;
00753         keys[3] = &domain_col;
00754 
00755         vals[0].type = DB1_STR;
00756         vals[0].nul = 0;
00757         vals[0].val.str_val = *_c->aor;
00758 
00759         vals[1].type = DB1_STR;
00760         vals[1].nul = 0;
00761         vals[1].val.str_val = _c->c;
00762 
00763         vals[2].type = DB1_STR;
00764         vals[2].nul = 0;
00765         vals[2].val.str_val = _c->callid;
00766 
00767         if (use_domain) {
00768                 vals[3].type = DB1_STR;
00769                 vals[3].nul = 0;
00770                 dom = memchr(_c->aor->s, '@', _c->aor->len);
00771                 if (dom==0) {
00772                         vals[0].val.str_val.len = 0;
00773                         vals[3].val.str_val = *_c->aor;
00774                 } else {
00775                         vals[0].val.str_val.len = dom - _c->aor->s;
00776                         vals[3].val.str_val.s = dom + 1;
00777                         vals[3].val.str_val.len = _c->aor->s + _c->aor->len - dom - 1;
00778                 }
00779         }
00780 
00781         if (ul_dbf.use_table(ul_dbh, _c->domain) < 0) {
00782                 LM_ERR("sql use_table failed\n");
00783                 return -1;
00784         }
00785 
00786         if (ul_dbf.delete(ul_dbh, keys, 0, vals, (use_domain) ? (4) : (3)) < 0) {
00787                 LM_ERR("deleting from database failed\n");
00788                 return -1;
00789         }
00790 
00791         return 0;
00792 }
00793 
00794 
00800 static inline void unlink_contact(struct urecord* _r, ucontact_t* _c)
00801 {
00802         if (_c->prev) {
00803                 _c->prev->next = _c->next;
00804                 if (_c->next) {
00805                         _c->next->prev = _c->prev;
00806                 }
00807         } else {
00808                 _r->contacts = _c->next;
00809                 if (_c->next) {
00810                         _c->next->prev = 0;
00811                 }
00812         }
00813 }
00814 
00815 
00821 static inline void update_contact_pos(struct urecord* _r, ucontact_t* _c)
00822 {
00823         ucontact_t *pos, *ppos;
00824 
00825         if (desc_time_order) {
00826                 /* order by time - first the newest */
00827                 if (_c->prev==0)
00828                         return;
00829                 unlink_contact(_r, _c);
00830                 /* insert it at the beginning */
00831                 _c->next = _r->contacts;
00832                 _c->prev = 0;
00833                 _r->contacts->prev = _c;
00834                 _r->contacts = _c;
00835         } else {
00836                 /* order by q - first the smaller q */
00837                 if ( (_c->prev==0 || _c->q<=_c->prev->q)
00838                 && (_c->next==0 || _c->q>=_c->next->q)  )
00839                         return;
00840                 /* need to move , but where? */
00841                 unlink_contact(_r, _c);
00842                 _c->next = _c->prev = 0;
00843                 for(pos=_r->contacts,ppos=0;pos&&pos->q<_c->q;ppos=pos,pos=pos->next);
00844                 if (pos) {
00845                         if (!pos->prev) {
00846                                 pos->prev = _c;
00847                                 _c->next = pos;
00848                                 _r->contacts = _c;
00849                         } else {
00850                                 _c->next = pos;
00851                                 _c->prev = pos->prev;
00852                                 pos->prev->next = _c;
00853                                 pos->prev = _c;
00854                         }
00855                 } else if (ppos) {
00856                         ppos->next = _c;
00857                         _c->prev = ppos;
00858                 } else {
00859                         _r->contacts = _c;
00860                 }
00861         }
00862 }
00863 
00864 
00872 int update_ucontact(struct urecord* _r, ucontact_t* _c, ucontact_info_t* _ci)
00873 {
00874         int res;
00875 
00876         /* we have to update memory in any case, but database directly
00877          * only in db_mode 1 */
00878         if (mem_update_ucontact( _c, _ci) < 0) {
00879                 LM_ERR("failed to update memory\n");
00880                 return -1;
00881         }
00882 
00883         /* run callbacks for UPDATE event */
00884         if (exists_ulcb_type(UL_CONTACT_UPDATE))
00885         {
00886                 LM_DBG("exists callback for type= UL_CONTACT_UPDATE\n");
00887                 run_ul_callbacks( UL_CONTACT_UPDATE, _c);
00888         }
00889 
00890         if (_r && db_mode!=DB_ONLY)
00891                 update_contact_pos( _r, _c);
00892 
00893         st_update_ucontact(_c);
00894 
00895         if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) {
00896                 if (ul_db_update_as_insert)
00897                         res = db_insert_ucontact(_c);
00898                 else
00899                         res = db_update_ucontact(_c);
00900 
00901                 if (res < 0) {
00902                         LM_ERR("failed to update database\n");
00903                         return -1;
00904                 } else {
00905                         _c->state = CS_SYNC;
00906                 }
00907         }
00908         return 0;
00909 }