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] = ®_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] = ®_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