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