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