1 /*
2  * $Id$
3  *
4  * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
5  * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
6  * Copyright (C) 2019 Aleksandar Yosifov
7  *
8  * The initial version of this code was written by Dragos Vingarzan
9  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
10  * Fruanhofer Institute. It was and still is maintained in a separate
11  * branch of the original SER. We are therefore migrating it to
12  * Kamailio/SR and look forward to maintaining it from here on out.
13  * 2011/2012 Smile Communications, Pty. Ltd.
14  * ported/maintained/improved by
15  * Jason Penton (jason(dot)penton(at)smilecoms.com and
16  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
17  * effort to add full IMS support to Kamailio/SR using a new and
18  * improved architecture
19  *
20  * NB: Alot of this code was originally part of OpenIMSCore,
21  * FhG Fokus.
22  * Copyright (C) 2004-2006 FhG Fokus
23  * Thanks for great work! This is an effort to
24  * break apart the various CSCF functions into logically separate
25  * components. We hope this will drive wider use. We also feel
26  * that in this way the architecture is more complete and thereby easier
27  * to manage in the Kamailio/SR environment
28  *
29  * This file is part of Kamailio, a free SIP server.
30  *
31  * Kamailio is free software; you can redistribute it and/or modify
32  * it under the terms of the GNU General Public License as published by
33  * the Free Software Foundation; either version 2 of the License, or
34  * (at your option) any later version
35  *
36  * Kamailio is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39  * GNU General Public License for more details.
40  *
41  * You should have received a copy of the GNU General Public License
42  * along with this program; if not, write to the Free Software
43  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
44  *
45  */
46 
47 #include "udomain.h"
48 #include <string.h>
49 #include "../../core/hashes.h"
50 #include "../../core/parser/parse_methods.h"
51 #include "../../core/mem/shm_mem.h"
52 #include "../../core/dprint.h"
53 #include "../../lib/srdb1/db.h"
54 #include "../../core/socket_info.h"
55 #include "../../core/ut.h"
56 #include "ims_usrloc_pcscf_mod.h"            /* usrloc module parameters */
57 #include "usrloc.h"
58 #include "utime.h"
59 #include "usrloc.h"
60 #include "usrloc_db.h"
61 #include "../../core/parser/parse_uri.h"
62 
63 #include "../../lib/ims/useful_defs.h"
64 #include "../../modules/presence/presence.h"
65 
66 extern int db_mode;
67 extern int db_mode_ext;
68 extern int match_contact_host_port;
69 
70 #ifdef STATISTICS
build_stat_name(str * domain,char * var_name)71 static char *build_stat_name( str* domain, char *var_name)
72 {
73 	int n;
74 	char *s;
75 	char *p;
76 
77 	n = domain->len + 1 + strlen(var_name) + 1;
78 	s = (char*)shm_malloc( n );
79 	if (s==0) {
80 		LM_ERR("no more shm mem\n");
81 		return 0;
82 	}
83 	memcpy( s, domain->s, domain->len);
84 	p = s + domain->len;
85 	*(p++) = *ksr_stats_namesep;
86 	memcpy( p , var_name, strlen(var_name));
87 	p += strlen(var_name);
88 	*(p++) = 0;
89 	return s;
90 }
91 #endif
92 
new_udomain(str * _n,int _s,udomain_t ** _d)93 int new_udomain(str* _n, int _s, udomain_t** _d)
94 {
95 	int i;
96 #ifdef STATISTICS
97 	char *name;
98 #endif
99 
100 	/* Must be always in shared memory, since
101 	 * the cache is accessed from timer which
102 	 * lives in a separate process
103 	 */
104 	*_d = (udomain_t*)shm_malloc(sizeof(udomain_t));
105 	if (!(*_d)) {
106 		LM_ERR("new_udomain(): No memory left\n");
107 		goto error0;
108 	}
109 	memset(*_d, 0, sizeof(udomain_t));
110 
111 	(*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s);
112 	if (!(*_d)->table) {
113 		LM_ERR("no memory left 2\n");
114 		goto error1;
115 	}
116 
117 	(*_d)->name = _n;
118 
119 	for(i = 0; i < _s; i++) {
120 		init_slot(*_d, &((*_d)->table[i]), i);
121 	}
122 
123 	(*_d)->size = _s;
124 
125 #ifdef STATISTICS
126 	/* register the statistics */
127 	if ( (name=build_stat_name(_n,"contacts"))==0 || register_stat("usrloc",
128 	name, &(*_d)->contacts, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
129 		LM_ERR("failed to add stat variable\n");
130 		goto error2;
131 	}
132 	if ( (name=build_stat_name(_n,"expires"))==0 || register_stat("usrloc",
133 	name, &(*_d)->expired, STAT_SHM_NAME)!=0 ) {
134 		LM_ERR("failed to add stat variable\n");
135 		goto error2;
136 	}
137 #endif
138 
139 	return 0;
140 #ifdef STATISTICS
141 error2:
142 	shm_free((*_d)->table);
143 #endif
144 error1:
145 	shm_free(*_d);
146 error0:
147 	return -1;
148 }
149 
free_udomain(udomain_t * _d)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 			lock_ulslot(_d, i);
157 			deinit_slot(_d->table + i);
158 			unlock_ulslot(_d, i);
159 		}
160 		shm_free(_d->table);
161 	}
162 	shm_free(_d);
163 }
164 
print_udomain(FILE * _f,udomain_t * _d)165 void print_udomain(FILE* _f, udomain_t* _d)
166 {
167 	int i;
168 	int max=0, slot=0, n=0;
169 	struct pcontact* r;
170 	fprintf(_f, "---Domain---\n");
171 	fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
172 	fprintf(_f, "size : %d\n", _d->size);
173 	fprintf(_f, "table: %p\n", _d->table);
174 	/*fprintf(_f, "lock : %d\n", _d->lock); -- can be a structure --andrei*/
175 	fprintf(_f, "\n");
176 	for(i=0; i<_d->size; i++)
177 	{
178 		r = _d->table[i].first;
179 		n += _d->table[i].n;
180 		if(max<_d->table[i].n){
181 			max= _d->table[i].n;
182 			slot = i;
183 		}
184 		while(r) {
185 			print_pcontact(_f, r);
186 			r = r->next;
187 		}
188 	}
189 	fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n);
190 	fprintf(_f, "\n---/Domain---\n");
191 }
192 
193 
time2str(time_t _v,char * _s,int * _l)194 inline int time2str(time_t _v, char* _s, int* _l)
195 {
196 	struct tm* t;
197 	int l;
198 
199 	if ((!_s) || (!_l) || (*_l < 2)) {
200 		LM_ERR("Invalid parameter value\n");
201 		return -1;
202 	}
203 
204 	*_s++ = '\'';
205 
206 	/* Convert time_t structure to format accepted by the database */
207 	t = localtime(&_v);
208 	l = strftime(_s, *_l -1, "%Y-%m-%d %H:%M:%S", t);
209 
210 	if (l == 0) {
211 		LM_ERR("Error during time conversion\n");
212 		/* the value of _s is now unspecified */
213 		_s = NULL;
214 		_l = 0;
215 		return -1;
216 	}
217 	*_l = l;
218 
219 	*(_s + l) = '\'';
220 	*_l = l + 2;
221 	return 0;
222 }
223 
mem_insert_pcontact(struct udomain * _d,str * _contact,struct pcontact_info * _ci,struct pcontact ** _c)224 int mem_insert_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, struct pcontact** _c){
225 	int sl;
226 
227 	if (new_pcontact(_d->name, _contact, _ci, _c) < 0) {
228 		LM_ERR("creating pcontact failed\n");
229 		return -1;
230 	}
231 
232 	sl = ((*_c)->aorhash) & (_d->size - 1);
233 	(*_c)->sl = sl;
234         LM_DBG("Putting contact into slot [%d]\n", sl);
235 	slot_add(&_d->table[sl], *_c);
236 	update_stat(_d->contacts, 1);
237 	return 0;
238 }
239 
mem_delete_pcontact(udomain_t * _d,struct pcontact * _c)240 void mem_delete_pcontact(udomain_t* _d, struct pcontact* _c)
241 {
242 	slot_rem(_c->slot, _c);
243 	free_pcontact(_c);
244 	update_stat( _d->contacts, -1);
245 }
246 
mem_timer_udomain(udomain_t * _d)247 void mem_timer_udomain(udomain_t* _d)
248 {
249 	struct pcontact* ptr, *tmp;
250 	int i;
251 
252 	for(i=0; i<_d->size; i++)
253 	{
254 		lock_ulslot(_d, i);
255 
256 		ptr = _d->table[i].first;
257 
258 		while(ptr) {
259 		    tmp = ptr;
260 			ptr = ptr->next;
261 		    timer_pcontact(tmp);
262 		}
263 
264 		unlock_ulslot(_d, i);
265 	}
266 }
267 
lock_udomain(udomain_t * _d,str * via_host,unsigned short via_port,unsigned short via_proto)268 void lock_udomain(udomain_t* _d, str* via_host, unsigned short via_port, unsigned short via_proto)
269 {
270 	unsigned int sl;
271 
272 	sl = get_hash_slot(_d, via_host, via_port, via_proto);
273 
274 #ifdef GEN_LOCK_T_PREFERED
275 	lock_get(_d->table[sl].lock);
276 #else
277 	ul_lock_idx(_d->table[sl].lockidx);
278 #endif
279 }
280 
unlock_udomain(udomain_t * _d,str * via_host,unsigned short via_port,unsigned short via_proto)281 void unlock_udomain(udomain_t* _d, str* via_host, unsigned short via_port, unsigned short via_proto)
282 {
283 	unsigned int sl;
284 	sl = get_hash_slot(_d, via_host, via_port, via_proto);
285 #ifdef GEN_LOCK_T_PREFERED
286 	lock_release(_d->table[sl].lock);
287 #else
288 	ul_release_idx(_d->table[sl].lockidx);
289 #endif
290 }
291 
lock_ulslot(udomain_t * _d,int i)292 void lock_ulslot(udomain_t* _d, int i)
293 {
294 #ifdef GEN_LOCK_T_PREFERED
295 	lock_get(_d->table[i].lock);
296 #else
297 	ul_lock_idx(_d->table[i].lockidx);
298 #endif
299 }
300 
301 
unlock_ulslot(udomain_t * _d,int i)302 void unlock_ulslot(udomain_t* _d, int i)
303 {
304 #ifdef GEN_LOCK_T_PREFERED
305 	lock_release(_d->table[i].lock);
306 #else
307 	ul_release_idx(_d->table[i].lockidx);
308 #endif
309 }
310 
311 //TODO: this should be removed...
update_rx_regsession(struct udomain * _d,str * session_id,struct pcontact * _c)312 int update_rx_regsession(struct udomain* _d, str* session_id, struct pcontact* _c) {
313 	if (session_id->len > 0 && session_id->s) {
314 		if (_c->rx_session_id.len > 0 && _c->rx_session_id.s) {
315 			_c->rx_session_id.len = 0;
316 			shm_free(_c->rx_session_id.s);
317 		}
318 		_c->rx_session_id.s = shm_malloc(session_id->len);
319 		if (!_c->rx_session_id.s) {
320 			LM_ERR("no more shm_mem\n");
321 			return -1;
322 		}
323 		memcpy(_c->rx_session_id.s, session_id->s, session_id->len);
324 		_c->rx_session_id.len = session_id->len;
325 	} else {
326 		return -1;
327 	}
328 	return 0;
329 }
330 
331 /**
332  * assume locked before calling this - lock the contact slot...
333  * @param _d
334  * @param _ci
335  * @param _c
336  * @return
337  */
update_pcontact(struct udomain * _d,struct pcontact_info * _ci,struct pcontact * _c)338 int update_pcontact(struct udomain* _d, struct pcontact_info* _ci, struct pcontact* _c) //TODO: should prob move this to pcontact
339 {
340 	int is_default = 1;
341 	ppublic_t* ppublic_ptr;
342 	int i;
343 
344 	_c->reg_state = _ci->reg_state;
345 
346 	if (_ci->expires > 0) {
347 		_c->expires = _ci->expires;
348 	}
349 
350 	if (_ci->num_service_routes > 0 && _ci->service_routes) {
351 		//replace all existing service routes
352 		if (_c->service_routes) { //remove old service routes
353 			for (i=0; i<_c->num_service_routes; i++) {
354 				if (_c->service_routes[i].s)
355 					shm_free(_c->service_routes[i].s);
356 			}
357 			shm_free(_c->service_routes);
358 			_c->service_routes=0;
359 			_c->num_service_routes=0;
360 		}
361 		//now add the new service routes
362 		if (_ci->num_service_routes > 0) {
363 			_c->service_routes = shm_malloc(_ci->num_service_routes*sizeof(str));
364 			if (!_c->service_routes) {
365 				LM_ERR("no more shm mem trying to allocate [%ld bytes]\n", _ci->num_service_routes*sizeof(str));
366 				goto out_of_memory;
367 			} else {
368 				for (i=0; i<_ci->num_service_routes; i++) {
369 					STR_SHM_DUP(_c->service_routes[i], _ci->service_routes[i], "update_pcontact");
370 				}
371 				_c->num_service_routes = _ci->num_service_routes;
372 			}
373 		}
374 	}
375 
376 	if (_ci->num_public_ids > 0 && _ci->public_ids) {
377 		if (_c->head) {
378 			LM_DBG("ppublic's already exist.... .not updating\n");
379 		} else {
380 			for (i = 0; i < _ci->num_public_ids; i++) {
381 				if (i > 0)
382 					is_default = 0; //only the first one is default - P-Associated-uri (first one is default)
383 				if (new_ppublic(&_ci->public_ids[i], is_default, &ppublic_ptr) != 0) {
384 					LM_ERR("unable to create new ppublic\n");
385 				} else {
386 					insert_ppublic(_c, ppublic_ptr);
387 				}
388 			}
389 		}
390 	}
391 
392 	//update Rx reg session information
393 	if (_ci->rx_regsession_id && _ci->rx_regsession_id->len>0 && _ci->rx_regsession_id->s) {
394 		if (_c->rx_session_id.len > 0 && _c->rx_session_id.s) {
395 			_c->rx_session_id.len = 0;
396 			shm_free(_c->rx_session_id.s);
397 		}
398 		_c->rx_session_id.s = shm_malloc(_ci->rx_regsession_id->len);
399 		if (!_c->rx_session_id.s) {
400 			LM_ERR("no more shm_mem\n");
401 			return -1;
402 		}
403 		memcpy(_c->rx_session_id.s, _ci->rx_regsession_id->s, _ci->rx_regsession_id->len);
404 		_c->rx_session_id.len = _ci->rx_regsession_id->len;
405 	}
406 
407 	//TODO: update path, etc
408 
409 	if (db_mode == WRITE_THROUGH && db_update_pcontact(_c) != 0) {
410 		LM_ERR("Error updating record in DB");
411 		return -1;
412 	}
413 
414 	run_ul_callbacks(PCSCF_CONTACT_UPDATE, _c);
415 	return 0;
416 
417 out_of_memory:
418 	return -1;
419 }
420 
insert_pcontact(struct udomain * _d,str * _contact,struct pcontact_info * _ci,struct pcontact ** _c)421 int insert_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, struct pcontact** _c) {
422 
423     if (mem_insert_pcontact(_d, _contact, _ci, _c)){
424         LM_ERR("inserting pcontact failed\n");
425         goto error;
426     }
427     if (exists_ulcb_type(PCSCF_CONTACT_INSERT)) {
428 		run_ul_create_callbacks(*_c);
429 	}
430 
431 	if (db_mode == WRITE_THROUGH && db_insert_pcontact(*_c) != 0) {
432 		LM_ERR("error inserting contact into db");
433 		goto error;
434 	}
435 
436     return 0;
437 
438 error:
439     return -1;
440 }
441 
442 /*
443  * search for P-CSCF contact in usrloc
444  * @udomain_t* _d - domain to search in
445  * @str* _contact - contact to search for - should be a SIP URI
446  * @struct pontact** _c - contact to return to if found (null if not found)
447  * @return 0 if found <>0 if not
448  */
get_pcontact(udomain_t * _d,pcontact_info_t * contact_info,struct pcontact ** _c)449 int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact** _c) {
450 	unsigned int sl, i, j, aorhash, params_len, has_rinstance=0;
451 	struct pcontact* c;
452 	struct sip_uri needle_uri;
453 	int serviceroutematch;
454 	char *params, *sep;
455 	str rinstance = {0, 0};
456 
457 	LM_DBG("Searching for contact with AOR [%.*s] in P-CSCF usrloc based on VIA [%d://%.*s:%d] Received [%d://%.*s:%d], Search flag is %d\n",
458 		contact_info->aor.len, contact_info->aor.s, contact_info->via_prot, contact_info->via_host.len, contact_info->via_host.s, contact_info->via_port,
459 		contact_info->received_proto, contact_info->received_host.len, contact_info->received_host.s, contact_info->received_port, contact_info->searchflag);
460 
461 	/* parse the uri in the NOTIFY */
462 	if (contact_info->aor.len>0 && contact_info->aor.s){
463 		LM_DBG("Have an AOR to search for\n");
464 		if (parse_uri(contact_info->aor.s, contact_info->aor.len, &needle_uri) != 0) {
465 			LM_ERR("Unable to parse contact aor in get_pcontact [%.*s]\n", contact_info->aor.len, contact_info->aor.s);
466 			return 0;
467 		}
468 		LM_DBG("checking for rinstance");
469 		/*check for alias - NAT */
470 		params = needle_uri.sip_params.s;
471 		params_len = needle_uri.sip_params.len;
472 
473 		while (params_len >= RINSTANCE_LEN) {
474 			if (strncmp(params, RINSTANCE, RINSTANCE_LEN) == 0) {
475 				has_rinstance = 1;
476 				break;
477 			}
478 			sep = memchr(params, 59 /* ; */, params_len);
479 			if (sep == NULL) {
480 				LM_DBG("no rinstance param\n");
481 				break;
482 			} else {
483 				params_len = params_len - (sep - params + 1);
484 				params = sep + 1;
485 			}
486 		}
487 		if (has_rinstance) {
488 			rinstance.s = params + RINSTANCE_LEN;
489 			rinstance.len = params_len - RINSTANCE_LEN;
490 			sep = (char*)memchr(rinstance.s, 59 /* ; */, rinstance.len);
491 			if (sep != NULL){
492 				rinstance.len = (sep-rinstance.s);
493 			}
494 			LM_DBG("rinstance found [%.*s]\n", rinstance.len, rinstance.s);
495 		}
496 	}
497 
498 
499 	/* search in cache */
500 	aorhash = get_aor_hash(_d, &contact_info->via_host, contact_info->via_port, contact_info->via_prot);
501 	sl = aorhash & (_d->size - 1);
502 
503 	LM_DBG("get_pcontact slot is [%d]\n", sl);
504 	c = _d->table[sl].first;
505 
506 	for (i = 0; i < _d->table[sl].n; i++) {
507 		LM_DBG("comparing contact with aorhash [%u], aor [%.*s]\n", c->aorhash, c->aor.len, c->aor.s);
508 		LM_DBG("  contact host [%.*s:%d]\n", c->contact_host.len, c->contact_host.s, c->contact_port);
509 		LM_DBG("contact received [%d:%.*s:%d]\n", c->received_proto, c->received_host.len, c->received_host.s, c->received_port);
510 
511 		if(c->aorhash == aorhash){
512 			int check1_passed = 0;
513 			int check2_passed = 0;
514 			ip_addr_t c_ip_addr;
515 			ip_addr_t ci_ip_addr;
516 
517 			// convert 'contact->contact host' ip string to ip_addr_t
518 			if (str2ipxbuf(&c->contact_host, &c_ip_addr) < 0){
519 				LM_ERR("Unable to convert c->contact_host [%.*s]\n", c->contact_host.len, c->contact_host.s);
520 				return 1;
521 			}
522 
523 			// convert 'contact info->via host' ip string to ip_addr_t
524 			if(str2ipxbuf(&contact_info->via_host, &ci_ip_addr) < 0){
525 				LM_ERR("Unable to convert contact_info->via_host [%.*s]\n", contact_info->via_host.len, contact_info->via_host.s);
526 				return 1;
527 			}
528 
529 			// compare 'contact->contact host' and 'contact info->via host'
530 			if(ip_addr_cmp(&c_ip_addr, &ci_ip_addr) &&
531 				(c->contact_port == contact_info->via_port) &&
532 				!(contact_info->searchflag & SEARCH_RECEIVED))
533 			{
534 				check1_passed = 1;
535 			}
536 
537 			if(contact_info->searchflag & SEARCH_RECEIVED){
538 				// convert 'contact->received host' ip string to ip_addr_t
539 				if (str2ipxbuf(&c->received_host, &c_ip_addr) < 0){
540 					LM_ERR("Unable to convert c->received_host [%.*s]\n", c->received_host.len, c->received_host.s);
541 					return 1;
542 				}
543 
544 				// convert 'contact info->received host' ip string to ip_addr_t
545 				if(str2ipxbuf(&contact_info->received_host, &ci_ip_addr) < 0){
546 					LM_ERR("Unable to convert contact_info->received_host [%.*s]\n", contact_info->received_host.len, contact_info->received_host.s);
547 					return 1;
548 				}
549 
550 				// compare 'contact->received host' and 'contact info->received host'
551 				if(ip_addr_cmp(&c_ip_addr, &ci_ip_addr) &&
552 					((c->received_port == contact_info->received_port) ||
553 					 (c->contact_port == contact_info->received_port))){ /*volte comes from a different port.... typically uses 4060*/
554 					check2_passed = 1;
555 				}
556 			}
557 
558 			if(check1_passed || check2_passed){
559 				LM_DBG("found contact with URI [%.*s]\n", c->aor.len, c->aor.s);
560 				if (has_rinstance) {
561 					LM_DBG("confirming rinstance is the same - search has [%.*s] and proposed found contact has [%.*s]",
562 							rinstance.len, rinstance.s,
563 							c->rinstance.len, c->rinstance.s);
564 					if ((rinstance.len == c->rinstance.len) && memcmp(rinstance.s, c->rinstance.s, rinstance.len) != 0) {
565 						LM_DBG("rinstance does not match - no match here...\n");
566 						c = c->next;
567 						continue;
568 					}
569 				}
570 
571 				if ((contact_info->extra_search_criteria & SEARCH_SERVICE_ROUTES) && contact_info->num_service_routes > 0) {
572 					LM_DBG("have %d service routes to search for\n", contact_info->num_service_routes);
573 					if (contact_info->num_service_routes != c->num_service_routes) {
574 						c = c->next;
575 						LM_DBG("number of service routes do not match - failing\n");
576 						continue;
577 					}
578 
579 					serviceroutematch = 1;
580 					for (j=0; j<contact_info->num_service_routes; j++) {
581 						if (contact_info->service_routes[j].len != c->service_routes[j].len || memcmp(contact_info->service_routes[j].s, c->service_routes[j].s, c->service_routes[j].len) != 0) {
582 							LM_DBG("service route at position %d does not match - looking for [%.*s] and contact has [%.*s]... continuing to next contact check\n",
583 							    j,
584 								contact_info->service_routes[j].len, contact_info->service_routes[j].s,
585 								c->service_routes[j].len, c->service_routes[j].s);
586 							serviceroutematch = 0;
587 							break;
588 						}
589 					}
590 					if (serviceroutematch == 0) {
591 						c = c->next;
592 						continue;
593 					}
594 				}
595 
596 				//finally check state being searched for
597 				if ( (contact_info->reg_state != PCONTACT_ANY) && ((contact_info->reg_state & c->reg_state) == 0)) {
598 					LM_DBG("can't find contact for requested reg state [%d] - (have [%d])\n", contact_info->reg_state, c->reg_state);
599 					c = c->next;
600 					continue;
601 				}
602 				*_c = c;
603 				return 0;
604 			}
605 		}
606 		c = c->next;
607 	}
608 
609 	LM_DBG("contact not found in memory\n");
610 	// Default: Not found.
611 	*_c = NULL;
612 
613 	return 1; /* Nothing found */
614 }
615 
update_security(udomain_t * _d,security_type _t,security_t * _s,struct pcontact * _c)616 int update_security(udomain_t* _d, security_type _t, security_t* _s, struct pcontact* _c) {
617 	if (db_mode == WRITE_THROUGH && db_update_pcontact_security(_c, _t, _s) != 0) {
618 		LM_ERR("Error updating security for contact in DB\n");
619 		return -1;
620 	}
621 	_c->security = _s;
622 	return 0;
623 }
624 
update_temp_security(udomain_t * _d,security_type _t,security_t * _s,struct pcontact * _c)625 int update_temp_security(udomain_t* _d, security_type _t, security_t* _s, struct pcontact* _c) {
626 	if (db_mode == WRITE_THROUGH && db_update_pcontact_security_temp(_c, _t, _s) != 0) {
627 		LM_ERR("Error updating temp security for contact in DB\n");
628 		return -1;
629 	}
630 	_c->security_temp = _s;
631 	return 0;
632 }
633 
634 
assert_identity(udomain_t * _d,str * _host,unsigned short _port,unsigned short _proto,str * _identity)635 int assert_identity(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, str * _identity) {
636 	int i;
637 	struct pcontact* c;
638 	// Public identities of this contact
639 	struct ppublic * p;
640 
641 	for(i=0; i<_d->size; i++)
642 	{
643 		c = _d->table[i].first;
644 		while(c) {
645 			LM_DBG("Port %d (search %d), Proto %d (search %d), reg_state %s (search %s)\n",
646 				c->received_port, _port, c->received_proto, _proto,
647 				reg_state_to_string(c->reg_state), reg_state_to_string(PCONTACT_REGISTERED)
648 				);
649 			// First check, if Proto and Port matches:
650 			if ((c->reg_state == PCONTACT_REGISTERED) && (c->received_port == _port) && (c->received_proto == _proto)) {
651 				LM_DBG("Received host len %d (search %d)\n", c->received_host.len, _host->len);
652 				// Then check the length:
653 				if (c->received_host.len == _host->len) {
654 					LM_DBG("Received host %.*s (search %.*s)\n",
655 						c->received_host.len, c->received_host.s,
656 						_host->len, _host->s);
657 
658 					// Finally really compare the "received_host"
659 					if (!memcmp(c->received_host.s, _host->s, _host->len)) {
660 						for (p = c->head; p; p = p->next) {
661 							LM_DBG("Public identity: %.*s\n", p->public_identity.len, p->public_identity.s);
662 							/* Check length: */
663 							if (_identity->len == p->public_identity.len) {
664 								/* Check contents: */
665 								if (strncasecmp(_identity->s, p->public_identity.s, _identity->len) == 0) {
666 									LM_DBG("Match!\n");
667 									return 1;
668 								}
669 							} else LM_DBG("Length does not match.\n");
670 						}
671 					}
672 				}
673 			}
674 			c = c->next;
675 		}
676 	}
677 	return 0; /* Nothing found */
678 }
679 
delete_pcontact(udomain_t * _d,struct pcontact * _c)680 int delete_pcontact(udomain_t* _d, /*str* _aor, str* _received_host, int _received_port,*/ struct pcontact* _c)
681 {
682 	if (_c==0) {
683 		return 0;
684 	}
685 
686 	if (exists_ulcb_type(PCSCF_CONTACT_DELETE)) {
687 		run_ul_callbacks(PCSCF_CONTACT_DELETE, _c);
688 	}
689 
690 	if (db_mode == WRITE_THROUGH && db_delete_pcontact(_c) != 0) {
691 		LM_ERR("Error deleting contact from DB");
692 		return -1;
693 	}
694 
695 	mem_delete_pcontact(_d, _c);
696 
697 	return 0;
698 }
699 
unreg_pending_contacts_cb(udomain_t * _d,pcontact_t * _c,int type)700 int unreg_pending_contacts_cb(udomain_t* _d, pcontact_t* _c, int type)
701 {
702 	pcontact_t*		c;
703 	pcontact_info_t	contact_info;
704 	unsigned int	aorhash, sl, i;
705 
706 	contact_info.via_host = _c->via_host;
707 	contact_info.via_port = SIP_PORT;
708 	contact_info.via_prot = _c->via_proto;
709 	contact_info.reg_state = PCONTACT_ANY;
710 
711 	LM_DBG("Searching for contact in P-CSCF usrloc based on VIA [%d://%.*s:%d], reg state 0x%02X\n",
712 			contact_info.via_prot, contact_info.via_host.len, contact_info.via_host.s, contact_info.via_port, contact_info.reg_state);
713 
714 	aorhash = get_aor_hash(_d, &contact_info.via_host, contact_info.via_port, contact_info.via_prot);
715 	sl = aorhash & (_d->size - 1);
716 
717     LM_DBG("get_pcontact slot is [%d]\n", sl);
718 	c = _d->table[sl].first;
719 
720 	for(i = 0; i < _d->table[sl].n; i++){
721 		LM_DBG("comparing contact with aorhash [%u], aor [%.*s]\n", c->aorhash, c->aor.len, c->aor.s);
722 		LM_DBG("contact host [%.*s:%d]\n", c->contact_host.len, c->contact_host.s, c->contact_port);
723 
724 		if(c->aorhash == aorhash){
725 			ip_addr_t c_ip_addr;
726 			ip_addr_t ci_ip_addr;
727 
728 			// convert 'contact->contact host' ip string to ip_addr_t
729 			if (str2ipxbuf(&c->contact_host, &c_ip_addr) < 0){
730 				LM_ERR("Unable to convert c->contact_host [%.*s]\n", c->contact_host.len, c->contact_host.s);
731 				return 1;
732 			}
733 
734 			// convert 'contact info->via host' ip string to ip_addr_t
735 			if(str2ipxbuf(&contact_info.via_host, &ci_ip_addr) < 0){
736 				LM_ERR("Unable to convert contact_info.via_host [%.*s]\n", contact_info.via_host.len, contact_info.via_host.s);
737 				return 1;
738 			}
739 
740 			// compare 'contact->contact host' and 'contact info->via host'
741 			if(ip_addr_cmp(&c_ip_addr, &ci_ip_addr) && (c->contact_port == contact_info.via_port)){
742 				LM_DBG("found contact with URI [%.*s]\n", c->aor.len, c->aor.s);
743 
744 				// finally check state being searched for
745 				if((contact_info.reg_state != PCONTACT_ANY) && ((contact_info.reg_state & c->reg_state) == 0)){
746 					LM_DBG("can't find contact for requested reg state [%d] - (have [%d])\n", contact_info.reg_state, c->reg_state);
747 					c = c->next;
748 					continue;
749 				}
750 
751 				// check for equal ipsec parameters
752 				if(c->security_temp == NULL || _c->security_temp == NULL){
753 					LM_DBG("Invalid temp security\n");
754 					c = c->next;
755 					continue;
756 				}
757 
758 				if(c->security_temp->type != SECURITY_IPSEC){
759 					LM_DBG("Invalid temp security type\n");
760 					c = c->next;
761 					continue;
762 				}
763 
764 				if(c->security_temp->data.ipsec == NULL || _c->security_temp->data.ipsec == NULL){
765 					LM_DBG("Invalid ipsec\n");
766 					c = c->next;
767 					continue;
768 				}
769 
770 				LM_DBG("=========== c->reg_state 0x%02X, %u-%u | %u-%u | %u-%u | %u-%u | %u-%u | %u-%u | %u-%u | %u-%u |",
771 					c->reg_state,
772 					c->security_temp->data.ipsec->port_pc, _c->security_temp->data.ipsec->port_pc,
773 				    c->security_temp->data.ipsec->port_ps, _c->security_temp->data.ipsec->port_ps,
774 				    c->security_temp->data.ipsec->port_uc, _c->security_temp->data.ipsec->port_uc,
775 				    c->security_temp->data.ipsec->port_us, _c->security_temp->data.ipsec->port_us,
776 				    c->security_temp->data.ipsec->spi_pc, _c->security_temp->data.ipsec->spi_pc,
777 				    c->security_temp->data.ipsec->spi_ps, _c->security_temp->data.ipsec->spi_ps,
778 				    c->security_temp->data.ipsec->spi_uc, _c->security_temp->data.ipsec->spi_uc,
779 				    c->security_temp->data.ipsec->spi_us, _c->security_temp->data.ipsec->spi_us);
780 
781 				if(c->security_temp->data.ipsec->port_pc == _c->security_temp->data.ipsec->port_pc &&
782 				   c->security_temp->data.ipsec->port_ps == _c->security_temp->data.ipsec->port_ps &&
783 				   c->security_temp->data.ipsec->port_uc == _c->security_temp->data.ipsec->port_uc &&
784 				   c->security_temp->data.ipsec->port_us == _c->security_temp->data.ipsec->port_us &&
785 				   c->security_temp->data.ipsec->spi_pc == _c->security_temp->data.ipsec->spi_pc &&
786 				   c->security_temp->data.ipsec->spi_ps == _c->security_temp->data.ipsec->spi_ps &&
787 				   c->security_temp->data.ipsec->spi_uc == _c->security_temp->data.ipsec->spi_uc &&
788 				   c->security_temp->data.ipsec->spi_us == _c->security_temp->data.ipsec->spi_us){
789 					// deregister user callback only for contacts with exact sec parameters like registerd contact
790 					delete_ulcb(c, type);
791 				}
792 			}
793 		}
794 		c = c->next;
795 	}
796 
797 	return 0;
798 }
799 
800 /*!
801  * \brief Convert database values into pcontact_info
802  *
803  * Convert database values into pcontact_info,
804  * expects 15 rows (aor, host, port, protocol, received, received_port, received_proto, rx_session_id_col
805  * reg_state, expires, socket, service_routes_col, public_ids, path
806  * \param vals database values
807  * \param contact contact
808  * \return pointer to the ucontact_info on success, 0 on failure
809  */
dbrow2info(db_val_t * vals,str * contact)810 static inline pcontact_info_t* dbrow2info( db_val_t *vals, str *contact)
811 {
812 	static pcontact_info_t ci;
813 	static str host, received, path, rx_session_id, implicit_impus, tmpstr, service_routes;
814 	static str *impu_list, *service_route_list;
815 	int flag=0, n;
816 	char *p, *q=0;
817 
818 	memset( &ci, 0, sizeof(pcontact_info_t));
819 
820 	host.s = (char*) VAL_STRING(vals + 1);
821 	if (VAL_NULL(vals+1) || !host.s || !host.s[0]) {
822 		host.len = 0;
823 		host.s = 0;
824 	} else {
825 		host.len = strlen(host.s);
826 	}
827 	ci.via_host = host;
828 	ci.via_port = VAL_INT(vals + 2);
829 	ci.via_prot = VAL_INT(vals + 3);
830 	received.s = (char*) VAL_STRING(vals + 4);
831 	if (VAL_NULL(vals+4) || !received.s || !received.s[0]) {
832 		LM_DBG("Empty received for contact [%.*s]....\n", contact->len, contact->s);	/*this could happen if you have been notified about a contact from S-CSCF*/
833 		received.len = 0;
834 		received.s = 0;
835 	} else {
836 		received.len = strlen(received.s);
837 	}
838 	ci.received_host = received;
839 	ci.received_port = VAL_INT(vals + 5);
840 	ci.received_proto = VAL_INT(vals + 6);
841 
842 	rx_session_id.s = (char*) VAL_STRING(vals + 7);
843 	if (VAL_NULL(vals+7) || !rx_session_id.s || !rx_session_id.s[0]) {
844 		rx_session_id.len = 0;
845 		rx_session_id.s = 0;
846 	} else {
847 		rx_session_id.len = strlen(rx_session_id.s);
848 	}
849 	ci.rx_regsession_id = &rx_session_id;
850 	if (VAL_NULL(vals + 8)) {
851 		LM_ERR("empty registration state in DB\n");
852 		return 0;
853 	}
854 	ci.reg_state = VAL_INT(vals + 8);
855 
856         if (VAL_NULL(vals + 9)) {
857 		LM_ERR("empty expire\n");
858 		return 0;
859 	}
860 	ci.expires = VAL_TIME(vals + 9);
861 	path.s  = (char*)VAL_STRING(vals+13);
862 		if (VAL_NULL(vals+13) || !path.s || !path.s[0]) {
863 			path.len = 0;
864 			path.s = 0;
865 		} else {
866 			path.len = strlen(path.s);
867 		}
868 	ci.path = &path;
869 
870 	//public IDs - implicit set
871 	implicit_impus.s = (char*) VAL_STRING(vals + 12);
872 	if (!VAL_NULL(vals + 12) && implicit_impus.s && implicit_impus.s[0]) {
873 		//how many
874 		n=0;
875 		p = implicit_impus.s;
876 		while (*p) {
877 			if ((*p) == '<') {
878 				n++;
879 			}
880 			p++;
881 		}
882 		impu_list = pkg_malloc(sizeof(str) * n);
883 
884 		n=0;
885 		p = implicit_impus.s;
886 		while (*p) {
887 			if (*p == '<') {
888 				q = p + 1;
889 				flag = 1;
890 			}
891 			if (*p == '>') {
892 				if (flag) {
893 					tmpstr.s = q;
894 					tmpstr.len = p - q;
895 					impu_list[n++] = tmpstr;
896 				}
897 				flag = 0;
898 			}
899 			p++;
900 		}
901 		ci.num_public_ids = n;
902 		ci.public_ids = impu_list;
903 	}
904 
905 	//service routes
906 	service_routes.s = (char*) VAL_STRING(vals + 11);
907 	if (!VAL_NULL(vals + 11) && service_routes.s && service_routes.s[0]) {
908 		//how many
909 		n = 0;
910 		p = service_routes.s;
911 		while (*p) {
912 			if ((*p) == '<') {
913 				n++;
914 			}
915 			p++;
916 		}
917 		service_route_list = pkg_malloc(sizeof(str) * n);
918 
919 		n = 0;
920 		p = service_routes.s;
921 		while (*p) {
922 			if (*p == '<') {
923 				q = p + 1;
924 				flag = 1;
925 			}
926 			if (*p == '>') {
927 				if (flag) {
928 					tmpstr.s = q;
929 					tmpstr.len = p - q;
930 					service_route_list[n++] = tmpstr;
931 				}
932 				flag = 0;
933 			}
934 			p++;
935 		}
936 		ci.num_service_routes = n;
937 		ci.service_routes = service_route_list;
938 	}
939 
940 	return &ci;
941 }
942 
943 /*!
944  * \brief Load all records from a udomain
945  *
946  * Load all records from a udomain, useful to populate the
947  * memory cache on startup.
948  * \param _c database connection
949  * \param _d loaded domain
950  * \return 0 on success, -1 on failure
951  */
preload_udomain(db1_con_t * _c,udomain_t * _d)952 int preload_udomain(db1_con_t* _c, udomain_t* _d)
953 {
954 	pcontact_info_t *ci;
955 	db_row_t *row;
956 	db_key_t columns[15];
957 	db1_res_t* res = NULL;
958 	str aor;
959 	int i, n;
960 
961 	pcontact_t* c;
962 
963 	LM_DBG("pre-loading domain from DB\n");
964 
965 	columns[0] = &domain_col;
966 	columns[1] = &aor_col;
967 	columns[2] = &host_col;
968 	columns[3] = &port_col;
969 	columns[4] = &protocol_col;
970 	columns[5] = &received_col;
971 	columns[6] = &received_port_col;
972 	columns[7] = &received_proto_col;
973 	columns[8] = &rx_session_id_col;
974 	columns[9] = &reg_state_col;
975 	columns[10] = &expires_col;
976 	columns[11] = &socket_col;
977 	columns[12] = &service_routes_col;
978 	columns[13] = &public_ids_col;
979 	columns[14] = &path_col;
980 
981 	if (ul_dbf.use_table(_c, _d->name) < 0) {
982 		LM_ERR("sql use_table failed\n");
983 		return -1;
984 	}
985 
986 #ifdef EXTRA_DEBUG
987 	LM_NOTICE("load start time [%d]\n", (int)time(NULL));
988 #endif
989 
990 	if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
991 		if (ul_dbf.query(_c, 0, 0, 0, columns, 0, 15, 0, 0) < 0) {
992 			LM_ERR("db_query (1) failed\n");
993 			return -1;
994 		}
995 		if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
996 			LM_ERR("fetching rows failed\n");
997 			return -1;
998 		}
999 	} else {
1000 		if (ul_dbf.query(_c, 0, 0, 0, columns, 0, 15, 0, &res) < 0) {
1001 			LM_ERR("db_query failed\n");
1002 			return -1;
1003 		}
1004 	}
1005 
1006 	if (RES_ROW_N(res) == 0) {
1007 		LM_DBG("table is empty\n");
1008 		ul_dbf.free_result(_c, res);
1009 		return 0;
1010 	}
1011 
1012 	LM_DBG("%d rows returned in preload\n", RES_ROW_N(res));
1013 
1014 	n = 0;
1015 	do {
1016 		LM_DBG("loading records - cycle [%d]\n", ++n);
1017 		for(i = 0; i < RES_ROW_N(res); i++) {
1018 			row = RES_ROWS(res) + i;
1019 
1020 			aor.s = (char*) VAL_STRING(ROW_VALUES(row) + 1);
1021 			if (VAL_NULL(ROW_VALUES(row) + 1) || aor.s == 0 || aor.s[0] == 0) {
1022 				LM_CRIT("empty aor record in table %s...skipping\n", _d->name->s);
1023 				continue;
1024 			}
1025 			aor.len = strlen(aor.s);
1026 			ci = dbrow2info(ROW_VALUES(row) + 1, &aor);
1027 			if (!ci) {
1028 				LM_WARN("Failed to get contact info from DB.... continuing...\n");
1029 				continue;
1030 			}
1031 			lock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
1032 
1033 			if ( (mem_insert_pcontact(_d, &aor, ci, &c)) != 0) {
1034 				LM_ERR("inserting contact failed\n");
1035 				unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
1036 				goto error1;
1037 			}
1038 			//c->flags = c->flags|(1<<FLAG_READFROMDB);
1039 			//TODO: need to subscribe to s-cscf for first public identity
1040 			unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
1041 		}
1042 
1043 		if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
1044 			if(ul_dbf.fetch_result(_c, &res, ul_fetch_rows)<0) {
1045 				LM_ERR("fetching rows (1) failed\n");
1046 				ul_dbf.free_result(_c, res);
1047 				return -1;
1048 			}
1049 		} else {
1050 			break;
1051 		}
1052 	} while(RES_ROW_N(res)>0);
1053 
1054 	ul_dbf.free_result(_c, res);
1055 
1056 #ifdef EXTRA_DEBUG
1057 	LM_NOTICE("load end time [%d]\n", (int)time(NULL));
1058 #endif
1059 
1060 	return 0;
1061 error1:
1062 	free_pcontact(c);
1063 
1064 	ul_dbf.free_result(_c, res);
1065 	return -1;
1066 }
1067 
db_load_pcontact(db1_con_t * _c,udomain_t * _d,str * _aor)1068 pcontact_t* db_load_pcontact(db1_con_t* _c, udomain_t* _d, str *_aor)
1069 {
1070 	pcontact_info_t *ci;
1071 	db_key_t columns[15];
1072 	db_key_t keys[1];
1073 	db_val_t vals[1];
1074 	db1_res_t* res = NULL;
1075 	db_row_t *row;
1076 	int i;
1077 	str aor;
1078 
1079 	pcontact_t* c;
1080 
1081 	keys[0] = &aor_col;
1082 	vals[0].type = DB1_STR;
1083 	vals[0].nul = 0;
1084 	vals[0].val.str_val = *_aor;
1085 
1086 	columns[0] = &domain_col;
1087 	columns[1] = &aor_col;
1088 	columns[2] = &host_col;
1089 	columns[3] = &port_col;
1090 	columns[4] = &protocol_col;
1091 	columns[5] = &received_col;
1092 	columns[6] = &received_port_col;
1093 	columns[7] = &received_proto_col;
1094 	columns[8] = &rx_session_id_col;
1095 	columns[9] = &reg_state_col;
1096 	columns[10] = &expires_col;
1097 	columns[11] = &socket_col;
1098 	columns[12] = &service_routes_col;
1099 	columns[13] = &public_ids_col;
1100 	columns[14] = &path_col;
1101 
1102 	LM_DBG("Querying database for P-CSCF contact [%.*s]\n", _aor->len, _aor->s);
1103 
1104 	if (ul_dbf.use_table(_c, _d->name) < 0) {
1105 		LM_ERR("failed to use table %.*s\n", _d->name->len, _d->name->s);
1106 		return 0;
1107 	}
1108 
1109 	if (ul_dbf.query(_c, keys, 0, vals, columns, 1, 15, 0, &res) < 0) {
1110 		LM_ERR("db_query failed\n");
1111 		return 0;
1112 	}
1113 
1114 	if (RES_ROW_N(res) == 0) {
1115 		LM_DBG("aor %.*s not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
1116 		ul_dbf.free_result(_c, res);
1117 		return 0;
1118 	}
1119 
1120 	for(i = 0; i < RES_ROW_N(res); i++) {
1121 		row = RES_ROWS(res) + i;
1122 		aor.s = (char*) VAL_STRING(ROW_VALUES(row) + 1);
1123 		if (VAL_NULL(ROW_VALUES(row) + 1) || aor.s == 0 || aor.s[0] == 0) {
1124 			LM_CRIT("empty aor record in table %s...skipping\n", _d->name->s);
1125 			continue;
1126 		}
1127 		aor.len = strlen(aor.s);
1128 		ci = dbrow2info(ROW_VALUES(row) + 1, &aor);
1129 		if (!ci) {
1130 			LM_WARN("Failed to get contact info from DB.... continuing...\n");
1131 			continue;
1132 		}
1133 		lock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
1134 			if ( (mem_insert_pcontact(_d, &aor, ci, &c)) != 0) {
1135 			LM_ERR("inserting contact failed\n");
1136 			unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
1137 			goto error;
1138 		}
1139 		//c->flags = c->flags|(1<<FLAG_READFROMDB);
1140 		//TODO: need to subscribe to s-cscf for first public identity
1141 		unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
1142 	}
1143 
1144 	ul_dbf.free_result(_c, res);
1145 
1146 	return c;
1147 
1148 error:
1149 	free_pcontact(c);
1150 
1151 	ul_dbf.free_result(_c, res);
1152 	return 0;
1153 }
1154 
1155 
1156