4 * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
5 * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
7 * The initial version of this code was written by Dragos Vingarzan
8 * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
9 * Fruanhofer Institute. It was and still is maintained in a separate
10 * branch of the original SER. We are therefore migrating it to
11 * Kamailio/SR and look forward to maintaining it from here on out.
12 * 2011/2012 Smile Communications, Pty. Ltd.
13 * ported/maintained/improved by
14 * Jason Penton (jason(dot)penton(at)smilecoms.com and
15 * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
16 * effort to add full IMS support to Kamailio/SR using a new and
17 * improved architecture
19 * NB: Alot of this code was originally part of OpenIMSCore,
21 * Copyright (C) 2004-2006 FhG Fokus
22 * Thanks for great work! This is an effort to
23 * break apart the various CSCF functions into logically separate
24 * components. We hope this will drive wider use. We also feel
25 * that in this way the architecture is more complete and thereby easier
26 * to manage in the Kamailio/SR environment
28 * This file is part of Kamailio, a free SIP server.
30 * Kamailio is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version
35 * Kamailio is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
48 #include "../../core/hashes.h"
49 #include "../../core/mem/shm_mem.h"
50 #include "../../core/dprint.h"
51 #include "../../core/ut.h"
52 #include "ims_usrloc_pcscf_mod.h"
55 #include "ul_callback.h"
57 #include "../../lib/ims/useful_defs.h"
58 #include "usrloc_db.h"
59 #include "../../core/parser/parse_uri.h"
63 extern int expires_grace;
65 /*! retransmission detection interval in seconds */
68 void insert_ppublic(struct pcontact* _c, ppublic_t* _p)
70 LM_DBG("linking IMPU <%.*s> to contact <%.*s>\n",
71 _p->public_identity.len,_p->public_identity.s,
72 _c->aor.len, _c->aor.s);
74 if (_c->head == 0) {//first entry
75 _c->head = _c->tail = _p;
82 int new_ppublic(str* public_identity, int is_default, ppublic_t** _p)
84 *_p = (ppublic_t*)shm_malloc(sizeof(ppublic_t));
86 LM_ERR("no more shm memory\n");
89 (*_p)->next=(*_p)->prev=0;
90 (*_p)->public_identity.s = (char*)shm_malloc(public_identity->len);
91 if (!(*_p)->public_identity.s) {
92 LM_ERR("no more shm memory\n");
99 (*_p)->is_default = is_default;
100 memcpy((*_p)->public_identity.s, public_identity->s, public_identity->len);
101 (*_p)->public_identity.len = public_identity->len;
105 void free_ppublic(ppublic_t* _p)
109 if (_p->public_identity.s) {
110 shm_free(_p->public_identity.s);
116 // The same piece of code also lives in modules/ims_registrar_pcscf/sec_agree.c
117 // Function - parse_sec_agree()
118 // goto label - cleanup
119 // Keep them in sync!
120 void free_security(security_t* _p)
126 if(_p->sec_header.s) {
127 shm_free(_p->sec_header.s);
134 if(_p->data.ipsec->ealg.s) shm_free(_p->data.ipsec->ealg.s);
135 if(_p->data.ipsec->r_ealg.s) shm_free(_p->data.ipsec->r_ealg.s);
136 if(_p->data.ipsec->ck.s) shm_free(_p->data.ipsec->ck.s);
137 if(_p->data.ipsec->alg.s) shm_free(_p->data.ipsec->alg.s);
138 if(_p->data.ipsec->r_alg.s) shm_free(_p->data.ipsec->r_alg.s);
139 if(_p->data.ipsec->ik.s) shm_free(_p->data.ipsec->ik.s);
140 if(_p->data.ipsec->prot.s) shm_free(_p->data.ipsec->prot.s);
141 if(_p->data.ipsec->mod.s) shm_free(_p->data.ipsec->mod.s);
143 shm_free(_p->data.ipsec);
149 shm_free(_p->data.tls);
154 //Nothing to deallocate
161 int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, struct pcontact** _c)
163 int i, has_rinstance=0;
164 ppublic_t* ppublic_ptr;
165 int is_default = 1, params_len;
166 struct sip_uri sip_uri;
167 char* p, *params, *sep;
168 str rinstance = {0,0};
170 *_c = (pcontact_t*)shm_malloc(sizeof(pcontact_t) + _contact->len + _ci->received_host.len + _ci->via_host.len);
172 LM_ERR("no more shared memory\n");
175 memset(*_c, 0, sizeof(pcontact_t));
177 LM_DBG("New contact [<%.*s>] with %d associated IMPUs in state: [%s]\n",
178 _contact->len, _contact->s,
180 reg_state_to_string(_ci->reg_state));
184 p = (char*)((struct pcontact*)(*_c) + 1);
186 memcpy(p, _contact->s, _contact->len);
188 (*_c)->aor.len = _contact->len;
189 (*_c)->domain = (str*)_d;
191 if (parse_uri((*_c)->aor.s, (*_c)->aor.len, &sip_uri) != 0) {
192 LM_ERR("unable to determine contact host from uri [%.*s\n", (*_c)->aor.len, (*_c)->aor.s);
193 shm_free((*_c)->aor.s);
199 /* is there an rinstance param */
200 LM_DBG("checking for rinstance");
201 /*check for alias - NAT */
202 params = sip_uri.sip_params.s;
203 params_len = sip_uri.sip_params.len;
204 while (params_len >= RINSTANCE_LEN) {
205 if (strncmp(params, RINSTANCE, RINSTANCE_LEN) == 0) {
209 sep = memchr(params, 59 /* ; */, params_len);
211 LM_DBG("no rinstance param\n");
214 params_len = params_len - (sep - params + 1);
219 rinstance.s = params + RINSTANCE_LEN;
220 rinstance.len = params_len - RINSTANCE_LEN;
221 sep = (char*)memchr(rinstance.s, 59 /* ; */, rinstance.len);
223 rinstance.len = (sep-rinstance.s);
226 (*_c)->rinstance.s = rinstance.s;
227 (*_c)->rinstance.len = rinstance.len;
228 (*_c)->contact_host.s = sip_uri.host.s;
229 (*_c)->contact_host.len = sip_uri.host.len;
230 (*_c)->contact_port = sip_uri.port_no?sip_uri.port_no:5060;
231 (*_c)->contact_user.s = sip_uri.user.s;
232 (*_c)->contact_user.len = sip_uri.user.len;
234 (*_c)->expires = _ci->expires;
235 (*_c)->reg_state = _ci->reg_state;
237 // Add received Info:
238 if (_ci->received_host.len > 0 && _ci->received_host.s) {
239 (*_c)->received_host.s = p;
240 memcpy(p, _ci->received_host.s, _ci->received_host.len);
241 p += _ci->received_host.len;
242 (*_c)->received_host.len = _ci->received_host.len;
243 (*_c)->received_port = _ci->received_port;
244 (*_c)->received_proto = _ci->received_proto;
247 if (_ci->via_host.len > 0 && _ci->via_host.s) {
248 (*_c)->via_host.s = p;
249 memcpy(p, _ci->via_host.s, _ci->via_host.len);
250 p += _ci->via_host.len;
251 (*_c)->via_host.len = _ci->via_host.len;
252 (*_c)->via_port = _ci->via_port;
253 (*_c)->via_proto = _ci->via_prot;
256 (*_c)->aorhash = get_aor_hash(_d, &_ci->via_host, _ci->via_port, _ci->via_prot);
259 for (i=0; i<_ci->num_public_ids; i++) {
260 if (i>0) is_default = 0; //only the first one is default - P-Associated-uri (first one is default)
261 if (new_ppublic(&_ci->public_ids[i], is_default, &ppublic_ptr)!=0) {
262 LM_ERR("unable to create new ppublic\n");
264 insert_ppublic(*_c, ppublic_ptr);
267 //add the service routes
268 if (_ci->num_service_routes > 0) {
269 (*_c)->service_routes = shm_malloc(_ci->num_service_routes * sizeof(str));
270 if (!(*_c)->service_routes) {
271 LM_ERR("no more shm mem\n");
274 for (i = 0; i < _ci->num_service_routes; i++) {
275 STR_SHM_DUP((*_c)->service_routes[i], _ci->service_routes[i], "new_pcontact");
277 (*_c)->num_service_routes = _ci->num_service_routes;
281 LM_DBG("New contact host:port [%.*s:%d]\n", (*_c)->contact_host.len, (*_c)->contact_host.s, (*_c)->contact_port);
282 LM_DBG("New contact via host:port:proto: [%.*s:%d:%d]\n", (*_c)->via_host.len, (*_c)->via_host.s, (*_c)->via_port, (*_c)->via_proto);
283 LM_DBG("New contact received host:port:proto: [%.*s:%d:%d]\n", (*_c)->received_host.len, (*_c)->received_host.s, (*_c)->received_port, (*_c)->received_proto);
284 LM_DBG("New contact aorhash [%u]\n", (*_c)->aorhash);
292 void free_pcontact(pcontact_t* _c) {
301 destroy_ul_callbacks_list(_c->cbs.first);
304 LM_DBG("freeing pcontact: <%.*s>\n", _c->aor.len, _c->aor.s);
308 LM_DBG("freeing linked IMPI: <%.*s>\n", p->public_identity.len, p->public_identity.s);
313 //free service_routes
314 if (_c->service_routes) { //remove old service routes
315 for (i = 0; i < _c->num_service_routes; i++) {
316 if (_c->service_routes[i].s)
317 shm_free(_c->service_routes[i].s);
319 shm_free(_c->service_routes);
320 _c->service_routes = 0;
321 _c->num_service_routes = 0;
324 // free_security() checks for NULL ptr
325 free_security(_c->security_temp);
326 free_security(_c->security);
328 if (_c->rx_session_id.len > 0 && _c->rx_session_id.s)
329 shm_free(_c->rx_session_id.s);
333 static inline void nodb_timer(pcontact_t* _c)
335 LM_DBG("Running nodb timer on <%.*s>, "
338 "Expires in: %d seconds, "
339 "Received: %.*s:%d, "
344 _c->aor.len, _c->aor.s,
345 reg_state_to_string(_c->reg_state),
347 (int)(_c->expires - time(NULL)),
348 _c->received_host.len, _c->received_host.s,
350 _c->path.len, _c->path.s,
358 if ((_c->expires - act_time) + expires_grace <= 0) {//we've allowed some grace time TODO: add as parameter
359 //if ((_c->expires - act_time) <= -10) {//we've allowed some grace time TODO: add as parameter
360 LM_DBG("pcscf contact <%.*s> has expired and will be removed\n", _c->aor.len, _c->aor.s);
361 if (exists_ulcb_type(PCSCF_CONTACT_EXPIRE)) {
362 run_ul_callbacks(PCSCF_CONTACT_EXPIRE, _c);
365 if (db_mode == WRITE_THROUGH && db_delete_pcontact(_c) != 0) {
366 LM_ERR("Error deleting ims_usrloc_pcscf record in DB");
369 update_stat(_c->slot->d->expired, 1);
370 mem_delete_pcontact(_c->slot->d, _c);
374 //TODO: this is just for tmp debugging
377 // if (p->is_default)
378 // LM_DBG("public identity %i (default): <%.*s>\n", i, p->public_identity.len, p->public_identity.s);
380 // LM_DBG("public identity %i: <%.*s>\n", i, p->public_identity.len, p->public_identity.s);
385 // LM_DBG("There are %i service routes as follows:\n", _c->num_service_routes);
386 // for (i=0; i<_c->num_service_routes; i++) {
387 // LM_DBG("service route %i: <%.*s>\n", i+1, _c->service_routes[i].len, _c->service_routes[i].s);
391 void timer_pcontact(pcontact_t* _r)
396 void print_pcontact(FILE* _f, pcontact_t* _r)