usrloc: delete contact attributes in db-only mode
[sip-router] / src / modules / usrloc / udomain.c
1 /*
2  * Copyright (C) 2001-2003 FhG Fokus
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 /*! \file
23  *  \brief USRLOC - Userloc domain handling functions
24  *  \ingroup usrloc
25  *
26  * - Module: \ref usrloc
27  */
28
29 #include "udomain.h"
30 #include <string.h>
31 #include "../../core/parser/parse_methods.h"
32 #include "../../core/mem/shm_mem.h"
33 #include "../../core/dprint.h"
34 #include "../../lib/srdb1/db.h"
35 #include "../../core/socket_info.h"
36 #include "../../core/ut.h"
37 #include "../../core/hashes.h"
38 #include "../../core/sr_module.h"
39 #include "usrloc_mod.h"            /* usrloc module parameters */
40 #include "usrloc.h"
41 #include "utime.h"
42 #include "usrloc.h"
43 #include "ul_callback.h"
44 #include "urecord.h"
45
46 extern int ul_rm_expired_delay;
47
48 #ifdef STATISTICS
49 static char *build_stat_name( str* domain, char *var_name)
50 {
51         int n;
52         char *s;
53         char *p;
54
55         n = domain->len + 1 + strlen(var_name) + 1;
56         s = (char*)shm_malloc( n );
57         if (s==0) {
58                 LM_ERR("no more shm mem\n");
59                 return 0;
60         }
61         memcpy( s, domain->s, domain->len);
62         p = s + domain->len;
63         *(p++) = '-';
64         memcpy( p , var_name, strlen(var_name));
65         p += strlen(var_name);
66         *(p++) = 0;
67         return s;
68 }
69 #endif
70
71
72 /*!
73  * \brief Create a new domain structure
74  * \param  _n is pointer to str representing name of the domain, the string is
75  * not copied, it should point to str structure stored in domain list
76  * \param _s is hash table size
77  * \param _d new created domain
78  * \return 0 on success, -1 on failure
79  */
80 int new_udomain(str* _n, int _s, udomain_t** _d)
81 {
82         int i;
83 #ifdef STATISTICS
84         char *name;
85 #endif
86
87         /* Must be always in shared memory, since
88          * the cache is accessed from timer which
89          * lives in a separate process
90          */
91         *_d = (udomain_t*)shm_malloc(sizeof(udomain_t));
92         if (!(*_d)) {
93                 LM_ERR("new_udomain(): No memory left\n");
94                 goto error0;
95         }
96         memset(*_d, 0, sizeof(udomain_t));
97
98         (*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s);
99         if (!(*_d)->table) {
100                 LM_ERR("no memory left 2\n");
101                 goto error1;
102         }
103
104         (*_d)->name = _n;
105
106         for(i = 0; i < _s; i++) {
107                 if(init_slot(*_d, &((*_d)->table[i]), i)<0) {
108                         LM_ERR("failed to init hash table slot %d\n", i);
109                         goto error2;
110                 }
111         }
112
113         (*_d)->size = _s;
114
115 #ifdef STATISTICS
116         /* register the statistics */
117         if ( (name=build_stat_name(_n,"users"))==0 || register_stat("usrloc",
118         name, &(*_d)->users, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
119                 LM_ERR("failed to add stat variable\n");
120                 goto error2;
121         }
122         if ( (name=build_stat_name(_n,"contacts"))==0 || register_stat("usrloc",
123         name, &(*_d)->contacts, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
124                 LM_ERR("failed to add stat variable\n");
125                 goto error2;
126         }
127         if ( (name=build_stat_name(_n,"expires"))==0 || register_stat("usrloc",
128         name, &(*_d)->expires, STAT_SHM_NAME)!=0 ) {
129                 LM_ERR("failed to add stat variable\n");
130                 goto error2;
131         }
132 #endif
133
134         return 0;
135 #ifdef STATISTICS
136 error2:
137         shm_free((*_d)->table);
138 #endif
139 error1:
140         shm_free(*_d);
141 error0:
142         return -1;
143 }
144
145
146 /*!
147  * \brief Free all memory allocated for the domain
148  * \param _d freed domain
149  */
150 void free_udomain(udomain_t* _d)
151 {
152         int i;
153
154         if (_d->table) {
155                 for(i = 0; i < _d->size; i++) {
156                         deinit_slot(_d->table + i);
157                 }
158                 shm_free(_d->table);
159         }
160         shm_free(_d);
161 }
162
163
164 /*!
165  * \brief Returns a static dummy urecord for temporary usage
166  * \param _d domain (needed for the name)
167  * \param _aor address of record
168  * \param _r new created urecord
169  */
170 static inline void get_static_urecord(udomain_t* _d, str* _aor,
171                                                                                                                 struct urecord** _r)
172 {
173         static struct urecord r;
174
175         memset( &r, 0, sizeof(struct urecord) );
176         r.aor = *_aor;
177         r.aorhash = ul_get_aorhash(_aor);
178         r.domain = _d->name;
179         *_r = &r;
180 }
181
182
183 /*!
184  * \brief Debugging helper function
185  */
186 void print_udomain(FILE* _f, udomain_t* _d)
187 {
188         int i;
189         int max=0, slot=0, n=0;
190         struct urecord* r;
191         fprintf(_f, "---Domain---\n");
192         fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
193         fprintf(_f, "size : %d\n", _d->size);
194         fprintf(_f, "table: %p\n", _d->table);
195         /*fprintf(_f, "lock : %d\n", _d->lock); -- can be a structure --andrei*/
196         fprintf(_f, "\n");
197         for(i=0; i<_d->size; i++)
198         {
199                 r = _d->table[i].first;
200                 n += _d->table[i].n;
201                 if(max<_d->table[i].n){
202                         max= _d->table[i].n;
203                         slot = i;
204                 }
205                 while(r) {
206                         print_urecord(_f, r);
207                         r = r->next;
208                 }
209         }
210         fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n);
211         fprintf(_f, "\n---/Domain---\n");
212 }
213
214
215 /*!
216  * \brief Convert database values into ucontact_info
217  *
218  * Convert database values into ucontact_info,
219  * expects 12 rows (contact, expirs, q, callid, cseq, flags,
220  * ua, received, path, socket, methods, last_modified)
221  * \param vals database values
222  * \param contact contact
223  * \param rcon restore connection id
224  * \return pointer to the ucontact_info on success, 0 on failure
225  */
226 static inline ucontact_info_t* dbrow2info(db_val_t *vals, str *contact, int rcon)
227 {
228         static ucontact_info_t ci;
229         static str callid, ua, received, host, path;
230         int port, proto;
231         char *p;
232
233         memset( &ci, 0, sizeof(ucontact_info_t));
234
235         contact->s = (char*)VAL_STRING(vals);
236         if (VAL_NULL(vals) || contact->s==0 || contact->s[0]==0) {
237                 LM_CRIT("bad contact\n");
238                 return 0;
239         }
240         contact->len = strlen(contact->s);
241
242         if (VAL_NULL(vals+1)) {
243                 LM_CRIT("empty expire\n");
244                 return 0;
245         }
246         ci.expires = UL_DB_EXPIRES_GET(vals+1);
247
248         if (VAL_NULL(vals+2)) {
249                 LM_CRIT("empty q\n");
250                 return 0;
251         }
252         ci.q = double2q(VAL_DOUBLE(vals+2));
253
254         if (VAL_NULL(vals+4)) {
255                 LM_CRIT("empty cseq_nr\n");
256                 return 0;
257         }
258         ci.cseq = VAL_INT(vals+4);
259
260         callid.s = (char*)VAL_STRING(vals+3);
261         if (VAL_NULL(vals+3) || !callid.s || !callid.s[0]) {
262                 LM_CRIT("bad callid\n");
263                 return 0;
264         }
265         callid.len  = strlen(callid.s);
266         ci.callid = &callid;
267
268         if (VAL_NULL(vals+5)) {
269                 LM_CRIT("empty flag\n");
270                 return 0;
271         }
272         ci.flags  = VAL_BITMAP(vals+5);
273
274         if (VAL_NULL(vals+6)) {
275                 LM_CRIT("empty cflag\n");
276                 return 0;
277         }
278         ci.cflags  = VAL_BITMAP(vals+6);
279
280         ua.s  = (char*)VAL_STRING(vals+7);
281         if (VAL_NULL(vals+7) || !ua.s || !ua.s[0]) {
282                 ua.s = 0;
283                 ua.len = 0;
284         } else {
285                 ua.len = strlen(ua.s);
286         }
287         ci.user_agent = &ua;
288
289         received.s  = (char*)VAL_STRING(vals+8);
290         if (VAL_NULL(vals+8) || !received.s || !received.s[0]) {
291                 received.len = 0;
292                 received.s = 0;
293         } else {
294                 received.len = strlen(received.s);
295         }
296         ci.received = received;
297
298         path.s  = (char*)VAL_STRING(vals+9);
299                 if (VAL_NULL(vals+9) || !path.s || !path.s[0]) {
300                         path.len = 0;
301                         path.s = 0;
302                 } else {
303                         path.len = strlen(path.s);
304                 }
305         ci.path= &path;
306
307         /* socket name */
308         p  = (char*)VAL_STRING(vals+10);
309         if (VAL_NULL(vals+10) || p==0 || p[0]==0){
310                 ci.sock = 0;
311         } else {
312                 if (parse_phostport( p, &host.s, &host.len,
313                 &port, &proto)!=0) {
314                         LM_ERR("bad socket <%s>\n", p);
315                         return 0;
316                 }
317                 ci.sock = grep_sock_info( &host, (unsigned short)port, proto);
318                 if (ci.sock==0) {
319                         LM_DBG("non-local socket <%s>...ignoring\n", p);
320                         if (skip_remote_socket) {
321                                 return 0;
322                         }
323                 }
324         }
325
326         /* supported methods */
327         if (VAL_NULL(vals+11)) {
328                 ci.methods = ALL_METHODS;
329         } else {
330                 ci.methods = VAL_BITMAP(vals+11);
331         }
332
333         /* last modified time */
334         if (!VAL_NULL(vals+12)) {
335                 ci.last_modified = UL_DB_EXPIRES_GET(vals+12);
336         }
337
338         /* record internal uid */
339         if (!VAL_NULL(vals+13)) {
340                 ci.ruid.s = (char*)VAL_STRING(vals+13);
341                 ci.ruid.len = strlen(ci.ruid.s);
342         }
343
344         /* sip instance */
345         if (!VAL_NULL(vals+14)) {
346                 ci.instance.s = (char*)VAL_STRING(vals+14);
347                 ci.instance.len = strlen(ci.instance.s);
348         }
349
350         /* reg-id */
351         if (!VAL_NULL(vals+15)) {
352                 ci.reg_id = VAL_UINT(vals+15);
353         }
354
355         /* server_id */
356         if (!VAL_NULL(vals+16)) {
357                 ci.server_id = VAL_UINT(vals+16);
358         }
359
360         /* tcp connection id (not restored always) */
361         ci.tcpconn_id = -1;
362         if(rcon==1 && !VAL_NULL(vals+17)) {
363                 ci.tcpconn_id = VAL_UINT(vals+17);
364         }
365
366         /* keepalive */
367         if (!VAL_NULL(vals+18)) {
368                 ci.keepalive = VAL_UINT(vals+18);
369         }
370
371         return &ci;
372 }
373
374
375 /*!
376  * \brief Load all records from a udomain
377  *
378  * Load all records from a udomain, useful to populate the
379  * memory cache on startup.
380  * \param _c database connection
381  * \param _d loaded domain
382  * \return 0 on success, -1 on failure
383  */
384 int preload_udomain(db1_con_t* _c, udomain_t* _d)
385 {
386         char uri[MAX_URI_SIZE];
387         ucontact_info_t *ci;
388         db_row_t *row;
389         db_key_t columns[21];
390         db1_res_t* res = NULL;
391         db_key_t keys[1]; /* where */
392         db_val_t vals[1];
393         db_op_t  ops[1];
394         str user, contact;
395         char* domain;
396         int i;
397         int n;
398
399         urecord_t* r;
400         ucontact_t* c;
401
402         columns[0] = &user_col;
403         columns[1] = &contact_col;
404         columns[2] = &expires_col;
405         columns[3] = &q_col;
406         columns[4] = &callid_col;
407         columns[5] = &cseq_col;
408         columns[6] = &flags_col;
409         columns[7] = &cflags_col;
410         columns[8] = &user_agent_col;
411         columns[9] = &received_col;
412         columns[10] = &path_col;
413         columns[11] = &sock_col;
414         columns[12] = &methods_col;
415         columns[13] = &last_mod_col;
416         columns[14] = &ruid_col;
417         columns[15] = &instance_col;
418         columns[16] = &reg_id_col;
419         columns[17] = &srv_id_col;
420         columns[18] = &con_id_col;
421         columns[19] = &keepalive_col;
422         columns[20] = &domain_col;
423
424         if (ul_dbf.use_table(_c, _d->name) < 0) {
425                 LM_ERR("sql use_table failed\n");
426                 return -1;
427         }
428
429 #ifdef EXTRA_DEBUG
430         LM_NOTICE("load start time [%d]\n", (int)time(NULL));
431 #endif
432
433         if (ul_db_srvid) {
434                 LM_NOTICE("filtered by server_id[%d]\n", server_id);
435                 keys[0] = &srv_id_col;
436                 ops[0] = OP_EQ;
437                 vals[0].type = DB1_INT;
438                 vals[0].nul = 0;
439                 vals[0].val.int_val = server_id;
440         }
441
442         if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
443                 if (ul_dbf.query(_c, (ul_db_srvid)?(keys):(0),
444                                                         (ul_db_srvid)?(ops):(0), (ul_db_srvid)?(vals):(0),
445                                                         columns, (ul_db_srvid)?(1):(0),
446                                                         (use_domain)?(21):(20), 0, 0) < 0)
447                 {
448                         LM_ERR("db_query (1) failed\n");
449                         return -1;
450                 }
451                 if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
452                         LM_ERR("fetching rows failed\n");
453                         return -1;
454                 }
455         } else {
456                 if (ul_dbf.query(_c, (ul_db_srvid)?(keys):(0),
457                                                         (ul_db_srvid)?(ops):(0), (ul_db_srvid)?(vals):(0),
458                                                         columns, (ul_db_srvid)?(1):(0),
459                                                         (use_domain)?(21):(20), 0, &res) < 0)
460                 {
461                         LM_ERR("db_query failed\n");
462                         return -1;
463                 }
464         }
465
466         if (RES_ROW_N(res) == 0) {
467                 LM_DBG("table is empty\n");
468                 ul_dbf.free_result(_c, res);
469                 return 0;
470         }
471
472
473         n = 0;
474         do {
475                 LM_DBG("loading records - cycle [%d]\n", ++n);
476                 for(i = 0; i < RES_ROW_N(res); i++) {
477                         row = RES_ROWS(res) + i;
478
479                         user.s = (char*)VAL_STRING(ROW_VALUES(row));
480                         if (VAL_NULL(ROW_VALUES(row)) || user.s==0 || user.s[0]==0) {
481                                 LM_CRIT("empty username record in table %s...skipping\n",
482                                                 _d->name->s);
483                                 continue;
484                         }
485                         user.len = strlen(user.s);
486
487                         ci = dbrow2info(ROW_VALUES(row)+1, &contact, 0);
488                         if (ci==0) {
489                                 LM_ERR("skipping record for %.*s in table %s\n",
490                                                 user.len, user.s, _d->name->s);
491                                 continue;
492                         }
493
494                         if (use_domain) {
495                                 domain = (char*)VAL_STRING(ROW_VALUES(row) + 20);
496                                 if (VAL_NULL(ROW_VALUES(row)+17) || domain==0 || domain[0]==0){
497                                         LM_CRIT("empty domain record for user %.*s...skipping\n",
498                                                         user.len, user.s);
499                                         continue;
500                                 }
501                                 /* user.s cannot be NULL - checked previosly */
502                                 user.len = snprintf(uri, MAX_URI_SIZE, "%.*s@%s",
503                                         user.len, user.s, domain);
504                                 user.s = uri;
505                                 if (user.s[user.len]!=0) {
506                                         LM_CRIT("URI '%.*s@%s' longer than %d\n", user.len, user.s,
507                                                         domain, MAX_URI_SIZE);
508                                         continue;
509                                 }
510                         }
511
512                         lock_udomain(_d, &user);
513                         if (get_urecord(_d, &user, &r) > 0) {
514                                 if (mem_insert_urecord(_d, &user, &r) < 0) {
515                                         LM_ERR("failed to create a record\n");
516                                         unlock_udomain(_d, &user);
517                                         goto error;
518                                 }
519                         }
520
521                         if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
522                                 LM_ERR("inserting contact failed\n");
523                                 unlock_udomain(_d, &user);
524                                 goto error1;
525                         }
526
527                         /* We have to do this, because insert_ucontact sets state to CS_NEW
528                          * and we have the contact in the database already */
529                         c->state = CS_SYNC;
530                         unlock_udomain(_d, &user);
531                 }
532
533                 if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
534                         if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
535                                 LM_ERR("fetching rows (1) failed\n");
536                                 ul_dbf.free_result(_c, res);
537                                 return -1;
538                         }
539                 } else {
540                         break;
541                 }
542         } while(RES_ROW_N(res)>0);
543
544         ul_dbf.free_result(_c, res);
545
546 #ifdef EXTRA_DEBUG
547         LM_NOTICE("load end time [%d]\n", (int)time(NULL));
548 #endif
549
550         return 0;
551 error1:
552         free_ucontact(c);
553 error:
554         ul_dbf.free_result(_c, res);
555         return -1;
556 }
557
558
559 /*!
560  * \brief Loads from DB all contacts for an AOR
561  * \param _c database connection
562  * \param _d domain
563  * \param _aor address of record
564  * \return pointer to the record on success, 0 on errors or if nothing is found
565  */
566 urecord_t* db_load_urecord(db1_con_t* _c, udomain_t* _d, str *_aor)
567 {
568         char tname_buf[64];
569         str tname;
570         ucontact_info_t *ci;
571         db_key_t columns[19];
572         db_key_t keys[2];
573         db_key_t order;
574         db_val_t vals[2];
575         db1_res_t* res = NULL;
576         db_row_t *row;
577         str aname;
578         str avalue;
579         sr_xval_t aval;
580         str contact;
581         char *domain;
582         int i;
583
584         urecord_t* r;
585         ucontact_t* c;
586
587         keys[0] = &user_col;
588         vals[0].type = DB1_STR;
589         vals[0].nul = 0;
590         if (use_domain) {
591                 keys[1] = &domain_col;
592                 vals[1].type = DB1_STR;
593                 vals[1].nul = 0;
594                 domain = memchr(_aor->s, '@', _aor->len);
595                 vals[0].val.str_val.s   = _aor->s;
596                 if (domain==0) {
597                         vals[0].val.str_val.len = 0;
598                         vals[1].val.str_val = *_aor;
599                 } else {
600                         vals[0].val.str_val.len = domain - _aor->s;
601                         vals[1].val.str_val.s   = domain+1;
602                         vals[1].val.str_val.len = _aor->s + _aor->len - domain - 1;
603                 }
604         } else {
605                 vals[0].val.str_val = *_aor;
606         }
607
608         columns[0] = &contact_col;
609         columns[1] = &expires_col;
610         columns[2] = &q_col;
611         columns[3] = &callid_col;
612         columns[4] = &cseq_col;
613         columns[5] = &flags_col;
614         columns[6] = &cflags_col;
615         columns[7] = &user_agent_col;
616         columns[8] = &received_col;
617         columns[9] = &path_col;
618         columns[10] = &sock_col;
619         columns[11] = &methods_col;
620         columns[12] = &last_mod_col;
621         columns[13] = &ruid_col;
622         columns[14] = &instance_col;
623         columns[15] = &reg_id_col;
624         columns[16] = &srv_id_col;
625         columns[17] = &con_id_col;
626         columns[18] = &keepalive_col;
627
628         if (desc_time_order)
629                 order = &last_mod_col;
630         else
631                 order = &q_col;
632
633         if (ul_dbf.use_table(_c, _d->name) < 0) {
634                 LM_ERR("failed to use table %.*s\n", _d->name->len, _d->name->s);
635                 return 0;
636         }
637
638         if (ul_dbf.query(_c, keys, 0, vals, columns, (use_domain)?2:1, 19, order,
639                                 &res) < 0) {
640                 LM_ERR("db_query failed\n");
641                 return 0;
642         }
643
644         if (RES_ROW_N(res) == 0) {
645                 LM_DBG("aor %.*s not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
646                 ul_dbf.free_result(_c, res);
647                 return 0;
648         }
649
650         r = 0;
651
652         for(i = 0; i < RES_ROW_N(res); i++) {
653                 ci = dbrow2info(ROW_VALUES(RES_ROWS(res) + i), &contact, 1);
654                 if (ci==0) {
655                         LM_ERR("skipping record for %.*s in table %s\n",
656                                         _aor->len, _aor->s, _d->name->s);
657                         continue;
658                 }
659
660                 if ( r==0 )
661                         get_static_urecord( _d, _aor, &r);
662
663                 if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
664                         LM_ERR("mem_insert failed\n");
665                         free_urecord(r);
666                         ul_dbf.free_result(_c, res);
667                         return 0;
668                 }
669
670                 /* We have to do this, because insert_ucontact sets state to CS_NEW
671                  * and we have the contact in the database already */
672                 c->state = CS_SYNC;
673         }
674
675         ul_dbf.free_result(_c, res);
676
677         /* Retrieve ul attributes */
678         if(ul_xavp_contact_name.s==NULL) {
679                 /* feature disabled by mod param */
680                 goto done;
681         }
682
683         if(_d->name->len + 6>=64) {
684                 LM_ERR("attributes table name is too big\n");
685                 goto done;
686         }
687         strncpy(tname_buf, _d->name->s, _d->name->len);
688         tname_buf[_d->name->len] = '\0';
689         strcat(tname_buf, "_attrs");
690         tname.s = tname_buf;
691         tname.len = _d->name->len + 6;
692
693         keys[0] = &ulattrs_ruid_col;
694         vals[0].type = DB1_STR;
695         vals[0].nul = 0;
696         columns[0] = &ulattrs_aname_col;
697         columns[1] = &ulattrs_atype_col;
698         columns[2] = &ulattrs_avalue_col;
699
700         if (ul_dbf.use_table(ul_dbh, &tname) < 0) {
701                 LM_ERR("sql use_table failed for %.*s\n", tname.len, tname.s);
702                 goto done;
703         }
704
705         if(r==0) goto done;
706
707         for (c = r->contacts; c != NULL; c = c->next) {
708                 vals[0].val.str_val.s = c->ruid.s;
709                 vals[0].val.str_val.len = c->ruid.len;
710
711                 if (ul_dbf.query(ul_dbh, keys, 0, vals, columns, 1, 3, 0, &res) < 0) {
712                         LM_ERR("db_query failed\n");
713                         continue;
714                 }
715
716                 if (RES_ROW_N(res) == 0) {
717                         LM_DBG("location attrs table is empty\n");
718                         ul_dbf.free_result(ul_dbh, res);
719                         continue;
720                 }
721
722                 for(i = 0; i < RES_ROW_N(res); i++) {
723                         row = RES_ROWS(res) + i;
724
725                         aname.s = (char*)VAL_STRING(ROW_VALUES(row));
726                         aname.len = strlen(aname.s);
727                         avalue.s = (char*)VAL_STRING(ROW_VALUES(row) + 2);
728                         avalue.len = strlen(avalue.s);
729                         memset(&aval, 0, sizeof(sr_xval_t));
730                         if(VAL_INT(ROW_VALUES(row)+1)==0) {
731                                 /* string value */
732                                 aval.v.s = avalue;
733                                 aval.type = SR_XTYPE_STR;
734                         } else if(VAL_INT(ROW_VALUES(row)+1)==1) {
735                                 /* int value */
736                                 str2sint(&avalue, &aval.v.i);
737                                 aval.type = SR_XTYPE_INT;
738                         } else {
739                                 /* unknown type - ignore */
740                                 continue;
741                         }
742
743                         /* add xavp to contact */
744                         if(c->xavp==NULL) {
745                                 if(xavp_add_xavp_value(&ul_xavp_contact_name, &aname,
746                                                         &aval, &c->xavp)==NULL)
747                                         LM_INFO("cannot add first xavp to contact - ignoring\n");
748                         } else {
749                                 if(c->xavp->val.type==SR_XTYPE_XAVP) {
750                                         if(xavp_add_value(&aname, &aval, &c->xavp->val.v.xavp)==NULL)
751                                                 LM_INFO("cannot add values to contact xavp\n");
752                                 }
753                         }
754                 }
755                 ul_dbf.free_result(ul_dbh, res);
756         }
757
758
759 done:
760         return r;
761 }
762
763 /*!
764  * \brief Loads from DB all contacts for a RUID
765  * \param _c database connection
766  * \param _d domain
767  * \param _ruid record unique id
768  * \return pointer to the record on success, 0 on errors or if nothing is found
769  */
770 urecord_t* db_load_urecord_by_ruid(db1_con_t* _c, udomain_t* _d, str *_ruid)
771 {
772         ucontact_info_t *ci;
773         db_key_t columns[21];
774         db_key_t keys[1];
775         db_key_t order;
776         db_val_t vals[1];
777         db1_res_t* res = NULL;
778         db_row_t *row;
779         str contact;
780         str aor;
781         static char aorbuf[512];
782         str domain;
783
784         urecord_t* r;
785         ucontact_t* c;
786
787         keys[0] = &ruid_col;
788         vals[0].type = DB1_STR;
789         vals[0].nul = 0;
790         vals[0].val.str_val = *_ruid;
791
792         columns[0] = &contact_col;
793         columns[1] = &expires_col;
794         columns[2] = &q_col;
795         columns[3] = &callid_col;
796         columns[4] = &cseq_col;
797         columns[5] = &flags_col;
798         columns[6] = &cflags_col;
799         columns[7] = &user_agent_col;
800         columns[8] = &received_col;
801         columns[9] = &path_col;
802         columns[10] = &sock_col;
803         columns[11] = &methods_col;
804         columns[12] = &last_mod_col;
805         columns[13] = &ruid_col;
806         columns[14] = &instance_col;
807         columns[15] = &reg_id_col;
808         columns[16] = &srv_id_col;
809         columns[17] = &con_id_col;
810         columns[18] = &keepalive_col;
811         columns[19] = &user_col;
812         columns[20] = &domain_col;
813
814         if (desc_time_order)
815                 order = &last_mod_col;
816         else
817                 order = &q_col;
818
819         if (ul_dbf.use_table(_c, _d->name) < 0) {
820                 LM_ERR("failed to use table %.*s\n", _d->name->len, _d->name->s);
821                 return 0;
822         }
823
824         if (ul_dbf.query(_c, keys, 0, vals, columns, 1, 21, order,
825                                 &res) < 0) {
826                 LM_ERR("db_query failed\n");
827                 return 0;
828         }
829
830         if (RES_ROW_N(res) == 0) {
831                 LM_DBG("aor %.*s not found in table %.*s\n",_ruid->len, _ruid->s,
832                                 _d->name->len, _d->name->s);
833                 ul_dbf.free_result(_c, res);
834                 return 0;
835         }
836
837         r = 0;
838
839         /* use first row - shouldn't be more */
840         row = RES_ROWS(res);
841
842         ci = dbrow2info(ROW_VALUES(RES_ROWS(res)), &contact, 1);
843         if (ci==0) {
844                 LM_ERR("skipping record for %.*s in table %s\n",
845                                 _ruid->len, _ruid->s, _d->name->s);
846                 goto done;
847         }
848
849         aor.s = (char*)VAL_STRING(ROW_VALUES(row) + 19);
850         aor.len = strlen(aor.s);
851
852         if (use_domain) {
853                 domain.s = (char*)VAL_STRING(ROW_VALUES(row) + 20);
854                 if (VAL_NULL(ROW_VALUES(row)+20) || domain.s==0 || domain.s[0]==0){
855                         LM_CRIT("empty domain record for user %.*s...skipping\n",
856                                         aor.len, aor.s);
857                         goto done;
858                 }
859                 domain.len = strlen(domain.s);
860                 if(aor.len + domain.len + 2 >= 512) {
861                         LM_ERR("AoR is too big\n");
862                         goto done;
863                 }
864                 memcpy(aorbuf, aor.s, aor.len);
865                 aorbuf[aor.len] = '@';
866                 memcpy(aorbuf + aor.len + 1, domain.s, domain.len);
867                 aor.len += 1 + domain.len;
868                 aor.s = aorbuf;
869                 aor.s[aor.len] = '\0';
870         }
871         get_static_urecord( _d, &aor, &r);
872
873         if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
874                 LM_ERR("mem_insert failed\n");
875                 free_urecord(r);
876                 ul_dbf.free_result(_c, res);
877                 return 0;
878         }
879
880         /* We have to do this, because insert_ucontact sets state to CS_NEW
881          * and we have the contact in the database already */
882         c->state = CS_SYNC;
883
884 done:
885         ul_dbf.free_result(_c, res);
886         return r;
887 }
888
889 /*!
890  * \brief call contact expired call back for a domain with db_mode: DB_ONLY
891  *
892  * call contact expired call back for a domain with db_mode: DB_ONLY since
893  * database rows are removed by the timer function: db_timer_udomain
894  * \param _c database connection
895  * \param _d loaded domain
896  * \return 0 on success, -1 on failure
897  */
898 int udomain_contact_expired_cb(db1_con_t* _c, udomain_t* _d)
899 {
900         ucontact_info_t *ci;
901         db_row_t *row;
902         db_key_t columns[21], query_cols[3];
903         db_op_t  query_ops[3];
904         db_val_t query_vals[3];
905         int key_num = 2;
906         db1_res_t* res = NULL;
907         str user, contact;
908         int i;
909         int n;
910         urecord_t* r;
911         ucontact_t* c;
912 #define RUIDBUF_SIZE 128
913         char ruidbuf[RUIDBUF_SIZE];
914         str ruid;
915
916         if (db_mode!=DB_ONLY) {
917                 return 0;
918         }
919
920         columns[0] = &user_col;
921         columns[1] = &contact_col;
922         columns[2] = &expires_col;
923         columns[3] = &q_col;
924         columns[4] = &callid_col;
925         columns[5] = &cseq_col;
926         columns[6] = &flags_col;
927         columns[7] = &cflags_col;
928         columns[8] = &user_agent_col;
929         columns[9] = &received_col;
930         columns[10] = &path_col;
931         columns[11] = &sock_col;
932         columns[12] = &methods_col;
933         columns[13] = &last_mod_col;
934         columns[14] = &ruid_col;
935         columns[15] = &instance_col;
936         columns[16] = &reg_id_col;
937         columns[17] = &srv_id_col;
938         columns[18] = &con_id_col;
939         columns[19] = &keepalive_col;
940         columns[20] = &domain_col;
941
942         query_cols[0] = &expires_col;
943         query_ops[0] = "<";
944         query_vals[0].nul = 0;
945         UL_DB_EXPIRES_SET(&query_vals[0], act_time + 1 - ul_rm_expired_delay);
946
947         query_cols[1] = &expires_col;
948         query_ops[1] = OP_NEQ;
949         query_vals[1].nul = 0;
950         UL_DB_EXPIRES_SET(&query_vals[1], 0);
951
952         if (ul_db_srvid != 0) {
953                 query_cols[2] = &srv_id_col;
954                 query_ops[2] = OP_EQ;
955                 query_vals[2].type = DB1_INT;
956                 query_vals[2].nul = 0;
957                 query_vals[2].val.int_val = server_id;
958                 key_num = 3;
959         }
960
961         if (ul_dbf.use_table(_c, _d->name) < 0) {
962                 LM_ERR("sql use_table failed\n");
963                 return -1;
964         }
965
966 #ifdef EXTRA_DEBUG
967         LM_NOTICE("udomain contact-expired start time [%d]\n", (int)time(NULL));
968 #endif
969
970         if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
971                 if (ul_dbf.query(_c, query_cols, query_ops, query_vals, columns, key_num, (use_domain)?(21):(20), 0,
972                 0) < 0) {
973                         LM_ERR("db_query (1) failed\n");
974                         return -1;
975                 }
976                 if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
977                         LM_ERR("fetching rows failed\n");
978                         return -1;
979                 }
980         } else {
981                 if (ul_dbf.query(_c, query_cols, query_ops, query_vals, columns, key_num, (use_domain)?(21):(20), 0,
982                 &res) < 0) {
983                         LM_ERR("db_query failed\n");
984                         return -1;
985                 }
986         }
987
988         if (RES_ROW_N(res) == 0) {
989                 LM_DBG("no rows to be contact expired\n");
990                 ul_dbf.free_result(_c, res);
991                 return 0;
992         }
993
994         n = 0;
995         do {
996                 LM_DBG("calling contact expired records - cycle [%d]\n", ++n);
997                 for(i = 0; i < RES_ROW_N(res); i++) {
998                         row = RES_ROWS(res) + i;
999
1000                         user.s = (char*)VAL_STRING(ROW_VALUES(row));
1001                         if (VAL_NULL(ROW_VALUES(row)) || user.s==0 || user.s[0]==0) {
1002                                 LM_CRIT("empty username record in table %s...skipping\n",
1003                                         _d->name->s);
1004                                 continue;
1005                         }
1006                         user.len = strlen(user.s);
1007
1008                         ci = dbrow2info(ROW_VALUES(row)+1, &contact, 0);
1009                         if (ci==0) {
1010                                 LM_CRIT("skipping record for %.*s in table %s\n",
1011                                         user.len, user.s, _d->name->s);
1012                                 continue;
1013                         }
1014
1015                         lock_udomain(_d, &user);
1016                         if (get_urecord(_d, &user, &r) > 0) {
1017                                 LM_ERR("failed to get a record\n");
1018                                 unlock_udomain(_d, &user);
1019                                 goto error;
1020                         }
1021
1022                         if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
1023                                 LM_ERR("inserting contact failed\n");
1024                                 release_urecord(r);
1025                                 unlock_udomain(_d, &user);
1026                                 goto error;
1027                         }
1028
1029                         /* Call the contact-expired call-back if it exists for the contact */
1030                         if (exists_ulcb_type(UL_CONTACT_EXPIRE)) {
1031                                 run_ul_callbacks( UL_CONTACT_EXPIRE, c);
1032                         }
1033                         c->state = CS_SYNC;
1034                         ruid.len = 0;
1035                         if(c->ruid.len > 0 && ul_xavp_contact_name.s != NULL) {
1036                                 /* clone ruid to delete attributes out of lock */
1037                                 if(c->ruid.len < RUIDBUF_SIZE - 2) {
1038                                         memcpy(ruidbuf, c->ruid.s, c->ruid.len);
1039                                         ruidbuf[c->ruid.len] = '\0';
1040                                         ruid.s = ruidbuf;
1041                                         ruid.len = c->ruid.len;
1042                                 } else {
1043                                         LM_ERR("ruid is too long: %d\n", c->ruid.len);
1044                                 }
1045                         }
1046                         release_urecord(r);
1047                         unlock_udomain(_d, &user);
1048                         if(ruid.len > 0 && ul_xavp_contact_name.s != NULL) {
1049                                 /* delete attributes by ruid */
1050                                 uldb_delete_attrs_ruid(_d->name, &ruid);
1051                         }
1052                 }
1053
1054                 if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
1055                         if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
1056                                 LM_ERR("fetching rows (1) failed\n");
1057                                 ul_dbf.free_result(_c, res);
1058                                 return -1;
1059                         }
1060                 } else {
1061                         break;
1062                 }
1063         } while(RES_ROW_N(res)>0);
1064
1065         ul_dbf.free_result(_c, res);
1066
1067 #ifdef EXTRA_DEBUG
1068         LM_NOTICE("udomain contact-expired end time [%d]\n", (int)time(NULL));
1069 #endif
1070
1071         return 0;
1072
1073 error:
1074         ul_dbf.free_result(_c, res);
1075         return -1;
1076 }
1077
1078
1079 /*!
1080  * \brief Timer function to cleanup expired contacts, db_mode: DB_ONLY
1081  *   and for WRITE_BACK, WRITE_THROUGH on config param
1082  * \param _d cleaned domain
1083  * \return 0 on success, -1 on failure
1084  */
1085 int db_timer_udomain(udomain_t* _d)
1086 {
1087         db_key_t keys[3];
1088         db_op_t  ops[3];
1089         db_val_t vals[3];
1090         int key_num = 2;
1091
1092         /* call contact expired call back for a domain before deleting database rows */
1093         udomain_contact_expired_cb(ul_dbh, _d);
1094
1095         keys[0] = &expires_col;
1096         ops[0] = "<";
1097         vals[0].nul = 0;
1098         UL_DB_EXPIRES_SET(&vals[0], act_time + 1 - ul_rm_expired_delay);
1099
1100         keys[1] = &expires_col;
1101         ops[1] = OP_NEQ;
1102         vals[1].nul = 0;
1103         UL_DB_EXPIRES_SET(&vals[1], 0);
1104
1105         if (ul_db_srvid != 0) {
1106                 keys[2] = &srv_id_col;
1107                 ops[2] = OP_EQ;
1108                 vals[2].type = DB1_INT;
1109                 vals[2].nul = 0;
1110                 vals[2].val.int_val = server_id;
1111                 key_num = 3;
1112         }
1113
1114         if (ul_dbf.use_table(ul_dbh, _d->name) < 0) {
1115                 LM_ERR("use_table failed\n");
1116                 return -1;
1117         }
1118
1119         if (ul_dbf.delete(ul_dbh, keys, ops, vals, key_num) < 0) {
1120                 LM_ERR("failed to delete from table %s\n",_d->name->s);
1121                 return -1;
1122         }
1123
1124         return 0;
1125 }
1126
1127
1128 /*!
1129  * \brief performs a dummy query just to see if DB is ok
1130  * \param con database connection
1131  * \param d domain
1132  */
1133 int testdb_udomain(db1_con_t* con, udomain_t* d)
1134 {
1135         db_key_t key[2], col[1];
1136         db_val_t val[2];
1137         db1_res_t* res = NULL;
1138
1139         if(ul_dbf.use_table(con, d->name) < 0) {
1140                 LM_ERR("failed to change table\n");
1141                 return -1;
1142         }
1143
1144         key[0] = &user_col;
1145         key[1] = &domain_col;
1146
1147         col[0] = &user_col;
1148
1149         VAL_TYPE(val) = DB1_STRING;
1150         VAL_NULL(val) = 0;
1151         VAL_STRING(val) = "dummy_user";
1152
1153         VAL_TYPE(val+1) = DB1_STRING;
1154         VAL_NULL(val+1) = 0;
1155         VAL_STRING(val+1) = "dummy_domain";
1156
1157         if(ul_dbf.query(con, key, 0, val, col, (use_domain)?2:1, 1, 0, &res)<0) {
1158                 if(res) ul_dbf.free_result( con, res);
1159                 LM_ERR("failure in db_query\n");
1160                 return -1;
1161         }
1162
1163         ul_dbf.free_result( con, res);
1164         return 0;
1165 }
1166
1167
1168 /*!
1169  * \brief Insert a new record into domain in memory
1170  * \param _d domain the record belongs to
1171  * \param _aor address of record
1172  * \param _r new created record
1173  * \return 0 on success, -1 on failure
1174  */
1175 int mem_insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
1176 {
1177         int sl;
1178
1179         if (new_urecord(_d->name, _aor, _r) < 0) {
1180                 LM_ERR("creating urecord failed\n");
1181                 return -1;
1182         }
1183
1184         sl = ((*_r)->aorhash)&(_d->size-1);
1185         slot_add(&_d->table[sl], *_r);
1186         update_stat( _d->users, 1);
1187         return 0;
1188 }
1189
1190
1191 /*!
1192  * \brief Remove a record from domain in memory
1193  * \param _d domain the record belongs to
1194  * \param _r deleted record
1195  */
1196 void mem_delete_urecord(udomain_t* _d, struct urecord* _r)
1197 {
1198         slot_rem(_r->slot, _r);
1199         free_urecord(_r);
1200         update_stat( _d->users, -1);
1201 }
1202
1203
1204 /*!
1205  * \brief Run timer handler for given domain, delete urecords
1206  * \param _d domain
1207  * \param istart start of run
1208  * \param istep loop steps
1209  */
1210 void mem_timer_udomain(udomain_t* _d, int istart, int istep)
1211 {
1212         struct urecord* ptr, *t;
1213         int i;
1214
1215         for(i=istart; i<_d->size; i+=istep)
1216         {
1217                 if(likely(destroy_modules_phase()==0)) lock_ulslot(_d, i);
1218
1219                 ptr = _d->table[i].first;
1220
1221                 while(ptr) {
1222                         timer_urecord(ptr);
1223                         /* Remove the entire record if it is empty */
1224                         if (ptr->contacts == 0) {
1225                                 t = ptr;
1226                                 ptr = ptr->next;
1227                                 mem_delete_urecord(_d, t);
1228                         } else {
1229                                 ptr = ptr->next;
1230                         }
1231                 }
1232                 if(likely(destroy_modules_phase()==0)) unlock_ulslot(_d, i);
1233         }
1234 }
1235
1236
1237 /*!
1238  * \brief Get lock for a domain
1239  * \param _d domain
1240  * \param _aor adress of record, used as hash source for the lock slot
1241  */
1242 void lock_udomain(udomain_t* _d, str* _aor)
1243 {
1244         unsigned int sl;
1245         if (db_mode!=DB_ONLY)
1246         {
1247                 sl = ul_get_aorhash(_aor) & (_d->size - 1);
1248
1249                 rec_lock_get(&_d->table[sl].rlock);
1250         }
1251 }
1252
1253
1254 /*!
1255  * \brief Release lock for a domain
1256  * \param _d domain
1257  * \param _aor address of record, uses as hash source for the lock slot
1258  */
1259 void unlock_udomain(udomain_t* _d, str* _aor)
1260 {
1261         unsigned int sl;
1262         if (db_mode!=DB_ONLY)
1263         {
1264                 sl = ul_get_aorhash(_aor) & (_d->size - 1);
1265                 rec_lock_release(&_d->table[sl].rlock);
1266         }
1267 }
1268
1269 /*!
1270  * \brief  Get lock for a slot
1271  * \param _d domain
1272  * \param i slot number
1273  */
1274 void lock_ulslot(udomain_t* _d, int i)
1275 {
1276         if (db_mode!=DB_ONLY)
1277                 rec_lock_get(&_d->table[i].rlock);
1278 }
1279
1280
1281 /*!
1282  * \brief Release lock for a slot
1283  * \param _d domain
1284  * \param i slot number
1285  */
1286 void unlock_ulslot(udomain_t* _d, int i)
1287 {
1288         if (db_mode!=DB_ONLY)
1289                 rec_lock_release(&_d->table[i].rlock);
1290 }
1291
1292
1293
1294 /*!
1295  * \brief Create and insert a new record
1296  * \param _d domain to insert the new record
1297  * \param _aor address of the record
1298  * \param _r new created record
1299  * \return return 0 on success, -1 on failure
1300  */
1301 int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
1302 {
1303         if (db_mode!=DB_ONLY) {
1304                 if (mem_insert_urecord(_d, _aor, _r) < 0) {
1305                         LM_ERR("inserting record failed\n");
1306                         return -1;
1307                 }
1308         } else {
1309                 get_static_urecord( _d, _aor, _r);
1310         }
1311         return 0;
1312 }
1313
1314
1315 /*!
1316  * \brief Obtain a urecord pointer if the urecord exists in domain
1317  * \param _d domain to search the record
1318  * \param _aor address of record
1319  * \param _r new created record
1320  * \return 0 if a record was found, 1 if nothing could be found
1321  */
1322 int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
1323 {
1324         unsigned int sl, i, aorhash;
1325         urecord_t* r;
1326         ucontact_t* ptr = NULL;
1327
1328         if (db_mode!=DB_ONLY) {
1329                 /* search in cache */
1330                 aorhash = ul_get_aorhash(_aor);
1331                 sl = aorhash&(_d->size-1);
1332                 r = _d->table[sl].first;
1333
1334                 for(i = 0; r!=NULL && i < _d->table[sl].n; i++) {
1335                         if((r->aorhash==aorhash) && (r->aor.len==_aor->len)
1336                                                 && !memcmp(r->aor.s,_aor->s,_aor->len))
1337                         {
1338                                 if (handle_lost_tcp)
1339                                 {
1340                                         for (ptr = r->contacts;ptr;ptr = ptr->next)
1341                                         {
1342                                                 if (ptr->expires == UL_EXPIRED_TIME )
1343                                                         continue;
1344                                                 if (is_valid_tcpconn(ptr) && !is_tcp_alive(ptr))
1345                                                         ptr->expires = UL_EXPIRED_TIME;
1346                                         }
1347                                 }
1348                                 *_r = r;
1349                                 return 0;
1350                         }
1351
1352                         r = r->next;
1353                 }
1354         } else {
1355                 /* search in DB */
1356                 r = db_load_urecord( ul_dbh, _d, _aor);
1357                 if (r) {
1358                         *_r = r;
1359                         return 0;
1360                 }
1361         }
1362
1363         return 1;   /* Nothing found */
1364 }
1365
1366 /*!
1367  * \brief Obtain a urecord pointer if the urecord exists in domain (lock slot)
1368  * \param _d domain to search the record
1369  * \param _aorhash hash id for address of record
1370  * \param _ruid record internal unique id
1371  * \param _r store pointer to location record
1372  * \param _c store pointer to contact structure
1373  * \return 0 if a record was found, -1 if nothing could be found
1374  */
1375 int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
1376                 str *_ruid, struct urecord** _r, struct ucontact** _c)
1377 {
1378         unsigned int sl, i;
1379         urecord_t* r;
1380         ucontact_t* c;
1381
1382         sl = _aorhash&(_d->size-1);
1383         lock_ulslot(_d, sl);
1384
1385         if (db_mode!=DB_ONLY) {
1386                 /* search in cache */
1387                 r = _d->table[sl].first;
1388
1389                 for(i = 0; i < _d->table[sl].n; i++) {
1390                         if(r->aorhash==_aorhash) {
1391                                 c = r->contacts;
1392                                 while(c) {
1393                                         if(c->ruid.len==_ruid->len
1394                                                         && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) {
1395                                                 *_r = r;
1396                                                 *_c = c;
1397                                                 return 0;
1398                                         }
1399                                         c = c->next;
1400                                 }
1401                         }
1402                         r = r->next;
1403                 }
1404         } else {
1405                 /* search in DB */
1406                 r = db_load_urecord_by_ruid(ul_dbh, _d, _ruid);
1407                 if (r) {
1408                         if(r->aorhash==_aorhash) {
1409                                 c = r->contacts;
1410                                 while(c) {
1411                                         if(c->ruid.len==_ruid->len
1412                                                         && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) {
1413                                                 *_r = r;
1414                                                 *_c = c;
1415                                                 return 0;
1416                                         }
1417                                         c = c->next;
1418                                 }
1419                         }
1420                 }
1421         }
1422
1423         unlock_ulslot(_d, (_aorhash & (_d->size - 1)));
1424         return -1;   /* Nothing found */
1425 }
1426
1427 /*!
1428  * \brief Delete a urecord from domain
1429  * \param _d domain where the record should be deleted
1430  * \param _aor address of record
1431  * \param _r deleted record
1432  * \return 0 on success, -1 if the record could not be deleted
1433  */
1434 int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r)
1435 {
1436         struct ucontact* c, *t;
1437
1438         if (db_mode==DB_ONLY) {
1439                 if (_r==0)
1440                         get_static_urecord( _d, _aor, &_r);
1441                 if (db_delete_urecord(_r)<0) {
1442                         LM_ERR("DB delete failed\n");
1443                         return -1;
1444                 }
1445                 free_urecord(_r);
1446                 return 0;
1447         }
1448
1449         if (_r==0) {
1450                 if (get_urecord(_d, _aor, &_r) > 0) {
1451                         return 0;
1452                 }
1453         }
1454
1455         c = _r->contacts;
1456         while(c) {
1457                 t = c;
1458                 c = c->next;
1459                 if (delete_ucontact(_r, t) < 0) {
1460                         LM_ERR("deleting contact failed\n");
1461                         return -1;
1462                 }
1463         }
1464         release_urecord(_r);
1465         return 0;
1466 }
1467
1468
1469 /*!
1470  * \brief Load all location attributes from an udomain
1471  *
1472  * Load all location attributes from a udomain, useful to populate the
1473  * memory cache on startup.
1474  * \param _d loaded domain
1475  * \return 0 on success, -1 on failure
1476  */
1477 int uldb_preload_attrs(udomain_t *_d)
1478 {
1479         char uri[MAX_URI_SIZE];
1480         str  suri;
1481         char tname_buf[64];
1482         str tname;
1483         db_row_t *row;
1484         db_key_t columns[6];
1485         db1_res_t* res = NULL;
1486         str user = {0};
1487         str domain = {0};
1488         str ruid;
1489         str aname;
1490         str avalue;
1491         sr_xval_t aval;
1492         int i;
1493         int n;
1494
1495         urecord_t* r;
1496         ucontact_t* c;
1497
1498         if(ul_xavp_contact_name.s==NULL) {
1499                 /* feature disabled by mod param */
1500                 return 0;
1501         }
1502
1503         if(_d->name->len + 6>=64) {
1504                 LM_ERR("attributes table name is too big\n");
1505                 return -1;
1506         }
1507         strncpy(tname_buf, _d->name->s, _d->name->len);
1508         tname_buf[_d->name->len] = '\0';
1509         strcat(tname_buf, "_attrs");
1510         tname.s = tname_buf;
1511         tname.len = _d->name->len + 6;
1512
1513         columns[0] = &ulattrs_user_col;
1514         columns[1] = &ulattrs_ruid_col;
1515         columns[2] = &ulattrs_aname_col;
1516         columns[3] = &ulattrs_atype_col;
1517         columns[4] = &ulattrs_avalue_col;
1518         columns[5] = &ulattrs_domain_col;
1519
1520         if (ul_dbf.use_table(ul_dbh, &tname) < 0) {
1521                 LM_ERR("sql use_table failed for %.*s\n", tname.len, tname.s);
1522                 return -1;
1523         }
1524
1525 #ifdef EXTRA_DEBUG
1526         LM_NOTICE("load start time [%d]\n", (int)time(NULL));
1527 #endif
1528
1529         if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
1530                 if (ul_dbf.query(ul_dbh, 0, 0, 0, columns, 0, (use_domain)?(6):(5), 0,
1531                                         0) < 0) {
1532                         LM_ERR("db_query (1) failed\n");
1533                         return -1;
1534                 }
1535                 if(ul_dbf.fetch_result(ul_dbh, &res, ul_fetch_rows)<0) {
1536                         LM_ERR("fetching rows failed\n");
1537                         return -1;
1538                 }
1539         } else {
1540                 if (ul_dbf.query(ul_dbh, 0, 0, 0, columns, 0, (use_domain)?(6):(5), 0,
1541                 &res) < 0) {
1542                         LM_ERR("db_query failed\n");
1543                         return -1;
1544                 }
1545         }
1546
1547         if (RES_ROW_N(res) == 0) {
1548                 LM_DBG("location attrs table is empty\n");
1549                 ul_dbf.free_result(ul_dbh, res);
1550                 return 0;
1551         }
1552
1553
1554         n = 0;
1555         do {
1556                 LM_DBG("loading records - cycle [%d]\n", ++n);
1557                 for(i = 0; i < RES_ROW_N(res); i++) {
1558                         row = RES_ROWS(res) + i;
1559
1560                         user.s = (char*)VAL_STRING(ROW_VALUES(row));
1561                         if (VAL_NULL(ROW_VALUES(row)) || user.s==0 || user.s[0]==0) {
1562                                 LM_CRIT("empty username record in table %s...skipping\n",
1563                                                 _d->name->s);
1564                                 continue;
1565                         }
1566                         user.len = strlen(user.s);
1567
1568                         ruid.s = (char*)VAL_STRING(ROW_VALUES(row) + 1);
1569                         ruid.len = strlen(ruid.s);
1570                         aname.s = (char*)VAL_STRING(ROW_VALUES(row) + 2);
1571                         aname.len = strlen(aname.s);
1572                         avalue.s = (char*)VAL_STRING(ROW_VALUES(row) + 4);
1573                         avalue.len = strlen(avalue.s);
1574                         memset(&aval, 0, sizeof(sr_xval_t));
1575                         if(VAL_INT(ROW_VALUES(row)+3)==0) {
1576                                 /* string value */
1577                                 aval.v.s = avalue;
1578                                 aval.type = SR_XTYPE_STR;
1579                         } else if(VAL_INT(ROW_VALUES(row)+3)==1) {
1580                                 /* int value */
1581                                 str2sint(&avalue, &aval.v.i);
1582                                 aval.type = SR_XTYPE_INT;
1583                         } else {
1584                                 /* unknown type - ignore */
1585                                 continue;
1586                         }
1587
1588                         if (use_domain) {
1589                                 domain.s = (char*)VAL_STRING(ROW_VALUES(row) + 5);
1590                                 if (VAL_NULL(ROW_VALUES(row)+5) || domain.s==0 || domain.s[0]==0){
1591                                         LM_CRIT("empty domain record for user %.*s...skipping\n",
1592                                                         user.len, user.s);
1593                                         continue;
1594                                 }
1595                                 domain.len = strlen(domain.s);
1596                                 /* user.s cannot be NULL - checked previosly */
1597                                 suri.len = snprintf(uri, MAX_URI_SIZE, "%.*s@%s",
1598                                         user.len, user.s, domain.s);
1599                                 suri.s = uri;
1600                                 if (suri.s[suri.len]!=0) {
1601                                         LM_CRIT("URI '%.*s@%s' longer than %d\n", user.len, user.s,
1602                                                         domain.s, MAX_URI_SIZE);
1603                                         continue;
1604                                 }
1605                         } else {
1606                                 suri = user;
1607                         }
1608
1609                         if (get_urecord_by_ruid(_d, ul_get_aorhash(&suri), &ruid, &r, &c) < 0) {
1610                                 /* delete attrs records from db table */
1611                                 LM_INFO("no contact record for this ruid\n");
1612                                 uldb_delete_attrs(_d->name, &user, &domain, &ruid);
1613                         } else {
1614                                 /* add xavp to contact */
1615                                 if(c->xavp==NULL) {
1616                                         if(xavp_add_xavp_value(&ul_xavp_contact_name, &aname,
1617                                                                 &aval, &c->xavp)==NULL)
1618                                                 LM_INFO("cannot add first xavp to contact - ignoring\n");
1619                                 } else {
1620                                         if(c->xavp->val.type==SR_XTYPE_XAVP) {
1621                                                 if(xavp_add_value(&aname, &aval, &c->xavp->val.v.xavp)==NULL)
1622                                                         LM_INFO("cannot add values to contact xavp\n");
1623                                         }
1624                                 }
1625                                 /* get_urecord_by_ruid() locks the slot */
1626                                 unlock_udomain(_d, &suri);
1627                         }
1628                 }
1629
1630                 if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
1631                         if(ul_dbf.fetch_result(ul_dbh, &res, ul_fetch_rows)<0) {
1632                                 LM_ERR("fetching rows (1) failed\n");
1633                                 ul_dbf.free_result(ul_dbh, res);
1634                                 return -1;
1635                         }
1636                 } else {
1637                         break;
1638                 }
1639         } while(RES_ROW_N(res)>0);
1640
1641         ul_dbf.free_result(ul_dbh, res);
1642
1643 #ifdef EXTRA_DEBUG
1644         LM_NOTICE("load end time [%d]\n", (int)time(NULL));
1645 #endif
1646
1647         return 0;
1648 }